1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef mozilla_MotionPathUtils_h 8 #define mozilla_MotionPathUtils_h 9 10 #include "mozilla/gfx/2D.h" 11 #include "mozilla/gfx/Point.h" 12 #include "mozilla/gfx/Rect.h" 13 #include "mozilla/Maybe.h" 14 #include "mozilla/ServoStyleConsts.h" 15 #include "Units.h" 16 17 class nsIFrame; 18 19 namespace nsStyleTransformMatrix { 20 class TransformReferenceBox; 21 } 22 23 namespace mozilla { 24 25 using RayFunction = StyleRayFunction<StyleAngle>; 26 27 namespace layers { 28 class MotionPathData; 29 class PathCommand; 30 } // namespace layers 31 32 struct ResolvedMotionPathData { 33 gfx::Point mTranslate; 34 float mRotate; 35 // The delta value between transform-origin and offset-anchor. 36 gfx::Point mShift; 37 }; 38 39 struct RayReferenceData { 40 // The initial position related to the containing block. 41 CSSPoint mInitialPosition; 42 // The rect of the containing block. 43 CSSRect mContainingBlockRect; 44 45 RayReferenceData() = default; 46 explicit RayReferenceData(const nsIFrame* aFrame); 47 48 bool operator==(const RayReferenceData& aOther) const { 49 return mInitialPosition == aOther.mInitialPosition && 50 mContainingBlockRect == aOther.mContainingBlockRect; 51 } 52 }; 53 54 // The collected information for offset-path. We preprocess the value of 55 // offset-path and use this data for resolving motion path. 56 struct OffsetPathData { 57 enum class Type : uint8_t { 58 None, 59 Path, 60 Ray, 61 }; 62 63 struct PathData { 64 RefPtr<gfx::Path> mGfxPath; 65 bool mIsClosedIntervals; 66 }; 67 68 struct RayData { 69 const RayFunction* mRay; 70 RayReferenceData mData; 71 }; 72 73 Type mType; 74 union { 75 PathData mPath; 76 RayData mRay; 77 }; 78 NoneOffsetPathData79 static OffsetPathData None() { return OffsetPathData(); } PathOffsetPathData80 static OffsetPathData Path(const StyleSVGPathData& aPath, 81 already_AddRefed<gfx::Path>&& aGfxPath) { 82 const auto& path = aPath._0.AsSpan(); 83 return OffsetPathData(std::move(aGfxPath), 84 !path.empty() && path.rbegin()->IsClosePath()); 85 } RayOffsetPathData86 static OffsetPathData Ray(const RayFunction& aRay, 87 const RayReferenceData& aData) { 88 return OffsetPathData(&aRay, aData); 89 } RayOffsetPathData90 static OffsetPathData Ray(const RayFunction& aRay, RayReferenceData&& aData) { 91 return OffsetPathData(&aRay, std::move(aData)); 92 } 93 IsNoneOffsetPathData94 bool IsNone() const { return mType == Type::None; } IsPathOffsetPathData95 bool IsPath() const { return mType == Type::Path; } IsRayOffsetPathData96 bool IsRay() const { return mType == Type::Ray; } 97 AsPathOffsetPathData98 const PathData& AsPath() const { 99 MOZ_ASSERT(IsPath()); 100 return mPath; 101 } 102 AsRayOffsetPathData103 const RayData& AsRay() const { 104 MOZ_ASSERT(IsRay()); 105 return mRay; 106 } 107 ~OffsetPathDataOffsetPathData108 ~OffsetPathData() { 109 switch (mType) { 110 case Type::Path: 111 mPath.~PathData(); 112 break; 113 case Type::Ray: 114 mRay.~RayData(); 115 break; 116 default: 117 break; 118 } 119 } 120 OffsetPathDataOffsetPathData121 OffsetPathData(const OffsetPathData& aOther) : mType(aOther.mType) { 122 switch (mType) { 123 case Type::Path: 124 mPath = aOther.mPath; 125 break; 126 case Type::Ray: 127 mRay = aOther.mRay; 128 break; 129 default: 130 break; 131 } 132 } 133 OffsetPathDataOffsetPathData134 OffsetPathData(OffsetPathData&& aOther) : mType(aOther.mType) { 135 switch (mType) { 136 case Type::Path: 137 mPath = std::move(aOther.mPath); 138 break; 139 case Type::Ray: 140 mRay = std::move(aOther.mRay); 141 break; 142 default: 143 break; 144 } 145 } 146 147 private: OffsetPathDataOffsetPathData148 OffsetPathData() : mType(Type::None) {} OffsetPathDataOffsetPathData149 OffsetPathData(already_AddRefed<gfx::Path>&& aPath, bool aIsClosed) 150 : mType(Type::Path), mPath{std::move(aPath), aIsClosed} {} OffsetPathDataOffsetPathData151 OffsetPathData(const RayFunction* aRay, RayReferenceData&& aRef) 152 : mType(Type::Ray), mRay{aRay, std::move(aRef)} {} OffsetPathDataOffsetPathData153 OffsetPathData(const RayFunction* aRay, const RayReferenceData& aRef) 154 : mType(Type::Ray), mRay{aRay, aRef} {} 155 OffsetPathData& operator=(const OffsetPathData&) = delete; 156 OffsetPathData& operator=(OffsetPathData&&) = delete; 157 }; 158 159 // MotionPathUtils is a namespace class containing utility functions related to 160 // processing motion path in the [motion-1]. 161 // https://drafts.fxtf.org/motion-1/ 162 class MotionPathUtils final { 163 using TransformReferenceBox = nsStyleTransformMatrix::TransformReferenceBox; 164 165 public: 166 // SVG frames (unlike other frames) have a reference box that can be (and 167 // typically is) offset from the TopLeft() of the frame. 168 // 169 // In motion path, we have to make sure the object is aligned with offset-path 170 // when using content area, so we should tweak the anchor point by a given 171 // offset. 172 static CSSPoint ComputeAnchorPointAdjustment(const nsIFrame& aFrame); 173 174 /** 175 * Generate the motion path transform result. This function may be called on 176 * the compositor thread. 177 */ 178 static Maybe<ResolvedMotionPathData> ResolveMotionPath( 179 const OffsetPathData& aPath, const LengthPercentage& aDistance, 180 const StyleOffsetRotate& aRotate, const StylePositionOrAuto& aAnchor, 181 const CSSPoint& aTransformOrigin, TransformReferenceBox&, 182 const CSSPoint& aAnchorPointAdjustment); 183 184 /** 185 * Generate the motion path transform result with |nsIFrame|. This is only 186 * called in the main thread. 187 */ 188 static Maybe<ResolvedMotionPathData> ResolveMotionPath( 189 const nsIFrame* aFrame, TransformReferenceBox&); 190 191 /** 192 * Generate the motion path transfrom result with styles and 193 * layers::MotionPathData. 194 * This is only called by the compositor. 195 */ 196 static Maybe<ResolvedMotionPathData> ResolveMotionPath( 197 const StyleOffsetPath* aPath, const StyleLengthPercentage* aDistance, 198 const StyleOffsetRotate* aRotate, const StylePositionOrAuto* aAnchor, 199 const Maybe<layers::MotionPathData>& aMotionPathData, 200 TransformReferenceBox&, gfx::Path* aCachedMotionPath); 201 202 /** 203 * Normalize StyleSVGPathData. 204 * 205 * The algorithm of normalization is the same as normalize() in 206 * servo/components/style/values/specified/svg_path.rs 207 * FIXME: Bug 1489392: We don't have to normalize the path here if we accept 208 * the spec issue which would like to normalize svg paths at computed time. 209 * https://github.com/w3c/svgwg/issues/321 210 */ 211 static StyleSVGPathData NormalizeSVGPathData(const StyleSVGPathData& aPath); 212 213 /** 214 * Build a gfx::Path from the computed svg path. We should give it a path 215 * builder. If |aPathBuilder| is nullptr, we return null path. 216 * */ 217 static already_AddRefed<gfx::Path> BuildPath(const StyleSVGPathData& aPath, 218 gfx::PathBuilder* aPathBuilder); 219 220 /** 221 * Get a path builder for compositor. 222 */ 223 static already_AddRefed<gfx::PathBuilder> GetCompositorPathBuilder(); 224 }; 225 226 } // namespace mozilla 227 228 #endif // mozilla_MotionPathUtils_h 229