blob: 37b6d2a44a7f4081447ae242b634cb8ed10dbbd3 [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "config.h"
#include "core/animation/LengthBoxStyleInterpolation.h"
#include "core/css/CSSQuadValue.h"
#include "core/css/resolver/StyleBuilder.h"
namespace blink {
namespace {
bool onlyInterpolateBetweenLengthAndCSSValueAuto(const CSSQuadValue& startRect, const CSSQuadValue& endRect)
{
return startRect.left()->isLength() != endRect.left()->isLength()
&& startRect.right()->isLength() != endRect.right()->isLength()
&& startRect.top()->isLength() != endRect.top()->isLength()
&& startRect.bottom()->isLength() != endRect.bottom()->isLength();
}
} // namespace
PassRefPtr<LengthBoxStyleInterpolation> LengthBoxStyleInterpolation::maybeCreateFrom(CSSValue& start, CSSValue& end, CSSPropertyID id)
{
bool startRect = start.isQuadValue() && toCSSQuadValue(start).serializationType() == CSSQuadValue::SerializationType::SerializeAsRect;
bool endRect = end.isQuadValue() && toCSSQuadValue(end).serializationType() == CSSQuadValue::SerializationType::SerializeAsRect;
if (startRect && endRect)
return adoptRef(new LengthBoxStyleInterpolation(lengthBoxtoInterpolableValue(start, end, false), lengthBoxtoInterpolableValue(end, start, true), id, &start, &end));
return nullptr;
}
PassOwnPtr<InterpolableValue> LengthBoxStyleInterpolation::lengthBoxtoInterpolableValue(const CSSValue& lengthBox, const CSSValue& matchingValue, bool isEndInterpolation)
{
const int numberOfSides = 4;
OwnPtr<InterpolableList> result = InterpolableList::create(numberOfSides);
const CSSQuadValue& rect = toCSSQuadValue(lengthBox);
const CSSQuadValue& matchingRect = toCSSQuadValue(matchingValue);
CSSPrimitiveValue* side[numberOfSides] = { rect.left(), rect.right(), rect.top(), rect.bottom() };
CSSPrimitiveValue* matchingSide[numberOfSides] = { matchingRect.left(), matchingRect.right(), matchingRect.top(), matchingRect.bottom() };
for (size_t i = 0; i < numberOfSides; i++) {
if (side[i]->isValueID() || matchingSide[i]->isValueID()) {
result->set(i, InterpolableBool::create(isEndInterpolation));
} else {
ASSERT(LengthStyleInterpolation::canCreateFrom(*side[i]));
result->set(i, LengthStyleInterpolation::toInterpolableValue(*side[i]));
}
}
return result.release();
}
bool LengthBoxStyleInterpolation::usesDefaultInterpolation(const CSSValue& start, const CSSValue& end)
{
if (start.isPrimitiveValue() && end.isPrimitiveValue()) {
const CSSPrimitiveValue& startValue = toCSSPrimitiveValue(start);
const CSSPrimitiveValue& endValue = toCSSPrimitiveValue(end);
return (startValue.isValueID() && startValue.getValueID() == CSSValueAuto)
|| (endValue.isValueID() && endValue.getValueID() == CSSValueAuto);
}
if (!start.isQuadValue() || !end.isQuadValue())
return false;
const CSSQuadValue& startValue = toCSSQuadValue(start);
const CSSQuadValue& endValue = toCSSQuadValue(end);
return onlyInterpolateBetweenLengthAndCSSValueAuto(startValue, endValue);
}
namespace {
PassRefPtrWillBeRawPtr<CSSPrimitiveValue> indexedValueToLength(InterpolableList& lengthBox, size_t i, CSSPrimitiveValue* start[], CSSPrimitiveValue* end[])
{
if (lengthBox.get(i)->isBool()) {
if (toInterpolableBool(lengthBox.get(i))->value())
return end[i];
return start[i];
}
return LengthStyleInterpolation::fromInterpolableValue(*lengthBox.get(i), RangeAll);
}
}
PassRefPtrWillBeRawPtr<CSSValue> LengthBoxStyleInterpolation::interpolableValueToLengthBox(InterpolableValue* value, const CSSValue& originalStart, const CSSValue& originalEnd)
{
InterpolableList* lengthBox = toInterpolableList(value);
const CSSQuadValue& startRect = toCSSQuadValue(originalStart);
const CSSQuadValue& endRect = toCSSQuadValue(originalEnd);
CSSPrimitiveValue* startSides[4] = { startRect.left(), startRect.right(), startRect.top(), startRect.bottom() };
CSSPrimitiveValue* endSides[4] = { endRect.left(), endRect.right(), endRect.top(), endRect.bottom() };
RefPtrWillBeRawPtr<CSSPrimitiveValue> left = indexedValueToLength(*lengthBox, 0, startSides, endSides);
RefPtrWillBeRawPtr<CSSPrimitiveValue> right = indexedValueToLength(*lengthBox, 1, startSides, endSides);
RefPtrWillBeRawPtr<CSSPrimitiveValue> top = indexedValueToLength(*lengthBox, 2, startSides, endSides);
RefPtrWillBeRawPtr<CSSPrimitiveValue> bottom = indexedValueToLength(*lengthBox, 3, startSides, endSides);
return CSSQuadValue::create(top.release(), right.release(), bottom.release(), left.release(), CSSQuadValue::SerializeAsRect);
}
void LengthBoxStyleInterpolation::apply(StyleResolverState& state) const
{
if (m_cachedValue.get()->isBool())
StyleBuilder::applyProperty(m_id, state, toInterpolableBool(m_cachedValue.get())->value() ? m_endCSSValue.get() : m_startCSSValue.get());
else
StyleBuilder::applyProperty(m_id, state, interpolableValueToLengthBox(m_cachedValue.get(), *m_startCSSValue, *m_endCSSValue).get());
}
}