diff options
author | Justin R. Miller <incanus@codesorcery.net> | 2014-05-22 12:46:53 -0700 |
---|---|---|
committer | Justin R. Miller <incanus@codesorcery.net> | 2014-05-22 12:46:53 -0700 |
commit | aa92e92595c385c5d7dcc88a361213818d715e73 (patch) | |
tree | d31f57debbe5495bc23ec5ca253fbe953acdd896 /src/style | |
parent | cbe84299ed1a3e52483c38ef279f6bf29d65e476 (diff) | |
download | qtlocation-mapboxgl-aa92e92595c385c5d7dcc88a361213818d715e73.tar.gz |
support for style transitions
Diffstat (limited to 'src/style')
-rw-r--r-- | src/style/style.cpp | 970 | ||||
-rw-r--r-- | src/style/style_parser.cpp | 99 |
2 files changed, 990 insertions, 79 deletions
diff --git a/src/style/style.cpp b/src/style/style.cpp index 54528f5271..b39a0bf5d5 100644 --- a/src/style/style.cpp +++ b/src/style/style.cpp @@ -19,135 +19,945 @@ void Style::reset() { computed.texts.clear(); computed.rasters.clear(); computed.composites.clear(); + computed.background.color = {{ 1, 1, 1, 1 }}; + computed.background.opacity = 1.0; + + properties_to_transition.clear(); } void Style::cascade(float z) { + uv::writelock lock(mtx); + + time start = util::now(); + + previous.fills = computed.fills; + previous.lines = computed.lines; + previous.icons = computed.icons; + previous.texts = computed.texts; + previous.rasters = computed.rasters; + previous.background = computed.background; + + previous.effective_classes = computed.effective_classes; + reset(); // Accomodate for different tile size. // TODO: Make this per-layer once individual layers have a specific tile size. z += std::log(util::tileSize / 256.0f) / M_LN2; - // Recalculate style - // Basic cascading + // Recalculate style with basic cascading. Also store the last applied class + // for each property to assist in determining transitions. for (const auto& class_pair : classes) { const std::string& class_name = class_pair.first; const ClassDescription& sheetClass = class_pair.second; - // Not enabled + // Skip if not enabled. if (appliedClasses.find(class_name) == appliedClasses.end()) continue; - // Cascade fill classes + // Cascade fill classes. for (const auto& fill_pair : sheetClass.fill) { const std::string& layer_name = fill_pair.first; const llmr::FillClass& layer = fill_pair.second; - // TODO: This should be restricted to fill styles that have actual - // values so as to not override with default values. llmr::FillProperties& fill = computed.fills[layer_name]; - fill.enabled = layer.enabled.evaluate<bool>(z); - fill.translate = {{ layer.translate[0].evaluate<float>(z), - layer.translate[1].evaluate<float>(z) }}; - fill.translateAnchor = layer.translateAnchor; - fill.winding = layer.winding; - fill.antialias = layer.antialias.evaluate<bool>(z); - fill.fill_color = layer.fill_color; - fill.stroke_color = layer.stroke_color; - fill.opacity = layer.opacity.evaluate<float>(z); - fill.image = layer.image; - } - - // Cascade line classes + + if (layer.specifiers.count("enabled")) { + fill.enabled = layer.enabled.evaluate<bool>(z); + } + + if (layer.specifiers.count("translate")) { + fill.translate = {{ layer.translate[0].evaluate<float>(z), + layer.translate[1].evaluate<float>(z) }}; + computed.effective_classes[layer_name][TransitionablePropertyKey::Translate] = class_name; + if (layer.translate_transition.duration) { + properties_to_transition[layer_name][TransitionablePropertyKey::Translate] = layer.translate_transition; + } + } + + if (layer.specifiers.count("translate-anchor")) { + fill.translateAnchor = layer.translateAnchor; + } + + if (layer.specifiers.count("winding")) { + fill.winding = layer.winding; + } + + if (layer.specifiers.count("antialias")) { + fill.antialias = layer.antialias.evaluate<bool>(z); + } + + if (layer.specifiers.count("color")) { + fill.fill_color = layer.fill_color; + computed.effective_classes[layer_name][TransitionablePropertyKey::FillColor] = class_name; + if (layer.fill_color_transition.duration) { + properties_to_transition[layer_name][TransitionablePropertyKey::FillColor] = layer.fill_color_transition; + } + } + + if (layer.specifiers.count("stroke")) { + fill.stroke_color = layer.stroke_color; + computed.effective_classes[layer_name][TransitionablePropertyKey::StrokeColor] = class_name; + if (layer.stroke_color_transition.duration) { + properties_to_transition[layer_name][TransitionablePropertyKey::StrokeColor] = layer.stroke_color_transition; + } + } + + if (layer.specifiers.count("opacity")) { + fill.opacity = layer.opacity.evaluate<float>(z); + computed.effective_classes[layer_name][TransitionablePropertyKey::Opacity] = class_name; + if (layer.opacity_transition.duration) { + properties_to_transition[layer_name][TransitionablePropertyKey::Opacity] = layer.opacity_transition; + } + } + + if (layer.specifiers.count("image")) { + fill.image = layer.image; + } + } + + // Cascade line classes. for (const auto& line_pair : sheetClass.line) { const std::string& layer_name = line_pair.first; const llmr::LineClass& layer = line_pair.second; - // TODO: This should be restricted to line styles that have actual - // values so as to not override with default values. llmr::LineProperties& stroke = computed.lines[layer_name]; - stroke.enabled = layer.enabled.evaluate<bool>(z); - stroke.translate = {{ layer.translate[0].evaluate<float>(z), - layer.translate[1].evaluate<float>(z) }}; - stroke.translateAnchor = layer.translateAnchor; - stroke.width = layer.width.evaluate<float>(z); - stroke.offset = layer.offset.evaluate<float>(z); - stroke.color = layer.color; - stroke.dash_array = {{ layer.dash_array[0].evaluate<float>(z), - layer.dash_array[1].evaluate<float>(z) }}; - stroke.opacity = layer.opacity.evaluate<float>(z); - } - - // Cascade icon classes + + if (layer.specifiers.count("enabled")) { + stroke.enabled = layer.enabled.evaluate<bool>(z); + } + + if (layer.specifiers.count("translate")) { + stroke.translate = {{ layer.translate[0].evaluate<float>(z), + layer.translate[1].evaluate<float>(z) }}; + computed.effective_classes[layer_name][TransitionablePropertyKey::Translate] = class_name; + if (layer.translate_transition.duration) { + properties_to_transition[layer_name][TransitionablePropertyKey::Translate] = layer.translate_transition; + } + } + + if (layer.specifiers.count("translate-anchor")) { + stroke.translateAnchor = layer.translateAnchor; + } + + if (layer.specifiers.count("width")) { + stroke.width = layer.width.evaluate<float>(z); + computed.effective_classes[layer_name][TransitionablePropertyKey::Width] = class_name; + if (layer.width_transition.duration) { + properties_to_transition[layer_name][TransitionablePropertyKey::Width] = layer.width_transition; + } + + } + + if (layer.specifiers.count("offset")) { + stroke.offset = layer.offset.evaluate<float>(z); + computed.effective_classes[layer_name][TransitionablePropertyKey::Offset] = class_name; + if (layer.offset_transition.duration) { + properties_to_transition[layer_name][TransitionablePropertyKey::Offset] = layer.offset_transition; + } + } + + if (layer.specifiers.count("color")) { + stroke.color = layer.color; + computed.effective_classes[layer_name][TransitionablePropertyKey::Color] = class_name; + if (layer.color_transition.duration) { + properties_to_transition[layer_name][TransitionablePropertyKey::Color] = layer.color_transition; + } + } + + if (layer.specifiers.count("dasharray")) { + stroke.dash_array = {{ layer.dash_array[0].evaluate<float>(z), + layer.dash_array[1].evaluate<float>(z) }}; + computed.effective_classes[layer_name][TransitionablePropertyKey::DashArray] = class_name; + if (layer.dash_array_transition.duration) { + properties_to_transition[layer_name][TransitionablePropertyKey::DashArray] = layer.dash_array_transition; + } + } + + if (layer.specifiers.count("opacity")) { + stroke.opacity = layer.opacity.evaluate<float>(z); + computed.effective_classes[layer_name][TransitionablePropertyKey::Opacity] = class_name; + if (layer.opacity_transition.duration) { + properties_to_transition[layer_name][TransitionablePropertyKey::Opacity] = layer.opacity_transition; + } + } + } + + // Cascade icon classes. for (const auto& icon_pair : sheetClass.icon) { const std::string& layer_name = icon_pair.first; const llmr::IconClass& layer = icon_pair.second; - // TODO: This should be restricted to icon styles that have actual - // values so as to not override with default values. llmr::IconProperties& icon = computed.icons[layer_name]; - icon.enabled = layer.enabled.evaluate<bool>(z); - icon.translate = {{ layer.translate[0].evaluate<float>(z), - layer.translate[1].evaluate<float>(z) }}; - icon.translateAnchor = layer.translateAnchor; - icon.color = layer.color; - icon.size = layer.size.evaluate<float>(z); - icon.opacity = layer.opacity.evaluate<float>(z); - icon.image = layer.image; - icon.radius = layer.radius.evaluate<float>(z); - icon.blur = layer.blur.evaluate<float>(z); - } - - // Cascade text classes + + if (layer.specifiers.count("enabled")) { + icon.enabled = layer.enabled.evaluate<bool>(z); + } + + if (layer.specifiers.count("translate")) { + icon.translate = {{ layer.translate[0].evaluate<float>(z), + layer.translate[1].evaluate<float>(z) }}; + computed.effective_classes[layer_name][TransitionablePropertyKey::Translate] = class_name; + if (layer.translate_transition.duration) { + properties_to_transition[layer_name][TransitionablePropertyKey::Translate] = layer.translate_transition; + } + } + + if (layer.specifiers.count("translate-anchor")) { + icon.translateAnchor = layer.translateAnchor; + } + + if (layer.specifiers.count("color")) { + icon.color = layer.color; + computed.effective_classes[layer_name][TransitionablePropertyKey::Color] = class_name; + if (layer.color_transition.duration) { + properties_to_transition[layer_name][TransitionablePropertyKey::Color] = layer.color_transition; + } + } + + if (layer.specifiers.count("size")) { + icon.size = layer.size.evaluate<float>(z); + } + + if (layer.specifiers.count("opacity")) { + icon.opacity = layer.opacity.evaluate<float>(z); + computed.effective_classes[layer_name][TransitionablePropertyKey::Opacity] = class_name; + if (layer.opacity_transition.duration) { + properties_to_transition[layer_name][TransitionablePropertyKey::Opacity] = layer.opacity_transition; + } + } + + if (layer.specifiers.count("image")) { + icon.image = layer.image; + } + + if (layer.specifiers.count("radius")) { + icon.radius = layer.radius.evaluate<float>(z); + computed.effective_classes[layer_name][TransitionablePropertyKey::Radius] = class_name; + if (layer.radius_transition.duration) { + properties_to_transition[layer_name][TransitionablePropertyKey::Radius] = layer.radius_transition; + } + } + + if (layer.specifiers.count("blur")) { + icon.blur = layer.blur.evaluate<float>(z); + computed.effective_classes[layer_name][TransitionablePropertyKey::Blur] = class_name; + if (layer.blur_transition.duration) { + properties_to_transition[layer_name][TransitionablePropertyKey::Blur] = layer.blur_transition; + } + } + } + + // Cascade text classes. for (const auto& text_pair : sheetClass.text) { const std::string& layer_name = text_pair.first; const llmr::TextClass& layer = text_pair.second; - // TODO: This should be restricted to text styles that have actual - // values so as to not override with default values. llmr::TextProperties& text = computed.texts[layer_name]; - text.enabled = layer.enabled.evaluate<bool>(z); - text.translate = {{ layer.translate[0].evaluate<float>(z), - layer.translate[1].evaluate<float>(z) }}; - text.translateAnchor = layer.translateAnchor; - text.color = layer.color; - text.size = layer.size.evaluate<float>(z); - text.halo = layer.halo; - text.halo_radius = layer.halo_radius.evaluate<float>(z); - text.halo_blur = layer.halo_blur.evaluate<float>(z); - text.rotate = layer.rotate.evaluate<float>(z); - text.alwaysVisible = layer.alwaysVisible.evaluate<bool>(z); - text.opacity = layer.opacity.evaluate<float>(z); - } - - // Cascade raster classes + + if (layer.specifiers.count("enabled")) { + text.enabled = layer.enabled.evaluate<bool>(z); + } + + if (layer.specifiers.count("translate")) { + text.translate = {{ layer.translate[0].evaluate<float>(z), + layer.translate[1].evaluate<float>(z) }}; + computed.effective_classes[layer_name][TransitionablePropertyKey::Translate] = class_name; + if (layer.translate_transition.duration) { + properties_to_transition[layer_name][TransitionablePropertyKey::Translate] = layer.translate_transition; + } + } + + if (layer.specifiers.count("translate-anchor")) { + text.translateAnchor = layer.translateAnchor; + } + + if (layer.specifiers.count("color")) { + text.color = layer.color; + computed.effective_classes[layer_name][TransitionablePropertyKey::Color] = class_name; + if (layer.color_transition.duration) { + properties_to_transition[layer_name][TransitionablePropertyKey::Color] = layer.color_transition; + } + } + + if (layer.specifiers.count("size")) { + text.size = layer.size.evaluate<float>(z); + } + + if (layer.specifiers.count("stroke")) { + text.halo = layer.halo; + computed.effective_classes[layer_name][TransitionablePropertyKey::Halo] = class_name; + if (layer.halo_transition.duration) { + properties_to_transition[layer_name][TransitionablePropertyKey::Halo] = layer.halo_transition; + } + } + + if (layer.specifiers.count("strokeWidth")) { + text.halo_radius = layer.halo_radius.evaluate<float>(z); + computed.effective_classes[layer_name][TransitionablePropertyKey::HaloRadius] = class_name; + if (layer.halo_radius_transition.duration) { + properties_to_transition[layer_name][TransitionablePropertyKey::HaloRadius] = layer.halo_radius_transition; + } + } + + if (layer.specifiers.count("strokeBlur")) { + text.halo_blur = layer.halo_blur.evaluate<float>(z); + computed.effective_classes[layer_name][TransitionablePropertyKey::HaloBlur] = class_name; + if (layer.halo_blur_transition.duration) { + properties_to_transition[layer_name][TransitionablePropertyKey::HaloBlur] = layer.halo_blur_transition; + } + } + + if (layer.specifiers.count("rotate")) { + text.rotate = layer.rotate.evaluate<float>(z); + } + + if (layer.specifiers.count("alwaysVisible")) { + text.always_visible = layer.always_visible.evaluate<bool>(z); + } + + if (layer.specifiers.count("opacity")) { + text.opacity = layer.opacity.evaluate<float>(z); + computed.effective_classes[layer_name][TransitionablePropertyKey::Opacity] = class_name; + if (layer.opacity_transition.duration) { + properties_to_transition[layer_name][TransitionablePropertyKey::Opacity] = layer.opacity_transition; + } + } + } + + // Cascade raster classes. for (const auto& raster_pair : sheetClass.raster) { const std::string& layer_name = raster_pair.first; const llmr::RasterClass& layer = raster_pair.second; - // TODO: This should be restricted to raster styles that have actual - // values so as to not override with default values. llmr::RasterProperties& raster = computed.rasters[layer_name]; - raster.enabled = layer.enabled.evaluate<bool>(z); - raster.opacity = layer.opacity.evaluate<float>(z); + + if (layer.specifiers.count("enabled")) { + raster.enabled = layer.enabled.evaluate<bool>(z); + } + + if (layer.specifiers.count("opacity")) { + raster.opacity = layer.opacity.evaluate<float>(z); + computed.effective_classes[layer_name][TransitionablePropertyKey::Opacity] = class_name; + if (layer.opacity_transition.duration) { + properties_to_transition[layer_name][TransitionablePropertyKey::Opacity] = layer.opacity_transition; + } + } } - // Cascade composite classes + // Cascade composite classes. for (const auto& composite_pair : sheetClass.composite) { const std::string& layer_name = composite_pair.first; const llmr::CompositeClass& layer = composite_pair.second; - // TODO: This should be restricted to composite styles that have actual - // values so as to not override with default values. llmr::CompositeProperties& composite = computed.composites[layer_name]; - composite.enabled = layer.enabled.evaluate<bool>(z); - composite.opacity = layer.opacity.evaluate<float>(z); + + if (layer.specifiers.count("enabled")) { + composite.enabled = layer.enabled.evaluate<bool>(z); + } + + if (layer.specifiers.count("opacity")) { + composite.opacity = layer.opacity.evaluate<float>(z); + computed.effective_classes[layer_name][TransitionablePropertyKey::Opacity] = class_name; + if (layer.opacity_transition.duration) { + properties_to_transition[layer_name][TransitionablePropertyKey::Opacity] = layer.opacity_transition; + } + } + } + + // Cascade background. + { + if (sheetClass.background.specifiers.count("color")) { + computed.background.color = sheetClass.background.color; + computed.effective_classes["background"][TransitionablePropertyKey::Color] = class_name; + if (sheetClass.background.color_transition.duration) { + properties_to_transition["background"][TransitionablePropertyKey::Color] = sheetClass.background.color_transition; + } + } + if (sheetClass.background.specifiers.count("opacity")) { + computed.background.opacity = sheetClass.background.opacity.evaluate<float>(z); + computed.effective_classes["background"][TransitionablePropertyKey::Opacity] = class_name; + if (sheetClass.background.opacity_transition.duration) { + properties_to_transition["background"][TransitionablePropertyKey::Opacity] = sheetClass.background.opacity_transition; + } + } + } + } + + // Apply transitions after the first time. + if (!initial_render_complete) { + initial_render_complete = true; + return; + } + + // Fills + for (const auto& fill_pair : computed.fills) { + const std::string& layer_name = fill_pair.first; + + // translate + if (transitionInProgress(layer_name, TransitionablePropertyKey::Translate)) { + + computed.fills[layer_name].translate = transitioning.fills[layer_name].translate; + + } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::Translate)) { + + transitioning.fills[layer_name].translate = previous.fills[layer_name].translate; + + transitions[layer_name][TransitionablePropertyKey::Translate] = + std::make_shared<util::ease_transition<std::array<float, 2>>>(previous.fills[layer_name].translate, + computed.fills[layer_name].translate, + transitioning.fills[layer_name].translate, + start + transitionDelay(layer_name, TransitionablePropertyKey::Translate), + transitionDuration(layer_name, TransitionablePropertyKey::Translate)); + + computed.fills[layer_name].translate = transitioning.fills[layer_name].translate; + } + + // fill color + if (transitionInProgress(layer_name, TransitionablePropertyKey::FillColor)) { + + computed.fills[layer_name].fill_color = transitioning.fills[layer_name].fill_color; + + } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::FillColor)) { + + transitioning.fills[layer_name].fill_color = previous.fills[layer_name].fill_color; + + transitions[layer_name][TransitionablePropertyKey::FillColor] = + std::make_shared<util::ease_transition<Color>>(previous.fills[layer_name].fill_color, + computed.fills[layer_name].fill_color, + transitioning.fills[layer_name].fill_color, + start + transitionDelay(layer_name, TransitionablePropertyKey::FillColor), + transitionDuration(layer_name, TransitionablePropertyKey::FillColor)); + + computed.fills[layer_name].fill_color = transitioning.fills[layer_name].fill_color; + } + + // stroke color + if (transitionInProgress(layer_name, TransitionablePropertyKey::StrokeColor)) { + + computed.fills[layer_name].stroke_color = transitioning.fills[layer_name].stroke_color; + + } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::StrokeColor)) { + + transitioning.fills[layer_name].stroke_color = previous.fills[layer_name].stroke_color; + + transitions[layer_name][TransitionablePropertyKey::StrokeColor] = + std::make_shared<util::ease_transition<Color>>(previous.fills[layer_name].stroke_color, + computed.fills[layer_name].stroke_color, + transitioning.fills[layer_name].stroke_color, + start + transitionDelay(layer_name, TransitionablePropertyKey::StrokeColor), + transitionDuration(layer_name, TransitionablePropertyKey::StrokeColor)); + + computed.fills[layer_name].stroke_color = transitioning.fills[layer_name].stroke_color; } + // opacity + if (transitionInProgress(layer_name, TransitionablePropertyKey::Opacity)) { + + computed.fills[layer_name].opacity = transitioning.fills[layer_name].opacity; + + } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::Opacity)) { - // Cascade background - computed.background.color = sheetClass.background.color; - computed.background.opacity = sheetClass.background.opacity.evaluate<float>(z); + transitioning.fills[layer_name].opacity = previous.fills[layer_name].opacity; + + transitions[layer_name][TransitionablePropertyKey::Opacity] = + std::make_shared<util::ease_transition<float>>(previous.fills[layer_name].opacity, + computed.fills[layer_name].opacity, + transitioning.fills[layer_name].opacity, + start + transitionDelay(layer_name, TransitionablePropertyKey::Opacity), + transitionDuration(layer_name, TransitionablePropertyKey::Opacity)); + + computed.fills[layer_name].opacity = transitioning.fills[layer_name].opacity; + } } + + // Lines + for (const auto& line_pair : computed.lines) { + const std::string& layer_name = line_pair.first; + + // translate + if (transitionInProgress(layer_name, TransitionablePropertyKey::Translate)) { + + computed.lines[layer_name].translate = transitioning.lines[layer_name].translate; + + } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::Translate)) { + + transitioning.lines[layer_name].translate = previous.lines[layer_name].translate; + + transitions[layer_name][TransitionablePropertyKey::Translate] = + std::make_shared<util::ease_transition<std::array<float, 2>>>(previous.lines[layer_name].translate, + computed.lines[layer_name].translate, + transitioning.lines[layer_name].translate, + start + transitionDelay(layer_name, TransitionablePropertyKey::Translate), + transitionDuration(layer_name, TransitionablePropertyKey::Translate)); + + computed.lines[layer_name].translate = transitioning.lines[layer_name].translate; + } + + // width + if (transitionInProgress(layer_name, TransitionablePropertyKey::Width)) { + + computed.lines[layer_name].width = transitioning.lines[layer_name].width; + + } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::Width)) { + + transitioning.lines[layer_name].width = previous.lines[layer_name].width; + + transitions[layer_name][TransitionablePropertyKey::Width] = + std::make_shared<util::ease_transition<float>>(previous.lines[layer_name].width, + computed.lines[layer_name].width, + transitioning.lines[layer_name].width, + start + transitionDelay(layer_name, TransitionablePropertyKey::Width), + transitionDuration(layer_name, TransitionablePropertyKey::Width)); + + computed.lines[layer_name].width = transitioning.lines[layer_name].width; + } + + // offset + if (transitionInProgress(layer_name, TransitionablePropertyKey::Offset)) { + + computed.lines[layer_name].offset = transitioning.lines[layer_name].offset; + + } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::Offset)) { + + transitioning.lines[layer_name].offset = previous.lines[layer_name].offset; + + transitions[layer_name][TransitionablePropertyKey::Offset] = + std::make_shared<util::ease_transition<float>>(previous.lines[layer_name].offset, + computed.lines[layer_name].offset, + transitioning.lines[layer_name].offset, + start + transitionDelay(layer_name, TransitionablePropertyKey::Offset), + transitionDuration(layer_name, TransitionablePropertyKey::Offset)); + + computed.lines[layer_name].offset = transitioning.lines[layer_name].offset; + } + + // color + if (transitionInProgress(layer_name, TransitionablePropertyKey::Color)) { + + computed.lines[layer_name].color = transitioning.lines[layer_name].color; + + } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::Color)) { + + transitioning.lines[layer_name].color = previous.lines[layer_name].color; + + transitions[layer_name][TransitionablePropertyKey::Color] = + std::make_shared<util::ease_transition<Color>>(previous.lines[layer_name].color, + computed.lines[layer_name].color, + transitioning.lines[layer_name].color, + start + transitionDelay(layer_name, TransitionablePropertyKey::Color), + transitionDuration(layer_name, TransitionablePropertyKey::Color)); + + computed.lines[layer_name].color = transitioning.lines[layer_name].color; + } + + // dasharray + if (transitionInProgress(layer_name, TransitionablePropertyKey::DashArray)) { + + computed.lines[layer_name].dash_array = transitioning.lines[layer_name].dash_array; + + } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::DashArray)) { + + transitioning.lines[layer_name].dash_array = previous.lines[layer_name].dash_array; + + transitions[layer_name][TransitionablePropertyKey::DashArray] = + std::make_shared<util::ease_transition<std::array<float, 2>>>(previous.lines[layer_name].dash_array, + computed.lines[layer_name].dash_array, + transitioning.lines[layer_name].dash_array, + start + transitionDelay(layer_name, TransitionablePropertyKey::DashArray), + transitionDuration(layer_name, TransitionablePropertyKey::DashArray)); + + computed.lines[layer_name].dash_array = transitioning.lines[layer_name].dash_array; + } + + // opacity + if (transitionInProgress(layer_name, TransitionablePropertyKey::Opacity)) { + + computed.lines[layer_name].opacity = transitioning.lines[layer_name].opacity; + + } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::Opacity)) { + + transitioning.lines[layer_name].opacity = previous.lines[layer_name].opacity; + + transitions[layer_name][TransitionablePropertyKey::Opacity] = + std::make_shared<util::ease_transition<float>>(previous.lines[layer_name].opacity, + computed.lines[layer_name].opacity, + transitioning.lines[layer_name].opacity, + start + transitionDelay(layer_name, TransitionablePropertyKey::Opacity), + transitionDuration(layer_name, TransitionablePropertyKey::Opacity)); + + computed.lines[layer_name].opacity = transitioning.lines[layer_name].opacity; + } + } + + // Icons + for (const auto& icon_pair : computed.icons) { + const std::string& layer_name = icon_pair.first; + + // translate + if (transitionInProgress(layer_name, TransitionablePropertyKey::Translate)) { + + computed.icons[layer_name].translate = transitioning.icons[layer_name].translate; + + } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::Translate)) { + + transitioning.icons[layer_name].translate = previous.icons[layer_name].translate; + + transitions[layer_name][TransitionablePropertyKey::Translate] = + std::make_shared<util::ease_transition<std::array<float, 2>>>(previous.icons[layer_name].translate, + computed.icons[layer_name].translate, + transitioning.icons[layer_name].translate, + start + transitionDelay(layer_name, TransitionablePropertyKey::Translate), + transitionDuration(layer_name, TransitionablePropertyKey::Translate)); + + computed.icons[layer_name].translate = transitioning.icons[layer_name].translate; + } + + // color + if (transitionInProgress(layer_name, TransitionablePropertyKey::Color)) { + + computed.icons[layer_name].color = transitioning.icons[layer_name].color; + + } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::Color)) { + + transitioning.icons[layer_name].color = previous.icons[layer_name].color; + + transitions[layer_name][TransitionablePropertyKey::Color] = + std::make_shared<util::ease_transition<Color>>(previous.icons[layer_name].color, + computed.icons[layer_name].color, + transitioning.icons[layer_name].color, + start + transitionDelay(layer_name, TransitionablePropertyKey::Color), + transitionDuration(layer_name, TransitionablePropertyKey::Color)); + + computed.icons[layer_name].color = transitioning.icons[layer_name].color; + } + + // opacity + if (transitionInProgress(layer_name, TransitionablePropertyKey::Opacity)) { + + computed.icons[layer_name].opacity = transitioning.icons[layer_name].opacity; + + } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::Opacity)) { + + transitioning.icons[layer_name].opacity = previous.icons[layer_name].opacity; + + transitions[layer_name][TransitionablePropertyKey::Opacity] = + std::make_shared<util::ease_transition<float>>(previous.icons[layer_name].opacity, + computed.icons[layer_name].opacity, + transitioning.icons[layer_name].opacity, + start + transitionDelay(layer_name, TransitionablePropertyKey::Opacity), + transitionDuration(layer_name, TransitionablePropertyKey::Opacity)); + + computed.icons[layer_name].opacity = transitioning.icons[layer_name].opacity; + } + + // radius + if (transitionInProgress(layer_name, TransitionablePropertyKey::Radius)) { + + computed.icons[layer_name].radius = transitioning.icons[layer_name].radius; + + } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::Radius)) { + + transitioning.icons[layer_name].radius = previous.icons[layer_name].radius; + + transitions[layer_name][TransitionablePropertyKey::Radius] = + std::make_shared<util::ease_transition<float>>(previous.icons[layer_name].radius, + computed.icons[layer_name].radius, + transitioning.icons[layer_name].radius, + start + transitionDelay(layer_name, TransitionablePropertyKey::Radius), + transitionDuration(layer_name, TransitionablePropertyKey::Radius)); + + computed.icons[layer_name].radius = transitioning.icons[layer_name].radius; + } + + // blur + if (transitionInProgress(layer_name, TransitionablePropertyKey::Blur)) { + + computed.icons[layer_name].blur = transitioning.icons[layer_name].blur; + + } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::Blur)) { + + transitioning.icons[layer_name].blur = previous.icons[layer_name].blur; + + transitions[layer_name][TransitionablePropertyKey::Blur] = + std::make_shared<util::ease_transition<float>>(previous.icons[layer_name].blur, + computed.icons[layer_name].blur, + transitioning.icons[layer_name].blur, + start + transitionDelay(layer_name, TransitionablePropertyKey::Blur), + transitionDuration(layer_name, TransitionablePropertyKey::Blur)); + + computed.icons[layer_name].blur = transitioning.icons[layer_name].blur; + } + } + + // Text + for (const auto& text_pair : computed.texts) { + const std::string& layer_name = text_pair.first; + + // translate + if (transitionInProgress(layer_name, TransitionablePropertyKey::Translate)) { + + computed.texts[layer_name].translate = transitioning.texts[layer_name].translate; + + } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::Translate)) { + + transitioning.texts[layer_name].translate = previous.texts[layer_name].translate; + + transitions[layer_name][TransitionablePropertyKey::Translate] = + std::make_shared<util::ease_transition<std::array<float, 2>>>(previous.texts[layer_name].translate, + computed.texts[layer_name].translate, + transitioning.texts[layer_name].translate, + start + transitionDelay(layer_name, TransitionablePropertyKey::Translate), + transitionDuration(layer_name, TransitionablePropertyKey::Translate)); + + computed.texts[layer_name].translate = transitioning.texts[layer_name].translate; + } + + // color + if (transitionInProgress(layer_name, TransitionablePropertyKey::Color)) { + + computed.texts[layer_name].color = transitioning.texts[layer_name].color; + + } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::Color)) { + + transitioning.texts[layer_name].color = previous.texts[layer_name].color; + + transitions[layer_name][TransitionablePropertyKey::Color] = + std::make_shared<util::ease_transition<Color>>(previous.texts[layer_name].color, + computed.texts[layer_name].color, + transitioning.texts[layer_name].color, + start + transitionDelay(layer_name, TransitionablePropertyKey::Color), + transitionDuration(layer_name, TransitionablePropertyKey::Color)); + + computed.texts[layer_name].color = transitioning.texts[layer_name].color; + } + + // halo + if (transitionInProgress(layer_name, TransitionablePropertyKey::Halo)) { + + computed.texts[layer_name].halo = transitioning.texts[layer_name].halo; + + } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::Halo)) { + + transitioning.texts[layer_name].halo = previous.texts[layer_name].halo; + + transitions[layer_name][TransitionablePropertyKey::Halo] = + std::make_shared<util::ease_transition<Color>>(previous.texts[layer_name].halo, + computed.texts[layer_name].halo, + transitioning.texts[layer_name].halo, + start + transitionDelay(layer_name, TransitionablePropertyKey::Halo), + transitionDuration(layer_name, TransitionablePropertyKey::Halo)); + + computed.texts[layer_name].halo = transitioning.texts[layer_name].halo; + } + + // halo radius + if (transitionInProgress(layer_name, TransitionablePropertyKey::HaloRadius)) { + + computed.texts[layer_name].halo_radius = transitioning.texts[layer_name].halo_radius; + + } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::HaloRadius)) { + + transitioning.texts[layer_name].halo_radius = previous.texts[layer_name].halo_radius; + + transitions[layer_name][TransitionablePropertyKey::HaloRadius] = + std::make_shared<util::ease_transition<float>>(previous.texts[layer_name].halo_radius, + computed.texts[layer_name].halo_radius, + transitioning.texts[layer_name].halo_radius, + start + transitionDelay(layer_name, TransitionablePropertyKey::HaloRadius), + transitionDuration(layer_name, TransitionablePropertyKey::HaloRadius)); + + computed.texts[layer_name].halo_radius = transitioning.texts[layer_name].halo_radius; + } + + // halo blur + if (transitionInProgress(layer_name, TransitionablePropertyKey::HaloBlur)) { + + computed.texts[layer_name].halo_blur = transitioning.texts[layer_name].halo_blur; + + } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::HaloBlur)) { + + transitioning.texts[layer_name].halo_blur = previous.texts[layer_name].halo_blur; + + transitions[layer_name][TransitionablePropertyKey::HaloBlur] = + std::make_shared<util::ease_transition<float>>(previous.texts[layer_name].halo_blur, + computed.texts[layer_name].halo_blur, + transitioning.texts[layer_name].halo_blur, + start + transitionDelay(layer_name, TransitionablePropertyKey::HaloBlur), + transitionDuration(layer_name, TransitionablePropertyKey::HaloBlur)); + + computed.texts[layer_name].halo_blur = transitioning.texts[layer_name].halo_blur; + } + + // opacity + if (transitionInProgress(layer_name, TransitionablePropertyKey::Opacity)) { + + computed.texts[layer_name].opacity = transitioning.texts[layer_name].opacity; + + } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::Opacity)) { + + transitioning.texts[layer_name].opacity = previous.texts[layer_name].opacity; + + transitions[layer_name][TransitionablePropertyKey::Opacity] = + std::make_shared<util::ease_transition<float>>(previous.texts[layer_name].opacity, + computed.texts[layer_name].opacity, + transitioning.texts[layer_name].opacity, + start + transitionDelay(layer_name, TransitionablePropertyKey::Opacity), + transitionDuration(layer_name, TransitionablePropertyKey::Opacity)); + + computed.texts[layer_name].opacity = transitioning.texts[layer_name].opacity; + } + } + + // Rasters + for (const auto& raster_pair : computed.rasters) { + const std::string& layer_name = raster_pair.first; + + // opacity + if (transitionInProgress(layer_name, TransitionablePropertyKey::Opacity)) { + + computed.rasters[layer_name].opacity = transitioning.rasters[layer_name].opacity; + + } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::Opacity)) { + + transitioning.rasters[layer_name].opacity = previous.rasters[layer_name].opacity; + + transitions[layer_name][TransitionablePropertyKey::Opacity] = + std::make_shared<util::ease_transition<float>>(previous.rasters[layer_name].opacity, + computed.rasters[layer_name].opacity, + transitioning.rasters[layer_name].opacity, + start + transitionDelay(layer_name, TransitionablePropertyKey::Opacity), + transitionDuration(layer_name, TransitionablePropertyKey::Opacity)); + + computed.rasters[layer_name].opacity = transitioning.rasters[layer_name].opacity; + } + } + + // Composites + for (const auto& composite_pair : computed.composites) { + const std::string& layer_name = composite_pair.first; + + // opacity + if (transitionInProgress(layer_name, TransitionablePropertyKey::Opacity)) { + + computed.composites[layer_name].opacity = transitioning.composites[layer_name].opacity; + + } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::Opacity)) { + + transitioning.composites[layer_name].opacity = previous.composites[layer_name].opacity; + + transitions[layer_name][TransitionablePropertyKey::Opacity] = + std::make_shared<util::ease_transition<float>>(previous.composites[layer_name].opacity, + computed.composites[layer_name].opacity, + transitioning.composites[layer_name].opacity, + start + transitionDelay(layer_name, TransitionablePropertyKey::Opacity), + transitionDuration(layer_name, TransitionablePropertyKey::Opacity)); + + computed.composites[layer_name].opacity = transitioning.composites[layer_name].opacity; + } + } + + // Background + { + // color + if (transitionInProgress("background", TransitionablePropertyKey::Color)) { + + computed.background.color = transitioning.background.color; + + } else if (inNeedOfTransition("background", TransitionablePropertyKey::Color)) { + + transitioning.background.color = previous.background.color; + + transitions["background"][TransitionablePropertyKey::Color] = + std::make_shared<util::ease_transition<Color>>(previous.background.color, + computed.background.color, + transitioning.background.color, + start + transitionDelay("background", TransitionablePropertyKey::Color), + transitionDuration("background", TransitionablePropertyKey::Color)); + + computed.background.color = transitioning.background.color; + } + + // opacity + if (transitionInProgress("background", TransitionablePropertyKey::Opacity)) { + + computed.background.opacity = transitioning.background.opacity; + + } else if (inNeedOfTransition("background", TransitionablePropertyKey::Opacity)) { + + transitioning.background.opacity = previous.background.opacity; + + transitions["background"][TransitionablePropertyKey::Opacity] = + std::make_shared<util::ease_transition<float>>(previous.background.opacity, + computed.background.opacity, + transitioning.background.opacity, + start + transitionDelay("background", TransitionablePropertyKey::Opacity), + transitionDuration("background", TransitionablePropertyKey::Opacity)); + + computed.background.opacity = transitioning.background.opacity; + } + } +} + +bool Style::transitionInProgress(std::string layer_name, TransitionablePropertyKey key) { + if (!transitionExists(layer_name, key)) return false; + + return (transitions[layer_name].find(key)->second->update(util::now()) != util::transition::complete); +} + +bool Style::transitionExists(std::string layer_name, TransitionablePropertyKey key) { + return (transitions[layer_name].count(key) != 0); +} + +bool Style::inNeedOfTransition(std::string layer_name, TransitionablePropertyKey key) { + if (!transitionDuration(layer_name, key)) return false; + if (transitionExists(layer_name, key)) return false; + + return (computed.effective_classes[layer_name][key] != previous.effective_classes[layer_name][key]); +} + +uint64_t Style::transitionDuration(std::string layer_name, TransitionablePropertyKey key) { + return (properties_to_transition[layer_name].count(key) ? + properties_to_transition[layer_name][key].duration : + default_transition_duration) * 1_millisecond; +} + +uint64_t Style::transitionDelay(std::string layer_name, TransitionablePropertyKey key) { + return (properties_to_transition[layer_name][key].delay * 1_millisecond); +} + +bool Style::needsTransition() const { + uv::readlock lock(mtx); + + for (auto layer_it = transitions.begin(); layer_it != transitions.end(); layer_it++) { + auto& layer_transitions = layer_it->second; + if (layer_transitions.size()) { + return true; + } + } + + return false; +} + +void Style::updateTransitions(time now) { + uv::writelock lock(mtx); + + for (auto layer_it = transitions.begin(); layer_it != transitions.end(); layer_it++) { + auto& layer_transitions = layer_it->second; + for (auto prop_it = layer_transitions.begin(); prop_it != layer_transitions.end();/**/) { + auto& transition = prop_it->second; + if (transition->update(now) == util::transition::complete) { + prop_it = layer_transitions.erase(prop_it); + } else { + prop_it++; + } + } + } +} + +void Style::cancelTransitions() { + uv::writelock lock(mtx); + + transitions.clear(); } size_t Style::layerCount() const { @@ -158,6 +968,10 @@ size_t Style::layerCount() const { return count; } +void Style::setDefaultTransitionDuration(uint64_t duration) { + default_transition_duration = duration; +} + void Style::loadJSON(const uint8_t *const data, size_t bytes) { rapidjson::Document doc; diff --git a/src/style/style_parser.cpp b/src/style/style_parser.cpp index 2198d5c369..feef6e3e15 100644 --- a/src/style/style_parser.cpp +++ b/src/style/style_parser.cpp @@ -477,42 +477,82 @@ FunctionProperty StyleParser::parseFunction(JSVal value) { return property; } +PropertyTransition StyleParser::parseTransition(JSVal value, std::string property_name) { + uint16_t duration = 0, delay = 0; + std::string transition_property = std::string("transition-").append(property_name); + if (value.HasMember(transition_property.c_str())) { + JSVal elements = value[transition_property.c_str()]; + if (elements.IsObject()) { + if (elements.HasMember("duration") && elements["duration"].IsNumber()) { + duration = elements["duration"].GetUint(); + } + if (elements.HasMember("delay") && elements["delay"].IsNumber()) { + delay = elements["delay"].GetUint(); + } + } + } + + PropertyTransition transition; + + transition.duration = duration; + transition.delay = delay; + + return transition; +} + FillClass StyleParser::parseFillClass(JSVal value) { FillClass klass; if (value.HasMember("enabled")) { klass.enabled = parseFunction(value["enabled"]); + klass.specifiers.insert("enabled"); } if (value.HasMember("translate")) { std::vector<FunctionProperty> values = parseArray(value["translate"], 2); klass.translate = std::array<FunctionProperty, 2> {{ values[0], values[1] }}; + klass.translate_transition = parseTransition(value, "translate"); + klass.specifiers.insert("translate"); } if (value.HasMember("translate-anchor")) { klass.translateAnchor = parseTranslateAnchor(value["translate-anchor"]); + klass.specifiers.insert("translate-anchor"); + } + + if (value.HasMember("winding")) { + throw std::runtime_error("winding in stylesheets not yet supported"); } if (value.HasMember("color")) { klass.fill_color = parseColor(value["color"]); + klass.fill_color_transition = parseTransition(value, "color"); + klass.specifiers.insert("color"); } if (value.HasMember("stroke")) { klass.stroke_color = parseColor(value["stroke"]); + klass.stroke_color_transition = parseTransition(value, "stroke"); + klass.specifiers.insert("stroke"); } else { klass.stroke_color = klass.fill_color; + klass.specifiers.insert("stroke"); } if (value.HasMember("antialias")) { klass.antialias = parseBoolean(value["antialias"]); + klass.specifiers.insert("antialias"); } if (value.HasMember("image")) { klass.image = parseString(value["image"]); + klass.specifiers.insert("image"); } if (value.HasMember("opacity")) { klass.opacity = parseFunction(value["opacity"]); + klass.opacity_transition = parseTransition(value, "opacity"); + klass.specifiers.insert("opacity"); } return klass; @@ -523,32 +563,44 @@ LineClass StyleParser::parseLineClass(JSVal value) { if (value.HasMember("enabled")) { klass.enabled = parseFunction(value["enabled"]); + klass.specifiers.insert("enabled"); } if (value.HasMember("translate")) { std::vector<FunctionProperty> values = parseArray(value["translate"], 2); klass.translate = std::array<FunctionProperty, 2> {{ values[0], values[1] }}; + klass.translate_transition = parseTransition(value, "translate"); + klass.specifiers.insert("translate"); } if (value.HasMember("translate-anchor")) { klass.translateAnchor = parseTranslateAnchor(value["translate-anchor"]); + klass.specifiers.insert("translate-anchor"); } if (value.HasMember("color")) { klass.color = parseColor(value["color"]); + klass.color_transition = parseTransition(value, "color"); + klass.specifiers.insert("color"); } if (value.HasMember("width")) { klass.width = parseFunction(value["width"]); + klass.width_transition = parseTransition(value, "width"); + klass.specifiers.insert("width"); } if (value.HasMember("opacity")) { klass.opacity = parseFunction(value["opacity"]); + klass.opacity_transition = parseTransition(value, "opacity"); + klass.specifiers.insert("opacity"); } if (value.HasMember("dasharray")) { std::vector<FunctionProperty> values = parseArray(value["dasharray"], 2); klass.dash_array = std::array<FunctionProperty, 2> {{ values[0], values[1] }}; + klass.dash_array_transition = parseTransition(value, "dasharray"); + klass.specifiers.insert("dasharray"); } return klass; @@ -559,39 +611,53 @@ IconClass StyleParser::parseIconClass(JSVal value) { if (value.HasMember("enabled")) { klass.enabled = parseFunction(value["enabled"]); + klass.specifiers.insert("enabled"); } if (value.HasMember("translate")) { std::vector<FunctionProperty> values = parseArray(value["translate"], 2); klass.translate = std::array<FunctionProperty, 2> {{ values[0], values[1] }}; + klass.translate_transition = parseTransition(value, "translate"); + klass.specifiers.insert("translate"); } if (value.HasMember("translate-anchor")) { klass.translateAnchor = parseTranslateAnchor(value["translate-anchor"]); + klass.specifiers.insert("translate-anchor"); } if (value.HasMember("color")) { klass.color = parseColor(value["color"]); + klass.color_transition = parseTransition(value, "color"); + klass.specifiers.insert("color"); } if (value.HasMember("opacity")) { klass.opacity = parseFunction(value["opacity"]); + klass.opacity_transition = parseTransition(value, "opacity"); + klass.specifiers.insert("opacity"); } if (value.HasMember("image")) { klass.image = parseString(value["image"]); + klass.specifiers.insert("image"); } if (value.HasMember("size")) { klass.size = parseFunction(value["size"]); + klass.specifiers.insert("size"); } if (value.HasMember("radius")) { klass.radius = parseFunction(value["radius"]); + klass.radius_transition = parseTransition(value, "radius"); + klass.specifiers.insert("radius"); } if (value.HasMember("blur")) { klass.blur = parseFunction(value["blur"]); + klass.blur_transition = parseTransition(value, "blur"); + klass.specifiers.insert("blur"); } return klass; @@ -602,43 +668,64 @@ TextClass StyleParser::parseTextClass(JSVal value) { if (value.HasMember("enabled")) { klass.enabled = parseFunction(value["enabled"]); + klass.specifiers.insert("enabled"); } if (value.HasMember("translate")) { std::vector<FunctionProperty> values = parseArray(value["translate"], 2); klass.translate = std::array<FunctionProperty, 2> {{ values[0], values[1] }}; + klass.translate_transition = parseTransition(value, "translate"); + klass.specifiers.insert("translate"); } if (value.HasMember("translate-anchor")) { klass.translateAnchor = parseTranslateAnchor(value["translate-anchor"]); + klass.specifiers.insert("translate-anchor"); } if (value.HasMember("color")) { klass.color = parseColor(value["color"]); + klass.color_transition = parseTransition(value, "color"); + klass.specifiers.insert("color"); } if (value.HasMember("stroke")) { klass.halo = parseColor(value["stroke"]); + klass.halo_transition = parseTransition(value, "stroke"); + klass.specifiers.insert("stroke"); } if (value.HasMember("strokeWidth")) { klass.halo_radius = parseFunction(value["strokeWidth"]); + klass.halo_radius_transition = parseTransition(value, "strokeWidth"); + klass.specifiers.insert("strokeWidth"); } if (value.HasMember("strokeBlur")) { klass.halo_blur = parseFunction(value["strokeBlur"]); + klass.halo_blur_transition = parseTransition(value, "strokeBlur"); + klass.specifiers.insert("strokeBlur"); } if (value.HasMember("size")) { klass.size = parseFunction(value["size"]); + klass.specifiers.insert("size"); } if (value.HasMember("rotate")) { klass.rotate = parseFunction(value["rotate"]); + klass.specifiers.insert("rotate"); } if (value.HasMember("alwaysVisible")) { - klass.alwaysVisible = parseFunction(value["alwaysVisible"]); + klass.always_visible = parseFunction(value["alwaysVisible"]); + klass.specifiers.insert("alwaysVisible"); + } + + if (value.HasMember("opacity")) { + klass.opacity = parseFunction(value["opacity"]); + klass.opacity_transition = parseTransition(value, "opacity"); + klass.specifiers.insert("opacity"); } return klass; @@ -649,10 +736,13 @@ RasterClass StyleParser::parseRasterClass(JSVal value) { if (value.HasMember("enabled")) { klass.enabled = parseFunction(value["enabled"]); + klass.specifiers.insert("enabled"); } if (value.HasMember("opacity")) { klass.opacity = parseFunction(value["opacity"]); + klass.opacity_transition = parseTransition(value, "opacity"); + klass.specifiers.insert("opacity"); } return klass; @@ -663,10 +753,13 @@ CompositeClass StyleParser::parseCompositeClass(JSVal value) { if (value.HasMember("enabled")) { klass.enabled = parseFunction(value["enabled"]); + klass.specifiers.insert("enabled"); } if (value.HasMember("opacity")) { klass.opacity = parseFunction(value["opacity"]); + klass.opacity_transition = parseTransition(value, "opacity"); + klass.specifiers.insert("opacity"); } return klass; @@ -677,10 +770,14 @@ BackgroundClass StyleParser::parseBackgroundClass(JSVal value) { if (value.HasMember("color")) { klass.color = parseColor(value["color"]); + klass.color_transition = parseTransition(value, "color"); + klass.specifiers.insert("color"); } if (value.HasMember("opacity")) { klass.opacity = parseFunction(value["opacity"]); + klass.opacity_transition = parseTransition(value, "opacity"); + klass.specifiers.insert("opacity"); } return klass; |