summaryrefslogtreecommitdiffstats
path: root/dom/smil/SMILCSSProperty.cpp
blob: 5e4adc45f923cc932a6c8fdce4b0102b7ce67ab8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
/* -*- 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 "SMILCSSProperty.h"

#include <utility>

#include "mozilla/SMILCSSValueType.h"
#include "mozilla/SMILValue.h"
#include "mozilla/ServoBindings.h"
#include "mozilla/StyleAnimationValue.h"
#include "mozilla/dom/Element.h"
#include "nsCSSProps.h"
#include "nsDOMCSSAttrDeclaration.h"

namespace mozilla {

// Class Methods
SMILCSSProperty::SMILCSSProperty(nsCSSPropertyID aPropID,
                                 dom::Element* aElement,
                                 const ComputedStyle* aBaseComputedStyle)
    : mPropID(aPropID),
      mElement(aElement),
      mBaseComputedStyle(aBaseComputedStyle) {
  MOZ_ASSERT(IsPropertyAnimatable(mPropID),
             "Creating a SMILCSSProperty for a property "
             "that's not supported for animation");
}

SMILValue SMILCSSProperty::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:
  SMILValue baseValue;

  // SPECIAL CASE: (a) Shorthands
  //               (b) 'display'
  //               (c) No base ComputedStyle
  if (nsCSSProps::IsShorthand(mPropID) || mPropID == eCSSProperty_display ||
      !mBaseComputedStyle) {
    // 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.
    //
    // Furthermore, if we don't (yet) have a base ComputedStyle we obviously
    // can't resolve a base value.
    //
    // In any case, just return a dummy value (initialized with the right
    // type, so as not to indicate failure).
    SMILValue tmpVal(&SMILCSSValueType::sSingleton);
    std::swap(baseValue, tmpVal);
    return baseValue;
  }

  AnimationValue computedValue;
  computedValue.mServo =
      Servo_ComputedValues_ExtractAnimationValue(mBaseComputedStyle, mPropID)
          .Consume();
  if (!computedValue.mServo) {
    return baseValue;
  }

  baseValue = SMILCSSValueType::ValueFromAnimationValue(mPropID, mElement,
                                                        computedValue);
  return baseValue;
}

nsresult SMILCSSProperty::ValueFromString(
    const nsAString& aStr, const dom::SVGAnimationElement* aSrcElement,
    SMILValue& aValue, bool& aPreventCachingOfSandwich) const {
  NS_ENSURE_TRUE(IsPropertyAnimatable(mPropID), NS_ERROR_FAILURE);

  SMILCSSValueType::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 SMILCSSProperty::SetAnimValue(const SMILValue& aValue) {
  NS_ENSURE_TRUE(IsPropertyAnimatable(mPropID), NS_ERROR_FAILURE);
  return mElement->SMILOverrideStyle()->SetSMILValue(mPropID, aValue);
}

void SMILCSSProperty::ClearAnimValue() {
  // Put empty string in override style for our property
  mElement->SMILOverrideStyle()->SetPropertyValue(mPropID, ""_ns, nullptr,
                                                  IgnoreErrors());
}

// Based on http://www.w3.org/TR/SVG/propidx.html
// static
bool SMILCSSProperty::IsPropertyAnimatable(nsCSSPropertyID aPropID) {
  // NOTE: Right now, Gecko doesn't recognize the following properties from
  // the SVG Property Index:
  //   alignment-baseline
  //   baseline-shift
  //   color-profile
  //   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;
  }
}

}  // namespace mozilla