author | Emilio Cobos Álvarez <emilio@crisal.io> |
Thu, 16 May 2019 23:25:10 +0000 | |
changeset 474261 | 02c806cb81d959f1fc08c7304f50266fb6a5e56c |
parent 474260 | 29c5fc63a9bf79e53cc8991c47ed47fedafda4e1 |
child 474262 | 3c388ac5887ceec18ae5db997cc34065cad9ac2f |
push id | 36027 |
push user | shindli@mozilla.com |
push date | Fri, 17 May 2019 16:24:38 +0000 |
treeherder | mozilla-central@c94c54aff466 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | boris |
bugs | 1529002 |
milestone | 68.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/gfx/layers/AnimationHelper.cpp +++ b/gfx/layers/AnimationHelper.cpp @@ -590,53 +590,59 @@ bool AnimationHelper::SampleAnimations(C } return isAnimating; } gfx::Matrix4x4 AnimationHelper::ServoAnimationValueToMatrix4x4( const nsTArray<RefPtr<RawServoAnimationValue>>& aValues, const TransformData& aTransformData) { - // FIXME: Bug 1457033: We should convert servo's animation value to matrix - // directly without nsCSSValueSharedList. + // This is a bit silly just to avoid the transform list copy from the + // animation transform list. + auto noneTranslate = StyleTranslate::None(); + auto noneRotate = StyleRotate::None(); + auto noneScale = StyleScale::None(); + const StyleTransform noneTransform; + + const StyleTranslate* translate = nullptr; + const StyleRotate* rotate = nullptr; + const StyleScale* scale = nullptr; + const StyleTransform* transform = nullptr; + // TODO: Bug 1429305: Support compositor animations for motion-path. - RefPtr<nsCSSValueSharedList> transform, translate, rotate, scale; for (const auto& value : aValues) { MOZ_ASSERT(value); - RefPtr<nsCSSValueSharedList> list; - nsCSSPropertyID id = Servo_AnimationValue_GetTransform(value, &list); + nsCSSPropertyID id = Servo_AnimationValue_GetPropertyId(value); switch (id) { case eCSSProperty_transform: MOZ_ASSERT(!transform); - transform = list.forget(); + transform = Servo_AnimationValue_GetTransform(value); break; case eCSSProperty_translate: MOZ_ASSERT(!translate); - translate = list.forget(); + translate = Servo_AnimationValue_GetTranslate(value); break; case eCSSProperty_rotate: MOZ_ASSERT(!rotate); - rotate = list.forget(); + rotate = Servo_AnimationValue_GetRotate(value); break; case eCSSProperty_scale: MOZ_ASSERT(!scale); - scale = list.forget(); + scale = Servo_AnimationValue_GetScale(value); break; default: MOZ_ASSERT_UNREACHABLE("Unsupported transform-like property"); } } - RefPtr<nsCSSValueSharedList> individualList = - nsStyleDisplay::GenerateCombinedIndividualTransform(translate, rotate, - scale); - // We expect all our transform data to arrive in device pixels gfx::Point3D transformOrigin = aTransformData.transformOrigin(); nsDisplayTransform::FrameTransformProperties props( - std::move(individualList), std::move(transform), transformOrigin); + translate ? *translate : noneTranslate, rotate ? *rotate : noneRotate, + scale ? *scale : noneScale, transform ? *transform : noneTransform, + transformOrigin); return nsDisplayTransform::GetResultingTransformMatrix( props, aTransformData.origin(), aTransformData.appUnitsPerDevPixel(), 0, &aTransformData.bounds()); } } // namespace layers } // namespace mozilla
--- a/gfx/layers/composite/AsyncCompositionManager.cpp +++ b/gfx/layers/composite/AsyncCompositionManager.cpp @@ -41,18 +41,16 @@ # include "mozilla/layers/UiCompositorControllerParent.h" # include "mozilla/widget/AndroidCompositorWidget.h" #endif #include "GeckoProfiler.h" #include "FrameUniformityData.h" #include "TreeTraversal.h" // for ForEachNode, BreadthFirstSearch #include "VsyncSource.h" -struct nsCSSValueSharedList; - namespace mozilla { namespace layers { using namespace mozilla::gfx; static bool IsSameDimension(hal::ScreenOrientation o1, hal::ScreenOrientation o2) { bool isO1portrait = (o1 == hal::eScreenOrientation_PortraitPrimary ||
--- a/layout/generic/nsFrame.cpp +++ b/layout/generic/nsFrame.cpp @@ -1209,18 +1209,20 @@ void nsFrame::DidSetComputedStyle(Comput oldPosition->mMinWidth != StylePosition()->mMinWidth || oldPosition->mMaxWidth != StylePosition()->mMaxWidth || oldPosition->mHeight != StylePosition()->mHeight || oldPosition->mMinHeight != StylePosition()->mMinHeight || oldPosition->mMaxHeight != StylePosition()->mMaxHeight) { needAnchorSuppression = true; } + // TODO(emilio): Should this do something about other transform-like + // properties? if (oldDisp->mPosition != StyleDisplay()->mPosition || - oldDisp->TransformChanged(*StyleDisplay())) { + oldDisp->mTransform != StyleDisplay()->mTransform) { needAnchorSuppression = true; } } if (mInScrollAnchorChain && needAnchorSuppression) { ScrollAnchorContainer::FindFor(this)->SuppressAdjustments(); } } @@ -10662,28 +10664,27 @@ static bool IsFrameScrolledOutOfView(con bool nsIFrame::IsScrolledOutOfView() const { nsRect rect = GetVisualOverflowRectRelativeToSelf(); return IsFrameScrolledOutOfView(this, rect, this); } gfx::Matrix nsIFrame::ComputeWidgetTransform() { const nsStyleUIReset* uiReset = StyleUIReset(); - if (!uiReset->mSpecifiedWindowTransform) { + if (uiReset->mMozWindowTransform.IsNone()) { return gfx::Matrix(); } nsStyleTransformMatrix::TransformReferenceBox refBox; refBox.Init(GetSize()); nsPresContext* presContext = PresContext(); int32_t appUnitsPerDevPixel = presContext->AppUnitsPerDevPixel(); gfx::Matrix4x4 matrix = nsStyleTransformMatrix::ReadTransforms( - uiReset->mSpecifiedWindowTransform->mHead, refBox, - float(appUnitsPerDevPixel)); + uiReset->mMozWindowTransform, refBox, float(appUnitsPerDevPixel)); // Apply the -moz-window-transform-origin translation to the matrix. const StyleTransformOrigin& origin = uiReset->mWindowTransformOrigin; Point transformOrigin = nsStyleTransformMatrix::Convert2DPosition( origin.horizontal, origin.vertical, refBox, appUnitsPerDevPixel); matrix.ChangeBasis(Point3D(transformOrigin.x, transformOrigin.y, 0)); gfx::Matrix result2d;
--- a/layout/painting/ActiveLayerTracker.cpp +++ b/layout/painting/ActiveLayerTracker.cpp @@ -259,34 +259,31 @@ void ActiveLayerTracker::TransferActivit layerActivity->mFrame = aFrame; aFrame->AddStateBits(NS_FRAME_HAS_LAYER_ACTIVITY_PROPERTY); aFrame->SetProperty(LayerActivityProperty(), layerActivity); } static void IncrementScaleRestyleCountIfNeeded(nsIFrame* aFrame, LayerActivity* aActivity) { const nsStyleDisplay* display = aFrame->StyleDisplay(); - if (!display->mSpecifiedTransform && !display->HasIndividualTransform() && + if (!display->HasTransformProperty() && !display->HasIndividualTransform() && !(display->mMotion && display->mMotion->HasPath())) { // The transform was removed. aActivity->mPreviousTransformScale = Nothing(); IncrementMutationCount( &aActivity->mRestyleCounts[LayerActivity::ACTIVITY_SCALE]); return; } // Compute the new scale due to the CSS transform property. nsStyleTransformMatrix::TransformReferenceBox refBox(aFrame); Matrix4x4 transform = nsStyleTransformMatrix::ReadTransforms( - display->mIndividualTransform ? display->mIndividualTransform->mHead - : nullptr, - nsLayoutUtils::ResolveMotionPath(aFrame), - display->mSpecifiedTransform ? display->mSpecifiedTransform->mHead - : nullptr, - refBox, AppUnitsPerCSSPixel()); + display->mTranslate, display->mRotate, display->mScale, + nsLayoutUtils::ResolveMotionPath(aFrame), display->mTransform, refBox, + AppUnitsPerCSSPixel()); Matrix transform2D; if (!transform.Is2D(&transform2D)) { // We don't attempt to handle 3D transforms; just assume the scale changed. aActivity->mPreviousTransformScale = Nothing(); IncrementMutationCount( &aActivity->mRestyleCounts[LayerActivity::ACTIVITY_SCALE]); return; }
--- a/layout/painting/nsDisplayList.cpp +++ b/layout/painting/nsDisplayList.cpp @@ -179,267 +179,262 @@ nsCString ActiveScrolledRoot::ToString( str.AppendPrintf("<0x%p>", asr->mScrollableFrame); if (asr->mParent) { str.AppendLiteral(", "); } } return std::move(str); } -static inline CSSAngle MakeCSSAngle(const nsCSSValue& aValue) { - return CSSAngle(aValue.GetAngleValue(), aValue.GetUnit()); -} - -static Rotate GetRotate(const nsCSSValue& aValue) { +static inline CSSAngle MakeCSSAngle(const StyleAngle& aValue) { + return CSSAngle(aValue.ToDegrees(), eCSSUnit_Degree); +} + +static Rotate GetRotate(const StyleRotate& aValue) { Rotate result = null_t(); - if (aValue.GetUnit() == eCSSUnit_None) { - return result; - } - - const nsCSSValue::Array* array = aValue.GetArrayValue(); - switch (nsStyleTransformMatrix::TransformFunctionOf(array)) { - case eCSSKeyword_rotate: - result = Rotate(Rotation(MakeCSSAngle(array->Item(1)))); + switch (aValue.tag) { + case StyleRotate::Tag::None: + break; + case StyleRotate::Tag::Rotate: + result = Rotate(Rotation(MakeCSSAngle(aValue.AsRotate()))); break; - case eCSSKeyword_rotate3d: - result = Rotate(Rotation3D( - array->Item(1).GetFloatValue(), array->Item(2).GetFloatValue(), - array->Item(3).GetFloatValue(), MakeCSSAngle(array->Item(4)))); + case StyleRotate::Tag::Rotate3D: { + const auto& rotate = aValue.AsRotate3D(); + result = Rotate( + Rotation3D(rotate._0, rotate._1, rotate._2, MakeCSSAngle(rotate._3))); break; + } default: MOZ_ASSERT_UNREACHABLE("Unsupported rotate"); } return result; } -static Scale GetScale(const nsCSSValue& aValue) { +static Scale GetScale(const StyleScale& aValue) { Scale result(1., 1., 1.); - if (aValue.GetUnit() == eCSSUnit_None) { - // Use (1, 1, 1) to replace the none case. - return result; - } - - const nsCSSValue::Array* array = aValue.GetArrayValue(); - switch (nsStyleTransformMatrix::TransformFunctionOf(array)) { - case eCSSKeyword_scalex: - result.x() = array->Item(1).GetFloatValue(); - break; - case eCSSKeyword_scaley: - result.y() = array->Item(1).GetFloatValue(); + switch (aValue.tag) { + case StyleScale::Tag::None: break; - case eCSSKeyword_scalez: - result.z() = array->Item(1).GetFloatValue(); + case StyleScale::Tag::Scale: { + auto& scale = aValue.AsScale(); + result.x() = scale._0; + result.y() = scale._1; break; - case eCSSKeyword_scale: - result.x() = array->Item(1).GetFloatValue(); - // scale(x) is shorthand for scale(x, x); - result.y() = - array->Count() == 2 ? result.x() : array->Item(2).GetFloatValue(); + } + case StyleScale::Tag::Scale3D: { + auto& scale = aValue.AsScale3D(); + result.x() = scale._0; + result.y() = scale._1; + result.z() = scale._2; break; - case eCSSKeyword_scale3d: - result.x() = array->Item(1).GetFloatValue(); - result.y() = array->Item(2).GetFloatValue(); - result.z() = array->Item(3).GetFloatValue(); - break; + } default: MOZ_ASSERT_UNREACHABLE("Unsupported scale"); } return result; } -static Translation GetTranslate(const nsCSSValue& aValue, +static Translation GetTranslate( + TransformReferenceBox& aRefBox, const LengthPercentage& aX, + const LengthPercentage& aY = LengthPercentage::Zero(), + const Length& aZ = Length{0}) { + Translation result(0, 0, 0); + result.x() = nsStyleTransformMatrix::ProcessTranslatePart( + aX, &aRefBox, &TransformReferenceBox::Width); + result.y() = nsStyleTransformMatrix::ProcessTranslatePart( + aY, &aRefBox, &TransformReferenceBox::Height); + result.z() = aZ.ToCSSPixels(); + return result; +} + +static Translation GetTranslate(const StyleTranslate& aValue, TransformReferenceBox& aRefBox) { Translation result(0, 0, 0); - if (aValue.GetUnit() == eCSSUnit_None) { - // Use (0, 0, 0) to replace the none case. - return result; - } - - const nsCSSValue::Array* array = aValue.GetArrayValue(); - switch (nsStyleTransformMatrix::TransformFunctionOf(array)) { - case eCSSKeyword_translatex: - result.x() = nsStyleTransformMatrix::ProcessTranslatePart( - array->Item(1), &aRefBox, &TransformReferenceBox::Width); + switch (aValue.tag) { + case StyleTranslate::Tag::None: break; - case eCSSKeyword_translatey: - result.y() = nsStyleTransformMatrix::ProcessTranslatePart( - array->Item(1), &aRefBox, &TransformReferenceBox::Height); + case StyleTranslate::Tag::Translate: { + auto& translate = aValue.AsTranslate(); + result = GetTranslate(aRefBox, translate._0, translate._1); break; - case eCSSKeyword_translatez: - result.z() = - nsStyleTransformMatrix::ProcessTranslatePart(array->Item(1), nullptr); + } + case StyleTranslate::Tag::Translate3D: { + auto& translate = aValue.AsTranslate3D(); + result = GetTranslate(aRefBox, translate._0, translate._1, translate._2); break; - case eCSSKeyword_translate: - result.x() = nsStyleTransformMatrix::ProcessTranslatePart( - array->Item(1), &aRefBox, &TransformReferenceBox::Width); - // translate(x) is shorthand for translate(x, 0) - if (array->Count() == 3) { - result.y() = nsStyleTransformMatrix::ProcessTranslatePart( - array->Item(2), &aRefBox, &TransformReferenceBox::Height); - } - break; - case eCSSKeyword_translate3d: - result.x() = nsStyleTransformMatrix::ProcessTranslatePart( - array->Item(1), &aRefBox, &TransformReferenceBox::Width); - result.y() = nsStyleTransformMatrix::ProcessTranslatePart( - array->Item(2), &aRefBox, &TransformReferenceBox::Height); - result.z() = - nsStyleTransformMatrix::ProcessTranslatePart(array->Item(3), nullptr); - break; + } default: MOZ_ASSERT_UNREACHABLE("Unsupported translate"); } return result; } static void AddTransformFunctions( - const nsCSSValueList* aList, mozilla::ComputedStyle* aStyle, - nsPresContext* aPresContext, TransformReferenceBox& aRefBox, + const StyleTransform& aTransform, TransformReferenceBox& aRefBox, InfallibleTArray<TransformFunction>& aFunctions) { - if (aList->mValue.GetUnit() == eCSSUnit_None) { - return; - } - - for (const nsCSSValueList* curr = aList; curr; curr = curr->mNext) { - const nsCSSValue& currElem = curr->mValue; - NS_ASSERTION(currElem.GetUnit() == eCSSUnit_Function, - "Stream should consist solely of functions!"); - nsCSSValue::Array* array = currElem.GetArrayValue(); - switch (nsStyleTransformMatrix::TransformFunctionOf(array)) { - case eCSSKeyword_rotatex: { - CSSAngle theta = MakeCSSAngle(array->Item(1)); + for (const StyleTransformOperation& op : aTransform.Operations()) { + switch (op.tag) { + case StyleTransformOperation::Tag::RotateX: { + CSSAngle theta = MakeCSSAngle(op.AsRotateX()); aFunctions.AppendElement(RotationX(theta)); break; } - case eCSSKeyword_rotatey: { - CSSAngle theta = MakeCSSAngle(array->Item(1)); + case StyleTransformOperation::Tag::RotateY: { + CSSAngle theta = MakeCSSAngle(op.AsRotateY()); aFunctions.AppendElement(RotationY(theta)); break; } - case eCSSKeyword_rotatez: { - CSSAngle theta = MakeCSSAngle(array->Item(1)); + case StyleTransformOperation::Tag::RotateZ: { + CSSAngle theta = MakeCSSAngle(op.AsRotateZ()); aFunctions.AppendElement(RotationZ(theta)); break; } - case eCSSKeyword_rotate: - aFunctions.AppendElement(GetRotate(currElem).get_Rotation()); + case StyleTransformOperation::Tag::Rotate: { + CSSAngle theta = MakeCSSAngle(op.AsRotate()); + aFunctions.AppendElement(Rotation(theta)); + break; + } + case StyleTransformOperation::Tag::Rotate3D: { + const auto& rotate = op.AsRotate3D(); + CSSAngle theta = MakeCSSAngle(rotate._3); + aFunctions.AppendElement( + Rotation3D(rotate._0, rotate._1, rotate._2, theta)); break; - case eCSSKeyword_rotate3d: - aFunctions.AppendElement(GetRotate(currElem).get_Rotation3D()); + } + case StyleTransformOperation::Tag::ScaleX: { + aFunctions.AppendElement(Scale(op.AsScaleX(), 1., 1.)); + break; + } + case StyleTransformOperation::Tag::ScaleY: { + aFunctions.AppendElement(Scale(1., op.AsScaleY(), 1.)); + break; + } + case StyleTransformOperation::Tag::ScaleZ: { + aFunctions.AppendElement(Scale(1., 1., op.AsScaleZ())); + break; + } + case StyleTransformOperation::Tag::Scale: { + const auto& scale = op.AsScale(); + aFunctions.AppendElement(Scale(scale._0, scale._1, 1.)); break; - case eCSSKeyword_scalex: - case eCSSKeyword_scaley: - case eCSSKeyword_scalez: - case eCSSKeyword_scale: - case eCSSKeyword_scale3d: - aFunctions.AppendElement(GetScale(currElem)); + } + case StyleTransformOperation::Tag::Scale3D: { + const auto& scale = op.AsScale3D(); + aFunctions.AppendElement(Scale(scale._0, scale._1, scale._2)); + break; + } + case StyleTransformOperation::Tag::TranslateX: { + aFunctions.AppendElement(GetTranslate(aRefBox, op.AsTranslateX())); + break; + } + case StyleTransformOperation::Tag::TranslateY: { + aFunctions.AppendElement( + GetTranslate(aRefBox, LengthPercentage::Zero(), op.AsTranslateY())); break; - case eCSSKeyword_translatex: - case eCSSKeyword_translatey: - case eCSSKeyword_translatez: - case eCSSKeyword_translate: - case eCSSKeyword_translate3d: - aFunctions.AppendElement(GetTranslate(currElem, aRefBox)); + } + case StyleTransformOperation::Tag::TranslateZ: { + aFunctions.AppendElement(GetTranslate(aRefBox, LengthPercentage::Zero(), + LengthPercentage::Zero(), + op.AsTranslateZ())); break; - case eCSSKeyword_skewx: { - CSSAngle x = MakeCSSAngle(array->Item(1)); + } + case StyleTransformOperation::Tag::Translate: { + const auto& translate = op.AsTranslate(); + aFunctions.AppendElement( + GetTranslate(aRefBox, translate._0, translate._1)); + break; + } + case StyleTransformOperation::Tag::Translate3D: { + const auto& translate = op.AsTranslate3D(); + aFunctions.AppendElement( + GetTranslate(aRefBox, translate._0, translate._1, translate._2)); + break; + } + case StyleTransformOperation::Tag::SkewX: { + CSSAngle x = MakeCSSAngle(op.AsSkewX()); aFunctions.AppendElement(SkewX(x)); break; } - case eCSSKeyword_skewy: { - CSSAngle y = MakeCSSAngle(array->Item(1)); + case StyleTransformOperation::Tag::SkewY: { + CSSAngle y = MakeCSSAngle(op.AsSkewY()); aFunctions.AppendElement(SkewY(y)); break; } - case eCSSKeyword_skew: { - CSSAngle x = MakeCSSAngle(array->Item(1)); - // skew(x) is shorthand for skew(x, 0) - CSSAngle y(0.0f, eCSSUnit_Degree); - if (array->Count() == 3) { - y = MakeCSSAngle(array->Item(2)); - } - aFunctions.AppendElement(Skew(x, y)); + case StyleTransformOperation::Tag::Skew: { + const auto& skew = op.AsSkew(); + aFunctions.AppendElement( + Skew(MakeCSSAngle(skew._0), MakeCSSAngle(skew._1))); break; } - case eCSSKeyword_matrix: { + case StyleTransformOperation::Tag::Matrix: { gfx::Matrix4x4 matrix; - matrix._11 = array->Item(1).GetFloatValue(); - matrix._12 = array->Item(2).GetFloatValue(); + const auto& m = op.AsMatrix(); + matrix._11 = m.a; + matrix._12 = m.b; matrix._13 = 0; matrix._14 = 0; - matrix._21 = array->Item(3).GetFloatValue(); - matrix._22 = array->Item(4).GetFloatValue(); + matrix._21 = m.c; + matrix._22 = m.d; matrix._23 = 0; matrix._24 = 0; matrix._31 = 0; matrix._32 = 0; matrix._33 = 1; matrix._34 = 0; - matrix._41 = ProcessTranslatePart(array->Item(5), &aRefBox, - &TransformReferenceBox::Width); - matrix._42 = ProcessTranslatePart(array->Item(6), &aRefBox, - &TransformReferenceBox::Height); + matrix._41 = m.e; + matrix._42 = m.f; matrix._43 = 0; matrix._44 = 1; aFunctions.AppendElement(TransformMatrix(matrix)); break; } - case eCSSKeyword_matrix3d: { + case StyleTransformOperation::Tag::Matrix3D: { + const auto& m = op.AsMatrix3D(); gfx::Matrix4x4 matrix; - matrix._11 = array->Item(1).GetFloatValue(); - matrix._12 = array->Item(2).GetFloatValue(); - matrix._13 = array->Item(3).GetFloatValue(); - matrix._14 = array->Item(4).GetFloatValue(); - matrix._21 = array->Item(5).GetFloatValue(); - matrix._22 = array->Item(6).GetFloatValue(); - matrix._23 = array->Item(7).GetFloatValue(); - matrix._24 = array->Item(8).GetFloatValue(); - matrix._31 = array->Item(9).GetFloatValue(); - matrix._32 = array->Item(10).GetFloatValue(); - matrix._33 = array->Item(11).GetFloatValue(); - matrix._34 = array->Item(12).GetFloatValue(); - matrix._41 = ProcessTranslatePart(array->Item(13), &aRefBox, - &TransformReferenceBox::Width); - matrix._42 = ProcessTranslatePart(array->Item(14), &aRefBox, - &TransformReferenceBox::Height); - matrix._43 = ProcessTranslatePart(array->Item(15), &aRefBox, nullptr); - matrix._44 = array->Item(16).GetFloatValue(); + + matrix._11 = m.m11; + matrix._12 = m.m12; + matrix._13 = m.m13; + matrix._14 = m.m14; + matrix._21 = m.m21; + matrix._22 = m.m22; + matrix._23 = m.m23; + matrix._24 = m.m24; + matrix._31 = m.m31; + matrix._32 = m.m32; + matrix._33 = m.m33; + matrix._34 = m.m34; + + matrix._41 = m.m41; + matrix._42 = m.m42; + matrix._43 = m.m43; + matrix._44 = m.m44; aFunctions.AppendElement(TransformMatrix(matrix)); break; } - case eCSSKeyword_interpolatematrix: { + case StyleTransformOperation::Tag::InterpolateMatrix: { Matrix4x4 matrix; - nsStyleTransformMatrix::ProcessInterpolateMatrix(matrix, array, - aRefBox); - aFunctions.AppendElement(TransformMatrix(matrix)); - break; - } - case eCSSKeyword_accumulatematrix: { - Matrix4x4 matrix; - nsStyleTransformMatrix::ProcessAccumulateMatrix(matrix, array, aRefBox); + nsStyleTransformMatrix::ProcessInterpolateMatrix(matrix, op, aRefBox); aFunctions.AppendElement(TransformMatrix(matrix)); break; } - case eCSSKeyword_perspective: { - aFunctions.AppendElement(Perspective(array->Item(1).GetFloatValue())); + case StyleTransformOperation::Tag::AccumulateMatrix: { + Matrix4x4 matrix; + nsStyleTransformMatrix::ProcessAccumulateMatrix(matrix, op, aRefBox); + aFunctions.AppendElement(TransformMatrix(matrix)); + break; + } + case StyleTransformOperation::Tag::Perspective: { + aFunctions.AppendElement(Perspective(op.AsPerspective().ToCSSPixels())); break; } default: - NS_ERROR("Function not handled yet!"); - } - } -} - -static void AddTransformFunctions(const nsCSSValueSharedList* aList, - const nsIFrame* aFrame, - TransformReferenceBox& aRefBox, - layers::Animatable& aAnimatable) { - MOZ_ASSERT(aList->mHead); - AddTransformFunctions(aList->mHead, aFrame->Style(), aFrame->PresContext(), - aRefBox, aAnimatable.get_ArrayOfTransformFunction()); + MOZ_ASSERT_UNREACHABLE("Function not handled yet!"); + } + } } static TimingFunction ToTimingFunction( const Maybe<ComputedTimingFunction>& aCTF) { if (aCTF.isNothing()) { return TimingFunction(null_t()); } @@ -472,44 +467,32 @@ static void SetAnimatable(nsCSSPropertyI aFrame->Style()->GetVisitedDependentColor(&nsStyleColor::mColor); aAnimatable = aAnimationValue.GetColor(foreground); break; } case eCSSProperty_opacity: aAnimatable = aAnimationValue.GetOpacity(); break; case eCSSProperty_rotate: { - RefPtr<const nsCSSValueSharedList> list = - aAnimationValue.GetTransformList(); - MOZ_ASSERT(list && list->mHead && !list->mHead->mNext, - "should have only one nsCSSValueList for rotate"); - aAnimatable = GetRotate(list->mHead->mValue); + aAnimatable = GetRotate(aAnimationValue.GetRotateProperty()); break; } case eCSSProperty_scale: { - RefPtr<const nsCSSValueSharedList> list = - aAnimationValue.GetTransformList(); - MOZ_ASSERT(list && list->mHead && !list->mHead->mNext, - "should have only one nsCSSValueList for scale"); - aAnimatable = GetScale(list->mHead->mValue); + aAnimatable = GetScale(aAnimationValue.GetScaleProperty()); break; } case eCSSProperty_translate: { - RefPtr<const nsCSSValueSharedList> list = - aAnimationValue.GetTransformList(); - MOZ_ASSERT(list && list->mHead && !list->mHead->mNext, - "should have only one nsCSSValueList for translate"); - aAnimatable = GetTranslate(list->mHead->mValue, aRefBox); + aAnimatable = + GetTranslate(aAnimationValue.GetTranslateProperty(), aRefBox); break; } case eCSSProperty_transform: { aAnimatable = InfallibleTArray<TransformFunction>(); - RefPtr<const nsCSSValueSharedList> list = - aAnimationValue.GetTransformList(); - AddTransformFunctions(list, aFrame, aRefBox, aAnimatable); + AddTransformFunctions(aAnimationValue.GetTransformProperty(), aRefBox, + aAnimatable.get_ArrayOfTransformFunction()); break; } default: MOZ_ASSERT_UNREACHABLE("Unsupported property"); } } enum class Send { @@ -7753,19 +7736,21 @@ bool nsDisplayTransform::ComputePerspect aOutMatrix.ChangeBasis(Point3D(perspectiveOrigin.x, perspectiveOrigin.y, 0)); return true; } nsDisplayTransform::FrameTransformProperties::FrameTransformProperties( const nsIFrame* aFrame, float aAppUnitsPerPixel, const nsRect* aBoundsOverride) : mFrame(aFrame), - mIndividualTransformList(aFrame->StyleDisplay()->mIndividualTransform), + mTranslate(aFrame->StyleDisplay()->mTranslate), + mRotate(aFrame->StyleDisplay()->mRotate), + mScale(aFrame->StyleDisplay()->mScale), + mTransform(aFrame->StyleDisplay()->mTransform), mMotion(nsLayoutUtils::ResolveMotionPath(aFrame)), - mTransformList(aFrame->StyleDisplay()->mSpecifiedTransform), mToTransformOrigin(GetDeltaToTransformOrigin(aFrame, aAppUnitsPerPixel, aBoundsOverride)) {} /* Wraps up the transform matrix in a change-of-basis matrix pair that * translates from local coordinate space to transform coordinate space, then * hands it back. */ Matrix4x4 nsDisplayTransform::GetResultingTransformMatrix( @@ -7823,23 +7808,18 @@ Matrix4x4 nsDisplayTransform::GetResulti frame->IsSVGTransformed(&svgTransform, &parentsChildrenOnlyTransform); bool shouldRound = ShouldRoundTransformOrigin(frame); /* Transformed frames always have a transform, or are preserving 3d (and might * still have perspective!) */ if (aProperties.HasTransform()) { result = nsStyleTransformMatrix::ReadTransforms( - aProperties.mIndividualTransformList - ? aProperties.mIndividualTransformList->mHead - : nullptr, - aProperties.mMotion, - aProperties.mTransformList ? aProperties.mTransformList->mHead - : nullptr, - refBox, aAppUnitsPerPixel); + aProperties.mTranslate, aProperties.mRotate, aProperties.mScale, + aProperties.mMotion, aProperties.mTransform, refBox, aAppUnitsPerPixel); } else if (hasSVGTransforms) { // Correct the translation components for zoom: float pixelsPerCSSPx = AppUnitsPerCSSPixel() / aAppUnitsPerPixel; svgTransform._31 *= pixelsPerCSSPx; svgTransform._32 *= pixelsPerCSSPx; result = Matrix4x4::From2D(svgTransform); }
--- a/layout/painting/nsDisplayList.h +++ b/layout/painting/nsDisplayList.h @@ -6885,44 +6885,50 @@ class nsDisplayTransform : public nsDisp * space). * aOutMatrix is assumed to be the identity matrix, and isn't explicitly * cleared. */ static bool ComputePerspectiveMatrix(const nsIFrame* aFrame, float aAppUnitsPerPixel, Matrix4x4& aOutMatrix); - struct FrameTransformProperties { + struct MOZ_STACK_CLASS FrameTransformProperties { FrameTransformProperties(const nsIFrame* aFrame, float aAppUnitsPerPixel, const nsRect* aBoundsOverride); // This constructor is used on the compositor (for animations). // FIXME: Bug 1186329: if we want to support compositor animations for // motion path, we need to update this. For now, let mMotion be Nothing(). - FrameTransformProperties( - RefPtr<const nsCSSValueSharedList>&& aIndividualTransform, - RefPtr<const nsCSSValueSharedList>&& aTransformList, - const Point3D& aToTransformOrigin) + FrameTransformProperties(const mozilla::StyleTranslate& aTranslate, + const mozilla::StyleRotate& aRotate, + const mozilla::StyleScale& aScale, + const mozilla::StyleTransform& aTransform, + const Point3D& aToTransformOrigin) : mFrame(nullptr), - mIndividualTransformList(std::move(aIndividualTransform)), - mTransformList(std::move(aTransformList)), + mTranslate(aTranslate), + mRotate(aRotate), + mScale(aScale), + mTransform(aTransform), mToTransformOrigin(aToTransformOrigin) {} bool HasTransform() const { - return mIndividualTransformList || mTransformList || mMotion.isSome(); + return !mTranslate.IsNone() || !mRotate.IsNone() || !mScale.IsNone() || + !mTransform.IsNone() || mMotion.isSome(); } const nsIFrame* mFrame; - const RefPtr<const nsCSSValueSharedList> mIndividualTransformList; + const mozilla::StyleTranslate& mTranslate; + const mozilla::StyleRotate& mRotate; + const mozilla::StyleScale& mScale; + const mozilla::StyleTransform& mTransform; const mozilla::Maybe<mozilla::MotionPathData> mMotion; - const RefPtr<const nsCSSValueSharedList> mTransformList; const Point3D mToTransformOrigin; }; /** - * Given a frame with the -moz-transform property or an SVG transform, + * Given a frame with the transform property or an SVG transform, * returns the transformation matrix for that frame. * * @param aFrame The frame to get the matrix from. * @param aOrigin Relative to which point this transform should be applied. * @param aAppUnitsPerPixel The number of app units per graphics unit. * @param aBoundsOverride [optional] If this is nullptr (the default), the * computation will use the value of TransformReferenceBox(aFrame). * Otherwise, it will use the value of aBoundsOverride. This is
--- a/layout/style/GeckoBindings.cpp +++ b/layout/style/GeckoBindings.cpp @@ -1685,43 +1685,16 @@ void Gecko_Snapshot_DebugListAttributes( } NS_IMPL_THREADSAFE_FFI_REFCOUNTING(URLValue, CSSURLValue); NS_IMPL_THREADSAFE_FFI_REFCOUNTING(URLExtraData, URLExtraData); NS_IMPL_THREADSAFE_FFI_REFCOUNTING(nsStyleCoord::Calc, Calc); -nsCSSValueSharedList* Gecko_NewCSSValueSharedList(uint32_t aLen) { - RefPtr<nsCSSValueSharedList> list = new nsCSSValueSharedList; - if (aLen == 0) { - return list.forget().take(); - } - - list->mHead = new nsCSSValueList; - nsCSSValueList* cur = list->mHead; - for (uint32_t i = 0; i < aLen - 1; i++) { - cur->mNext = new nsCSSValueList; - cur = cur->mNext; - } - - return list.forget().take(); -} - -nsCSSValueSharedList* Gecko_NewNoneTransform() { - RefPtr<nsCSSValueSharedList> list = new nsCSSValueSharedList; - list->mHead = new nsCSSValueList; - list->mHead->mValue.SetNoneValue(); - return list.forget().take(); -} - -void Gecko_StyleDisplay_GenerateCombinedTransform(nsStyleDisplay* aDisplay) { - aDisplay->GenerateCombinedIndividualTransform(); -} - void Gecko_CSSValue_SetNumber(nsCSSValue* aCSSValue, float aNumber) { aCSSValue->SetFloatValue(aNumber, eCSSUnit_Number); } float Gecko_CSSValue_GetNumber(const nsCSSValue* aCSSValue) { return aCSSValue->GetFloatValue(); } @@ -1823,29 +1796,16 @@ void Gecko_CSSValue_SetPairList(nsCSSVal MOZ_ASSERT(NS_IsMainThread()); nsCSSValuePairList* item = aCSSValue->SetPairListValue(); for (uint32_t i = 1; i < aLen; ++i) { item->mNext = new nsCSSValuePairList; item = item->mNext; } } -void Gecko_CSSValue_InitSharedList(nsCSSValue* aCSSValue, uint32_t aLen) { - MOZ_ASSERT(aLen > 0, "Must create at least one nsCSSValueList (mHead)"); - - nsCSSValueSharedList* list = new nsCSSValueSharedList; - aCSSValue->SetSharedListValue(list); - list->mHead = new nsCSSValueList; - nsCSSValueList* cur = list->mHead; - for (uint32_t i = 1; i < aLen; ++i) { - cur->mNext = new nsCSSValueList; - cur = cur->mNext; - } -} - void Gecko_CSSValue_Drop(nsCSSValue* aCSSValue) { aCSSValue->~nsCSSValue(); } void Gecko_nsStyleFont_SetLang(nsStyleFont* aFont, nsAtom* aAtom) { aFont->mLanguage = dont_AddRef(aAtom); aFont->mExplicitLanguage = true; } void Gecko_nsStyleFont_CopyLangFrom(nsStyleFont* aFont, @@ -2107,18 +2067,16 @@ const char* Gecko_CSSKeywordString(nsCSS return value.get(); } void Gecko_AddPropertyToSet(nsCSSPropertyIDSet* aPropertySet, nsCSSPropertyID aProperty) { aPropertySet->AddProperty(aProperty); } -NS_IMPL_THREADSAFE_FFI_REFCOUNTING(nsCSSValueSharedList, CSSValueSharedList); - #define STYLE_STRUCT(name) \ \ void Gecko_Construct_Default_nsStyle##name(nsStyle##name* ptr, \ const Document* doc) { \ new (ptr) nsStyle##name(*doc); \ } \ \ void Gecko_CopyConstruct_nsStyle##name(nsStyle##name* ptr, \
--- a/layout/style/GeckoBindings.h +++ b/layout/style/GeckoBindings.h @@ -581,20 +581,16 @@ void Gecko_nsIURI_Debug(nsIURI*, nsCStri NS_DECL_THREADSAFE_FFI_REFCOUNTING(mozilla::css::URLValue, CSSURLValue); NS_DECL_THREADSAFE_FFI_REFCOUNTING(mozilla::URLExtraData, URLExtraData); void Gecko_FillAllImageLayers(nsStyleImageLayers* layers, uint32_t max_len); NS_DECL_THREADSAFE_FFI_REFCOUNTING(nsStyleCoord::Calc, Calc); -nsCSSValueSharedList* Gecko_NewCSSValueSharedList(uint32_t len); -nsCSSValueSharedList* Gecko_NewNoneTransform(); -void Gecko_StyleDisplay_GenerateCombinedTransform(nsStyleDisplay*); - // Getter for nsCSSValue nsCSSValue* Gecko_CSSValue_GetArrayItem(nsCSSValue*, int32_t index); // const version of the above function. const nsCSSValue* Gecko_CSSValue_GetArrayItemConst(const nsCSSValue*, int32_t index); nsCSSKeyword Gecko_CSSValue_GetKeyword(const nsCSSValue*); @@ -631,22 +627,18 @@ void Gecko_CSSValue_SetFloat(nsCSSValue* nsCSSUnit unit); void Gecko_CSSValue_SetPair(nsCSSValue* css_value, const nsCSSValue* xvalue, const nsCSSValue* yvalue); void Gecko_CSSValue_SetList(nsCSSValue* css_value, uint32_t len); void Gecko_CSSValue_SetPairList(nsCSSValue* css_value, uint32_t len); -void Gecko_CSSValue_InitSharedList(nsCSSValue* css_value, uint32_t len); - void Gecko_CSSValue_Drop(nsCSSValue* css_value); -NS_DECL_THREADSAFE_FFI_REFCOUNTING(nsCSSValueSharedList, CSSValueSharedList); - float Gecko_FontStretch_ToFloat(mozilla::FontStretch aStretch); void Gecko_FontStretch_SetFloat(mozilla::FontStretch* aStretch, float aFloatValue); float Gecko_FontSlantStyle_ToFloat(mozilla::FontSlantStyle aStyle); void Gecko_FontSlantStyle_SetNormal(mozilla::FontSlantStyle*); void Gecko_FontSlantStyle_SetItalic(mozilla::FontSlantStyle*);
--- a/layout/style/ServoBindings.toml +++ b/layout/style/ServoBindings.toml @@ -47,16 +47,18 @@ raw-lines = [ "use atomic_refcell::AtomicRefCell;", "use data::ElementData;", ] hide-types = [ ".*char_traits", ".*incompatible_char_type", # https://github.com/rust-lang/rust-bindgen/issues/1503 "mozilla::StyleTimingFunction.*", + # https://github.com/rust-lang/rust-bindgen/issues/1559 + "mozilla::StyleGenericTransformOperation_.*", ] bitfield-enums = [ "nsChangeHint", "mozilla::OriginFlags", ] rusty-enums = [ "nsCompatibility", "mozilla::EffectCompositor_CascadeLevel", @@ -481,16 +483,22 @@ cbindgen-types = [ { gecko = "StyleArcSlice", servo = "style_traits::arc_slice::ArcSlice" }, { gecko = "StyleForgottenArcSlicePtr", servo = "style_traits::arc_slice::ForgottenArcSlicePtr" }, { gecko = "StyleOwnedSlice", servo = "style_traits::owned_slice::OwnedSlice" }, { gecko = "StyleMozContextProperties", servo = "values::specified::svg::MozContextProperties" }, { gecko = "StyleQuotes", servo = "values::specified::list::Quotes" }, { gecko = "StyleOwnedStr", servo = "style_traits::owned_str::OwnedStr" }, { gecko = "StyleGenericBoxShadow", servo = "values::generics::effects::BoxShadow" }, { gecko = "StyleGenericSimpleShadow", servo = "values::generics::effects::SimpleShadow" }, + { gecko = "StyleGenericTransformOperation", servo = "values::generics::transform::TransformOperation" }, + { gecko = "StyleGenericTransform", servo = "values::generics::transform::Transform" }, + { gecko = "StyleGenericScale", servo = "values::generics::transform::Scale" }, + { gecko = "StyleGenericRotate", servo = "values::generics::transform::Rotate" }, + { gecko = "StyleGenericTranslate", servo = "values::generics::transform::Translate" }, + { gecko = "StyleAngle", servo = "values::computed::Angle" } ] mapped-generic-types = [ { generic = true, gecko = "mozilla::RustCell", servo = "::std::cell::Cell" }, { generic = false, gecko = "ServoNodeData", servo = "AtomicRefCell<ElementData>" }, { generic = false, gecko = "mozilla::ServoWritingMode", servo = "::logical_geometry::WritingMode" }, { generic = false, gecko = "mozilla::ServoCustomPropertiesMap", servo = "Option<::servo_arc::Arc<::custom_properties::CustomPropertiesMap>>" }, { generic = false, gecko = "mozilla::ServoRuleNode", servo = "Option<::rule_tree::StrongRuleNode>" },
--- a/layout/style/ServoStyleConstsInlines.h +++ b/layout/style/ServoStyleConstsInlines.h @@ -155,11 +155,29 @@ inline StyleAtom::StyleAtom(const StyleA inline nsAtom* StyleCustomIdent::AsAtom() const { return _0.AsAtom(); } inline nsDependentCSubstring StyleOwnedStr::AsString() const { Span<const uint8_t> s = _0.AsSpan(); return nsDependentCSubstring(reinterpret_cast<const char*>(s.Elements()), s.Length()); } +template <typename T> +inline Span<const T> StyleGenericTransform<T>::Operations() const { + return _0.AsSpan(); +} + +template <typename T> +inline bool StyleGenericTransform<T>::IsNone() const { + return Operations().IsEmpty(); +} + +inline StyleAngle StyleAngle::Zero() { return {0.0f}; } + +inline float StyleAngle::ToDegrees() const { return _0; } + +inline double StyleAngle::ToRadians() const { + return double(ToDegrees()) * M_PI / 180.0; +} + } // namespace mozilla #endif
--- a/layout/style/StyleAnimationValue.cpp +++ b/layout/style/StyleAnimationValue.cpp @@ -37,206 +37,117 @@ using namespace mozilla; using namespace mozilla::css; using namespace mozilla::dom; using namespace mozilla::gfx; using nsStyleTransformMatrix::Decompose2DMatrix; using nsStyleTransformMatrix::Decompose3DMatrix; using nsStyleTransformMatrix::ShearType; -static already_AddRefed<nsCSSValue::Array> AppendFunction( - nsCSSKeyword aTransformFunction) { - uint32_t nargs; - switch (aTransformFunction) { - case eCSSKeyword_matrix3d: - nargs = 16; - break; - case eCSSKeyword_matrix: - nargs = 6; - break; - case eCSSKeyword_rotate3d: - nargs = 4; - break; - case eCSSKeyword_interpolatematrix: - case eCSSKeyword_accumulatematrix: - case eCSSKeyword_translate3d: - case eCSSKeyword_scale3d: - nargs = 3; - break; - case eCSSKeyword_translate: - case eCSSKeyword_skew: - case eCSSKeyword_scale: - nargs = 2; - break; - default: - NS_ERROR("must be a transform function"); - MOZ_FALLTHROUGH; - case eCSSKeyword_translatex: - case eCSSKeyword_translatey: - case eCSSKeyword_translatez: - case eCSSKeyword_scalex: - case eCSSKeyword_scaley: - case eCSSKeyword_scalez: - case eCSSKeyword_skewx: - case eCSSKeyword_skewy: - case eCSSKeyword_rotate: - case eCSSKeyword_rotatex: - case eCSSKeyword_rotatey: - case eCSSKeyword_rotatez: - case eCSSKeyword_perspective: - nargs = 1; - break; +// TODO(emilio): Remove angle unit in a followup, should always be degrees. +static inline StyleAngle GetCSSAngle(const layers::CSSAngle& aAngle) { + if (aAngle.unit() != eCSSUnit_Degree) { + NS_ERROR("Bogus animation from IPC"); + return StyleAngle{0.0}; } - - RefPtr<nsCSSValue::Array> arr = nsCSSValue::Array::Create(nargs + 1); - arr->Item(0).SetIntValue(aTransformFunction, eCSSUnit_Enumerated); - - return arr.forget(); -} - -static already_AddRefed<nsCSSValue::Array> AppendTransformFunction( - nsCSSKeyword aTransformFunction, nsCSSValueList**& aListTail) { - RefPtr<nsCSSValue::Array> arr = AppendFunction(aTransformFunction); - nsCSSValueList* item = new nsCSSValueList; - item->mValue.SetArrayValue(arr, eCSSUnit_Function); - - *aListTail = item; - aListTail = &item->mNext; - - return arr.forget(); -} - -struct BogusAnimation {}; - -static inline Result<Ok, BogusAnimation> SetCSSAngle( - const layers::CSSAngle& aAngle, nsCSSValue& aValue) { - aValue.SetFloatValue(aAngle.value(), nsCSSUnit(aAngle.unit())); - if (!aValue.IsAngularUnit()) { - NS_ERROR("Bogus animation from IPC"); - return Err(BogusAnimation{}); - } - return Ok(); + return StyleAngle{aAngle.value()}; } -static Result<nsCSSValueSharedList*, BogusAnimation> CreateCSSValueList( - const InfallibleTArray<layers::TransformFunction>& aFunctions) { - nsAutoPtr<nsCSSValueList> result; - nsCSSValueList** resultTail = getter_Transfers(result); +static StyleTransformOperation OperationFromLayers( + const layers::TransformFunction& aFunction) { + switch (aFunction.type()) { + case layers::TransformFunction::TRotationX: { + const layers::CSSAngle& angle = aFunction.get_RotationX().angle(); + return StyleTransformOperation::RotateX(GetCSSAngle(angle)); + } + case layers::TransformFunction::TRotationY: { + const layers::CSSAngle& angle = aFunction.get_RotationY().angle(); + return StyleTransformOperation::RotateY(GetCSSAngle(angle)); + } + case layers::TransformFunction::TRotationZ: { + const layers::CSSAngle& angle = aFunction.get_RotationZ().angle(); + return StyleTransformOperation::RotateZ(GetCSSAngle(angle)); + } + case layers::TransformFunction::TRotation: { + const layers::CSSAngle& angle = aFunction.get_Rotation().angle(); + return StyleTransformOperation::Rotate(GetCSSAngle(angle)); + } + case layers::TransformFunction::TRotation3D: { + float x = aFunction.get_Rotation3D().x(); + float y = aFunction.get_Rotation3D().y(); + float z = aFunction.get_Rotation3D().z(); + const layers::CSSAngle& angle = aFunction.get_Rotation3D().angle(); + return StyleTransformOperation::Rotate3D(x, y, z, GetCSSAngle(angle)); + } + case layers::TransformFunction::TScale: { + float x = aFunction.get_Scale().x(); + float y = aFunction.get_Scale().y(); + float z = aFunction.get_Scale().z(); + return StyleTransformOperation::Scale3D(x, y, z); + } + case layers::TransformFunction::TTranslation: { + float x = aFunction.get_Translation().x(); + float y = aFunction.get_Translation().y(); + float z = aFunction.get_Translation().z(); + return StyleTransformOperation::Translate3D( + LengthPercentage::FromPixels(x), LengthPercentage::FromPixels(y), + Length{z}); + } + case layers::TransformFunction::TSkewX: { + const layers::CSSAngle& x = aFunction.get_SkewX().x(); + return StyleTransformOperation::SkewX(GetCSSAngle(x)); + } + case layers::TransformFunction::TSkewY: { + const layers::CSSAngle& y = aFunction.get_SkewY().y(); + return StyleTransformOperation::SkewY(GetCSSAngle(y)); + } + case layers::TransformFunction::TSkew: { + const layers::CSSAngle& x = aFunction.get_Skew().x(); + const layers::CSSAngle& y = aFunction.get_Skew().y(); + return StyleTransformOperation::Skew(GetCSSAngle(x), GetCSSAngle(y)); + } + case layers::TransformFunction::TTransformMatrix: { + const gfx::Matrix4x4& matrix = aFunction.get_TransformMatrix().value(); + return StyleTransformOperation::Matrix3D({ + matrix._11, + matrix._12, + matrix._13, + matrix._14, + matrix._21, + matrix._22, + matrix._23, + matrix._24, + matrix._31, + matrix._32, + matrix._33, + matrix._34, + matrix._41, + matrix._42, + matrix._43, + matrix._44, + }); + } + case layers::TransformFunction::TPerspective: { + float perspective = aFunction.get_Perspective().value(); + return StyleTransformOperation::Perspective(Length{perspective}); + } + default: + MOZ_ASSERT_UNREACHABLE("All functions should be implemented?"); + return StyleTransformOperation::TranslateX(LengthPercentage::Zero()); + } +} + +static nsTArray<StyleTransformOperation> CreateTransformList( + const nsTArray<layers::TransformFunction>& aFunctions) { + nsTArray<StyleTransformOperation> result; + result.SetCapacity(aFunctions.Length()); for (const layers::TransformFunction& function : aFunctions) { - RefPtr<nsCSSValue::Array> arr; - switch (function.type()) { - case layers::TransformFunction::TRotationX: { - const layers::CSSAngle& angle = function.get_RotationX().angle(); - arr = AppendTransformFunction(eCSSKeyword_rotatex, resultTail); - MOZ_TRY(SetCSSAngle(angle, arr->Item(1))); - break; - } - case layers::TransformFunction::TRotationY: { - const layers::CSSAngle& angle = function.get_RotationY().angle(); - arr = AppendTransformFunction(eCSSKeyword_rotatey, resultTail); - MOZ_TRY(SetCSSAngle(angle, arr->Item(1))); - break; - } - case layers::TransformFunction::TRotationZ: { - const layers::CSSAngle& angle = function.get_RotationZ().angle(); - arr = AppendTransformFunction(eCSSKeyword_rotatez, resultTail); - MOZ_TRY(SetCSSAngle(angle, arr->Item(1))); - break; - } - case layers::TransformFunction::TRotation: { - const layers::CSSAngle& angle = function.get_Rotation().angle(); - arr = AppendTransformFunction(eCSSKeyword_rotate, resultTail); - MOZ_TRY(SetCSSAngle(angle, arr->Item(1))); - break; - } - case layers::TransformFunction::TRotation3D: { - float x = function.get_Rotation3D().x(); - float y = function.get_Rotation3D().y(); - float z = function.get_Rotation3D().z(); - const layers::CSSAngle& angle = function.get_Rotation3D().angle(); - arr = AppendTransformFunction(eCSSKeyword_rotate3d, resultTail); - arr->Item(1).SetFloatValue(x, eCSSUnit_Number); - arr->Item(2).SetFloatValue(y, eCSSUnit_Number); - arr->Item(3).SetFloatValue(z, eCSSUnit_Number); - MOZ_TRY(SetCSSAngle(angle, arr->Item(4))); - break; - } - case layers::TransformFunction::TScale: { - arr = AppendTransformFunction(eCSSKeyword_scale3d, resultTail); - arr->Item(1).SetFloatValue(function.get_Scale().x(), eCSSUnit_Number); - arr->Item(2).SetFloatValue(function.get_Scale().y(), eCSSUnit_Number); - arr->Item(3).SetFloatValue(function.get_Scale().z(), eCSSUnit_Number); - break; - } - case layers::TransformFunction::TTranslation: { - arr = AppendTransformFunction(eCSSKeyword_translate3d, resultTail); - arr->Item(1).SetFloatValue(function.get_Translation().x(), - eCSSUnit_Pixel); - arr->Item(2).SetFloatValue(function.get_Translation().y(), - eCSSUnit_Pixel); - arr->Item(3).SetFloatValue(function.get_Translation().z(), - eCSSUnit_Pixel); - break; - } - case layers::TransformFunction::TSkewX: { - const layers::CSSAngle& x = function.get_SkewX().x(); - arr = AppendTransformFunction(eCSSKeyword_skewx, resultTail); - MOZ_TRY(SetCSSAngle(x, arr->Item(1))); - break; - } - case layers::TransformFunction::TSkewY: { - const layers::CSSAngle& y = function.get_SkewY().y(); - arr = AppendTransformFunction(eCSSKeyword_skewy, resultTail); - MOZ_TRY(SetCSSAngle(y, arr->Item(1))); - break; - } - case layers::TransformFunction::TSkew: { - const layers::CSSAngle& x = function.get_Skew().x(); - const layers::CSSAngle& y = function.get_Skew().y(); - arr = AppendTransformFunction(eCSSKeyword_skew, resultTail); - MOZ_TRY(SetCSSAngle(x, arr->Item(1))); - MOZ_TRY(SetCSSAngle(y, arr->Item(2))); - break; - } - case layers::TransformFunction::TTransformMatrix: { - arr = AppendTransformFunction(eCSSKeyword_matrix3d, resultTail); - const gfx::Matrix4x4& matrix = function.get_TransformMatrix().value(); - arr->Item(1).SetFloatValue(matrix._11, eCSSUnit_Number); - arr->Item(2).SetFloatValue(matrix._12, eCSSUnit_Number); - arr->Item(3).SetFloatValue(matrix._13, eCSSUnit_Number); - arr->Item(4).SetFloatValue(matrix._14, eCSSUnit_Number); - arr->Item(5).SetFloatValue(matrix._21, eCSSUnit_Number); - arr->Item(6).SetFloatValue(matrix._22, eCSSUnit_Number); - arr->Item(7).SetFloatValue(matrix._23, eCSSUnit_Number); - arr->Item(8).SetFloatValue(matrix._24, eCSSUnit_Number); - arr->Item(9).SetFloatValue(matrix._31, eCSSUnit_Number); - arr->Item(10).SetFloatValue(matrix._32, eCSSUnit_Number); - arr->Item(11).SetFloatValue(matrix._33, eCSSUnit_Number); - arr->Item(12).SetFloatValue(matrix._34, eCSSUnit_Number); - arr->Item(13).SetFloatValue(matrix._41, eCSSUnit_Number); - arr->Item(14).SetFloatValue(matrix._42, eCSSUnit_Number); - arr->Item(15).SetFloatValue(matrix._43, eCSSUnit_Number); - arr->Item(16).SetFloatValue(matrix._44, eCSSUnit_Number); - break; - } - case layers::TransformFunction::TPerspective: { - float perspective = function.get_Perspective().value(); - arr = AppendTransformFunction(eCSSKeyword_perspective, resultTail); - arr->Item(1).SetFloatValue(perspective, eCSSUnit_Pixel); - break; - } - default: - NS_ASSERTION(false, "All functions should be implemented?"); - } + result.AppendElement(OperationFromLayers(function)); } - if (aFunctions.Length() == 0) { - result = new nsCSSValueList(); - result->mValue.SetNoneValue(); - } - return new nsCSSValueSharedList(result.forget()); + return result; } // AnimationValue Implementation bool AnimationValue::operator==(const AnimationValue& aOther) const { if (mServo && aOther.mServo) { return Servo_AnimationValue_DeepEqual(mServo, aOther.mServo); } @@ -255,27 +166,76 @@ float AnimationValue::GetOpacity() const return Servo_AnimationValue_GetOpacity(mServo); } nscolor AnimationValue::GetColor(nscolor aForegroundColor) const { MOZ_ASSERT(mServo); return Servo_AnimationValue_GetColor(mServo, aForegroundColor); } -already_AddRefed<const nsCSSValueSharedList> AnimationValue::GetTransformList() - const { +const StyleTranslate& AnimationValue::GetTranslateProperty() const { + MOZ_ASSERT(mServo); + return *Servo_AnimationValue_GetTranslate(mServo); +} + +const StyleRotate& AnimationValue::GetRotateProperty() const { MOZ_ASSERT(mServo); - RefPtr<nsCSSValueSharedList> transform; - Servo_AnimationValue_GetTransform(mServo, &transform); - return transform.forget(); + return *Servo_AnimationValue_GetRotate(mServo); +} + +const StyleScale& AnimationValue::GetScaleProperty() const { + MOZ_ASSERT(mServo); + return *Servo_AnimationValue_GetScale(mServo); +} + +const StyleTransform& AnimationValue::GetTransformProperty() const { + MOZ_ASSERT(mServo); + return *Servo_AnimationValue_GetTransform(mServo); } Size AnimationValue::GetScaleValue(const nsIFrame* aFrame) const { - RefPtr<const nsCSSValueSharedList> list = GetTransformList(); - return nsStyleTransformMatrix::GetScaleValue(list, aFrame); + using namespace nsStyleTransformMatrix; + + const StyleTranslate* translate = nullptr; + const StyleRotate* rotate = nullptr; + const StyleScale* scale = nullptr; + const StyleTransform* transform = nullptr; + + switch (Servo_AnimationValue_GetPropertyId(mServo)) { + case eCSSProperty_scale: + scale = &GetScaleProperty(); + break; + case eCSSProperty_translate: + translate = &GetTranslateProperty(); + break; + case eCSSProperty_rotate: + rotate = &GetRotateProperty(); + break; + case eCSSProperty_transform: + transform = &GetTransformProperty(); + break; + default: + MOZ_ASSERT_UNREACHABLE( + "Should only need to check in transform properties"); + return Size(1.0, 1.0); + } + + TransformReferenceBox refBox(aFrame); + Matrix4x4 t = + ReadTransforms(translate ? *translate : StyleTranslate::None(), + rotate ? *rotate : StyleRotate::None(), + scale ? *scale : StyleScale::None(), Nothing(), + transform ? *transform : StyleTransform(), refBox, + aFrame->PresContext()->AppUnitsPerDevPixel()); + Matrix transform2d; + bool canDraw2D = t.CanDraw2D(&transform2d); + if (!canDraw2D) { + return Size(); + } + return transform2d.ScaleFactors(true); } void AnimationValue::SerializeSpecifiedValue(nsCSSPropertyID aProperty, nsAString& aString) const { MOZ_ASSERT(mServo); Servo_AnimationValue_Serialize(mServo, aProperty, &aString); } @@ -336,106 +296,68 @@ AnimationValue AnimationValue::FromStrin return result; } result.mServo = presShell->StyleSet()->ComputeAnimationValue( aElement, declarations, computedStyle); return result; } +StyleRotate RotateFromLayers(const layers::Rotate& aRotate) { + switch (aRotate.type()) { + case layers::Rotate::Tnull_t: + return StyleRotate::None(); + case layers::Rotate::TRotation: { + const layers::CSSAngle& angle = aRotate.get_Rotation().angle(); + return StyleRotate::Rotate(GetCSSAngle(angle)); + } + case layers::Rotate::TRotation3D: { + float x = aRotate.get_Rotation3D().x(); + float y = aRotate.get_Rotation3D().y(); + float z = aRotate.get_Rotation3D().z(); + const layers::CSSAngle& angle = aRotate.get_Rotation3D().angle(); + return StyleRotate::Rotate3D(x, y, z, GetCSSAngle(angle)); + } + default: + MOZ_ASSERT_UNREACHABLE("Unknown rotate value?"); + return StyleRotate::None(); + } +} + /* static */ already_AddRefed<RawServoAnimationValue> AnimationValue::FromAnimatable( nsCSSPropertyID aProperty, const layers::Animatable& aAnimatable) { - RefPtr<RawServoAnimationValue> result; - switch (aAnimatable.type()) { case layers::Animatable::Tnull_t: break; case layers::Animatable::TArrayOfTransformFunction: { - const InfallibleTArray<layers::TransformFunction>& transforms = - aAnimatable.get_ArrayOfTransformFunction(); - auto listOrError = CreateCSSValueList(transforms); - if (listOrError.isOk()) { - RefPtr<nsCSSValueSharedList> list = listOrError.unwrap(); - MOZ_ASSERT(list, "Transform list should be non null"); - result = Servo_AnimationValue_Transform(eCSSProperty_transform, list) - .Consume(); - } - break; + nsTArray<StyleTransformOperation> ops = + CreateTransformList(aAnimatable.get_ArrayOfTransformFunction()); + ; + return Servo_AnimationValue_Transform(ops.Elements(), ops.Length()) + .Consume(); } case layers::Animatable::Tfloat: - result = Servo_AnimationValue_Opacity(aAnimatable.get_float()).Consume(); - break; + return Servo_AnimationValue_Opacity(aAnimatable.get_float()).Consume(); case layers::Animatable::Tnscolor: - result = Servo_AnimationValue_Color(aProperty, aAnimatable.get_nscolor()) - .Consume(); - break; + return Servo_AnimationValue_Color(aProperty, aAnimatable.get_nscolor()) + .Consume(); case layers::Animatable::TRotate: { - RefPtr<nsCSSValueSharedList> list = new nsCSSValueSharedList; - list->mHead = new nsCSSValueList; - - const layers::Rotate& r = aAnimatable.get_Rotate(); - if (r.type() == layers::Rotate::Tnull_t) { - list->mHead->mValue.SetNoneValue(); - } else { - RefPtr<nsCSSValue::Array> arr; - if (r.type() == layers::Rotate::TRotation) { - const layers::CSSAngle& angle = r.get_Rotation().angle(); - arr = AppendFunction(eCSSKeyword_rotate); - auto rv = SetCSSAngle(angle, arr->Item(1)); - if (rv.isErr()) { - arr->Item(1).SetFloatValue(0.0, eCSSUnit_Degree); - } - } else { - MOZ_ASSERT(r.type() == layers::Rotate::TRotation3D, - "Should be rotate3D"); - float x = r.get_Rotation3D().x(); - float y = r.get_Rotation3D().y(); - float z = r.get_Rotation3D().z(); - const layers::CSSAngle& angle = r.get_Rotation3D().angle(); - arr = AppendFunction(eCSSKeyword_rotate3d); - arr->Item(1).SetFloatValue(x, eCSSUnit_Number); - arr->Item(2).SetFloatValue(y, eCSSUnit_Number); - arr->Item(3).SetFloatValue(z, eCSSUnit_Number); - auto rv = SetCSSAngle(angle, arr->Item(4)); - if (rv.isErr()) { - arr->Item(4).SetFloatValue(0.0, eCSSUnit_Degree); - } - } - list->mHead->mValue.SetArrayValue(arr, eCSSUnit_Function); - } - result = - Servo_AnimationValue_Transform(eCSSProperty_rotate, list).Consume(); - break; + auto rotate = RotateFromLayers(aAnimatable.get_Rotate()); + return Servo_AnimationValue_Rotate(&rotate).Consume(); } case layers::Animatable::TScale: { - const layers::Scale& scale = aAnimatable.get_Scale(); - RefPtr<nsCSSValue::Array> arr = AppendFunction(eCSSKeyword_scale3d); - arr->Item(1).SetFloatValue(scale.x(), eCSSUnit_Number); - arr->Item(2).SetFloatValue(scale.y(), eCSSUnit_Number); - arr->Item(3).SetFloatValue(scale.z(), eCSSUnit_Number); - - RefPtr<nsCSSValueSharedList> list = new nsCSSValueSharedList; - list->mHead = new nsCSSValueList; - list->mHead->mValue.SetArrayValue(arr, eCSSUnit_Function); - result = - Servo_AnimationValue_Transform(eCSSProperty_scale, list).Consume(); - break; + const layers::Scale& s = aAnimatable.get_Scale(); + auto scale = StyleScale::Scale3D(s.x(), s.y(), s.z()); + return Servo_AnimationValue_Scale(&scale).Consume(); } case layers::Animatable::TTranslation: { - const layers::Translation& translate = aAnimatable.get_Translation(); - RefPtr<nsCSSValue::Array> arr = AppendFunction(eCSSKeyword_translate3d); - arr->Item(1).SetFloatValue(translate.x(), eCSSUnit_Pixel); - arr->Item(2).SetFloatValue(translate.y(), eCSSUnit_Pixel); - arr->Item(3).SetFloatValue(translate.z(), eCSSUnit_Pixel); - - RefPtr<nsCSSValueSharedList> list = new nsCSSValueSharedList; - list->mHead = new nsCSSValueList; - list->mHead->mValue.SetArrayValue(arr, eCSSUnit_Function); - result = Servo_AnimationValue_Transform(eCSSProperty_translate, list) - .Consume(); - break; + const layers::Translation& t = aAnimatable.get_Translation(); + auto translate = StyleTranslate::Translate3D( + LengthPercentage::FromPixels(t.x()), + LengthPercentage::FromPixels(t.y()), Length{t.z()}); + return Servo_AnimationValue_Translate(&translate).Consume(); } default: MOZ_ASSERT_UNREACHABLE("Unsupported type"); } - return result.forget(); + return nullptr; }
--- a/layout/style/StyleAnimationValue.h +++ b/layout/style/StyleAnimationValue.h @@ -72,18 +72,21 @@ struct AnimationValue { bool IsNull() const { return !mServo; } float GetOpacity() const; // Returns nscolor value in this AnimationValue. // Currently only background-color is supported. nscolor GetColor(nscolor aForegroundColor) const; - // Return the transform list as a RefPtr. - already_AddRefed<const nsCSSValueSharedList> GetTransformList() const; + // Return a transform list for the transform property. + const mozilla::StyleTransform& GetTransformProperty() const; + const mozilla::StyleScale& GetScaleProperty() const; + const mozilla::StyleTranslate& GetTranslateProperty() const; + const mozilla::StyleRotate& GetRotateProperty() const; // Return the scale for mServo, which is calculated with reference to aFrame. mozilla::gfx::Size GetScaleValue(const nsIFrame* aFrame) const; // Uncompute this AnimationValue and then serialize it. void SerializeSpecifiedValue(nsCSSPropertyID aProperty, nsAString& aString) const;
--- a/layout/style/nsComputedDOMStyle.cpp +++ b/layout/style/nsComputedDOMStyle.cpp @@ -1094,17 +1094,17 @@ already_AddRefed<CSSValue> nsComputedDOM auto position = MaybeResolvePositionForTransform( origin.horizontal, origin.vertical, mInnerFrame); SetValueToPosition(position, valueList); return valueList.forget(); } already_AddRefed<CSSValue> nsComputedDOMStyle::DoGetTransform() { const nsStyleDisplay* display = StyleDisplay(); - return GetTransformValue(display->mSpecifiedTransform); + return GetTransformValue(display->mTransform); } /* static */ already_AddRefed<nsROCSSPrimitiveValue> nsComputedDOMStyle::MatrixToCSSValue( const mozilla::gfx::Matrix4x4& matrix) { bool is3D = !matrix.Is2D(); nsAutoString resultString(NS_LITERAL_STRING("matrix")); @@ -2497,24 +2497,22 @@ bool nsComputedDOMStyle::GetFrameBorderR return true; } /* If the property is "none", hand back "none" wrapped in a value. * Otherwise, compute the aggregate transform matrix and hands it back in a * "matrix" wrapper. */ already_AddRefed<CSSValue> nsComputedDOMStyle::GetTransformValue( - nsCSSValueSharedList* aSpecifiedTransform) { + const StyleTransform& aTransform) { /* If there are no transforms, then we should construct a single-element * entry and hand it back. */ - if (!aSpecifiedTransform) { + if (aTransform.IsNone()) { RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue; - - /* Set it to "none." */ val->SetIdent(eCSSKeyword_none); return val.forget(); } /* Otherwise, we need to compute the current value of the transform matrix, * store it in a string, and hand it back to the caller. */ @@ -2528,18 +2526,17 @@ already_AddRefed<CSSValue> nsComputedDOM * problem, because only two of these values can be explicitly referenced * using the named transforms. Until a real solution is found, we'll just * use this approach. */ nsStyleTransformMatrix::TransformReferenceBox refBox(mInnerFrame, nsSize(0, 0)); gfx::Matrix4x4 matrix = nsStyleTransformMatrix::ReadTransforms( - aSpecifiedTransform->mHead, refBox, - float(mozilla::AppUnitsPerCSSPixel())); + aTransform, refBox, float(mozilla::AppUnitsPerCSSPixel())); return MatrixToCSSValue(matrix); } void nsComputedDOMStyle::SetCssTextToCoord(nsAString& aCssText, const nsStyleCoord& aCoord, bool aClampNegativeCalc) { RefPtr<nsROCSSPrimitiveValue> value = new nsROCSSPrimitiveValue;
--- a/layout/style/nsComputedDOMStyle.h +++ b/layout/style/nsComputedDOMStyle.h @@ -183,18 +183,17 @@ class nsComputedDOMStyle final : public already_AddRefed<CSSValue> GetBorderStyleFor(mozilla::Side aSide); already_AddRefed<CSSValue> GetBorderWidthFor(mozilla::Side aSide); already_AddRefed<CSSValue> GetBorderColorFor(mozilla::Side aSide); already_AddRefed<CSSValue> GetMarginWidthFor(mozilla::Side aSide); - already_AddRefed<CSSValue> GetTransformValue( - nsCSSValueSharedList* aSpecifiedTransform); + already_AddRefed<CSSValue> GetTransformValue(const mozilla::StyleTransform&); // Appends all aLineNames (may be empty) space-separated to aResult. void AppendGridLineNames(nsString& aResult, const nsTArray<nsString>& aLineNames); // Appends aLineNames as a CSSValue* to aValueList. If aLineNames is empty // a value ("[]") is only appended if aSuppressEmptyList is false. void AppendGridLineNames(nsDOMCSSValueList* aValueList, const nsTArray<nsString>& aLineNames,
--- a/layout/style/nsStyleStruct.cpp +++ b/layout/style/nsStyleStruct.cpp @@ -2992,20 +2992,20 @@ nsStyleDisplay::nsStyleDisplay(const nsS mScrollSnapPointsX(aSource.mScrollSnapPointsX), mScrollSnapPointsY(aSource.mScrollSnapPointsY), mScrollSnapDestination(aSource.mScrollSnapDestination), mScrollSnapCoordinate(aSource.mScrollSnapCoordinate), mLineClamp(aSource.mLineClamp), mBackfaceVisibility(aSource.mBackfaceVisibility), mTransformStyle(aSource.mTransformStyle), mTransformBox(aSource.mTransformBox), - mSpecifiedTransform(aSource.mSpecifiedTransform), - mSpecifiedRotate(aSource.mSpecifiedRotate), - mSpecifiedTranslate(aSource.mSpecifiedTranslate), - mSpecifiedScale(aSource.mSpecifiedScale), + mTransform(aSource.mTransform), + mRotate(aSource.mRotate), + mTranslate(aSource.mTranslate), + mScale(aSource.mScale), // We intentionally leave mIndividualTransform as null, is the caller's // responsibility to call GenerateCombinedIndividualTransform when // appropriate. mMotion(aSource.mMotion ? MakeUnique<StyleMotion>(*aSource.mMotion) : nullptr), mTransformOrigin(aSource.mTransformOrigin), mChildPerspective(aSource.mChildPerspective), mPerspectiveOrigin(aSource.mPerspectiveOrigin), @@ -3025,77 +3025,38 @@ nsStyleDisplay::nsStyleDisplay(const nsS mAnimationPlayStateCount(aSource.mAnimationPlayStateCount), mAnimationIterationCountCount(aSource.mAnimationIterationCountCount), mShapeImageThreshold(aSource.mShapeImageThreshold), mShapeMargin(aSource.mShapeMargin), mShapeOutside(aSource.mShapeOutside) { MOZ_COUNT_CTOR(nsStyleDisplay); } -static void ReleaseSharedListOnMainThread(const char* aName, - RefPtr<nsCSSValueSharedList>& aList) { - // We don't allow releasing nsCSSValues with refcounted data in the Servo - // traversal, since the refcounts aren't threadsafe. Since Servo may trigger - // the deallocation of style structs during styling, we need to handle it - // here. - if (aList && ServoStyleSet::IsInServoTraversal()) { - // The default behavior of NS_ReleaseOnMainThreadSystemGroup is to only - // proxy the release if we're not already on the main thread. This is a nice - // optimization for the cases we happen to be doing a sequential traversal - // (i.e. a single-core machine), but it trips our assertions which check - // whether we're in a Servo traversal, parallel or not. So we - // unconditionally proxy in debug builds. - bool alwaysProxy = -#ifdef DEBUG - true; -#else - false; -#endif - NS_ReleaseOnMainThreadSystemGroup(aName, aList.forget(), alwaysProxy); - } -} - nsStyleDisplay::~nsStyleDisplay() { - ReleaseSharedListOnMainThread("nsStyleDisplay::mSpecifiedTransform", - mSpecifiedTransform); - ReleaseSharedListOnMainThread("nsStyleDisplay::mSpecifiedRotate", - mSpecifiedRotate); - ReleaseSharedListOnMainThread("nsStyleDisplay::mSpecifiedTranslate", - mSpecifiedTranslate); - ReleaseSharedListOnMainThread("nsStyleDisplay::mSpecifiedScale", - mSpecifiedScale); - ReleaseSharedListOnMainThread("nsStyleDisplay::mIndividualTransform", - mIndividualTransform); MOZ_COUNT_DTOR(nsStyleDisplay); } void nsStyleDisplay::TriggerImageLoads(Document& aDocument, const nsStyleDisplay* aOldStyle) { MOZ_ASSERT(NS_IsMainThread()); mShapeOutside.TriggerImageLoads( aDocument, aOldStyle ? &aOldStyle->mShapeOutside : nullptr); } -static inline bool TransformListChanged( - const RefPtr<nsCSSValueSharedList>& aList, - const RefPtr<nsCSSValueSharedList>& aNewList) { - return !aList != !aNewList || (aList && *aList != *aNewList); -} - +template <typename TransformLike> static inline nsChangeHint CompareTransformValues( - const RefPtr<nsCSSValueSharedList>& aList, - const RefPtr<nsCSSValueSharedList>& aNewList) { + const TransformLike& aOldTransform, const TransformLike& aNewTransform) { nsChangeHint result = nsChangeHint(0); // Note: If we add a new change hint for transform changes here, we have to // modify KeyframeEffect::CalculateCumulativeChangeHint too! - if (!aList != !aNewList || (aList && *aList != *aNewList)) { + if (aOldTransform != aNewTransform) { result |= nsChangeHint_UpdateTransformLayer; - if (aList && aNewList) { + if (!aOldTransform.IsNone() && !aNewTransform.IsNone()) { result |= nsChangeHint_UpdatePostTransformOverflow; } else { result |= nsChangeHint_UpdateOverflow; } } return result; } @@ -3234,24 +3195,20 @@ nsChangeHint nsStyleDisplay::CalcDiffere * overflow rect. * * If the property isn't present in either style struct, we still do the * comparisons but turn all the resulting change hints into * nsChangeHint_NeutralChange. */ nsChangeHint transformHint = nsChangeHint(0); - transformHint |= CompareTransformValues(mSpecifiedTransform, - aNewData.mSpecifiedTransform); - transformHint |= - CompareTransformValues(mSpecifiedRotate, aNewData.mSpecifiedRotate); - transformHint |= CompareTransformValues(mSpecifiedTranslate, - aNewData.mSpecifiedTranslate); - transformHint |= - CompareTransformValues(mSpecifiedScale, aNewData.mSpecifiedScale); + transformHint |= CompareTransformValues(mTransform, aNewData.mTransform); + transformHint |= CompareTransformValues(mRotate, aNewData.mRotate); + transformHint |= CompareTransformValues(mTranslate, aNewData.mTranslate); + transformHint |= CompareTransformValues(mScale, aNewData.mScale); transformHint |= CompareMotionValues(mMotion.get(), aNewData.mMotion.get()); if (mTransformOrigin != aNewData.mTransformOrigin) { transformHint |= nsChangeHint_UpdateTransformLayer | nsChangeHint_UpdatePostTransformOverflow; } if (mPerspectiveOrigin != aNewData.mPerspectiveOrigin || @@ -3354,78 +3311,16 @@ nsChangeHint nsStyleDisplay::CalcDiffere mScrollSnapCoordinate != aNewData.mScrollSnapCoordinate || mWillChange != aNewData.mWillChange)) { hint |= nsChangeHint_NeutralChange; } return hint; } -bool nsStyleDisplay::TransformChanged(const nsStyleDisplay& aNewData) const { - return TransformListChanged(mSpecifiedTransform, - aNewData.mSpecifiedTransform); -} - -/* static */ -already_AddRefed<nsCSSValueSharedList> -nsStyleDisplay::GenerateCombinedIndividualTransform( - nsCSSValueSharedList* aTranslate, nsCSSValueSharedList* aRotate, - nsCSSValueSharedList* aScale) { - // Follow the order defined in the spec to append transform functions. - // https://drafts.csswg.org/css-transforms-2/#ctm - AutoTArray<nsCSSValueSharedList*, 3> shareLists; - if (aTranslate) { - shareLists.AppendElement(aTranslate); - } - - if (aRotate) { - shareLists.AppendElement(aRotate); - } - - if (aScale) { - shareLists.AppendElement(aScale); - } - - if (shareLists.IsEmpty()) { - return nullptr; - } - - if (shareLists.Length() == 1) { - return RefPtr<nsCSSValueSharedList>(shareLists[0]).forget(); - } - - // In common, we may have 3 transform functions: - // 1. one rotate function in aRotate, - // 2. one translate function in aTranslate, - // 3. one scale function in aScale. - AutoTArray<nsCSSValueList*, 3> valueLists; - for (auto list : shareLists) { - if (list) { - valueLists.AppendElement(list->mHead->Clone()); - } - } - - // Check we have at least one list or else valueLists.Length() - 1 below will - // underflow. - MOZ_ASSERT(!valueLists.IsEmpty()); - - for (uint32_t i = 0; i < valueLists.Length() - 1; i++) { - valueLists[i]->mNext = valueLists[i + 1]; - } - - RefPtr<nsCSSValueSharedList> list = new nsCSSValueSharedList(valueLists[0]); - return list.forget(); -} - -void nsStyleDisplay::GenerateCombinedIndividualTransform() { - MOZ_ASSERT(!mIndividualTransform); - mIndividualTransform = GenerateCombinedIndividualTransform( - mSpecifiedTranslate, mSpecifiedRotate, mSpecifiedScale); -} - // -------------------- // nsStyleVisibility // nsStyleVisibility::nsStyleVisibility(const Document& aDocument) : mDirection(aDocument.GetBidiOptions() == IBMBIDI_TEXTDIRECTION_RTL ? NS_STYLE_DIRECTION_RTL : NS_STYLE_DIRECTION_LTR), @@ -3980,41 +3875,37 @@ nsChangeHint nsStyleUI::CalcDifference(c nsStyleUIReset::nsStyleUIReset(const Document& aDocument) : mUserSelect(StyleUserSelect::Auto), mScrollbarWidth(StyleScrollbarWidth::Auto), mForceBrokenImageIcon(0), mIMEMode(NS_STYLE_IME_MODE_AUTO), mWindowDragging(StyleWindowDragging::Default), mWindowShadow(NS_STYLE_WINDOW_SHADOW_DEFAULT), mWindowOpacity(1.0), - mSpecifiedWindowTransform(nullptr), mWindowTransformOrigin{LengthPercentage::FromPercentage(0.5), LengthPercentage::FromPercentage(0.5), {0.}} { MOZ_COUNT_CTOR(nsStyleUIReset); } nsStyleUIReset::nsStyleUIReset(const nsStyleUIReset& aSource) : mUserSelect(aSource.mUserSelect), mScrollbarWidth(aSource.mScrollbarWidth), mForceBrokenImageIcon(aSource.mForceBrokenImageIcon), mIMEMode(aSource.mIMEMode), mWindowDragging(aSource.mWindowDragging), mWindowShadow(aSource.mWindowShadow), mWindowOpacity(aSource.mWindowOpacity), - mSpecifiedWindowTransform(aSource.mSpecifiedWindowTransform), + mMozWindowTransform(aSource.mMozWindowTransform), mWindowTransformOrigin(aSource.mWindowTransformOrigin) { MOZ_COUNT_CTOR(nsStyleUIReset); } nsStyleUIReset::~nsStyleUIReset() { MOZ_COUNT_DTOR(nsStyleUIReset); - - ReleaseSharedListOnMainThread("nsStyleUIReset::mSpecifiedWindowTransform", - mSpecifiedWindowTransform); } nsChangeHint nsStyleUIReset::CalcDifference( const nsStyleUIReset& aNewData) const { nsChangeHint hint = nsChangeHint(0); if (mForceBrokenImageIcon != aNewData.mForceBrokenImageIcon) { hint |= nsChangeHint_ReconstructFrame; @@ -4035,20 +3926,17 @@ nsChangeHint nsStyleUIReset::CalcDiffere hint |= NS_STYLE_HINT_VISUAL; } if (mWindowDragging != aNewData.mWindowDragging) { hint |= nsChangeHint_SchedulePaint; } if (mWindowOpacity != aNewData.mWindowOpacity || - !mSpecifiedWindowTransform != !aNewData.mSpecifiedWindowTransform || - (mSpecifiedWindowTransform && - *mSpecifiedWindowTransform != *aNewData.mSpecifiedWindowTransform) || - mWindowTransformOrigin != aNewData.mWindowTransformOrigin) { + mMozWindowTransform != aNewData.mMozWindowTransform) { hint |= nsChangeHint_UpdateWidgetProperties; } if (!hint && mIMEMode != aNewData.mIMEMode) { hint |= nsChangeHint_NeutralChange; } return hint;
--- a/layout/style/nsStyleStruct.h +++ b/layout/style/nsStyleStruct.h @@ -1694,18 +1694,16 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsSt nsStyleDisplay(const nsStyleDisplay& aOther); ~nsStyleDisplay(); void TriggerImageLoads(mozilla::dom::Document&, const nsStyleDisplay*); const static bool kHasTriggerImageLoads = true; nsChangeHint CalcDifference(const nsStyleDisplay& aNewData) const; - bool TransformChanged(const nsStyleDisplay& aNewData) const; - // We guarantee that if mBinding is non-null, so are mBinding->GetURI() and // mBinding->mOriginPrincipal. RefPtr<mozilla::css::URLValue> mBinding; mozilla::StyleDisplay mDisplay; mozilla::StyleDisplay mOriginalDisplay; // saved mDisplay for // position:absolute/fixed // and float:left/right; // otherwise equal to @@ -1747,23 +1745,22 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsSt // mSpecifiedTransform is the list of transform functions as // specified, or null to indicate there is no transform. (inherit or // initial are replaced by an actual list of transform functions, or // null, as appropriate.) uint8_t mBackfaceVisibility; uint8_t mTransformStyle; StyleGeometryBox mTransformBox; - RefPtr<nsCSSValueSharedList> mSpecifiedTransform; - RefPtr<nsCSSValueSharedList> mSpecifiedRotate; - RefPtr<nsCSSValueSharedList> mSpecifiedTranslate; - RefPtr<nsCSSValueSharedList> mSpecifiedScale; - // Used to store the final combination of mSpecifiedRotate, - // mSpecifiedTranslate, and mSpecifiedScale. - RefPtr<nsCSSValueSharedList> mIndividualTransform; + + mozilla::StyleTransform mTransform; + mozilla::StyleRotate mRotate; + mozilla::StyleTranslate mTranslate; + mozilla::StyleScale mScale; + mozilla::UniquePtr<mozilla::StyleMotion> mMotion; mozilla::StyleTransformOrigin mTransformOrigin; mozilla::StylePerspective mChildPerspective; mozilla::Position mPerspectiveOrigin; mozilla::StyleVerticalAlign mVerticalAlign; @@ -1994,28 +1991,29 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsSt // responsible for checking if the box in question is // non-atomic and inline-level, and creating an // exemption as necessary. return (mContain & mozilla::StyleContain_SIZE) && !IsInternalRubyDisplayType() && (mozilla::StyleDisplay::Table != mDisplay) && !IsInnerTableStyle(); } - /* Returns whether the element has the -moz-transform property - * or a related property. */ + /* Returns whether the element has the transform property or a related + * property. */ bool HasTransformStyle() const { - return mSpecifiedTransform || mSpecifiedRotate || mSpecifiedTranslate || - mSpecifiedScale || + return HasTransformProperty() || HasIndividualTransform() || mTransformStyle == NS_STYLE_TRANSFORM_STYLE_PRESERVE_3D || (mWillChange.bits & mozilla::StyleWillChangeBits_TRANSFORM) || (mMotion && mMotion->HasPath()); } + bool HasTransformProperty() const { return !mTransform._0.IsEmpty(); } + bool HasIndividualTransform() const { - return mSpecifiedRotate || mSpecifiedTranslate || mSpecifiedScale; + return !mRotate.IsNone() || !mTranslate.IsNone() || !mScale.IsNone(); } bool HasPerspectiveStyle() const { return !mChildPerspective.IsNone(); } bool BackfaceIsHidden() const { return mBackfaceVisibility == NS_STYLE_BACKFACE_VISIBILITY_HIDDEN; } @@ -2112,33 +2110,16 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsSt * frame (i.e., when calculating style changes). */ inline bool IsFixedPosContainingBlockForNonSVGTextFrames( const mozilla::ComputedStyle&) const; inline bool IsFixedPosContainingBlockForContainLayoutAndPaintSupportingFrames() const; inline bool IsFixedPosContainingBlockForTransformSupportingFrames() const; - /** - * Returns the final combined individual transform. - **/ - already_AddRefed<nsCSSValueSharedList> GetCombinedTransform() const { - return mIndividualTransform ? do_AddRef(mIndividualTransform) : nullptr; - } - - /** - * Returns the combined transform list based on translate, rotate, scale - * individual transforms. The combination order is defined in - * https://drafts.csswg.org/css-transforms-2/#ctm - */ - static already_AddRefed<nsCSSValueSharedList> - GenerateCombinedIndividualTransform(nsCSSValueSharedList* aTranslate, - nsCSSValueSharedList* aRotate, - nsCSSValueSharedList* aScale); - void GenerateCombinedIndividualTransform(); }; struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleTable { explicit nsStyleTable(const mozilla::dom::Document&); nsStyleTable(const nsStyleTable& aOther); ~nsStyleTable(); void TriggerImageLoads(mozilla::dom::Document&, const nsStyleTable*) {} @@ -2372,17 +2353,17 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsSt mozilla::StyleUserSelect mUserSelect; // [reset](selection-style) mozilla::StyleScrollbarWidth mScrollbarWidth; uint8_t mForceBrokenImageIcon; // (0 if not forcing, otherwise forcing) uint8_t mIMEMode; mozilla::StyleWindowDragging mWindowDragging; uint8_t mWindowShadow; float mWindowOpacity; - RefPtr<nsCSSValueSharedList> mSpecifiedWindowTransform; + mozilla::StyleTransform mMozWindowTransform; mozilla::StyleTransformOrigin mWindowTransformOrigin; }; struct nsCursorImage { bool mHaveHotspot; float mHotspotX, mHotspotY; RefPtr<nsStyleImageRequest> mImage;
--- a/layout/style/nsStyleTransformMatrix.cpp +++ b/layout/style/nsStyleTransformMatrix.cpp @@ -122,108 +122,70 @@ void TransformReferenceBox::Init(const n mX = 0; mY = 0; mWidth = aDimensions.width; mHeight = aDimensions.height; mIsCached = true; } float ProcessTranslatePart( - const nsCSSValue& aValue, TransformReferenceBox* aRefBox, + const LengthPercentage& aValue, TransformReferenceBox* aRefBox, TransformReferenceBox::DimensionGetter aDimensionGetter) { - nscoord offset = 0; - float percent = 0.0f; - - if (aValue.GetUnit() == eCSSUnit_Percent) { - percent = aValue.GetPercentValue(); - } else if (aValue.GetUnit() == eCSSUnit_Pixel || - aValue.GetUnit() == eCSSUnit_Number) { - // Raw numbers are treated as being pixels. - return aValue.GetFloatValue(); - } else if (aValue.IsCalcUnit()) { - // We can retrieve the Calc value directly because it has been computed - // from the Servo side and set by nsCSSValue::SetCalcValue(). - nsStyleCoord::CalcValue calc = aValue.GetCalcValue(); - percent = calc.mPercent; - offset = calc.mLength; - } else { - // Note: The unit of nsCSSValue passed from Servo side would be number, - // pixel, percent, or eCSSUnit_Calc, so it is impossible to go into - // this branch. - MOZ_CRASH("unexpected unit in ProcessTranslatePart"); - } - - float translation = NSAppUnitsToFloatPixels(offset, AppUnitsPerCSSPixel()); - // We want to avoid calling aDimensionGetter if there's no percentage to be - // resolved (for performance reasons - see TransformReferenceBox). - if (percent != 0.0f && aRefBox && !aRefBox->IsEmpty()) { - translation += - percent * NSAppUnitsToFloatPixels((aRefBox->*aDimensionGetter)(), - AppUnitsPerCSSPixel()); - } - return translation; + return aValue.ResolveToCSSPixelsWith([&] { + return aRefBox && !aRefBox->IsEmpty() + ? CSSPixel::FromAppUnits((aRefBox->*aDimensionGetter)()) + : CSSCoord(0); + }); } /** * Helper functions to process all the transformation function types. * * These take a matrix parameter to accumulate the current matrix. */ /* Helper function to process a matrix entry. */ -static void ProcessMatrix(Matrix4x4& aMatrix, const nsCSSValue::Array* aData, - TransformReferenceBox& aRefBox) { - MOZ_ASSERT(aData->Count() == 7, "Invalid array!"); - +static void ProcessMatrix(Matrix4x4& aMatrix, + const StyleTransformOperation& aOp) { + const auto& matrix = aOp.AsMatrix(); gfxMatrix result; - /* Take the first four elements out of the array as floats and store - * them. - */ - result._11 = aData->Item(1).GetFloatValue(); - result._12 = aData->Item(2).GetFloatValue(); - result._21 = aData->Item(3).GetFloatValue(); - result._22 = aData->Item(4).GetFloatValue(); - - /* The last two elements have their length parts stored in aDelta - * and their percent parts stored in aX[0] and aY[1]. - */ - result._31 = ProcessTranslatePart(aData->Item(5), &aRefBox, - &TransformReferenceBox::Width); - result._32 = ProcessTranslatePart(aData->Item(6), &aRefBox, - &TransformReferenceBox::Height); + result._11 = matrix.a; + result._12 = matrix.b; + result._21 = matrix.c; + result._22 = matrix.d; + result._31 = matrix.e; + result._32 = matrix.f; aMatrix = result * aMatrix; } -static void ProcessMatrix3D(Matrix4x4& aMatrix, const nsCSSValue::Array* aData, - TransformReferenceBox& aRefBox) { - MOZ_ASSERT(aData->Count() == 17, "Invalid array!"); - +static void ProcessMatrix3D(Matrix4x4& aMatrix, + const StyleTransformOperation& aOp) { Matrix4x4 temp; - temp._11 = aData->Item(1).GetFloatValue(); - temp._12 = aData->Item(2).GetFloatValue(); - temp._13 = aData->Item(3).GetFloatValue(); - temp._14 = aData->Item(4).GetFloatValue(); - temp._21 = aData->Item(5).GetFloatValue(); - temp._22 = aData->Item(6).GetFloatValue(); - temp._23 = aData->Item(7).GetFloatValue(); - temp._24 = aData->Item(8).GetFloatValue(); - temp._31 = aData->Item(9).GetFloatValue(); - temp._32 = aData->Item(10).GetFloatValue(); - temp._33 = aData->Item(11).GetFloatValue(); - temp._34 = aData->Item(12).GetFloatValue(); - temp._44 = aData->Item(16).GetFloatValue(); + const auto& matrix = aOp.AsMatrix3D(); - temp._41 = ProcessTranslatePart(aData->Item(13), &aRefBox, - &TransformReferenceBox::Width); - temp._42 = ProcessTranslatePart(aData->Item(14), &aRefBox, - &TransformReferenceBox::Height); - temp._43 = ProcessTranslatePart(aData->Item(15), nullptr); + temp._11 = matrix.m11; + temp._12 = matrix.m12; + temp._13 = matrix.m13; + temp._14 = matrix.m14; + temp._21 = matrix.m21; + temp._22 = matrix.m22; + temp._23 = matrix.m23; + temp._24 = matrix.m24; + temp._31 = matrix.m31; + temp._32 = matrix.m32; + temp._33 = matrix.m33; + temp._34 = matrix.m34; + + temp._41 = matrix.m41; + temp._42 = matrix.m42; + temp._43 = matrix.m43; + temp._44 = matrix.m44; aMatrix = temp * aMatrix; } // For accumulation for transform functions, |aOne| corresponds to |aB| and // |aTwo| corresponds to |aA| for StyleAnimationValue::Accumulate(). class Accumulate { public: @@ -405,346 +367,212 @@ template <typename Operator> static Matrix4x4 OperateTransformMatrixByServo(const Matrix4x4& aMatrix1, const Matrix4x4& aMatrix2, double aProgress) { return Operator::operateByServo(aMatrix1, aMatrix2, aProgress); } template <typename Operator> static void ProcessMatrixOperator(Matrix4x4& aMatrix, - const nsCSSValue::Array* aData, + const StyleTransform& aFrom, + const StyleTransform& aTo, float aProgress, TransformReferenceBox& aRefBox) { - MOZ_ASSERT(aData->Count() == 4, "Invalid array!"); - - auto readTransform = [&](const nsCSSValue& aValue) -> Matrix4x4 { - const nsCSSValueList* list = nullptr; - switch (aValue.GetUnit()) { - case eCSSUnit_List: - // For Gecko style backend. - list = aValue.GetListValue(); - break; - case eCSSUnit_SharedList: - // For Servo style backend. The transform lists of interpolatematrix - // are not created on the main thread (i.e. during parallel traversal), - // and nsCSSValueList_heap is not thread safe. Therefore, we use - // nsCSSValueSharedList as a workaround. - list = aValue.GetSharedListValue()->mHead; - break; - default: - list = nullptr; - } + float appUnitPerCSSPixel = AppUnitsPerCSSPixel(); + Matrix4x4 matrix1 = ReadTransforms(aFrom, aRefBox, appUnitPerCSSPixel); + Matrix4x4 matrix2 = ReadTransforms(aTo, aRefBox, appUnitPerCSSPixel); - Matrix4x4 matrix; - if (!list) { - return matrix; - } - - float appUnitPerCSSPixel = AppUnitsPerCSSPixel(); - matrix = nsStyleTransformMatrix::ReadTransforms(list, aRefBox, - appUnitPerCSSPixel); - return matrix; - }; - - Matrix4x4 matrix1 = readTransform(aData->Item(1)); - Matrix4x4 matrix2 = readTransform(aData->Item(2)); - double progress = aData->Item(3).GetPercentValue(); - - // We cannot use GeckoComputedStyle to check if we use Servo backend because - // it could be null in Gecko. Instead, use the unit of the nsCSSValue because - // we use eCSSUnit_SharedList for Servo backend. - if (aData->Item(1).GetUnit() == eCSSUnit_SharedList) { + // TODO(emilio): I think the legacy decomposition code couldn't be reached + // before, probably just remove it? + const bool kUseLegacyDecomposition = false; + if (kUseLegacyDecomposition) { aMatrix = - OperateTransformMatrixByServo<Operator>(matrix1, matrix2, progress) * - aMatrix; + OperateTransformMatrix<Operator>(matrix1, matrix2, aProgress) * aMatrix; return; } aMatrix = - OperateTransformMatrix<Operator>(matrix1, matrix2, progress) * aMatrix; + OperateTransformMatrixByServo<Operator>(matrix1, matrix2, aProgress) * + aMatrix; } /* Helper function to process two matrices that we need to interpolate between */ void ProcessInterpolateMatrix(Matrix4x4& aMatrix, - const nsCSSValue::Array* aData, + const StyleTransformOperation& aOp, TransformReferenceBox& aRefBox) { - ProcessMatrixOperator<Interpolate>(aMatrix, aData, aRefBox); + const auto& args = aOp.AsInterpolateMatrix(); + ProcessMatrixOperator<Interpolate>(aMatrix, args.from_list, args.to_list, + args.progress._0, aRefBox); } -void ProcessAccumulateMatrix(Matrix4x4& aMatrix, const nsCSSValue::Array* aData, +void ProcessAccumulateMatrix(Matrix4x4& aMatrix, + const StyleTransformOperation& aOp, TransformReferenceBox& aRefBox) { - ProcessMatrixOperator<Accumulate>(aMatrix, aData, aRefBox); + const auto& args = aOp.AsAccumulateMatrix(); + ProcessMatrixOperator<Accumulate>(aMatrix, args.from_list, args.to_list, + args.count, aRefBox); } /* Helper function to process a translatex function. */ static void ProcessTranslateX(Matrix4x4& aMatrix, - const nsCSSValue::Array* aData, + const LengthPercentage& aLength, TransformReferenceBox& aRefBox) { - MOZ_ASSERT(aData->Count() == 2, "Invalid array!"); - Point3D temp; - - temp.x = ProcessTranslatePart(aData->Item(1), &aRefBox, - &TransformReferenceBox::Width); + temp.x = + ProcessTranslatePart(aLength, &aRefBox, &TransformReferenceBox::Width); aMatrix.PreTranslate(temp); } /* Helper function to process a translatey function. */ static void ProcessTranslateY(Matrix4x4& aMatrix, - const nsCSSValue::Array* aData, + const LengthPercentage& aLength, TransformReferenceBox& aRefBox) { - MOZ_ASSERT(aData->Count() == 2, "Invalid array!"); - Point3D temp; - - temp.y = ProcessTranslatePart(aData->Item(1), &aRefBox, - &TransformReferenceBox::Height); + temp.y = + ProcessTranslatePart(aLength, &aRefBox, &TransformReferenceBox::Height); aMatrix.PreTranslate(temp); } -static void ProcessTranslateZ(Matrix4x4& aMatrix, - const nsCSSValue::Array* aData) { - MOZ_ASSERT(aData->Count() == 2, "Invalid array!"); - +static void ProcessTranslateZ(Matrix4x4& aMatrix, const Length& aLength) { Point3D temp; - - temp.z = ProcessTranslatePart(aData->Item(1), nullptr); + temp.z = aLength.ToCSSPixels(); aMatrix.PreTranslate(temp); } /* Helper function to process a translate function. */ -static void ProcessTranslate(Matrix4x4& aMatrix, const nsCSSValue::Array* aData, +static void ProcessTranslate(Matrix4x4& aMatrix, const LengthPercentage& aX, + const LengthPercentage& aY, TransformReferenceBox& aRefBox) { - MOZ_ASSERT(aData->Count() == 2 || aData->Count() == 3, "Invalid array!"); - Point3D temp; - - temp.x = ProcessTranslatePart(aData->Item(1), &aRefBox, - &TransformReferenceBox::Width); - - /* If we read in a Y component, set it appropriately */ - if (aData->Count() == 3) { - temp.y = ProcessTranslatePart(aData->Item(2), &aRefBox, - &TransformReferenceBox::Height); - } + temp.x = ProcessTranslatePart(aX, &aRefBox, &TransformReferenceBox::Width); + temp.y = ProcessTranslatePart(aY, &aRefBox, &TransformReferenceBox::Height); aMatrix.PreTranslate(temp); } -static void ProcessTranslate3D(Matrix4x4& aMatrix, - const nsCSSValue::Array* aData, +static void ProcessTranslate3D(Matrix4x4& aMatrix, const LengthPercentage& aX, + const LengthPercentage& aY, const Length& aZ, TransformReferenceBox& aRefBox) { - MOZ_ASSERT(aData->Count() == 4, "Invalid array!"); - Point3D temp; - temp.x = ProcessTranslatePart(aData->Item(1), &aRefBox, - &TransformReferenceBox::Width); - - temp.y = ProcessTranslatePart(aData->Item(2), &aRefBox, - &TransformReferenceBox::Height); - - temp.z = ProcessTranslatePart(aData->Item(3), nullptr); + temp.x = ProcessTranslatePart(aX, &aRefBox, &TransformReferenceBox::Width); + temp.y = ProcessTranslatePart(aY, &aRefBox, &TransformReferenceBox::Height); + temp.z = aZ.ToCSSPixels(); aMatrix.PreTranslate(temp); } /* Helper function to set up a scale matrix. */ static void ProcessScaleHelper(Matrix4x4& aMatrix, float aXScale, float aYScale, float aZScale) { aMatrix.PreScale(aXScale, aYScale, aZScale); } -/* Process a scalex function. */ -static void ProcessScaleX(Matrix4x4& aMatrix, const nsCSSValue::Array* aData) { - MOZ_ASSERT(aData->Count() == 2, "Bad array!"); - ProcessScaleHelper(aMatrix, aData->Item(1).GetFloatValue(), 1.0f, 1.0f); -} - -/* Process a scaley function. */ -static void ProcessScaleY(Matrix4x4& aMatrix, const nsCSSValue::Array* aData) { - MOZ_ASSERT(aData->Count() == 2, "Bad array!"); - ProcessScaleHelper(aMatrix, 1.0f, aData->Item(1).GetFloatValue(), 1.0f); -} - -static void ProcessScaleZ(Matrix4x4& aMatrix, const nsCSSValue::Array* aData) { - MOZ_ASSERT(aData->Count() == 2, "Bad array!"); - ProcessScaleHelper(aMatrix, 1.0f, 1.0f, aData->Item(1).GetFloatValue()); -} - -static void ProcessScale3D(Matrix4x4& aMatrix, const nsCSSValue::Array* aData) { - MOZ_ASSERT(aData->Count() == 4, "Bad array!"); - ProcessScaleHelper(aMatrix, aData->Item(1).GetFloatValue(), - aData->Item(2).GetFloatValue(), - aData->Item(3).GetFloatValue()); -} - -/* Process a scale function. */ -static void ProcessScale(Matrix4x4& aMatrix, const nsCSSValue::Array* aData) { - MOZ_ASSERT(aData->Count() == 2 || aData->Count() == 3, "Bad array!"); - /* We either have one element or two. If we have one, it's for both X and Y. - * Otherwise it's one for each. - */ - const nsCSSValue& scaleX = aData->Item(1); - const nsCSSValue& scaleY = (aData->Count() == 2 ? scaleX : aData->Item(2)); - - ProcessScaleHelper(aMatrix, scaleX.GetFloatValue(), scaleY.GetFloatValue(), - 1.0f); +static void ProcessScale3D(Matrix4x4& aMatrix, + const StyleTransformOperation& aOp) { + const auto& scale = aOp.AsScale3D(); + ProcessScaleHelper(aMatrix, scale._0, scale._1, scale._2); } /* Helper function that, given a set of angles, constructs the appropriate * skew matrix. */ -static void ProcessSkewHelper(Matrix4x4& aMatrix, double aXAngle, - double aYAngle) { - aMatrix.SkewXY(aXAngle, aYAngle); -} - -/* Function that converts a skewx transform into a matrix. */ -static void ProcessSkewX(Matrix4x4& aMatrix, const nsCSSValue::Array* aData) { - NS_ASSERTION(aData->Count() == 2, "Bad array!"); - ProcessSkewHelper(aMatrix, aData->Item(1).GetAngleValueInRadians(), 0.0); -} - -/* Function that converts a skewy transform into a matrix. */ -static void ProcessSkewY(Matrix4x4& aMatrix, const nsCSSValue::Array* aData) { - NS_ASSERTION(aData->Count() == 2, "Bad array!"); - ProcessSkewHelper(aMatrix, 0.0, aData->Item(1).GetAngleValueInRadians()); -} - -/* Function that converts a skew transform into a matrix. */ -static void ProcessSkew(Matrix4x4& aMatrix, const nsCSSValue::Array* aData) { - NS_ASSERTION(aData->Count() == 2 || aData->Count() == 3, "Bad array!"); - - double xSkew = aData->Item(1).GetAngleValueInRadians(); - double ySkew = - (aData->Count() == 2 ? 0.0 : aData->Item(2).GetAngleValueInRadians()); - - ProcessSkewHelper(aMatrix, xSkew, ySkew); +static void ProcessSkewHelper(Matrix4x4& aMatrix, const StyleAngle& aXAngle, + const StyleAngle& aYAngle) { + aMatrix.SkewXY(aXAngle.ToRadians(), aYAngle.ToRadians()); } -/* Function that converts a rotate transform into a matrix. */ -static void ProcessRotateZ(Matrix4x4& aMatrix, const nsCSSValue::Array* aData) { - MOZ_ASSERT(aData->Count() == 2, "Invalid array!"); - double theta = aData->Item(1).GetAngleValueInRadians(); - aMatrix.RotateZ(theta); -} - -static void ProcessRotateX(Matrix4x4& aMatrix, const nsCSSValue::Array* aData) { - MOZ_ASSERT(aData->Count() == 2, "Invalid array!"); - double theta = aData->Item(1).GetAngleValueInRadians(); - aMatrix.RotateX(theta); -} - -static void ProcessRotateY(Matrix4x4& aMatrix, const nsCSSValue::Array* aData) { - MOZ_ASSERT(aData->Count() == 2, "Invalid array!"); - double theta = aData->Item(1).GetAngleValueInRadians(); - aMatrix.RotateY(theta); -} - -static void ProcessRotate3D(Matrix4x4& aMatrix, - const nsCSSValue::Array* aData) { - MOZ_ASSERT(aData->Count() == 5, "Invalid array!"); - - double theta = aData->Item(4).GetAngleValueInRadians(); - float x = aData->Item(1).GetFloatValue(); - float y = aData->Item(2).GetFloatValue(); - float z = aData->Item(3).GetFloatValue(); - +static void ProcessRotate3D(Matrix4x4& aMatrix, float aX, float aY, float aZ, + const StyleAngle& aAngle) { Matrix4x4 temp; - temp.SetRotateAxisAngle(x, y, z, theta); - + temp.SetRotateAxisAngle(aX, aY, aZ, aAngle.ToRadians()); aMatrix = temp * aMatrix; } -static void ProcessPerspective(Matrix4x4& aMatrix, - const nsCSSValue::Array* aData) { - MOZ_ASSERT(aData->Count() == 2, "Invalid array!"); - - float depth = ProcessTranslatePart(aData->Item(1), nullptr); +static void ProcessPerspective(Matrix4x4& aMatrix, const Length& aLength) { + float depth = aLength.ToCSSPixels(); ApplyPerspectiveToMatrix(aMatrix, depth); } -/** - * SetToTransformFunction is essentially a giant switch statement that fans - * out to many smaller helper functions. - */ static void MatrixForTransformFunction(Matrix4x4& aMatrix, - const nsCSSValue::Array* aData, + const StyleTransformOperation& aOp, TransformReferenceBox& aRefBox) { - MOZ_ASSERT(aData, "Why did you want to get data from a null array?"); - /* Get the keyword for the transform. */ - switch (TransformFunctionOf(aData)) { - case eCSSKeyword_translatex: - ProcessTranslateX(aMatrix, aData, aRefBox); + switch (aOp.tag) { + case StyleTransformOperation::Tag::TranslateX: + ProcessTranslateX(aMatrix, aOp.AsTranslateX(), aRefBox); + break; + case StyleTransformOperation::Tag::TranslateY: + ProcessTranslateY(aMatrix, aOp.AsTranslateY(), aRefBox); break; - case eCSSKeyword_translatey: - ProcessTranslateY(aMatrix, aData, aRefBox); + case StyleTransformOperation::Tag::TranslateZ: + ProcessTranslateZ(aMatrix, aOp.AsTranslateZ()); + break; + case StyleTransformOperation::Tag::Translate: + ProcessTranslate(aMatrix, aOp.AsTranslate()._0, aOp.AsTranslate()._1, + aRefBox); break; - case eCSSKeyword_translatez: - ProcessTranslateZ(aMatrix, aData); + case StyleTransformOperation::Tag::Translate3D: + return ProcessTranslate3D(aMatrix, aOp.AsTranslate3D()._0, + aOp.AsTranslate3D()._1, aOp.AsTranslate3D()._2, + aRefBox); break; - case eCSSKeyword_translate: - ProcessTranslate(aMatrix, aData, aRefBox); - break; - case eCSSKeyword_translate3d: - ProcessTranslate3D(aMatrix, aData, aRefBox); + case StyleTransformOperation::Tag::ScaleX: + ProcessScaleHelper(aMatrix, aOp.AsScaleX(), 1.0f, 1.0f); break; - case eCSSKeyword_scalex: - ProcessScaleX(aMatrix, aData); + case StyleTransformOperation::Tag::ScaleY: + ProcessScaleHelper(aMatrix, 1.0f, aOp.AsScaleY(), 1.0f); break; - case eCSSKeyword_scaley: - ProcessScaleY(aMatrix, aData); + case StyleTransformOperation::Tag::ScaleZ: + ProcessScaleHelper(aMatrix, 1.0f, 1.0f, aOp.AsScaleZ()); break; - case eCSSKeyword_scalez: - ProcessScaleZ(aMatrix, aData); + case StyleTransformOperation::Tag::Scale: + ProcessScaleHelper(aMatrix, aOp.AsScale()._0, aOp.AsScale()._1, 1.0f); break; - case eCSSKeyword_scale: - ProcessScale(aMatrix, aData); + case StyleTransformOperation::Tag::Scale3D: + ProcessScale3D(aMatrix, aOp); break; - case eCSSKeyword_scale3d: - ProcessScale3D(aMatrix, aData); + case StyleTransformOperation::Tag::SkewX: + ProcessSkewHelper(aMatrix, aOp.AsSkewX(), StyleAngle::Zero()); break; - case eCSSKeyword_skewx: - ProcessSkewX(aMatrix, aData); + case StyleTransformOperation::Tag::SkewY: + ProcessSkewHelper(aMatrix, StyleAngle::Zero(), aOp.AsSkewY()); break; - case eCSSKeyword_skewy: - ProcessSkewY(aMatrix, aData); + case StyleTransformOperation::Tag::Skew: + ProcessSkewHelper(aMatrix, aOp.AsSkew()._0, aOp.AsSkew()._1); break; - case eCSSKeyword_skew: - ProcessSkew(aMatrix, aData); + case StyleTransformOperation::Tag::RotateX: + aMatrix.RotateX(aOp.AsRotateX().ToRadians()); break; - case eCSSKeyword_rotatex: - ProcessRotateX(aMatrix, aData); + case StyleTransformOperation::Tag::RotateY: + aMatrix.RotateY(aOp.AsRotateY().ToRadians()); break; - case eCSSKeyword_rotatey: - ProcessRotateY(aMatrix, aData); + case StyleTransformOperation::Tag::RotateZ: + aMatrix.RotateZ(aOp.AsRotateZ().ToRadians()); break; - case eCSSKeyword_rotatez: - MOZ_FALLTHROUGH; - case eCSSKeyword_rotate: - ProcessRotateZ(aMatrix, aData); + case StyleTransformOperation::Tag::Rotate: + aMatrix.RotateZ(aOp.AsRotate().ToRadians()); break; - case eCSSKeyword_rotate3d: - ProcessRotate3D(aMatrix, aData); + case StyleTransformOperation::Tag::Rotate3D: + ProcessRotate3D(aMatrix, aOp.AsRotate3D()._0, aOp.AsRotate3D()._1, + aOp.AsRotate3D()._2, aOp.AsRotate3D()._3); break; - case eCSSKeyword_matrix: - ProcessMatrix(aMatrix, aData, aRefBox); + case StyleTransformOperation::Tag::Matrix: + ProcessMatrix(aMatrix, aOp); break; - case eCSSKeyword_matrix3d: - ProcessMatrix3D(aMatrix, aData, aRefBox); + case StyleTransformOperation::Tag::Matrix3D: + ProcessMatrix3D(aMatrix, aOp); break; - case eCSSKeyword_interpolatematrix: - ProcessMatrixOperator<Interpolate>(aMatrix, aData, aRefBox); + case StyleTransformOperation::Tag::InterpolateMatrix: + ProcessInterpolateMatrix(aMatrix, aOp, aRefBox); break; - case eCSSKeyword_accumulatematrix: - ProcessMatrixOperator<Accumulate>(aMatrix, aData, aRefBox); + case StyleTransformOperation::Tag::AccumulateMatrix: + ProcessAccumulateMatrix(aMatrix, aOp, aRefBox); break; - case eCSSKeyword_perspective: - ProcessPerspective(aMatrix, aData); + case StyleTransformOperation::Tag::Perspective: + ProcessPerspective(aMatrix, aOp.AsPerspective()); break; default: MOZ_ASSERT_UNREACHABLE("Unknown transform function!"); } } /** * Return the transform function, as an nsCSSKeyword, for the given @@ -773,71 +601,107 @@ void SetIdentityMatrix(nsCSSValue::Array MOZ_ASSERT(aMatrix->Count() == 17, "Invalid matrix3d"); Matrix4x4 m; for (size_t i = 0; i < 16; ++i) { aMatrix->Item(i + 1).SetFloatValue(m.components[i], eCSSUnit_Number); } } -static void ReadTransformsImpl(Matrix4x4& aMatrix, const nsCSSValueList* aList, - TransformReferenceBox& aRefBox) { - for (const nsCSSValueList* curr = aList; curr != nullptr; - curr = curr->mNext) { - const nsCSSValue& currElem = curr->mValue; - if (currElem.GetUnit() != eCSSUnit_Function) { - NS_ASSERTION(currElem.GetUnit() == eCSSUnit_None && !aList->mNext, - "stream should either be a list of functions or a " - "lone None"); - continue; - } - NS_ASSERTION(currElem.GetArrayValue()->Count() >= 1, - "Incoming function is too short!"); - - /* Read in a single transform matrix. */ - MatrixForTransformFunction(aMatrix, currElem.GetArrayValue(), aRefBox); - } -} - -Matrix4x4 ReadTransforms(const nsCSSValueList* aList, +Matrix4x4 ReadTransforms(const StyleTransform& aTransform, TransformReferenceBox& aRefBox, float aAppUnitsPerMatrixUnit) { Matrix4x4 result; - ReadTransformsImpl(result, aList, aRefBox); + + for (const StyleTransformOperation& op : aTransform.Operations()) { + MatrixForTransformFunction(result, op, aRefBox); + } float scale = float(AppUnitsPerCSSPixel()) / aAppUnitsPerMatrixUnit; result.PreScale(1 / scale, 1 / scale, 1 / scale); result.PostScale(scale, scale, scale); return result; } -Matrix4x4 ReadTransforms(const nsCSSValueList* aIndividualTransforms, +static void ProcessTranslate(Matrix4x4& aMatrix, + const StyleTranslate& aTranslate, + TransformReferenceBox& aRefBox) { + switch (aTranslate.tag) { + case StyleTranslate::Tag::None: + return; + case StyleTranslate::Tag::Translate: + return ProcessTranslate(aMatrix, aTranslate.AsTranslate()._0, + aTranslate.AsTranslate()._1, aRefBox); + case StyleTranslate::Tag::Translate3D: + return ProcessTranslate3D(aMatrix, aTranslate.AsTranslate3D()._0, + aTranslate.AsTranslate3D()._1, + aTranslate.AsTranslate3D()._2, aRefBox); + default: + MOZ_ASSERT_UNREACHABLE("Huh?"); + } +} + +static void ProcessRotate(Matrix4x4& aMatrix, const StyleRotate& aRotate, + TransformReferenceBox& aRefBox) { + switch (aRotate.tag) { + case StyleRotate::Tag::None: + return; + case StyleRotate::Tag::Rotate: + aMatrix.RotateZ(aRotate.AsRotate().ToRadians()); + return; + case StyleRotate::Tag::Rotate3D: + return ProcessRotate3D(aMatrix, aRotate.AsRotate3D()._0, + aRotate.AsRotate3D()._1, aRotate.AsRotate3D()._2, + aRotate.AsRotate3D()._3); + default: + MOZ_ASSERT_UNREACHABLE("Huh?"); + } +} + +static void ProcessScale(Matrix4x4& aMatrix, const StyleScale& aScale, + TransformReferenceBox& aRefBox) { + switch (aScale.tag) { + case StyleScale::Tag::None: + return; + case StyleScale::Tag::Scale: + return ProcessScaleHelper(aMatrix, aScale.AsScale()._0, + aScale.AsScale()._1, 1.0f); + case StyleScale::Tag::Scale3D: + return ProcessScaleHelper(aMatrix, aScale.AsScale3D()._0, + aScale.AsScale3D()._1, aScale.AsScale3D()._2); + default: + MOZ_ASSERT_UNREACHABLE("Huh?"); + } +} + +Matrix4x4 ReadTransforms(const StyleTranslate& aTranslate, + const StyleRotate& aRotate, const StyleScale& aScale, const Maybe<MotionPathData>& aMotion, - const nsCSSValueList* aTransform, + const StyleTransform& aTransform, TransformReferenceBox& aRefBox, float aAppUnitsPerMatrixUnit) { Matrix4x4 result; - if (aIndividualTransforms) { - ReadTransformsImpl(result, aIndividualTransforms, aRefBox); - } + ProcessTranslate(result, aTranslate, aRefBox); + ProcessRotate(result, aRotate, aRefBox); + ProcessScale(result, aScale, aRefBox); if (aMotion.isSome()) { // Create the equivalent translate and rotate function, according to the // order in spec. We combine the translate and then the rotate. // https://drafts.fxtf.org/motion-1/#calculating-path-transform result.PreTranslate(aMotion->mTranslate.x, aMotion->mTranslate.y, 0.0); if (aMotion->mRotate != 0.0) { result.RotateZ(aMotion->mRotate); } } - if (aTransform) { - ReadTransformsImpl(result, aTransform, aRefBox); + for (const StyleTransformOperation& op : aTransform.Operations()) { + MatrixForTransformFunction(result, op, aRefBox); } float scale = float(AppUnitsPerCSSPixel()) / aAppUnitsPerMatrixUnit; result.PreScale(1 / scale, 1 / scale, 1 / scale); result.PostScale(scale, scale, scale); return result; } @@ -1044,16 +908,17 @@ bool Decompose2DMatrix(const Matrix& aMa bool Decompose3DMatrix(const Matrix4x4& aMatrix, Point3D& aScale, ShearArray& aShear, gfxQuaternion& aRotate, Point3D& aTranslate, Point4D& aPerspective) { Matrix4x4 local = aMatrix; if (local[3][3] == 0) { return false; } + /* Normalize the matrix */ local.Normalize(); /** * perspective is used to solve for perspective, but it also provides * an easy way to test for singularity of the upper 3x3 component. */ Matrix4x4 perspective = local; @@ -1129,46 +994,9 @@ bool Decompose3DMatrix(const Matrix4x4& } /* Now, get the rotations out */ aRotate = gfxQuaternion(local); return true; } -Matrix CSSValueArrayTo2DMatrix(nsCSSValue::Array* aArray) { - MOZ_ASSERT(aArray && TransformFunctionOf(aArray) == eCSSKeyword_matrix && - aArray->Count() == 7); - Matrix m(aArray->Item(1).GetFloatValue(), aArray->Item(2).GetFloatValue(), - aArray->Item(3).GetFloatValue(), aArray->Item(4).GetFloatValue(), - aArray->Item(5).GetFloatValue(), aArray->Item(6).GetFloatValue()); - return m; -} - -Matrix4x4 CSSValueArrayTo3DMatrix(nsCSSValue::Array* aArray) { - MOZ_ASSERT(aArray && TransformFunctionOf(aArray) == eCSSKeyword_matrix3d && - aArray->Count() == 17); - gfx::Float array[16]; - for (size_t i = 0; i < 16; ++i) { - array[i] = aArray->Item(i + 1).GetFloatValue(); - } - Matrix4x4 m(array); - return m; -} - -Size GetScaleValue(const nsCSSValueSharedList* aList, - const nsIFrame* aForFrame) { - MOZ_ASSERT(aList && aList->mHead); - MOZ_ASSERT(aForFrame); - - TransformReferenceBox refBox(aForFrame); - Matrix4x4 transform = ReadTransforms( - aList->mHead, refBox, aForFrame->PresContext()->AppUnitsPerDevPixel()); - Matrix transform2d; - bool canDraw2D = transform.CanDraw2D(&transform2d); - if (!canDraw2D) { - return Size(); - } - - return transform2d.ScaleFactors(true); -} - } // namespace nsStyleTransformMatrix
--- a/layout/style/nsStyleTransformMatrix.h +++ b/layout/style/nsStyleTransformMatrix.h @@ -148,47 +148,46 @@ class MOZ_STACK_CLASS TransformReference * Return the transform function, as an nsCSSKeyword, for the given * nsCSSValue::Array from a transform list. */ nsCSSKeyword TransformFunctionOf(const nsCSSValue::Array* aData); void SetIdentityMatrix(nsCSSValue::Array* aMatrix); float ProcessTranslatePart( - const nsCSSValue& aValue, TransformReferenceBox* aRefBox, + const mozilla::LengthPercentage& aValue, TransformReferenceBox* aRefBox, TransformReferenceBox::DimensionGetter aDimensionGetter = nullptr); void ProcessInterpolateMatrix(mozilla::gfx::Matrix4x4& aMatrix, - const nsCSSValue::Array* aData, + const mozilla::StyleTransformOperation& aOp, TransformReferenceBox& aBounds); void ProcessAccumulateMatrix(mozilla::gfx::Matrix4x4& aMatrix, - const nsCSSValue::Array* aData, + const mozilla::StyleTransformOperation& aOp, TransformReferenceBox& aBounds); /** - * Given an nsCSSValueList containing -moz-transform functions, - * returns a matrix containing the value of those functions. + * Given a StyleTransform containing transform functions, returns a matrix + * containing the value of those functions. * - * @param aData The nsCSSValueList containing the transform functions + * @param aList the transform operation list. * @param aBounds The frame's bounding rectangle. * @param aAppUnitsPerMatrixUnit The number of app units per device pixel. - * - * eCSSUnit_Pixel (as they are in an StyleAnimationValue) */ -mozilla::gfx::Matrix4x4 ReadTransforms(const nsCSSValueList* aList, +mozilla::gfx::Matrix4x4 ReadTransforms(const mozilla::StyleTransform& aList, TransformReferenceBox& aBounds, float aAppUnitsPerMatrixUnit); // Generate the gfx::Matrix for CSS Transform Module Level 2. // https://drafts.csswg.org/css-transforms-2/#ctm mozilla::gfx::Matrix4x4 ReadTransforms( - const nsCSSValueList* aIndividualTransforms, + const mozilla::StyleTranslate&, const mozilla::StyleRotate&, + const mozilla::StyleScale&, const mozilla::Maybe<mozilla::MotionPathData>& aMotion, - const nsCSSValueList* aTransform, TransformReferenceBox& aRefBox, + const mozilla::StyleTransform&, TransformReferenceBox& aRefBox, float aAppUnitsPerMatrixUnit); /** * Given the x and y values, compute the 2d position with respect to the given * TransformReferenceBox that these values describe, in CSS pixels. */ mozilla::CSSPoint Convert2DPosition(const mozilla::LengthPercentage& aX, const mozilla::LengthPercentage& aY, @@ -218,16 +217,11 @@ bool Decompose2DMatrix(const mozilla::gf * Implements the 3d transform matrix decomposition algorithm. */ bool Decompose3DMatrix(const mozilla::gfx::Matrix4x4& aMatrix, mozilla::gfx::Point3D& aScale, ShearArray& aShear, gfxQuaternion& aRotate, mozilla::gfx::Point3D& aTranslate, mozilla::gfx::Point4D& aPerspective); -mozilla::gfx::Matrix CSSValueArrayTo2DMatrix(nsCSSValue::Array* aArray); -mozilla::gfx::Matrix4x4 CSSValueArrayTo3DMatrix(nsCSSValue::Array* aArray); - -mozilla::gfx::Size GetScaleValue(const nsCSSValueSharedList* aList, - const nsIFrame* aForFrame); } // namespace nsStyleTransformMatrix #endif
--- a/layout/svg/nsSVGUtils.cpp +++ b/layout/svg/nsSVGUtils.cpp @@ -1719,22 +1719,19 @@ gfxMatrix nsSVGUtils::GetTransformMatrix properties.mToTransformOrigin.z}; Matrix svgTransform; Matrix4x4 trans; (void)aFrame->IsSVGTransformed(&svgTransform); if (properties.HasTransform()) { trans = nsStyleTransformMatrix::ReadTransforms( - properties.mIndividualTransformList - ? properties.mIndividualTransformList->mHead - : nullptr, - properties.mMotion, - properties.mTransformList ? properties.mTransformList->mHead : nullptr, - refBox, AppUnitsPerCSSPixel()); + properties.mTranslate, properties.mRotate, properties.mScale, + properties.mMotion, properties.mTransform, refBox, + AppUnitsPerCSSPixel()); } else { trans = Matrix4x4::From2D(svgTransform); } trans.ChangeBasis(svgTransformOrigin); Matrix mm; trans.ProjectTo2D();
--- a/servo/components/style/gecko_bindings/sugar/ns_css_value.rs +++ b/servo/components/style/gecko_bindings/sugar/ns_css_value.rs @@ -271,39 +271,16 @@ impl nsCSSValue { while let Some(item) = unsafe { item_ptr.as_mut() } { let value = values.next().expect("Values shouldn't have been exhausted"); item.mXValue = value.0; item.mYValue = value.1; item_ptr = item.mNext; } debug_assert!(values.next().is_none(), "Values should have been exhausted"); } - - /// Set a shared list - pub fn set_shared_list<I>(&mut self, values: I) - where - I: ExactSizeIterator<Item = nsCSSValue>, - { - debug_assert!(values.len() > 0, "Empty list is not supported"); - unsafe { bindings::Gecko_CSSValue_InitSharedList(self, values.len() as u32) }; - debug_assert_eq!(self.mUnit, nsCSSUnit::eCSSUnit_SharedList); - let list = unsafe { - self.mValue - .mSharedList - .as_ref() - .as_mut() - .expect("List pointer should be non-null") - .mHead - .as_mut() - }; - debug_assert!(list.is_some(), "New created shared list shouldn't be null"); - for (item, new_value) in list.unwrap().into_iter().zip(values) { - *item = new_value; - } - } } impl Drop for nsCSSValue { fn drop(&mut self) { unsafe { bindings::Gecko_CSSValue_Drop(self) }; } }
--- a/servo/components/style/gecko_bindings/sugar/refptr.rs +++ b/servo/components/style/gecko_bindings/sugar/refptr.rs @@ -285,21 +285,16 @@ macro_rules! impl_threadsafe_refcount { } impl_threadsafe_refcount!( structs::mozilla::URLExtraData, bindings::Gecko_AddRefURLExtraDataArbitraryThread, bindings::Gecko_ReleaseURLExtraDataArbitraryThread ); impl_threadsafe_refcount!( - structs::nsCSSValueSharedList, - bindings::Gecko_AddRefCSSValueSharedListArbitraryThread, - bindings::Gecko_ReleaseCSSValueSharedListArbitraryThread -); -impl_threadsafe_refcount!( structs::mozilla::css::URLValue, bindings::Gecko_AddRefCSSURLValueArbitraryThread, bindings::Gecko_ReleaseCSSURLValueArbitraryThread ); impl_threadsafe_refcount!( structs::mozilla::css::GridTemplateAreasValue, bindings::Gecko_AddRefGridTemplateAreasValueArbitraryThread, bindings::Gecko_ReleaseGridTemplateAreasValueArbitraryThread
--- a/servo/components/style/properties/cascade.rs +++ b/servo/components/style/properties/cascade.rs @@ -623,20 +623,16 @@ impl<'a, 'b: 'a> Cascade<'a, 'b> { self.context.builder.visited_style = Some(style); } fn finished_applying_properties(&mut self) { let builder = &mut self.context.builder; #[cfg(feature = "gecko")] { - if let Some(display) = builder.get_box_if_mutated() { - display.generate_combined_transform(); - } - if let Some(bg) = builder.get_background_if_mutated() { bg.fill_arrays(); } if let Some(svg) = builder.get_svg_if_mutated() { svg.fill_arrays(); } }
--- a/servo/components/style/properties/gecko.mako.rs +++ b/servo/components/style/properties/gecko.mako.rs @@ -806,291 +806,16 @@ def set_gecko_property(ffi_name, expr): } UrlOrNone::Url(unsafe { ComputedUrl::from_url_value(self.gecko.${gecko_ffi_name}.to_safe()) }) } </%def> -<% -transform_functions = [ - ("Matrix3D", "matrix3d", ["number"] * 16), - ("Matrix", "matrix", ["number"] * 6), - ("Translate", "translate", ["lp", "lp"]), - ("Translate3D", "translate3d", ["lp", "lp", "length"]), - ("TranslateX", "translatex", ["lp"]), - ("TranslateY", "translatey", ["lp"]), - ("TranslateZ", "translatez", ["length"]), - ("Scale3D", "scale3d", ["number"] * 3), - ("Scale", "scale", ["number", "number"]), - ("ScaleX", "scalex", ["number"]), - ("ScaleY", "scaley", ["number"]), - ("ScaleZ", "scalez", ["number"]), - ("Rotate", "rotate", ["angle"]), - ("Rotate3D", "rotate3d", ["number"] * 3 + ["angle"]), - ("RotateX", "rotatex", ["angle"]), - ("RotateY", "rotatey", ["angle"]), - ("RotateZ", "rotatez", ["angle"]), - ("Skew", "skew", ["angle", "angle"]), - ("SkewX", "skewx", ["angle"]), - ("SkewY", "skewy", ["angle"]), - ("Perspective", "perspective", ["length"]), - ("InterpolateMatrix", "interpolatematrix", ["list"] * 2 + ["percentage"]), - ("AccumulateMatrix", "accumulatematrix", ["list"] * 2 + ["integer_to_percentage"]) -] -%> - -<%def name="transform_function_arm(name, keyword, items)"> - <% - pattern = None - if keyword == "matrix3d": - # m11: number1, m12: number2, .. - single_patterns = ["m%s: %s" % (str(a / 4 + 1) + str(a % 4 + 1), b + str(a + 1)) for (a, b) - in enumerate(items)] - pattern = "(Matrix3D { %s })" % ", ".join(single_patterns) - elif keyword == "matrix": - # a: number1, b: number2, .. - single_patterns = ["%s: %s" % (chr(ord('a') + a), b + str(a + 1)) for (a, b) - in enumerate(items)] - pattern = "(Matrix { %s })" % ", ".join(single_patterns) - elif keyword == "interpolatematrix": - pattern = " { from_list: ref list1, to_list: ref list2, progress: percentage3 }" - elif keyword == "accumulatematrix": - pattern = " { from_list: ref list1, to_list: ref list2, count: integer_to_percentage3 }" - else: - # Generate contents of pattern from items - pattern = "(%s)" % ", ".join([b + str(a+1) for (a,b) in enumerate(items)]) - - # First %s substituted with the call to GetArrayItem, the second - # %s substituted with the corresponding variable - css_value_setters = { - "length" : "bindings::Gecko_CSSValue_SetPixelLength(%s, %s.px())", - "percentage" : "bindings::Gecko_CSSValue_SetPercentage(%s, %s.0)", - # Note: This is an integer type, but we use it as a percentage value in Gecko, so - # need to cast it to f32. - "integer_to_percentage" : "bindings::Gecko_CSSValue_SetPercentage(%s, %s as f32)", - "lp" : "%s.set_length_percentage(%s)", - "angle" : "%s.set_angle(%s)", - "number" : "bindings::Gecko_CSSValue_SetNumber(%s, %s)", - # Note: We use nsCSSValueSharedList here, instead of nsCSSValueList_heap - # because this function is not called on the main thread and - # nsCSSValueList_heap is not thread safe. - "list" : "%s.set_shared_list(%s.0.iter().map(&convert_to_ns_css_value));", - } - %> - crate::values::generics::transform::TransformOperation::${name}${pattern} => { - let len = ${len(items) + 1}; - bindings::Gecko_CSSValue_SetFunction(gecko_value, len); - bindings::Gecko_CSSValue_SetKeyword( - bindings::Gecko_CSSValue_GetArrayItem(gecko_value, 0), - structs::nsCSSKeyword::eCSSKeyword_${keyword} - ); - % for index, item in enumerate(items): - % if item == "list": - debug_assert!(!${item}${index + 1}.0.is_empty()); - % endif - ${css_value_setters[item] % ( - "(&mut *bindings::Gecko_CSSValue_GetArrayItem(gecko_value, %d))" % (index + 1), - item + str(index + 1) - )}; - % endfor - } -</%def> - -<%def name="computed_operation_arm(name, keyword, items)"> - <% - # %s is substituted with the call to GetArrayItem. - css_value_getters = { - "length" : "Length::new(bindings::Gecko_CSSValue_GetNumber(%s))", - "lp" : "%s.get_length_percentage()", - "angle" : "%s.get_angle()", - "number" : "bindings::Gecko_CSSValue_GetNumber(%s)", - "percentage" : "Percentage(bindings::Gecko_CSSValue_GetPercentage(%s))", - "integer_to_percentage" : "bindings::Gecko_CSSValue_GetPercentage(%s) as i32", - "list" : "Transform(convert_shared_list_to_operations(%s))", - } - pre_symbols = "(" - post_symbols = ")" - if keyword == "interpolatematrix" or keyword == "accumulatematrix": - # We generate this like: "TransformOperation::InterpolateMatrix {", so the space is - # between "InterpolateMatrix"/"AccumulateMatrix" and '{' - pre_symbols = " {" - post_symbols = "}" - elif keyword == "matrix3d": - pre_symbols = "(Matrix3D {" - post_symbols = "})" - elif keyword == "matrix": - pre_symbols = "(Matrix {" - post_symbols = "})" - field_names = None - if keyword == "interpolatematrix": - field_names = ["from_list", "to_list", "progress"] - elif keyword == "accumulatematrix": - field_names = ["from_list", "to_list", "count"] - - %> - structs::nsCSSKeyword::eCSSKeyword_${keyword} => { - crate::values::generics::transform::TransformOperation::${name}${pre_symbols} - % for index, item in enumerate(items): - % if keyword == "matrix3d": - m${index / 4 + 1}${index % 4 + 1}: - % elif keyword == "matrix": - ${chr(ord('a') + index)}: - % elif keyword == "interpolatematrix" or keyword == "accumulatematrix": - ${field_names[index]}: - % endif - <% - getter = css_value_getters[item] % ( - "(&*bindings::Gecko_CSSValue_GetArrayItemConst(gecko_value, %d))" % (index + 1) - ) - %> - ${getter}, - % endfor - ${post_symbols} - }, -</%def> - -#[allow(unused_parens)] -fn set_single_transform_function( - servo_value: &values::computed::TransformOperation, - gecko_value: &mut structs::nsCSSValue /* output */ -) { - use crate::values::computed::TransformOperation; - use crate::values::generics::transform::{Matrix, Matrix3D}; - - let convert_to_ns_css_value = |item: &TransformOperation| -> structs::nsCSSValue { - let mut value = structs::nsCSSValue::null(); - set_single_transform_function(item, &mut value); - value - }; - - unsafe { - match *servo_value { - % for servo, gecko, format in transform_functions: - ${transform_function_arm(servo, gecko, format)} - % endfor - } - } -} - -pub fn convert_transform( - input: &[values::computed::TransformOperation], - output: &mut structs::root::RefPtr<structs::root::nsCSSValueSharedList> -) { - use crate::gecko_bindings::sugar::refptr::RefPtr; - - unsafe { output.clear() }; - - let list = unsafe { - RefPtr::from_addrefed(bindings::Gecko_NewCSSValueSharedList(input.len() as u32)) - }; - let value_list = unsafe { list.mHead.as_mut() }; - if let Some(value_list) = value_list { - for (gecko, servo) in value_list.into_iter().zip(input.into_iter()) { - set_single_transform_function(servo, gecko); - } - } - output.set_move(list); -} - -#[allow(unused_parens)] -fn clone_single_transform_function( - gecko_value: &structs::nsCSSValue -) -> values::computed::TransformOperation { - use crate::values::computed::{Length, Percentage, TransformOperation}; - use crate::values::generics::transform::{Matrix, Matrix3D}; - use crate::values::generics::transform::Transform; - - let convert_shared_list_to_operations = |value: &structs::nsCSSValue| - -> Vec<TransformOperation> { - debug_assert_eq!(value.mUnit, structs::nsCSSUnit::eCSSUnit_SharedList); - let value_list = unsafe { - value.mValue.mSharedList.as_ref() - .as_mut().expect("List pointer should be non-null").mHead.as_ref() - }; - debug_assert!(value_list.is_some(), "An empty shared list is not allowed"); - value_list.unwrap().into_iter() - .map(|item| clone_single_transform_function(item)) - .collect() - }; - - let transform_function = unsafe { - bindings::Gecko_CSSValue_GetKeyword(bindings::Gecko_CSSValue_GetArrayItemConst(gecko_value, 0)) - }; - - unsafe { - match transform_function { - % for servo, gecko, format in transform_functions: - ${computed_operation_arm(servo, gecko, format)} - % endfor - _ => panic!("unacceptable transform function"), - } - } -} - -pub fn clone_transform_from_list( - list: Option< &structs::root::nsCSSValueList> -) -> values::computed::Transform { - use crate::values::generics::transform::Transform; - - let result = match list { - Some(list) => { - list.into_iter() - .filter_map(|value| { - // Handle none transform. - if value.is_none() { - None - } else { - Some(clone_single_transform_function(value)) - } - }) - .collect::<Vec<_>>() - }, - _ => vec![], - }; - Transform(result) -} - -<%def name="impl_transform(ident, gecko_ffi_name)"> - #[allow(non_snake_case)] - pub fn set_${ident}(&mut self, other: values::computed::Transform) { - use crate::gecko_properties::convert_transform; - if other.0.is_empty() { - unsafe { - self.gecko.${gecko_ffi_name}.clear(); - } - return; - }; - convert_transform(&other.0, &mut self.gecko.${gecko_ffi_name}); - } - - #[allow(non_snake_case)] - pub fn copy_${ident}_from(&mut self, other: &Self) { - unsafe { self.gecko.${gecko_ffi_name}.set(&other.gecko.${gecko_ffi_name}); } - } - - #[allow(non_snake_case)] - pub fn reset_${ident}(&mut self, other: &Self) { - self.copy_${ident}_from(other) - } - - #[allow(non_snake_case)] - pub fn clone_${ident}(&self) -> values::computed::Transform { - use crate::gecko_properties::clone_transform_from_list; - use crate::values::generics::transform::Transform; - - if self.gecko.${gecko_ffi_name}.mRawPtr.is_null() { - return Transform(vec!()); - } - let list = unsafe { (*self.gecko.${gecko_ffi_name}.to_safe().get()).mHead.as_ref() }; - clone_transform_from_list(list) - } -</%def> - <%def name="impl_logical(name, **kwargs)"> ${helpers.logical_setter(name)} </%def> <%def name="impl_style_struct(style_struct)"> impl ${style_struct.gecko_struct_name} { #[allow(dead_code, unused_variables)] pub fn default(document: &structs::Document) -> Arc<Self> { @@ -1186,17 +911,16 @@ impl Clone for ${style_struct.gecko_stru # Types used with predefined_type()-defined properties that we can auto-generate. predefined_types = { "MozScriptMinSize": impl_absolute_length, "SVGLength": impl_svg_length, "SVGOpacity": impl_svg_opacity, "SVGPaint": impl_svg_paint, "SVGWidth": impl_svg_length, - "Transform": impl_transform, "url::UrlOrNone": impl_css_url, } def longhand_method(longhand): args = dict(ident=longhand.ident, gecko_ffi_name=longhand.gecko_ffi_name) # get the method and pass additional keyword or type-specific arguments if longhand.logical: @@ -2506,28 +2230,22 @@ fn static_assert() { </%def> <% skip_box_longhands= """display animation-name animation-delay animation-duration animation-direction animation-fill-mode animation-play-state animation-iteration-count animation-timing-function clear transition-duration transition-delay transition-timing-function transition-property - transform-style - rotate scroll-snap-points-x scroll-snap-points-y - scroll-snap-coordinate -moz-binding - offset-path shape-outside - translate scale -webkit-line-clamp""" %> + transform-style scroll-snap-points-x + scroll-snap-points-y scroll-snap-coordinate + -moz-binding offset-path shape-outside + -webkit-line-clamp""" %> <%self:impl_trait style_struct_name="Box" skip_longhands="${skip_box_longhands}"> #[inline] - pub fn generate_combined_transform(&mut self) { - unsafe { bindings::Gecko_StyleDisplay_GenerateCombinedTransform(&mut *self.gecko) }; - } - - #[inline] pub fn set_display(&mut self, v: longhands::display::computed_value::T) { self.gecko.mDisplay = v; self.gecko.mOriginalDisplay = v; } #[inline] pub fn copy_display_from(&mut self, other: &Self) { self.gecko.mDisplay = other.gecko.mDisplay; @@ -2820,20 +2538,16 @@ fn static_assert() { } } ${impl_animation_count('iteration_count', 'IterationCount')} ${impl_copy_animation_value('iteration_count', 'IterationCount')} ${impl_animation_timing_function()} - ${impl_individual_transform('rotate', 'Rotate', 'mSpecifiedRotate')} - ${impl_individual_transform('translate', 'Translate', 'mSpecifiedTranslate')} - ${impl_individual_transform('scale', 'Scale', 'mSpecifiedScale')} - <% impl_shape_source("shape_outside", "mShapeOutside") %> pub fn set_offset_path(&mut self, v: longhands::offset_path::computed_value::T) { use crate::gecko_bindings::bindings::{Gecko_NewStyleMotion, Gecko_SetStyleMotion}; use crate::gecko_bindings::structs::StyleShapeSourceType; use crate::values::generics::basic_shape::FillRule; use crate::values::specified::OffsetPath;
--- a/servo/components/style/properties/longhands/box.mako.rs +++ b/servo/components/style/properties/longhands/box.mako.rs @@ -347,17 +347,16 @@ <% transform_extra_prefixes = "moz:layout.css.prefixes.transforms webkit" %> ${helpers.predefined_type( "transform", "Transform", "generics::transform::Transform::none()", extra_prefixes=transform_extra_prefixes, animation_value_type="ComputedValue", - gecko_ffi_name="mSpecifiedTransform", flags="CREATES_STACKING_CONTEXT FIXPOS_CB \ GETCS_NEEDS_LAYOUT_FLUSH CAN_ANIMATE_ON_COMPOSITOR", spec="https://drafts.csswg.org/css-transforms/#propdef-transform", servo_restyle_damage="reflow_out_of_flow", )} ${helpers.predefined_type( "rotate",
--- a/servo/components/style/properties/longhands/ui.mako.rs +++ b/servo/components/style/properties/longhands/ui.mako.rs @@ -76,17 +76,16 @@ enabled_in="chrome", )} ${helpers.predefined_type( "-moz-window-transform", "Transform", "generics::transform::Transform::none()", products="gecko", - gecko_ffi_name="mSpecifiedWindowTransform", flags="GETCS_NEEDS_LAYOUT_FLUSH", animation_value_type="ComputedValue", spec="None (Nonstandard internal property)", enabled_in="chrome", )} ${helpers.predefined_type( "-moz-window-transform-origin",
--- a/servo/components/style/values/animated/transform.rs +++ b/servo/components/style/values/animated/transform.rs @@ -856,17 +856,17 @@ impl Animate for ComputedTransform { fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> { use std::borrow::Cow; // Addition for transforms simply means appending to the list of // transform functions. This is different to how we handle the other // animation procedures so we treat it separately here rather than // handling it in TransformOperation. if procedure == Procedure::Add { - let result = self.0.iter().chain(&other.0).cloned().collect::<Vec<_>>(); + let result = self.0.iter().chain(&*other.0).cloned().collect(); return Ok(Transform(result)); } let this = Cow::Borrowed(&self.0); let other = Cow::Borrowed(&other.0); // Interpolate the common prefix let mut result = this @@ -893,25 +893,25 @@ impl Animate for ComputedTransform { // => Add the remainders to a suitable ___Matrix function. (Some(this_remainder), Some(other_remainder)) => match procedure { Procedure::Add => { debug_assert!(false, "Should have already dealt with add by the point"); return Err(()); }, Procedure::Interpolate { progress } => { result.push(TransformOperation::InterpolateMatrix { - from_list: Transform(this_remainder.to_vec()), - to_list: Transform(other_remainder.to_vec()), + from_list: Transform(this_remainder.to_vec().into()), + to_list: Transform(other_remainder.to_vec().into()), progress: Percentage(progress as f32), }); }, Procedure::Accumulate { count } => { result.push(TransformOperation::AccumulateMatrix { - from_list: Transform(this_remainder.to_vec()), - to_list: Transform(other_remainder.to_vec()), + from_list: Transform(this_remainder.to_vec().into()), + to_list: Transform(other_remainder.to_vec().into()), count: cmp::min(count, i32::max_value() as u64) as i32, }); }, }, // If there is a remainder from just one list, then one list must be shorter but // completely match the type of the corresponding functions in the longer list. // => Interpolate the remainder with identity transforms. (Some(remainder), None) | (None, Some(remainder)) => { @@ -922,18 +922,18 @@ impl Animate for ComputedTransform { .map(|transform| { let identity = transform.to_animated_zero().unwrap(); match transform { // We can't interpolate/accumulate ___Matrix types directly with a // matrix. Instead we need to wrap it in another ___Matrix type. TransformOperation::AccumulateMatrix { .. } | TransformOperation::InterpolateMatrix { .. } => { - let transform_list = Transform(vec![transform.clone()]); - let identity_list = Transform(vec![identity]); + let transform_list = Transform(vec![transform.clone()].into()); + let identity_list = Transform(vec![identity].into()); let (from_list, to_list) = if fill_right { (transform_list, identity_list) } else { (identity_list, transform_list) }; match procedure { Procedure::Add => Err(()), @@ -965,17 +965,17 @@ impl Animate for ComputedTransform { } }) .collect::<Result<Vec<_>, _>>()?, ); }, (None, None) => {}, } - Ok(Transform(result)) + Ok(Transform(result.into())) } } impl ComputeSquaredDistance for ComputedTransform { #[inline] fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> { let squared_dist = self.0.squared_distance_with_zero(&other.0);
--- a/servo/components/style/values/computed/angle.rs +++ b/servo/components/style/values/computed/angle.rs @@ -21,16 +21,17 @@ use style_traits::{CssWriter, ToCss}; Copy, Debug, MallocSizeOf, PartialEq, PartialOrd, ToAnimatedZero, ToResolvedValue, )] +#[repr(C)] pub struct Angle(CSSFloat); impl ToCss for Angle { fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result where W: Write, { self.degrees().to_css(dest)?;
--- a/servo/components/style/values/computed/transform.rs +++ b/servo/components/style/values/computed/transform.rs @@ -11,19 +11,19 @@ use crate::values::computed::{Angle, Int use crate::values::generics::transform as generic; use crate::Zero; use euclid::{Transform3D, Vector3D}; pub use crate::values::generics::transform::TransformStyle; /// A single operation in a computed CSS `transform` pub type TransformOperation = - generic::TransformOperation<Angle, Number, Length, Integer, LengthPercentage>; + generic::GenericTransformOperation<Angle, Number, Length, Integer, LengthPercentage>; /// A computed CSS `transform` -pub type Transform = generic::Transform<TransformOperation>; +pub type Transform = generic::GenericTransform<TransformOperation>; /// The computed value of a CSS `<transform-origin>` pub type TransformOrigin = generic::GenericTransformOrigin<LengthPercentage, LengthPercentage, Length>; /// A vector to represent the direction vector (rotate axis) for Rotate3D. pub type DirectionVector = Vector3D<CSSFloat>; @@ -535,23 +535,23 @@ impl ToAnimatedZero for TransformOperati impl ToAnimatedZero for Transform { #[inline] fn to_animated_zero(&self) -> Result<Self, ()> { Ok(generic::Transform( self.0 .iter() .map(|op| op.to_animated_zero()) - .collect::<Result<Vec<_>, _>>()?, + .collect::<Result<crate::OwnedSlice<_>, _>>()?, )) } } /// A computed CSS `rotate` -pub type Rotate = generic::Rotate<Number, Angle>; +pub type Rotate = generic::GenericRotate<Number, Angle>; impl Rotate { /// Convert TransformOperation to Rotate. pub fn to_transform_operation(&self) -> Option<TransformOperation> { match *self { generic::Rotate::None => None, generic::Rotate::Rotate(angle) => Some(generic::TransformOperation::Rotate(angle)), generic::Rotate::Rotate3D(rx, ry, rz, angle) => { @@ -568,17 +568,17 @@ impl Rotate { generic::Rotate::Rotate3D(rx, ry, rz, angle) }, _ => unreachable!("Found unexpected value for rotate property"), } } } /// A computed CSS `translate` -pub type Translate = generic::Translate<LengthPercentage, Length>; +pub type Translate = generic::GenericTranslate<LengthPercentage, Length>; impl Translate { /// Convert TransformOperation to Translate. pub fn to_transform_operation(&self) -> Option<TransformOperation> { match *self { generic::Translate::None => None, generic::Translate::Translate(tx, ty) => { Some(generic::TransformOperation::Translate(tx, ty)) @@ -597,17 +597,17 @@ impl Translate { generic::Translate::Translate3D(tx, ty, tz) }, _ => unreachable!("Found unexpected value for translate"), } } } /// A computed CSS `scale` -pub type Scale = generic::Scale<Number>; +pub type Scale = generic::GenericScale<Number>; impl Scale { /// Convert TransformOperation to Scale. pub fn to_transform_operation(&self) -> Option<TransformOperation> { match *self { generic::Scale::None => None, generic::Scale::Scale(sx, sy) => Some(generic::TransformOperation::Scale(sx, sy)), generic::Scale::Scale3D(sx, sy, sz) => {
--- a/servo/components/style/values/generics/transform.rs +++ b/servo/components/style/values/generics/transform.rs @@ -25,48 +25,54 @@ use style_traits::{CssWriter, ToCss}; MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss, ToResolvedValue, ToShmem, )] -#[css(comma, function)] -pub struct Matrix<T> { +#[css(comma, function = "matrix")] +#[repr(C)] +pub struct GenericMatrix<T> { pub a: T, pub b: T, pub c: T, pub d: T, pub e: T, pub f: T, } +pub use self::GenericMatrix as Matrix; + #[allow(missing_docs)] #[cfg_attr(rustfmt, rustfmt_skip)] #[css(comma, function = "matrix3d")] #[derive( Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss, ToResolvedValue, ToShmem, )] -pub struct Matrix3D<T> { +#[repr(C)] +pub struct GenericMatrix3D<T> { pub m11: T, pub m12: T, pub m13: T, pub m14: T, pub m21: T, pub m22: T, pub m23: T, pub m24: T, pub m31: T, pub m32: T, pub m33: T, pub m34: T, pub m41: T, pub m42: T, pub m43: T, pub m44: T, } +pub use self::GenericMatrix3D as Matrix3D; + #[cfg_attr(rustfmt, rustfmt_skip)] impl<T: Into<f64>> From<Matrix<T>> for Transform3D<f64> { #[inline] fn from(m: Matrix<T>) -> Self { Transform3D::row_major( m.a.into(), m.b.into(), 0.0, 0.0, m.c.into(), m.d.into(), 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, @@ -137,27 +143,29 @@ fn is_same<N: PartialEq>(x: &N, y: &N) - MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss, ToResolvedValue, ToShmem, )] +#[repr(C, u8)] /// A single operation in the list of a `transform` value -pub enum TransformOperation<Angle, Number, Length, Integer, LengthPercentage> +/// cbindgen:derive-tagged-enum-copy-constructor=true +pub enum GenericTransformOperation<Angle, Number, Length, Integer, LengthPercentage> where Angle: Zero, LengthPercentage: Zero, Number: PartialEq, { /// Represents a 2D 2x3 matrix. - Matrix(Matrix<Number>), + Matrix(GenericMatrix<Number>), /// Represents a 3D 4x4 matrix. - Matrix3D(Matrix3D<Number>), + Matrix3D(GenericMatrix3D<Number>), /// A 2D skew. /// /// If the second angle is not provided it is assumed zero. /// /// Syntax can be skew(angle) or skew(angle, angle) #[css(comma, function)] Skew(Angle, #[css(skip_if = "Zero::is_zero")] Angle), /// skewX(angle) @@ -227,43 +235,48 @@ where /// /// The value must be greater than or equal to zero. #[css(function)] Perspective(Length), /// A intermediate type for interpolation of mismatched transform lists. #[allow(missing_docs)] #[css(comma, function = "interpolatematrix")] InterpolateMatrix { - from_list: Transform<TransformOperation<Angle, Number, Length, Integer, LengthPercentage>>, - to_list: Transform<TransformOperation<Angle, Number, Length, Integer, LengthPercentage>>, + from_list: GenericTransform<GenericTransformOperation<Angle, Number, Length, Integer, LengthPercentage>>, + to_list: GenericTransform<GenericTransformOperation<Angle, Number, Length, Integer, LengthPercentage>>, progress: computed::Percentage, }, /// A intermediate type for accumulation of mismatched transform lists. #[allow(missing_docs)] #[css(comma, function = "accumulatematrix")] AccumulateMatrix { - from_list: Transform<TransformOperation<Angle, Number, Length, Integer, LengthPercentage>>, - to_list: Transform<TransformOperation<Angle, Number, Length, Integer, LengthPercentage>>, + from_list: GenericTransform<GenericTransformOperation<Angle, Number, Length, Integer, LengthPercentage>>, + to_list: GenericTransform<GenericTransformOperation<Angle, Number, Length, Integer, LengthPercentage>>, count: Integer, }, } +pub use self::GenericTransformOperation as TransformOperation; + #[derive( Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss, ToResolvedValue, ToShmem, )] +#[repr(C)] /// A value of the `transform` property -pub struct Transform<T>(#[css(if_empty = "none", iterable)] pub Vec<T>); +pub struct GenericTransform<T>(#[css(if_empty = "none", iterable)] pub crate::OwnedSlice<T>); + +pub use self::GenericTransform as Transform; impl<Angle, Number, Length, Integer, LengthPercentage> TransformOperation<Angle, Number, Length, Integer, LengthPercentage> where Angle: Zero, LengthPercentage: Zero, Number: PartialEq, { @@ -492,17 +505,17 @@ where }; Ok(matrix) } } impl<T> Transform<T> { /// `none` pub fn none() -> Self { - Transform(vec![]) + Transform(Default::default()) } } impl<T: ToMatrix> Transform<T> { /// Return the equivalent 3d matrix of this transform list. /// We return a pair: the first one is the transform matrix, and the second one /// indicates if there is any 3d transform function in this transform list. #[cfg_attr(rustfmt, rustfmt_skip)] @@ -524,17 +537,17 @@ impl<T: ToMatrix> Transform<T> { // We intentionally use Transform3D<f64> during computation to avoid error propagation // because using f32 to compute triangle functions (e.g. in create_rotation()) is not // accurate enough. In Gecko, we also use "double" to compute the triangle functions. // Therefore, let's use Transform3D<f64> during matrix computation and cast it into f32 // in the end. let mut transform = Transform3D::<f64>::identity(); let mut contain_3d = false; - for operation in &self.0 { + for operation in &*self.0 { let matrix = operation.to_3d_matrix(reference_box)?; contain_3d |= operation.is_3d(); transform = transform.pre_mul(&matrix); } Ok((cast_3d_transform(transform), contain_3d)) } } @@ -584,28 +597,31 @@ pub fn get_normalized_vector_and_angle<T MallocSizeOf, PartialEq, SpecifiedValueInfo, ToAnimatedZero, ToComputedValue, ToResolvedValue, ToShmem, )] +#[repr(C, u8)] /// A value of the `Rotate` property /// /// <https://drafts.csswg.org/css-transforms-2/#individual-transforms> -pub enum Rotate<Number, Angle> { +pub enum GenericRotate<Number, Angle> { /// 'none' None, /// '<angle>' Rotate(Angle), /// '<number>{3} <angle>' Rotate3D(Number, Number, Number, Angle), } +pub use self::GenericRotate as Rotate; + /// A trait to check if the current 3D vector is parallel to the DirectionVector. /// This is especially for serialization on Rotate. pub trait IsParallelTo { /// Returns true if this is parallel to the vector. fn is_parallel_to(&self, vector: &computed::transform::DirectionVector) -> bool; } impl<Number, Angle> ToCss for Rotate<Number, Angle> @@ -655,28 +671,31 @@ where MallocSizeOf, PartialEq, SpecifiedValueInfo, ToAnimatedZero, ToComputedValue, ToResolvedValue, ToShmem, )] +#[repr(C, u8)] /// A value of the `Scale` property /// /// <https://drafts.csswg.org/css-transforms-2/#individual-transforms> -pub enum Scale<Number> { +pub enum GenericScale<Number> { /// 'none' None, /// '<number>{1,2}' Scale(Number, Number), /// '<number>{3}' Scale3D(Number, Number, Number), } +pub use self::GenericScale as Scale; + impl<Number: ToCss + PartialEq> ToCss for Scale<Number> { fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result where W: fmt::Write, { match *self { Scale::None => dest.write_str("none"), Scale::Scale(ref x, ref y) => { @@ -705,45 +724,48 @@ impl<Number: ToCss + PartialEq> ToCss fo PartialEq, SpecifiedValueInfo, ToAnimatedZero, ToComputedValue, ToCss, ToResolvedValue, ToShmem, )] +#[repr(C, u8)] /// A value of the `translate` property /// /// https://drafts.csswg.org/css-transforms-2/#individual-transform-serialization: /// /// If a 2d translation is specified, the property must serialize with only one /// or two values (per usual, if the second value is 0px, the default, it must /// be omitted when serializing). /// /// If a 3d translation is specified, all three values must be serialized. /// /// We don't omit the 3rd component even if it is 0px for now, and the /// related spec issue is https://github.com/w3c/csswg-drafts/issues/3305 /// /// <https://drafts.csswg.org/css-transforms-2/#individual-transforms> -pub enum Translate<LengthPercentage, Length> +pub enum GenericTranslate<LengthPercentage, Length> where LengthPercentage: Zero, { /// 'none' None, /// '<length-percentage>' or '<length-percentage> <length-percentage>' Translate( LengthPercentage, #[css(skip_if = "Zero::is_zero")] LengthPercentage, ), /// '<length-percentage> <length-percentage> <length>' Translate3D(LengthPercentage, LengthPercentage, Length), } +pub use self::GenericTranslate as Translate; + #[allow(missing_docs)] #[derive( Clone, Copy, Debug, MallocSizeOf, Parse, PartialEq,
--- a/servo/components/style/values/specified/transform.rs +++ b/servo/components/style/values/specified/transform.rs @@ -37,17 +37,17 @@ impl Transform { input: &mut Parser<'i, 't>, ) -> Result<Self, ParseError<'i>> { use style_traits::{Separator, Space}; if input .try(|input| input.expect_ident_matching("none")) .is_ok() { - return Ok(generic::Transform(Vec::new())); + return Ok(generic::Transform::none()); } Ok(generic::Transform(Space::parse(input, |input| { let function = input.expect_function()?.clone(); input.parse_nested_block(|input| { let location = input.current_source_location(); let result = match_ignore_ascii_case! { &function, "matrix" => { @@ -213,17 +213,17 @@ impl Transform { }, _ => Err(()), }; result.map_err(|()| { location .new_custom_error(StyleParseErrorKind::UnexpectedFunction(function.clone())) }) }) - })?)) + })?.into())) } } impl Parse for Transform { fn parse<'i, 't>( context: &ParserContext, input: &mut Parser<'i, 't>, ) -> Result<Self, ParseError<'i>> {
--- a/servo/ports/geckolib/cbindgen.toml +++ b/servo/ports/geckolib/cbindgen.toml @@ -126,16 +126,20 @@ include = [ "ShapeRadius", "ArcSlice", "ForgottenArcSlicePtr", "HeaderWithLength", "MozContextProperties", "Quotes", "BoxShadow", "SimpleShadow", + "Transform", + "Rotate", + "Scale", + "Translate", ] item_types = ["enums", "structs", "typedefs", "functions"] renaming_overrides_prefixing = true # Prevent some renaming for Gecko types that cbindgen doesn't otherwise understand. [export.rename] "nscolor" = "nscolor" "nsAtom" = "nsAtom" @@ -182,16 +186,17 @@ renaming_overrides_prefixing = true "OriginFlags" = "OriginFlags" "ServoTraversalFlags" = "ServoTraversalFlags" "ServoStyleSetSizes" = "ServoStyleSetSizes" [export.body] "CSSPixelLength" = """ inline nscoord ToAppUnits() const; inline bool IsZero() const; + float ToCSSPixels() const { return _0; } """ "LengthPercentage" = """ // Defined in nsStyleCoord.h static constexpr inline StyleLengthPercentage Zero(); static inline StyleLengthPercentage FromAppUnits(nscoord); static inline StyleLengthPercentage FromPixels(CSSCoord); static inline StyleLengthPercentage FromPercentage(float); @@ -399,8 +404,29 @@ renaming_overrides_prefixing = true inline StyleAtom(const StyleAtom& aOther); inline ~StyleAtom(); """ "OwnedStr" = """ inline nsDependentCSubstring AsString() const; """ + +"GenericTransform" = """ + inline Span<const T> Operations() const; + inline bool IsNone() const; +""" + +"GenericTransformOperation" = """ + private: + // Private default constructor without initialization so that the helper + // constructor functions still work as expected. They take care of + // initializing the fields properly. + StyleGenericTransformOperation() {} + public: +""" + + +"Angle" = """ + inline static StyleAngle Zero(); + inline float ToDegrees() const; + inline double ToRadians() const; +"""
--- a/servo/ports/geckolib/glue.rs +++ b/servo/ports/geckolib/glue.rs @@ -42,17 +42,16 @@ use style::gecko_bindings::bindings::nsA use style::gecko_bindings::bindings::nsAString; use style::gecko_bindings::bindings::Gecko_AddPropertyToSet; use style::gecko_bindings::bindings::Gecko_AppendPropertyValuePair; use style::gecko_bindings::bindings::Gecko_ConstructFontFeatureValueSet; use style::gecko_bindings::bindings::Gecko_GetOrCreateFinalKeyframe; use style::gecko_bindings::bindings::Gecko_GetOrCreateInitialKeyframe; use style::gecko_bindings::bindings::Gecko_GetOrCreateKeyframeAtStart; use style::gecko_bindings::bindings::Gecko_HaveSeenPtr; -use style::gecko_bindings::bindings::Gecko_NewNoneTransform; use style::gecko_bindings::structs; use style::gecko_bindings::structs::{Element as RawGeckoElement, nsINode as RawGeckoNode}; use style::gecko_bindings::structs::{ RawServoStyleSet, RawServoAuthorStyles, RawServoCssUrlData, RawServoDeclarationBlock, RawServoMediaList, RawServoCounterStyleRule, RawServoAnimationValue, RawServoSupportsRule, RawServoKeyframesRule, ServoCssRules, RawServoStyleSheetContents, RawServoPageRule, RawServoNamespaceRule, RawServoMozDocumentRule, @@ -60,17 +59,16 @@ use style::gecko_bindings::structs::{ RawServoFontFaceRule, RawServoFontFeatureValuesRule, RawServoSharedMemoryBuilder }; use style::gecko_bindings::structs::gfxFontFeatureValueSet; use style::gecko_bindings::structs::nsAtom; use style::gecko_bindings::structs::nsCSSCounterDesc; use style::gecko_bindings::structs::nsCSSFontDesc; use style::gecko_bindings::structs::nsCSSPropertyID; -use style::gecko_bindings::structs::nsCSSValueSharedList; use style::gecko_bindings::structs::nsChangeHint; use style::gecko_bindings::structs::nsCompatibility; use style::gecko_bindings::structs::nsStyleTransformMatrix::MatrixTransformOperator; use style::gecko_bindings::structs::nsTArray; use style::gecko_bindings::structs::nsTimingFunction; use style::gecko_bindings::structs::nsresult; use style::gecko_bindings::structs::AtomArray; use style::gecko_bindings::structs::PseudoStyleType; @@ -94,17 +92,16 @@ use style::gecko_bindings::structs::Shee use style::gecko_bindings::structs::SheetLoadDataHolder; use style::gecko_bindings::structs::SheetParsingMode; use style::gecko_bindings::structs::StyleRuleInclusion; use style::gecko_bindings::structs::StyleSheet as DomStyleSheet; use style::gecko_bindings::structs::URLExtraData; use style::gecko_bindings::sugar::ownership::{FFIArcHelpers, HasArcFFI, HasFFI}; use style::gecko_bindings::sugar::ownership::{HasSimpleFFI, HasBoxFFI, Strong, Owned, OwnedOrNull}; use style::gecko_bindings::sugar::refptr::RefPtr; -use style::gecko_properties; use style::global_style_data::{GlobalStyleData, GLOBAL_STYLE_DATA, STYLE_THREAD_POOL}; use style::invalidation::element::restyle_hints::RestyleHint; use style::media_queries::MediaList; use style::parser::{self, Parse, ParserContext}; use style::properties::animated_properties::AnimationValue; use style::properties::{parse_one_declaration_into, parse_style_attribute}; use style::properties::{ComputedValues, Importance, NonCustomPropertyId}; use style::properties::{LonghandId, LonghandIdSet, PropertyDeclarationBlock, PropertyId}; @@ -786,97 +783,85 @@ pub extern "C" fn Servo_AnimationValue_C LonghandId::BackgroundColor => { Arc::new(AnimationValue::BackgroundColor(animatedRGBA.into())).into_strong() }, _ => panic!("Should be background-color property"), } } #[no_mangle] -pub unsafe extern "C" fn Servo_AnimationValue_GetTransform( +pub unsafe extern "C" fn Servo_AnimationValue_GetScale( + value: &RawServoAnimationValue, +) -> *const computed::Scale { + let value = AnimationValue::as_arc(&value); + match **value { + AnimationValue::Scale(ref value) => value, + _ => unreachable!("Expected scale"), + } +} + +#[no_mangle] +pub unsafe extern "C" fn Servo_AnimationValue_GetTranslate( value: &RawServoAnimationValue, - list: *mut structs::RefPtr<nsCSSValueSharedList>, -) -> nsCSSPropertyID { - let list = &mut *list; +) -> *const computed::Translate { + let value = AnimationValue::as_arc(&value); + match **value { + AnimationValue::Translate(ref value) => value, + _ => unreachable!("Expected translate"), + } +} + +#[no_mangle] +pub unsafe extern "C" fn Servo_AnimationValue_GetRotate( + value: &RawServoAnimationValue, +) -> *const computed::Rotate { let value = AnimationValue::as_arc(&value); match **value { - AnimationValue::Transform(ref servo_list) => { - if servo_list.0.is_empty() { - list.set_move(RefPtr::from_addrefed(Gecko_NewNoneTransform())); - } else { - gecko_properties::convert_transform(&servo_list.0, list); - } - nsCSSPropertyID::eCSSProperty_transform - }, - AnimationValue::Translate(ref v) => { - if let Some(v) = v.to_transform_operation() { - gecko_properties::convert_transform(&[v], list); - } else { - list.set_move(RefPtr::from_addrefed(Gecko_NewNoneTransform())); - } - nsCSSPropertyID::eCSSProperty_translate - }, - AnimationValue::Rotate(ref v) => { - if let Some(v) = v.to_transform_operation() { - gecko_properties::convert_transform(&[v], list); - } else { - list.set_move(RefPtr::from_addrefed(Gecko_NewNoneTransform())); - } - nsCSSPropertyID::eCSSProperty_rotate - }, - AnimationValue::Scale(ref v) => { - if let Some(v) = v.to_transform_operation() { - gecko_properties::convert_transform(&[v], list); - } else { - list.set_move(RefPtr::from_addrefed(Gecko_NewNoneTransform())); - } - nsCSSPropertyID::eCSSProperty_scale - }, - _ => unreachable!("Unsupported transform-like animation value"), + AnimationValue::Rotate(ref value) => value, + _ => unreachable!("Expected rotate"), + } +} + +#[no_mangle] +pub unsafe extern "C" fn Servo_AnimationValue_GetTransform( + value: &RawServoAnimationValue, +) -> *const computed::Transform { + let value = AnimationValue::as_arc(&value); + match **value { + AnimationValue::Transform(ref value) => value, + _ => unreachable!("Unsupported transform animation value"), } } #[no_mangle] +pub unsafe extern "C" fn Servo_AnimationValue_Rotate(r: &computed::Rotate) -> Strong<RawServoAnimationValue> { + Arc::new(AnimationValue::Rotate(r.clone())).into_strong() +} + +#[no_mangle] +pub unsafe extern "C" fn Servo_AnimationValue_Translate(t: &computed::Translate) -> Strong<RawServoAnimationValue> { + Arc::new(AnimationValue::Translate(t.clone())).into_strong() +} + +#[no_mangle] +pub unsafe extern "C" fn Servo_AnimationValue_Scale(s: &computed::Scale) -> Strong<RawServoAnimationValue> { + Arc::new(AnimationValue::Scale(s.clone())).into_strong() +} + +#[no_mangle] pub unsafe extern "C" fn Servo_AnimationValue_Transform( - property: nsCSSPropertyID, - list: *const nsCSSValueSharedList, + list: *const computed::TransformOperation, + len: usize, ) -> Strong<RawServoAnimationValue> { - use style::values::computed::transform::{Rotate, Scale, Translate}; - - let list = (&*list).mHead.as_ref(); - - let property = LonghandId::from_nscsspropertyid(property) - .expect("We don't have shorthand property animation value"); - let transform = gecko_properties::clone_transform_from_list(list); - match property { - LonghandId::Rotate => { - let rotate = if transform.0.is_empty() { - style::values::generics::transform::Rotate::None - } else { - debug_assert_eq!(transform.0.len(), 1); - Rotate::from_transform_operation(&(transform.0)[0]) - }; - Arc::new(AnimationValue::Rotate(rotate)).into_strong() - }, - LonghandId::Scale => { - debug_assert_eq!(transform.0.len(), 1); - Arc::new(AnimationValue::Scale(Scale::from_transform_operation(&(transform.0)[0]))) - .into_strong() - }, - LonghandId::Translate => { - debug_assert_eq!(transform.0.len(), 1); - Arc::new(AnimationValue::Translate( - Translate::from_transform_operation(&(transform.0)[0]) - )).into_strong() - }, - LonghandId::Transform => { - Arc::new(AnimationValue::Transform(transform)).into_strong() - }, - _ => unreachable!("Unsupported transform-like animation value"), - } + use style::values::generics::transform::Transform; + + let slice = std::slice::from_raw_parts(list, len); + Arc::new(AnimationValue::Transform( + Transform(slice.iter().cloned().collect()) + )).into_strong() } #[no_mangle] pub extern "C" fn Servo_AnimationValue_DeepEqual( this: &RawServoAnimationValue, other: &RawServoAnimationValue, ) -> bool { let this_value = AnimationValue::as_arc(&this); @@ -5204,16 +5189,22 @@ pub extern "C" fn Servo_GetAnimationValu ); for (index, anim) in iter.enumerate() { unsafe { animation_values.set_len((index + 1) as u32) }; animation_values[index].set_arc_leaky(Arc::new(anim)); } } #[no_mangle] +pub extern "C" fn Servo_AnimationValue_GetPropertyId(value: &RawServoAnimationValue) -> nsCSSPropertyID { + let value = AnimationValue::as_arc(&value); + value.id().to_nscsspropertyid() +} + +#[no_mangle] pub extern "C" fn Servo_AnimationValue_Compute( element: &RawGeckoElement, declarations: &RawServoDeclarationBlock, style: &ComputedValues, raw_data: &RawServoStyleSet, ) -> Strong<RawServoAnimationValue> { let data = PerDocumentStyleData::from_ffi(raw_data).borrow(); let metrics = get_metrics_provider_for_product();