diff options
author | Jocelyn Turcotte <jocelyn.turcotte@digia.com> | 2014-08-08 14:30:41 +0200 |
---|---|---|
committer | Jocelyn Turcotte <jocelyn.turcotte@digia.com> | 2014-08-12 13:49:54 +0200 |
commit | ab0a50979b9eb4dfa3320eff7e187e41efedf7a9 (patch) | |
tree | 498dfb8a97ff3361a9f7486863a52bb4e26bb898 /chromium/third_party/WebKit/Source/core/animation/css | |
parent | 4ce69f7403811819800e7c5ae1318b2647e778d1 (diff) |
Update Chromium to beta version 37.0.2062.68
Change-Id: I188e3b5aff1bec75566014291b654eb19f5bc8ca
Reviewed-by: Andras Becsi <andras.becsi@digia.com>
Diffstat (limited to 'chromium/third_party/WebKit/Source/core/animation/css')
16 files changed, 1193 insertions, 766 deletions
diff --git a/chromium/third_party/WebKit/Source/core/animation/css/CSSAnimatableValueFactory.cpp b/chromium/third_party/WebKit/Source/core/animation/css/CSSAnimatableValueFactory.cpp index 41138cdd177..b401069725e 100644 --- a/chromium/third_party/WebKit/Source/core/animation/css/CSSAnimatableValueFactory.cpp +++ b/chromium/third_party/WebKit/Source/core/animation/css/CSSAnimatableValueFactory.cpp @@ -31,7 +31,7 @@ #include "config.h" #include "core/animation/css/CSSAnimatableValueFactory.h" -#include "CSSValueKeywords.h" +#include "core/CSSValueKeywords.h" #include "core/animation/AnimatableClipPathOperation.h" #include "core/animation/AnimatableColor.h" #include "core/animation/AnimatableDouble.h" @@ -41,6 +41,7 @@ #include "core/animation/AnimatableLengthBox.h" #include "core/animation/AnimatableLengthBoxAndBool.h" #include "core/animation/AnimatableLengthPoint.h" +#include "core/animation/AnimatableLengthPoint3D.h" #include "core/animation/AnimatableLengthSize.h" #include "core/animation/AnimatableRepeatable.h" #include "core/animation/AnimatableSVGLength.h" @@ -61,23 +62,13 @@ namespace WebCore { -static PassRefPtr<AnimatableValue> createFromLength(const Length& length, const RenderStyle& style) +static PassRefPtrWillBeRawPtr<AnimatableValue> createFromLength(const Length& length, const RenderStyle& style) { switch (length.type()) { case Fixed: - return AnimatableLength::create(adjustFloatForAbsoluteZoom(length.value(), style), AnimatableLength::UnitTypePixels); case Percent: - return AnimatableLength::create(length.value(), AnimatableLength::UnitTypePercentage); - case ViewportPercentageWidth: - return AnimatableLength::create(length.value(), AnimatableLength::UnitTypeViewportWidth); - case ViewportPercentageHeight: - return AnimatableLength::create(length.value(), AnimatableLength::UnitTypeViewportHeight); - case ViewportPercentageMin: - return AnimatableLength::create(length.value(), AnimatableLength::UnitTypeViewportMin); - case ViewportPercentageMax: - return AnimatableLength::create(length.value(), AnimatableLength::UnitTypeViewportMax); case Calculated: - return AnimatableLength::create(CSSCalcValue::createExpressionNode(length.calculationValue()->expression(), style.effectiveZoom())); + return AnimatableLength::create(length, style.effectiveZoom()); case Auto: case Intrinsic: case MinIntrinsic: @@ -85,18 +76,20 @@ static PassRefPtr<AnimatableValue> createFromLength(const Length& length, const case MaxContent: case FillAvailable: case FitContent: - return AnimatableUnknown::create(CSSPrimitiveValue::create(length)); + return AnimatableUnknown::create(CSSPrimitiveValue::create(length, 1)); case Undefined: return AnimatableUnknown::create(CSSValueNone); case ExtendToZoom: // Does not apply to elements. + case DeviceWidth: + case DeviceHeight: ASSERT_NOT_REACHED(); - return 0; + return nullptr; } ASSERT_NOT_REACHED(); - return 0; + return nullptr; } -static PassRefPtr<AnimatableValue> createFromLineHeight(const Length& length, const RenderStyle& style) +static PassRefPtrWillBeRawPtr<AnimatableValue> createFromLineHeight(const Length& length, const RenderStyle& style) { if (length.type() == Percent) { double value = length.value(); @@ -108,12 +101,12 @@ static PassRefPtr<AnimatableValue> createFromLineHeight(const Length& length, co return createFromLength(length, style); } -inline static PassRefPtr<AnimatableValue> createFromDouble(double value, AnimatableDouble::Constraint constraint = AnimatableDouble::Unconstrained) +inline static PassRefPtrWillBeRawPtr<AnimatableValue> createFromDouble(double value, AnimatableDouble::Constraint constraint = AnimatableDouble::Unconstrained) { return AnimatableDouble::create(value, constraint); } -inline static PassRefPtr<AnimatableValue> createFromLengthBox(const LengthBox& lengthBox, const RenderStyle& style) +inline static PassRefPtrWillBeRawPtr<AnimatableValue> createFromLengthBox(const LengthBox& lengthBox, const RenderStyle& style) { return AnimatableLengthBox::create( createFromLength(lengthBox.left(), style), @@ -122,14 +115,14 @@ inline static PassRefPtr<AnimatableValue> createFromLengthBox(const LengthBox& l createFromLength(lengthBox.bottom(), style)); } -static PassRefPtr<AnimatableValue> createFromBorderImageLength(const BorderImageLength& borderImageLength, const RenderStyle& style) +static PassRefPtrWillBeRawPtr<AnimatableValue> createFromBorderImageLength(const BorderImageLength& borderImageLength, const RenderStyle& style) { if (borderImageLength.isNumber()) return createFromDouble(borderImageLength.number()); return createFromLength(borderImageLength.length(), style); } -inline static PassRefPtr<AnimatableValue> createFromBorderImageLengthBox(const BorderImageLengthBox& borderImageLengthBox, const RenderStyle& style) +inline static PassRefPtrWillBeRawPtr<AnimatableValue> createFromBorderImageLengthBox(const BorderImageLengthBox& borderImageLengthBox, const RenderStyle& style) { return AnimatableLengthBox::create( createFromBorderImageLength(borderImageLengthBox.left(), style), @@ -138,35 +131,37 @@ inline static PassRefPtr<AnimatableValue> createFromBorderImageLengthBox(const B createFromBorderImageLength(borderImageLengthBox.bottom(), style)); } -inline static PassRefPtr<AnimatableValue> createFromLengthBoxAndBool(const LengthBox lengthBox, const bool flag, const RenderStyle& style) +inline static PassRefPtrWillBeRawPtr<AnimatableValue> createFromLengthBoxAndBool(const LengthBox lengthBox, const bool flag, const RenderStyle& style) { return AnimatableLengthBoxAndBool::create( createFromLengthBox(lengthBox, style), flag); } -inline static PassRefPtr<AnimatableValue> createFromLengthPoint(const LengthPoint& lengthPoint, const RenderStyle& style) +inline static PassRefPtrWillBeRawPtr<AnimatableValue> createFromLengthPoint(const LengthPoint& lengthPoint, const RenderStyle& style) { return AnimatableLengthPoint::create( createFromLength(lengthPoint.x(), style), createFromLength(lengthPoint.y(), style)); } -inline static PassRefPtr<AnimatableValue> createFromLengthSize(const LengthSize& lengthSize, const RenderStyle& style) +inline static PassRefPtrWillBeRawPtr<AnimatableValue> createFromLengthSize(const LengthSize& lengthSize, const RenderStyle& style) { return AnimatableLengthSize::create( createFromLength(lengthSize.width(), style), createFromLength(lengthSize.height(), style)); } -inline static PassRefPtr<AnimatableValue> createFromStyleImage(StyleImage* image) +inline static PassRefPtrWillBeRawPtr<AnimatableValue> createFromStyleImage(StyleImage* image) { - if (image) - return AnimatableImage::create(image); + if (image) { + if (RefPtrWillBeRawPtr<CSSValue> cssValue = image->cssValue()) + return AnimatableImage::create(cssValue.release()); + } return AnimatableUnknown::create(CSSValueNone); } -inline static PassRefPtr<AnimatableValue> createFromFillSize(const FillSize& fillSize, const RenderStyle& style) +inline static PassRefPtrWillBeRawPtr<AnimatableValue> createFromFillSize(const FillSize& fillSize, const RenderStyle& style) { switch (fillSize.type) { case SizeLength: @@ -177,15 +172,22 @@ inline static PassRefPtr<AnimatableValue> createFromFillSize(const FillSize& fil return AnimatableUnknown::create(CSSPrimitiveValue::create(fillSize.type)); default: ASSERT_NOT_REACHED(); - return 0; + return nullptr; } } +inline static PassRefPtrWillBeRawPtr<AnimatableValue> createFromBackgroundPosition(const Length& length, bool originIsSet, BackgroundEdgeOrigin origin, const RenderStyle& style) +{ + if (!originIsSet || origin == LeftEdge || origin == TopEdge) + return createFromLength(length, style); + return createFromLength(length.subtractFromOneHundredPercent(), style); +} + template<CSSPropertyID property> -inline static PassRefPtr<AnimatableValue> createFromFillLayers(const FillLayer* fillLayer, const RenderStyle& style) +inline static PassRefPtrWillBeRawPtr<AnimatableValue> createFromFillLayers(const FillLayer* fillLayer, const RenderStyle& style) { ASSERT(fillLayer); - Vector<RefPtr<AnimatableValue> > values; + WillBeHeapVector<RefPtrWillBeMember<AnimatableValue> > values; while (fillLayer) { if (property == CSSPropertyBackgroundImage || property == CSSPropertyWebkitMaskImage) { if (!fillLayer->isImageSet()) @@ -194,11 +196,11 @@ inline static PassRefPtr<AnimatableValue> createFromFillLayers(const FillLayer* } else if (property == CSSPropertyBackgroundPositionX || property == CSSPropertyWebkitMaskPositionX) { if (!fillLayer->isXPositionSet()) break; - values.append(createFromLength(fillLayer->xPosition(), style)); + values.append(createFromBackgroundPosition(fillLayer->xPosition(), fillLayer->isBackgroundXOriginSet(), fillLayer->backgroundXOrigin(), style)); } else if (property == CSSPropertyBackgroundPositionY || property == CSSPropertyWebkitMaskPositionY) { if (!fillLayer->isYPositionSet()) break; - values.append(createFromLength(fillLayer->yPosition(), style)); + values.append(createFromBackgroundPosition(fillLayer->yPosition(), fillLayer->isBackgroundYOriginSet(), fillLayer->backgroundYOrigin(), style)); } else if (property == CSSPropertyBackgroundSize || property == CSSPropertyWebkitMaskSize) { if (!fillLayer->isSizeSet()) break; @@ -211,42 +213,56 @@ inline static PassRefPtr<AnimatableValue> createFromFillLayers(const FillLayer* return AnimatableRepeatable::create(values); } -PassRefPtr<AnimatableValue> CSSAnimatableValueFactory::createFromColor(CSSPropertyID property, const RenderStyle& style) +PassRefPtrWillBeRawPtr<AnimatableValue> CSSAnimatableValueFactory::createFromColor(CSSPropertyID property, const RenderStyle& style) { Color color = style.colorIncludingFallback(property, false); Color visitedLinkColor = style.colorIncludingFallback(property, true); - Color fallbackColor = style.color(); - Color fallbackVisitedLinkColor = style.visitedLinkColor(); - Color resolvedColor; + return AnimatableColor::create(color, visitedLinkColor); +} + +inline static PassRefPtrWillBeRawPtr<AnimatableValue> createFromShapeValue(ShapeValue* value) +{ + if (value) + return AnimatableShapeValue::create(value); + return AnimatableUnknown::create(CSSValueNone); +} - if (property == CSSPropertyBackgroundColor) { - // For background-color, invalid color means transparent and not currentColor. - fallbackColor = Color::transparent; - fallbackVisitedLinkColor = Color::transparent; +static double fontWeightToDouble(FontWeight fontWeight) +{ + switch (fontWeight) { + case FontWeight100: + return 100; + case FontWeight200: + return 200; + case FontWeight300: + return 300; + case FontWeight400: + return 400; + case FontWeight500: + return 500; + case FontWeight600: + return 600; + case FontWeight700: + return 700; + case FontWeight800: + return 800; + case FontWeight900: + return 900; } - if (color.isValid()) - resolvedColor = color; - else - resolvedColor = fallbackColor; - Color resolvedVisitedLinkColor; - if (visitedLinkColor.isValid()) - resolvedVisitedLinkColor = visitedLinkColor; - else - resolvedVisitedLinkColor = fallbackVisitedLinkColor; - return AnimatableColor::create(resolvedColor, resolvedVisitedLinkColor); + ASSERT_NOT_REACHED(); + return 400; } -inline static PassRefPtr<AnimatableValue> createFromShapeValue(ShapeValue* value) +static PassRefPtrWillBeRawPtr<AnimatableValue> createFromFontWeight(FontWeight fontWeight) { - if (value) - return AnimatableShapeValue::create(value); - return AnimatableUnknown::create(CSSValueAuto); + return createFromDouble(fontWeightToDouble(fontWeight)); } // FIXME: Generate this function. -PassRefPtr<AnimatableValue> CSSAnimatableValueFactory::create(CSSPropertyID property, const RenderStyle& style) +PassRefPtrWillBeRawPtr<AnimatableValue> CSSAnimatableValueFactory::create(CSSPropertyID property, const RenderStyle& style) { + ASSERT(CSSAnimations::isAnimatableProperty(property)); switch (property) { case CSSPropertyBackgroundColor: return createFromColor(property, style); @@ -307,7 +323,10 @@ PassRefPtr<AnimatableValue> CSSAnimatableValueFactory::create(CSSPropertyID prop case CSSPropertyFillOpacity: return createFromDouble(style.fillOpacity()); case CSSPropertyFill: - return AnimatableSVGPaint::create(style.svgStyle()->fillPaintType(), style.svgStyle()->fillPaintColor(), style.svgStyle()->fillPaintUri()); + return AnimatableSVGPaint::create( + style.svgStyle()->fillPaintType(), style.svgStyle()->visitedLinkFillPaintType(), + style.svgStyle()->fillPaintColor(), style.svgStyle()->visitedLinkFillPaintColor(), + style.svgStyle()->fillPaintUri(), style.svgStyle()->visitedLinkFillPaintUri()); case CSSPropertyFlexGrow: return createFromDouble(style.flexGrow(), AnimatableDouble::InterpolationIsNonContinuousWithZero); case CSSPropertyFlexShrink: @@ -324,10 +343,10 @@ PassRefPtr<AnimatableValue> CSSAnimatableValueFactory::create(CSSPropertyID prop // FIXME: Should we introduce an option to pass the computed font size here, allowing consumers to // enable text zoom rather than Text Autosizing? See http://crbug.com/227545. return createFromDouble(style.specifiedFontSize()); + case CSSPropertyFontWeight: + return createFromFontWeight(style.fontWeight()); case CSSPropertyHeight: return createFromLength(style.height(), style); - case CSSPropertyKerning: - return AnimatableSVGLength::create(style.kerning()); case CSSPropertyLightingColor: return createFromColor(property, style); case CSSPropertyListStyleImage: @@ -391,9 +410,12 @@ PassRefPtr<AnimatableValue> CSSAnimatableValueFactory::create(CSSPropertyID prop case CSSPropertyStrokeOpacity: return createFromDouble(style.strokeOpacity()); case CSSPropertyStroke: - return AnimatableSVGPaint::create(style.svgStyle()->strokePaintType(), style.svgStyle()->strokePaintColor(), style.svgStyle()->strokePaintUri()); + return AnimatableSVGPaint::create( + style.svgStyle()->strokePaintType(), style.svgStyle()->visitedLinkStrokePaintType(), + style.svgStyle()->strokePaintColor(), style.svgStyle()->visitedLinkStrokePaintColor(), + style.svgStyle()->strokePaintUri(), style.svgStyle()->visitedLinkStrokePaintUri()); case CSSPropertyTextDecorationColor: - return createFromColor(property, style); + return AnimatableColor::create(style.textDecorationColor().resolve(style.color()), style.visitedLinkTextDecorationColor().resolve(style.visitedLinkColor())); case CSSPropertyTextIndent: return createFromLength(style.textIndent(), style); case CSSPropertyTextShadow: @@ -436,14 +458,19 @@ PassRefPtr<AnimatableValue> CSSAnimatableValueFactory::create(CSSPropertyID prop return createFromFillLayers<CSSPropertyWebkitMaskPositionY>(style.maskLayers(), style); case CSSPropertyWebkitMaskSize: return createFromFillLayers<CSSPropertyWebkitMaskSize>(style.maskLayers(), style); - case CSSPropertyWebkitPerspective: + case CSSPropertyPerspective: return createFromDouble(style.perspective()); + case CSSPropertyPerspectiveOrigin: + ASSERT(RuntimeEnabledFeatures::cssTransformsUnprefixedEnabled()); + return AnimatableLengthPoint::create( + createFromLength(style.perspectiveOriginX(), style), + createFromLength(style.perspectiveOriginY(), style)); case CSSPropertyWebkitPerspectiveOriginX: + ASSERT(!RuntimeEnabledFeatures::cssTransformsUnprefixedEnabled()); return createFromLength(style.perspectiveOriginX(), style); case CSSPropertyWebkitPerspectiveOriginY: + ASSERT(!RuntimeEnabledFeatures::cssTransformsUnprefixedEnabled()); return createFromLength(style.perspectiveOriginY(), style); - case CSSPropertyShapeInside: - return createFromShapeValue(style.shapeInside()); case CSSPropertyShapeOutside: return createFromShapeValue(style.shapeOutside()); case CSSPropertyShapeMargin: @@ -452,13 +479,22 @@ PassRefPtr<AnimatableValue> CSSAnimatableValueFactory::create(CSSPropertyID prop return createFromDouble(style.shapeImageThreshold()); case CSSPropertyWebkitTextStrokeColor: return createFromColor(property, style); - case CSSPropertyWebkitTransform: + case CSSPropertyTransform: return AnimatableTransform::create(style.transform()); + case CSSPropertyTransformOrigin: + ASSERT(RuntimeEnabledFeatures::cssTransformsUnprefixedEnabled()); + return AnimatableLengthPoint3D::create( + createFromLength(style.transformOriginX(), style), + createFromLength(style.transformOriginY(), style), + createFromDouble(style.transformOriginZ())); case CSSPropertyWebkitTransformOriginX: + ASSERT(!RuntimeEnabledFeatures::cssTransformsUnprefixedEnabled()); return createFromLength(style.transformOriginX(), style); case CSSPropertyWebkitTransformOriginY: + ASSERT(!RuntimeEnabledFeatures::cssTransformsUnprefixedEnabled()); return createFromLength(style.transformOriginY(), style); case CSSPropertyWebkitTransformOriginZ: + ASSERT(!RuntimeEnabledFeatures::cssTransformsUnprefixedEnabled()); return createFromDouble(style.transformOriginZ()); case CSSPropertyWidows: return createFromDouble(style.widows()); @@ -466,6 +502,10 @@ PassRefPtr<AnimatableValue> CSSAnimatableValueFactory::create(CSSPropertyID prop return createFromLength(style.width(), style); case CSSPropertyWordSpacing: return createFromDouble(style.wordSpacing()); + case CSSPropertyVerticalAlign: + if (style.verticalAlign() == LENGTH) + return createFromLength(style.verticalAlignLength(), style); + return AnimatableUnknown::create(CSSPrimitiveValue::create(style.verticalAlign())); case CSSPropertyVisibility: return AnimatableVisibility::create(style.visibility()); case CSSPropertyZIndex: @@ -473,10 +513,9 @@ PassRefPtr<AnimatableValue> CSSAnimatableValueFactory::create(CSSPropertyID prop case CSSPropertyZoom: return createFromDouble(style.zoom()); default: - ASSERT_WITH_MESSAGE(!CSSAnimations::isAnimatableProperty(property), "Web Animations not yet implemented: Create AnimatableValue from render style: %s", getPropertyNameString(property).utf8().data()); ASSERT_NOT_REACHED(); // This return value is to avoid a release crash if possible. - return AnimatableUnknown::create(0); + return AnimatableUnknown::create(nullptr); } } diff --git a/chromium/third_party/WebKit/Source/core/animation/css/CSSAnimatableValueFactory.h b/chromium/third_party/WebKit/Source/core/animation/css/CSSAnimatableValueFactory.h index bac18c19241..7e6ea3dc03d 100644 --- a/chromium/third_party/WebKit/Source/core/animation/css/CSSAnimatableValueFactory.h +++ b/chromium/third_party/WebKit/Source/core/animation/css/CSSAnimatableValueFactory.h @@ -31,7 +31,7 @@ #ifndef CSSAnimatableValueFactory_h #define CSSAnimatableValueFactory_h -#include "CSSPropertyNames.h" +#include "core/CSSPropertyNames.h" #include "core/animation/AnimatableValue.h" #include "wtf/PassRefPtr.h" @@ -41,9 +41,9 @@ class RenderStyle; class CSSAnimatableValueFactory { public: - static PassRefPtr<AnimatableValue> create(CSSPropertyID, const RenderStyle&); + static PassRefPtrWillBeRawPtr<AnimatableValue> create(CSSPropertyID, const RenderStyle&); private: - static PassRefPtr<AnimatableValue> createFromColor(CSSPropertyID, const RenderStyle&); + static PassRefPtrWillBeRawPtr<AnimatableValue> createFromColor(CSSPropertyID, const RenderStyle&); }; } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/core/animation/css/CSSAnimationData.cpp b/chromium/third_party/WebKit/Source/core/animation/css/CSSAnimationData.cpp new file mode 100644 index 00000000000..bda53a4f535 --- /dev/null +++ b/chromium/third_party/WebKit/Source/core/animation/css/CSSAnimationData.cpp @@ -0,0 +1,54 @@ +// 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/css/CSSAnimationData.h" + +#include "core/animation/Timing.h" + +namespace WebCore { + +CSSAnimationData::CSSAnimationData() +{ + m_nameList.append(initialName()); + m_iterationCountList.append(initialIterationCount()); + m_directionList.append(initialDirection()); + m_fillModeList.append(initialFillMode()); + m_playStateList.append(initialPlayState()); +} + +CSSAnimationData::CSSAnimationData(const CSSAnimationData& other) + : CSSTimingData(other) + , m_nameList(other.m_nameList) + , m_iterationCountList(other.m_iterationCountList) + , m_directionList(other.m_directionList) + , m_fillModeList(other.m_fillModeList) + , m_playStateList(other.m_playStateList) +{ +} + +const AtomicString& CSSAnimationData::initialName() +{ + DEFINE_STATIC_LOCAL(const AtomicString, name, ("none", AtomicString::ConstructFromLiteral)); + return name; +} + +bool CSSAnimationData::animationsMatchForStyleRecalc(const CSSAnimationData& other) const +{ + return m_nameList == other.m_nameList && m_playStateList == other.m_playStateList; +} + +Timing CSSAnimationData::convertToTiming(size_t index) const +{ + ASSERT(index < m_nameList.size()); + Timing timing = CSSTimingData::convertToTiming(index); + + timing.iterationCount = getRepeated(m_iterationCountList, index); + timing.direction = getRepeated(m_directionList, index); + timing.fillMode = getRepeated(m_fillModeList, index); + timing.assertValid(); + return timing; +} + +} // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/core/animation/css/CSSAnimationData.h b/chromium/third_party/WebKit/Source/core/animation/css/CSSAnimationData.h new file mode 100644 index 00000000000..5a23feedcc4 --- /dev/null +++ b/chromium/third_party/WebKit/Source/core/animation/css/CSSAnimationData.h @@ -0,0 +1,61 @@ +// 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. + +#ifndef CSSAnimationData_h +#define CSSAnimationData_h + +#include "core/animation/Timing.h" +#include "core/animation/css/CSSTimingData.h" +#include "core/rendering/style/RenderStyleConstants.h" + +namespace WebCore { + +class CSSAnimationData FINAL : public CSSTimingData { +public: + static PassOwnPtrWillBeRawPtr<CSSAnimationData> create() + { + return adoptPtrWillBeNoop(new CSSAnimationData); + } + + static PassOwnPtrWillBeRawPtr<CSSAnimationData> create(const CSSAnimationData& animationData) + { + return adoptPtrWillBeNoop(new CSSAnimationData(animationData)); + } + + bool animationsMatchForStyleRecalc(const CSSAnimationData& other) const; + + Timing convertToTiming(size_t index) const; + + const Vector<AtomicString>& nameList() const { return m_nameList; } + const Vector<double>& iterationCountList() const { return m_iterationCountList; } + const Vector<Timing::PlaybackDirection>& directionList() const { return m_directionList; } + const Vector<Timing::FillMode>& fillModeList() const { return m_fillModeList; } + const Vector<EAnimPlayState>& playStateList() const { return m_playStateList; } + + Vector<AtomicString>& nameList() { return m_nameList; } + Vector<double>& iterationCountList() { return m_iterationCountList; } + Vector<Timing::PlaybackDirection>& directionList() { return m_directionList; } + Vector<Timing::FillMode>& fillModeList() { return m_fillModeList; } + Vector<EAnimPlayState>& playStateList() { return m_playStateList; } + + static const AtomicString& initialName(); + static Timing::PlaybackDirection initialDirection() { return Timing::PlaybackDirectionNormal; } + static Timing::FillMode initialFillMode() { return Timing::FillModeNone; } + static double initialIterationCount() { return 1.0; } + static EAnimPlayState initialPlayState() { return AnimPlayStatePlaying; } + +private: + CSSAnimationData(); + explicit CSSAnimationData(const CSSAnimationData&); + + Vector<AtomicString> m_nameList; + Vector<double> m_iterationCountList; + Vector<Timing::PlaybackDirection> m_directionList; + Vector<Timing::FillMode> m_fillModeList; + Vector<EAnimPlayState> m_playStateList; +}; + +} // namespace WebCore + +#endif // CSSAnimationData_h diff --git a/chromium/third_party/WebKit/Source/core/animation/css/CSSAnimations.cpp b/chromium/third_party/WebKit/Source/core/animation/css/CSSAnimations.cpp index 807c59096b5..05e358ec619 100644 --- a/chromium/third_party/WebKit/Source/core/animation/css/CSSAnimations.cpp +++ b/chromium/third_party/WebKit/Source/core/animation/css/CSSAnimations.cpp @@ -31,25 +31,26 @@ #include "config.h" #include "core/animation/css/CSSAnimations.h" -#include "StylePropertyShorthand.h" +#include "core/StylePropertyShorthand.h" #include "core/animation/ActiveAnimations.h" +#include "core/animation/AnimationTimeline.h" #include "core/animation/CompositorAnimations.h" -#include "core/animation/DocumentTimeline.h" -#include "core/animation/KeyframeAnimationEffect.h" +#include "core/animation/KeyframeEffectModel.h" #include "core/animation/css/CSSAnimatableValueFactory.h" +#include "core/animation/css/CSSPropertyEquality.h" +#include "core/animation/interpolation/LegacyStyleInterpolation.h" #include "core/css/CSSKeyframeRule.h" +#include "core/css/resolver/CSSToStyleMap.h" #include "core/css/resolver/StyleResolver.h" #include "core/dom/Element.h" #include "core/dom/PseudoElement.h" -#include "core/events/ThreadLocalEventNames.h" #include "core/events/TransitionEvent.h" #include "core/events/WebKitAnimationEvent.h" #include "core/frame/UseCounter.h" -#include "core/frame/animation/CSSPropertyAnimation.h" -#include "core/platform/animation/CSSAnimationDataList.h" -#include "core/platform/animation/TimingFunction.h" +#include "core/rendering/RenderLayer.h" #include "core/rendering/RenderObject.h" #include "core/rendering/style/KeyframeList.h" +#include "platform/animation/TimingFunction.h" #include "public/platform/Platform.h" #include "wtf/BitArray.h" #include "wtf/HashSet.h" @@ -58,90 +59,81 @@ namespace WebCore { namespace { -bool isEarlierPhase(TimedItem::Phase target, TimedItem::Phase reference) +CSSPropertyID propertyForAnimation(CSSPropertyID property) { - ASSERT(target != TimedItem::PhaseNone); - ASSERT(reference != TimedItem::PhaseNone); - return target < reference; -} - -bool isLaterPhase(TimedItem::Phase target, TimedItem::Phase reference) -{ - ASSERT(target != TimedItem::PhaseNone); - ASSERT(reference != TimedItem::PhaseNone); - return target > reference; -} - -static PassRefPtr<TimingFunction> generateTimingFunction(const KeyframeAnimationEffect::KeyframeVector keyframes, const HashMap<double, RefPtr<TimingFunction> > perKeyframeTimingFunctions) -{ - // Generate the chained timing function. Note that timing functions apply - // from the keyframe in which they're specified to the next keyframe. - bool isTimingFunctionLinearThroughout = true; - RefPtr<ChainedTimingFunction> chainedTimingFunction = ChainedTimingFunction::create(); - for (size_t i = 0; i < keyframes.size() - 1; ++i) { - double lowerBound = keyframes[i]->offset(); - ASSERT(lowerBound >=0 && lowerBound < 1); - double upperBound = keyframes[i + 1]->offset(); - ASSERT(upperBound > 0 && upperBound <= 1); - TimingFunction* timingFunction = perKeyframeTimingFunctions.get(lowerBound); - isTimingFunctionLinearThroughout &= timingFunction->type() == TimingFunction::LinearFunction; - chainedTimingFunction->appendSegment(upperBound, timingFunction); - } - if (isTimingFunctionLinearThroughout) - return LinearTimingFunction::create(); - return chainedTimingFunction; + switch (property) { + case CSSPropertyWebkitPerspective: + return CSSPropertyPerspective; + case CSSPropertyWebkitTransform: + return CSSPropertyTransform; + case CSSPropertyWebkitPerspectiveOriginX: + case CSSPropertyWebkitPerspectiveOriginY: + if (RuntimeEnabledFeatures::cssTransformsUnprefixedEnabled()) + return CSSPropertyPerspectiveOrigin; + break; + case CSSPropertyWebkitTransformOriginX: + case CSSPropertyWebkitTransformOriginY: + case CSSPropertyWebkitTransformOriginZ: + if (RuntimeEnabledFeatures::cssTransformsUnprefixedEnabled()) + return CSSPropertyTransformOrigin; + break; + default: + break; + } + return property; } static void resolveKeyframes(StyleResolver* resolver, Element* element, const Element& parentElement, const RenderStyle& style, RenderStyle* parentStyle, const AtomicString& name, TimingFunction* defaultTimingFunction, - Vector<std::pair<KeyframeAnimationEffect::KeyframeVector, RefPtr<TimingFunction> > >& keyframesAndTimingFunctions) + AnimatableValueKeyframeVector& keyframes) { - ASSERT(RuntimeEnabledFeatures::webAnimationsCSSEnabled()); // When the element is null, use its parent for scoping purposes. const Element* elementForScoping = element ? element : &parentElement; const StyleRuleKeyframes* keyframesRule = CSSAnimations::matchScopedKeyframesRule(resolver, elementForScoping, name.impl()); if (!keyframesRule) return; - const Vector<RefPtr<StyleKeyframe> >& styleKeyframes = keyframesRule->keyframes(); + const WillBeHeapVector<RefPtrWillBeMember<StyleKeyframe> >& styleKeyframes = keyframesRule->keyframes(); if (styleKeyframes.isEmpty()) return; // Construct and populate the style for each keyframe - PropertySet specifiedProperties; - KeyframeAnimationEffect::KeyframeVector keyframes; - HashMap<double, RefPtr<TimingFunction> > perKeyframeTimingFunctions; + PropertySet specifiedPropertiesForUseCounter; for (size_t i = 0; i < styleKeyframes.size(); ++i) { const StyleKeyframe* styleKeyframe = styleKeyframes[i].get(); // It's OK to pass a null element here. RefPtr<RenderStyle> keyframeStyle = resolver->styleForKeyframe(element, style, parentStyle, styleKeyframe, name); - RefPtr<Keyframe> keyframe = Keyframe::create(); + RefPtrWillBeRawPtr<AnimatableValueKeyframe> keyframe = AnimatableValueKeyframe::create(); const Vector<double>& offsets = styleKeyframe->keys(); ASSERT(!offsets.isEmpty()); keyframe->setOffset(offsets[0]); - TimingFunction* timingFunction = defaultTimingFunction; - const StylePropertySet* properties = styleKeyframe->properties(); - for (unsigned j = 0; j < properties->propertyCount(); j++) { - CSSPropertyID property = properties->propertyAt(j).id(); - specifiedProperties.add(property); - if (property == CSSPropertyWebkitAnimationTimingFunction || property == CSSPropertyAnimationTimingFunction) - timingFunction = KeyframeValue::timingFunction(*keyframeStyle); - else if (CSSAnimations::isAnimatableProperty(property)) + keyframe->setEasing(defaultTimingFunction); + const StylePropertySet& properties = styleKeyframe->properties(); + for (unsigned j = 0; j < properties.propertyCount(); j++) { + specifiedPropertiesForUseCounter.add(properties.propertyAt(j).id()); + CSSPropertyID property = propertyForAnimation(properties.propertyAt(j).id()); + if (property == CSSPropertyWebkitAnimationTimingFunction || property == CSSPropertyAnimationTimingFunction) { + CSSValue* value = properties.propertyAt(j).value(); + RefPtr<TimingFunction> timingFunction; + if (value->isInheritedValue() && parentStyle->animations()) + timingFunction = parentStyle->animations()->timingFunctionList()[0]; + else if (value->isInheritedValue() || value->isInitialValue()) + timingFunction = CSSTimingData::initialTimingFunction(); + else + timingFunction = CSSToStyleMap::mapAnimationTimingFunction(toCSSValueList(value)->item(0)); + keyframe->setEasing(timingFunction.release()); + } else if (CSSAnimations::isAnimatableProperty(property)) { keyframe->setPropertyValue(property, CSSAnimatableValueFactory::create(property, *keyframeStyle).get()); + } } keyframes.append(keyframe); // The last keyframe specified at a given offset is used. - perKeyframeTimingFunctions.set(offsets[0], timingFunction); for (size_t j = 1; j < offsets.size(); ++j) { - keyframes.append(keyframe->cloneWithOffset(offsets[j])); - perKeyframeTimingFunctions.set(offsets[j], timingFunction); + keyframes.append(toAnimatableValueKeyframe(keyframe->cloneWithOffset(offsets[j]).get())); } } ASSERT(!keyframes.isEmpty()); - if (!perKeyframeTimingFunctions.contains(0)) - perKeyframeTimingFunctions.set(0, defaultTimingFunction); - - for (PropertySet::const_iterator iter = specifiedProperties.begin(); iter != specifiedProperties.end(); ++iter) { + for (PropertySet::const_iterator iter = specifiedPropertiesForUseCounter.begin(); iter != specifiedPropertiesForUseCounter.end(); ++iter) { const CSSPropertyID property = *iter; ASSERT(property != CSSPropertyInvalid); blink::Platform::current()->histogramSparse("WebCore.Animation.CSSProperties", UseCounter::mapCSSPropertyIdToCSSSampleIdForHistogram(property)); @@ -159,16 +151,18 @@ static void resolveKeyframes(StyleResolver* resolver, Element* element, const El keyframes.shrink(targetIndex + 1); // Add 0% and 100% keyframes if absent. - RefPtr<Keyframe> startKeyframe = keyframes[0]; + RefPtrWillBeRawPtr<AnimatableValueKeyframe> startKeyframe = keyframes[0]; if (startKeyframe->offset()) { - startKeyframe = Keyframe::create(); + startKeyframe = AnimatableValueKeyframe::create(); startKeyframe->setOffset(0); + startKeyframe->setEasing(defaultTimingFunction); keyframes.prepend(startKeyframe); } - RefPtr<Keyframe> endKeyframe = keyframes[keyframes.size() - 1]; + RefPtrWillBeRawPtr<AnimatableValueKeyframe> endKeyframe = keyframes[keyframes.size() - 1]; if (endKeyframe->offset() != 1) { - endKeyframe = Keyframe::create(); + endKeyframe = AnimatableValueKeyframe::create(); endKeyframe->setOffset(1); + endKeyframe->setEasing(defaultTimingFunction); keyframes.append(endKeyframe); } ASSERT(keyframes.size() >= 2); @@ -194,7 +188,7 @@ static void resolveKeyframes(StyleResolver* resolver, Element* element, const El bool endNeedsValue = missingEndValues && !endKeyframeProperties.contains(property); if (!startNeedsValue && !endNeedsValue) continue; - RefPtr<AnimatableValue> snapshotValue = CSSAnimatableValueFactory::create(property, style); + RefPtrWillBeRawPtr<AnimatableValue> snapshotValue = CSSAnimatableValueFactory::create(property, style); if (startNeedsValue) startKeyframe->setPropertyValue(property, snapshotValue.get()); if (endNeedsValue) @@ -203,129 +197,6 @@ static void resolveKeyframes(StyleResolver* resolver, Element* element, const El } ASSERT(startKeyframe->properties().size() == allProperties.size()); ASSERT(endKeyframe->properties().size() == allProperties.size()); - - // Determine how many keyframes specify each property. Note that this must - // be done after we've filled in end keyframes. - typedef HashCountedSet<CSSPropertyID> PropertyCountedSet; - PropertyCountedSet propertyCounts; - for (size_t i = 0; i < numKeyframes; ++i) { - const PropertySet& properties = keyframes[i]->properties(); - for (PropertySet::const_iterator iter = properties.begin(); iter != properties.end(); ++iter) - propertyCounts.add(*iter); - } - - // Split keyframes into groups, where each group contains only keyframes - // which specify all properties used in that group. Each group is animated - // in a separate animation, to allow per-keyframe timing functions to be - // applied correctly. - for (PropertyCountedSet::const_iterator iter = propertyCounts.begin(); iter != propertyCounts.end(); ++iter) { - const CSSPropertyID property = iter->key; - const size_t count = iter->value; - ASSERT(count <= numKeyframes); - if (count == numKeyframes) - continue; - KeyframeAnimationEffect::KeyframeVector splitOutKeyframes; - for (size_t i = 0; i < numKeyframes; i++) { - Keyframe* keyframe = keyframes[i].get(); - if (!keyframe->properties().contains(property)) { - ASSERT(i && i != numKeyframes - 1); - continue; - } - RefPtr<Keyframe> clonedKeyframe = Keyframe::create(); - clonedKeyframe->setOffset(keyframe->offset()); - clonedKeyframe->setComposite(keyframe->composite()); - clonedKeyframe->setPropertyValue(property, keyframe->propertyValue(property)); - splitOutKeyframes.append(clonedKeyframe); - // Note that it's OK if this keyframe ends up having no - // properties. This can only happen when none of the properties - // are specified in all keyframes, in which case we won't animate - // anything with these keyframes. - keyframe->clearPropertyValue(property); - } - ASSERT(!splitOutKeyframes.first()->offset()); - ASSERT(splitOutKeyframes.last()->offset() == 1); -#ifndef NDEBUG - for (size_t j = 0; j < splitOutKeyframes.size(); ++j) - ASSERT(splitOutKeyframes[j]->properties().size() == 1); -#endif - keyframesAndTimingFunctions.append(std::make_pair(splitOutKeyframes, generateTimingFunction(splitOutKeyframes, perKeyframeTimingFunctions))); - } - - unsigned numPropertiesSpecifiedInAllKeyframes = keyframes.first()->properties().size(); -#ifndef NDEBUG - for (size_t i = 1; i < numKeyframes; ++i) - ASSERT(keyframes[i]->properties().size() == numPropertiesSpecifiedInAllKeyframes); -#endif - - // If the animation specifies any keyframes, we always provide at least one - // vector of resolved keyframes, even if no properties are animated. - if (numPropertiesSpecifiedInAllKeyframes || keyframesAndTimingFunctions.isEmpty()) - keyframesAndTimingFunctions.append(std::make_pair(keyframes, generateTimingFunction(keyframes, perKeyframeTimingFunctions))); -} - -// Returns the default timing function. -const PassRefPtr<TimingFunction> timingFromAnimationData(const CSSAnimationData* animationData, Timing& timing, bool& isPaused) -{ - if (animationData->isDelaySet()) - timing.startDelay = animationData->delay(); - if (animationData->isDurationSet()) { - timing.iterationDuration = animationData->duration(); - timing.hasIterationDuration = true; - } - if (animationData->isIterationCountSet()) { - if (animationData->iterationCount() == CSSAnimationData::IterationCountInfinite) - timing.iterationCount = std::numeric_limits<double>::infinity(); - else - timing.iterationCount = animationData->iterationCount(); - } - if (animationData->isFillModeSet()) { - switch (animationData->fillMode()) { - case AnimationFillModeForwards: - timing.fillMode = Timing::FillModeForwards; - break; - case AnimationFillModeBackwards: - timing.fillMode = Timing::FillModeBackwards; - break; - case AnimationFillModeBoth: - timing.fillMode = Timing::FillModeBoth; - break; - case AnimationFillModeNone: - timing.fillMode = Timing::FillModeNone; - break; - default: - ASSERT_NOT_REACHED(); - } - } else { - timing.fillMode = Timing::FillModeNone; - } - if (animationData->isDirectionSet()) { - switch (animationData->direction()) { - case CSSAnimationData::AnimationDirectionNormal: - timing.direction = Timing::PlaybackDirectionNormal; - break; - case CSSAnimationData::AnimationDirectionAlternate: - timing.direction = Timing::PlaybackDirectionAlternate; - break; - case CSSAnimationData::AnimationDirectionReverse: - timing.direction = Timing::PlaybackDirectionReverse; - break; - case CSSAnimationData::AnimationDirectionAlternateReverse: - timing.direction = Timing::PlaybackDirectionAlternateReverse; - break; - default: - ASSERT_NOT_REACHED(); - } - } - - // For CSS, the constraints on the timing properties are tighter than in - // the general case of the Web Animations model. - timing.assertValid(); - ASSERT(!timing.iterationStart); - ASSERT(timing.playbackRate == 1); - ASSERT(timing.iterationDuration >= 0 && std::isfinite(timing.iterationDuration)); - - isPaused = animationData->isPlayStateSet() && animationData->playState() == AnimPlayStatePaused; - return animationData->isTimingFunctionSet() ? animationData->timingFunction() : CSSAnimationData::initialAnimationTimingFunction(); } } // namespace @@ -347,21 +218,32 @@ const StyleRuleKeyframes* CSSAnimations::matchScopedKeyframesRule(StyleResolver* return 0; } -PassOwnPtr<CSSAnimationUpdate> CSSAnimations::calculateUpdate(Element* element, const Element& parentElement, const RenderStyle& style, RenderStyle* parentStyle, StyleResolver* resolver) +CSSAnimations::CSSAnimations() { - ASSERT(RuntimeEnabledFeatures::webAnimationsCSSEnabled()); - OwnPtr<CSSAnimationUpdate> update = adoptPtr(new CSSAnimationUpdate()); +} + +PassOwnPtrWillBeRawPtr<CSSAnimationUpdate> CSSAnimations::calculateUpdate(Element* element, const Element& parentElement, const RenderStyle& style, RenderStyle* parentStyle, StyleResolver* resolver) +{ + OwnPtrWillBeRawPtr<CSSAnimationUpdate> update = adoptPtrWillBeNoop(new CSSAnimationUpdate()); calculateAnimationUpdate(update.get(), element, parentElement, style, parentStyle, resolver); - calculateAnimationCompositableValues(update.get(), element); + calculateAnimationActiveInterpolations(update.get(), element, parentElement.document().timeline().currentTimeInternal()); calculateTransitionUpdate(update.get(), element, style); - calculateTransitionCompositableValues(update.get(), element); + calculateTransitionActiveInterpolations(update.get(), element, parentElement.document().timeline().currentTimeInternal()); return update->isEmpty() ? nullptr : update.release(); } void CSSAnimations::calculateAnimationUpdate(CSSAnimationUpdate* update, Element* element, const Element& parentElement, const RenderStyle& style, RenderStyle* parentStyle, StyleResolver* resolver) { const ActiveAnimations* activeAnimations = element ? element->activeAnimations() : 0; - const CSSAnimationDataList* animationDataList = style.animations(); + +#if !ASSERT_ENABLED + // If we're in an animation style change, no animations can have started, been cancelled or changed play state. + // When ASSERT is enabled, we verify this optimization. + if (activeAnimations && activeAnimations->isAnimationStyleChange()) + return; +#endif + + const CSSAnimationData* animationData = style.animations(); const CSSAnimations* cssAnimations = activeAnimations ? &activeAnimations->cssAnimations() : 0; HashSet<AtomicString> inactive; @@ -370,12 +252,12 @@ void CSSAnimations::calculateAnimationUpdate(CSSAnimationUpdate* update, Element inactive.add(iter->key); if (style.display() != NONE) { - for (size_t i = 0; animationDataList && i < animationDataList->size(); ++i) { - const CSSAnimationData* animationData = animationDataList->animation(i); - if (animationData->isNoneAnimation()) + for (size_t i = 0; animationData && i < animationData->nameList().size(); ++i) { + AtomicString animationName(animationData->nameList()[i]); + if (animationName == CSSAnimationData::initialName()) continue; - ASSERT(animationData->isValidAnimation()); - AtomicString animationName(animationData->name()); + + bool isPaused = CSSTimingData::getRepeated(animationData->playStateList(), i) == AnimPlayStatePaused; // Keyframes and animation properties are snapshotted when the // animation starts, so we don't need to track changes to these, @@ -384,85 +266,76 @@ void CSSAnimations::calculateAnimationUpdate(CSSAnimationUpdate* update, Element AnimationMap::const_iterator existing(cssAnimations->m_animations.find(animationName)); if (existing != cssAnimations->m_animations.end()) { inactive.remove(animationName); - const HashSet<RefPtr<Player> >& players = existing->value; - ASSERT(!players.isEmpty()); - bool isFirstPlayerPaused = (*players.begin())->paused(); -#ifndef NDEBUG - for (HashSet<RefPtr<Player> >::const_iterator iter = players.begin(); iter != players.end(); ++iter) - ASSERT((*iter)->paused() == isFirstPlayerPaused); -#endif - if ((animationData->playState() == AnimPlayStatePaused) != isFirstPlayerPaused) + AnimationPlayer* player = existing->value.get(); + if (isPaused != player->paused()) { + ASSERT(!activeAnimations || !activeAnimations->isAnimationStyleChange()); update->toggleAnimationPaused(animationName); + } continue; } } - Timing timing; - bool isPaused; - RefPtr<TimingFunction> defaultTimingFunction = timingFromAnimationData(animationData, timing, isPaused); - Vector<std::pair<KeyframeAnimationEffect::KeyframeVector, RefPtr<TimingFunction> > > keyframesAndTimingFunctions; - resolveKeyframes(resolver, element, parentElement, style, parentStyle, animationName, defaultTimingFunction.get(), keyframesAndTimingFunctions); - if (!keyframesAndTimingFunctions.isEmpty()) { - HashSet<RefPtr<InertAnimation> > animations; - for (size_t j = 0; j < keyframesAndTimingFunctions.size(); ++j) { - ASSERT(!keyframesAndTimingFunctions[j].first.isEmpty()); - timing.timingFunction = keyframesAndTimingFunctions[j].second; - // FIXME: crbug.com/268791 - Keyframes are already normalized, perhaps there should be a flag on KeyframeAnimationEffect to skip normalization. - animations.add(InertAnimation::create(KeyframeAnimationEffect::create(keyframesAndTimingFunctions[j].first), timing, isPaused)); - } - update->startAnimation(animationName, animations); + Timing timing = animationData->convertToTiming(i); + RefPtr<TimingFunction> keyframeTimingFunction = timing.timingFunction; + timing.timingFunction = Timing::defaults().timingFunction; + AnimatableValueKeyframeVector resolvedKeyframes; + resolveKeyframes(resolver, element, parentElement, style, parentStyle, animationName, keyframeTimingFunction.get(), resolvedKeyframes); + if (!resolvedKeyframes.isEmpty()) { + ASSERT(!activeAnimations || !activeAnimations->isAnimationStyleChange()); + update->startAnimation(animationName, InertAnimation::create(AnimatableValueKeyframeEffectModel::create(resolvedKeyframes), timing, isPaused)); } } } ASSERT(inactive.isEmpty() || cssAnimations); - for (HashSet<AtomicString>::const_iterator iter = inactive.begin(); iter != inactive.end(); ++iter) - update->cancelAnimation(*iter, cssAnimations->m_animations.get(*iter)); + for (HashSet<AtomicString>::const_iterator iter = inactive.begin(); iter != inactive.end(); ++iter) { + ASSERT(!activeAnimations || !activeAnimations->isAnimationStyleChange()); + update->cancelAnimation(*iter, *cssAnimations->m_animations.get(*iter)); + } } void CSSAnimations::maybeApplyPendingUpdate(Element* element) { if (!m_pendingUpdate) { - m_previousCompositableValuesForAnimations.clear(); + m_previousActiveInterpolationsForAnimations.clear(); return; } - OwnPtr<CSSAnimationUpdate> update = m_pendingUpdate.release(); + OwnPtrWillBeRawPtr<CSSAnimationUpdate> update = m_pendingUpdate.release(); + + m_previousActiveInterpolationsForAnimations.swap(update->activeInterpolationsForAnimations()); - m_previousCompositableValuesForAnimations.swap(update->compositableValuesForAnimations()); + // FIXME: cancelling, pausing, unpausing animations all query compositingState, which is not necessarily up to date here + // since we call this from recalc style. + // https://code.google.com/p/chromium/issues/detail?id=339847 + DisableCompositingQueryAsserts disabler; for (Vector<AtomicString>::const_iterator iter = update->cancelledAnimationNames().begin(); iter != update->cancelledAnimationNames().end(); ++iter) { - const HashSet<RefPtr<Player> >& players = m_animations.take(*iter); - for (HashSet<RefPtr<Player> >::const_iterator iter = players.begin(); iter != players.end(); ++iter) - (*iter)->cancel(); + RefPtr<AnimationPlayer> player = m_animations.take(*iter); + player->cancel(); + player->update(TimingUpdateOnDemand); } for (Vector<AtomicString>::const_iterator iter = update->animationsWithPauseToggled().begin(); iter != update->animationsWithPauseToggled().end(); ++iter) { - const HashSet<RefPtr<Player> >& players = m_animations.get(*iter); - ASSERT(!players.isEmpty()); - bool isFirstPlayerPaused = (*players.begin())->paused(); - for (HashSet<RefPtr<Player> >::const_iterator iter = players.begin(); iter != players.end(); ++iter) { - Player* player = iter->get(); - ASSERT(player->paused() == isFirstPlayerPaused); - player->setPaused(!isFirstPlayerPaused); - } + AnimationPlayer* player = m_animations.get(*iter); + if (player->paused()) + player->unpause(); + else + player->pause(); + if (player->outdated()) + player->update(TimingUpdateOnDemand); } - for (Vector<CSSAnimationUpdate::NewAnimation>::const_iterator iter = update->newAnimations().begin(); iter != update->newAnimations().end(); ++iter) { + for (WillBeHeapVector<CSSAnimationUpdate::NewAnimation>::const_iterator iter = update->newAnimations().begin(); iter != update->newAnimations().end(); ++iter) { + const InertAnimation* inertAnimation = iter->animation.get(); OwnPtr<AnimationEventDelegate> eventDelegate = adoptPtr(new AnimationEventDelegate(element, iter->name)); - HashSet<RefPtr<Player> > players; - for (HashSet<RefPtr<InertAnimation> >::const_iterator animationsIter = iter->animations.begin(); animationsIter != iter->animations.end(); ++animationsIter) { - const InertAnimation* inertAnimation = animationsIter->get(); - // The event delegate is set on the the first animation only. We - // rely on the behavior of OwnPtr::release() to achieve this. - RefPtr<Animation> animation = Animation::create(element, inertAnimation->effect(), inertAnimation->specified(), Animation::DefaultPriority, eventDelegate.release()); - Player* player = element->document().timeline()->createPlayer(animation.get()); - player->setPaused(inertAnimation->paused()); - element->document().cssPendingAnimations().add(player); - player->update(); - players.add(player); - } - m_animations.set(iter->name, players); + RefPtrWillBeRawPtr<Animation> animation = Animation::create(element, inertAnimation->effect(), inertAnimation->specifiedTiming(), Animation::DefaultPriority, eventDelegate.release()); + RefPtrWillBeRawPtr<AnimationPlayer> player = element->document().timeline().createAnimationPlayer(animation.get()); + element->document().compositorPendingAnimations().add(player.get()); + if (inertAnimation->paused()) + player->pause(); + player->update(TimingUpdateOnDemand); + m_animations.set(iter->name, player.get()); } // Transitions that are run on the compositor only update main-thread state @@ -470,15 +343,17 @@ void CSSAnimations::maybeApplyPendingUpdate(Element* element) // be when transitions are retargeted. Instead of triggering complete style // recalculation, we find these cases by searching for new transitions that // have matching cancelled animation property IDs on the compositor. - HashMap<CSSPropertyID, std::pair<RefPtr<Animation>, double> > retargetedCompositorTransitions; - const ActiveAnimations* activeAnimations = element->activeAnimations(); + WillBeHeapHashMap<CSSPropertyID, std::pair<RefPtrWillBeMember<Animation>, double> > retargetedCompositorTransitions; for (HashSet<CSSPropertyID>::iterator iter = update->cancelledTransitions().begin(); iter != update->cancelledTransitions().end(); ++iter) { CSSPropertyID id = *iter; ASSERT(m_transitions.contains(id)); - Player* player = m_transitions.take(id).transition->player(); - if (activeAnimations && activeAnimations->hasActiveAnimationsOnCompositor(id) && update->newTransitions().find(id) != update->newTransitions().end()) - retargetedCompositorTransitions.add(id, std::pair<RefPtr<Animation>, double>(toAnimation(player->source()), player->startTime())); + + RefPtrWillBeRawPtr<AnimationPlayer> player = m_transitions.take(id).player; + Animation* animation = toAnimation(player->source()); + if (animation->hasActiveAnimationsOnCompositor(id) && update->newTransitions().find(id) != update->newTransitions().end()) + retargetedCompositorTransitions.add(id, std::pair<RefPtrWillBeMember<Animation>, double>(animation, player->startTimeInternal())); player->cancel(); + player->update(TimingUpdateOnDemand); } for (CSSAnimationUpdate::NewTransitionMap::const_iterator iter = update->newTransitions().begin(); iter != update->newTransitions().end(); ++iter) { @@ -490,42 +365,46 @@ void CSSAnimations::maybeApplyPendingUpdate(Element* element) CSSPropertyID id = newTransition.id; InertAnimation* inertAnimation = newTransition.animation.get(); - OwnPtr<TransitionEventDelegate> eventDelegate = adoptPtr(new TransitionEventDelegate(element, id)); + OwnPtr<TransitionEventDelegate> eventDelegate = adoptPtr(new TransitionEventDelegate(element, newTransition.eventId)); - RefPtr<AnimationEffect> effect = inertAnimation->effect(); + RefPtrWillBeRawPtr<AnimationEffect> effect = inertAnimation->effect(); if (retargetedCompositorTransitions.contains(id)) { - const std::pair<RefPtr<Animation>, double>& oldTransition = retargetedCompositorTransitions.get(id); - RefPtr<Animation> oldAnimation = oldTransition.first; + const std::pair<RefPtrWillBeMember<Animation>, double>& oldTransition = retargetedCompositorTransitions.get(id); + RefPtrWillBeRawPtr<Animation> oldAnimation = oldTransition.first; double oldStartTime = oldTransition.second; - double inheritedTime = isNull(oldStartTime) ? 0 : element->document().transitionTimeline()->currentTime() - oldStartTime; - oldAnimation->updateInheritedTime(inheritedTime); - KeyframeAnimationEffect* oldEffect = toKeyframeAnimationEffect(inertAnimation->effect()); - const KeyframeAnimationEffect::KeyframeVector& frames = oldEffect->getFrames(); - KeyframeAnimationEffect::KeyframeVector newFrames; - newFrames.append(frames[0]->clone()); + double inheritedTime = isNull(oldStartTime) ? 0 : element->document().timeline().currentTimeInternal() - oldStartTime; + + AnimatableValueKeyframeEffectModel* oldEffect = toAnimatableValueKeyframeEffectModel(inertAnimation->effect()); + const KeyframeVector& frames = oldEffect->getFrames(); + + AnimatableValueKeyframeVector newFrames; + newFrames.append(toAnimatableValueKeyframe(frames[0]->clone().get())); + newFrames.append(toAnimatableValueKeyframe(frames[1]->clone().get())); + newFrames[0]->clearPropertyValue(id); - ASSERT(oldAnimation->compositableValues()->size() == 1); - const AnimationEffect::CompositableValue* compositableValue = oldAnimation->compositableValues()->at(0).second.get(); - ASSERT(!compositableValue->dependsOnUnderlyingValue()); - newFrames[0]->setPropertyValue(id, compositableValue->compositeOnto(0).get()); - newFrames.append(frames[1]->clone()); - effect = KeyframeAnimationEffect::create(newFrames); + RefPtrWillBeRawPtr<InertAnimation> inertAnimationForSampling = InertAnimation::create(oldAnimation->effect(), oldAnimation->specifiedTiming(), false); + OwnPtrWillBeRawPtr<WillBeHeapVector<RefPtrWillBeMember<Interpolation> > > sample = inertAnimationForSampling->sample(inheritedTime); + ASSERT(sample->size() == 1); + newFrames[0]->setPropertyValue(id, toLegacyStyleInterpolation(sample->at(0).get())->currentValue()); + + effect = AnimatableValueKeyframeEffectModel::create(newFrames); } - RefPtr<Animation> transition = Animation::create(element, effect, inertAnimation->specified(), Animation::TransitionPriority, eventDelegate.release()); - RefPtr<Player> player = element->document().transitionTimeline()->createPlayer(transition.get()); - player->update(); - element->document().cssPendingAnimations().add(player.get()); - runningTransition.transition = transition.get(); + + RefPtrWillBeRawPtr<Animation> transition = Animation::create(element, effect, inertAnimation->specifiedTiming(), Animation::TransitionPriority, eventDelegate.release()); + RefPtrWillBeRawPtr<AnimationPlayer> player = element->document().timeline().createAnimationPlayer(transition.get()); + element->document().compositorPendingAnimations().add(player.get()); + player->update(TimingUpdateOnDemand); + runningTransition.player = player; m_transitions.set(id, runningTransition); ASSERT(id != CSSPropertyInvalid); blink::Platform::current()->histogramSparse("WebCore.Animation.CSSProperties", UseCounter::mapCSSPropertyIdToCSSSampleIdForHistogram(id)); } } -void CSSAnimations::calculateTransitionUpdateForProperty(CSSPropertyID id, const CSSAnimationData* anim, const RenderStyle& oldStyle, const RenderStyle& style, const TransitionMap* activeTransitions, CSSAnimationUpdate* update, const Element* element) +void CSSAnimations::calculateTransitionUpdateForProperty(CSSPropertyID id, CSSPropertyID eventId, const CSSTransitionData& transitionData, size_t transitionIndex, const RenderStyle& oldStyle, const RenderStyle& style, const TransitionMap* activeTransitions, CSSAnimationUpdate* update, const Element* element) { - RefPtr<AnimatableValue> to; + RefPtrWillBeRawPtr<AnimatableValue> to = nullptr; if (activeTransitions) { TransitionMap::const_iterator activeTransitionIter = activeTransitions->find(id); if (activeTransitionIter != activeTransitions->end()) { @@ -538,44 +417,37 @@ void CSSAnimations::calculateTransitionUpdateForProperty(CSSPropertyID id, const } } - if (anim->duration() + anim->delay() <= 0) + if (CSSPropertyEquality::propertiesEqual(id, oldStyle, style)) return; - - if (CSSPropertyAnimation::propertiesEqual(id, &oldStyle, &style)) - return; - if (!to) to = CSSAnimatableValueFactory::create(id, style); - RefPtr<AnimatableValue> from = CSSAnimatableValueFactory::create(id, oldStyle); + RefPtrWillBeRawPtr<AnimatableValue> from = CSSAnimatableValueFactory::create(id, oldStyle); // If we have multiple transitions on the same property, we will use the // last one since we iterate over them in order. - if (!from->usesNonDefaultInterpolationWith(to.get())) + if (AnimatableValue::usesDefaultInterpolation(to.get(), from.get())) + return; + + Timing timing = transitionData.convertToTiming(transitionIndex); + if (timing.startDelay + timing.iterationDuration <= 0) return; - KeyframeAnimationEffect::KeyframeVector keyframes; + AnimatableValueKeyframeVector keyframes; - RefPtr<Keyframe> startKeyframe = Keyframe::create(); + RefPtrWillBeRawPtr<AnimatableValueKeyframe> startKeyframe = AnimatableValueKeyframe::create(); startKeyframe->setPropertyValue(id, from.get()); startKeyframe->setOffset(0); + startKeyframe->setEasing(timing.timingFunction.release()); + timing.timingFunction = LinearTimingFunction::shared(); keyframes.append(startKeyframe); - RefPtr<Keyframe> endKeyframe = Keyframe::create(); + RefPtrWillBeRawPtr<AnimatableValueKeyframe> endKeyframe = AnimatableValueKeyframe::create(); endKeyframe->setPropertyValue(id, to.get()); endKeyframe->setOffset(1); keyframes.append(endKeyframe); - RefPtr<KeyframeAnimationEffect> effect = KeyframeAnimationEffect::create(keyframes); - - Timing timing; - bool isPaused; - RefPtr<TimingFunction> timingFunction = timingFromAnimationData(anim, timing, isPaused); - ASSERT(!isPaused); - timing.timingFunction = timingFunction; - // Note that the backwards part is required for delay to work. - timing.fillMode = Timing::FillModeBoth; - - update->startTransition(id, from.get(), to.get(), InertAnimation::create(effect, timing, isPaused)); + RefPtrWillBeRawPtr<AnimatableValueKeyframeEffectModel> effect = AnimatableValueKeyframeEffectModel::create(keyframes); + update->startTransition(id, eventId, from.get(), to.get(), InertAnimation::create(effect, timing, false)); ASSERT(!element->activeAnimations() || !element->activeAnimations()->isAnimationStyleChange()); } @@ -586,37 +458,41 @@ void CSSAnimations::calculateTransitionUpdate(CSSAnimationUpdate* update, const ActiveAnimations* activeAnimations = element->activeAnimations(); const TransitionMap* activeTransitions = activeAnimations ? &activeAnimations->cssAnimations().m_transitions : 0; + const CSSTransitionData* transitionData = style.transitions(); -#if ASSERT_DISABLED - // In release builds we avoid the cost of checking for new and interrupted transitions if the style recalc is due to animation. - const bool animationStyleRecalc = activeAnimations && activeAnimations->isAnimationStyleChange(); -#else +#if ASSERT_ENABLED // In debug builds we verify that it would have been safe to avoid populating and testing listedProperties if the style recalc is due to animation. const bool animationStyleRecalc = false; +#else + // In release builds we avoid the cost of checking for new and interrupted transitions if the style recalc is due to animation. + const bool animationStyleRecalc = activeAnimations && activeAnimations->isAnimationStyleChange(); #endif BitArray<numCSSProperties> listedProperties; - bool anyTransitionHadAnimateAll = false; + bool anyTransitionHadTransitionAll = false; const RenderObject* renderer = element->renderer(); - if (!animationStyleRecalc && style.display() != NONE && renderer && renderer->style() && style.transitions()) { + if (!animationStyleRecalc && style.display() != NONE && renderer && renderer->style() && transitionData) { const RenderStyle& oldStyle = *renderer->style(); - for (size_t i = 0; i < style.transitions()->size(); ++i) { - const CSSAnimationData* anim = style.transitions()->animation(i); - CSSAnimationData::AnimationMode mode = anim->animationMode(); - if (mode == CSSAnimationData::AnimateNone) + for (size_t i = 0; i < transitionData->propertyList().size(); ++i) { + const CSSTransitionData::TransitionProperty& transitionProperty = transitionData->propertyList()[i]; + CSSTransitionData::TransitionPropertyType mode = transitionProperty.propertyType; + CSSPropertyID property = transitionProperty.propertyId; + if (mode == CSSTransitionData::TransitionNone || mode == CSSTransitionData::TransitionUnknown) continue; - bool animateAll = mode == CSSAnimationData::AnimateAll; - ASSERT(animateAll || mode == CSSAnimationData::AnimateSingleProperty); + bool animateAll = mode == CSSTransitionData::TransitionAll; + ASSERT(animateAll || mode == CSSTransitionData::TransitionSingleProperty); if (animateAll) - anyTransitionHadAnimateAll = true; - const StylePropertyShorthand& propertyList = animateAll ? CSSAnimations::animatableProperties() : shorthandForProperty(anim->property()); + anyTransitionHadTransitionAll = true; + const StylePropertyShorthand& propertyList = animateAll ? CSSAnimations::animatableProperties() : shorthandForProperty(property); // If not a shorthand we only execute one iteration of this loop, and refer to the property directly. for (unsigned j = 0; !j || j < propertyList.length(); ++j) { - CSSPropertyID id = propertyList.length() ? propertyList.properties()[j] : anim->property(); + CSSPropertyID id = propertyList.length() ? propertyList.properties()[j] : property; + CSSPropertyID eventId = id; if (!animateAll) { + id = propertyForAnimation(id); if (CSSAnimations::isAnimatableProperty(id)) listedProperties.set(id); else @@ -625,9 +501,9 @@ void CSSAnimations::calculateTransitionUpdate(CSSAnimationUpdate* update, const // FIXME: We should transition if an !important property changes even when an animation is running, // but this is a bit hard to do with the current applyMatchedProperties system. - if (!update->compositableValuesForAnimations().contains(id) - && (!activeAnimations || !activeAnimations->cssAnimations().m_previousCompositableValuesForAnimations.contains(id))) { - calculateTransitionUpdateForProperty(id, anim, oldStyle, style, activeTransitions, update, element); + if (!update->activeInterpolationsForAnimations().contains(id) + && (!activeAnimations || !activeAnimations->cssAnimations().m_previousActiveInterpolationsForAnimations.contains(id))) { + calculateTransitionUpdateForProperty(id, eventId, *transitionData, i, oldStyle, style, activeTransitions, update, element); } } } @@ -635,10 +511,11 @@ void CSSAnimations::calculateTransitionUpdate(CSSAnimationUpdate* update, const if (activeTransitions) { for (TransitionMap::const_iterator iter = activeTransitions->begin(); iter != activeTransitions->end(); ++iter) { - const TimedItem* timedItem = iter->value.transition; + const AnimationPlayer& player = *iter->value.player; CSSPropertyID id = iter->key; - if (timedItem->phase() == TimedItem::PhaseAfter || (!anyTransitionHadAnimateAll && !animationStyleRecalc && !listedProperties.get(id))) { - ASSERT(timedItem->phase() == TimedItem::PhaseAfter || !(activeAnimations && activeAnimations->isAnimationStyleChange())); + if (player.finishedInternal() || (!anyTransitionHadTransitionAll && !animationStyleRecalc && !listedProperties.get(id))) { + // TODO: Figure out why this fails on Chrome OS login page. crbug.com/365507 + // ASSERT(player.finishedInternal() || !(activeAnimations && activeAnimations->isAnimationStyleChange())); update->cancelTransition(id); } } @@ -648,130 +525,129 @@ void CSSAnimations::calculateTransitionUpdate(CSSAnimationUpdate* update, const void CSSAnimations::cancel() { for (AnimationMap::iterator iter = m_animations.begin(); iter != m_animations.end(); ++iter) { - const HashSet<RefPtr<Player> >& players = iter->value; - for (HashSet<RefPtr<Player> >::const_iterator animationsIter = players.begin(); animationsIter != players.end(); ++animationsIter) - (*animationsIter)->cancel(); + iter->value->cancel(); + iter->value->update(TimingUpdateOnDemand); } - for (TransitionMap::iterator iter = m_transitions.begin(); iter != m_transitions.end(); ++iter) - iter->value.transition->player()->cancel(); + for (TransitionMap::iterator iter = m_transitions.begin(); iter != m_transitions.end(); ++iter) { + iter->value.player->cancel(); + iter->value.player->update(TimingUpdateOnDemand); + } m_animations.clear(); m_transitions.clear(); m_pendingUpdate = nullptr; } -void CSSAnimations::calculateAnimationCompositableValues(CSSAnimationUpdate* update, const Element* element) +void CSSAnimations::calculateAnimationActiveInterpolations(CSSAnimationUpdate* update, const Element* element, double timelineCurrentTime) { ActiveAnimations* activeAnimations = element ? element->activeAnimations() : 0; AnimationStack* animationStack = activeAnimations ? &activeAnimations->defaultStack() : 0; - if (update->newAnimations().isEmpty() && update->cancelledAnimationPlayers().isEmpty()) { - AnimationEffect::CompositableValueMap compositableValuesForAnimations(AnimationStack::compositableValues(animationStack, 0, 0, Animation::DefaultPriority)); - update->adoptCompositableValuesForAnimations(compositableValuesForAnimations); + if (update->newAnimations().isEmpty() && update->cancelledAnimationAnimationPlayers().isEmpty()) { + WillBeHeapHashMap<CSSPropertyID, RefPtrWillBeMember<Interpolation> > activeInterpolationsForAnimations(AnimationStack::activeInterpolations(animationStack, 0, 0, Animation::DefaultPriority, timelineCurrentTime)); + update->adoptActiveInterpolationsForAnimations(activeInterpolationsForAnimations); return; } - Vector<InertAnimation*> newAnimations; + WillBeHeapVector<RawPtrWillBeMember<InertAnimation> > newAnimations; for (size_t i = 0; i < update->newAnimations().size(); ++i) { - HashSet<RefPtr<InertAnimation> > animations = update->newAnimations()[i].animations; - for (HashSet<RefPtr<InertAnimation> >::const_iterator animationsIter = animations.begin(); animationsIter != animations.end(); ++animationsIter) - newAnimations.append(animationsIter->get()); + newAnimations.append(update->newAnimations()[i].animation.get()); } - AnimationEffect::CompositableValueMap compositableValuesForAnimations(AnimationStack::compositableValues(animationStack, &newAnimations, &update->cancelledAnimationPlayers(), Animation::DefaultPriority)); - update->adoptCompositableValuesForAnimations(compositableValuesForAnimations); + WillBeHeapHashMap<CSSPropertyID, RefPtrWillBeMember<Interpolation> > activeInterpolationsForAnimations(AnimationStack::activeInterpolations(animationStack, &newAnimations, &update->cancelledAnimationAnimationPlayers(), Animation::DefaultPriority, timelineCurrentTime)); + update->adoptActiveInterpolationsForAnimations(activeInterpolationsForAnimations); } -void CSSAnimations::calculateTransitionCompositableValues(CSSAnimationUpdate* update, const Element* element) +void CSSAnimations::calculateTransitionActiveInterpolations(CSSAnimationUpdate* update, const Element* element, double timelineCurrentTime) { ActiveAnimations* activeAnimations = element ? element->activeAnimations() : 0; AnimationStack* animationStack = activeAnimations ? &activeAnimations->defaultStack() : 0; - AnimationEffect::CompositableValueMap compositableValuesForTransitions; + WillBeHeapHashMap<CSSPropertyID, RefPtrWillBeMember<Interpolation> > activeInterpolationsForTransitions; if (update->newTransitions().isEmpty() && update->cancelledTransitions().isEmpty()) { - compositableValuesForTransitions = AnimationStack::compositableValues(animationStack, 0, 0, Animation::TransitionPriority); + activeInterpolationsForTransitions = AnimationStack::activeInterpolations(animationStack, 0, 0, Animation::TransitionPriority, timelineCurrentTime); } else { - Vector<InertAnimation*> newTransitions; + WillBeHeapVector<RawPtrWillBeMember<InertAnimation> > newTransitions; for (CSSAnimationUpdate::NewTransitionMap::const_iterator iter = update->newTransitions().begin(); iter != update->newTransitions().end(); ++iter) newTransitions.append(iter->value.animation.get()); - HashSet<const Player*> cancelledPlayers; + WillBeHeapHashSet<RawPtrWillBeMember<const AnimationPlayer> > cancelledAnimationPlayers; if (!update->cancelledTransitions().isEmpty()) { ASSERT(activeAnimations); const TransitionMap& transitionMap = activeAnimations->cssAnimations().m_transitions; for (HashSet<CSSPropertyID>::iterator iter = update->cancelledTransitions().begin(); iter != update->cancelledTransitions().end(); ++iter) { ASSERT(transitionMap.contains(*iter)); - cancelledPlayers.add(transitionMap.get(*iter).transition->player()); + cancelledAnimationPlayers.add(transitionMap.get(*iter).player.get()); } } - compositableValuesForTransitions = AnimationStack::compositableValues(animationStack, &newTransitions, &cancelledPlayers, Animation::TransitionPriority); + activeInterpolationsForTransitions = AnimationStack::activeInterpolations(animationStack, &newTransitions, &cancelledAnimationPlayers, Animation::TransitionPriority, timelineCurrentTime); } // Properties being animated by animations don't get values from transitions applied. - if (!update->compositableValuesForAnimations().isEmpty() && !compositableValuesForTransitions.isEmpty()) { - for (AnimationEffect::CompositableValueMap::const_iterator iter = update->compositableValuesForAnimations().begin(); iter != update->compositableValuesForAnimations().end(); ++iter) - compositableValuesForTransitions.remove(iter->key); + if (!update->activeInterpolationsForAnimations().isEmpty() && !activeInterpolationsForTransitions.isEmpty()) { + for (WillBeHeapHashMap<CSSPropertyID, RefPtrWillBeMember<Interpolation> >::const_iterator iter = update->activeInterpolationsForAnimations().begin(); iter != update->activeInterpolationsForAnimations().end(); ++iter) + activeInterpolationsForTransitions.remove(iter->key); } - update->adoptCompositableValuesForTransitions(compositableValuesForTransitions); + update->adoptActiveInterpolationsForTransitions(activeInterpolationsForTransitions); } void CSSAnimations::AnimationEventDelegate::maybeDispatch(Document::ListenerType listenerType, const AtomicString& eventName, double elapsedTime) { - if (m_target->document().hasListenerType(listenerType)) - m_target->document().timeline()->addEventToDispatch(m_target, WebKitAnimationEvent::create(eventName, m_name, elapsedTime)); + if (m_target->document().hasListenerType(listenerType)) { + RefPtrWillBeRawPtr<WebKitAnimationEvent> event = WebKitAnimationEvent::create(eventName, m_name, elapsedTime); + event->setTarget(m_target); + m_target->document().enqueueAnimationFrameEvent(event); + } } -void CSSAnimations::AnimationEventDelegate::onEventCondition(const TimedItem* timedItem, bool isFirstSample, TimedItem::Phase previousPhase, double previousIteration) +void CSSAnimations::AnimationEventDelegate::onEventCondition(const AnimationNode* animationNode) { - // Events for a single document are queued and dispatched as a group at - // the end of DocumentTimeline::serviceAnimations. - // FIXME: Events which are queued outside of serviceAnimations should - // trigger a timer to dispatch when control is released. - const TimedItem::Phase currentPhase = timedItem->phase(); - const double currentIteration = timedItem->currentIteration(); - - // Note that the elapsedTime is measured from when the animation starts playing. - if (!isFirstSample && previousPhase == TimedItem::PhaseActive && currentPhase == TimedItem::PhaseActive && previousIteration != currentIteration) { - ASSERT(!isNull(previousIteration)); - ASSERT(!isNull(currentIteration)); + const AnimationNode::Phase currentPhase = animationNode->phase(); + const double currentIteration = animationNode->currentIteration(); + + if (m_previousPhase != currentPhase + && (currentPhase == AnimationNode::PhaseActive || currentPhase == AnimationNode::PhaseAfter) + && (m_previousPhase == AnimationNode::PhaseNone || m_previousPhase == AnimationNode::PhaseBefore)) { + // The spec states that the elapsed time should be + // 'delay < 0 ? -delay : 0', but we always use 0 to match the existing + // implementation. See crbug.com/279611 + maybeDispatch(Document::ANIMATIONSTART_LISTENER, EventTypeNames::animationstart, 0); + } + + if (currentPhase == AnimationNode::PhaseActive && m_previousPhase == currentPhase && m_previousIteration != currentIteration) { // We fire only a single event for all iterations thast terminate // between a single pair of samples. See http://crbug.com/275263. For // compatibility with the existing implementation, this event uses // the elapsedTime for the first iteration in question. - ASSERT(timedItem->specified().hasIterationDuration); - const double elapsedTime = timedItem->specified().iterationDuration * (previousIteration + 1); + ASSERT(!std::isnan(animationNode->specifiedTiming().iterationDuration)); + const double elapsedTime = animationNode->specifiedTiming().iterationDuration * (m_previousIteration + 1); maybeDispatch(Document::ANIMATIONITERATION_LISTENER, EventTypeNames::animationiteration, elapsedTime); - return; } - if ((isFirstSample || previousPhase == TimedItem::PhaseBefore) && isLaterPhase(currentPhase, TimedItem::PhaseBefore)) { - ASSERT(timedItem->specified().startDelay > 0 || isFirstSample); - // The spec states that the elapsed time should be - // 'delay < 0 ? -delay : 0', but we always use 0 to match the existing - // implementation. See crbug.com/279611 - maybeDispatch(Document::ANIMATIONSTART_LISTENER, EventTypeNames::animationstart, 0); - } - if ((isFirstSample || isEarlierPhase(previousPhase, TimedItem::PhaseAfter)) && currentPhase == TimedItem::PhaseAfter) - maybeDispatch(Document::ANIMATIONEND_LISTENER, EventTypeNames::animationend, timedItem->activeDuration()); + + if (currentPhase == AnimationNode::PhaseAfter && m_previousPhase != AnimationNode::PhaseAfter) + maybeDispatch(Document::ANIMATIONEND_LISTENER, EventTypeNames::animationend, animationNode->activeDurationInternal()); + + m_previousPhase = currentPhase; + m_previousIteration = currentIteration; } -void CSSAnimations::TransitionEventDelegate::onEventCondition(const TimedItem* timedItem, bool isFirstSample, TimedItem::Phase previousPhase, double previousIteration) +void CSSAnimations::TransitionEventDelegate::onEventCondition(const AnimationNode* animationNode) { - // Events for a single document are queued and dispatched as a group at - // the end of DocumentTimeline::serviceAnimations. - // FIXME: Events which are queued outside of serviceAnimations should - // trigger a timer to dispatch when control is released. - const TimedItem::Phase currentPhase = timedItem->phase(); - if (currentPhase == TimedItem::PhaseAfter && (isFirstSample || previousPhase != currentPhase) && m_target->document().hasListenerType(Document::TRANSITIONEND_LISTENER)) { + const AnimationNode::Phase currentPhase = animationNode->phase(); + if (currentPhase == AnimationNode::PhaseAfter && currentPhase != m_previousPhase && m_target->document().hasListenerType(Document::TRANSITIONEND_LISTENER)) { String propertyName = getPropertyNameString(m_property); - const Timing& timing = timedItem->specified(); + const Timing& timing = animationNode->specifiedTiming(); double elapsedTime = timing.iterationDuration; const AtomicString& eventType = EventTypeNames::transitionend; String pseudoElement = PseudoElement::pseudoElementNameForEvents(m_target->pseudoId()); - m_target->document().transitionTimeline()->addEventToDispatch(m_target, TransitionEvent::create(eventType, propertyName, elapsedTime, pseudoElement)); + RefPtrWillBeRawPtr<TransitionEvent> event = TransitionEvent::create(eventType, propertyName, elapsedTime, pseudoElement); + event->setTarget(m_target); + m_target->document().enqueueAnimationFrameEvent(event); } -} + m_previousPhase = currentPhase; +} bool CSSAnimations::isAnimatableProperty(CSSPropertyID property) { @@ -810,8 +686,8 @@ bool CSSAnimations::isAnimatableProperty(CSSPropertyID property) case CSSPropertyFloodColor: case CSSPropertyFloodOpacity: case CSSPropertyFontSize: + case CSSPropertyFontWeight: case CSSPropertyHeight: - case CSSPropertyKerning: case CSSPropertyLeft: case CSSPropertyLetterSpacing: case CSSPropertyLightingColor: @@ -848,6 +724,7 @@ bool CSSAnimations::isAnimatableProperty(CSSPropertyID property) case CSSPropertyTextIndent: case CSSPropertyTextShadow: case CSSPropertyTop: + case CSSPropertyVerticalAlign: case CSSPropertyVisibility: case CSSPropertyWebkitBackgroundSize: case CSSPropertyWebkitBorderHorizontalSpacing: @@ -868,29 +745,27 @@ bool CSSAnimations::isAnimatableProperty(CSSPropertyID property) case CSSPropertyWebkitMaskPositionX: case CSSPropertyWebkitMaskPositionY: case CSSPropertyWebkitMaskSize: - case CSSPropertyWebkitPerspective: - case CSSPropertyWebkitPerspectiveOriginX: - case CSSPropertyWebkitPerspectiveOriginY: - case CSSPropertyShapeInside: + case CSSPropertyPerspective: case CSSPropertyShapeOutside: case CSSPropertyShapeMargin: case CSSPropertyShapeImageThreshold: case CSSPropertyWebkitTextStrokeColor: - case CSSPropertyWebkitTransform: - case CSSPropertyWebkitTransformOriginX: - case CSSPropertyWebkitTransformOriginY: - case CSSPropertyWebkitTransformOriginZ: + case CSSPropertyTransform: case CSSPropertyWidows: case CSSPropertyWidth: case CSSPropertyWordSpacing: case CSSPropertyZIndex: case CSSPropertyZoom: return true; - // FIXME: Shorthands should not be present in this list, but - // CSSPropertyAnimation implements animation of these shorthands - // directly and makes use of this method. - case CSSPropertyFlex: - return !RuntimeEnabledFeatures::webAnimationsCSSEnabled(); + case CSSPropertyPerspectiveOrigin: + case CSSPropertyTransformOrigin: + return RuntimeEnabledFeatures::cssTransformsUnprefixedEnabled(); + case CSSPropertyWebkitPerspectiveOriginX: + case CSSPropertyWebkitPerspectiveOriginY: + case CSSPropertyWebkitTransformOriginX: + case CSSPropertyWebkitTransformOriginY: + case CSSPropertyWebkitTransformOriginZ: + return !RuntimeEnabledFeatures::cssTransformsUnprefixedEnabled(); default: return false; } @@ -911,4 +786,61 @@ const StylePropertyShorthand& CSSAnimations::animatableProperties() return propertyShorthand; } +// Animation properties are not allowed to be affected by Web Animations. +// http://dev.w3.org/fxtf/web-animations/#not-animatable +bool CSSAnimations::isAllowedAnimation(CSSPropertyID property) +{ + switch (property) { + case CSSPropertyAnimation: + case CSSPropertyAnimationDelay: + case CSSPropertyAnimationDirection: + case CSSPropertyAnimationDuration: + case CSSPropertyAnimationFillMode: + case CSSPropertyAnimationIterationCount: + case CSSPropertyAnimationName: + case CSSPropertyAnimationPlayState: + case CSSPropertyAnimationTimingFunction: + case CSSPropertyDisplay: + case CSSPropertyTransition: + case CSSPropertyTransitionDelay: + case CSSPropertyTransitionDuration: + case CSSPropertyTransitionProperty: + case CSSPropertyTransitionTimingFunction: + case CSSPropertyWebkitAnimation: + case CSSPropertyWebkitAnimationDelay: + case CSSPropertyWebkitAnimationDirection: + case CSSPropertyWebkitAnimationDuration: + case CSSPropertyWebkitAnimationFillMode: + case CSSPropertyWebkitAnimationIterationCount: + case CSSPropertyWebkitAnimationName: + case CSSPropertyWebkitAnimationPlayState: + case CSSPropertyWebkitAnimationTimingFunction: + case CSSPropertyWebkitTransition: + case CSSPropertyWebkitTransitionDelay: + case CSSPropertyWebkitTransitionDuration: + case CSSPropertyWebkitTransitionProperty: + case CSSPropertyWebkitTransitionTimingFunction: + return false; + default: + return true; + } +} + +void CSSAnimations::trace(Visitor* visitor) +{ + visitor->trace(m_transitions); + visitor->trace(m_pendingUpdate); + visitor->trace(m_animations); + visitor->trace(m_previousActiveInterpolationsForAnimations); +} + +void CSSAnimationUpdate::trace(Visitor* visitor) +{ + visitor->trace(m_newTransitions); + visitor->trace(m_activeInterpolationsForAnimations); + visitor->trace(m_activeInterpolationsForTransitions); + visitor->trace(m_newAnimations); + visitor->trace(m_cancelledAnimationPlayers); +} + } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/core/animation/css/CSSAnimations.h b/chromium/third_party/WebKit/Source/core/animation/css/CSSAnimations.h index fb553d96232..31159f908ec 100644 --- a/chromium/third_party/WebKit/Source/core/animation/css/CSSAnimations.h +++ b/chromium/third_party/WebKit/Source/core/animation/css/CSSAnimations.h @@ -32,11 +32,11 @@ #define CSSAnimations_h #include "core/animation/Animation.h" +#include "core/animation/AnimationPlayer.h" #include "core/animation/InertAnimation.h" -#include "core/animation/Player.h" +#include "core/animation/interpolation/Interpolation.h" #include "core/css/StylePropertySet.h" #include "core/dom/Document.h" -#include "core/platform/animation/CSSAnimationData.h" #include "core/rendering/style/RenderStyleConstants.h" #include "wtf/HashMap.h" #include "wtf/Vector.h" @@ -44,39 +44,40 @@ namespace WebCore { +class CSSTransitionData; class Element; class StylePropertyShorthand; class StyleResolver; class StyleRuleKeyframes; // This class stores the CSS Animations/Transitions information we use during a style recalc. -// This includes updates to animations/transitions as well as the CompositableValueMaps to be applied. -class CSSAnimationUpdate FINAL { +// This includes updates to animations/transitions as well as the Interpolations to be applied. +class CSSAnimationUpdate FINAL : public NoBaseWillBeGarbageCollectedFinalized<CSSAnimationUpdate> { public: - void startAnimation(AtomicString& animationName, const HashSet<RefPtr<InertAnimation> >& animations) + void startAnimation(AtomicString& animationName, PassRefPtrWillBeRawPtr<InertAnimation> animation) { NewAnimation newAnimation; newAnimation.name = animationName; - newAnimation.animations = animations; + newAnimation.animation = animation; m_newAnimations.append(newAnimation); } // Returns whether player has been cancelled and should be filtered during style application. - bool isCancelledAnimation(const Player* player) const { return m_cancelledAnimationPlayers.contains(player); } - void cancelAnimation(const AtomicString& name, const HashSet<RefPtr<Player> >& players) + bool isCancelledAnimation(const AnimationPlayer* player) const { return m_cancelledAnimationPlayers.contains(player); } + void cancelAnimation(const AtomicString& name, AnimationPlayer& player) { m_cancelledAnimationNames.append(name); - for (HashSet<RefPtr<Player> >::const_iterator iter = players.begin(); iter != players.end(); ++iter) - m_cancelledAnimationPlayers.add(iter->get()); + m_cancelledAnimationPlayers.add(&player); } void toggleAnimationPaused(const AtomicString& name) { m_animationsWithPauseToggled.append(name); } - void startTransition(CSSPropertyID id, const AnimatableValue* from, const AnimatableValue* to, PassRefPtr<InertAnimation> animation) + void startTransition(CSSPropertyID id, CSSPropertyID eventId, const AnimatableValue* from, const AnimatableValue* to, PassRefPtrWillBeRawPtr<InertAnimation> animation) { NewTransition newTransition; newTransition.id = id; + newTransition.eventId = eventId; newTransition.from = from; newTransition.to = to; newTransition.animation = animation; @@ -86,29 +87,46 @@ public: void cancelTransition(CSSPropertyID id) { m_cancelledTransitions.add(id); } struct NewAnimation { + ALLOW_ONLY_INLINE_ALLOCATION(); + public: + void trace(Visitor* visitor) + { + visitor->trace(animation); + } + AtomicString name; - HashSet<RefPtr<InertAnimation> > animations; + RefPtrWillBeMember<InertAnimation> animation; }; - const Vector<NewAnimation>& newAnimations() const { return m_newAnimations; } + const WillBeHeapVector<NewAnimation>& newAnimations() const { return m_newAnimations; } const Vector<AtomicString>& cancelledAnimationNames() const { return m_cancelledAnimationNames; } - const HashSet<const Player*>& cancelledAnimationPlayers() const { return m_cancelledAnimationPlayers; } + const WillBeHeapHashSet<RawPtrWillBeMember<const AnimationPlayer> >& cancelledAnimationAnimationPlayers() const { return m_cancelledAnimationPlayers; } const Vector<AtomicString>& animationsWithPauseToggled() const { return m_animationsWithPauseToggled; } struct NewTransition { + ALLOW_ONLY_INLINE_ALLOCATION(); + public: + void trace(Visitor* visitor) + { + visitor->trace(from); + visitor->trace(to); + visitor->trace(animation); + } + CSSPropertyID id; - const AnimatableValue* from; - const AnimatableValue* to; - RefPtr<InertAnimation> animation; + CSSPropertyID eventId; + RawPtrWillBeMember<const AnimatableValue> from; + RawPtrWillBeMember<const AnimatableValue> to; + RefPtrWillBeMember<InertAnimation> animation; }; - typedef HashMap<CSSPropertyID, NewTransition> NewTransitionMap; + typedef WillBeHeapHashMap<CSSPropertyID, NewTransition> NewTransitionMap; const NewTransitionMap& newTransitions() const { return m_newTransitions; } const HashSet<CSSPropertyID>& cancelledTransitions() const { return m_cancelledTransitions; } - void adoptCompositableValuesForAnimations(AnimationEffect::CompositableValueMap& newMap) { newMap.swap(m_compositableValuesForAnimations); } - void adoptCompositableValuesForTransitions(AnimationEffect::CompositableValueMap& newMap) { newMap.swap(m_compositableValuesForTransitions); } - const AnimationEffect::CompositableValueMap& compositableValuesForAnimations() const { return m_compositableValuesForAnimations; } - const AnimationEffect::CompositableValueMap& compositableValuesForTransitions() const { return m_compositableValuesForTransitions; } - AnimationEffect::CompositableValueMap& compositableValuesForAnimations() { return m_compositableValuesForAnimations; } + void adoptActiveInterpolationsForAnimations(WillBeHeapHashMap<CSSPropertyID, RefPtrWillBeMember<Interpolation> >& newMap) { newMap.swap(m_activeInterpolationsForAnimations); } + void adoptActiveInterpolationsForTransitions(WillBeHeapHashMap<CSSPropertyID, RefPtrWillBeMember<Interpolation> >& newMap) { newMap.swap(m_activeInterpolationsForTransitions); } + const WillBeHeapHashMap<CSSPropertyID, RefPtrWillBeMember<Interpolation> >& activeInterpolationsForAnimations() const { return m_activeInterpolationsForAnimations; } + const WillBeHeapHashMap<CSSPropertyID, RefPtrWillBeMember<Interpolation> >& activeInterpolationsForTransitions() const { return m_activeInterpolationsForTransitions; } + WillBeHeapHashMap<CSSPropertyID, RefPtrWillBeMember<Interpolation> >& activeInterpolationsForAnimations() { return m_activeInterpolationsForAnimations; } bool isEmpty() const { @@ -118,28 +136,35 @@ public: && m_animationsWithPauseToggled.isEmpty() && m_newTransitions.isEmpty() && m_cancelledTransitions.isEmpty() - && m_compositableValuesForAnimations.isEmpty() - && m_compositableValuesForTransitions.isEmpty(); + && m_activeInterpolationsForAnimations.isEmpty() + && m_activeInterpolationsForTransitions.isEmpty(); } + + void trace(Visitor*); + private: // Order is significant since it defines the order in which new animations // will be started. Note that there may be multiple animations present // with the same name, due to the way in which we split up animations with // incomplete keyframes. - Vector<NewAnimation> m_newAnimations; + WillBeHeapVector<NewAnimation> m_newAnimations; Vector<AtomicString> m_cancelledAnimationNames; - HashSet<const Player*> m_cancelledAnimationPlayers; + WillBeHeapHashSet<RawPtrWillBeMember<const AnimationPlayer> > m_cancelledAnimationPlayers; Vector<AtomicString> m_animationsWithPauseToggled; NewTransitionMap m_newTransitions; HashSet<CSSPropertyID> m_cancelledTransitions; - AnimationEffect::CompositableValueMap m_compositableValuesForAnimations; - AnimationEffect::CompositableValueMap m_compositableValuesForTransitions; + WillBeHeapHashMap<CSSPropertyID, RefPtrWillBeMember<Interpolation> > m_activeInterpolationsForAnimations; + WillBeHeapHashMap<CSSPropertyID, RefPtrWillBeMember<Interpolation> > m_activeInterpolationsForTransitions; }; class CSSAnimations FINAL { + WTF_MAKE_NONCOPYABLE(CSSAnimations); + DISALLOW_ALLOCATION(); public: + CSSAnimations(); + // FIXME: This method is only used here and in the legacy animations // implementation. It should be made private or file-scope when the legacy // engine is removed. @@ -147,68 +172,91 @@ public: static bool isAnimatableProperty(CSSPropertyID); static const StylePropertyShorthand& animatableProperties(); + static bool isAllowedAnimation(CSSPropertyID); // FIXME: This should take a const ScopedStyleTree instead of a StyleResolver. // We should also change the Element* to a const Element* - static PassOwnPtr<CSSAnimationUpdate> calculateUpdate(Element*, const Element& parentElement, const RenderStyle&, RenderStyle* parentStyle, StyleResolver*); + static PassOwnPtrWillBeRawPtr<CSSAnimationUpdate> calculateUpdate(Element*, const Element& parentElement, const RenderStyle&, RenderStyle* parentStyle, StyleResolver*); - void setPendingUpdate(PassOwnPtr<CSSAnimationUpdate> update) { m_pendingUpdate = update; } + void setPendingUpdate(PassOwnPtrWillBeRawPtr<CSSAnimationUpdate> update) { m_pendingUpdate = update; } void maybeApplyPendingUpdate(Element*); bool isEmpty() const { return m_animations.isEmpty() && m_transitions.isEmpty() && !m_pendingUpdate; } void cancel(); + void trace(Visitor*); + private: - // Note that a single animation name may map to multiple players due to - // the way in which we split up animations with incomplete keyframes. - // FIXME: Once the Web Animations model supports groups, we could use a - // ParGroup to drive multiple animations from a single Player. - typedef HashMap<AtomicString, HashSet<RefPtr<Player> > > AnimationMap; struct RunningTransition { - Animation* transition; // The TransitionTimeline keeps the Players alive - const AnimatableValue* from; - const AnimatableValue* to; + ALLOW_ONLY_INLINE_ALLOCATION(); + public: + void trace(Visitor* visitor) + { + visitor->trace(from); + visitor->trace(to); + visitor->trace(player); + } + + RefPtrWillBeMember<AnimationPlayer> player; + RawPtrWillBeMember<const AnimatableValue> from; + RawPtrWillBeMember<const AnimatableValue> to; }; - typedef HashMap<CSSPropertyID, RunningTransition > TransitionMap; + + typedef WillBeHeapHashMap<AtomicString, RefPtrWillBeMember<AnimationPlayer> > AnimationMap; AnimationMap m_animations; + + typedef WillBeHeapHashMap<CSSPropertyID, RunningTransition> TransitionMap; TransitionMap m_transitions; - OwnPtr<CSSAnimationUpdate> m_pendingUpdate; - AnimationEffect::CompositableValueMap m_previousCompositableValuesForAnimations; + OwnPtrWillBeMember<CSSAnimationUpdate> m_pendingUpdate; + + WillBeHeapHashMap<CSSPropertyID, RefPtrWillBeMember<Interpolation> > m_previousActiveInterpolationsForAnimations; static void calculateAnimationUpdate(CSSAnimationUpdate*, Element*, const Element& parentElement, const RenderStyle&, RenderStyle* parentStyle, StyleResolver*); static void calculateTransitionUpdate(CSSAnimationUpdate*, const Element*, const RenderStyle&); - static void calculateTransitionUpdateForProperty(CSSPropertyID, const CSSAnimationData*, const RenderStyle& oldStyle, const RenderStyle&, const TransitionMap* activeTransitions, CSSAnimationUpdate*, const Element*); + static void calculateTransitionUpdateForProperty(CSSPropertyID, CSSPropertyID eventId, const CSSTransitionData&, size_t transitionIndex, const RenderStyle& oldStyle, const RenderStyle&, const TransitionMap* activeTransitions, CSSAnimationUpdate*, const Element*); - static void calculateAnimationCompositableValues(CSSAnimationUpdate*, const Element*); - static void calculateTransitionCompositableValues(CSSAnimationUpdate*, const Element*); + static void calculateAnimationActiveInterpolations(CSSAnimationUpdate*, const Element*, double timelineCurrentTime); + static void calculateTransitionActiveInterpolations(CSSAnimationUpdate*, const Element*, double timelineCurrentTime); - class AnimationEventDelegate FINAL : public TimedItem::EventDelegate { + class AnimationEventDelegate FINAL : public AnimationNode::EventDelegate { public: AnimationEventDelegate(Element* target, const AtomicString& name) : m_target(target) , m_name(name) + , m_previousPhase(AnimationNode::PhaseNone) + , m_previousIteration(nullValue()) { } - virtual void onEventCondition(const TimedItem*, bool isFirstSample, TimedItem::Phase previousPhase, double previousIteration) OVERRIDE; + virtual void onEventCondition(const AnimationNode*) OVERRIDE; private: void maybeDispatch(Document::ListenerType, const AtomicString& eventName, double elapsedTime); Element* m_target; const AtomicString m_name; + AnimationNode::Phase m_previousPhase; + double m_previousIteration; }; - class TransitionEventDelegate FINAL : public TimedItem::EventDelegate { + class TransitionEventDelegate FINAL : public AnimationNode::EventDelegate { public: TransitionEventDelegate(Element* target, CSSPropertyID property) : m_target(target) , m_property(property) + , m_previousPhase(AnimationNode::PhaseNone) { } - virtual void onEventCondition(const TimedItem*, bool isFirstSample, TimedItem::Phase previousPhase, double previousIteration) OVERRIDE; + virtual void onEventCondition(const AnimationNode*) OVERRIDE; private: Element* m_target; const CSSPropertyID m_property; + AnimationNode::Phase m_previousPhase; }; }; } // namespace WebCore +namespace WTF { +template<> struct VectorTraits<WebCore::CSSAnimationUpdate::NewAnimation> : VectorTraitsBase<WebCore::CSSAnimationUpdate::NewAnimation> { + static const bool canInitializeWithMemset = true; +}; +} + #endif diff --git a/chromium/third_party/WebKit/Source/core/animation/css/CSSPendingAnimations.cpp b/chromium/third_party/WebKit/Source/core/animation/css/CSSPendingAnimations.cpp deleted file mode 100644 index 3a4ec03d29e..00000000000 --- a/chromium/third_party/WebKit/Source/core/animation/css/CSSPendingAnimations.cpp +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (C) 2013 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "core/animation/css/CSSPendingAnimations.h" - -#include "core/animation/Animation.h" -#include "core/animation/DocumentTimeline.h" -#include "core/frame/FrameView.h" - -namespace WebCore { - -void CSSPendingAnimations::add(Player* player) -{ - ASSERT(player->source()->isAnimation()); - // The actual start time is either this value, or the time that - // this animation, or an animation that it is synchronized with - // is started on the compositor. - const double defaultStartTime = player->timeline().currentTime(); - m_pending.append(std::make_pair(player, defaultStartTime)); -} - -bool CSSPendingAnimations::startPendingAnimations() -{ - bool startedOnCompositor = false; - for (size_t i = 0; i < m_pending.size(); ++i) { - if (m_pending[i].first->maybeStartAnimationOnCompositor()) - startedOnCompositor = true; - } - - // If any animations were started on the compositor, all remaining - // need to wait for a synchronized start time. Otherwise they may - // start immediately. - if (startedOnCompositor) { - for (size_t i = 0; i < m_pending.size(); ++i) - m_waitingForCompositorAnimationStart.append(m_pending[i].first); - } else { - for (size_t i = 0; i < m_pending.size(); ++i) - m_pending[i].first->setStartTime(m_pending[i].second); - } - m_pending.clear(); - - if (startedOnCompositor || m_waitingForCompositorAnimationStart.isEmpty()) - return !m_waitingForCompositorAnimationStart.isEmpty(); - - // Check if we're still waiting for any compositor animations to start. - for (size_t i = 0; i < m_waitingForCompositorAnimationStart.size(); ++i) { - if (m_waitingForCompositorAnimationStart[i].get()->hasActiveAnimationsOnCompositor()) - return true; - } - - // If not, go ahead and start any animations that were waiting. - notifyCompositorAnimationStarted(monotonicallyIncreasingTime()); - return false; -} - -void CSSPendingAnimations::notifyCompositorAnimationStarted(double monotonicAnimationStartTime) -{ - for (size_t i = 0; i < m_waitingForCompositorAnimationStart.size(); ++i) { - Player* player = m_waitingForCompositorAnimationStart[i].get(); - player->setStartTime(monotonicAnimationStartTime - player->timeline().zeroTime()); - } - - m_waitingForCompositorAnimationStart.clear(); -} - -} // namespace diff --git a/chromium/third_party/WebKit/Source/core/animation/css/CSSPendingAnimations.h b/chromium/third_party/WebKit/Source/core/animation/css/CSSPendingAnimations.h deleted file mode 100644 index 1bb3c28d4c0..00000000000 --- a/chromium/third_party/WebKit/Source/core/animation/css/CSSPendingAnimations.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (C) 2013 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef CSSPendingAnimations_h -#define CSSPendingAnimations_h - -#include "core/animation/Player.h" -#include "wtf/Vector.h" - -namespace WebCore { - -// Used to synchronize the start of main-thread animations with compositor -// animations when both classes of CSS Animations are triggered by the same recalc -class CSSPendingAnimations FINAL { -public: - void add(Player*); - // Returns whether we are waiting for an animation to start and should - // service again on the next frame. - bool startPendingAnimations(); - void notifyCompositorAnimationStarted(double monotonicAnimationStartTime); - -private: - Vector<std::pair<RefPtr<Player>, double> > m_pending; - Vector<RefPtr<Player> > m_waitingForCompositorAnimationStart; -}; - -} // namespace WebCore - -#endif diff --git a/chromium/third_party/WebKit/Source/core/animation/css/CSSPropertyEquality.cpp b/chromium/third_party/WebKit/Source/core/animation/css/CSSPropertyEquality.cpp new file mode 100644 index 00000000000..70ad01dbcb4 --- /dev/null +++ b/chromium/third_party/WebKit/Source/core/animation/css/CSSPropertyEquality.cpp @@ -0,0 +1,318 @@ +// 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/css/CSSPropertyEquality.h" + +#include "core/animation/css/CSSAnimations.h" +#include "core/rendering/style/DataEquivalency.h" +#include "core/rendering/style/RenderStyle.h" +#include "core/rendering/style/ShadowList.h" + +namespace WebCore { + +namespace { + +template <CSSPropertyID property> +bool fillLayersEqual(const FillLayer* aLayer, const FillLayer* bLayer) +{ + if (aLayer == bLayer) + return true; + if (!aLayer || !bLayer) + return false; + while (aLayer && bLayer) { + switch (property) { + case CSSPropertyBackgroundPositionX: + case CSSPropertyWebkitMaskPositionX: + if (aLayer->xPosition() != bLayer->xPosition()) + return false; + break; + case CSSPropertyBackgroundPositionY: + case CSSPropertyWebkitMaskPositionY: + if (aLayer->yPosition() != bLayer->yPosition()) + return false; + break; + case CSSPropertyBackgroundSize: + case CSSPropertyWebkitBackgroundSize: + case CSSPropertyWebkitMaskSize: + if (!(aLayer->sizeLength() == bLayer->sizeLength())) + return false; + break; + case CSSPropertyBackgroundImage: + if (!dataEquivalent(aLayer->image(), bLayer->image())) + return false; + break; + default: + ASSERT_NOT_REACHED(); + return true; + } + + aLayer = aLayer->next(); + bLayer = bLayer->next(); + } + + // FIXME: Shouldn't this be return !aLayer && !bLayer; ? + return true; +} + +} + +bool CSSPropertyEquality::propertiesEqual(CSSPropertyID prop, const RenderStyle& a, const RenderStyle& b) +{ + switch (prop) { + case CSSPropertyBackgroundColor: + return a.backgroundColor().resolve(a.color()) == b.backgroundColor().resolve(b.color()) + && a.visitedLinkBackgroundColor().resolve(a.color()) == b.visitedLinkBackgroundColor().resolve(b.color()); + case CSSPropertyBackgroundImage: + return fillLayersEqual<CSSPropertyBackgroundImage>(a.backgroundLayers(), b.backgroundLayers()); + case CSSPropertyBackgroundPositionX: + return fillLayersEqual<CSSPropertyBackgroundPositionX>(a.backgroundLayers(), b.backgroundLayers()); + case CSSPropertyBackgroundPositionY: + return fillLayersEqual<CSSPropertyBackgroundPositionY>(a.backgroundLayers(), b.backgroundLayers()); + case CSSPropertyBackgroundSize: + return fillLayersEqual<CSSPropertyBackgroundSize>(a.backgroundLayers(), b.backgroundLayers()); + case CSSPropertyBaselineShift: + return dataEquivalent(a.baselineShiftValue(), b.baselineShiftValue()); + case CSSPropertyBorderBottomColor: + return a.borderBottomColor().resolve(a.color()) == b.borderBottomColor().resolve(b.color()) + && a.visitedLinkBorderBottomColor().resolve(a.color()) == b.visitedLinkBorderBottomColor().resolve(b.color()); + case CSSPropertyBorderBottomLeftRadius: + return a.borderBottomLeftRadius() == b.borderBottomLeftRadius(); + case CSSPropertyBorderBottomRightRadius: + return a.borderBottomRightRadius() == b.borderBottomRightRadius(); + case CSSPropertyBorderBottomWidth: + return a.borderBottomWidth() == b.borderBottomWidth(); + case CSSPropertyBorderImageOutset: + return a.borderImageOutset() == b.borderImageOutset(); + case CSSPropertyBorderImageSlice: + return a.borderImageSlices() == b.borderImageSlices(); + case CSSPropertyBorderImageSource: + return dataEquivalent(a.borderImageSource(), b.borderImageSource()); + case CSSPropertyBorderImageWidth: + return a.borderImageWidth() == b.borderImageWidth(); + case CSSPropertyBorderLeftColor: + return a.borderLeftColor().resolve(a.color()) == b.borderLeftColor().resolve(b.color()) + && a.visitedLinkBorderLeftColor().resolve(a.color()) == b.visitedLinkBorderLeftColor().resolve(b.color()); + case CSSPropertyBorderLeftWidth: + return a.borderLeftWidth() == b.borderLeftWidth(); + case CSSPropertyBorderRightColor: + return a.borderRightColor().resolve(a.color()) == b.borderRightColor().resolve(b.color()) + && a.visitedLinkBorderRightColor().resolve(a.color()) == b.visitedLinkBorderRightColor().resolve(b.color()); + case CSSPropertyBorderRightWidth: + return a.borderRightWidth() == b.borderRightWidth(); + case CSSPropertyBorderTopColor: + return a.borderTopColor().resolve(a.color()) == b.borderTopColor().resolve(b.color()) + && a.visitedLinkBorderTopColor().resolve(a.color()) == b.visitedLinkBorderTopColor().resolve(b.color()); + case CSSPropertyBorderTopLeftRadius: + return a.borderTopLeftRadius() == b.borderTopLeftRadius(); + case CSSPropertyBorderTopRightRadius: + return a.borderTopRightRadius() == b.borderTopRightRadius(); + case CSSPropertyBorderTopWidth: + return a.borderTopWidth() == b.borderTopWidth(); + case CSSPropertyBottom: + return a.bottom() == b.bottom(); + case CSSPropertyBoxShadow: + return dataEquivalent(a.boxShadow(), b.boxShadow()); + case CSSPropertyClip: + return a.clip() == b.clip(); + case CSSPropertyColor: + return a.color() == b.color() && a.visitedLinkColor() == b.visitedLinkColor(); + case CSSPropertyFill: { + const SVGRenderStyle& aSVG = *a.svgStyle(); + const SVGRenderStyle& bSVG = *b.svgStyle(); + return aSVG.fillPaintType() == bSVG.fillPaintType() + && (aSVG.fillPaintType() != SVGPaint::SVG_PAINTTYPE_RGBCOLOR || aSVG.fillPaintColor() == bSVG.fillPaintColor()) + && aSVG.visitedLinkFillPaintType() == bSVG.visitedLinkFillPaintType() + && (aSVG.visitedLinkFillPaintType() != SVGPaint::SVG_PAINTTYPE_RGBCOLOR || aSVG.visitedLinkFillPaintColor() == bSVG.visitedLinkFillPaintColor()); + } + case CSSPropertyFillOpacity: + return a.fillOpacity() == b.fillOpacity(); + case CSSPropertyFlexBasis: + return a.flexBasis() == b.flexBasis(); + case CSSPropertyFlexGrow: + return a.flexGrow() == b.flexGrow(); + case CSSPropertyFlexShrink: + return a.flexShrink() == b.flexShrink(); + case CSSPropertyFloodColor: + return a.floodColor() == b.floodColor(); + case CSSPropertyFloodOpacity: + return a.floodOpacity() == b.floodOpacity(); + case CSSPropertyFontSize: + // CSSPropertyFontSize: Must pass a specified size to setFontSize if Text Autosizing is enabled, but a computed size + // if text zoom is enabled (if neither is enabled it's irrelevant as they're probably the same). + // FIXME: Should we introduce an option to pass the computed font size here, allowing consumers to + // enable text zoom rather than Text Autosizing? See http://crbug.com/227545. + return a.specifiedFontSize() == b.specifiedFontSize(); + case CSSPropertyFontWeight: + return a.fontWeight() == b.fontWeight(); + case CSSPropertyHeight: + return a.height() == b.height(); + case CSSPropertyLeft: + return a.left() == b.left(); + case CSSPropertyLetterSpacing: + return a.letterSpacing() == b.letterSpacing(); + case CSSPropertyLightingColor: + return a.lightingColor() == b.lightingColor(); + case CSSPropertyLineHeight: + return a.specifiedLineHeight() == b.specifiedLineHeight(); + case CSSPropertyListStyleImage: + return dataEquivalent(a.listStyleImage(), b.listStyleImage()); + case CSSPropertyMarginBottom: + return a.marginBottom() == b.marginBottom(); + case CSSPropertyMarginLeft: + return a.marginLeft() == b.marginLeft(); + case CSSPropertyMarginRight: + return a.marginRight() == b.marginRight(); + case CSSPropertyMarginTop: + return a.marginTop() == b.marginTop(); + case CSSPropertyMaxHeight: + return a.maxHeight() == b.maxHeight(); + case CSSPropertyMaxWidth: + return a.maxWidth() == b.maxWidth(); + case CSSPropertyMinHeight: + return a.minHeight() == b.minHeight(); + case CSSPropertyMinWidth: + return a.minWidth() == b.minWidth(); + case CSSPropertyObjectPosition: + return a.objectPosition() == b.objectPosition(); + case CSSPropertyOpacity: + return a.opacity() == b.opacity(); + case CSSPropertyOrphans: + return a.orphans() == b.orphans(); + case CSSPropertyOutlineColor: + return a.outlineColor().resolve(a.color()) == b.outlineColor().resolve(b.color()) + && a.visitedLinkOutlineColor().resolve(a.color()) == b.visitedLinkOutlineColor().resolve(b.color()); + case CSSPropertyOutlineOffset: + return a.outlineOffset() == b.outlineOffset(); + case CSSPropertyOutlineWidth: + return a.outlineWidth() == b.outlineWidth(); + case CSSPropertyPaddingBottom: + return a.paddingBottom() == b.paddingBottom(); + case CSSPropertyPaddingLeft: + return a.paddingLeft() == b.paddingLeft(); + case CSSPropertyPaddingRight: + return a.paddingRight() == b.paddingRight(); + case CSSPropertyPaddingTop: + return a.paddingTop() == b.paddingTop(); + case CSSPropertyRight: + return a.right() == b.right(); + case CSSPropertyShapeImageThreshold: + return a.shapeImageThreshold() == b.shapeImageThreshold(); + case CSSPropertyShapeMargin: + return a.shapeMargin() == b.shapeMargin(); + case CSSPropertyShapeOutside: + return dataEquivalent(a.shapeOutside(), b.shapeOutside()); + case CSSPropertyStopColor: + return a.stopColor() == b.stopColor(); + case CSSPropertyStopOpacity: + return a.stopOpacity() == b.stopOpacity(); + case CSSPropertyStroke: { + const SVGRenderStyle& aSVG = *a.svgStyle(); + const SVGRenderStyle& bSVG = *b.svgStyle(); + return aSVG.strokePaintType() == bSVG.strokePaintType() + && (aSVG.strokePaintType() != SVGPaint::SVG_PAINTTYPE_RGBCOLOR || aSVG.strokePaintColor() == bSVG.strokePaintColor()) + && aSVG.visitedLinkStrokePaintType() == bSVG.visitedLinkStrokePaintType() + && (aSVG.visitedLinkStrokePaintType() != SVGPaint::SVG_PAINTTYPE_RGBCOLOR || aSVG.visitedLinkStrokePaintColor() == bSVG.visitedLinkStrokePaintColor()); + } + case CSSPropertyStrokeDasharray: + return dataEquivalent(a.strokeDashArray(), b.strokeDashArray()); + case CSSPropertyStrokeDashoffset: + return dataEquivalent(a.strokeDashOffset(), b.strokeDashOffset()); + case CSSPropertyStrokeMiterlimit: + return a.strokeMiterLimit() == b.strokeMiterLimit(); + case CSSPropertyStrokeOpacity: + return a.strokeOpacity() == b.strokeOpacity(); + case CSSPropertyStrokeWidth: + return dataEquivalent(a.strokeWidth(), b.strokeWidth()); + case CSSPropertyTextDecorationColor: + return a.textDecorationColor().resolve(a.color()) == b.textDecorationColor().resolve(b.color()) + && a.visitedLinkTextDecorationColor().resolve(a.color()) == b.visitedLinkTextDecorationColor().resolve(b.color()); + case CSSPropertyTextIndent: + return a.textIndent() == b.textIndent(); + case CSSPropertyTextShadow: + return dataEquivalent(a.textShadow(), b.textShadow()); + case CSSPropertyTop: + return a.top() == b.top(); + case CSSPropertyVerticalAlign: + return a.verticalAlign() == b.verticalAlign() + && (a.verticalAlign() != LENGTH || a.verticalAlignLength() == b.verticalAlignLength()); + case CSSPropertyVisibility: + return a.visibility() == b.visibility(); + case CSSPropertyWebkitBackgroundSize: + return fillLayersEqual<CSSPropertyWebkitBackgroundSize>(a.backgroundLayers(), b.backgroundLayers()); + case CSSPropertyWebkitBorderHorizontalSpacing: + return a.horizontalBorderSpacing() == b.horizontalBorderSpacing(); + case CSSPropertyWebkitBorderVerticalSpacing: + return a.verticalBorderSpacing() == b.verticalBorderSpacing(); + case CSSPropertyWebkitBoxShadow: + return dataEquivalent(a.boxShadow(), b.boxShadow()); + case CSSPropertyWebkitClipPath: + return dataEquivalent(a.clipPath(), b.clipPath()); + case CSSPropertyWebkitColumnCount: + return a.columnCount() == b.columnCount(); + case CSSPropertyWebkitColumnGap: + return a.columnGap() == b.columnGap(); + case CSSPropertyWebkitColumnRuleColor: + return a.columnRuleColor().resolve(a.color()) == b.columnRuleColor().resolve(b.color()) + && a.visitedLinkColumnRuleColor().resolve(a.color()) == b.visitedLinkColumnRuleColor().resolve(b.color()); + case CSSPropertyWebkitColumnRuleWidth: + return a.columnRuleWidth() == b.columnRuleWidth(); + case CSSPropertyWebkitColumnWidth: + return a.columnWidth() == b.columnWidth(); + case CSSPropertyWebkitFilter: + return a.filter() == b.filter(); + case CSSPropertyWebkitMaskBoxImageOutset: + return a.maskBoxImageOutset() == b.maskBoxImageOutset(); + case CSSPropertyWebkitMaskBoxImageSlice: + return a.maskBoxImageSlices() == b.maskBoxImageSlices(); + case CSSPropertyWebkitMaskBoxImageSource: + return dataEquivalent(a.maskBoxImageSource(), b.maskBoxImageSource()); + case CSSPropertyWebkitMaskBoxImageWidth: + return a.maskBoxImageWidth() == b.maskBoxImageWidth(); + case CSSPropertyWebkitMaskImage: + return dataEquivalent(a.maskImage(), b.maskImage()); + case CSSPropertyWebkitMaskPositionX: + return fillLayersEqual<CSSPropertyWebkitMaskPositionX>(a.maskLayers(), b.maskLayers()); + case CSSPropertyWebkitMaskPositionY: + return fillLayersEqual<CSSPropertyWebkitMaskPositionY>(a.maskLayers(), b.maskLayers()); + case CSSPropertyWebkitMaskSize: + return fillLayersEqual<CSSPropertyWebkitMaskSize>(a.maskLayers(), b.maskLayers()); + case CSSPropertyPerspective: + return a.perspective() == b.perspective(); + case CSSPropertyPerspectiveOrigin: + return a.perspectiveOriginX() == b.perspectiveOriginX() && a.perspectiveOriginY() == b.perspectiveOriginY(); + case CSSPropertyWebkitPerspectiveOriginX: + return a.perspectiveOriginX() == b.perspectiveOriginX(); + case CSSPropertyWebkitPerspectiveOriginY: + return a.perspectiveOriginY() == b.perspectiveOriginY(); + case CSSPropertyWebkitTextStrokeColor: + return a.textStrokeColor().resolve(a.color()) == b.textStrokeColor().resolve(b.color()) + && a.visitedLinkTextStrokeColor().resolve(a.color()) == b.visitedLinkTextStrokeColor().resolve(b.color()); + case CSSPropertyTransform: + return a.transform() == b.transform(); + case CSSPropertyTransformOrigin: + return a.transformOriginX() == b.transformOriginX() && a.transformOriginY() == b.transformOriginY() && a.transformOriginZ() == b.transformOriginZ(); + case CSSPropertyWebkitTransformOriginX: + return a.transformOriginX() == b.transformOriginX(); + case CSSPropertyWebkitTransformOriginY: + return a.transformOriginY() == b.transformOriginY(); + case CSSPropertyWebkitTransformOriginZ: + return a.transformOriginZ() == b.transformOriginZ(); + case CSSPropertyWidows: + return a.widows() == b.widows(); + case CSSPropertyWidth: + return a.width() == b.width(); + case CSSPropertyWordSpacing: + return a.wordSpacing() == b.wordSpacing(); + case CSSPropertyZIndex: + return a.zIndex() == b.zIndex(); + case CSSPropertyZoom: + return a.zoom() == b.zoom(); + default: + ASSERT_NOT_REACHED(); + return true; + } +} + +} diff --git a/chromium/third_party/WebKit/Source/core/animation/css/CSSPropertyEquality.h b/chromium/third_party/WebKit/Source/core/animation/css/CSSPropertyEquality.h new file mode 100644 index 00000000000..0a436f0046c --- /dev/null +++ b/chromium/third_party/WebKit/Source/core/animation/css/CSSPropertyEquality.h @@ -0,0 +1,21 @@ +// 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. + +#ifndef CSSPropertyEquality_h +#define CSSPropertyEquality_h + +#include "core/CSSPropertyNames.h" + +namespace WebCore { + +class RenderStyle; + +class CSSPropertyEquality { +public: + static bool propertiesEqual(CSSPropertyID, const RenderStyle&, const RenderStyle&); +}; + +} // namespace WebCore + +#endif // CSSPropertyEquality_h diff --git a/chromium/third_party/WebKit/Source/core/animation/css/CSSTimingData.cpp b/chromium/third_party/WebKit/Source/core/animation/css/CSSTimingData.cpp new file mode 100644 index 00000000000..9d628bd32c3 --- /dev/null +++ b/chromium/third_party/WebKit/Source/core/animation/css/CSSTimingData.cpp @@ -0,0 +1,36 @@ +// 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/css/CSSTimingData.h" + +#include "core/animation/Timing.h" + +namespace WebCore { + +CSSTimingData::CSSTimingData() +{ + m_delayList.append(initialDelay()); + m_durationList.append(initialDuration()); + m_timingFunctionList.append(initialTimingFunction()); +} + +CSSTimingData::CSSTimingData(const CSSTimingData& other) + : m_delayList(other.m_delayList) + , m_durationList(other.m_durationList) + , m_timingFunctionList(other.m_timingFunctionList) +{ +} + +Timing CSSTimingData::convertToTiming(size_t index) const +{ + Timing timing; + timing.startDelay = getRepeated(m_delayList, index); + timing.iterationDuration = getRepeated(m_durationList, index); + timing.timingFunction = getRepeated(m_timingFunctionList, index); + timing.assertValid(); + return timing; +} + +} // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/core/animation/css/CSSTimingData.h b/chromium/third_party/WebKit/Source/core/animation/css/CSSTimingData.h new file mode 100644 index 00000000000..33eab3b4b27 --- /dev/null +++ b/chromium/third_party/WebKit/Source/core/animation/css/CSSTimingData.h @@ -0,0 +1,50 @@ +// 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. + +#ifndef CSSTimingData_h +#define CSSTimingData_h + +#include "platform/animation/TimingFunction.h" +#include "platform/heap/Handle.h" +#include "wtf/Vector.h" + +namespace WebCore { + +struct Timing; + +class CSSTimingData : public NoBaseWillBeGarbageCollectedFinalized<CSSTimingData> { +public: + ~CSSTimingData() { } + + void trace(Visitor*) { } + + const Vector<double>& delayList() const { return m_delayList; } + const Vector<double>& durationList() const { return m_durationList; } + const Vector<RefPtr<TimingFunction> >& timingFunctionList() const { return m_timingFunctionList; } + + Vector<double>& delayList() { return m_delayList; } + Vector<double>& durationList() { return m_durationList; } + Vector<RefPtr<TimingFunction> >& timingFunctionList() { return m_timingFunctionList; } + + static double initialDelay() { return 0; } + static double initialDuration() { return 0; } + static PassRefPtr<TimingFunction> initialTimingFunction() { return CubicBezierTimingFunction::preset(CubicBezierTimingFunction::Ease); } + + template <class T> static const T& getRepeated(const Vector<T>& v, size_t index) { return v[index % v.size()]; } + +protected: + CSSTimingData(); + explicit CSSTimingData(const CSSTimingData&); + + Timing convertToTiming(size_t index) const; + +private: + Vector<double> m_delayList; + Vector<double> m_durationList; + Vector<RefPtr<TimingFunction> > m_timingFunctionList; +}; + +} // namespace WebCore + +#endif // CSSTimingData_h diff --git a/chromium/third_party/WebKit/Source/core/animation/css/CSSTransitionData.cpp b/chromium/third_party/WebKit/Source/core/animation/css/CSSTransitionData.cpp new file mode 100644 index 00000000000..ad20621f30f --- /dev/null +++ b/chromium/third_party/WebKit/Source/core/animation/css/CSSTransitionData.cpp @@ -0,0 +1,37 @@ +// 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/css/CSSTransitionData.h" + +#include "core/animation/Timing.h" + +namespace WebCore { + +CSSTransitionData::CSSTransitionData() +{ + m_propertyList.append(initialProperty()); +} + +CSSTransitionData::CSSTransitionData(const CSSTransitionData& other) + : CSSTimingData(other) + , m_propertyList(other.m_propertyList) +{ +} + +bool CSSTransitionData::transitionsMatchForStyleRecalc(const CSSTransitionData& other) const +{ + return m_propertyList == other.m_propertyList; +} + +Timing CSSTransitionData::convertToTiming(size_t index) const +{ + ASSERT(index < m_propertyList.size()); + // Note that the backwards fill part is required for delay to work. + Timing timing = CSSTimingData::convertToTiming(index); + timing.fillMode = Timing::FillModeBoth; + return timing; +} + +} // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/core/animation/css/CSSTransitionData.h b/chromium/third_party/WebKit/Source/core/animation/css/CSSTransitionData.h new file mode 100644 index 00000000000..792afc77afa --- /dev/null +++ b/chromium/third_party/WebKit/Source/core/animation/css/CSSTransitionData.h @@ -0,0 +1,81 @@ +// 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. + +#ifndef CSSTransitionData_h +#define CSSTransitionData_h + +#include "core/CSSPropertyNames.h" +#include "core/animation/css/CSSTimingData.h" +#include "wtf/Vector.h" + +namespace WebCore { + +class CSSTransitionData FINAL : public CSSTimingData { +public: + enum TransitionPropertyType { + TransitionNone, + TransitionSingleProperty, + TransitionUnknown, + TransitionAll + }; + + // FIXME: We shouldn't allow 'none' to be used alongside other properties. + struct TransitionProperty { + TransitionProperty(CSSPropertyID id) + : propertyType(TransitionSingleProperty) + , propertyId(id) + { + ASSERT(id != CSSPropertyInvalid); + } + + TransitionProperty(const String& string) + : propertyType(TransitionUnknown) + , propertyId(CSSPropertyInvalid) + , propertyString(string) + { + } + + TransitionProperty(TransitionPropertyType type) + : propertyType(type) + , propertyId(CSSPropertyInvalid) + { + ASSERT(type == TransitionNone || type == TransitionAll); + } + + bool operator==(const TransitionProperty& other) const { return propertyType == other.propertyType && propertyId == other.propertyId && propertyString == other.propertyString; } + + TransitionPropertyType propertyType; + CSSPropertyID propertyId; + String propertyString; + }; + + static PassOwnPtrWillBeRawPtr<CSSTransitionData> create() + { + return adoptPtrWillBeNoop(new CSSTransitionData); + } + + static PassOwnPtrWillBeRawPtr<CSSTransitionData> create(const CSSTransitionData& transitionData) + { + return adoptPtrWillBeNoop(new CSSTransitionData(transitionData)); + } + + bool transitionsMatchForStyleRecalc(const CSSTransitionData& other) const; + + Timing convertToTiming(size_t index) const; + + const Vector<TransitionProperty>& propertyList() const { return m_propertyList; } + Vector<TransitionProperty>& propertyList() { return m_propertyList; } + + static TransitionProperty initialProperty() { return TransitionProperty(TransitionAll); } + +private: + CSSTransitionData(); + explicit CSSTransitionData(const CSSTransitionData&); + + Vector<TransitionProperty> m_propertyList; +}; + +} // namespace WebCore + +#endif // CSSTransitionData_h diff --git a/chromium/third_party/WebKit/Source/core/animation/css/TransitionTimeline.cpp b/chromium/third_party/WebKit/Source/core/animation/css/TransitionTimeline.cpp deleted file mode 100644 index 33ec27f2b0b..00000000000 --- a/chromium/third_party/WebKit/Source/core/animation/css/TransitionTimeline.cpp +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (C) 2013 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "core/animation/css/TransitionTimeline.h" - -#include "core/animation/ActiveAnimations.h" -#include "core/animation/AnimationClock.h" -#include "core/animation/AnimationStack.h" - -namespace WebCore { - -PassRefPtr<TransitionTimeline> TransitionTimeline::create(Document* document, PassOwnPtr<PlatformTiming> timing) -{ - return adoptRef(new TransitionTimeline(document, timing)); -} - -TransitionTimeline::TransitionTimeline(Document* document, PassOwnPtr<PlatformTiming> timing) - : DocumentTimeline(document, timing) -{ - setZeroTime(document->animationClock().currentTime()); - document->animationClock().unfreeze(); -} - -} // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/core/animation/css/TransitionTimeline.h b/chromium/third_party/WebKit/Source/core/animation/css/TransitionTimeline.h deleted file mode 100644 index 6d55f48772e..00000000000 --- a/chromium/third_party/WebKit/Source/core/animation/css/TransitionTimeline.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C) 2013 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef TransitionTimeline_h -#define TransitionTimeline_h - -#include "core/animation/DocumentTimeline.h" - -namespace WebCore { - -class TransitionTimeline FINAL : public DocumentTimeline { -public: - static PassRefPtr<TransitionTimeline> create(Document*, PassOwnPtr<PlatformTiming> = nullptr); - -private: - TransitionTimeline(Document*, PassOwnPtr<PlatformTiming>); -}; - -} // namespace WebCore - -#endif |