Source code

Revision control

Other Tools

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 GFX_FRAMEMETRICS_H
8
#define GFX_FRAMEMETRICS_H
9
10
#include <stdint.h> // for uint8_t, uint32_t, uint64_t
11
#include "Units.h" // for CSSRect, CSSPixel, etc
12
#include "mozilla/DefineEnum.h" // for MOZ_DEFINE_ENUM
13
#include "mozilla/HashFunctions.h" // for HashGeneric
14
#include "mozilla/Maybe.h"
15
#include "mozilla/gfx/BasePoint.h" // for BasePoint
16
#include "mozilla/gfx/Rect.h" // for RoundedIn
17
#include "mozilla/gfx/ScaleFactor.h" // for ScaleFactor
18
#include "mozilla/gfx/Logging.h" // for Log
19
#include "mozilla/layers/LayersTypes.h" // for ScrollDirection
20
#include "mozilla/layers/ScrollableLayerGuid.h" // for ScrollableLayerGuid
21
#include "mozilla/StaticPtr.h" // for StaticAutoPtr
22
#include "mozilla/TimeStamp.h" // for TimeStamp
23
#include "nsDataHashtable.h" // for nsDataHashtable
24
#include "nsString.h"
25
#include "PLDHashTable.h" // for PLDHashNumber
26
27
struct nsStyleDisplay;
28
namespace mozilla {
29
enum class StyleScrollSnapStrictness : uint8_t;
30
enum class StyleOverscrollBehavior : uint8_t;
31
class WritingMode;
32
} // namespace mozilla
33
34
namespace IPC {
35
template <typename T>
36
struct ParamTraits;
37
} // namespace IPC
38
39
namespace mozilla {
40
namespace layers {
41
42
/**
43
* Helper struct to hold a couple of fields that can be updated as part of
44
* an empty transaction.
45
*/
46
struct ScrollUpdateInfo {
47
uint32_t mScrollGeneration;
48
CSSPoint mScrollOffset;
49
CSSPoint mBaseScrollOffset;
50
bool mIsRelative;
51
};
52
53
/**
54
* Metrics about a scroll frame that are sent to the compositor and used
55
* by APZ.
56
*
57
* This is used for two main purposes:
58
*
59
* (1) Sending information about a scroll frame to the compositor and APZ
60
* as part of a layers or WebRender transaction.
61
* (2) Storing information about a scroll frame in APZ that persists
62
* between transactions.
63
*
64
* TODO: Separate these two uses into two distinct structures.
65
*
66
* A related class, RepaintRequest, is used for sending information about a
67
* scroll frame back from the compositor to the main thread when requesting
68
* a repaint of the scroll frame's contents.
69
*/
70
struct FrameMetrics {
71
friend struct IPC::ParamTraits<mozilla::layers::FrameMetrics>;
72
73
typedef ScrollableLayerGuid::ViewID ViewID;
74
75
public:
76
// clang-format off
77
MOZ_DEFINE_ENUM_WITH_BASE_AT_CLASS_SCOPE(
78
ScrollOffsetUpdateType, uint8_t, (
79
eNone, // The default; the scroll offset was not updated
80
eMainThread, // The scroll offset was updated by the main thread.
81
ePending, // The scroll offset was updated on the main thread, but
82
// not painted, so the layer texture data is still at the
83
// old offset.
84
eRestore // The scroll offset was updated by the main thread, but
85
// as a restore from history or after a frame
86
// reconstruction. In this case, APZ can ignore the
87
// offset change if the user has done an APZ scroll
88
// already.
89
));
90
// clang-format on
91
92
FrameMetrics()
93
: mScrollId(ScrollableLayerGuid::NULL_SCROLL_ID),
94
mPresShellResolution(1),
95
mCompositionBounds(0, 0, 0, 0),
96
mDisplayPort(0, 0, 0, 0),
97
mCriticalDisplayPort(0, 0, 0, 0),
98
mScrollableRect(0, 0, 0, 0),
99
mCumulativeResolution(),
100
mDevPixelsPerCSSPixel(1),
101
mScrollOffset(0, 0),
102
mBaseScrollOffset(0, 0),
103
mZoom(),
104
mScrollGeneration(0),
105
mSmoothScrollOffset(0, 0),
106
mRootCompositionSize(0, 0),
107
mDisplayPortMargins(0, 0, 0, 0),
108
mPresShellId(-1),
109
mLayoutViewport(0, 0, 0, 0),
110
mExtraResolution(),
111
mPaintRequestTime(),
112
mScrollUpdateType(eNone),
113
mVisualViewportOffset(0, 0),
114
mVisualScrollUpdateType(eNone),
115
mIsRootContent(false),
116
mIsRelative(false),
117
mDoSmoothScroll(false),
118
mIsScrollInfoLayer(false) {}
119
120
// Default copy ctor and operator= are fine
121
122
bool operator==(const FrameMetrics& aOther) const {
123
// Put mScrollId at the top since it's the most likely one to fail.
124
return mScrollId == aOther.mScrollId &&
125
mPresShellResolution == aOther.mPresShellResolution &&
126
mCompositionBounds.IsEqualEdges(aOther.mCompositionBounds) &&
127
mDisplayPort.IsEqualEdges(aOther.mDisplayPort) &&
128
mCriticalDisplayPort.IsEqualEdges(aOther.mCriticalDisplayPort) &&
129
mScrollableRect.IsEqualEdges(aOther.mScrollableRect) &&
130
mCumulativeResolution == aOther.mCumulativeResolution &&
131
mDevPixelsPerCSSPixel == aOther.mDevPixelsPerCSSPixel &&
132
mScrollOffset == aOther.mScrollOffset &&
133
mBaseScrollOffset == aOther.mBaseScrollOffset &&
134
// don't compare mZoom
135
mScrollGeneration == aOther.mScrollGeneration &&
136
mSmoothScrollOffset == aOther.mSmoothScrollOffset &&
137
mRootCompositionSize == aOther.mRootCompositionSize &&
138
mDisplayPortMargins == aOther.mDisplayPortMargins &&
139
mPresShellId == aOther.mPresShellId &&
140
mLayoutViewport.IsEqualEdges(aOther.mLayoutViewport) &&
141
mExtraResolution == aOther.mExtraResolution &&
142
mPaintRequestTime == aOther.mPaintRequestTime &&
143
mScrollUpdateType == aOther.mScrollUpdateType &&
144
mVisualViewportOffset == aOther.mVisualViewportOffset &&
145
mVisualScrollUpdateType == aOther.mVisualScrollUpdateType &&
146
mIsRootContent == aOther.mIsRootContent &&
147
mIsRelative == aOther.mIsRelative &&
148
mDoSmoothScroll == aOther.mDoSmoothScroll &&
149
mIsScrollInfoLayer == aOther.mIsScrollInfoLayer &&
150
mFixedLayerMargins == aOther.mFixedLayerMargins;
151
}
152
153
bool operator!=(const FrameMetrics& aOther) const {
154
return !operator==(aOther);
155
}
156
157
bool IsScrollable() const {
158
return mScrollId != ScrollableLayerGuid::NULL_SCROLL_ID;
159
}
160
161
CSSToScreenScale2D DisplayportPixelsPerCSSPixel() const {
162
// Note: use 'mZoom * ParentLayerToLayerScale(1.0f)' as the CSS-to-Layer
163
// scale instead of LayersPixelsPerCSSPixel(), because displayport
164
// calculations are done in the context of a repaint request, where we ask
165
// Layout to repaint at a new resolution that includes any async zoom. Until
166
// this repaint request is processed, LayersPixelsPerCSSPixel() does not yet
167
// include the async zoom, but it will when the displayport is interpreted
168
// for the repaint.
169
return mZoom * ParentLayerToLayerScale(1.0f) / mExtraResolution;
170
}
171
172
CSSToLayerScale2D LayersPixelsPerCSSPixel() const {
173
return mDevPixelsPerCSSPixel * mCumulativeResolution;
174
}
175
176
// Get the amount by which this frame has been zoomed since the last repaint.
177
LayerToParentLayerScale GetAsyncZoom() const {
178
// The async portion of the zoom should be the same along the x and y
179
// axes.
180
return (mZoom / LayersPixelsPerCSSPixel()).ToScaleFactor();
181
}
182
183
// Ensure the scrollableRect is at least as big as the compositionBounds
184
// because the scrollableRect can be smaller if the content is not large
185
// and the scrollableRect hasn't been updated yet.
186
// We move the scrollableRect up because we don't know if we can move it
187
// down. i.e. we know that scrollableRect can go back as far as zero.
188
// but we don't know how much further ahead it can go.
189
CSSRect GetExpandedScrollableRect() const {
190
CSSRect scrollableRect = mScrollableRect;
191
CSSSize compSize = CalculateCompositedSizeInCssPixels();
192
if (scrollableRect.Width() < compSize.width) {
193
scrollableRect.SetRectX(
194
std::max(0.f, scrollableRect.X() -
195
(compSize.width - scrollableRect.Width())),
196
compSize.width);
197
}
198
199
if (scrollableRect.Height() < compSize.height) {
200
scrollableRect.SetRectY(
201
std::max(0.f, scrollableRect.Y() -
202
(compSize.height - scrollableRect.Height())),
203
compSize.height);
204
}
205
206
return scrollableRect;
207
}
208
209
CSSSize CalculateCompositedSizeInCssPixels() const {
210
if (GetZoom() == CSSToParentLayerScale2D(0, 0)) {
211
return CSSSize(); // avoid division by zero
212
}
213
return mCompositionBounds.Size() / GetZoom();
214
}
215
216
/*
217
* Calculate the composition bounds of this frame in the CSS pixels of
218
* the content surrounding the scroll frame. (This can be thought of as
219
* "parent CSS" pixels).
220
* Note that it does not make sense to ask for the composition bounds in the
221
* CSS pixels of the scrolled content (that is, regular CSS pixels),
222
* because the origin of the composition bounds is not meaningful in that
223
* coordinate space. (The size is, use CalculateCompositedSizeInCssPixels()
224
* for that.)
225
*/
226
CSSRect CalculateCompositionBoundsInCssPixelsOfSurroundingContent() const {
227
if (GetZoom() == CSSToParentLayerScale2D(0, 0)) {
228
return CSSRect(); // avoid division by zero
229
}
230
// The CSS pixels of the scrolled content and the CSS pixels of the
231
// surrounding content only differ if the scrolled content is rendered
232
// at a higher resolution, and the difference is the resolution.
233
return mCompositionBounds / GetZoom() * CSSToCSSScale{mPresShellResolution};
234
}
235
236
CSSSize CalculateBoundedCompositedSizeInCssPixels() const {
237
CSSSize size = CalculateCompositedSizeInCssPixels();
238
size.width = std::min(size.width, mRootCompositionSize.width);
239
size.height = std::min(size.height, mRootCompositionSize.height);
240
return size;
241
}
242
243
CSSRect CalculateScrollRange() const {
244
CSSSize scrollPortSize = CalculateCompositedSizeInCssPixels();
245
CSSRect scrollRange = mScrollableRect;
246
scrollRange.SetWidth(
247
std::max(scrollRange.Width() - scrollPortSize.width, 0.0f));
248
scrollRange.SetHeight(
249
std::max(scrollRange.Height() - scrollPortSize.height, 0.0f));
250
return scrollRange;
251
}
252
253
void ScrollBy(const CSSPoint& aPoint) { mScrollOffset += aPoint; }
254
255
void ZoomBy(float aScale) { ZoomBy(gfxSize(aScale, aScale)); }
256
257
void ZoomBy(const gfxSize& aScale) {
258
mZoom.xScale *= aScale.width;
259
mZoom.yScale *= aScale.height;
260
}
261
262
/*
263
* Compares an APZ frame metrics with an incoming content frame metrics
264
* to see if APZ has a scroll offset that has not been incorporated into
265
* the content frame metrics.
266
*/
267
bool HasPendingScroll(const FrameMetrics& aContentFrameMetrics) const {
268
return mScrollOffset != aContentFrameMetrics.mBaseScrollOffset;
269
}
270
271
void ApplyScrollUpdateFrom(const FrameMetrics& aOther) {
272
mScrollOffset = aOther.mScrollOffset;
273
mScrollGeneration = aOther.mScrollGeneration;
274
}
275
276
void ApplySmoothScrollUpdateFrom(const FrameMetrics& aOther) {
277
mSmoothScrollOffset = aOther.mSmoothScrollOffset;
278
mScrollGeneration = aOther.mScrollGeneration;
279
mDoSmoothScroll = aOther.mDoSmoothScroll;
280
}
281
282
/**
283
* Applies the relative scroll offset update contained in aOther to the
284
* scroll offset contained in this. The scroll delta is clamped to the
285
* scrollable region.
286
*
287
* @returns The clamped scroll offset delta that was applied
288
*/
289
CSSPoint ApplyRelativeScrollUpdateFrom(const FrameMetrics& aOther) {
290
MOZ_ASSERT(aOther.IsRelative());
291
CSSPoint origin = mScrollOffset;
292
CSSPoint delta = (aOther.mScrollOffset - aOther.mBaseScrollOffset);
293
ClampAndSetScrollOffset(mScrollOffset + delta);
294
mScrollGeneration = aOther.mScrollGeneration;
295
return mScrollOffset - origin;
296
}
297
298
/**
299
* Applies the relative scroll offset update contained in aOther to the
300
* smooth scroll destination offset contained in this. The scroll delta is
301
* clamped to the scrollable region.
302
*/
303
void ApplyRelativeSmoothScrollUpdateFrom(const FrameMetrics& aOther) {
304
MOZ_ASSERT(aOther.IsRelative());
305
CSSPoint delta = (aOther.mSmoothScrollOffset - aOther.mBaseScrollOffset);
306
ClampAndSetSmoothScrollOffset(mScrollOffset + delta);
307
mScrollGeneration = aOther.mScrollGeneration;
308
mDoSmoothScroll = aOther.mDoSmoothScroll;
309
}
310
311
void UpdatePendingScrollInfo(const ScrollUpdateInfo& aInfo) {
312
mScrollOffset = aInfo.mScrollOffset;
313
mBaseScrollOffset = aInfo.mBaseScrollOffset;
314
mScrollGeneration = aInfo.mScrollGeneration;
315
mScrollUpdateType = ePending;
316
mIsRelative = aInfo.mIsRelative;
317
}
318
319
public:
320
void SetPresShellResolution(float aPresShellResolution) {
321
mPresShellResolution = aPresShellResolution;
322
}
323
324
float GetPresShellResolution() const { return mPresShellResolution; }
325
326
void SetCompositionBounds(const ParentLayerRect& aCompositionBounds) {
327
mCompositionBounds = aCompositionBounds;
328
}
329
330
const ParentLayerRect& GetCompositionBounds() const {
331
return mCompositionBounds;
332
}
333
334
void SetDisplayPort(const CSSRect& aDisplayPort) {
335
mDisplayPort = aDisplayPort;
336
}
337
338
const CSSRect& GetDisplayPort() const { return mDisplayPort; }
339
340
void SetCriticalDisplayPort(const CSSRect& aCriticalDisplayPort) {
341
mCriticalDisplayPort = aCriticalDisplayPort;
342
}
343
344
const CSSRect& GetCriticalDisplayPort() const { return mCriticalDisplayPort; }
345
346
void SetCumulativeResolution(
347
const LayoutDeviceToLayerScale2D& aCumulativeResolution) {
348
mCumulativeResolution = aCumulativeResolution;
349
}
350
351
const LayoutDeviceToLayerScale2D& GetCumulativeResolution() const {
352
return mCumulativeResolution;
353
}
354
355
void SetDevPixelsPerCSSPixel(
356
const CSSToLayoutDeviceScale& aDevPixelsPerCSSPixel) {
357
mDevPixelsPerCSSPixel = aDevPixelsPerCSSPixel;
358
}
359
360
const CSSToLayoutDeviceScale& GetDevPixelsPerCSSPixel() const {
361
return mDevPixelsPerCSSPixel;
362
}
363
364
void SetIsRootContent(bool aIsRootContent) {
365
mIsRootContent = aIsRootContent;
366
}
367
368
bool IsRootContent() const { return mIsRootContent; }
369
370
void SetScrollOffset(const CSSPoint& aScrollOffset) {
371
mScrollOffset = aScrollOffset;
372
}
373
374
void SetBaseScrollOffset(const CSSPoint& aScrollOffset) {
375
mBaseScrollOffset = aScrollOffset;
376
}
377
378
// Set scroll offset, first clamping to the scroll range.
379
void ClampAndSetScrollOffset(const CSSPoint& aScrollOffset) {
380
SetScrollOffset(CalculateScrollRange().ClampPoint(aScrollOffset));
381
}
382
383
const CSSPoint& GetScrollOffset() const { return mScrollOffset; }
384
385
const CSSPoint& GetBaseScrollOffset() const { return mBaseScrollOffset; }
386
387
void SetSmoothScrollOffset(const CSSPoint& aSmoothScrollDestination) {
388
mSmoothScrollOffset = aSmoothScrollDestination;
389
}
390
391
void ClampAndSetSmoothScrollOffset(const CSSPoint& aSmoothScrollOffset) {
392
SetSmoothScrollOffset(
393
CalculateScrollRange().ClampPoint(aSmoothScrollOffset));
394
}
395
396
const CSSPoint& GetSmoothScrollOffset() const { return mSmoothScrollOffset; }
397
398
void SetZoom(const CSSToParentLayerScale2D& aZoom) { mZoom = aZoom; }
399
400
const CSSToParentLayerScale2D& GetZoom() const { return mZoom; }
401
402
void SetScrollGeneration(uint32_t aScrollGeneration) {
403
mScrollGeneration = aScrollGeneration;
404
}
405
406
void SetScrollOffsetUpdateType(ScrollOffsetUpdateType aScrollUpdateType) {
407
mScrollUpdateType = aScrollUpdateType;
408
}
409
410
void SetSmoothScrollOffsetUpdated(int32_t aScrollGeneration) {
411
mDoSmoothScroll = true;
412
mScrollGeneration = aScrollGeneration;
413
}
414
415
ScrollOffsetUpdateType GetScrollUpdateType() const {
416
return mScrollUpdateType;
417
}
418
419
bool GetScrollOffsetUpdated() const { return mScrollUpdateType != eNone; }
420
421
void SetIsRelative(bool aIsRelative) { mIsRelative = aIsRelative; }
422
423
bool IsRelative() const { return mIsRelative; }
424
425
bool GetDoSmoothScroll() const { return mDoSmoothScroll; }
426
427
uint32_t GetScrollGeneration() const { return mScrollGeneration; }
428
429
ViewID GetScrollId() const { return mScrollId; }
430
431
void SetScrollId(ViewID scrollId) { mScrollId = scrollId; }
432
433
void SetRootCompositionSize(const CSSSize& aRootCompositionSize) {
434
mRootCompositionSize = aRootCompositionSize;
435
}
436
437
const CSSSize& GetRootCompositionSize() const { return mRootCompositionSize; }
438
439
void SetDisplayPortMargins(const ScreenMargin& aDisplayPortMargins) {
440
mDisplayPortMargins = aDisplayPortMargins;
441
}
442
443
const ScreenMargin& GetDisplayPortMargins() const {
444
return mDisplayPortMargins;
445
}
446
447
uint32_t GetPresShellId() const { return mPresShellId; }
448
449
void SetPresShellId(uint32_t aPresShellId) { mPresShellId = aPresShellId; }
450
451
void SetLayoutViewport(const CSSRect& aLayoutViewport) {
452
mLayoutViewport = aLayoutViewport;
453
}
454
455
const CSSRect& GetLayoutViewport() const { return mLayoutViewport; }
456
457
CSSRect GetVisualViewport() const {
458
return CSSRect(mScrollOffset, CalculateCompositedSizeInCssPixels());
459
}
460
461
void SetExtraResolution(const ScreenToLayerScale2D& aExtraResolution) {
462
mExtraResolution = aExtraResolution;
463
}
464
465
const ScreenToLayerScale2D& GetExtraResolution() const {
466
return mExtraResolution;
467
}
468
469
const CSSRect& GetScrollableRect() const { return mScrollableRect; }
470
471
void SetScrollableRect(const CSSRect& aScrollableRect) {
472
mScrollableRect = aScrollableRect;
473
}
474
475
// If the frame is in vertical-RTL writing mode(E.g. "writing-mode:
476
// vertical-rl" in CSS), or if it's in horizontal-RTL writing-mode(E.g.
477
// "writing-mode: horizontal-tb; direction: rtl;" in CSS), then this function
478
// returns true. From the representation perspective, frames whose horizontal
479
// contents start at rightside also cause their horizontal scrollbars, if any,
480
// initially start at rightside. So we can also learn about the initial side
481
// of the horizontal scrollbar for the frame by calling this function.
482
bool IsHorizontalContentRightToLeft() const { return mScrollableRect.x < 0; }
483
484
void SetPaintRequestTime(const TimeStamp& aTime) {
485
mPaintRequestTime = aTime;
486
}
487
const TimeStamp& GetPaintRequestTime() const { return mPaintRequestTime; }
488
489
void SetIsScrollInfoLayer(bool aIsScrollInfoLayer) {
490
mIsScrollInfoLayer = aIsScrollInfoLayer;
491
}
492
bool IsScrollInfoLayer() const { return mIsScrollInfoLayer; }
493
494
void SetVisualViewportOffset(const CSSPoint& aVisualViewportOffset) {
495
mVisualViewportOffset = aVisualViewportOffset;
496
}
497
const CSSPoint& GetVisualViewportOffset() const {
498
return mVisualViewportOffset;
499
}
500
501
void SetVisualScrollUpdateType(ScrollOffsetUpdateType aUpdateType) {
502
mVisualScrollUpdateType = aUpdateType;
503
}
504
ScrollOffsetUpdateType GetVisualScrollUpdateType() const {
505
return mVisualScrollUpdateType;
506
}
507
508
// Determine if the visual viewport is outside of the layout viewport and
509
// adjust the x,y-offset in mLayoutViewport accordingly. This is necessary to
510
// allow APZ to async-scroll the layout viewport.
511
//
512
// This is a no-op if mIsRootContent is false.
513
void RecalculateLayoutViewportOffset();
514
515
void SetFixedLayerMargins(const ScreenMargin& aFixedLayerMargins) {
516
mFixedLayerMargins = aFixedLayerMargins;
517
}
518
const ScreenMargin& GetFixedLayerMargins() const {
519
return mFixedLayerMargins;
520
}
521
522
// Helper function for RecalculateViewportOffset(). Exposed so that
523
// APZC can perform the operation on other copies of the layout
524
// and visual viewport rects (e.g. the "effective" ones used to implement
525
// the frame delay).
526
// Modifies |aLayoutViewport| to continue enclosing |aVisualViewport|
527
// if possible.
528
// The layout viewport needs to remain clamped to the scrollable rect,
529
// and we pass in the scrollable rect so this function can maintain that
530
// constraint.
531
static void KeepLayoutViewportEnclosingVisualViewport(
532
const CSSRect& aVisualViewport, const CSSRect& aScrollableRect,
533
CSSRect& aLayoutViewport);
534
535
private:
536
// A ID assigned to each scrollable frame, unique within each LayersId..
537
ViewID mScrollId;
538
539
// The pres-shell resolution that has been induced on the document containing
540
// this scroll frame as a result of zooming this scroll frame (whether via
541
// user action, or choosing an initial zoom level on page load). This can
542
// only be different from 1.0 for frames that are zoomable, which currently
543
// is just the root content document's root scroll frame
544
// (mIsRootContent = true).
545
// This is a plain float rather than a ScaleFactor because in and of itself
546
// it does not convert between any coordinate spaces for which we have names.
547
float mPresShellResolution;
548
549
// This is the area within the widget that we're compositing to. It is in the
550
// layer coordinates of the scrollable content's parent layer.
551
//
552
// The size of the composition bounds corresponds to the size of the scroll
553
// frame's scroll port (but in a coordinate system where the size does not
554
// change during zooming).
555
//
556
// The origin of the composition bounds is relative to the layer tree origin.
557
// Unlike the scroll port's origin, it does not change during scrolling of
558
// the scrollable layer to which it is associated. However, it may change due
559
// to scrolling of ancestor layers.
560
//
561
// This value is provided by Gecko at layout/paint time.
562
ParentLayerRect mCompositionBounds;
563
564
// The area of a scroll frame's contents that has been painted, relative to
565
// mScrollOffset.
566
//
567
// Should not be larger than GetExpandedScrollableRect().
568
//
569
// To pre-render a margin of 100 CSS pixels around the scroll port,
570
// { x = -100, y = - 100,
571
// width = scrollPort.width + 200, height = scrollPort.height + 200 }
572
// where scrollPort = CalculateCompositedSizeInCssPixels().
573
CSSRect mDisplayPort;
574
575
// If non-empty, the area of a frame's contents that is considered critical
576
// to paint. Area outside of this area (i.e. area inside mDisplayPort, but
577
// outside of mCriticalDisplayPort) is considered low-priority, and may be
578
// painted with lower precision, or not painted at all.
579
//
580
// The same restrictions for mDisplayPort apply here.
581
CSSRect mCriticalDisplayPort;
582
583
// The scrollable bounds of a frame. This is determined by reflow.
584
// Ordinarily the x and y will be 0 and the width and height will be the
585
// size of the element being scrolled. However for RTL pages or elements
586
// the x value may be negative.
587
//
588
// For scrollable frames that are overflow:hidden the x and y are usually
589
// set to the value of the current scroll offset, and the width and height
590
// will match the composition bounds width and height. In effect this reduces
591
// the scrollable range to 0.
592
//
593
// This is in the same coordinate space as |mScrollOffset|, but a different
594
// coordinate space than |mDisplayPort|. Note also that this coordinate
595
// system is understood by window.scrollTo().
596
CSSRect mScrollableRect;
597
598
// The cumulative resolution that the current frame has been painted at.
599
// This is the product of the pres-shell resolutions of the document
600
// containing this scroll frame and its ancestors, and any css-driven
601
// resolution. This information is provided by Gecko at layout/paint time.
602
// Note that this is allowed to have different x- and y-scales, but only
603
// for subframes (mIsRootContent = false). (The same applies to other scales
604
// that "inherit" the 2D-ness of this one, such as mZoom.)
605
LayoutDeviceToLayerScale2D mCumulativeResolution;
606
607
// The conversion factor between CSS pixels and device pixels for this frame.
608
// This can vary based on a variety of things, such as reflowing-zoom.
609
CSSToLayoutDeviceScale mDevPixelsPerCSSPixel;
610
611
// The position of the top-left of the scroll frame's scroll port, relative
612
// to the scrollable content's origin.
613
//
614
// This is in the same coordinate space as |mScrollableRect|, but a different
615
// coordinate space than |mDisplayPort|.
616
//
617
// It is required that the rect:
618
// { x = mScrollOffset.x, y = mScrollOffset.y,
619
// width = scrollPort.width,
620
// height = scrollPort.height }
621
// (where scrollPort = CalculateCompositedSizeInCssPixels())
622
// be within |mScrollableRect|.
623
CSSPoint mScrollOffset;
624
625
// The base scroll offset to use for calculating a relative update to a
626
// scroll offset.
627
CSSPoint mBaseScrollOffset;
628
629
// The "user zoom". Content is painted by gecko at mCumulativeResolution *
630
// mDevPixelsPerCSSPixel, but will be drawn to the screen at mZoom. In the
631
// steady state, the two will be the same, but during an async zoom action the
632
// two may diverge. This information is initialized in Gecko but updated in
633
// the APZC.
634
CSSToParentLayerScale2D mZoom;
635
636
// The scroll generation counter used to acknowledge the scroll offset update.
637
uint32_t mScrollGeneration;
638
639
// If mDoSmoothScroll is true, the scroll offset will be animated smoothly
640
// to this value.
641
CSSPoint mSmoothScrollOffset;
642
643
// The size of the root scrollable's composition bounds, but in local CSS
644
// pixels.
645
CSSSize mRootCompositionSize;
646
647
// A display port expressed as layer margins that apply to the rect of what
648
// is drawn of the scrollable element.
649
ScreenMargin mDisplayPortMargins;
650
651
uint32_t mPresShellId;
652
653
// For a root scroll frame (RSF), the document's layout viewport
654
// (sometimes called "CSS viewport" in older code).
655
//
656
// Its size is the dimensions we're using to constrain the <html> element
657
// of the document (i.e. the initial containing block (ICB) size).
658
//
659
// Its origin is the RSF's layout scroll position, i.e. the scroll position
660
// exposed to web content via window.scrollX/Y.
661
//
662
// Note that only the root content document's RSF has a layout viewport
663
// that's distinct from the visual viewport. For an iframe RSF, the two
664
// are the same.
665
//
666
// For a scroll frame that is not an RSF, this metric is meaningless and
667
// invalid.
668
CSSRect mLayoutViewport;
669
670
// The extra resolution at which content in this scroll frame is drawn beyond
671
// that necessary to draw one Layer pixel per Screen pixel.
672
ScreenToLayerScale2D mExtraResolution;
673
674
// The time at which the APZC last requested a repaint for this scroll frame.
675
TimeStamp mPaintRequestTime;
676
677
// Whether mScrollOffset was updated by something other than the APZ code, and
678
// if the APZC receiving this metrics should update its local copy.
679
ScrollOffsetUpdateType mScrollUpdateType;
680
681
// These fields are used when the main thread wants to set a visual viewport
682
// offset that's distinct from the layout viewport offset.
683
// In this case, mVisualScrollUpdateType is set to eMainThread, and
684
// mVisualViewportOffset is set to desired visual viewport offset (relative
685
// to the document, like mScrollOffset).
686
// TODO: Get rid of mVisualViewportOffset: between mViewport.TopLeft() and
687
// mScrollOffset, we have enough storage for the two scroll offsets.
688
// However, to avoid confusion, that first requires refactoring
689
// existing to consistently use the two fields for those two purposes.
690
CSSPoint mVisualViewportOffset;
691
ScrollOffsetUpdateType mVisualScrollUpdateType;
692
693
// 'fixed layer margins' on the main-thread. This is only used for the
694
// root-content scroll frame.
695
ScreenMargin mFixedLayerMargins;
696
697
// Whether or not this is the root scroll frame for the root content document.
698
bool mIsRootContent : 1;
699
700
// When mIsRelative, the scroll offset was updated using a relative API,
701
// such as `ScrollBy`, and can combined with an async scroll.
702
bool mIsRelative : 1;
703
704
// When mDoSmoothScroll, the scroll offset should be animated to
705
// smoothly transition to mScrollOffset rather than be updated instantly.
706
bool mDoSmoothScroll : 1;
707
708
// True if this scroll frame is a scroll info layer. A scroll info layer is
709
// not layerized and its content cannot be truly async-scrolled, but its
710
// metrics are still sent to and updated by the compositor, with the updates
711
// being reflected on the next paint rather than the next composite.
712
bool mIsScrollInfoLayer : 1;
713
714
// WARNING!!!!
715
//
716
// When adding a new field:
717
//
718
// - First, consider whether the field can be added to ScrollMetadata
719
// instead. If so, prefer that.
720
//
721
// - Otherwise, the following places should be updated to include them
722
// (as needed):
723
// FrameMetrics::operator ==
724
// AsyncPanZoomController::NotifyLayersUpdated
725
// The ParamTraits specialization in LayersMessageUtils.h
726
//
727
// Please add new fields above this comment.
728
729
// Private helpers for IPC purposes
730
void SetDoSmoothScroll(bool aValue) { mDoSmoothScroll = aValue; }
731
};
732
733
struct ScrollSnapInfo {
734
ScrollSnapInfo();
735
736
bool operator==(const ScrollSnapInfo& aOther) const {
737
return mScrollSnapStrictnessX == aOther.mScrollSnapStrictnessX &&
738
mScrollSnapStrictnessY == aOther.mScrollSnapStrictnessY &&
739
mSnapPositionX == aOther.mSnapPositionX &&
740
mSnapPositionY == aOther.mSnapPositionY &&
741
mXRangeWiderThanSnapport == aOther.mXRangeWiderThanSnapport &&
742
mYRangeWiderThanSnapport == aOther.mYRangeWiderThanSnapport &&
743
mSnapportSize == aOther.mSnapportSize;
744
}
745
746
bool HasScrollSnapping() const;
747
bool HasSnapPositions() const;
748
749
void InitializeScrollSnapStrictness(WritingMode aWritingMode,
750
const nsStyleDisplay* aDisplay);
751
752
// The scroll frame's scroll-snap-type.
753
StyleScrollSnapStrictness mScrollSnapStrictnessX;
754
StyleScrollSnapStrictness mScrollSnapStrictnessY;
755
756
// The scroll positions corresponding to scroll-snap-align values.
757
nsTArray<nscoord> mSnapPositionX;
758
nsTArray<nscoord> mSnapPositionY;
759
760
struct ScrollSnapRange {
761
ScrollSnapRange() = default;
762
763
ScrollSnapRange(nscoord aStart, nscoord aEnd)
764
: mStart(aStart), mEnd(aEnd) {}
765
766
nscoord mStart;
767
nscoord mEnd;
768
bool operator==(const ScrollSnapRange& aOther) const {
769
return mStart == aOther.mStart && mEnd == aOther.mEnd;
770
}
771
772
// Returns true if |aPoint| is a valid snap position in this range.
773
bool IsValid(nscoord aPoint, nscoord aSnapportSize) const {
774
MOZ_ASSERT(mEnd - mStart > aSnapportSize);
775
return mStart <= aPoint && aPoint <= mEnd - aSnapportSize;
776
}
777
};
778
// An array of the range that the target element is larger than the snapport
779
// on the axis.
780
// Snap positions in this range will be valid snap positions in the case where
781
// the distance between the closest snap position and the second closest snap
782
// position is still larger than the snapport size.
784
//
785
// Note: This range contains scroll-margin values.
786
nsTArray<ScrollSnapRange> mXRangeWiderThanSnapport;
787
nsTArray<ScrollSnapRange> mYRangeWiderThanSnapport;
788
789
// Note: This snapport size has been already deflated by scroll-padding.
790
nsSize mSnapportSize;
791
};
792
793
// clang-format off
794
MOZ_DEFINE_ENUM_CLASS_WITH_BASE(
795
OverscrollBehavior, uint8_t, (
796
Auto,
797
Contain,
798
None
799
));
800
// clang-format on
801
802
struct OverscrollBehaviorInfo {
803
OverscrollBehaviorInfo()
804
: mBehaviorX(OverscrollBehavior::Auto),
805
mBehaviorY(OverscrollBehavior::Auto) {}
806
807
// Construct from StyleOverscrollBehavior values.
808
static OverscrollBehaviorInfo FromStyleConstants(
809
StyleOverscrollBehavior aBehaviorX, StyleOverscrollBehavior aBehaviorY);
810
811
bool operator==(const OverscrollBehaviorInfo& aOther) const {
812
return mBehaviorX == aOther.mBehaviorX && mBehaviorY == aOther.mBehaviorY;
813
}
814
815
OverscrollBehavior mBehaviorX;
816
OverscrollBehavior mBehaviorY;
817
};
818
819
/**
820
* A clip that applies to a layer, that may be scrolled by some of the
821
* scroll frames associated with the layer.
822
*/
823
struct LayerClip {
824
friend struct IPC::ParamTraits<mozilla::layers::LayerClip>;
825
826
public:
827
LayerClip() : mClipRect(), mMaskLayerIndex() {}
828
829
explicit LayerClip(const ParentLayerIntRect& aClipRect)
830
: mClipRect(aClipRect), mMaskLayerIndex() {}
831
832
bool operator==(const LayerClip& aOther) const {
833
return mClipRect == aOther.mClipRect &&
834
mMaskLayerIndex == aOther.mMaskLayerIndex;
835
}
836
837
void SetClipRect(const ParentLayerIntRect& aClipRect) {
838
mClipRect = aClipRect;
839
}
840
const ParentLayerIntRect& GetClipRect() const { return mClipRect; }
841
842
void SetMaskLayerIndex(const Maybe<size_t>& aIndex) {
843
mMaskLayerIndex = aIndex;
844
}
845
const Maybe<size_t>& GetMaskLayerIndex() const { return mMaskLayerIndex; }
846
847
private:
848
ParentLayerIntRect mClipRect;
849
850
// Optionally, specifies a mask layer that's part of the clip.
851
// This is an index into the MetricsMaskLayers array on the Layer.
852
Maybe<size_t> mMaskLayerIndex;
853
};
854
855
typedef Maybe<LayerClip> MaybeLayerClip; // for passing over IPDL
856
857
/**
858
* Metadata about a scroll frame that's sent to the compositor during a layers
859
* or WebRender transaction, and also stored by APZ between transactions.
860
* This includes the scroll frame's FrameMetrics, as well as other metadata.
861
* We don't put the other metadata into FrameMetrics to avoid FrameMetrics
862
* becoming too bloated (as a FrameMetrics is e.g. stored in memory shared
863
* with the content process).
864
*/
865
struct ScrollMetadata {
866
friend struct IPC::ParamTraits<mozilla::layers::ScrollMetadata>;
867
868
typedef ScrollableLayerGuid::ViewID ViewID;
869
870
public:
871
static StaticAutoPtr<const ScrollMetadata>
872
sNullMetadata; // We sometimes need an empty metadata
873
874
ScrollMetadata()
875
: mMetrics(),
876
mSnapInfo(),
877
mScrollParentId(ScrollableLayerGuid::NULL_SCROLL_ID),
878
mBackgroundColor(),
879
mContentDescription(),
880
mLineScrollAmount(0, 0),
881
mPageScrollAmount(0, 0),
882
mScrollClip(),
883
mHasScrollgrab(false),
884
mIsLayersIdRoot(false),
885
mIsAutoDirRootContentRTL(false),
886
mForceDisableApz(false),
887
mResolutionUpdated(false),
888
mOverscrollBehavior() {}
889
890
bool operator==(const ScrollMetadata& aOther) const {
891
return mMetrics == aOther.mMetrics && mSnapInfo == aOther.mSnapInfo &&
892
mScrollParentId == aOther.mScrollParentId &&
893
mBackgroundColor == aOther.mBackgroundColor &&
894
// don't compare mContentDescription
895
mLineScrollAmount == aOther.mLineScrollAmount &&
896
mPageScrollAmount == aOther.mPageScrollAmount &&
897
mScrollClip == aOther.mScrollClip &&
898
mHasScrollgrab == aOther.mHasScrollgrab &&
899
mIsLayersIdRoot == aOther.mIsLayersIdRoot &&
900
mIsAutoDirRootContentRTL == aOther.mIsAutoDirRootContentRTL &&
901
mForceDisableApz == aOther.mForceDisableApz &&
902
mResolutionUpdated == aOther.mResolutionUpdated &&
903
mDisregardedDirection == aOther.mDisregardedDirection &&
904
mOverscrollBehavior == aOther.mOverscrollBehavior;
905
}
906
907
bool operator!=(const ScrollMetadata& aOther) const {
908
return !operator==(aOther);
909
}
910
911
bool IsDefault() const {
912
ScrollMetadata def;
913
914
def.mMetrics.SetPresShellId(mMetrics.GetPresShellId());
915
return (def == *this);
916
}
917
918
FrameMetrics& GetMetrics() { return mMetrics; }
919
const FrameMetrics& GetMetrics() const { return mMetrics; }
920
921
void SetSnapInfo(ScrollSnapInfo&& aSnapInfo) {
922
mSnapInfo = std::move(aSnapInfo);
923
}
924
const ScrollSnapInfo& GetSnapInfo() const { return mSnapInfo; }
925
926
ViewID GetScrollParentId() const { return mScrollParentId; }
927
928
void SetScrollParentId(ViewID aParentId) { mScrollParentId = aParentId; }
929
const gfx::DeviceColor& GetBackgroundColor() const {
930
return mBackgroundColor;
931
}
932
void SetBackgroundColor(const gfx::sRGBColor& aBackgroundColor);
933
const nsCString& GetContentDescription() const { return mContentDescription; }
934
void SetContentDescription(const nsCString& aContentDescription) {
935
mContentDescription = aContentDescription;
936
}
937
const LayoutDeviceIntSize& GetLineScrollAmount() const {
938
return mLineScrollAmount;
939
}
940
void SetLineScrollAmount(const LayoutDeviceIntSize& size) {
941
mLineScrollAmount = size;
942
}
943
const LayoutDeviceIntSize& GetPageScrollAmount() const {
944
return mPageScrollAmount;
945
}
946
void SetPageScrollAmount(const LayoutDeviceIntSize& size) {
947
mPageScrollAmount = size;
948
}
949
950
void SetScrollClip(const Maybe<LayerClip>& aScrollClip) {
951
mScrollClip = aScrollClip;
952
}
953
const Maybe<LayerClip>& GetScrollClip() const { return mScrollClip; }
954
bool HasScrollClip() const { return mScrollClip.isSome(); }
955
const LayerClip& ScrollClip() const { return mScrollClip.ref(); }
956
LayerClip& ScrollClip() { return mScrollClip.ref(); }
957
958
bool HasMaskLayer() const {
959
return HasScrollClip() && ScrollClip().GetMaskLayerIndex();
960
}
961
Maybe<ParentLayerIntRect> GetClipRect() const {
962
return mScrollClip.isSome() ? Some(mScrollClip->GetClipRect()) : Nothing();
963
}
964
965
void SetHasScrollgrab(bool aHasScrollgrab) {
966
mHasScrollgrab = aHasScrollgrab;
967
}
968
bool GetHasScrollgrab() const { return mHasScrollgrab; }
969
void SetIsLayersIdRoot(bool aValue) { mIsLayersIdRoot = aValue; }
970
bool IsLayersIdRoot() const { return mIsLayersIdRoot; }
971
void SetIsAutoDirRootContentRTL(bool aValue) {
972
mIsAutoDirRootContentRTL = aValue;
973
}
974
bool IsAutoDirRootContentRTL() const { return mIsAutoDirRootContentRTL; }
975
void SetForceDisableApz(bool aForceDisable) {
976
mForceDisableApz = aForceDisable;
977
}
978
bool IsApzForceDisabled() const { return mForceDisableApz; }
979
void SetResolutionUpdated(bool aUpdated) { mResolutionUpdated = aUpdated; }
980
bool IsResolutionUpdated() const { return mResolutionUpdated; }
981
982
// For more details about the concept of a disregarded direction, refer to the
983
// code which defines mDisregardedDirection.
984
Maybe<ScrollDirection> GetDisregardedDirection() const {
985
return mDisregardedDirection;
986
}
987
void SetDisregardedDirection(const Maybe<ScrollDirection>& aValue) {
988
mDisregardedDirection = aValue;
989
}
990
991
void SetOverscrollBehavior(
992
const OverscrollBehaviorInfo& aOverscrollBehavior) {
993
mOverscrollBehavior = aOverscrollBehavior;
994
}
995
const OverscrollBehaviorInfo& GetOverscrollBehavior() const {
996
return mOverscrollBehavior;
997
}
998
999
private:
1000
FrameMetrics mMetrics;
1001
1002
// Information used to determine where to snap to for a given scroll.
1003
ScrollSnapInfo mSnapInfo;
1004
1005
// The ViewID of the scrollable frame to which overscroll should be handed
1006
// off.
1007
ViewID mScrollParentId;
1008
1009
// The background color to use when overscrolling.
1010
gfx::DeviceColor mBackgroundColor;
1011
1012
// A description of the content element corresponding to this frame.
1013
// This is empty unless this is a scrollable layer and the
1014
// apz.printtree pref is turned on.
1015
nsCString mContentDescription;
1016
1017
// The value of GetLineScrollAmount(), for scroll frames.
1018
LayoutDeviceIntSize mLineScrollAmount;
1019
1020
// The value of GetPageScrollAmount(), for scroll frames.
1021
LayoutDeviceIntSize mPageScrollAmount;
1022
1023
// A clip to apply when compositing the layer bearing this ScrollMetadata,
1024
// after applying any transform arising from scrolling this scroll frame.
1025
// Note that, unlike most other fields of ScrollMetadata, this is allowed
1026
// to differ between different layers scrolled by the same scroll frame.
1027
// TODO: Group the fields of ScrollMetadata into sub-structures to separate
1028
// fields with this property better.
1029
Maybe<LayerClip> mScrollClip;
1030
1031
// Whether or not this frame is for an element marked 'scrollgrab'.
1032
bool mHasScrollgrab : 1;
1033
1034
// Whether these framemetrics are for the root scroll frame (root element if
1035
// we don't have a root scroll frame) for its layers id.
1036
bool mIsLayersIdRoot : 1;
1037
1038
// The AutoDirRootContent is the <body> element in an HTML document, or the
1039
// root scrollframe if there is no body. This member variable indicates
1040
// whether this element's content in the horizontal direction starts from
1041
// right to left (e.g. it's true either if "writing-mode: vertical-rl", or
1042
// "writing-mode: horizontal-tb; direction: rtl" in CSS).
1043
// When we do auto-dir scrolling (@see mozilla::WheelDeltaAdjustmentStrategy
1044
// or refer to bug 1358017 for details), setting a pref can make the code use
1045
// the writing mode of this root element instead of the target scrollframe,
1046
// and so we need to know if the writing mode is RTL or not.
1047
bool mIsAutoDirRootContentRTL : 1;
1048
1049
// Whether or not the compositor should actually do APZ-scrolling on this
1050
// scrollframe.
1051
bool mForceDisableApz : 1;
1052
1053
// Whether the pres shell resolution stored in mMetrics reflects a change
1054
// originated by the main thread. Plays a similar role for the resolution as
1055
// FrameMetrics::mScrollUpdateType) does for the scroll offset.
1056
bool mResolutionUpdated : 1;
1057
1058
// The disregarded direction means the direction which is disregarded anyway,
1059
// even if the scroll frame overflows in that direction and the direction is
1060
// specified as scrollable. This could happen in some scenarios, for instance,
1061
// a single-line text control frame should disregard wheel scroll in
1062
// its block-flow direction even if it overflows in that direction.
1063
Maybe<ScrollDirection> mDisregardedDirection;
1064
1065
// The overscroll behavior for this scroll frame.
1066
OverscrollBehaviorInfo mOverscrollBehavior;
1067
1068
// WARNING!!!!
1069
//
1070
// When adding new fields to ScrollMetadata, the following places should be
1071
// updated to include them (as needed):
1072
// 1. ScrollMetadata::operator ==
1073
// 2. AsyncPanZoomController::NotifyLayersUpdated
1074
// 3. The ParamTraits specialization in LayersMessageUtils.h
1075
//
1076
// Please add new fields above this comment.
1077
};
1078
1079
typedef nsDataHashtable<ScrollableLayerGuid::ViewIDHashKey, ScrollUpdateInfo>
1080
ScrollUpdatesMap;
1081
1082
} // namespace layers
1083
} // namespace mozilla
1084
1085
#endif /* GFX_FRAMEMETRICS_H */