/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef mozilla_MotionPathUtils_h #define mozilla_MotionPathUtils_h #include "mozilla/gfx/2D.h" #include "mozilla/gfx/Point.h" #include "mozilla/gfx/Rect.h" #include "mozilla/Maybe.h" #include "mozilla/ServoStyleConsts.h" #include "Units.h" class nsIFrame; namespace nsStyleTransformMatrix { class TransformReferenceBox; } namespace mozilla { namespace layers { class MotionPathData; class PathCommand; } // namespace layers struct ResolvedMotionPathData { gfx::Point mTranslate; float mRotate; // The delta value between transform-origin and offset-anchor. gfx::Point mShift; }; // The collected information for offset-path. We preprocess the value of // offset-path and use this data for resolving motion path. struct OffsetPathData { enum class Type : uint8_t { None, Shape, Ray, }; struct ShapeData { RefPtr mGfxPath; // The current position of this transfromed box in the coordinate system of // its containing block. nsPoint mCurrentPosition; // True if it is a closed loop; false if it is a unclosed interval. // https://drafts.fxtf.org/motion/#path-distance bool mIsClosedLoop; }; struct RayData { const StyleRayFunction* mRay; // The coord box of the containing block. nsRect mCoordBox; // The current position of this transfromed box in the coordinate system of // its containing block. nsPoint mCurrentPosition; // The reference length for computing ray(contain). CSSCoord mContainReferenceLength; }; Type mType; union { ShapeData mShape; RayData mRay; }; static OffsetPathData None() { return OffsetPathData(); } static OffsetPathData Shape(already_AddRefed&& aGfxPath, nsPoint&& aCurrentPosition, bool aIsClosedPath) { return OffsetPathData(std::move(aGfxPath), std::move(aCurrentPosition), aIsClosedPath); } static OffsetPathData Ray(const StyleRayFunction& aRay, nsRect&& aCoordBox, nsPoint&& aPosition, CSSCoord&& aContainReferenceLength) { return OffsetPathData(&aRay, std::move(aCoordBox), std::move(aPosition), std::move(aContainReferenceLength)); } static OffsetPathData Ray(const StyleRayFunction& aRay, const nsRect& aCoordBox, const nsPoint& aPosition, const CSSCoord& aContainReferenceLength) { return OffsetPathData(&aRay, aCoordBox, aPosition, aContainReferenceLength); } bool IsNone() const { return mType == Type::None; } bool IsShape() const { return mType == Type::Shape; } bool IsRay() const { return mType == Type::Ray; } const ShapeData& AsShape() const { MOZ_ASSERT(IsShape()); return mShape; } const RayData& AsRay() const { MOZ_ASSERT(IsRay()); return mRay; } ~OffsetPathData() { switch (mType) { case Type::Shape: mShape.~ShapeData(); break; case Type::Ray: mRay.~RayData(); break; default: break; } } OffsetPathData(const OffsetPathData& aOther) : mType(aOther.mType) { switch (mType) { case Type::Shape: mShape = aOther.mShape; break; case Type::Ray: mRay = aOther.mRay; break; default: break; } } OffsetPathData(OffsetPathData&& aOther) : mType(aOther.mType) { switch (mType) { case Type::Shape: mShape = std::move(aOther.mShape); break; case Type::Ray: mRay = std::move(aOther.mRay); break; default: break; } } private: OffsetPathData() : mType(Type::None) {} OffsetPathData(already_AddRefed&& aPath, nsPoint&& aCurrentPosition, bool aIsClosed) : mType(Type::Shape), mShape{std::move(aPath), std::move(aCurrentPosition), aIsClosed} {} OffsetPathData(const StyleRayFunction* aRay, nsRect&& aCoordBox, nsPoint&& aPosition, CSSCoord&& aContainReferenceLength) : mType(Type::Ray), mRay{aRay, std::move(aCoordBox), std::move(aPosition), std::move(aContainReferenceLength)} {} OffsetPathData(const StyleRayFunction* aRay, const nsRect& aCoordBox, const nsPoint& aPosition, const CSSCoord& aContainReferenceLength) : mType(Type::Ray), mRay{aRay, aCoordBox, aPosition, aContainReferenceLength} {} OffsetPathData& operator=(const OffsetPathData&) = delete; OffsetPathData& operator=(OffsetPathData&&) = delete; }; // MotionPathUtils is a namespace class containing utility functions related to // processing motion path in the [motion-1]. // https://drafts.fxtf.org/motion-1/ class MotionPathUtils final { using TransformReferenceBox = nsStyleTransformMatrix::TransformReferenceBox; public: /** * SVG frames (unlike other frames) have a reference box that can be (and * typically is) offset from the TopLeft() of the frame. * * In motion path, we have to make sure the object is aligned with offset-path * when using content area, so we should tweak the anchor point by a given * offset. */ static CSSPoint ComputeAnchorPointAdjustment(const nsIFrame& aFrame); /** * In CSS context, this returns the the box being referenced from the element * that establishes the containing block for this element. * In SVG context, we always use view-box. * https://drafts.fxtf.org/motion-1/#valdef-offset-path-coord-box */ static const nsIFrame* GetOffsetPathReferenceBox(const nsIFrame* aFrame, nsRect& aOutputRect); /** * Return the width or the height of the element’s border box, whichever is * larger. This is for computing the ray() with "contain" keyword. */ static CSSCoord GetRayContainReferenceSize(nsIFrame* aFrame); /** * Get the resolved radius for inset(0 round X), where X is the parameter of * |aRadius|. * This returns an empty array if we cannot compute the radii; otherwise, it * returns an array with 8 elements. */ static nsTArray ComputeBorderRadii( const StyleBorderRadius& aBorderRadius, const nsRect& aCoordBox); /** * Generate the motion path transform result. This function may be called on * the compositor thread. */ static Maybe ResolveMotionPath( const OffsetPathData& aPath, const LengthPercentage& aDistance, const StyleOffsetRotate& aRotate, const StylePositionOrAuto& aAnchor, const StyleOffsetPosition& aPosition, const CSSPoint& aTransformOrigin, TransformReferenceBox&, const CSSPoint& aAnchorPointAdjustment); /** * Generate the motion path transform result with |nsIFrame|. This is only * called in the main thread. */ static Maybe ResolveMotionPath( const nsIFrame* aFrame, TransformReferenceBox&); /** * Generate the motion path transfrom result with styles and * layers::MotionPathData. * This is only called by the compositor. */ static Maybe ResolveMotionPath( const StyleOffsetPath* aPath, const StyleLengthPercentage* aDistance, const StyleOffsetRotate* aRotate, const StylePositionOrAuto* aAnchor, const StyleOffsetPosition* aPosition, const Maybe& aMotionPathData, TransformReferenceBox&, gfx::Path* aCachedMotionPath); /** * Build a gfx::Path from the svg path data. We should give it a path builder. * If |aPathBuilder| is nullptr, we return null path. * This can be used on the main thread or on the compositor thread. */ static already_AddRefed BuildSVGPath( const StyleSVGPathData& aPath, gfx::PathBuilder* aPathBuilder); /** * Build a gfx::Path from the computed basic shape. */ static already_AddRefed BuildPath(const StyleBasicShape&, const StyleOffsetPosition&, const nsRect& aCoordBox, const nsPoint& aCurrentPosition, gfx::PathBuilder*); /** * Get a path builder for motion path on the main thread. */ static already_AddRefed GetPathBuilder(); /** * Get a path builder for compositor. */ static already_AddRefed GetCompositorPathBuilder(); }; } // namespace mozilla #endif // mozilla_MotionPathUtils_h