nsStyleTransformMatrix.h (6783B)
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 /* 8 * A class representing three matrices that can be used for style transforms. 9 */ 10 11 #ifndef nsStyleTransformMatrix_h_ 12 #define nsStyleTransformMatrix_h_ 13 14 #include "Units.h" // for CSSPoint 15 #include "mozilla/ServoStyleConsts.h" 16 #include "mozilla/gfx/Matrix.h" 17 #include "nsSize.h" 18 19 class nsIFrame; 20 class nsPresContext; 21 struct gfxQuaternion; 22 struct nsRect; 23 24 namespace mozilla { 25 struct ResolvedMotionPathData; 26 } // namespace mozilla 27 28 /** 29 * A helper to generate gfxMatrixes from css transform functions. 30 */ 31 namespace nsStyleTransformMatrix { 32 // The operator passed to Servo backend. 33 enum class MatrixTransformOperator : uint8_t { Interpolate, Accumulate }; 34 35 /** 36 * This class provides on-demand access to the 'reference box' for CSS 37 * transforms (needed to resolve percentage values in 'transform', 38 * 'transform-origin', etc.): 39 * 40 * http://dev.w3.org/csswg/css-transforms/#reference-box 41 * 42 * This class helps us to avoid calculating the reference box unless and 43 * until it is actually needed. This is important for performance when 44 * transforms are applied to SVG elements since the reference box for SVG is 45 * much more expensive to calculate (than for elements with a CSS layout box 46 * where we can use the nsIFrame's cached mRect), much more common (than on 47 * HTML), and yet very rarely have percentage values that require the 48 * reference box to be resolved. We also don't want to cause SVG frames to 49 * cache lots of ObjectBoundingBoxProperty objects that aren't needed. 50 * 51 * If UNIFIED_CONTINUATIONS (experimental, and currently broke) is defined, 52 * we consider the reference box for non-SVG frames to be the smallest 53 * rectangle containing a frame and all of its continuations. For example, 54 * if there is a <span> element with several continuations split over 55 * several lines, this function will return the rectangle containing all of 56 * those continuations. (This behavior is not currently in a spec.) 57 */ 58 class MOZ_STACK_CLASS TransformReferenceBox final { 59 public: 60 typedef nscoord (TransformReferenceBox::*DimensionGetter)(); 61 62 TransformReferenceBox() = default; 63 64 explicit TransformReferenceBox(const nsIFrame* aFrame) : mFrame(aFrame) { 65 MOZ_ASSERT(mFrame); 66 } 67 68 TransformReferenceBox(const nsIFrame* aFrame, 69 const nsRect& aFallbackDimensions) { 70 mFrame = aFrame; 71 if (!mFrame) { 72 Init(aFallbackDimensions); 73 } 74 } 75 76 void Init(const nsIFrame* aFrame) { 77 MOZ_ASSERT(!mFrame && !mIsCached); 78 mFrame = aFrame; 79 } 80 81 void Init(const nsRect& aDimensions) { 82 MOZ_ASSERT(!mFrame && !mIsCached); 83 mBox = aDimensions; 84 mIsCached = true; 85 } 86 87 /** 88 * The offset of the reference box from the nsIFrame's TopLeft(). This 89 * is non-zero only in the case of SVG content. If we can successfully 90 * implement UNIFIED_CONTINUATIONS at some point in the future then it 91 * may also be non-zero for non-SVG content. 92 */ 93 nscoord X() { 94 EnsureDimensionsAreCached(); 95 return mBox.X(); 96 } 97 nscoord Y() { 98 EnsureDimensionsAreCached(); 99 return mBox.Y(); 100 } 101 102 /** 103 * The size of the reference box. 104 */ 105 nscoord Width() { 106 EnsureDimensionsAreCached(); 107 return mBox.Width(); 108 } 109 nscoord Height() { 110 EnsureDimensionsAreCached(); 111 return mBox.Height(); 112 } 113 114 bool IsEmpty() { return !mFrame; } 115 116 private: 117 // We don't really need to prevent copying, but since none of our consumers 118 // currently need to copy, preventing copying may allow us to catch some 119 // cases where we use pass-by-value instead of pass-by-reference. 120 TransformReferenceBox(const TransformReferenceBox&) = delete; 121 122 void EnsureDimensionsAreCached(); 123 124 const nsIFrame* mFrame = nullptr; 125 nsRect mBox; 126 bool mIsCached = false; 127 }; 128 129 float ProcessTranslatePart( 130 const mozilla::LengthPercentage& aValue, TransformReferenceBox* aRefBox, 131 TransformReferenceBox::DimensionGetter aDimensionGetter = nullptr); 132 133 void ProcessInterpolateMatrix(mozilla::gfx::Matrix4x4& aMatrix, 134 const mozilla::StyleTransformOperation& aOp, 135 TransformReferenceBox& aBounds); 136 137 void ProcessAccumulateMatrix(mozilla::gfx::Matrix4x4& aMatrix, 138 const mozilla::StyleTransformOperation& aOp, 139 TransformReferenceBox& aBounds); 140 141 /** 142 * Given a StyleTransform containing transform functions, returns a matrix 143 * containing the value of those functions. 144 * 145 * @param aList the transform operation list. 146 * @param aBounds The frame's bounding rectangle. 147 * @param aAppUnitsPerMatrixUnit The number of app units per device pixel. 148 */ 149 mozilla::gfx::Matrix4x4 ReadTransforms(const mozilla::StyleTransform& aList, 150 TransformReferenceBox& aBounds, 151 float aAppUnitsPerMatrixUnit); 152 153 // Generate the gfx::Matrix for CSS Transform Module Level 2. 154 // https://drafts.csswg.org/css-transforms-2/#ctm 155 mozilla::gfx::Matrix4x4 ReadTransforms( 156 const mozilla::StyleTranslate&, const mozilla::StyleRotate&, 157 const mozilla::StyleScale&, const mozilla::ResolvedMotionPathData* aMotion, 158 const mozilla::StyleTransform&, TransformReferenceBox& aRefBox, 159 float aAppUnitsPerMatrixUnit); 160 161 /** 162 * Given the x and y values, compute the 2d position with respect to the given 163 * a reference box size that these values describe, in CSS pixels. 164 */ 165 mozilla::CSSPoint Convert2DPosition(const mozilla::LengthPercentage& aX, 166 const mozilla::LengthPercentage& aY, 167 const mozilla::CSSSize& aSize); 168 169 /** 170 * Given the x and y values, compute the 2d position with respect to the given 171 * TransformReferenceBox that these values describe, in CSS pixels. 172 */ 173 mozilla::CSSPoint Convert2DPosition(const mozilla::LengthPercentage& aX, 174 const mozilla::LengthPercentage& aY, 175 TransformReferenceBox& aRefBox); 176 177 /** 178 * Given the x and y values, compute the 2d position with respect to the given 179 * TransformReferenceBox that these values describe, in device pixels. 180 */ 181 mozilla::gfx::Point Convert2DPosition(const mozilla::LengthPercentage& aX, 182 const mozilla::LengthPercentage& aY, 183 TransformReferenceBox& aRefBox, 184 int32_t aAppUnitsPerDevPixel); 185 186 } // namespace nsStyleTransformMatrix 187 188 #endif