OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "config.h" | 5 #include "config.h" |
6 #include "core/animation/InvalidatableStyleInterpolation.h" | 6 #include "core/animation/InvalidatableStyleInterpolation.h" |
7 | 7 |
8 #include "core/animation/StringKeyframe.h" | 8 #include "core/animation/StringKeyframe.h" |
9 #include "core/css/resolver/StyleResolverState.h" | 9 #include "core/css/resolver/StyleResolverState.h" |
10 | 10 |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
90 if (!underlyingValue || !m_cachedValue || m_cachedValue->type() != under
lyingValue->type()) | 90 if (!underlyingValue || !m_cachedValue || m_cachedValue->type() != under
lyingValue->type()) |
91 return false; | 91 return false; |
92 } | 92 } |
93 for (const auto& checker : m_conversionCheckers) { | 93 for (const auto& checker : m_conversionCheckers) { |
94 if (!checker->isValid(state)) | 94 if (!checker->isValid(state)) |
95 return false; | 95 return false; |
96 } | 96 } |
97 return true; | 97 return true; |
98 } | 98 } |
99 | 99 |
100 void InvalidatableStyleInterpolation::ensureValidInterpolation(const StyleResolv
erState& state, const InterpolationValue* underlyingValue) const | 100 const InterpolationValue* InvalidatableStyleInterpolation::ensureValidInterpolat
ion(const StyleResolverState& state, const InterpolationValue* underlyingValue)
const |
101 { | 101 { |
102 if (m_cachedConversion && isCacheValid(state, underlyingValue)) | 102 if (m_cachedConversion && isCacheValid(state, underlyingValue)) |
103 return; | 103 return m_cachedValue.get(); |
104 m_conversionCheckers.clear(); | 104 m_conversionCheckers.clear(); |
105 if (!maybeCachePairwiseConversion(&state, underlyingValue)) { | 105 if (!maybeCachePairwiseConversion(&state, underlyingValue)) { |
106 m_cachedConversion = FlipPrimitiveInterpolation::create( | 106 m_cachedConversion = FlipPrimitiveInterpolation::create( |
107 convertSingleKeyframe(*m_startKeyframe, state, underlyingValue), | 107 convertSingleKeyframe(*m_startKeyframe, state, underlyingValue), |
108 convertSingleKeyframe(*m_endKeyframe, state, underlyingValue)); | 108 convertSingleKeyframe(*m_endKeyframe, state, underlyingValue)); |
109 } | 109 } |
110 m_cachedConversion->interpolateValue(m_currentFraction, m_cachedValue); | 110 m_cachedConversion->interpolateValue(m_currentFraction, m_cachedValue); |
| 111 return m_cachedValue.get(); |
111 } | 112 } |
112 | 113 |
113 void InvalidatableStyleInterpolation::setFlagIfInheritUsed(StyleResolverState& s
tate) const | 114 void InvalidatableStyleInterpolation::setFlagIfInheritUsed(StyleResolverState& s
tate) const |
114 { | 115 { |
115 if (!state.parentStyle()) | 116 if (!state.parentStyle()) |
116 return; | 117 return; |
117 if ((m_startKeyframe->value() && m_startKeyframe->value()->isInheritedValue(
)) | 118 if ((m_startKeyframe->value() && m_startKeyframe->value()->isInheritedValue(
)) |
118 || (m_endKeyframe->value() && m_endKeyframe->value()->isInheritedValue()
)) { | 119 || (m_endKeyframe->value() && m_endKeyframe->value()->isInheritedValue()
)) { |
119 state.parentStyle()->setHasExplicitlyInheritedProperties(); | 120 state.parentStyle()->setHasExplicitlyInheritedProperties(); |
120 } | 121 } |
121 } | 122 } |
122 | 123 |
123 void InvalidatableStyleInterpolation::apply(StyleResolverState& state) const | 124 // Handles memory management of underlying InterpolationValues in applyStack() |
| 125 // Ensures we perform copy on write if we are not the owner of an underlying Int
erpolationValue. |
| 126 // This functions similar to a DataRef except on OwnPtr'd objects. |
| 127 class UnderlyingValue { |
| 128 STACK_ALLOCATED(); |
| 129 public: |
| 130 UnderlyingValue() |
| 131 : m_owner() |
| 132 , m_pointer(nullptr) |
| 133 { } |
| 134 |
| 135 void set(const InterpolationValue* interpolationValue) |
| 136 { |
| 137 // By clearing m_owner we will perform a copy when attempting to access(
) |
| 138 // m_pointer as a mutable reference, thus upholding the const contract f
or |
| 139 // this instance of interpolationValue despite the const_cast. |
| 140 m_owner.clear(); |
| 141 m_pointer = const_cast<InterpolationValue*>(interpolationValue); |
| 142 } |
| 143 void set(PassOwnPtr<InterpolationValue> interpolationValue) |
| 144 { |
| 145 m_owner = interpolationValue; |
| 146 m_pointer = m_owner.get(); |
| 147 } |
| 148 InterpolationValue& access() |
| 149 { |
| 150 ASSERT(m_pointer); |
| 151 if (!m_owner) |
| 152 set(m_pointer->clone()); |
| 153 return *m_pointer; |
| 154 } |
| 155 const InterpolationValue* get() const { return m_pointer; } |
| 156 operator bool() const { return m_pointer; } |
| 157 const InterpolationValue* operator->() const |
| 158 { |
| 159 ASSERT(m_pointer); |
| 160 return m_pointer; |
| 161 } |
| 162 |
| 163 private: |
| 164 OwnPtr<InterpolationValue> m_owner; |
| 165 InterpolationValue* m_pointer; |
| 166 }; |
| 167 |
| 168 void InvalidatableStyleInterpolation::applyStack(const ActiveInterpolations& int
erpolations, StyleResolverState& state) |
124 { | 169 { |
125 OwnPtr<InterpolationValue> underlyingValue = dependsOnUnderlyingValue() ? ma
ybeConvertUnderlyingValue(state) : nullptr; | 170 ASSERT(!interpolations.isEmpty()); |
126 ensureValidInterpolation(state, underlyingValue.get()); | 171 size_t startingIndex = 0; |
127 if (!m_cachedValue) | 172 |
128 return; | 173 // Compute the underlying value to composite onto. |
129 const InterpolableValue* appliedInterpolableValue = &m_cachedValue->interpol
ableValue(); | 174 UnderlyingValue underlyingValue; |
130 if (underlyingValue && m_cachedValue->type() == underlyingValue->type()) { | 175 const InvalidatableStyleInterpolation& firstInterpolation = toInvalidatableS
tyleInterpolation(*interpolations.at(startingIndex)); |
131 double underlyingFraction = m_cachedConversion->interpolateUnderlyingFra
ction(m_startKeyframe->underlyingFraction(), m_endKeyframe->underlyingFraction()
, m_currentFraction); | 176 if (firstInterpolation.dependsOnUnderlyingValue()) { |
132 underlyingValue->interpolableValue().scaleAndAdd(underlyingFraction, m_c
achedValue->interpolableValue()); | 177 underlyingValue.set(firstInterpolation.maybeConvertUnderlyingValue(state
)); |
133 appliedInterpolableValue = &underlyingValue->interpolableValue(); | 178 } else { |
| 179 const InterpolationValue* firstValue = firstInterpolation.ensureValidInt
erpolation(state, nullptr); |
| 180 // Fast path for replace interpolations that are the only one to apply. |
| 181 if (interpolations.size() == 1) { |
| 182 if (firstValue) { |
| 183 firstInterpolation.setFlagIfInheritUsed(state); |
| 184 firstValue->type().apply(firstValue->interpolableValue(), firstV
alue->nonInterpolableValue(), state); |
| 185 } |
| 186 return; |
| 187 } |
| 188 underlyingValue.set(firstValue); |
| 189 startingIndex++; |
134 } | 190 } |
135 m_cachedValue->type().apply(*appliedInterpolableValue, m_cachedValue->nonInt
erpolableValue(), state); | 191 |
136 setFlagIfInheritUsed(state); | 192 // Composite interpolations onto the underlying value. |
| 193 bool shouldApply = false; |
| 194 for (size_t i = startingIndex; i < interpolations.size(); i++) { |
| 195 const InvalidatableStyleInterpolation& currentInterpolation = toInvalida
tableStyleInterpolation(*interpolations.at(i)); |
| 196 ASSERT(currentInterpolation.dependsOnUnderlyingValue()); |
| 197 const InterpolationValue* currentValue = currentInterpolation.ensureVali
dInterpolation(state, underlyingValue.get()); |
| 198 if (!currentValue) |
| 199 continue; |
| 200 shouldApply = true; |
| 201 currentInterpolation.setFlagIfInheritUsed(state); |
| 202 if (!underlyingValue || underlyingValue->type() != currentValue->type())
{ |
| 203 underlyingValue.set(currentValue); |
| 204 } else { |
| 205 double underlyingFraction = currentInterpolation.m_cachedConversion-
>interpolateUnderlyingFraction( |
| 206 currentInterpolation.m_startKeyframe->underlyingFraction(), |
| 207 currentInterpolation.m_endKeyframe->underlyingFraction(), |
| 208 currentInterpolation.m_currentFraction); |
| 209 underlyingValue.access().interpolableValue().scaleAndAdd(underlyingF
raction, currentInterpolation.m_cachedValue->interpolableValue()); |
| 210 } |
| 211 } |
| 212 |
| 213 if (shouldApply && underlyingValue) |
| 214 underlyingValue->type().apply(underlyingValue->interpolableValue(), unde
rlyingValue->nonInterpolableValue(), state); |
137 } | 215 } |
138 | 216 |
139 } // namespace blink | 217 } // namespace blink |
OLD | NEW |