diff options
Diffstat (limited to 'layout/base/MotionPathUtils.h')
-rw-r--r-- | layout/base/MotionPathUtils.h | 232 |
1 files changed, 232 insertions, 0 deletions
diff --git a/layout/base/MotionPathUtils.h b/layout/base/MotionPathUtils.h new file mode 100644 index 0000000000..286a435c4d --- /dev/null +++ b/layout/base/MotionPathUtils.h @@ -0,0 +1,232 @@ +/* -*- 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 { + +using RayFunction = StyleRayFunction<StyleAngle>; + +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; +}; + +struct RayReferenceData { + // The initial position related to the containing block. + CSSPoint mInitialPosition; + // The rect of the containing block. + CSSRect mContainingBlockRect; + // The size of its border-box in CSS Layout. If it's in SVG layout, this is + // the size of view box. + CSSSize mBorderBoxSize; + + RayReferenceData() = default; + explicit RayReferenceData(const nsIFrame* aFrame); + + bool operator==(const RayReferenceData& aOther) const { + return mInitialPosition == aOther.mInitialPosition && + mContainingBlockRect == aOther.mContainingBlockRect && + mBorderBoxSize == aOther.mBorderBoxSize; + } +}; + +// 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, + Path, + Ray, + }; + + struct PathData { + RefPtr<gfx::Path> mGfxPath; + bool mIsClosedIntervals; + }; + + struct RayData { + const RayFunction* mRay; + RayReferenceData mData; + }; + + Type mType; + union { + PathData mPath; + RayData mRay; + }; + + static OffsetPathData None() { return OffsetPathData(); } + static OffsetPathData Path(const StyleSVGPathData& aPath, + already_AddRefed<gfx::Path>&& aGfxPath) { + const auto& path = aPath._0.AsSpan(); + return OffsetPathData(std::move(aGfxPath), + !path.empty() && path.rbegin()->IsClosePath()); + } + static OffsetPathData Ray(const RayFunction& aRay, + const RayReferenceData& aData) { + return OffsetPathData(&aRay, aData); + } + static OffsetPathData Ray(const RayFunction& aRay, RayReferenceData&& aData) { + return OffsetPathData(&aRay, std::move(aData)); + } + + bool IsNone() const { return mType == Type::None; } + bool IsPath() const { return mType == Type::Path; } + bool IsRay() const { return mType == Type::Ray; } + + const PathData& AsPath() const { + MOZ_ASSERT(IsPath()); + return mPath; + } + + const RayData& AsRay() const { + MOZ_ASSERT(IsRay()); + return mRay; + } + + ~OffsetPathData() { + switch (mType) { + case Type::Path: + mPath.~PathData(); + break; + case Type::Ray: + mRay.~RayData(); + break; + default: + break; + } + } + + OffsetPathData(const OffsetPathData& aOther) : mType(aOther.mType) { + switch (mType) { + case Type::Path: + mPath = aOther.mPath; + break; + case Type::Ray: + mRay = aOther.mRay; + break; + default: + break; + } + } + + OffsetPathData(OffsetPathData&& aOther) : mType(aOther.mType) { + switch (mType) { + case Type::Path: + mPath = std::move(aOther.mPath); + break; + case Type::Ray: + mRay = std::move(aOther.mRay); + break; + default: + break; + } + } + + private: + OffsetPathData() : mType(Type::None) {} + OffsetPathData(already_AddRefed<gfx::Path>&& aPath, bool aIsClosed) + : mType(Type::Path), mPath{std::move(aPath), aIsClosed} {} + OffsetPathData(const RayFunction* aRay, RayReferenceData&& aRef) + : mType(Type::Ray), mRay{aRay, std::move(aRef)} {} + OffsetPathData(const RayFunction* aRay, const RayReferenceData& aRef) + : mType(Type::Ray), mRay{aRay, aRef} {} + 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); + + /** + * Generate the motion path transform result. This function may be called on + * the compositor thread. + */ + static Maybe<ResolvedMotionPathData> ResolveMotionPath( + const OffsetPathData& aPath, const LengthPercentage& aDistance, + const StyleOffsetRotate& aRotate, const StylePositionOrAuto& aAnchor, + 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<ResolvedMotionPathData> 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<ResolvedMotionPathData> ResolveMotionPath( + const StyleOffsetPath* aPath, const StyleLengthPercentage* aDistance, + const StyleOffsetRotate* aRotate, const StylePositionOrAuto* aAnchor, + const Maybe<layers::MotionPathData>& aMotionPathData, + TransformReferenceBox&, gfx::Path* aCachedMotionPath); + + /** + * Normalize StyleSVGPathData. + * + * The algorithm of normalization is the same as normalize() in + * servo/components/style/values/specified/svg_path.rs + * FIXME: Bug 1489392: We don't have to normalize the path here if we accept + * the spec issue which would like to normalize svg paths at computed time. + * https://github.com/w3c/svgwg/issues/321 + */ + static StyleSVGPathData NormalizeSVGPathData(const StyleSVGPathData& aPath); + + /** + * Build a gfx::Path from the computed svg path. We should give it a path + * builder. If |aPathBuilder| is nullptr, we return null path. + * */ + static already_AddRefed<gfx::Path> BuildPath(const StyleSVGPathData& aPath, + gfx::PathBuilder* aPathBuilder); + + /** + * Get a path builder for compositor. + */ + static already_AddRefed<gfx::PathBuilder> GetCompositorPathBuilder(); +}; + +} // namespace mozilla + +#endif // mozilla_MotionPathUtils_h |