PassRefPtr<AnimatableValue> AnimatableFilterOperations::interpolateTo(const AnimatableValue* value, double fraction) const { if (usesDefaultInterpolationWith(value)) return defaultInterpolateTo(this, value, fraction); const AnimatableFilterOperations* target = toAnimatableFilterOperations(value); FilterOperations result; size_t fromSize = operations().size(); size_t toSize = target->operations().size(); size_t size = std::max(fromSize, toSize); for (size_t i = 0; i < size; i++) { #if ENABLE(OILPAN) FilterOperation* from = (i < fromSize) ? m_operationWrapper->operations().operations()[i].get() : 0; FilterOperation* to = (i < toSize) ? target->m_operationWrapper->operations().operations()[i].get() : 0; #else FilterOperation* from = (i < fromSize) ? m_operations.operations()[i].get() : 0; FilterOperation* to = (i < toSize) ? target->m_operations.operations()[i].get() : 0; #endif RefPtrWillBeRawPtr<FilterOperation> blendedOp = FilterOperation::blend(from, to, fraction); if (blendedOp) result.operations().append(blendedOp); else ASSERT_NOT_REACHED(); } return AnimatableFilterOperations::create(result); }
void CompositorAnimationsImpl::addKeyframesToCurve(blink::WebAnimationCurve& curve, const KeyframeVector& keyframes, const TimingFunction& timingFunction) { for (size_t i = 0; i < keyframes.size(); i++) { const TimingFunction* keyframeTimingFunction = 0; if (i + 1 < keyframes.size()) { // Last keyframe has no timing function switch (timingFunction.type()) { case TimingFunction::LinearFunction: case TimingFunction::CubicBezierFunction: keyframeTimingFunction = &timingFunction; break; case TimingFunction::ChainedFunction: { const ChainedTimingFunction& chained = toChainedTimingFunction(timingFunction); // ChainedTimingFunction criteria was checked in isCandidate, // assert it is valid. ASSERT(keyframes.size() == chained.m_segments.size() + 1); keyframeTimingFunction = chained.m_segments[i].m_timingFunction.get(); break; } case TimingFunction::StepsFunction: default: ASSERT_NOT_REACHED(); } } ASSERT(!keyframes[i]->value()->dependsOnUnderlyingValue()); RefPtr<AnimatableValue> value = keyframes[i]->value()->compositeOnto(0); switch (curve.type()) { case blink::WebAnimationCurve::AnimationCurveTypeFilter: { OwnPtr<blink::WebFilterOperations> ops = adoptPtr(blink::Platform::current()->compositorSupport()->createFilterOperations()); bool converted = toWebFilterOperations(toAnimatableFilterOperations(value.get())->operations(), ops.get()); ASSERT_UNUSED(converted, converted); blink::WebFilterKeyframe filterKeyframe(keyframes[i]->offset(), ops.release()); blink::WebFilterAnimationCurve* filterCurve = static_cast<blink::WebFilterAnimationCurve*>(&curve); addKeyframeWithTimingFunction(*filterCurve, filterKeyframe, keyframeTimingFunction); break; } case blink::WebAnimationCurve::AnimationCurveTypeFloat: { blink::WebFloatKeyframe floatKeyframe(keyframes[i]->offset(), toAnimatableDouble(value.get())->toDouble()); blink::WebFloatAnimationCurve* floatCurve = static_cast<blink::WebFloatAnimationCurve*>(&curve); addKeyframeWithTimingFunction(*floatCurve, floatKeyframe, keyframeTimingFunction); break; } case blink::WebAnimationCurve::AnimationCurveTypeTransform: { OwnPtr<blink::WebTransformOperations> ops = adoptPtr(blink::Platform::current()->compositorSupport()->createTransformOperations()); toWebTransformOperations(toAnimatableTransform(value.get())->transformOperations(), FloatSize(), ops.get()); blink::WebTransformKeyframe transformKeyframe(keyframes[i]->offset(), ops.release()); blink::WebTransformAnimationCurve* transformCurve = static_cast<blink::WebTransformAnimationCurve*>(&curve); addKeyframeWithTimingFunction(*transformCurve, transformKeyframe, keyframeTimingFunction); break; } default: ASSERT_NOT_REACHED(); } } }
bool CompositorAnimations::isCandidateForAnimationOnCompositor(const Timing& timing, const Element& targetElement, const AnimationPlayer* playerToAdd, const AnimationEffect& effect, double playerPlaybackRate) { const KeyframeEffectModelBase& keyframeEffect = toKeyframeEffectModelBase(effect); PropertySet properties = keyframeEffect.properties(); if (properties.isEmpty()) return false; for (const auto& property : properties) { const PropertySpecificKeyframeVector& keyframes = keyframeEffect.getPropertySpecificKeyframes(property); ASSERT(keyframes.size() >= 2); for (const auto& keyframe : keyframes) { // FIXME: Determine candidacy based on the CSSValue instead of a snapshot AnimatableValue. bool isNeutralKeyframe = keyframe->isStringPropertySpecificKeyframe() && !toStringPropertySpecificKeyframe(keyframe.get())->value() && keyframe->composite() == AnimationEffect::CompositeAdd; if ((keyframe->composite() != AnimationEffect::CompositeReplace && !isNeutralKeyframe) || !keyframe->getAnimatableValue()) return false; switch (property) { case CSSPropertyOpacity: break; case CSSPropertyTransform: if (toAnimatableTransform(keyframe->getAnimatableValue().get())->transformOperations().dependsOnBoxSize()) return false; break; case CSSPropertyWebkitFilter: { const FilterOperations& operations = toAnimatableFilterOperations(keyframe->getAnimatableValue().get())->operations(); if (operations.hasFilterThatMovesPixels()) return false; break; } default: // any other types are not allowed to run on compositor. return false; } } } if (playerToAdd && hasIncompatibleAnimations(targetElement, *playerToAdd, effect)) return false; CompositorAnimationsImpl::CompositorTiming out; if (!CompositorAnimationsImpl::convertTimingForCompositor(timing, 0, out, playerPlaybackRate)) return false; return true; }
void CompositorAnimationsImpl::addKeyframesToCurve(WebCompositorAnimationCurve& curve, const PropertySpecificKeyframeVector& keyframes, const Timing& timing) { auto* lastKeyframe = keyframes.last().get(); for (const auto& keyframe : keyframes) { const TimingFunction* keyframeTimingFunction = 0; if (keyframe != lastKeyframe) { // Ignore timing function of last frame. keyframeTimingFunction = &keyframe->easing(); } // FIXME: This relies on StringKeyframes being eagerly evaluated, which will // not happen eventually. Instead we should extract the CSSValue here // and convert using another set of toAnimatableXXXOperations functions. const AnimatableValue* value = keyframe->getAnimatableValue().get(); switch (curve.type()) { case WebCompositorAnimationCurve::AnimationCurveTypeFilter: { OwnPtr<WebFilterOperations> ops = adoptPtr(Platform::current()->compositorSupport()->createFilterOperations()); toWebFilterOperations(toAnimatableFilterOperations(value)->operations(), ops.get()); WebFilterKeyframe filterKeyframe(keyframe->offset(), ops.release()); WebFilterAnimationCurve* filterCurve = static_cast<WebFilterAnimationCurve*>(&curve); addKeyframeWithTimingFunction(*filterCurve, filterKeyframe, keyframeTimingFunction); break; } case WebCompositorAnimationCurve::AnimationCurveTypeFloat: { WebFloatKeyframe floatKeyframe(keyframe->offset(), toAnimatableDouble(value)->toDouble()); WebFloatAnimationCurve* floatCurve = static_cast<WebFloatAnimationCurve*>(&curve); addKeyframeWithTimingFunction(*floatCurve, floatKeyframe, keyframeTimingFunction); break; } case WebCompositorAnimationCurve::AnimationCurveTypeTransform: { OwnPtr<WebTransformOperations> ops = adoptPtr(Platform::current()->compositorSupport()->createTransformOperations()); toWebTransformOperations(toAnimatableTransform(value)->transformOperations(), ops.get()); WebTransformKeyframe transformKeyframe(keyframe->offset(), ops.release()); WebTransformAnimationCurve* transformCurve = static_cast<WebTransformAnimationCurve*>(&curve); addKeyframeWithTimingFunction(*transformCurve, transformKeyframe, keyframeTimingFunction); break; } default: ASSERT_NOT_REACHED(); } } }
bool AnimatableFilterOperations::equalTo(const AnimatableValue* value) const { return operations() == toAnimatableFilterOperations(value)->operations(); }
bool AnimatableFilterOperations::usesDefaultInterpolationWith(const AnimatableValue* value) const { const AnimatableFilterOperations* target = toAnimatableFilterOperations(value); return !operations().canInterpolateWith(target->operations()); }
// FIXME: Generate this function. void AnimatedStyleBuilder::applyProperty(CSSPropertyID property, StyleResolverState& state, const AnimatableValue* value) { ASSERT(CSSPropertyMetadata::isAnimatableProperty(property)); if (value->isUnknown()) { StyleBuilder::applyProperty(property, state, toAnimatableUnknown(value)->toCSSValue().get()); return; } RenderStyle* style = state.style(); switch (property) { case CSSPropertyBackgroundColor: style->setBackgroundColor(toAnimatableColor(value)->color()); return; case CSSPropertyBackgroundImage: setOnFillLayers<CSSPropertyBackgroundImage>(style->accessBackgroundLayers(), value, state); return; case CSSPropertyBackgroundPositionX: setOnFillLayers<CSSPropertyBackgroundPositionX>(style->accessBackgroundLayers(), value, state); return; case CSSPropertyBackgroundPositionY: setOnFillLayers<CSSPropertyBackgroundPositionY>(style->accessBackgroundLayers(), value, state); return; case CSSPropertyBackgroundSize: setOnFillLayers<CSSPropertyBackgroundSize>(style->accessBackgroundLayers(), value, state); return; case CSSPropertyBorderBottomColor: style->setBorderBottomColor(toAnimatableColor(value)->color()); return; case CSSPropertyBorderBottomLeftRadius: style->setBorderBottomLeftRadius(animatableValueToLengthSize(value, state, ValueRangeNonNegative)); return; case CSSPropertyBorderBottomRightRadius: style->setBorderBottomRightRadius(animatableValueToLengthSize(value, state, ValueRangeNonNegative)); return; case CSSPropertyBorderBottomWidth: style->setBorderBottomWidth(animatableValueRoundClampTo<unsigned>(value)); return; case CSSPropertyBorderImageOutset: style->setBorderImageOutset(animatableValueToBorderImageLengthBox(value, state)); return; case CSSPropertyBorderImageSlice: style->setBorderImageSlices(animatableValueToLengthBox(value, state, ValueRangeNonNegative)); return; case CSSPropertyBorderImageSource: style->setBorderImageSource(state.styleImage(property, toAnimatableImage(value)->toCSSValue())); return; case CSSPropertyBorderImageWidth: style->setBorderImageWidth(animatableValueToBorderImageLengthBox(value, state)); return; case CSSPropertyBorderLeftColor: style->setBorderLeftColor(toAnimatableColor(value)->color()); return; case CSSPropertyBorderLeftWidth: style->setBorderLeftWidth(animatableValueRoundClampTo<unsigned>(value)); return; case CSSPropertyBorderRightColor: style->setBorderRightColor(toAnimatableColor(value)->color()); return; case CSSPropertyBorderRightWidth: style->setBorderRightWidth(animatableValueRoundClampTo<unsigned>(value)); return; case CSSPropertyBorderTopColor: style->setBorderTopColor(toAnimatableColor(value)->color()); return; case CSSPropertyBorderTopLeftRadius: style->setBorderTopLeftRadius(animatableValueToLengthSize(value, state, ValueRangeNonNegative)); return; case CSSPropertyBorderTopRightRadius: style->setBorderTopRightRadius(animatableValueToLengthSize(value, state, ValueRangeNonNegative)); return; case CSSPropertyBorderTopWidth: style->setBorderTopWidth(animatableValueRoundClampTo<unsigned>(value)); return; case CSSPropertyBottom: style->setBottom(animatableValueToLength(value, state)); return; case CSSPropertyBoxShadow: case CSSPropertyWebkitBoxShadow: style->setBoxShadow(toAnimatableShadow(value)->shadowList()); return; case CSSPropertyClip: style->setClip(animatableValueToLengthBox(value, state)); return; case CSSPropertyColor: style->setColor(toAnimatableColor(value)->color()); return; case CSSPropertyFlexGrow: style->setFlexGrow(clampTo<float>(toAnimatableDouble(value)->toDouble(), 0)); return; case CSSPropertyFlexShrink: style->setFlexShrink(clampTo<float>(toAnimatableDouble(value)->toDouble(), 0)); return; case CSSPropertyFlexBasis: style->setFlexBasis(animatableValueToLength(value, state, ValueRangeNonNegative)); return; case CSSPropertyFontSize: style->setFontSize(clampTo<float>(toAnimatableDouble(value)->toDouble(), 0)); return; case CSSPropertyFontStretch: style->setFontStretch(animatableValueToFontStretch(value)); return; case CSSPropertyFontWeight: style->setFontWeight(animatableValueToFontWeight(value)); return; case CSSPropertyHeight: style->setHeight(animatableValueToLength(value, state, ValueRangeNonNegative)); return; case CSSPropertyLeft: style->setLeft(animatableValueToLength(value, state)); return; case CSSPropertyLineHeight: if (value->isLength()) style->setLineHeight(animatableValueToLength(value, state, ValueRangeNonNegative)); else style->setLineHeight(Length(clampTo<float>(toAnimatableDouble(value)->toDouble(), 0), Percent)); return; case CSSPropertyLetterSpacing: style->setLetterSpacing(clampTo<float>(toAnimatableDouble(value)->toDouble())); return; case CSSPropertyMarginBottom: style->setMarginBottom(animatableValueToLength(value, state)); return; case CSSPropertyMarginLeft: style->setMarginLeft(animatableValueToLength(value, state)); return; case CSSPropertyMarginRight: style->setMarginRight(animatableValueToLength(value, state)); return; case CSSPropertyMarginTop: style->setMarginTop(animatableValueToLength(value, state)); return; case CSSPropertyMaxHeight: style->setMaxHeight(animatableValueToLength(value, state, ValueRangeNonNegative)); return; case CSSPropertyMaxWidth: style->setMaxWidth(animatableValueToLength(value, state, ValueRangeNonNegative)); return; case CSSPropertyMinHeight: style->setMinHeight(animatableValueToLength(value, state, ValueRangeNonNegative)); return; case CSSPropertyMinWidth: style->setMinWidth(animatableValueToLength(value, state, ValueRangeNonNegative)); return; case CSSPropertyObjectPosition: style->setObjectPosition(animatableValueToLengthPoint(value, state)); return; case CSSPropertyOpacity: // Avoiding a value of 1 forces a layer to be created. style->setOpacity(clampTo<float>(toAnimatableDouble(value)->toDouble(), 0, nextafterf(1, 0))); return; case CSSPropertyOutlineColor: style->setOutlineColor(toAnimatableColor(value)->color()); return; case CSSPropertyOutlineOffset: style->setOutlineOffset(animatableValueRoundClampTo<int>(value)); return; case CSSPropertyOutlineWidth: style->setOutlineWidth(animatableValueRoundClampTo<unsigned short>(value)); return; case CSSPropertyPaddingBottom: style->setPaddingBottom(animatableValueToLength(value, state, ValueRangeNonNegative)); return; case CSSPropertyPaddingLeft: style->setPaddingLeft(animatableValueToLength(value, state, ValueRangeNonNegative)); return; case CSSPropertyPaddingRight: style->setPaddingRight(animatableValueToLength(value, state, ValueRangeNonNegative)); return; case CSSPropertyPaddingTop: style->setPaddingTop(animatableValueToLength(value, state, ValueRangeNonNegative)); return; case CSSPropertyRight: style->setRight(animatableValueToLength(value, state)); return; case CSSPropertyTextDecorationColor: style->setTextDecorationColor(toAnimatableColor(value)->color()); return; case CSSPropertyTextIndent: style->setTextIndent(animatableValueToLength(value, state)); return; case CSSPropertyTextShadow: style->setTextShadow(toAnimatableShadow(value)->shadowList()); return; case CSSPropertyTop: style->setTop(animatableValueToLength(value, state)); return; case CSSPropertyWebkitBackgroundSize: setOnFillLayers<CSSPropertyWebkitBackgroundSize>(style->accessBackgroundLayers(), value, state); return; case CSSPropertyWebkitBorderHorizontalSpacing: style->setHorizontalBorderSpacing(animatableValueRoundClampTo<unsigned short>(value)); return; case CSSPropertyWebkitBorderVerticalSpacing: style->setVerticalBorderSpacing(animatableValueRoundClampTo<unsigned short>(value)); return; case CSSPropertyWebkitClipPath: style->setClipPath(toAnimatableClipPathOperation(value)->clipPathOperation()); return; case CSSPropertyFilter: style->setFilter(toAnimatableFilterOperations(value)->operations()); return; case CSSPropertyPerspective: style->setPerspective(clampTo<float>(toAnimatableDouble(value)->toDouble())); return; case CSSPropertyPerspectiveOrigin: { const AnimatableLengthPoint* animatableLengthPoint = toAnimatableLengthPoint(value); style->setPerspectiveOriginX(animatableValueToLength(animatableLengthPoint->x(), state)); style->setPerspectiveOriginY(animatableValueToLength(animatableLengthPoint->y(), state)); return; } case CSSPropertyWebkitTextStrokeColor: style->setTextStrokeColor(toAnimatableColor(value)->color()); return; case CSSPropertyTransform: { const TransformOperations& operations = toAnimatableTransform(value)->transformOperations(); // FIXME: This normalization (handling of 'none') should be performed at input in AnimatableValueFactory. style->setTransform(operations.size() ? operations : TransformOperations(true)); return; } case CSSPropertyTransformOrigin: { const AnimatableLengthPoint3D* animatableLengthPoint3D = toAnimatableLengthPoint3D(value); style->setTransformOriginX(animatableValueToLength(animatableLengthPoint3D->x(), state)); style->setTransformOriginY(animatableValueToLength(animatableLengthPoint3D->y(), state)); style->setTransformOriginZ(clampTo<float>(toAnimatableDouble(animatableLengthPoint3D->z())->toDouble())); return; } case CSSPropertyWidth: style->setWidth(animatableValueToLength(value, state, ValueRangeNonNegative)); return; case CSSPropertyWordSpacing: style->setWordSpacing(clampTo<float>(toAnimatableDouble(value)->toDouble())); return; case CSSPropertyVerticalAlign: style->setVerticalAlignLength(animatableValueToLength(value, state)); return; case CSSPropertyZIndex: style->setZIndex(animatableValueRoundClampTo<unsigned>(value)); return; default: ASSERT_NOT_REACHED(); } }
// FIXME: Generate this function. void AnimatedStyleBuilder::applyProperty(CSSPropertyID property, StyleResolverState& state, const AnimatableValue* value) { ASSERT(CSSPropertyMetadata::isAnimatableProperty(property)); if (value->isUnknown()) { StyleBuilder::applyProperty(property, state, toAnimatableUnknown(value)->toCSSValue().get()); return; } RenderStyle* style = state.style(); switch (property) { case CSSPropertyBackgroundColor: style->setBackgroundColor(toAnimatableColor(value)->color()); style->setVisitedLinkBackgroundColor(toAnimatableColor(value)->visitedLinkColor()); return; case CSSPropertyBackgroundImage: setOnFillLayers<CSSPropertyBackgroundImage>(style->accessBackgroundLayers(), value, state); return; case CSSPropertyBackgroundPositionX: setOnFillLayers<CSSPropertyBackgroundPositionX>(style->accessBackgroundLayers(), value, state); return; case CSSPropertyBackgroundPositionY: setOnFillLayers<CSSPropertyBackgroundPositionY>(style->accessBackgroundLayers(), value, state); return; case CSSPropertyBackgroundSize: setOnFillLayers<CSSPropertyBackgroundSize>(style->accessBackgroundLayers(), value, state); return; case CSSPropertyBaselineShift: style->setBaselineShiftValue(toAnimatableSVGLength(value)->toSVGLength()); return; case CSSPropertyBorderBottomColor: style->setBorderBottomColor(toAnimatableColor(value)->color()); style->setVisitedLinkBorderBottomColor(toAnimatableColor(value)->visitedLinkColor()); return; case CSSPropertyBorderBottomLeftRadius: style->setBorderBottomLeftRadius(animatableValueToLengthSize(value, state, ValueRangeNonNegative)); return; case CSSPropertyBorderBottomRightRadius: style->setBorderBottomRightRadius(animatableValueToLengthSize(value, state, ValueRangeNonNegative)); return; case CSSPropertyBorderBottomWidth: style->setBorderBottomWidth(animatableValueRoundClampTo<unsigned>(value)); return; case CSSPropertyBorderImageOutset: style->setBorderImageOutset(animatableValueToBorderImageLengthBox(value, state)); return; case CSSPropertyBorderImageSlice: style->setBorderImageSlices(animatableValueToLengthBox(value, state, ValueRangeNonNegative)); return; case CSSPropertyBorderImageSource: style->setBorderImageSource(state.styleImage(property, toAnimatableImage(value)->toCSSValue())); return; case CSSPropertyBorderImageWidth: style->setBorderImageWidth(animatableValueToBorderImageLengthBox(value, state)); return; case CSSPropertyBorderLeftColor: style->setBorderLeftColor(toAnimatableColor(value)->color()); style->setVisitedLinkBorderLeftColor(toAnimatableColor(value)->visitedLinkColor()); return; case CSSPropertyBorderLeftWidth: style->setBorderLeftWidth(animatableValueRoundClampTo<unsigned>(value)); return; case CSSPropertyBorderRightColor: style->setBorderRightColor(toAnimatableColor(value)->color()); style->setVisitedLinkBorderRightColor(toAnimatableColor(value)->visitedLinkColor()); return; case CSSPropertyBorderRightWidth: style->setBorderRightWidth(animatableValueRoundClampTo<unsigned>(value)); return; case CSSPropertyBorderTopColor: style->setBorderTopColor(toAnimatableColor(value)->color()); style->setVisitedLinkBorderTopColor(toAnimatableColor(value)->visitedLinkColor()); return; case CSSPropertyBorderTopLeftRadius: style->setBorderTopLeftRadius(animatableValueToLengthSize(value, state, ValueRangeNonNegative)); return; case CSSPropertyBorderTopRightRadius: style->setBorderTopRightRadius(animatableValueToLengthSize(value, state, ValueRangeNonNegative)); return; case CSSPropertyBorderTopWidth: style->setBorderTopWidth(animatableValueRoundClampTo<unsigned>(value)); return; case CSSPropertyBottom: style->setBottom(animatableValueToLength(value, state)); return; case CSSPropertyBoxShadow: case CSSPropertyWebkitBoxShadow: style->setBoxShadow(toAnimatableShadow(value)->shadowList()); return; case CSSPropertyClip: style->setClip(animatableValueToLengthBox(value, state)); return; case CSSPropertyColor: style->setColor(toAnimatableColor(value)->color()); style->setVisitedLinkColor(toAnimatableColor(value)->visitedLinkColor()); return; case CSSPropertyFillOpacity: style->setFillOpacity(clampTo<float>(toAnimatableDouble(value)->toDouble(), 0, 1)); return; case CSSPropertyFill: { const AnimatableSVGPaint* svgPaint = toAnimatableSVGPaint(value); style->accessSVGStyle().setFillPaint(svgPaint->paintType(), svgPaint->color(), svgPaint->uri(), true, false); style->accessSVGStyle().setFillPaint(svgPaint->visitedLinkPaintType(), svgPaint->visitedLinkColor(), svgPaint->visitedLinkURI(), false, true); } return; case CSSPropertyFlexGrow: style->setFlexGrow(clampTo<float>(toAnimatableDouble(value)->toDouble(), 0)); return; case CSSPropertyFlexShrink: style->setFlexShrink(clampTo<float>(toAnimatableDouble(value)->toDouble(), 0)); return; case CSSPropertyFlexBasis: style->setFlexBasis(animatableValueToLength(value, state, ValueRangeNonNegative)); return; case CSSPropertyFloodColor: style->setFloodColor(toAnimatableColor(value)->color()); return; case CSSPropertyFloodOpacity: style->setFloodOpacity(clampTo<float>(toAnimatableDouble(value)->toDouble(), 0, 1)); return; case CSSPropertyFontSize: state.fontBuilder().setSize(animatableValueToFontSize(value)); return; case CSSPropertyFontStretch: state.fontBuilder().setStretch(animatableValueToFontStretch(value)); return; case CSSPropertyFontWeight: state.fontBuilder().setWeight(animatableValueToFontWeight(value)); return; case CSSPropertyHeight: style->setHeight(animatableValueToLength(value, state, ValueRangeNonNegative)); return; case CSSPropertyLeft: style->setLeft(animatableValueToLength(value, state)); return; case CSSPropertyLightingColor: style->setLightingColor(toAnimatableColor(value)->color()); return; case CSSPropertyLineHeight: if (value->isLength()) style->setLineHeight(animatableValueToLength(value, state, ValueRangeNonNegative)); else style->setLineHeight(Length(clampTo<float>(toAnimatableDouble(value)->toDouble(), 0), Percent)); return; case CSSPropertyListStyleImage: style->setListStyleImage(state.styleImage(property, toAnimatableImage(value)->toCSSValue())); return; case CSSPropertyLetterSpacing: style->setLetterSpacing(clampTo<float>(toAnimatableDouble(value)->toDouble())); return; case CSSPropertyMarginBottom: style->setMarginBottom(animatableValueToLength(value, state)); return; case CSSPropertyMarginLeft: style->setMarginLeft(animatableValueToLength(value, state)); return; case CSSPropertyMarginRight: style->setMarginRight(animatableValueToLength(value, state)); return; case CSSPropertyMarginTop: style->setMarginTop(animatableValueToLength(value, state)); return; case CSSPropertyMaxHeight: style->setMaxHeight(animatableValueToLength(value, state, ValueRangeNonNegative)); return; case CSSPropertyMaxWidth: style->setMaxWidth(animatableValueToLength(value, state, ValueRangeNonNegative)); return; case CSSPropertyMinHeight: style->setMinHeight(animatableValueToLength(value, state, ValueRangeNonNegative)); return; case CSSPropertyMinWidth: style->setMinWidth(animatableValueToLength(value, state, ValueRangeNonNegative)); return; case CSSPropertyObjectPosition: style->setObjectPosition(animatableValueToLengthPoint(value, state)); return; case CSSPropertyOpacity: // Avoiding a value of 1 forces a layer to be created. style->setOpacity(clampTo<float>(toAnimatableDouble(value)->toDouble(), 0, nextafterf(1, 0))); return; case CSSPropertyOrphans: style->setOrphans(animatableValueRoundClampTo<unsigned short>(value, 1)); return; case CSSPropertyOutlineColor: style->setOutlineColor(toAnimatableColor(value)->color()); style->setVisitedLinkOutlineColor(toAnimatableColor(value)->visitedLinkColor()); return; case CSSPropertyOutlineOffset: style->setOutlineOffset(animatableValueRoundClampTo<int>(value)); return; case CSSPropertyOutlineWidth: style->setOutlineWidth(animatableValueRoundClampTo<unsigned short>(value)); return; case CSSPropertyPaddingBottom: style->setPaddingBottom(animatableValueToLength(value, state, ValueRangeNonNegative)); return; case CSSPropertyPaddingLeft: style->setPaddingLeft(animatableValueToLength(value, state, ValueRangeNonNegative)); return; case CSSPropertyPaddingRight: style->setPaddingRight(animatableValueToLength(value, state, ValueRangeNonNegative)); return; case CSSPropertyPaddingTop: style->setPaddingTop(animatableValueToLength(value, state, ValueRangeNonNegative)); return; case CSSPropertyRight: style->setRight(animatableValueToLength(value, state)); return; case CSSPropertyStrokeWidth: style->setStrokeWidth(animatableValueToNonNegativeSVGLength(value)); return; case CSSPropertyStopColor: style->setStopColor(toAnimatableColor(value)->color()); return; case CSSPropertyStopOpacity: style->setStopOpacity(clampTo<float>(toAnimatableDouble(value)->toDouble(), 0, 1)); return; case CSSPropertyStrokeDasharray: style->setStrokeDashArray(toAnimatableStrokeDasharrayList(value)->toSVGLengthList()); return; case CSSPropertyStrokeDashoffset: style->setStrokeDashOffset(toAnimatableSVGLength(value)->toSVGLength()); return; case CSSPropertyStrokeMiterlimit: style->setStrokeMiterLimit(clampTo<float>(toAnimatableDouble(value)->toDouble(), 1)); return; case CSSPropertyStrokeOpacity: style->setStrokeOpacity(clampTo<float>(toAnimatableDouble(value)->toDouble(), 0, 1)); return; case CSSPropertyStroke: { const AnimatableSVGPaint* svgPaint = toAnimatableSVGPaint(value); style->accessSVGStyle().setStrokePaint(svgPaint->paintType(), svgPaint->color(), svgPaint->uri(), true, false); style->accessSVGStyle().setStrokePaint(svgPaint->visitedLinkPaintType(), svgPaint->visitedLinkColor(), svgPaint->visitedLinkURI(), false, true); } return; case CSSPropertyTextDecorationColor: style->setTextDecorationColor(toAnimatableColor(value)->color()); style->setVisitedLinkTextDecorationColor(toAnimatableColor(value)->visitedLinkColor()); return; case CSSPropertyTextIndent: style->setTextIndent(animatableValueToLength(value, state)); return; case CSSPropertyTextShadow: style->setTextShadow(toAnimatableShadow(value)->shadowList()); return; case CSSPropertyTop: style->setTop(animatableValueToLength(value, state)); return; case CSSPropertyWebkitBackgroundSize: setOnFillLayers<CSSPropertyWebkitBackgroundSize>(style->accessBackgroundLayers(), value, state); return; case CSSPropertyWebkitBorderHorizontalSpacing: style->setHorizontalBorderSpacing(animatableValueRoundClampTo<unsigned short>(value)); return; case CSSPropertyWebkitBorderVerticalSpacing: style->setVerticalBorderSpacing(animatableValueRoundClampTo<unsigned short>(value)); return; case CSSPropertyWebkitClipPath: style->setClipPath(toAnimatableClipPathOperation(value)->clipPathOperation()); return; case CSSPropertyWebkitColumnCount: style->setColumnCount(animatableValueRoundClampTo<unsigned short>(value, 1)); return; case CSSPropertyWebkitColumnGap: style->setColumnGap(clampTo(toAnimatableDouble(value)->toDouble(), 0)); return; case CSSPropertyWebkitColumnRuleColor: style->setColumnRuleColor(toAnimatableColor(value)->color()); style->setVisitedLinkColumnRuleColor(toAnimatableColor(value)->visitedLinkColor()); return; case CSSPropertyWebkitColumnWidth: style->setColumnWidth(clampTo(toAnimatableDouble(value)->toDouble(), std::numeric_limits<float>::epsilon())); return; case CSSPropertyWebkitColumnRuleWidth: style->setColumnRuleWidth(animatableValueRoundClampTo<unsigned short>(value)); return; case CSSPropertyWebkitFilter: style->setFilter(toAnimatableFilterOperations(value)->operations()); return; case CSSPropertyWebkitMaskBoxImageOutset: style->setMaskBoxImageOutset(animatableValueToBorderImageLengthBox(value, state)); return; case CSSPropertyWebkitMaskBoxImageSlice: style->setMaskBoxImageSlices(animatableValueToLengthBox(toAnimatableLengthBoxAndBool(value)->box(), state, ValueRangeNonNegative)); style->setMaskBoxImageSlicesFill(toAnimatableLengthBoxAndBool(value)->flag()); return; case CSSPropertyWebkitMaskBoxImageSource: style->setMaskBoxImageSource(state.styleImage(property, toAnimatableImage(value)->toCSSValue())); return; case CSSPropertyWebkitMaskBoxImageWidth: style->setMaskBoxImageWidth(animatableValueToBorderImageLengthBox(value, state)); return; case CSSPropertyWebkitMaskImage: setOnFillLayers<CSSPropertyWebkitMaskImage>(style->accessMaskLayers(), value, state); return; case CSSPropertyWebkitMaskPositionX: setOnFillLayers<CSSPropertyWebkitMaskPositionX>(style->accessMaskLayers(), value, state); return; case CSSPropertyWebkitMaskPositionY: setOnFillLayers<CSSPropertyWebkitMaskPositionY>(style->accessMaskLayers(), value, state); return; case CSSPropertyWebkitMaskSize: setOnFillLayers<CSSPropertyWebkitMaskSize>(style->accessMaskLayers(), value, state); return; case CSSPropertyPerspective: style->setPerspective(clampTo<float>(toAnimatableDouble(value)->toDouble())); return; case CSSPropertyPerspectiveOrigin: style->setPerspectiveOrigin(animatableValueToLengthPoint(value, state)); return; case CSSPropertyShapeOutside: style->setShapeOutside(toAnimatableShapeValue(value)->shapeValue()); return; case CSSPropertyShapeMargin: style->setShapeMargin(animatableValueToLength(value, state, ValueRangeNonNegative)); return; case CSSPropertyShapeImageThreshold: style->setShapeImageThreshold(clampTo<float>(toAnimatableDouble(value)->toDouble(), 0, 1)); return; case CSSPropertyWebkitTextStrokeColor: style->setTextStrokeColor(toAnimatableColor(value)->color()); style->setVisitedLinkTextStrokeColor(toAnimatableColor(value)->visitedLinkColor()); return; case CSSPropertyTransform: { const TransformOperations& operations = toAnimatableTransform(value)->transformOperations(); // FIXME: This normalization (handling of 'none') should be performed at input in AnimatableValueFactory. style->setTransform(operations.size() ? operations : TransformOperations(true)); return; } case CSSPropertyTransformOrigin: style->setTransformOrigin(animatableValueToTransformOrigin(value, state)); return; case CSSPropertyMotionPosition: style->setMotionPosition(animatableValueToLength(value, state, ValueRangeNonNegative)); return; case CSSPropertyMotionRotation: style->setMotionRotation(toAnimatableDoubleAndBool(value)->toDouble()); style->setMotionRotationType(toAnimatableDoubleAndBool(value)->flag() ? MotionRotationAuto : MotionRotationFixed); return; case CSSPropertyWidows: style->setWidows(animatableValueRoundClampTo<unsigned short>(value, 1)); return; case CSSPropertyWidth: style->setWidth(animatableValueToLength(value, state, ValueRangeNonNegative)); return; case CSSPropertyWordSpacing: style->setWordSpacing(clampTo<float>(toAnimatableDouble(value)->toDouble())); return; case CSSPropertyVerticalAlign: style->setVerticalAlignLength(animatableValueToLength(value, state)); return; case CSSPropertyVisibility: style->setVisibility(toAnimatableVisibility(value)->visibility()); return; case CSSPropertyZIndex: style->setZIndex(animatableValueRoundClampTo<int>(value)); return; case CSSPropertyZoom: style->setZoom(clampTo<float>(toAnimatableDouble(value)->toDouble(), std::numeric_limits<float>::denorm_min())); return; default: ASSERT_NOT_REACHED(); } }
bool CompositorAnimations::isCandidateForAnimationOnCompositor(const Timing& timing, const AnimationEffect& effect) { const KeyframeEffectModel& keyframeEffect = *toKeyframeEffectModel(&effect); // Are the keyframes convertible? const KeyframeEffectModel::KeyframeVector frames = keyframeEffect.getFrames(); for (size_t i = 0; i < frames.size(); ++i) { // Only replace mode can be accelerated if (frames[i]->composite() != AnimationEffect::CompositeReplace) return false; // Check all the properties can be accelerated const PropertySet properties = frames[i]->properties(); // FIXME: properties creates a whole new PropertySet! if (properties.isEmpty()) return false; for (PropertySet::const_iterator it = properties.begin(); it != properties.end(); ++it) { switch (*it) { case CSSPropertyOpacity: continue; case CSSPropertyWebkitTransform: if (toAnimatableTransform(frames[i]->propertyValue(CSSPropertyWebkitTransform))->transformOperations().dependsOnBoxSize()) return false; continue; case CSSPropertyWebkitFilter: { const FilterOperations& operations = toAnimatableFilterOperations(frames[i]->propertyValue(CSSPropertyWebkitFilter))->operations(); if (operations.hasFilterThatMovesPixels()) return false; for (size_t i = 0; i < operations.size(); i++) { const FilterOperation& op = *operations.at(i); if (op.type() == FilterOperation::VALIDATED_CUSTOM || op.type() == FilterOperation::CUSTOM) return false; } continue; } default: return false; } } } // Is the timing object convertible? CompositorAnimationsImpl::CompositorTiming out; if (!CompositorAnimationsImpl::convertTimingForCompositor(timing, out)) return false; // Is the timing function convertible? switch (timing.timingFunction->type()) { case TimingFunction::LinearFunction: break; case TimingFunction::CubicBezierFunction: // Can have a cubic if we don't have to split it (IE only have two frames). if (frames.size() != 2) return false; ASSERT(frames[0]->offset() == 0.0 && frames[1]->offset() == 1.0); break; case TimingFunction::StepsFunction: return false; case TimingFunction::ChainedFunction: { // Currently we only support chained segments in the form the CSS code // generates. These chained segments are only one level deep and have // one timing function per frame. const ChainedTimingFunction* chained = static_cast<const ChainedTimingFunction*>(timing.timingFunction.get()); if (!chained->m_segments.size()) return false; if (frames.size() != chained->m_segments.size() + 1) return false; for (size_t timeIndex = 0; timeIndex < chained->m_segments.size(); timeIndex++) { const ChainedTimingFunction::Segment& segment = chained->m_segments[timeIndex]; if (frames[timeIndex]->offset() != segment.m_min || frames[timeIndex + 1]->offset() != segment.m_max) return false; switch (segment.m_timingFunction->type()) { case TimingFunction::LinearFunction: case TimingFunction::CubicBezierFunction: continue; case TimingFunction::StepsFunction: case TimingFunction::ChainedFunction: default: return false; } } break; } default: ASSERT_NOT_REACHED(); return false; } return true; }
bool CompositorAnimations::isCandidateForAnimationOnCompositor(const Timing& timing, const Element& targetElement, const Animation* animationToAdd, const EffectModel& effect, double animationPlaybackRate) { const KeyframeEffectModelBase& keyframeEffect = toKeyframeEffectModelBase(effect); PropertyHandleSet properties = keyframeEffect.properties(); if (properties.isEmpty()) return false; unsigned transformPropertyCount = 0; for (const auto& property : properties) { if (!property.isCSSProperty()) return false; if (isTransformRelatedCSSProperty(property)) { if (targetElement.layoutObject() && targetElement.layoutObject()->isInline()) { return false; } transformPropertyCount++; } const PropertySpecificKeyframeVector& keyframes = keyframeEffect.getPropertySpecificKeyframes(property); ASSERT(keyframes.size() >= 2); for (const auto& keyframe : keyframes) { // FIXME: Determine candidacy based on the CSSValue instead of a snapshot AnimatableValue. bool isNeutralKeyframe = keyframe->isCSSPropertySpecificKeyframe() && !toCSSPropertySpecificKeyframe(keyframe.get())->value() && keyframe->composite() == EffectModel::CompositeAdd; if ((keyframe->composite() != EffectModel::CompositeReplace && !isNeutralKeyframe) || !keyframe->getAnimatableValue()) return false; switch (property.cssProperty()) { case CSSPropertyOpacity: break; case CSSPropertyRotate: case CSSPropertyScale: case CSSPropertyTranslate: case CSSPropertyTransform: if (toAnimatableTransform(keyframe->getAnimatableValue().get())->transformOperations().dependsOnBoxSize()) return false; break; case CSSPropertyWebkitFilter: case CSSPropertyBackdropFilter: { const FilterOperations& operations = toAnimatableFilterOperations(keyframe->getAnimatableValue().get())->operations(); if (operations.hasFilterThatMovesPixels()) return false; break; } default: // any other types are not allowed to run on compositor. return false; } } } // TODO: Support multiple transform property animations on the compositor if (transformPropertyCount > 1) return false; if (animationToAdd && hasIncompatibleAnimations(targetElement, *animationToAdd, effect)) return false; CompositorAnimationsImpl::CompositorTiming out; if (!CompositorAnimationsImpl::convertTimingForCompositor(timing, 0, out, animationPlaybackRate)) return false; return true; }