gfx/layers/FrameMetrics.h

branch
TOR_BUG_9701
changeset 8
97036ab72558
equal deleted inserted replaced
-1:000000000000 0:96dad3801e65
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 #ifndef GFX_FRAMEMETRICS_H
7 #define GFX_FRAMEMETRICS_H
8
9 #include <stdint.h> // for uint32_t, uint64_t
10 #include <string> // for std::string
11 #include "Units.h" // for CSSRect, CSSPixel, etc
12 #include "mozilla/gfx/BasePoint.h" // for BasePoint
13 #include "mozilla/gfx/Rect.h" // for RoundedIn
14 #include "mozilla/gfx/ScaleFactor.h" // for ScaleFactor
15 #include "mozilla/gfx/Logging.h" // for Log
16
17 namespace IPC {
18 template <typename T> struct ParamTraits;
19 } // namespace IPC
20
21 namespace mozilla {
22
23 // The layer coordinates of the parent layer.
24 // This can be arrived at in two ways:
25 // - Start with the CSS coordinates of the parent layer (note: NOT the
26 // CSS coordinates of the current layer, that will give you the wrong
27 // answer), multiply by the device scale and the resolutions of all
28 // layers from the root down to and including the parent.
29 // - Start with global screen coordinates and unapply all CSS and async
30 // transforms from the root down to and including the parent.
31 // It's helpful to look at https://wiki.mozilla.org/Platform/GFX/APZ#Coordinate_systems
32 // to get a picture of how the various coordinate systems relate to each other.
33 struct ParentLayerPixel {};
34
35 typedef gfx::PointTyped<ParentLayerPixel> ParentLayerPoint;
36 typedef gfx::RectTyped<ParentLayerPixel> ParentLayerRect;
37 typedef gfx::SizeTyped<ParentLayerPixel> ParentLayerSize;
38
39 typedef gfx::IntMarginTyped<ParentLayerPixel> ParentLayerIntMargin;
40 typedef gfx::IntPointTyped<ParentLayerPixel> ParentLayerIntPoint;
41 typedef gfx::IntRectTyped<ParentLayerPixel> ParentLayerIntRect;
42 typedef gfx::IntSizeTyped<ParentLayerPixel> ParentLayerIntSize;
43
44 typedef gfx::ScaleFactor<CSSPixel, ParentLayerPixel> CSSToParentLayerScale;
45 typedef gfx::ScaleFactor<LayoutDevicePixel, ParentLayerPixel> LayoutDeviceToParentLayerScale;
46 typedef gfx::ScaleFactor<ScreenPixel, ParentLayerPixel> ScreenToParentLayerScale;
47
48 typedef gfx::ScaleFactor<ParentLayerPixel, LayerPixel> ParentLayerToLayerScale;
49 typedef gfx::ScaleFactor<ParentLayerPixel, ScreenPixel> ParentLayerToScreenScale;
50
51
52 namespace layers {
53
54 /**
55 * The viewport and displayport metrics for the painted frame at the
56 * time of a layer-tree transaction. These metrics are especially
57 * useful for shadow layers, because the metrics values are updated
58 * atomically with new pixels.
59 */
60 struct FrameMetrics {
61 friend struct IPC::ParamTraits<mozilla::layers::FrameMetrics>;
62 public:
63 // We use IDs to identify frames across processes.
64 typedef uint64_t ViewID;
65 static const ViewID NULL_SCROLL_ID; // This container layer does not scroll.
66 static const ViewID START_SCROLL_ID = 2; // This is the ID that scrolling subframes
67 // will begin at.
68
69 FrameMetrics()
70 : mCompositionBounds(0, 0, 0, 0)
71 , mDisplayPort(0, 0, 0, 0)
72 , mCriticalDisplayPort(0, 0, 0, 0)
73 , mViewport(0, 0, 0, 0)
74 , mScrollableRect(0, 0, 0, 0)
75 , mResolution(1)
76 , mCumulativeResolution(1)
77 , mTransformScale(1)
78 , mDevPixelsPerCSSPixel(1)
79 , mPresShellId(-1)
80 , mMayHaveTouchListeners(false)
81 , mIsRoot(false)
82 , mHasScrollgrab(false)
83 , mScrollId(NULL_SCROLL_ID)
84 , mScrollOffset(0, 0)
85 , mZoom(1)
86 , mUpdateScrollOffset(false)
87 , mScrollGeneration(0)
88 , mRootCompositionSize(0, 0)
89 , mDisplayPortMargins(0, 0, 0, 0)
90 , mUseDisplayPortMargins(false)
91 {}
92
93 // Default copy ctor and operator= are fine
94
95 bool operator==(const FrameMetrics& aOther) const
96 {
97 // mContentDescription is not compared on purpose as it's only used
98 // for debugging.
99 return mCompositionBounds.IsEqualEdges(aOther.mCompositionBounds) &&
100 mRootCompositionSize == aOther.mRootCompositionSize &&
101 mDisplayPort.IsEqualEdges(aOther.mDisplayPort) &&
102 mDisplayPortMargins == aOther.mDisplayPortMargins &&
103 mUseDisplayPortMargins == aOther.mUseDisplayPortMargins &&
104 mCriticalDisplayPort.IsEqualEdges(aOther.mCriticalDisplayPort) &&
105 mViewport.IsEqualEdges(aOther.mViewport) &&
106 mScrollableRect.IsEqualEdges(aOther.mScrollableRect) &&
107 mResolution == aOther.mResolution &&
108 mCumulativeResolution == aOther.mCumulativeResolution &&
109 mDevPixelsPerCSSPixel == aOther.mDevPixelsPerCSSPixel &&
110 mMayHaveTouchListeners == aOther.mMayHaveTouchListeners &&
111 mPresShellId == aOther.mPresShellId &&
112 mIsRoot == aOther.mIsRoot &&
113 mScrollId == aOther.mScrollId &&
114 mScrollOffset == aOther.mScrollOffset &&
115 mHasScrollgrab == aOther.mHasScrollgrab &&
116 mUpdateScrollOffset == aOther.mUpdateScrollOffset;
117 }
118 bool operator!=(const FrameMetrics& aOther) const
119 {
120 return !operator==(aOther);
121 }
122
123 bool IsDefault() const
124 {
125 FrameMetrics def;
126
127 def.mPresShellId = mPresShellId;
128 return (def == *this);
129 }
130
131 bool IsRootScrollable() const
132 {
133 return mIsRoot;
134 }
135
136 bool IsScrollable() const
137 {
138 return mScrollId != NULL_SCROLL_ID;
139 }
140
141 CSSToLayerScale LayersPixelsPerCSSPixel() const
142 {
143 return mCumulativeResolution * mDevPixelsPerCSSPixel;
144 }
145
146 LayerPoint GetScrollOffsetInLayerPixels() const
147 {
148 return GetScrollOffset() * LayersPixelsPerCSSPixel();
149 }
150
151 LayoutDeviceToParentLayerScale GetParentResolution() const
152 {
153 return mCumulativeResolution / mResolution;
154 }
155
156 // Ensure the scrollableRect is at least as big as the compositionBounds
157 // because the scrollableRect can be smaller if the content is not large
158 // and the scrollableRect hasn't been updated yet.
159 // We move the scrollableRect up because we don't know if we can move it
160 // down. i.e. we know that scrollableRect can go back as far as zero.
161 // but we don't know how much further ahead it can go.
162 CSSRect GetExpandedScrollableRect() const
163 {
164 CSSRect scrollableRect = mScrollableRect;
165 CSSSize compSize = CalculateCompositedSizeInCssPixels();
166 if (scrollableRect.width < compSize.width) {
167 scrollableRect.x = std::max(0.f,
168 scrollableRect.x - (compSize.width - scrollableRect.width));
169 scrollableRect.width = compSize.width;
170 }
171
172 if (scrollableRect.height < compSize.height) {
173 scrollableRect.y = std::max(0.f,
174 scrollableRect.y - (compSize.height - scrollableRect.height));
175 scrollableRect.height = compSize.height;
176 }
177
178 return scrollableRect;
179 }
180
181 // Return the scale factor needed to fit the viewport
182 // into its composition bounds.
183 CSSToScreenScale CalculateIntrinsicScale() const
184 {
185 return CSSToScreenScale(float(mCompositionBounds.width) / float(mViewport.width));
186 }
187
188 // Return the scale factor for converting from CSS pixels (for this layer)
189 // to layer pixels of our parent layer. Much as mZoom is used to interface
190 // between inputs we get in screen pixels and quantities in CSS pixels,
191 // this is used to interface between mCompositionBounds and quantities
192 // in CSS pixels.
193 CSSToParentLayerScale GetZoomToParent() const
194 {
195 return mZoom * mTransformScale;
196 }
197
198 CSSSize CalculateCompositedSizeInCssPixels() const
199 {
200 return mCompositionBounds.Size() / GetZoomToParent();
201 }
202
203 CSSRect CalculateCompositedRectInCssPixels() const
204 {
205 return mCompositionBounds / GetZoomToParent();
206 }
207
208 void ScrollBy(const CSSPoint& aPoint)
209 {
210 mScrollOffset += aPoint;
211 }
212
213 void ZoomBy(float aFactor)
214 {
215 mZoom.scale *= aFactor;
216 }
217
218 void CopyScrollInfoFrom(const FrameMetrics& aOther)
219 {
220 mScrollOffset = aOther.mScrollOffset;
221 mScrollGeneration = aOther.mScrollGeneration;
222 }
223
224 // ---------------------------------------------------------------------------
225 // The following metrics are all in widget space/device pixels.
226 //
227
228 // This is the area within the widget that we're compositing to. It is relative
229 // to the layer tree origin.
230 //
231 // This is useful because, on mobile, the viewport and composition dimensions
232 // are not always the same. In this case, we calculate the displayport using
233 // an area bigger than the region we're compositing to. If we used the
234 // viewport dimensions to calculate the displayport, we'd run into situations
235 // where we're prerendering the wrong regions and the content may be clipped,
236 // or too much of it prerendered. If the composition dimensions are the same as the
237 // viewport dimensions, there is no need for this and we can just use the viewport
238 // instead.
239 //
240 // This value is valid for nested scrollable layers as well, and is still
241 // relative to the layer tree origin. This value is provided by Gecko at
242 // layout/paint time.
243 ParentLayerIntRect mCompositionBounds;
244
245 // ---------------------------------------------------------------------------
246 // The following metrics are all in CSS pixels. They are not in any uniform
247 // space, so each is explained separately.
248 //
249
250 // The area of a frame's contents that has been painted, relative to the
251 // viewport. It is in the same coordinate space as |mViewport|. For example,
252 // if it is at 0,0, then it's at the same place at the viewport, which is at
253 // the top-left in the layer, and at the same place as the scroll offset of
254 // the document.
255 //
256 // Note that this is structured in such a way that it doesn't depend on the
257 // method layout uses to scroll content.
258 //
259 // May be larger or smaller than |mScrollableRect|.
260 //
261 // To pre-render a margin of 100 CSS pixels around the window,
262 // { x = -100, y = - 100,
263 // width = window.innerWidth + 200, height = window.innerHeight + 200 }
264 CSSRect mDisplayPort;
265
266 // If non-empty, the area of a frame's contents that is considered critical
267 // to paint. Area outside of this area (i.e. area inside mDisplayPort, but
268 // outside of mCriticalDisplayPort) is considered low-priority, and may be
269 // painted with lower precision, or not painted at all.
270 //
271 // The same restrictions for mDisplayPort apply here.
272 CSSRect mCriticalDisplayPort;
273
274 // The CSS viewport, which is the dimensions we're using to constrain the
275 // <html> element of this frame, relative to the top-left of the layer. Note
276 // that its offset is structured in such a way that it doesn't depend on the
277 // method layout uses to scroll content.
278 //
279 // This is mainly useful on the root layer, however nested iframes can have
280 // their own viewport, which will just be the size of the window of the
281 // iframe. For layers that don't correspond to a document, this metric is
282 // meaningless and invalid.
283 CSSRect mViewport;
284
285 // The scrollable bounds of a frame. This is determined by reflow.
286 // Ordinarily the x and y will be 0 and the width and height will be the
287 // size of the element being scrolled. However for RTL pages or elements
288 // the x value may be negative.
289 //
290 // This is relative to the document. It is in the same coordinate space as
291 // |mScrollOffset|, but a different coordinate space than |mViewport| and
292 // |mDisplayPort|. Note also that this coordinate system is understood by
293 // window.scrollTo().
294 //
295 // This is valid on any layer unless it has no content.
296 CSSRect mScrollableRect;
297
298 // ---------------------------------------------------------------------------
299 // The following metrics are dimensionless.
300 //
301
302 // The incremental resolution that the current frame has been painted at
303 // relative to the parent frame's resolution. This information is provided
304 // by Gecko at layout/paint time.
305 ParentLayerToLayerScale mResolution;
306
307 // The cumulative resolution that the current frame has been painted at.
308 // This is the product of our mResolution and the mResolutions of our parent frames.
309 // This information is provided by Gecko at layout/paint time.
310 LayoutDeviceToLayerScale mCumulativeResolution;
311
312 // The conversion factor between local screen pixels (the coordinate
313 // system in which APZCs receive input events) and our parent layer's
314 // layer pixels (the coordinate system of mCompositionBounds).
315 // This consists of the scale of the local CSS transform and the
316 // nontransient async transform.
317 // TODO: APZ does not currently work well if there is a CSS transform
318 // on the layer being scrolled that's not just a scale that's
319 // the same in both directions. When we fix this, mTransformScale
320 // will probably need to turn into a matrix.
321 ScreenToParentLayerScale mTransformScale;
322
323 // The conversion factor between CSS pixels and device pixels for this frame.
324 // This can vary based on a variety of things, such as reflowing-zoom. The
325 // conversion factor for device pixels to layers pixels is just the
326 // resolution.
327 CSSToLayoutDeviceScale mDevPixelsPerCSSPixel;
328
329 uint32_t mPresShellId;
330
331 // Whether or not this frame may have touch listeners.
332 bool mMayHaveTouchListeners;
333
334 // Whether or not this is the root scroll frame for the root content document.
335 bool mIsRoot;
336
337 // Whether or not this frame is for an element marked 'scrollgrab'.
338 bool mHasScrollgrab;
339
340 public:
341 void SetScrollOffset(const CSSPoint& aScrollOffset)
342 {
343 mScrollOffset = aScrollOffset;
344 }
345
346 const CSSPoint& GetScrollOffset() const
347 {
348 return mScrollOffset;
349 }
350
351 void SetZoom(const CSSToScreenScale& aZoom)
352 {
353 mZoom = aZoom;
354 }
355
356 CSSToScreenScale GetZoom() const
357 {
358 return mZoom;
359 }
360
361 void SetScrollOffsetUpdated(uint32_t aScrollGeneration)
362 {
363 mUpdateScrollOffset = true;
364 mScrollGeneration = aScrollGeneration;
365 }
366
367 bool GetScrollOffsetUpdated() const
368 {
369 return mUpdateScrollOffset;
370 }
371
372 uint32_t GetScrollGeneration() const
373 {
374 return mScrollGeneration;
375 }
376
377 const std::string& GetContentDescription() const
378 {
379 return mContentDescription;
380 }
381
382 void SetContentDescription(const std::string& aContentDescription)
383 {
384 mContentDescription = aContentDescription;
385 }
386
387 ViewID GetScrollId() const
388 {
389 return mScrollId;
390 }
391
392 void SetScrollId(ViewID scrollId)
393 {
394 mScrollId = scrollId;
395 }
396
397 void SetRootCompositionSize(const CSSSize& aRootCompositionSize)
398 {
399 mRootCompositionSize = aRootCompositionSize;
400 }
401
402 const CSSSize& GetRootCompositionSize() const
403 {
404 return mRootCompositionSize;
405 }
406
407 void SetDisplayPortMargins(const LayerMargin& aDisplayPortMargins)
408 {
409 mDisplayPortMargins = aDisplayPortMargins;
410 }
411
412 const LayerMargin& GetDisplayPortMargins() const
413 {
414 return mDisplayPortMargins;
415 }
416
417 void SetUseDisplayPortMargins()
418 {
419 mUseDisplayPortMargins = true;
420 }
421
422 bool GetUseDisplayPortMargins() const
423 {
424 return mUseDisplayPortMargins;
425 }
426
427 private:
428 // New fields from now on should be made private and old fields should
429 // be refactored to be private.
430
431 // A unique ID assigned to each scrollable frame.
432 ViewID mScrollId;
433
434 // The position of the top-left of the CSS viewport, relative to the document
435 // (or the document relative to the viewport, if that helps understand it).
436 //
437 // Thus it is relative to the document. It is in the same coordinate space as
438 // |mScrollableRect|, but a different coordinate space than |mViewport| and
439 // |mDisplayPort|.
440 //
441 // It is required that the rect:
442 // { x = mScrollOffset.x, y = mScrollOffset.y,
443 // width = mCompositionBounds.x / mResolution.scale,
444 // height = mCompositionBounds.y / mResolution.scale }
445 // Be within |mScrollableRect|.
446 //
447 // This is valid for any layer, but is always relative to this frame and
448 // not any parents, regardless of parent transforms.
449 CSSPoint mScrollOffset;
450
451 // The "user zoom". Content is painted by gecko at mResolution * mDevPixelsPerCSSPixel,
452 // but will be drawn to the screen at mZoom. In the steady state, the
453 // two will be the same, but during an async zoom action the two may
454 // diverge. This information is initialized in Gecko but updated in the APZC.
455 CSSToScreenScale mZoom;
456
457 // Whether mScrollOffset was updated by something other than the APZ code, and
458 // if the APZC receiving this metrics should update its local copy.
459 bool mUpdateScrollOffset;
460 // The scroll generation counter used to acknowledge the scroll offset update.
461 uint32_t mScrollGeneration;
462
463 // A description of the content element corresponding to this frame.
464 // This is empty unless the apz.printtree pref is turned on.
465 std::string mContentDescription;
466
467 // The size of the root scrollable's composition bounds, but in local CSS pixels.
468 CSSSize mRootCompositionSize;
469
470 // A display port expressed as layer margins that apply to the rect of what
471 // is drawn of the scrollable element.
472 LayerMargin mDisplayPortMargins;
473
474 // If this is true then we use the display port margins on this metrics,
475 // otherwise use the display port rect.
476 bool mUseDisplayPortMargins;
477 };
478
479 /**
480 * This class allows us to uniquely identify a scrollable layer. The
481 * mLayersId identifies the layer tree (corresponding to a child process
482 * and/or tab) that the scrollable layer belongs to. The mPresShellId
483 * is a temporal identifier (corresponding to the document loaded that
484 * contains the scrollable layer, which may change over time). The
485 * mScrollId corresponds to the actual frame that is scrollable.
486 */
487 struct ScrollableLayerGuid {
488 uint64_t mLayersId;
489 uint32_t mPresShellId;
490 FrameMetrics::ViewID mScrollId;
491
492 ScrollableLayerGuid()
493 : mLayersId(0)
494 , mPresShellId(0)
495 , mScrollId(0)
496 {
497 MOZ_COUNT_CTOR(ScrollableLayerGuid);
498 }
499
500 ScrollableLayerGuid(uint64_t aLayersId, uint32_t aPresShellId,
501 FrameMetrics::ViewID aScrollId)
502 : mLayersId(aLayersId)
503 , mPresShellId(aPresShellId)
504 , mScrollId(aScrollId)
505 {
506 MOZ_COUNT_CTOR(ScrollableLayerGuid);
507 }
508
509 ScrollableLayerGuid(uint64_t aLayersId, const FrameMetrics& aMetrics)
510 : mLayersId(aLayersId)
511 , mPresShellId(aMetrics.mPresShellId)
512 , mScrollId(aMetrics.GetScrollId())
513 {
514 MOZ_COUNT_CTOR(ScrollableLayerGuid);
515 }
516
517 ~ScrollableLayerGuid()
518 {
519 MOZ_COUNT_DTOR(ScrollableLayerGuid);
520 }
521
522 bool operator==(const ScrollableLayerGuid& other) const
523 {
524 return mLayersId == other.mLayersId
525 && mPresShellId == other.mPresShellId
526 && mScrollId == other.mScrollId;
527 }
528
529 bool operator!=(const ScrollableLayerGuid& other) const
530 {
531 return !(*this == other);
532 }
533 };
534
535 template <int LogLevel>
536 gfx::Log<LogLevel>& operator<<(gfx::Log<LogLevel>& log, const ScrollableLayerGuid& aGuid) {
537 return log << '(' << aGuid.mLayersId << ',' << aGuid.mPresShellId << ',' << aGuid.mScrollId << ')';
538 }
539
540 struct ZoomConstraints {
541 bool mAllowZoom;
542 bool mAllowDoubleTapZoom;
543 CSSToScreenScale mMinZoom;
544 CSSToScreenScale mMaxZoom;
545
546 ZoomConstraints()
547 : mAllowZoom(true)
548 , mAllowDoubleTapZoom(true)
549 {
550 MOZ_COUNT_CTOR(ZoomConstraints);
551 }
552
553 ZoomConstraints(bool aAllowZoom,
554 bool aAllowDoubleTapZoom,
555 const CSSToScreenScale& aMinZoom,
556 const CSSToScreenScale& aMaxZoom)
557 : mAllowZoom(aAllowZoom)
558 , mAllowDoubleTapZoom(aAllowDoubleTapZoom)
559 , mMinZoom(aMinZoom)
560 , mMaxZoom(aMaxZoom)
561 {
562 MOZ_COUNT_CTOR(ZoomConstraints);
563 }
564
565 ~ZoomConstraints()
566 {
567 MOZ_COUNT_DTOR(ZoomConstraints);
568 }
569
570 bool operator==(const ZoomConstraints& other) const
571 {
572 return mAllowZoom == other.mAllowZoom
573 && mAllowDoubleTapZoom == other.mAllowDoubleTapZoom
574 && mMinZoom == other.mMinZoom
575 && mMaxZoom == other.mMaxZoom;
576 }
577
578 bool operator!=(const ZoomConstraints& other) const
579 {
580 return !(*this == other);
581 }
582 };
583
584 }
585 }
586
587 #endif /* GFX_FRAMEMETRICS_H */

mercurial