Line data Source code
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 MOZ_UNIT_TRANSFORMS_H_
8 : #define MOZ_UNIT_TRANSFORMS_H_
9 :
10 : #include "Units.h"
11 : #include "mozilla/gfx/Matrix.h"
12 : #include "mozilla/Maybe.h"
13 : #include "nsRegion.h"
14 :
15 : namespace mozilla {
16 :
17 : // Convenience functions for converting an entity from one strongly-typed
18 : // coordinate system to another without changing the values it stores (this
19 : // can be thought of as a cast).
20 : // To use these functions, you must provide a justification for each use!
21 : // Feel free to add more justifications to PixelCastJustification, along with
22 : // a comment that explains under what circumstances it is appropriate to use.
23 :
24 : enum class PixelCastJustification : uint8_t {
25 : // For the root layer, Screen Pixel = Parent Layer Pixel.
26 : ScreenIsParentLayerForRoot,
27 : // On the layout side, Screen Pixel = LayoutDevice at the outer-window level.
28 : LayoutDeviceIsScreenForBounds,
29 : // For the root layer, Render Target Pixel = Parent Layer Pixel.
30 : RenderTargetIsParentLayerForRoot,
31 : // For the root composition size we want to view it as layer pixels in any layer
32 : ParentLayerToLayerForRootComposition,
33 : // The Layer coordinate space for one layer is the ParentLayer coordinate
34 : // space for its children
35 : MovingDownToChildren,
36 : // The transform that is usually used to convert between two coordinate
37 : // systems is not available (for example, because the object that stores it
38 : // is being destroyed), so fall back to the identity.
39 : TransformNotAvailable,
40 : // When an OS event is initially constructed, its reference point is
41 : // technically in screen pixels, as it has not yet accounted for any
42 : // asynchronous transforms. This justification is for viewing the initial
43 : // reference point as a screen point. The reverse is useful when synthetically
44 : // created WidgetEvents need to be converted back to InputData.
45 : LayoutDeviceIsScreenForUntransformedEvent,
46 : // Similar to LayoutDeviceIsScreenForUntransformedEvent, PBrowser handles
47 : // some widget/tab dimension information as the OS does -- in screen units.
48 : LayoutDeviceIsScreenForTabDims,
49 : // A combination of LayoutDeviceIsScreenForBounds and
50 : // ScreenIsParentLayerForRoot, which is how we're using it.
51 : LayoutDeviceIsParentLayerForRCDRSF,
52 : // Used to treat the product of AsyncTransformComponentMatrix objects
53 : // as an AsyncTransformMatrix. See the definitions of these matrices in
54 : // LayersTypes.h for details.
55 : MultipleAsyncTransforms,
56 : // We have reason to believe a layer doesn't have a local transform.
57 : // Should only be used if we've already checked or asserted this.
58 : NoTransformOnLayer,
59 : // When building non-rasterized WebRender layers (e.g.
60 : // WebRenderDisplayItemLayer, or anything else that doesn't deal in textures),
61 : // there is no "resolution" and so the LayoutDevicePixel space is equal to the
62 : // LayerPixel space.
63 : WebRenderHasUnitResolution
64 : };
65 :
66 : template <class TargetUnits, class SourceUnits>
67 0 : gfx::CoordTyped<TargetUnits> ViewAs(const gfx::CoordTyped<SourceUnits>& aCoord, PixelCastJustification) {
68 0 : return gfx::CoordTyped<TargetUnits>(aCoord.value);
69 : }
70 : template <class TargetUnits, class SourceUnits>
71 27 : gfx::SizeTyped<TargetUnits> ViewAs(const gfx::SizeTyped<SourceUnits>& aSize, PixelCastJustification) {
72 27 : return gfx::SizeTyped<TargetUnits>(aSize.width, aSize.height);
73 : }
74 : template <class TargetUnits, class SourceUnits>
75 8 : gfx::IntSizeTyped<TargetUnits> ViewAs(const gfx::IntSizeTyped<SourceUnits>& aSize, PixelCastJustification) {
76 8 : return gfx::IntSizeTyped<TargetUnits>(aSize.width, aSize.height);
77 : }
78 : template <class TargetUnits, class SourceUnits>
79 33 : gfx::PointTyped<TargetUnits> ViewAs(const gfx::PointTyped<SourceUnits>& aPoint, PixelCastJustification) {
80 33 : return gfx::PointTyped<TargetUnits>(aPoint.x, aPoint.y);
81 : }
82 : template <class TargetUnits, class SourceUnits>
83 7 : gfx::IntPointTyped<TargetUnits> ViewAs(const gfx::IntPointTyped<SourceUnits>& aPoint, PixelCastJustification) {
84 7 : return gfx::IntPointTyped<TargetUnits>(aPoint.x, aPoint.y);
85 : }
86 : template <class TargetUnits, class SourceUnits>
87 0 : gfx::RectTyped<TargetUnits> ViewAs(const gfx::RectTyped<SourceUnits>& aRect, PixelCastJustification) {
88 0 : return gfx::RectTyped<TargetUnits>(aRect.x, aRect.y, aRect.width, aRect.height);
89 : }
90 : template <class TargetUnits, class SourceUnits>
91 241 : gfx::IntRectTyped<TargetUnits> ViewAs(const gfx::IntRectTyped<SourceUnits>& aRect, PixelCastJustification) {
92 241 : return gfx::IntRectTyped<TargetUnits>(aRect.x, aRect.y, aRect.width, aRect.height);
93 : }
94 : template <class TargetUnits, class SourceUnits>
95 : gfx::MarginTyped<TargetUnits> ViewAs(const gfx::MarginTyped<SourceUnits>& aMargin, PixelCastJustification) {
96 : return gfx::MarginTyped<TargetUnits>(aMargin.top, aMargin.right, aMargin.bottom, aMargin.left);
97 : }
98 : template <class TargetUnits, class SourceUnits>
99 : gfx::IntMarginTyped<TargetUnits> ViewAs(const gfx::IntMarginTyped<SourceUnits>& aMargin, PixelCastJustification) {
100 : return gfx::IntMarginTyped<TargetUnits>(aMargin.top, aMargin.right, aMargin.bottom, aMargin.left);
101 : }
102 : template <class TargetUnits, class SourceUnits>
103 121 : gfx::IntRegionTyped<TargetUnits> ViewAs(const gfx::IntRegionTyped<SourceUnits>& aRegion, PixelCastJustification) {
104 121 : return gfx::IntRegionTyped<TargetUnits>::FromUnknownRegion(aRegion.ToUnknownRegion());
105 : }
106 : template <class NewTargetUnits, class OldTargetUnits, class SourceUnits>
107 0 : gfx::ScaleFactor<SourceUnits, NewTargetUnits> ViewTargetAs(
108 : const gfx::ScaleFactor<SourceUnits, OldTargetUnits>& aScaleFactor,
109 : PixelCastJustification) {
110 0 : return gfx::ScaleFactor<SourceUnits, NewTargetUnits>(aScaleFactor.scale);
111 : }
112 : template <class TargetUnits, class SourceUnits>
113 29 : Maybe<gfx::IntRectTyped<TargetUnits>> ViewAs(const Maybe<gfx::IntRectTyped<SourceUnits>>& aRect, PixelCastJustification aJustification) {
114 29 : if (aRect.isSome()) {
115 0 : return Some(ViewAs<TargetUnits>(aRect.value(), aJustification));
116 : }
117 29 : return Nothing();
118 : }
119 : // Unlike the other functions in this category, this function takes the
120 : // target matrix type, rather than its source and target unit types, as
121 : // the explicit template argument, so an example invocation is:
122 : // ViewAs<ScreenToLayerMatrix4x4>(otherTypedMatrix, justification)
123 : // The reason is that if it took the source and target unit types as two
124 : // template arguments, there may be some confusion as to which is the
125 : // source and which is the target.
126 : template <class TargetMatrix, class SourceMatrixSourceUnits, class SourceMatrixTargetUnits>
127 109 : TargetMatrix ViewAs(
128 : const gfx::Matrix4x4Typed<SourceMatrixSourceUnits, SourceMatrixTargetUnits>& aMatrix,
129 : PixelCastJustification) {
130 109 : return TargetMatrix::FromUnknownMatrix(aMatrix.ToUnknownMatrix());
131 : }
132 :
133 : // Convenience functions for casting untyped entities to typed entities.
134 : // Using these functions does not require a justification, but once we convert
135 : // all code to use strongly typed units they should not be needed any longer.
136 : template <class TargetUnits>
137 : gfx::PointTyped<TargetUnits> ViewAs(const gfxPoint& aPoint) {
138 : return gfx::PointTyped<TargetUnits>(aPoint.x, aPoint.y);
139 : }
140 : template <class TargetUnits>
141 : gfx::PointTyped<TargetUnits> ViewAs(const gfx::Point& aPoint) {
142 : return gfx::PointTyped<TargetUnits>(aPoint.x, aPoint.y);
143 : }
144 : template <class TargetUnits>
145 0 : gfx::RectTyped<TargetUnits> ViewAs(const gfx::Rect& aRect) {
146 0 : return gfx::RectTyped<TargetUnits>(aRect.x, aRect.y, aRect.width, aRect.height);
147 : }
148 : template <class TargetUnits>
149 : gfx::IntSizeTyped<TargetUnits> ViewAs(const nsIntSize& aSize) {
150 : return gfx::IntSizeTyped<TargetUnits>(aSize.width, aSize.height);
151 : }
152 : template <class TargetUnits>
153 1507 : gfx::IntPointTyped<TargetUnits> ViewAs(const nsIntPoint& aPoint) {
154 1507 : return gfx::IntPointTyped<TargetUnits>(aPoint.x, aPoint.y);
155 : }
156 : template <class TargetUnits>
157 1557 : gfx::IntRectTyped<TargetUnits> ViewAs(const nsIntRect& aRect) {
158 1557 : return gfx::IntRectTyped<TargetUnits>(aRect.x, aRect.y, aRect.width, aRect.height);
159 : }
160 : template <class TargetUnits>
161 121 : gfx::IntRegionTyped<TargetUnits> ViewAs(const nsIntRegion& aRegion) {
162 121 : return gfx::IntRegionTyped<TargetUnits>::FromUnknownRegion(aRegion);
163 : }
164 : // Unlike the other functions in this category, this function takes the
165 : // target matrix type, rather than its source and target unit types, as
166 : // the template argument, so an example invocation is:
167 : // ViewAs<ScreenToLayerMatrix4x4>(untypedMatrix)
168 : // The reason is that if it took the source and target unit types as two
169 : // template arguments, there may be some confusion as to which is the
170 : // source and which is the target.
171 : template <class TypedMatrix>
172 752 : TypedMatrix ViewAs(const gfx::Matrix4x4& aMatrix) {
173 752 : return TypedMatrix::FromUnknownMatrix(aMatrix);
174 : }
175 :
176 : // Convenience functions for transforming an entity from one strongly-typed
177 : // coordinate system to another using the provided transformation matrix.
178 : template <typename TargetUnits, typename SourceUnits>
179 : static gfx::PointTyped<TargetUnits>
180 0 : TransformBy(const gfx::Matrix4x4Typed<SourceUnits, TargetUnits>& aTransform,
181 : const gfx::PointTyped<SourceUnits>& aPoint)
182 : {
183 0 : return aTransform.TransformPoint(aPoint);
184 : }
185 : template <typename TargetUnits, typename SourceUnits>
186 : static gfx::IntPointTyped<TargetUnits>
187 : TransformBy(const gfx::Matrix4x4Typed<SourceUnits, TargetUnits>& aTransform,
188 : const gfx::IntPointTyped<SourceUnits>& aPoint)
189 : {
190 : return RoundedToInt(TransformBy(aTransform, gfx::PointTyped<SourceUnits>(aPoint)));
191 : }
192 : template <typename TargetUnits, typename SourceUnits>
193 : static gfx::RectTyped<TargetUnits>
194 550 : TransformBy(const gfx::Matrix4x4Typed<SourceUnits, TargetUnits>& aTransform,
195 : const gfx::RectTyped<SourceUnits>& aRect)
196 : {
197 550 : return aTransform.TransformBounds(aRect);
198 : }
199 : template <typename TargetUnits, typename SourceUnits>
200 : static gfx::IntRectTyped<TargetUnits>
201 69 : TransformBy(const gfx::Matrix4x4Typed<SourceUnits, TargetUnits>& aTransform,
202 : const gfx::IntRectTyped<SourceUnits>& aRect)
203 : {
204 69 : return RoundedToInt(TransformBy(aTransform, gfx::RectTyped<SourceUnits>(aRect)));
205 : }
206 : template <typename TargetUnits, typename SourceUnits>
207 : static gfx::IntRegionTyped<TargetUnits>
208 121 : TransformBy(const gfx::Matrix4x4Typed<SourceUnits, TargetUnits>& aTransform,
209 : const gfx::IntRegionTyped<SourceUnits>& aRegion)
210 : {
211 242 : return ViewAs<TargetUnits>(aRegion.ToUnknownRegion().Transform(
212 242 : aTransform.ToUnknownMatrix()));
213 : }
214 :
215 : // Transform |aVector|, which is anchored at |aAnchor|, by the given transform
216 : // matrix, yielding a point in |TargetUnits|.
217 : // The anchor is necessary because with 3D tranforms, the location of the
218 : // vector can affect the result of the transform.
219 : template <typename TargetUnits, typename SourceUnits>
220 : static gfx::PointTyped<TargetUnits>
221 0 : TransformVector(const gfx::Matrix4x4Typed<SourceUnits, TargetUnits>& aTransform,
222 : const gfx::PointTyped<SourceUnits>& aVector,
223 : const gfx::PointTyped<SourceUnits>& aAnchor)
224 : {
225 0 : gfx::PointTyped<TargetUnits> transformedStart = TransformBy(aTransform, aAnchor);
226 0 : gfx::PointTyped<TargetUnits> transformedEnd = TransformBy(aTransform, aAnchor + aVector);
227 0 : return transformedEnd - transformedStart;
228 : }
229 :
230 : // UntransformBy() and UntransformVector() are like TransformBy() and
231 : // TransformVector(), respectively, but are intended for cases where
232 : // the transformation matrix is the inverse of a 3D projection. When
233 : // using such transforms, the resulting Point4D is only meaningful
234 : // if it has a positive w-coordinate. To handle this, these functions
235 : // return a Maybe object which contains a value if and only if the
236 : // result is meaningful
237 : template <typename TargetUnits, typename SourceUnits>
238 : static Maybe<gfx::PointTyped<TargetUnits>>
239 24 : UntransformBy(const gfx::Matrix4x4Typed<SourceUnits, TargetUnits>& aTransform,
240 : const gfx::PointTyped<SourceUnits>& aPoint)
241 : {
242 24 : gfx::Point4DTyped<TargetUnits> point = aTransform.ProjectPoint(aPoint);
243 24 : if (!point.HasPositiveWCoord()) {
244 0 : return Nothing();
245 : }
246 24 : return Some(point.As2DPoint());
247 : }
248 : template <typename TargetUnits, typename SourceUnits>
249 : static Maybe<gfx::IntPointTyped<TargetUnits>>
250 1 : UntransformBy(const gfx::Matrix4x4Typed<SourceUnits, TargetUnits>& aTransform,
251 : const gfx::IntPointTyped<SourceUnits>& aPoint)
252 : {
253 1 : gfx::PointTyped<SourceUnits> p = aPoint;
254 1 : gfx::Point4DTyped<TargetUnits> point = aTransform.ProjectPoint(p);
255 1 : if (!point.HasPositiveWCoord()) {
256 0 : return Nothing();
257 : }
258 1 : return Some(RoundedToInt(point.As2DPoint()));
259 : }
260 :
261 : // The versions of UntransformBy() that take a rectangle also take a clip,
262 : // which represents the bounds within which the target must fall. The
263 : // result of the transform is intersected with this clip, and is considered
264 : // meaningful if the intersection is not empty.
265 : template <typename TargetUnits, typename SourceUnits>
266 : static Maybe<gfx::RectTyped<TargetUnits>>
267 115 : UntransformBy(const gfx::Matrix4x4Typed<SourceUnits, TargetUnits>& aTransform,
268 : const gfx::RectTyped<SourceUnits>& aRect,
269 : const gfx::RectTyped<TargetUnits>& aClip)
270 : {
271 115 : gfx::RectTyped<TargetUnits> rect = aTransform.ProjectRectBounds(aRect, aClip);
272 115 : if (rect.IsEmpty()) {
273 11 : return Nothing();
274 : }
275 104 : return Some(rect);
276 : }
277 : template <typename TargetUnits, typename SourceUnits>
278 : static Maybe<gfx::IntRectTyped<TargetUnits>>
279 : UntransformBy(const gfx::Matrix4x4Typed<SourceUnits, TargetUnits>& aTransform,
280 : const gfx::IntRectTyped<SourceUnits>& aRect,
281 : const gfx::IntRectTyped<TargetUnits>& aClip)
282 : {
283 : gfx::RectTyped<TargetUnits> rect = aTransform.ProjectRectBounds(aRect, aClip);
284 : if (rect.IsEmpty()) {
285 : return Nothing();
286 : }
287 : return Some(RoundedToInt(rect));
288 : }
289 :
290 : template <typename TargetUnits, typename SourceUnits>
291 : static Maybe<gfx::PointTyped<TargetUnits>>
292 0 : UntransformVector(const gfx::Matrix4x4Typed<SourceUnits, TargetUnits>& aTransform,
293 : const gfx::PointTyped<SourceUnits>& aVector,
294 : const gfx::PointTyped<SourceUnits>& aAnchor)
295 : {
296 0 : gfx::Point4DTyped<TargetUnits> projectedAnchor = aTransform.ProjectPoint(aAnchor);
297 0 : gfx::Point4DTyped<TargetUnits> projectedTarget = aTransform.ProjectPoint(aAnchor + aVector);
298 0 : if (!projectedAnchor.HasPositiveWCoord() || !projectedTarget.HasPositiveWCoord()){
299 0 : return Nothing();
300 : }
301 0 : return Some(projectedTarget.As2DPoint() - projectedAnchor.As2DPoint());
302 : }
303 :
304 : } // namespace mozilla
305 :
306 : #endif
|