diff options
Diffstat (limited to 'dom/smil/nsSMILCSSProperty.cpp')
-rw-r--r-- | dom/smil/nsSMILCSSProperty.cpp | 275 |
1 files changed, 275 insertions, 0 deletions
diff --git a/dom/smil/nsSMILCSSProperty.cpp b/dom/smil/nsSMILCSSProperty.cpp new file mode 100644 index 000000000..53f3e0fbf --- /dev/null +++ b/dom/smil/nsSMILCSSProperty.cpp @@ -0,0 +1,275 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* representation of a SMIL-animatable CSS property on an element */ + +#include "nsSMILCSSProperty.h" + +#include "mozilla/dom/Element.h" +#include "mozilla/Move.h" +#include "nsSMILCSSValueType.h" +#include "nsSMILValue.h" +#include "nsComputedDOMStyle.h" +#include "nsCSSProps.h" +#include "nsIDOMElement.h" +#include "nsIDocument.h" + +using namespace mozilla::dom; + +// Helper function +static bool +GetCSSComputedValue(Element* aElem, + nsCSSPropertyID aPropID, + nsAString& aResult) +{ + MOZ_ASSERT(!nsCSSProps::IsShorthand(aPropID), + "Can't look up computed value of shorthand property"); + MOZ_ASSERT(nsSMILCSSProperty::IsPropertyAnimatable(aPropID), + "Shouldn't get here for non-animatable properties"); + + nsIDocument* doc = aElem->GetUncomposedDoc(); + if (!doc) { + // This can happen if we process certain types of restyles mid-sample + // and remove anonymous animated content from the document as a result. + // See bug 534975. + return false; + } + + nsIPresShell* shell = doc->GetShell(); + if (!shell) { + NS_WARNING("Unable to look up computed style -- no pres shell"); + return false; + } + + RefPtr<nsComputedDOMStyle> computedStyle = + NS_NewComputedDOMStyle(aElem, EmptyString(), shell); + + computedStyle->GetPropertyValue(aPropID, aResult); + return true; +} + +// Class Methods +nsSMILCSSProperty::nsSMILCSSProperty(nsCSSPropertyID aPropID, + Element* aElement) + : mPropID(aPropID), mElement(aElement) +{ + MOZ_ASSERT(IsPropertyAnimatable(mPropID), + "Creating a nsSMILCSSProperty for a property " + "that's not supported for animation"); +} + +nsSMILValue +nsSMILCSSProperty::GetBaseValue() const +{ + // To benefit from Return Value Optimization and avoid copy constructor calls + // due to our use of return-by-value, we must return the exact same object + // from ALL return points. This function must only return THIS variable: + nsSMILValue baseValue; + + // SPECIAL CASE: (a) Shorthands + // (b) 'display' + if (nsCSSProps::IsShorthand(mPropID) || mPropID == eCSSProperty_display) { + // We can't look up the base (computed-style) value of shorthand + // properties because they aren't guaranteed to have a consistent computed + // value. + // + // Also, although we can look up the base value of the display property, + // doing so involves clearing and resetting the property which can cause + // frames to be recreated which we'd like to avoid. + // + // In either case, just return a dummy value (initialized with the right + // type, so as not to indicate failure). + nsSMILValue tmpVal(&nsSMILCSSValueType::sSingleton); + Swap(baseValue, tmpVal); + return baseValue; + } + + // GENERAL CASE: Non-Shorthands + // (1) Put empty string in override style for property mPropID + // (saving old override style value, so we can set it again when we're done) + nsICSSDeclaration* overrideDecl = mElement->GetSMILOverrideStyle(); + nsAutoString cachedOverrideStyleVal; + if (overrideDecl) { + overrideDecl->GetPropertyValue(mPropID, cachedOverrideStyleVal); + // (Don't bother clearing override style if it's already empty) + if (!cachedOverrideStyleVal.IsEmpty()) { + overrideDecl->SetPropertyValue(mPropID, EmptyString()); + } + } + + // (2) Get Computed Style + nsAutoString computedStyleVal; + bool didGetComputedVal = GetCSSComputedValue(mElement, mPropID, + computedStyleVal); + + // (3) Put cached override style back (if it's non-empty) + if (overrideDecl && !cachedOverrideStyleVal.IsEmpty()) { + overrideDecl->SetPropertyValue(mPropID, cachedOverrideStyleVal); + } + + // (4) Populate our nsSMILValue from the computed style + if (didGetComputedVal) { + // When we parse animation values we check if they are context-sensitive or + // not so that we don't cache animation values whose meaning may change. + // For base values however this is unnecessary since on each sample the + // compositor will fetch the (computed) base value and compare it against + // the cached (computed) value and detect changes for us. + nsSMILCSSValueType::ValueFromString(mPropID, mElement, + computedStyleVal, baseValue, + nullptr); + } + return baseValue; +} + +nsresult +nsSMILCSSProperty::ValueFromString(const nsAString& aStr, + const SVGAnimationElement* aSrcElement, + nsSMILValue& aValue, + bool& aPreventCachingOfSandwich) const +{ + NS_ENSURE_TRUE(IsPropertyAnimatable(mPropID), NS_ERROR_FAILURE); + + nsSMILCSSValueType::ValueFromString(mPropID, mElement, aStr, aValue, + &aPreventCachingOfSandwich); + + if (aValue.IsNull()) { + return NS_ERROR_FAILURE; + } + + // XXX Due to bug 536660 (or at least that seems to be the most likely + // culprit), when we have animation setting display:none on a <use> element, + // if we DON'T set the property every sample, chaos ensues. + if (!aPreventCachingOfSandwich && mPropID == eCSSProperty_display) { + aPreventCachingOfSandwich = true; + } + return NS_OK; +} + +nsresult +nsSMILCSSProperty::SetAnimValue(const nsSMILValue& aValue) +{ + NS_ENSURE_TRUE(IsPropertyAnimatable(mPropID), NS_ERROR_FAILURE); + + // Convert nsSMILValue to string + nsAutoString valStr; + if (!nsSMILCSSValueType::ValueToString(aValue, valStr)) { + NS_WARNING("Failed to convert nsSMILValue for CSS property into a string"); + return NS_ERROR_FAILURE; + } + + // Use string value to style the target element + nsICSSDeclaration* overrideDecl = mElement->GetSMILOverrideStyle(); + if (overrideDecl) { + nsAutoString oldValStr; + overrideDecl->GetPropertyValue(mPropID, oldValStr); + if (valStr.Equals(oldValStr)) { + return NS_OK; + } + overrideDecl->SetPropertyValue(mPropID, valStr); + } + return NS_OK; +} + +void +nsSMILCSSProperty::ClearAnimValue() +{ + // Put empty string in override style for our property + nsICSSDeclaration* overrideDecl = mElement->GetSMILOverrideStyle(); + if (overrideDecl) { + overrideDecl->SetPropertyValue(mPropID, EmptyString()); + } +} + +// Based on http://www.w3.org/TR/SVG/propidx.html +// static +bool +nsSMILCSSProperty::IsPropertyAnimatable(nsCSSPropertyID aPropID) +{ + // NOTE: Right now, Gecko doesn't recognize the following properties from + // the SVG Property Index: + // alignment-baseline + // baseline-shift + // color-profile + // color-rendering + // glyph-orientation-horizontal + // glyph-orientation-vertical + // kerning + // writing-mode + + switch (aPropID) { + case eCSSProperty_clip: + case eCSSProperty_clip_rule: + case eCSSProperty_clip_path: + case eCSSProperty_color: + case eCSSProperty_color_interpolation: + case eCSSProperty_color_interpolation_filters: + case eCSSProperty_cursor: + case eCSSProperty_display: + case eCSSProperty_dominant_baseline: + case eCSSProperty_fill: + case eCSSProperty_fill_opacity: + case eCSSProperty_fill_rule: + case eCSSProperty_filter: + case eCSSProperty_flood_color: + case eCSSProperty_flood_opacity: + case eCSSProperty_font: + case eCSSProperty_font_family: + case eCSSProperty_font_size: + case eCSSProperty_font_size_adjust: + case eCSSProperty_font_stretch: + case eCSSProperty_font_style: + case eCSSProperty_font_variant: + case eCSSProperty_font_weight: + case eCSSProperty_height: + case eCSSProperty_image_rendering: + case eCSSProperty_letter_spacing: + case eCSSProperty_lighting_color: + case eCSSProperty_marker: + case eCSSProperty_marker_end: + case eCSSProperty_marker_mid: + case eCSSProperty_marker_start: + case eCSSProperty_mask: + case eCSSProperty_mask_type: + case eCSSProperty_opacity: + case eCSSProperty_overflow: + case eCSSProperty_pointer_events: + case eCSSProperty_shape_rendering: + case eCSSProperty_stop_color: + case eCSSProperty_stop_opacity: + case eCSSProperty_stroke: + case eCSSProperty_stroke_dasharray: + case eCSSProperty_stroke_dashoffset: + case eCSSProperty_stroke_linecap: + case eCSSProperty_stroke_linejoin: + case eCSSProperty_stroke_miterlimit: + case eCSSProperty_stroke_opacity: + case eCSSProperty_stroke_width: + case eCSSProperty_text_anchor: + case eCSSProperty_text_decoration: + case eCSSProperty_text_decoration_line: + case eCSSProperty_text_rendering: + case eCSSProperty_vector_effect: + case eCSSProperty_width: + case eCSSProperty_visibility: + case eCSSProperty_word_spacing: + return true; + + // EXPLICITLY NON-ANIMATABLE PROPERTIES: + // (Some of these aren't supported at all in Gecko -- I've commented those + // ones out. If/when we add support for them, uncomment their line here) + // ---------------------------------------------------------------------- + // case eCSSProperty_enable_background: + // case eCSSProperty_glyph_orientation_horizontal: + // case eCSSProperty_glyph_orientation_vertical: + // case eCSSProperty_writing_mode: + case eCSSProperty_direction: + case eCSSProperty_unicode_bidi: + return false; + + default: + return false; + } +} |