Chromium Code Reviews| Index: Source/core/animation/InvalidatableStyleInterpolation.cpp |
| diff --git a/Source/core/animation/InvalidatableStyleInterpolation.cpp b/Source/core/animation/InvalidatableStyleInterpolation.cpp |
| index d0f20a686b362d16feadb1ca1e5c59b8d394b7e9..9f815c218aec52aca4197f3afdd246b4627c0c13 100644 |
| --- a/Source/core/animation/InvalidatableStyleInterpolation.cpp |
| +++ b/Source/core/animation/InvalidatableStyleInterpolation.cpp |
| @@ -97,10 +97,10 @@ bool InvalidatableStyleInterpolation::isCacheValid(const StyleResolverState& sta |
| return true; |
| } |
| -void InvalidatableStyleInterpolation::ensureValidInterpolation(const StyleResolverState& state, const InterpolationValue* underlyingValue) const |
| +const InterpolationValue* InvalidatableStyleInterpolation::ensureValidInterpolation(const StyleResolverState& state, const InterpolationValue* underlyingValue) const |
| { |
| if (m_cachedConversion && isCacheValid(state, underlyingValue)) |
| - return; |
| + return m_cachedValue.get(); |
| m_conversionCheckers.clear(); |
| if (!maybeCachePairwiseConversion(&state, underlyingValue)) { |
| m_cachedConversion = FlipPrimitiveInterpolation::create( |
| @@ -108,6 +108,7 @@ void InvalidatableStyleInterpolation::ensureValidInterpolation(const StyleResolv |
| convertSingleKeyframe(*m_endKeyframe, state, underlyingValue)); |
| } |
| m_cachedConversion->interpolateValue(m_currentFraction, m_cachedValue); |
| + return m_cachedValue.get(); |
| } |
| void InvalidatableStyleInterpolation::setFlagIfInheritUsed(StyleResolverState& state) const |
| @@ -120,20 +121,95 @@ void InvalidatableStyleInterpolation::setFlagIfInheritUsed(StyleResolverState& s |
| } |
| } |
| -void InvalidatableStyleInterpolation::apply(StyleResolverState& state) const |
| +// Handles memory management of underlying InterpolationValues in applyStack() |
| +// Ensures we perform copy on write if we are not the owner of an underlying InterpolationValue. |
| +// This functions similar to a DataRef except on OwnPtr'd objects. |
| +class UnderlyingValue { |
| + STACK_ALLOCATED(); |
| +public: |
| + UnderlyingValue() |
| + : m_owner() |
| + , m_pointer(nullptr) |
| + { } |
| + |
| + void set(const InterpolationValue* interpolationValue) |
| + { |
| + m_owner.clear(); |
| + m_pointer = const_cast<InterpolationValue*>(interpolationValue); |
|
dstockwell
2015/09/07 03:46:23
comment why this is safe
alancutter (OOO until 2018)
2015/09/07 04:34:12
Done.
|
| + } |
| + void set(PassOwnPtr<InterpolationValue> interpolateValue) |
| + { |
| + m_owner = interpolateValue; |
| + m_pointer = m_owner.get(); |
| + } |
| + InterpolationValue& access() |
| + { |
| + ASSERT(m_pointer); |
| + if (!m_owner) |
| + set(m_pointer->clone()); |
| + return *m_pointer; |
| + } |
| + const InterpolationValue* get() const { return m_pointer; } |
| + operator bool() const { return m_pointer; } |
| + const InterpolationValue* operator->() const |
| + { |
| + ASSERT(m_pointer); |
| + return m_pointer; |
| + } |
| + |
| +private: |
| + OwnPtr<InterpolationValue> m_owner; |
| + InterpolationValue* m_pointer; |
| +}; |
| + |
| +void InvalidatableStyleInterpolation::applyStack(const ActiveInterpolations& interpolations, StyleResolverState& state) |
| { |
| - OwnPtr<InterpolationValue> underlyingValue = dependsOnUnderlyingValue() ? maybeConvertUnderlyingValue(state) : nullptr; |
| - ensureValidInterpolation(state, underlyingValue.get()); |
| - if (!m_cachedValue) |
| - return; |
| - const InterpolableValue* appliedInterpolableValue = &m_cachedValue->interpolableValue(); |
| - if (underlyingValue && m_cachedValue->type() == underlyingValue->type()) { |
| - double underlyingFraction = m_cachedConversion->interpolateUnderlyingFraction(m_startKeyframe->underlyingFraction(), m_endKeyframe->underlyingFraction(), m_currentFraction); |
| - underlyingValue->interpolableValue().scaleAndAdd(underlyingFraction, m_cachedValue->interpolableValue()); |
| - appliedInterpolableValue = &underlyingValue->interpolableValue(); |
| + ASSERT(interpolations.size() > 0); |
| + size_t startingIndex = 0; |
| + |
| + // Compute the underlying value to composite onto. |
| + UnderlyingValue underlyingValue; |
| + const InvalidatableStyleInterpolation& firstInterpolation = toInvalidatableStyleInterpolation(*interpolations.at(startingIndex)); |
| + if (firstInterpolation.dependsOnUnderlyingValue()) { |
| + underlyingValue.set(firstInterpolation.maybeConvertUnderlyingValue(state)); |
| + } else { |
| + const InterpolationValue* firstValue = firstInterpolation.ensureValidInterpolation(state, nullptr); |
| + // Fast path for replace interpolations that are the only one to apply. |
| + if (interpolations.size() == 1) { |
| + if (firstValue) { |
|
dstockwell
2015/09/07 03:46:23
merge with previous line
alancutter (OOO until 2018)
2015/09/07 04:34:12
It would not be equivalent due to the return state
|
| + firstInterpolation.setFlagIfInheritUsed(state); |
| + firstValue->type().apply(firstValue->interpolableValue(), firstValue->nonInterpolableValue(), state); |
| + } |
| + return; |
| + } |
| + underlyingValue.set(firstValue); |
| + startingIndex++; |
| + } |
| + |
| + // Composite interpolations onto the underlying value. |
| + bool shouldApply = false; |
| + for (size_t i = startingIndex; i < interpolations.size(); i++) { |
| + const InvalidatableStyleInterpolation& currentInterpolation = toInvalidatableStyleInterpolation(*interpolations.at(i)); |
| + ASSERT(currentInterpolation.dependsOnUnderlyingValue()); |
| + const InterpolationValue* currentValue = currentInterpolation.ensureValidInterpolation(state, underlyingValue.get()); |
| + if (!currentValue) |
| + continue; |
| + shouldApply = true; |
| + currentInterpolation.setFlagIfInheritUsed(state); |
| + if (!underlyingValue || underlyingValue->type() != currentValue->type()) { |
| + underlyingValue.set(currentValue); |
| + } else { |
| + double underlyingFraction = currentInterpolation.m_cachedConversion->interpolateUnderlyingFraction( |
| + currentInterpolation.m_startKeyframe->underlyingFraction(), |
| + currentInterpolation.m_endKeyframe->underlyingFraction(), |
| + currentInterpolation.m_currentFraction); |
| + underlyingValue.access().interpolableValue().scaleAndAdd(underlyingFraction, currentInterpolation.m_cachedValue->interpolableValue()); |
| + } |
| + } |
| + |
| + if (shouldApply && underlyingValue) { |
| + underlyingValue->type().apply(underlyingValue->interpolableValue(), underlyingValue->nonInterpolableValue(), state); |
| } |
| - m_cachedValue->type().apply(*appliedInterpolableValue, m_cachedValue->nonInterpolableValue(), state); |
| - setFlagIfInheritUsed(state); |
| } |
| } // namespace blink |