Line data Source code
1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* This Source Code Form is subject to the terms of the Mozilla Public
3 : * License, v. 2.0. If a copy of the MPL was not distributed with this
4 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 :
6 : /*
7 : * A class representing three matrices that can be used for style transforms.
8 : */
9 :
10 : #ifndef nsStyleTransformMatrix_h_
11 : #define nsStyleTransformMatrix_h_
12 :
13 : #include "gfxPoint.h"
14 : #include "mozilla/gfx/Matrix.h"
15 : #include "mozilla/EnumeratedArray.h"
16 : #include "nsCSSValue.h"
17 : #include "nsSize.h"
18 :
19 : #include <limits>
20 :
21 : class nsIFrame;
22 : class nsStyleContext;
23 : class nsPresContext;
24 : struct gfxQuaternion;
25 : struct nsRect;
26 : namespace mozilla {
27 : class RuleNodeCacheConditions;
28 : } // namespace mozilla
29 :
30 : /**
31 : * A helper to generate gfxMatrixes from css transform functions.
32 : */
33 : namespace nsStyleTransformMatrix {
34 : // The operator passed to Servo backend.
35 : enum class MatrixTransformOperator: uint8_t {
36 : Interpolate,
37 : Accumulate
38 : };
39 :
40 : // Function for applying perspective() transform function. We treat
41 : // any value smaller than epsilon as perspective(infinity), which
42 : // follows CSSWG's resolution on perspective(0). See bug 1316236.
43 0 : inline void ApplyPerspectiveToMatrix(mozilla::gfx::Matrix4x4& aMatrix,
44 : float aDepth)
45 : {
46 0 : if (aDepth >= std::numeric_limits<float>::epsilon()) {
47 0 : aMatrix.Perspective(aDepth);
48 : }
49 0 : }
50 :
51 : /**
52 : * This class provides on-demand access to the 'reference box' for CSS
53 : * transforms (needed to resolve percentage values in 'transform',
54 : * 'transform-origin', etc.):
55 : *
56 : * http://dev.w3.org/csswg/css-transforms/#reference-box
57 : *
58 : * This class helps us to avoid calculating the reference box unless and
59 : * until it is actually needed. This is important for performance when
60 : * transforms are applied to SVG elements since the reference box for SVG is
61 : * much more expensive to calculate (than for elements with a CSS layout box
62 : * where we can use the nsIFrame's cached mRect), much more common (than on
63 : * HTML), and yet very rarely have percentage values that require the
64 : * reference box to be resolved. We also don't want to cause SVG frames to
65 : * cache lots of ObjectBoundingBoxProperty objects that aren't needed.
66 : *
67 : * If UNIFIED_CONTINUATIONS (experimental, and currently broke) is defined,
68 : * we consider the reference box for non-SVG frames to be the smallest
69 : * rectangle containing a frame and all of its continuations. For example,
70 : * if there is a <span> element with several continuations split over
71 : * several lines, this function will return the rectangle containing all of
72 : * those continuations. (This behavior is not currently in a spec.)
73 : */
74 : class MOZ_STACK_CLASS TransformReferenceBox final {
75 : public:
76 : typedef nscoord (TransformReferenceBox::*DimensionGetter)();
77 :
78 388 : explicit TransformReferenceBox()
79 388 : : mFrame(nullptr)
80 388 : , mIsCached(false)
81 388 : {}
82 :
83 0 : explicit TransformReferenceBox(const nsIFrame* aFrame)
84 0 : : mFrame(aFrame)
85 0 : , mIsCached(false)
86 : {
87 0 : MOZ_ASSERT(mFrame);
88 0 : }
89 :
90 0 : explicit TransformReferenceBox(const nsIFrame* aFrame,
91 : const nsSize& aFallbackDimensions)
92 0 : {
93 0 : mFrame = aFrame;
94 0 : mIsCached = false;
95 0 : if (!mFrame) {
96 0 : Init(aFallbackDimensions);
97 : }
98 0 : }
99 :
100 388 : void Init(const nsIFrame* aFrame) {
101 388 : MOZ_ASSERT(!mFrame && !mIsCached);
102 388 : mFrame = aFrame;
103 388 : }
104 :
105 : void Init(const nsSize& aDimensions);
106 :
107 : /**
108 : * The offset of the reference box from the nsIFrame's TopLeft(). This
109 : * is non-zero only in the case of SVG content. If we can successfully
110 : * implement UNIFIED_CONTINUATIONS at some point in the future then it
111 : * may also be non-zero for non-SVG content.
112 : */
113 144 : nscoord X() {
114 144 : EnsureDimensionsAreCached();
115 144 : return mX;
116 : }
117 144 : nscoord Y() {
118 144 : EnsureDimensionsAreCached();
119 144 : return mY;
120 : }
121 :
122 : /**
123 : * The size of the reference box.
124 : */
125 152 : nscoord Width() {
126 152 : EnsureDimensionsAreCached();
127 152 : return mWidth;
128 : }
129 152 : nscoord Height() {
130 152 : EnsureDimensionsAreCached();
131 152 : return mHeight;
132 : }
133 :
134 0 : bool IsEmpty() {
135 0 : return !mFrame;
136 : }
137 :
138 : private:
139 : // We don't really need to prevent copying, but since none of our consumers
140 : // currently need to copy, preventing copying may allow us to catch some
141 : // cases where we use pass-by-value instead of pass-by-reference.
142 : TransformReferenceBox(const TransformReferenceBox&) = delete;
143 :
144 : void EnsureDimensionsAreCached();
145 :
146 : const nsIFrame* mFrame;
147 : nscoord mX, mY, mWidth, mHeight;
148 : bool mIsCached;
149 : };
150 :
151 : /**
152 : * Return the transform function, as an nsCSSKeyword, for the given
153 : * nsCSSValue::Array from a transform list.
154 : */
155 : nsCSSKeyword TransformFunctionOf(const nsCSSValue::Array* aData);
156 :
157 : void SetIdentityMatrix(nsCSSValue::Array* aMatrix);
158 :
159 : float ProcessTranslatePart(const nsCSSValue& aValue,
160 : nsStyleContext* aContext,
161 : nsPresContext* aPresContext,
162 : mozilla::RuleNodeCacheConditions& aConditions,
163 : TransformReferenceBox* aRefBox,
164 : TransformReferenceBox::DimensionGetter aDimensionGetter = nullptr);
165 :
166 : void
167 : ProcessInterpolateMatrix(mozilla::gfx::Matrix4x4& aMatrix,
168 : const nsCSSValue::Array* aData,
169 : nsStyleContext* aContext,
170 : nsPresContext* aPresContext,
171 : mozilla::RuleNodeCacheConditions& aConditions,
172 : TransformReferenceBox& aBounds,
173 : bool* aContains3dTransform);
174 :
175 : void
176 : ProcessAccumulateMatrix(mozilla::gfx::Matrix4x4& aMatrix,
177 : const nsCSSValue::Array* aData,
178 : nsStyleContext* aContext,
179 : nsPresContext* aPresContext,
180 : mozilla::RuleNodeCacheConditions& aConditions,
181 : TransformReferenceBox& aBounds,
182 : bool* aContains3dTransform);
183 :
184 : /**
185 : * Given an nsCSSValueList containing -moz-transform functions,
186 : * returns a matrix containing the value of those functions.
187 : *
188 : * @param aData The nsCSSValueList containing the transform functions
189 : * @param aContext The style context, used for unit conversion.
190 : * @param aPresContext The presentation context, used for unit conversion.
191 : * @param aConditions Set to uncachable (by calling SetUncacheable()) if the
192 : * result cannot be cached in the rule tree, otherwise untouched.
193 : * @param aBounds The frame's bounding rectangle.
194 : * @param aAppUnitsPerMatrixUnit The number of app units per device pixel.
195 : * @param aContains3dTransform [out] Set to true if aList contains at least
196 : * one 3d transform function (as defined in the CSS transforms
197 : * specification), false otherwise.
198 : *
199 : * aContext and aPresContext may be null if all of the (non-percent)
200 : * length values in aData are already known to have been converted to
201 : * eCSSUnit_Pixel (as they are in an StyleAnimationValue)
202 : */
203 : mozilla::gfx::Matrix4x4 ReadTransforms(const nsCSSValueList* aList,
204 : nsStyleContext* aContext,
205 : nsPresContext* aPresContext,
206 : mozilla::RuleNodeCacheConditions& aConditions,
207 : TransformReferenceBox& aBounds,
208 : float aAppUnitsPerMatrixUnit,
209 : bool* aContains3dTransform);
210 :
211 : /**
212 : * Given two nsStyleCoord values, compute the 2d position with respect to the
213 : * given TransformReferenceBox that these values describe, in device pixels.
214 : */
215 : mozilla::gfx::Point Convert2DPosition(nsStyleCoord const (&aValue)[2],
216 : TransformReferenceBox& aRefBox,
217 : int32_t aAppUnitsPerDevPixel);
218 :
219 : // Shear type for decomposition.
220 : enum class ShearType {
221 : XYSHEAR,
222 : XZSHEAR,
223 : YZSHEAR,
224 : Count
225 : };
226 : using ShearArray =
227 : mozilla::EnumeratedArray<ShearType, ShearType::Count, float>;
228 :
229 : /*
230 : * Implements the 2d transform matrix decomposition algorithm.
231 : */
232 : bool Decompose2DMatrix(const mozilla::gfx::Matrix& aMatrix,
233 : mozilla::gfx::Point3D& aScale,
234 : ShearArray& aShear,
235 : gfxQuaternion& aRotate,
236 : mozilla::gfx::Point3D& aTranslate);
237 : /*
238 : * Implements the 3d transform matrix decomposition algorithm.
239 : */
240 : bool Decompose3DMatrix(const mozilla::gfx::Matrix4x4& aMatrix,
241 : mozilla::gfx::Point3D& aScale,
242 : ShearArray& aShear,
243 : gfxQuaternion& aRotate,
244 : mozilla::gfx::Point3D& aTranslate,
245 : mozilla::gfx::Point4D& aPerspective);
246 :
247 : mozilla::gfx::Matrix CSSValueArrayTo2DMatrix(nsCSSValue::Array* aArray);
248 : mozilla::gfx::Matrix4x4 CSSValueArrayTo3DMatrix(nsCSSValue::Array* aArray);
249 :
250 : gfxSize GetScaleValue(const nsCSSValueSharedList* aList,
251 : const nsIFrame* aForFrame);
252 : } // namespace nsStyleTransformMatrix
253 :
254 : #endif
|