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 nsLayoutUtils_h__
8 #define nsLayoutUtils_h__
9
10 #include "LayoutConstants.h"
11 #include "mozilla/MemoryReporting.h"
12 #include "mozilla/ArrayUtils.h"
13 #include "mozilla/LookAndFeel.h"
14 #include "mozilla/Maybe.h"
15 #include "mozilla/RelativeTo.h"
16 #include "mozilla/StaticPrefs_nglayout.h"
17 #include "mozilla/SurfaceFromElementResult.h"
18 #include "mozilla/SVGImageContext.h"
19 #include "mozilla/ToString.h"
20 #include "mozilla/TypedEnumBits.h"
21 #include "mozilla/Span.h"
22 #include "mozilla/UniquePtr.h"
23 #include "mozilla/WritingModes.h"
24 #include "mozilla/layout/FrameChildList.h"
25 #include "mozilla/layers/ScrollableLayerGuid.h"
26 #include "mozilla/gfx/2D.h"
27
28 #include "gfxPoint.h"
29 #include "nsBoundingMetrics.h"
30 #include "nsCSSPropertyIDSet.h"
31 #include "nsThreadUtils.h"
32 #include "Units.h"
33 #include "mozilla/layers/LayersTypes.h"
34 #include <limits>
35 #include <algorithm>
36 // If you're thinking of adding a new include here, please try hard to not.
37 // This header file gets included just about everywhere and adding headers here
38 // can dramatically increase avoidable build activity. Try instead:
39 // - using a forward declaration
40 // - putting the include in the .cpp file, if it is only needed by the body
41 // - putting your new functions in some other less-widely-used header
42
43 class gfxContext;
44 class gfxFontEntry;
45 class imgIContainer;
46 class nsFrameList;
47 class nsPresContext;
48 class nsIContent;
49 class nsIPrincipal;
50 class nsIWidget;
51 class nsAtom;
52 class nsIScrollableFrame;
53 class nsRegion;
54 enum nsChangeHint : uint32_t;
55 class nsFontMetrics;
56 class nsFontFaceList;
57 class nsIImageLoadingContent;
58 class nsBlockFrame;
59 class nsContainerFrame;
60 class nsView;
61 class nsIFrame;
62 class nsPIDOMWindowOuter;
63 class imgIRequest;
64 struct nsStyleFont;
65
66 namespace mozilla {
67 class nsDisplayItem;
68 class nsDisplayList;
69 class nsDisplayListBuilder;
70 enum class nsDisplayListBuilderMode : uint8_t;
71 struct AspectRatio;
72 class ComputedStyle;
73 class DisplayPortUtils;
74 class PresShell;
75 enum class PseudoStyleType : uint8_t;
76 class EventListenerManager;
77 enum class LayoutFrameType : uint8_t;
78 struct IntrinsicSize;
79 class ReflowOutput;
80 class WritingMode;
81 class DisplayItemClip;
82 class EffectSet;
83 struct ActiveScrolledRoot;
84 enum class ScrollOrigin : uint8_t;
85 enum class StyleImageOrientation : uint8_t;
86 enum class StyleSystemFont : uint8_t;
87 enum class StyleScrollbarWidth : uint8_t;
88 struct OverflowAreas;
89 namespace dom {
90 class CanvasRenderingContext2D;
91 class DOMRectList;
92 class Document;
93 class Element;
94 class Event;
95 class HTMLImageElement;
96 class HTMLCanvasElement;
97 class HTMLVideoElement;
98 class InspectorFontFace;
99 class OffscreenCanvas;
100 class Selection;
101 } // namespace dom
102 namespace gfx {
103 struct RectCornerRadii;
104 enum class ShapedTextFlags : uint16_t;
105 } // namespace gfx
106 namespace image {
107 class ImageIntRegion;
108 struct Resolution;
109 } // namespace image
110 namespace layers {
111 struct FrameMetrics;
112 struct ScrollMetadata;
113 class Image;
114 class StackingContextHelper;
115 class Layer;
116 class WebRenderLayerManager;
117
118 } // namespace layers
119 } // namespace mozilla
120
121 // Flags to customize the behavior of nsLayoutUtils::DrawString.
122 enum class DrawStringFlags {
123 Default = 0x0,
124 ForceHorizontal = 0x1 // Forces the text to be drawn horizontally.
125 };
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(DrawStringFlags)126 MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(DrawStringFlags)
127
128 namespace mozilla {
129
130 class RectCallback {
131 public:
132 virtual void AddRect(const nsRect& aRect) = 0;
133 };
134
135 } // namespace mozilla
136
137 /**
138 * nsLayoutUtils is a namespace class used for various helper
139 * functions that are useful in multiple places in layout. The goal
140 * is not to define multiple copies of the same static helper.
141 */
142 class nsLayoutUtils {
143 typedef mozilla::AspectRatio AspectRatio;
144 typedef mozilla::ComputedStyle ComputedStyle;
145 typedef mozilla::LengthPercentage LengthPercentage;
146 typedef mozilla::LengthPercentageOrAuto LengthPercentageOrAuto;
147 typedef mozilla::dom::DOMRectList DOMRectList;
148 typedef mozilla::layers::Layer Layer;
149 typedef mozilla::layers::StackingContextHelper StackingContextHelper;
150 typedef mozilla::IntrinsicSize IntrinsicSize;
151 typedef mozilla::RelativeTo RelativeTo;
152 typedef mozilla::ScrollOrigin ScrollOrigin;
153 typedef mozilla::ViewportType ViewportType;
154 typedef mozilla::gfx::SourceSurface SourceSurface;
155 typedef mozilla::gfx::sRGBColor sRGBColor;
156 typedef mozilla::gfx::DrawTarget DrawTarget;
157 typedef mozilla::gfx::ExtendMode ExtendMode;
158 typedef mozilla::gfx::SamplingFilter SamplingFilter;
159 typedef mozilla::gfx::Float Float;
160 typedef mozilla::gfx::Point Point;
161 typedef mozilla::gfx::Rect Rect;
162 typedef mozilla::gfx::RectDouble RectDouble;
163 typedef mozilla::gfx::Size Size;
164 typedef mozilla::gfx::Matrix4x4 Matrix4x4;
165 typedef mozilla::gfx::Matrix4x4Flagged Matrix4x4Flagged;
166 typedef mozilla::gfx::RectCornerRadii RectCornerRadii;
167 typedef mozilla::gfx::StrokeOptions StrokeOptions;
168 typedef mozilla::image::ImgDrawResult ImgDrawResult;
169
170 using nsDisplayItem = mozilla::nsDisplayItem;
171 using nsDisplayList = mozilla::nsDisplayList;
172 using nsDisplayListBuilder = mozilla::nsDisplayListBuilder;
173 using nsDisplayListBuilderMode = mozilla::nsDisplayListBuilderMode;
174
175 public:
176 typedef mozilla::layers::FrameMetrics FrameMetrics;
177 typedef mozilla::layers::ScrollMetadata ScrollMetadata;
178 typedef mozilla::layers::ScrollableLayerGuid::ViewID ViewID;
179 typedef mozilla::CSSPoint CSSPoint;
180 typedef mozilla::CSSSize CSSSize;
181 typedef mozilla::CSSIntSize CSSIntSize;
182 typedef mozilla::CSSRect CSSRect;
183 typedef mozilla::ScreenMargin ScreenMargin;
184 typedef mozilla::LayoutDeviceIntSize LayoutDeviceIntSize;
185 typedef mozilla::LayoutDeviceRect LayoutDeviceRect;
186 typedef mozilla::PresShell PresShell;
187 typedef mozilla::StyleGeometryBox StyleGeometryBox;
188 typedef mozilla::SVGImageContext SVGImageContext;
189 typedef mozilla::LogicalSize LogicalSize;
190
191 /**
192 * Finds previously assigned ViewID for the given content element, if any.
193 * Returns whether a ViewID was previously assigned.
194 */
195 static bool FindIDFor(const nsIContent* aContent, ViewID* aOutViewId);
196
197 /**
198 * Finds previously assigned or generates a unique ViewID for the given
199 * content element.
200 */
201 static ViewID FindOrCreateIDFor(nsIContent* aContent);
202
203 /**
204 * Find content for given ID.
205 */
206 static nsIContent* FindContentFor(ViewID aId);
207
208 /**
209 * Find the scrollable frame for a given content element.
210 */
211 static nsIScrollableFrame* FindScrollableFrameFor(nsIContent* aContent);
212
213 /**
214 * Find the scrollable frame for a given ID.
215 */
216 static nsIScrollableFrame* FindScrollableFrameFor(ViewID aId);
217
218 /**
219 * Helper for FindScrollableFrameFor(), also used in DisplayPortUtils.
220 * Most clients should use FindScrollableFrameFor().
221 */
222 static nsIFrame* GetScrollFrameFromContent(nsIContent* aContent);
223
224 /**
225 * Find the ID for a given scrollable frame.
226 */
227 static ViewID FindIDForScrollableFrame(nsIScrollableFrame* aScrollable);
228
229 /**
230 * Notify the scroll frame with the given scroll id that its scroll offset
231 * is being sent to APZ as part of a paint-skip transaction.
232 *
233 * Normally, this notification happens during painting, after calls to
234 * ComputeScrollMetadata(). During paint-skipping that code is skipped,
235 * but it's still important for the scroll frame to be notified for
236 * correctness of relative scroll updates, so the code that sends the
237 * empty paint-skip transaction needs to call this.
238 */
239 static void NotifyPaintSkipTransaction(ViewID aScrollId);
240
241 /**
242 * Use heuristics to figure out the child list that
243 * aChildFrame is currently in.
244 */
245 static mozilla::layout::FrameChildListID GetChildListNameFor(
246 nsIFrame* aChildFrame);
247
248 /**
249 * Returns the ::before pseudo-element for aContent, if any.
250 */
251 static mozilla::dom::Element* GetBeforePseudo(const nsIContent* aContent);
252
253 /**
254 * Returns the frame corresponding to the ::before pseudo-element for
255 * aContent, if any.
256 */
257 static nsIFrame* GetBeforeFrame(const nsIContent* aContent);
258
259 /**
260 * Returns the ::after pseudo-element for aContent, if any.
261 */
262 static mozilla::dom::Element* GetAfterPseudo(const nsIContent* aContent);
263
264 /**
265 * Returns the frame corresponding to the ::after pseudo-element for aContent,
266 * if any.
267 */
268 static nsIFrame* GetAfterFrame(const nsIContent* aContent);
269
270 /**
271 * Returns the ::marker pseudo-element for aContent, if any.
272 */
273 static mozilla::dom::Element* GetMarkerPseudo(const nsIContent* aContent);
274
275 /**
276 * Returns the frame corresponding to the ::marker pseudo-element for
277 * aContent, if any.
278 */
279 static nsIFrame* GetMarkerFrame(const nsIContent* aContent);
280
281 #ifdef ACCESSIBILITY
282 /**
283 * Set aText to the spoken text for the given ::marker content (aContent)
284 * if it has a frame, or the empty string otherwise.
285 */
286 static void GetMarkerSpokenText(const nsIContent* aContent, nsAString& aText);
287 #endif
288
289 /**
290 * Given a frame, search up the frame tree until we find an
291 * ancestor that (or the frame itself) is of type aFrameType, if any.
292 *
293 * @param aFrame the frame to start at
294 * @param aFrameType the frame type to look for
295 * @param aStopAt a frame to stop at after we checked it
296 * @return a frame of the given type or nullptr if no
297 * such ancestor exists
298 */
299 static nsIFrame* GetClosestFrameOfType(nsIFrame* aFrame,
300 mozilla::LayoutFrameType aFrameType,
301 nsIFrame* aStopAt = nullptr);
302
303 /**
304 * Given a frame, search up the frame tree until we find an
305 * ancestor that (or the frame itself) is a "Page" frame, if any.
306 *
307 * @param aFrame the frame to start at
308 * @return a frame of type mozilla::LayoutFrameType::Page or nullptr if no
309 * such ancestor exists
310 */
311 static nsIFrame* GetPageFrame(nsIFrame* aFrame);
312
313 /**
314 * Given a frame which is the primary frame for an element,
315 * return the frame that has the non-pseudoelement ComputedStyle for
316 * the content.
317 * This is aPrimaryFrame itself except for tableWrapper frames.
318 *
319 * Given a non-null input, this will return null if and only if its
320 * argument is a table wrapper frame that is mid-destruction (and its
321 * table frame has been destroyed).
322 */
323 static nsIFrame* GetStyleFrame(nsIFrame* aPrimaryFrame);
324 static const nsIFrame* GetStyleFrame(const nsIFrame* aPrimaryFrame);
325
326 /**
327 * Given a content node,
328 * return the frame that has the non-pseudoelement ComputedStyle for
329 * the content. May return null.
330 * This is aContent->GetPrimaryFrame() except for tableWrapper frames.
331 */
332 static nsIFrame* GetStyleFrame(const nsIContent* aContent);
333
334 /**
335 * Returns the placeholder size for when the scrollbar is unthemed.
336 */
337 static mozilla::CSSIntCoord UnthemedScrollbarSize(
338 mozilla::StyleScrollbarWidth);
339
340 /**
341 * The inverse of GetStyleFrame. Returns |aStyleFrame| unless it is an inner
342 * table frame, in which case the table wrapper frame is returned.
343 */
344 static nsIFrame* GetPrimaryFrameFromStyleFrame(nsIFrame* aStyleFrame);
345 static const nsIFrame* GetPrimaryFrameFromStyleFrame(
346 const nsIFrame* aStyleFrame);
347
348 /**
349 * Similar to nsIFrame::IsPrimaryFrame except that this will return true
350 * for the inner table frame rather than for its wrapper frame.
351 */
352 static bool IsPrimaryStyleFrame(const nsIFrame* aFrame);
353
354 #ifdef DEBUG
355 // TODO: remove, see bug 598468.
356 static bool gPreventAssertInCompareTreePosition;
357 #endif // DEBUG
358
359 /**
360 * CompareTreePosition determines whether aContent1 comes before or
361 * after aContent2 in a preorder traversal of the content tree.
362 *
363 * @param aCommonAncestor either null, or a common ancestor of
364 * aContent1 and aContent2. Actually this is
365 * only a hint; if it's not an ancestor of
366 * aContent1 or aContent2, this function will
367 * still work, but it will be slower than
368 * normal.
369 * @return < 0 if aContent1 is before aContent2
370 * > 0 if aContent1 is after aContent2,
371 * 0 otherwise (meaning they're the same, or they're in
372 * different documents)
373 */
374 static int32_t CompareTreePosition(
375 nsIContent* aContent1, nsIContent* aContent2,
376 const nsIContent* aCommonAncestor = nullptr) {
377 return DoCompareTreePosition(aContent1, aContent2, -1, 1, aCommonAncestor);
378 }
379
380 /*
381 * More generic version of |CompareTreePosition|. |aIf1Ancestor|
382 * gives the value to return when 1 is an ancestor of 2, and likewise
383 * for |aIf2Ancestor|. Passing (-1, 1) gives preorder traversal
384 * order, and (1, -1) gives postorder traversal order.
385 */
386 static int32_t DoCompareTreePosition(
387 nsIContent* aContent1, nsIContent* aContent2, int32_t aIf1Ancestor,
388 int32_t aIf2Ancestor, const nsIContent* aCommonAncestor = nullptr);
389
390 /**
391 * CompareTreePosition determines whether aFrame1 comes before or
392 * after aFrame2 in a preorder traversal of the frame tree, where out
393 * of flow frames are treated as children of their placeholders. This is
394 * basically the same ordering as DoCompareTreePosition(nsIContent*) except
395 * that it handles anonymous content properly and there are subtleties with
396 * continuations.
397 *
398 * @param aCommonAncestor either null, or a common ancestor of
399 * aContent1 and aContent2. Actually this is
400 * only a hint; if it's not an ancestor of
401 * aContent1 or aContent2, this function will
402 * still work, but it will be slower than
403 * normal.
404 * @return < 0 if aContent1 is before aContent2
405 * > 0 if aContent1 is after aContent2,
406 * 0 otherwise (meaning they're the same, or they're in
407 * different frame trees)
408 */
409 static int32_t CompareTreePosition(nsIFrame* aFrame1, nsIFrame* aFrame2,
410 nsIFrame* aCommonAncestor = nullptr) {
411 return DoCompareTreePosition(aFrame1, aFrame2, -1, 1, aCommonAncestor);
412 }
413
414 static int32_t CompareTreePosition(nsIFrame* aFrame1, nsIFrame* aFrame2,
415 nsTArray<nsIFrame*>& aFrame2Ancestors,
416 nsIFrame* aCommonAncestor = nullptr) {
417 return DoCompareTreePosition(aFrame1, aFrame2, aFrame2Ancestors, -1, 1,
418 aCommonAncestor);
419 }
420
421 /*
422 * More generic version of |CompareTreePosition|. |aIf1Ancestor|
423 * gives the value to return when 1 is an ancestor of 2, and likewise
424 * for |aIf2Ancestor|. Passing (-1, 1) gives preorder traversal
425 * order, and (1, -1) gives postorder traversal order.
426 */
427 static int32_t DoCompareTreePosition(nsIFrame* aFrame1, nsIFrame* aFrame2,
428 int32_t aIf1Ancestor,
429 int32_t aIf2Ancestor,
430 nsIFrame* aCommonAncestor = nullptr);
431
432 static nsIFrame* FillAncestors(nsIFrame* aFrame, nsIFrame* aStopAtAncestor,
433 nsTArray<nsIFrame*>* aAncestors);
434
435 static int32_t DoCompareTreePosition(nsIFrame* aFrame1, nsIFrame* aFrame2,
436 nsTArray<nsIFrame*>& aFrame2Ancestors,
437 int32_t aIf1Ancestor,
438 int32_t aIf2Ancestor,
439 nsIFrame* aCommonAncestor);
440
441 /**
442 * LastContinuationWithChild gets the last continuation in aFrame's chain
443 * that has a child, or the first continuation if the frame has no children.
444 */
445 static nsContainerFrame* LastContinuationWithChild(nsContainerFrame* aFrame);
446
447 /**
448 * GetLastSibling simply finds the last sibling of aFrame, or returns nullptr
449 * if aFrame is null.
450 */
451 static nsIFrame* GetLastSibling(nsIFrame* aFrame);
452
453 /**
454 * FindSiblingViewFor locates the child of aParentView that aFrame's
455 * view should be inserted 'above' (i.e., before in sibling view
456 * order). This is the first child view of aParentView whose
457 * corresponding content is before aFrame's content (view siblings
458 * are in reverse content order).
459 */
460 static nsView* FindSiblingViewFor(nsView* aParentView, nsIFrame* aFrame);
461
462 /**
463 * Get the parent of aFrame. If aFrame is the root frame for a document,
464 * and the document has a parent document in the same view hierarchy, then
465 * we try to return the subdocumentframe in the parent document.
466 * @param aCrossDocOffset [in/out] if non-null, then as we cross documents
467 * an extra offset may be required and it will be added to aCrossDocOffset.
468 * Be careful dealing with this extra offset as it is in app units of the
469 * parent document, which may have a different app units per dev pixel ratio
470 * than the child document.
471 * Note that, while this function crosses document boundaries, it (naturally)
472 * cannot cross process boundaries.
473 */
474 static nsIFrame* GetCrossDocParentFrameInProcess(
475 const nsIFrame* aFrame, nsPoint* aCrossDocOffset = nullptr);
476
477 /**
478 * Does the same thing as GetCrossDocParentFrameInProcess().
479 * The purpose of having two functions is to more easily track which call
480 * sites have been audited to consider out-of-process iframes (bug 1599913).
481 * Once all call sites have been audited, this function can be removed.
482 */
483 static nsIFrame* GetCrossDocParentFrame(const nsIFrame* aFrame,
484 nsPoint* aCrossDocOffset = nullptr);
485
486 /**
487 * IsProperAncestorFrame checks whether aAncestorFrame is an ancestor
488 * of aFrame and not equal to aFrame.
489 * @param aCommonAncestor nullptr, or a common ancestor of aFrame and
490 * aAncestorFrame. If non-null, this can bound the search and speed up
491 * the function
492 */
493 static bool IsProperAncestorFrame(const nsIFrame* aAncestorFrame,
494 const nsIFrame* aFrame,
495 const nsIFrame* aCommonAncestor = nullptr);
496
497 /**
498 * Like IsProperAncestorFrame, but looks across document boundaries.
499 *
500 * Just like IsAncestorFrameCrossDoc, except that it returns false when
501 * aFrame == aAncestorFrame.
502 * TODO: Once after we fixed bug 1715932, this function should be removed.
503 */
504 static bool IsProperAncestorFrameCrossDoc(
505 const nsIFrame* aAncestorFrame, const nsIFrame* aFrame,
506 const nsIFrame* aCommonAncestor = nullptr);
507
508 /**
509 * Like IsProperAncestorFrame, but looks across document boundaries.
510 *
511 * Just like IsAncestorFrameCrossDoc, except that it returns false when
512 * aFrame == aAncestorFrame.
513 */
514 static bool IsProperAncestorFrameCrossDocInProcess(
515 const nsIFrame* aAncestorFrame, const nsIFrame* aFrame,
516 const nsIFrame* aCommonAncestor = nullptr);
517
518 /**
519 * IsAncestorFrameCrossDoc checks whether aAncestorFrame is an ancestor
520 * of aFrame or equal to aFrame, looking across document boundaries.
521 * @param aCommonAncestor nullptr, or a common ancestor of aFrame and
522 * aAncestorFrame. If non-null, this can bound the search and speed up
523 * the function.
524 *
525 * Just like IsProperAncestorFrameCrossDoc, except that it returns true when
526 * aFrame == aAncestorFrame.
527 *
528 * TODO: Bug 1700245, all call sites of this function will be eventually
529 * replaced by IsAncestorFrameCrossDocInProcess.
530 */
531 static bool IsAncestorFrameCrossDoc(
532 const nsIFrame* aAncestorFrame, const nsIFrame* aFrame,
533 const nsIFrame* aCommonAncestor = nullptr);
534
535 /**
536 * IsAncestorFrameCrossDocInProcess checks whether aAncestorFrame is an
537 * ancestor of aFrame or equal to aFrame, looking across document boundaries
538 * in the same process.
539 * @param aCommonAncestor nullptr, or a common ancestor of aFrame and
540 * aAncestorFrame. If non-null, this can bound the search and speed up
541 * the function.
542 *
543 * Just like IsProperAncestorFrameCrossDoc, except that it returns true when
544 * aFrame == aAncestorFrame.
545 *
546 * NOTE: This function doesn't return true even if |aAncestorFrame| and
547 * |aFrame| is in the same process but they are not directly connected, e.g.
548 * both |aAncestorFrame| and |aFrame| in A domain documents, but there's
549 * another an iframe document domain B, such as A1 -> B1 ->A2 document tree.
550 */
551 static bool IsAncestorFrameCrossDocInProcess(
552 const nsIFrame* aAncestorFrame, const nsIFrame* aFrame,
553 const nsIFrame* aCommonAncestor = nullptr);
554
555 static mozilla::SideBits GetSideBitsForFixedPositionContent(
556 const nsIFrame* aFixedPosFrame);
557
558 /**
559 * Get the scroll id for the root scrollframe of the presshell of the given
560 * prescontext. Returns NULL_SCROLL_ID if it couldn't be found.
561 */
562 static ViewID ScrollIdForRootScrollFrame(nsPresContext* aPresContext);
563
564 /**
565 * GetScrollableFrameFor returns the scrollable frame for a scrolled frame
566 */
567 static nsIScrollableFrame* GetScrollableFrameFor(
568 const nsIFrame* aScrolledFrame);
569
570 /**
571 * GetNearestScrollableFrameForDirection locates the first ancestor of
572 * aFrame (or aFrame itself) that is scrollable with overflow:scroll or
573 * overflow:auto in the given direction and where either the scrollbar for
574 * that direction is visible or the frame can be scrolled by some
575 * positive amount in that direction.
576 * The search extends across document boundaries.
577 *
578 * @param aFrame the frame to start with
579 * @param aDirection Whether it's for horizontal or vertical scrolling.
580 * @return the nearest scrollable frame or nullptr if not found
581 */
582 static nsIScrollableFrame* GetNearestScrollableFrameForDirection(
583 nsIFrame* aFrame, mozilla::layers::ScrollDirections aDirections);
584
585 enum {
586 /**
587 * If the SCROLLABLE_SAME_DOC flag is set, then we only walk the frame tree
588 * up to the root frame in the current document.
589 */
590 SCROLLABLE_SAME_DOC = 0x01,
591 /**
592 * If the SCROLLABLE_INCLUDE_HIDDEN flag is set then we allow
593 * overflow:hidden scrollframes to be returned as scrollable frames.
594 */
595 SCROLLABLE_INCLUDE_HIDDEN = 0x02,
596 /**
597 * If the SCROLLABLE_ONLY_ASYNC_SCROLLABLE flag is set, then we only
598 * want to match scrollable frames for which WantAsyncScroll() returns
599 * true.
600 */
601 SCROLLABLE_ONLY_ASYNC_SCROLLABLE = 0x04,
602 /**
603 * If the SCROLLABLE_ALWAYS_MATCH_ROOT flag is set, then we will always
604 * return the root scrollable frame for the root document (in the current
605 * process) if we encounter it, whether or not it is async scrollable or
606 * overflow: hidden.
607 */
608 SCROLLABLE_ALWAYS_MATCH_ROOT = 0x08,
609 /**
610 * If the SCROLLABLE_FIXEDPOS_FINDS_ROOT flag is set, then for fixed-pos
611 * frames return the root scrollable frame for that document.
612 */
613 SCROLLABLE_FIXEDPOS_FINDS_ROOT = 0x10,
614 /**
615 * If the SCROLLABLE_STOP_AT_PAGE flag is set, then we stop searching
616 * for scrollable ancestors when seeing a nsPageFrame. This can be used
617 * to avoid finding the viewport scroll frame in Print Preview (which
618 * would be undesirable as a 'position:sticky' container for content).
619 */
620 SCROLLABLE_STOP_AT_PAGE = 0x20,
621 /**
622 * If the SCROLLABLE_FOLLOW_OOF_TO_PLACEHOLDER flag is set, we navigate
623 * from out-of-flow frames to their placeholder frame rather than their
624 * parent frame.
625 * Note, fixed-pos frames are out-of-flow frames, but
626 * SCROLLABLE_FIXEDPOS_FINDS_ROOT takes precedence over this.
627 */
628 SCROLLABLE_FOLLOW_OOF_TO_PLACEHOLDER = 0x40
629 };
630 /**
631 * GetNearestScrollableFrame locates the first ancestor of aFrame
632 * (or aFrame itself) that is scrollable with overflow:scroll or
633 * overflow:auto in some direction.
634 *
635 * @param aFrame the frame to start with
636 * @param aFlags if SCROLLABLE_SAME_DOC is set, do not search across
637 * document boundaries. If SCROLLABLE_INCLUDE_HIDDEN is set, include
638 * frames scrollable with overflow:hidden.
639 * @return the nearest scrollable frame or nullptr if not found
640 */
641 static nsIScrollableFrame* GetNearestScrollableFrame(nsIFrame* aFrame,
642 uint32_t aFlags = 0);
643
644 /**
645 * GetScrolledRect returns the range of allowable scroll offsets
646 * for aScrolledFrame, assuming the scrollable overflow area is
647 * aScrolledFrameOverflowArea and the scrollport size is aScrollPortSize.
648 */
649 static nsRect GetScrolledRect(nsIFrame* aScrolledFrame,
650 const nsRect& aScrolledFrameOverflowArea,
651 const nsSize& aScrollPortSize,
652 mozilla::StyleDirection);
653
654 /**
655 * HasPseudoStyle returns true if aContent (whose primary style
656 * context is aComputedStyle) has the aPseudoElement pseudo-style
657 * attached to it; returns false otherwise.
658 *
659 * @param aContent the content node we're looking at
660 * @param aComputedStyle aContent's ComputedStyle
661 * @param aPseudoElement the id of the pseudo style we care about
662 * @param aPresContext the presentation context
663 * @return whether aContent has aPseudoElement style attached to it
664 */
665 static bool HasPseudoStyle(nsIContent* aContent,
666 ComputedStyle* aComputedStyle,
667 mozilla::PseudoStyleType aPseudoElement,
668 nsPresContext* aPresContext);
669
670 /**
671 * If this frame is a placeholder for a float, then return the float,
672 * otherwise return nullptr. aPlaceholder must be a placeholder frame.
673 */
674 static nsIFrame* GetFloatFromPlaceholder(nsIFrame* aPlaceholder);
675
676 // Combine aNewBreakType with aOrigBreakType, but limit the break types
677 // to StyleClear::Left, Right, Both.
678 static mozilla::StyleClear CombineBreakType(
679 mozilla::StyleClear aOrigBreakType, mozilla::StyleClear aNewBreakType);
680
681 /**
682 * Get the coordinates of a given DOM mouse event, relative to a given
683 * frame. Works only for DOM events generated by WidgetGUIEvents.
684 * @param aDOMEvent the event
685 * @param aFrame the frame to make coordinates relative to
686 * @return the point, or (NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE) if
687 * for some reason the coordinates for the mouse are not known (e.g.,
688 * the event is not a GUI event).
689 */
690 static nsPoint GetDOMEventCoordinatesRelativeTo(
691 mozilla::dom::Event* aDOMEvent, nsIFrame* aFrame);
692
693 /**
694 * Get the coordinates of a given native mouse event, relative to a given
695 * frame.
696 * @param aEvent the event
697 * @param aFrame the frame to make coordinates relative to
698 * @return the point, or (NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE) if
699 * for some reason the coordinates for the mouse are not known (e.g.,
700 * the event is not a GUI event).
701 */
702 static nsPoint GetEventCoordinatesRelativeTo(
703 const mozilla::WidgetEvent* aEvent, RelativeTo aFrame);
704
705 /**
706 * Get the coordinates of a given point relative to an event and a
707 * given frame.
708 * @param aEvent the event
709 * @param aPoint the point to get the coordinates relative to
710 * @param aFrame the frame to make coordinates relative to
711 * @return the point, or (NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE) if
712 * for some reason the coordinates for the mouse are not known (e.g.,
713 * the event is not a GUI event).
714 */
715 static nsPoint GetEventCoordinatesRelativeTo(
716 const mozilla::WidgetEvent* aEvent,
717 const mozilla::LayoutDeviceIntPoint& aPoint, RelativeTo aFrame);
718
719 /**
720 * Get the coordinates of a given point relative to a widget and a
721 * given frame.
722 * @param aWidget the event src widget
723 * @param aPoint the point to get the coordinates relative to
724 * @param aFrame the frame to make coordinates relative to
725 * @return the point, or (NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE) if
726 * for some reason the coordinates for the mouse are not known (e.g.,
727 * the event is not a GUI event).
728 */
729 static nsPoint GetEventCoordinatesRelativeTo(
730 nsIWidget* aWidget, const mozilla::LayoutDeviceIntPoint& aPoint,
731 RelativeTo aFrame);
732
733 /**
734 * Get the popup frame of a given native mouse event.
735 * @param aRootPresContext only check popups within aRootPresContext or a
736 * descendant
737 * @param aEvent the event.
738 * @return Null, if there is no popup frame at the point, otherwise,
739 * returns top-most popup frame at the point.
740 */
741 static nsIFrame* GetPopupFrameForEventCoordinates(
742 nsPresContext* aRootPresContext, const mozilla::WidgetEvent* aEvent);
743
744 /**
745 * Get the popup frame of a given point relative to a widget.
746 * @param aRootPresContext only check popups within aRootPresContext or a
747 * descendant
748 * @param aEvent the event.
749 * @return Null, if there is no popup frame at the point, otherwise,
750 * returns top-most popup frame at the point.
751 */
752 static nsIFrame* GetPopupFrameForPoint(
753 nsPresContext* aRootPresContext, nsIWidget* aWidget,
754 const mozilla::LayoutDeviceIntPoint& aPoint);
755
756 /**
757 * Get container and offset if aEvent collapses Selection.
758 * @param aPresShell The PresShell handling aEvent.
759 * @param aEvent The event having coordinates where you want to
760 * collapse Selection.
761 * @param aContainer Returns the container node at the point.
762 * Set nullptr if you don't need this.
763 * @param aOffset Returns offset in the container node at the point.
764 * Set nullptr if you don't need this.
765 */
766 MOZ_CAN_RUN_SCRIPT
767 static void GetContainerAndOffsetAtEvent(PresShell* aPresShell,
768 const mozilla::WidgetEvent* aEvent,
769 nsIContent** aContainer,
770 int32_t* aOffset);
771
772 /**
773 * Translate from widget coordinates to the view's coordinates
774 * @param aPresContext the PresContext for the view
775 * @param aWidget the widget
776 * @param aPt the point relative to the widget
777 * @param aView view to which returned coordinates are relative
778 * @return the point in the view's coordinates
779 */
780 static nsPoint TranslateWidgetToView(nsPresContext* aPresContext,
781 nsIWidget* aWidget,
782 const mozilla::LayoutDeviceIntPoint& aPt,
783 nsView* aView);
784
785 /**
786 * Translate from view coordinates to the widget's coordinates.
787 * @param aPresContext the PresContext for the view
788 * @param aView the view
789 * @param aPt the point relative to the view
790 * @param aViewportType whether the point is in visual or layout coordinates
791 * @param aWidget the widget to which returned coordinates are relative
792 * @return the point in the view's coordinates
793 */
794 static mozilla::LayoutDeviceIntPoint TranslateViewToWidget(
795 nsPresContext* aPresContext, nsView* aView, nsPoint aPt,
796 ViewportType aViewportType, nsIWidget* aWidget);
797
798 static mozilla::LayoutDeviceIntPoint WidgetToWidgetOffset(
799 nsIWidget* aFromWidget, nsIWidget* aToWidget);
800
801 enum class FrameForPointOption {
802 /**
803 * When set, paint suppression is ignored, so we'll return non-root page
804 * elements even if paint suppression is stopping them from painting.
805 */
806 IgnorePaintSuppression = 1,
807 /**
808 * When set, clipping due to the root scroll frame (and any other viewport-
809 * related clipping) is ignored.
810 */
811 IgnoreRootScrollFrame,
812 /**
813 * When set, return only content in the same document as aFrame.
814 */
815 IgnoreCrossDoc,
816 /**
817 * When set, return only content that is actually visible.
818 */
819 OnlyVisible,
820 };
821
822 struct FrameForPointOptions {
823 using Bits = mozilla::EnumSet<FrameForPointOption>;
824
825 Bits mBits;
826 // If mBits contains OnlyVisible, what is the opacity threshold which we
827 // consider "opaque enough" to clobber stuff underneath.
828 float mVisibleThreshold;
829
FrameForPointOptionsFrameForPointOptions830 FrameForPointOptions(Bits aBits, float aVisibleThreshold)
831 : mBits(aBits), mVisibleThreshold(aVisibleThreshold){};
832
FrameForPointOptionsFrameForPointOptions833 MOZ_IMPLICIT FrameForPointOptions(Bits aBits)
834 : FrameForPointOptions(aBits, 1.0f) {}
835
FrameForPointOptionsFrameForPointOptions836 FrameForPointOptions() : FrameForPointOptions(Bits()){};
837 };
838
839 /**
840 * Given aFrame, the root frame of a stacking context, find its descendant
841 * frame under the point aPt that receives a mouse event at that location,
842 * or nullptr if there is no such frame.
843 * @param aPt the point, relative to the frame origin, in either visual
844 * or layout coordinates depending on aRelativeTo.mViewportType
845 */
846 static nsIFrame* GetFrameForPoint(RelativeTo aRelativeTo, nsPoint aPt,
847 const FrameForPointOptions& = {});
848
849 /**
850 * Given aFrame, the root frame of a stacking context, find all descendant
851 * frames under the area of a rectangle that receives a mouse event,
852 * or nullptr if there is no such frame.
853 * @param aRect the rect, relative to the frame origin, in either visual
854 * or layout coordinates depending on aRelativeTo.mViewportType
855 * @param aOutFrames an array to add all the frames found
856 */
857 static nsresult GetFramesForArea(RelativeTo aRelativeTo, const nsRect& aRect,
858 nsTArray<nsIFrame*>& aOutFrames,
859 const FrameForPointOptions& = {});
860
861 /**
862 * Transform aRect relative to aFrame up to the coordinate system of
863 * aAncestor. Computes the bounding-box of the true quadrilateral.
864 * Pass non-null aPreservesAxisAlignedRectangles and it will be set to true if
865 * we only need to use a 2d transform that PreservesAxisAlignedRectangles().
866 * The corner positions of aRect are treated as meaningful even if aRect is
867 * empty.
868 *
869 * |aMatrixCache| allows for optimizations in recomputing the same matrix over
870 * and over. The argument can be one of the following values:
871 *
872 * nullptr (the default) - No optimization; the transform matrix is computed
873 * on every call to this function.
874 *
875 * non-null pointer to an empty Maybe<Matrix4x4> - Upon return, the Maybe is
876 * filled with the transform matrix that was computed. This can then be passed
877 * in to subsequent calls with the same source and destination frames to avoid
878 * recomputing the matrix.
879 *
880 * non-null pointer to a non-empty Matrix4x4 - The provided matrix will be
881 * used as the transform matrix and applied to the rect.
882 */
883 static nsRect TransformFrameRectToAncestor(
884 const nsIFrame* aFrame, const nsRect& aRect, const nsIFrame* aAncestor,
885 bool* aPreservesAxisAlignedRectangles = nullptr,
886 mozilla::Maybe<Matrix4x4Flagged>* aMatrixCache = nullptr,
887 bool aStopAtStackingContextAndDisplayPortAndOOFFrame = false,
888 nsIFrame** aOutAncestor = nullptr) {
889 return TransformFrameRectToAncestor(
890 aFrame, aRect, RelativeTo{aAncestor}, aPreservesAxisAlignedRectangles,
891 aMatrixCache, aStopAtStackingContextAndDisplayPortAndOOFFrame,
892 aOutAncestor);
893 }
894 static nsRect TransformFrameRectToAncestor(
895 const nsIFrame* aFrame, const nsRect& aRect, RelativeTo aAncestor,
896 bool* aPreservesAxisAlignedRectangles = nullptr,
897 mozilla::Maybe<Matrix4x4Flagged>* aMatrixCache = nullptr,
898 bool aStopAtStackingContextAndDisplayPortAndOOFFrame = false,
899 nsIFrame** aOutAncestor = nullptr);
900
901 /**
902 * Gets the transform for aFrame relative to aAncestor. Pass null for
903 * aAncestor to go up to the root frame. Including nsIFrame::IN_CSS_UNITS
904 * flag in aFlags will return CSS pixels, by default it returns device
905 * pixels.
906 * More info can be found in nsIFrame::GetTransformMatrix.
907 *
908 * Some notes on the possible combinations of |aFrame.mViewportType| and
909 * |aAncestor.mViewportType|:
910 *
911 * | aFrame. | aAncestor. | Notes
912 * | mViewportType | mViewportType |
913 * ==========================================================================
914 * | Layout | Layout | Commonplace, when both source and target
915 * | | | are inside zoom boundary.
916 * | | |
917 * | | | Could also happen in non-e10s setups
918 * | | | when both source and target are outside
919 * | | | the zoom boundary and the code is
920 * | | | oblivious to the existence of a zoom
921 * | | | boundary.
922 * ==========================================================================
923 * | Layout | Visual | Commonplace, used when hit testing visual
924 * | | | coordinates (e.g. coming from user input
925 * | | | events). We expected to encounter a
926 * | | | zoomed content root during traversal and
927 * | | | apply a layout-to-visual transform.
928 * ==========================================================================
929 * | Visual | Layout | Should never happen, will assert.
930 * ==========================================================================
931 * | Visual | Visual | In e10s setups, should only happen if
932 * | | | aFrame and aAncestor are both the
933 * | | | RCD viewport frame.
934 * | | |
935 * | | | In non-e10s setups, could happen with
936 * | | | different frames if they are both
937 * | | | outside the zoom boundary.
938 * ==========================================================================
939 */
940 static Matrix4x4Flagged GetTransformToAncestor(
941 RelativeTo aFrame, RelativeTo aAncestor, uint32_t aFlags = 0,
942 nsIFrame** aOutAncestor = nullptr);
943
944 /**
945 * Gets the scale factors of the transform for aFrame relative to the root
946 * frame if this transform can be drawn 2D, or the identity scale factors
947 * otherwise.
948 */
949 static gfxSize GetTransformToAncestorScale(const nsIFrame* aFrame);
950
951 /**
952 * Gets the scale factors of the transform for aFrame relative to the root
953 * frame if this transform is 2D, or the identity scale factors otherwise.
954 * If some frame on the path from aFrame to the display root frame may have an
955 * animated scale, returns the identity scale factors.
956 */
957 static gfxSize GetTransformToAncestorScaleExcludingAnimated(nsIFrame* aFrame);
958
959 /**
960 * Gets a scale that includes CSS transforms in this process as well as the
961 * transform to ancestor scale passed down from our direct ancestor process
962 * (which includes any enclosing CSS transforms and resolution). Note: this
963 * does not include any resolution in the current process (this is on purpose
964 * because that is what the transform to ancestor field on FrameMetrics needs,
965 * see its definition for explanation as to why). This is the transform to
966 * ancestor scale to set on FrameMetrics.
967 */
968 static mozilla::ParentLayerToScreenScale2D
969 GetTransformToAncestorScaleCrossProcessForFrameMetrics(
970 const nsIFrame* aFrame);
971
972 /**
973 * Find the nearest common ancestor frame for aFrame1 and aFrame2. The
974 * ancestor frame could be cross-doc.
975 */
976 static const nsIFrame* FindNearestCommonAncestorFrame(
977 const nsIFrame* aFrame1, const nsIFrame* aFrame2);
978
979 /**
980 * Find the nearest common ancestor frame for aFrame1 and aFrame2, assuming
981 * that they are within the same block.
982 *
983 * Returns null if they are not within the same block.
984 */
985 static const nsIFrame* FindNearestCommonAncestorFrameWithinBlock(
986 const nsTextFrame* aFrame1, const nsTextFrame* aFrame2);
987
988 /**
989 * Whether author-specified borders / backgrounds disable theming for a given
990 * appearance value.
991 */
992 static bool AuthorSpecifiedBorderBackgroundDisablesTheming(
993 mozilla::StyleAppearance);
994
995 /**
996 * Transforms a list of CSSPoints from aFromFrame to aToFrame, taking into
997 * account all relevant transformations on the frames up to (but excluding)
998 * their nearest common ancestor.
999 * If we encounter a transform that we need to invert but which is
1000 * non-invertible, we return NONINVERTIBLE_TRANSFORM. If the frames have
1001 * no common ancestor, we return NO_COMMON_ANCESTOR.
1002 * If this returns TRANSFORM_SUCCEEDED, the points in aPoints are transformed
1003 * in-place, otherwise they are untouched.
1004 */
1005 enum TransformResult {
1006 TRANSFORM_SUCCEEDED,
1007 NO_COMMON_ANCESTOR,
1008 NONINVERTIBLE_TRANSFORM
1009 };
1010 static TransformResult TransformPoints(RelativeTo aFromFrame,
1011 RelativeTo aToFrame,
1012 uint32_t aPointCount,
1013 CSSPoint* aPoints);
1014
1015 /**
1016 * Same as above function, but transform points in app units and
1017 * handle 1 point per call.
1018 */
1019 static TransformResult TransformPoint(RelativeTo aFromFrame,
1020 RelativeTo aToFrame, nsPoint& aPoint);
1021
1022 /**
1023 * Transforms a rect from aFromFrame to aToFrame. In app units.
1024 * Returns the bounds of the actual rect if the transform requires rotation
1025 * or anything complex like that.
1026 */
1027 static TransformResult TransformRect(const nsIFrame* aFromFrame,
1028 const nsIFrame* aToFrame, nsRect& aRect);
1029
1030 /**
1031 * Converts app units to pixels (with optional snapping) and appends as a
1032 * translation to aTransform.
1033 */
1034 static void PostTranslate(Matrix4x4& aTransform, const nsPoint& aOrigin,
1035 float aAppUnitsPerPixel, bool aRounded);
1036
1037 /*
1038 * Whether the frame should snap to grid. This will end up being passed
1039 * as the aRounded parameter in PostTranslate above. SVG frames should
1040 * not have their translation rounded.
1041 */
1042 static bool ShouldSnapToGrid(const nsIFrame* aFrame);
1043
1044 /**
1045 * Get the border-box of aElement's primary frame, transformed it to be
1046 * relative to aFrame.
1047 */
1048 static nsRect GetRectRelativeToFrame(mozilla::dom::Element* aElement,
1049 nsIFrame* aFrame);
1050
1051 /**
1052 * Returns true if aRect with border inflation of size aInflateSize contains
1053 * aPoint.
1054 */
1055 static bool ContainsPoint(const nsRect& aRect, const nsPoint& aPoint,
1056 nscoord aInflateSize);
1057
1058 /**
1059 * Clamp aRect relative to aFrame to the scroll frames boundary searching from
1060 * aFrame.
1061 */
1062 static nsRect ClampRectToScrollFrames(nsIFrame* aFrame, const nsRect& aRect);
1063
1064 /**
1065 * Return true if a "layer transform" could be computed for aFrame,
1066 * and optionally return the computed transform. The returned
1067 * transform is what would be set on the layer currently if a layers
1068 * transaction were opened at the time this helper is called.
1069 */
1070 static bool GetLayerTransformForFrame(nsIFrame* aFrame,
1071 Matrix4x4Flagged* aTransform);
1072
1073 /**
1074 * Given a point in the global coordinate space, returns that point expressed
1075 * in the coordinate system of aFrame. This effectively inverts all
1076 * transforms between this point and the root frame.
1077 *
1078 * @param aFromType Specifies whether |aPoint| is in layout or visual
1079 * coordinates.
1080 * @param aFrame The frame that acts as the coordinate space container.
1081 * @param aPoint The point, in global layout or visual coordinates (as per
1082 * |aFromType|, to get in the frame-local space.
1083 * @return aPoint, expressed in aFrame's canonical coordinate space.
1084 */
TransformRootPointToFrame(ViewportType aFromType,RelativeTo aFrame,const nsPoint & aPoint)1085 static nsPoint TransformRootPointToFrame(ViewportType aFromType,
1086 RelativeTo aFrame,
1087 const nsPoint& aPoint) {
1088 return TransformAncestorPointToFrame(aFrame, aPoint,
1089 RelativeTo{nullptr, aFromType});
1090 }
1091
1092 /**
1093 * Transform aPoint relative to aAncestor down to the coordinate system of
1094 * aFrame.
1095 */
1096 static nsPoint TransformAncestorPointToFrame(RelativeTo aFrame,
1097 const nsPoint& aPoint,
1098 RelativeTo aAncestor);
1099
1100 /**
1101 * Helper function that, given a rectangle and a matrix, returns the smallest
1102 * rectangle containing the image of the source rectangle.
1103 *
1104 * @param aBounds The rectangle to transform.
1105 * @param aMatrix The matrix to transform it with.
1106 * @param aFactor The number of app units per graphics unit.
1107 * @return The smallest rect that contains the image of aBounds.
1108 */
1109 static nsRect MatrixTransformRect(const nsRect& aBounds,
1110 const Matrix4x4& aMatrix, float aFactor);
1111 static nsRect MatrixTransformRect(const nsRect& aBounds,
1112 const Matrix4x4Flagged& aMatrix,
1113 float aFactor);
1114
1115 /**
1116 * Helper function that, given a point and a matrix, returns the image
1117 * of that point under the matrix transform.
1118 *
1119 * @param aPoint The point to transform.
1120 * @param aMatrix The matrix to transform it with.
1121 * @param aFactor The number of app units per graphics unit.
1122 * @return The image of the point under the transform.
1123 */
1124 static nsPoint MatrixTransformPoint(const nsPoint& aPoint,
1125 const Matrix4x4& aMatrix, float aFactor);
1126
1127 /**
1128 * Given a graphics rectangle in graphics space, return a rectangle in
1129 * app space that contains the graphics rectangle, rounding out as necessary.
1130 *
1131 * @param aRect The graphics rect to round outward.
1132 * @param aFactor The number of app units per graphics unit.
1133 * @return The smallest rectangle in app space that contains aRect.
1134 */
1135 template <typename T>
1136 static nsRect RoundGfxRectToAppRect(const T& aRect, const float aFactor);
1137
1138 /**
1139 * Returns a subrectangle of aContainedRect that is entirely inside the
1140 * rounded rect. Complex cases are handled conservatively by returning a
1141 * smaller rect than necessary.
1142 */
1143 static nsRegion RoundedRectIntersectRect(const nsRect& aRoundedRect,
1144 const nscoord aRadii[8],
1145 const nsRect& aContainedRect);
1146 static nsIntRegion RoundedRectIntersectIntRect(
1147 const nsIntRect& aRoundedRect, const RectCornerRadii& aCornerRadii,
1148 const nsIntRect& aContainedRect);
1149
1150 /**
1151 * Return whether any part of aTestRect is inside of the rounded
1152 * rectangle formed by aBounds and aRadii (which are indexed by the
1153 * enum HalfCorner constants in gfx/2d/Types.h). This is precise.
1154 */
1155 static bool RoundedRectIntersectsRect(const nsRect& aRoundedRect,
1156 const nscoord aRadii[8],
1157 const nsRect& aTestRect);
1158
1159 enum class PaintFrameFlags : uint32_t {
1160 InTransform = 0x01,
1161 SyncDecodeImages = 0x02,
1162 WidgetLayers = 0x04,
1163 IgnoreSuppression = 0x08,
1164 DocumentRelative = 0x10,
1165 HideCaret = 0x20,
1166 ToWindow = 0x40,
1167 ExistingTransaction = 0x80,
1168 ForWebRender = 0x100,
1169 UseHighQualityScaling = 0x200,
1170 ResetViewportScrolling = 0x400,
1171 };
1172
1173 /**
1174 * Given aFrame, the root frame of a stacking context, paint it and its
1175 * descendants to aRenderingContext.
1176 * @param aRenderingContext a rendering context translated so that (0,0)
1177 * is the origin of aFrame; for best results, (0,0) should transform
1178 * to pixel-aligned coordinates. This can be null, in which case
1179 * aFrame must be a "display root" (root frame for a root document,
1180 * or the root of a popup) with an associated widget and we draw using
1181 * the layer manager for the frame's widget.
1182 * @param aDirtyRegion the region that must be painted, in the coordinates
1183 * of aFrame.
1184 * @param aBackstop paint the dirty area with this color before drawing
1185 * the actual content; pass NS_RGBA(0,0,0,0) to draw no background.
1186 * @param aBuilderMode Passed through to the display-list builder.
1187 * @param aFlags if PAINT_IN_TRANSFORM is set, then we assume
1188 * this is inside a transform or SVG foreignObject. If
1189 * PAINT_SYNC_DECODE_IMAGES is set, we force synchronous decode on all
1190 * images. If PAINT_WIDGET_LAYERS is set, aFrame must be a display root,
1191 * and we will use the frame's widget's layer manager to paint
1192 * even if aRenderingContext is non-null. This is useful if you want
1193 * to force rendering to use the widget's layer manager for testing
1194 * or speed. PAINT_WIDGET_LAYERS must be set if aRenderingContext is null.
1195 * If PAINT_DOCUMENT_RELATIVE is used, the visible region is interpreted
1196 * as being relative to the document (normally it's relative to the CSS
1197 * viewport) and the document is painted as if no scrolling has occured.
1198 * Only considered if PresShell::IgnoringViewportScrolling is true.
1199 * If ResetViewportScrolling is used, then the root scroll frame's scroll
1200 * position is set to 0 during painting, so that position:fixed elements
1201 * are drawn in their initial position.
1202 * PAINT_TO_WINDOW sets painting to window to true on the display list
1203 * builder even if we can't tell that we are painting to the window.
1204 * If PAINT_EXISTING_TRANSACTION is set, then BeginTransaction() has already
1205 * been called on aFrame's widget's layer manager and should not be
1206 * called again.
1207 * If PAINT_COMPRESSED is set, the FrameLayerBuilder should be set to
1208 * compressed mode to avoid short cut optimizations.
1209 *
1210 * So there are three possible behaviours:
1211 * 1) PAINT_WIDGET_LAYERS is set and aRenderingContext is null; we paint
1212 * by calling BeginTransaction on the widget's layer manager.
1213 * 2) PAINT_WIDGET_LAYERS is set and aRenderingContext is non-null; we
1214 * paint by calling BeginTransactionWithTarget on the widget's layer
1215 * manager.
1216 * 3) PAINT_WIDGET_LAYERS is not set and aRenderingContext is non-null;
1217 * we paint by construct a BasicLayerManager and calling
1218 * BeginTransactionWithTarget on it. This is desirable if we're doing
1219 * something like drawWindow in a mode where what gets rendered doesn't
1220 * necessarily correspond to what's visible in the window; we don't
1221 * want to mess up the widget's layer tree.
1222 */
1223 static void PaintFrame(gfxContext* aRenderingContext, nsIFrame* aFrame,
1224 const nsRegion& aDirtyRegion, nscolor aBackstop,
1225 nsDisplayListBuilderMode aBuilderMode,
1226 PaintFrameFlags aFlags = PaintFrameFlags(0));
1227
1228 /**
1229 * Uses a binary search for find where the cursor falls in the line of text
1230 * It also keeps track of the part of the string that has already been
1231 * measured so it doesn't have to keep measuring the same text over and over.
1232 *
1233 * @param "aBaseWidth" contains the width in twips of the portion
1234 * of the text that has already been measured, and aBaseInx contains
1235 * the index of the text that has already been measured.
1236 *
1237 * @param aTextWidth returns (in twips) the length of the text that falls
1238 * before the cursor aIndex contains the index of the text where the cursor
1239 * falls.
1240 */
1241 static bool BinarySearchForPosition(DrawTarget* aDrawTarget,
1242 nsFontMetrics& aFontMetrics,
1243 const char16_t* aText, int32_t aBaseWidth,
1244 int32_t aBaseInx, int32_t aStartInx,
1245 int32_t aEndInx, int32_t aCursorPos,
1246 int32_t& aIndex, int32_t& aTextWidth);
1247
1248 class BoxCallback {
1249 public:
1250 BoxCallback() = default;
1251 virtual void AddBox(nsIFrame* aFrame) = 0;
1252 bool mIncludeCaptionBoxForTable = true;
1253 // Whether we are in a continuation or ib-split-sibling of the target we're
1254 // measuring. This is useful because if we know we're in the target subtree
1255 // and measuring against it we can avoid finding the common ancestor.
1256 bool mInTargetContinuation = false;
1257 };
1258 /**
1259 * Collect all CSS boxes associated with aFrame and its
1260 * continuations, "drilling down" through table wrapper frames and
1261 * some anonymous blocks since they're not real CSS boxes.
1262 * If aFrame is null, no boxes are returned.
1263 * SVG frames return a single box, themselves.
1264 */
1265 static void GetAllInFlowBoxes(nsIFrame* aFrame, BoxCallback* aCallback);
1266
1267 /**
1268 * Like GetAllInFlowBoxes, but doesn't include continuations.
1269 */
1270 static void AddBoxesForFrame(nsIFrame* aFrame, BoxCallback* aCallback);
1271
1272 /**
1273 * Find the first frame descendant of aFrame (including aFrame) which is
1274 * not an anonymous frame that getBoxQuads/getClientRects should ignore.
1275 */
1276 static nsIFrame* GetFirstNonAnonymousFrame(nsIFrame* aFrame);
1277
1278 struct RectAccumulator : public mozilla::RectCallback {
1279 nsRect mResultRect;
1280 nsRect mFirstRect;
1281 bool mSeenFirstRect;
1282
1283 RectAccumulator();
1284
1285 virtual void AddRect(const nsRect& aRect) override;
1286 };
1287
1288 struct RectListBuilder : public mozilla::RectCallback {
1289 DOMRectList* mRectList;
1290
1291 explicit RectListBuilder(DOMRectList* aList);
1292 virtual void AddRect(const nsRect& aRect) override;
1293 };
1294
1295 static nsIFrame* GetContainingBlockForClientRect(nsIFrame* aFrame);
1296
1297 enum {
1298 RECTS_ACCOUNT_FOR_TRANSFORMS = 0x01,
1299 // Two bits for specifying which box type to use.
1300 // With neither bit set (default), use the border box.
1301 RECTS_USE_CONTENT_BOX = 0x02,
1302 RECTS_USE_PADDING_BOX = 0x04,
1303 RECTS_USE_MARGIN_BOX = 0x06, // both bits set
1304 RECTS_WHICH_BOX_MASK = 0x06 // bitmask for these two bits
1305 };
1306 /**
1307 * Collect all CSS boxes (content, padding, border, or margin) associated
1308 * with aFrame and its continuations, "drilling down" through table wrapper
1309 * frames and some anonymous blocks since they're not real CSS boxes.
1310 * The boxes are positioned relative to aRelativeTo (taking scrolling
1311 * into account) and passed to the callback in frame-tree order.
1312 * If aFrame is null, no boxes are returned.
1313 * For SVG frames, returns one rectangle, the bounding box.
1314 * If aFlags includes RECTS_ACCOUNT_FOR_TRANSFORMS, then when converting
1315 * the boxes into aRelativeTo coordinates, transforms (including CSS
1316 * and SVG transforms) are taken into account.
1317 * If aFlags includes one of RECTS_USE_CONTENT_BOX, RECTS_USE_PADDING_BOX,
1318 * or RECTS_USE_MARGIN_BOX, the corresponding type of box is used.
1319 * Otherwise (by default), the border box is used.
1320 */
1321 static void GetAllInFlowRects(nsIFrame* aFrame, const nsIFrame* aRelativeTo,
1322 mozilla::RectCallback* aCallback,
1323 uint32_t aFlags = 0);
1324
1325 static void GetAllInFlowRectsAndTexts(
1326 nsIFrame* aFrame, const nsIFrame* aRelativeTo,
1327 mozilla::RectCallback* aCallback,
1328 mozilla::dom::Sequence<nsString>* aTextList, uint32_t aFlags = 0);
1329
1330 /**
1331 * Computes the union of all rects returned by GetAllInFlowRects. If
1332 * the union is empty, returns the first rect.
1333 * If aFlags includes RECTS_ACCOUNT_FOR_TRANSFORMS, then when converting
1334 * the boxes into aRelativeTo coordinates, transforms (including CSS
1335 * and SVG transforms) are taken into account.
1336 * If aFlags includes one of RECTS_USE_CONTENT_BOX, RECTS_USE_PADDING_BOX,
1337 * or RECTS_USE_MARGIN_BOX, the corresponding type of box is used.
1338 * Otherwise (by default), the border box is used.
1339 */
1340 static nsRect GetAllInFlowRectsUnion(nsIFrame* aFrame,
1341 const nsIFrame* aRelativeTo,
1342 uint32_t aFlags = 0);
1343
1344 enum { EXCLUDE_BLUR_SHADOWS = 0x01 };
1345 /**
1346 * Takes a text-shadow array from the style properties of a given nsIFrame and
1347 * computes the union of those shadows along with the given initial rect.
1348 * If there are no shadows, the initial rect is returned.
1349 */
1350 static nsRect GetTextShadowRectsUnion(const nsRect& aTextAndDecorationsRect,
1351 nsIFrame* aFrame, uint32_t aFlags = 0);
1352
1353 /**
1354 * Computes the destination rect that a given replaced element should render
1355 * into, based on its CSS 'object-fit' and 'object-position' properties.
1356 *
1357 * @param aConstraintRect The constraint rect that we have at our disposal,
1358 * which would e.g. be exactly filled by the image
1359 * if we had "object-fit: fill".
1360 * @param aIntrinsicSize The replaced content's intrinsic size, as reported
1361 * by nsIFrame::GetIntrinsicSize().
1362 * @param aIntrinsicRatio The replaced content's intrinsic ratio, as reported
1363 * by nsIFrame::GetIntrinsicRatio().
1364 * @param aStylePos The nsStylePosition struct that contains the 'object-fit'
1365 * and 'object-position' values that we should rely on.
1366 * (This should usually be the nsStylePosition for the
1367 * replaced element in question, but not always. For
1368 * example, a <video>'s poster-image has a dedicated
1369 * anonymous element & child-frame, but we should still use
1370 * the <video>'s 'object-fit' and 'object-position' values.)
1371 * @param aAnchorPoint [out] A point that should be pixel-aligned by functions
1372 * like nsLayoutUtils::DrawImage. See documentation
1373 * in nsCSSRendering.h for ComputeObjectAnchorPoint.
1374 * @return The nsRect into which we should render the replaced content (using
1375 * the same coordinate space as the passed-in aConstraintRect).
1376 */
1377 static nsRect ComputeObjectDestRect(const nsRect& aConstraintRect,
1378 const IntrinsicSize& aIntrinsicSize,
1379 const AspectRatio& aIntrinsicRatio,
1380 const nsStylePosition* aStylePos,
1381 nsPoint* aAnchorPoint = nullptr);
1382
1383 /**
1384 * Get the font metrics corresponding to the frame's style data.
1385 * @param aFrame the frame
1386 * @param aSizeInflation number to multiply font size by
1387 */
1388 static already_AddRefed<nsFontMetrics> GetFontMetricsForFrame(
1389 const nsIFrame* aFrame, float aSizeInflation);
1390
GetInflatedFontMetricsForFrame(const nsIFrame * aFrame)1391 static already_AddRefed<nsFontMetrics> GetInflatedFontMetricsForFrame(
1392 const nsIFrame* aFrame) {
1393 return GetFontMetricsForFrame(aFrame, FontSizeInflationFor(aFrame));
1394 }
1395
1396 /**
1397 * Get the font metrics corresponding to the given style data.
1398 * @param aComputedStyle the style data
1399 * @param aSizeInflation number to multiply font size by
1400 */
1401 static already_AddRefed<nsFontMetrics> GetFontMetricsForComputedStyle(
1402 ComputedStyle* aComputedStyle, nsPresContext* aPresContext,
1403 float aSizeInflation = 1.0f,
1404 uint8_t aVariantWidth = NS_FONT_VARIANT_WIDTH_NORMAL);
1405
1406 /**
1407 * Get the font metrics of emphasis marks corresponding to the given
1408 * style data. The result is same as GetFontMetricsForComputedStyle
1409 * except that the font size is scaled down to 50%.
1410 * @param aComputedStyle the style data
1411 * @param aInflation number to multiple font size by
1412 */
GetFontMetricsOfEmphasisMarks(ComputedStyle * aComputedStyle,nsPresContext * aPresContext,float aInflation)1413 static already_AddRefed<nsFontMetrics> GetFontMetricsOfEmphasisMarks(
1414 ComputedStyle* aComputedStyle, nsPresContext* aPresContext,
1415 float aInflation) {
1416 return GetFontMetricsForComputedStyle(aComputedStyle, aPresContext,
1417 aInflation * 0.5f);
1418 }
1419
1420 /**
1421 * Find the immediate child of aParent whose frame subtree contains
1422 * aDescendantFrame. Returns null if aDescendantFrame is not a descendant
1423 * of aParent.
1424 */
1425 static nsIFrame* FindChildContainingDescendant(nsIFrame* aParent,
1426 nsIFrame* aDescendantFrame);
1427
1428 /**
1429 * Find the nearest ancestor that's a block
1430 */
1431 static nsBlockFrame* FindNearestBlockAncestor(nsIFrame* aFrame);
1432
1433 /**
1434 * Find the nearest ancestor that's not for generated content. Will return
1435 * aFrame if aFrame is not for generated content.
1436 */
1437 static nsIFrame* GetNonGeneratedAncestor(nsIFrame* aFrame);
1438
1439 /*
1440 * Whether the frame is an nsBlockFrame which is not a wrapper block.
1441 */
1442 static bool IsNonWrapperBlock(nsIFrame* aFrame);
1443
1444 /**
1445 * If aFrame is an out of flow frame, return its placeholder, otherwise
1446 * return its parent.
1447 */
1448 static nsIFrame* GetParentOrPlaceholderFor(const nsIFrame* aFrame);
1449
1450 /**
1451 * If aFrame is an out of flow frame, return its placeholder, otherwise
1452 * return its (possibly cross-doc) parent.
1453 */
1454 static nsIFrame* GetParentOrPlaceholderForCrossDoc(const nsIFrame* aFrame);
1455
1456 /**
1457 * Returns the frame that would act as the parent of aFrame when
1458 * descending through the frame tree in display list building.
1459 * Usually the same as GetParentOrPlaceholderForCrossDoc, except
1460 * that pushed floats are treated as children of their containing
1461 * block.
1462 */
1463 static nsIFrame* GetDisplayListParent(nsIFrame* aFrame);
1464
1465 /**
1466 * Get a frame's previous continuation, or, if it doesn't have one, its
1467 * previous block-in-inline-split sibling.
1468 */
1469 static nsIFrame* GetPrevContinuationOrIBSplitSibling(const nsIFrame* aFrame);
1470
1471 /**
1472 * Get a frame's next continuation, or, if it doesn't have one, its
1473 * block-in-inline-split sibling.
1474 */
1475 static nsIFrame* GetNextContinuationOrIBSplitSibling(const nsIFrame* aFrame);
1476
1477 /**
1478 * Get the first frame in the continuation-plus-ib-split-sibling chain
1479 * containing aFrame.
1480 */
1481 static nsIFrame* FirstContinuationOrIBSplitSibling(const nsIFrame* aFrame);
1482
1483 /**
1484 * Get the last frame in the continuation-plus-ib-split-sibling chain
1485 * containing aFrame.
1486 */
1487 static nsIFrame* LastContinuationOrIBSplitSibling(const nsIFrame* aFrame);
1488
1489 /**
1490 * Is FirstContinuationOrIBSplitSibling(aFrame) going to return
1491 * aFrame?
1492 */
1493 static bool IsFirstContinuationOrIBSplitSibling(const nsIFrame* aFrame);
1494
1495 /**
1496 * Check whether aFrame is a part of the scrollbar or scrollcorner of
1497 * the root content.
1498 * @param aFrame the checking frame.
1499 * @return true if the frame is a part of the scrollbar or scrollcorner of
1500 * the root content.
1501 */
1502 static bool IsViewportScrollbarFrame(nsIFrame* aFrame);
1503
1504 /**
1505 * Get the contribution of aFrame to its containing block's intrinsic
1506 * size for the given physical axis. This considers the child's intrinsic
1507 * width, its 'width', 'min-width', and 'max-width' properties (or 'height'
1508 * variations if that's what matches aAxis) and its padding, border and margin
1509 * in the corresponding dimension.
1510 * @param aPercentageBasis an optional percentage basis (in aFrame's WM).
1511 * If the basis is indefinite in a given axis, pass a size with
1512 * NS_UNCONSTRAINEDSIZE in that component.
1513 * If you pass Nothing() a percentage basis will be calculated from aFrame's
1514 * ancestors' computed size in the relevant axis, if needed.
1515 * @param aMarginBoxMinSizeClamp make the result fit within this margin-box
1516 * size by reducing the *content size* (flooring at zero). This is used for:
1517 * https://drafts.csswg.org/css-grid/#min-size-auto
1518 */
1519 enum {
1520 IGNORE_PADDING = 0x01,
1521 BAIL_IF_REFLOW_NEEDED = 0x02, // returns NS_INTRINSIC_ISIZE_UNKNOWN if so
1522 MIN_INTRINSIC_ISIZE = 0x04, // use min-width/height instead of width/height
1523 };
1524 static nscoord IntrinsicForAxis(
1525 mozilla::PhysicalAxis aAxis, gfxContext* aRenderingContext,
1526 nsIFrame* aFrame, mozilla::IntrinsicISizeType aType,
1527 const mozilla::Maybe<LogicalSize>& aPercentageBasis = mozilla::Nothing(),
1528 uint32_t aFlags = 0, nscoord aMarginBoxMinSizeClamp = NS_MAXSIZE);
1529 /**
1530 * Calls IntrinsicForAxis with aFrame's parent's inline physical axis.
1531 */
1532 static nscoord IntrinsicForContainer(gfxContext* aRenderingContext,
1533 nsIFrame* aFrame,
1534 mozilla::IntrinsicISizeType aType,
1535 uint32_t aFlags = 0);
1536
1537 /**
1538 * Get the definite size contribution of aFrame for the given physical axis.
1539 * This considers the child's 'min-width' property (or 'min-height' if the
1540 * given axis is vertical), and its padding, border, and margin in the
1541 * corresponding dimension. If the 'min-' property is 'auto' (and 'overflow'
1542 * is 'visible') and the corresponding 'width'/'height' is definite it returns
1543 * the "specified size" for:
1544 * https://drafts.csswg.org/css-grid/#min-size-auto
1545 * Note that the "transferred size" is not handled here; use IntrinsicForAxis.
1546 * Note that any percentage in 'width'/'height' makes it count as indefinite.
1547 * If the 'min-' property is 'auto' and 'overflow' is not 'visible', then it
1548 * calculates the result as if the 'min-' computed value is zero.
1549 * Otherwise, return NS_UNCONSTRAINEDSIZE.
1550 *
1551 * @param aPercentageBasis the percentage basis (in aFrame's WM).
1552 * Pass NS_UNCONSTRAINEDSIZE if the basis is indefinite in either/both axes.
1553 * @note this behavior is specific to Grid/Flexbox (currently) so aFrame
1554 * should be a grid/flex item.
1555 */
1556 static nscoord MinSizeContributionForAxis(mozilla::PhysicalAxis aAxis,
1557 gfxContext* aRC, nsIFrame* aFrame,
1558 mozilla::IntrinsicISizeType aType,
1559 const LogicalSize& aPercentageBasis,
1560 uint32_t aFlags = 0);
1561
1562 /*
1563 * Convert LengthPercentage to nscoord when percentages depend on the
1564 * containing block size.
1565 * @param aPercentBasis The width or height of the containing block
1566 * (whichever the client wants to use for resolving percentages).
1567 */
ComputeCBDependentValue(nscoord aPercentBasis,const LengthPercentage & aCoord)1568 static nscoord ComputeCBDependentValue(nscoord aPercentBasis,
1569 const LengthPercentage& aCoord) {
1570 NS_WARNING_ASSERTION(
1571 aPercentBasis != NS_UNCONSTRAINEDSIZE,
1572 "have unconstrained width or height; this should only result from very "
1573 "large sizes, not attempts at intrinsic size calculation");
1574 return aCoord.Resolve(aPercentBasis);
1575 }
ComputeCBDependentValue(nscoord aPercentBasis,const LengthPercentageOrAuto & aCoord)1576 static nscoord ComputeCBDependentValue(nscoord aPercentBasis,
1577 const LengthPercentageOrAuto& aCoord) {
1578 if (aCoord.IsAuto()) {
1579 return 0;
1580 }
1581 return ComputeCBDependentValue(aPercentBasis, aCoord.AsLengthPercentage());
1582 }
1583
1584 static nscoord ComputeBSizeDependentValue(nscoord aContainingBlockBSize,
1585 const LengthPercentageOrAuto&);
1586
ComputeBSizeValue(nscoord aContainingBlockBSize,nscoord aContentEdgeToBoxSizingBoxEdge,const LengthPercentage & aCoord)1587 static nscoord ComputeBSizeValue(nscoord aContainingBlockBSize,
1588 nscoord aContentEdgeToBoxSizingBoxEdge,
1589 const LengthPercentage& aCoord) {
1590 MOZ_ASSERT(aContainingBlockBSize != nscoord_MAX || !aCoord.HasPercent(),
1591 "caller must deal with %% of unconstrained block-size");
1592
1593 nscoord result = aCoord.Resolve(aContainingBlockBSize);
1594 // Clamp calc(), and the subtraction for box-sizing.
1595 return std::max(0, result - aContentEdgeToBoxSizingBoxEdge);
1596 }
1597
1598 /**
1599 * The "extremum length" values (see ExtremumLength) were originally aimed at
1600 * inline-size (or width, as it was before logicalization). For now, we return
1601 * true for those here, so that we don't call ComputeBSizeValue with value
1602 * types that it doesn't understand. (See bug 1113216.)
1603 *
1604 * FIXME (bug 567039, bug 527285)
1605 * This isn't correct for the 'fill' value or for the 'min-*' or 'max-*'
1606 * properties, which need to be handled differently by the callers of
1607 * IsAutoBSize().
1608 */
1609 template <typename SizeOrMaxSize>
IsAutoBSize(const SizeOrMaxSize & aCoord,nscoord aCBBSize)1610 static bool IsAutoBSize(const SizeOrMaxSize& aCoord, nscoord aCBBSize) {
1611 return aCoord.BehavesLikeInitialValueOnBlockAxis() ||
1612 (aCBBSize == nscoord_MAX && aCoord.HasPercent());
1613 }
1614
IsPaddingZero(const LengthPercentage & aLength)1615 static bool IsPaddingZero(const LengthPercentage& aLength) {
1616 // clamp negative calc() to 0
1617 return aLength.Resolve(nscoord_MAX) <= 0 && aLength.Resolve(0) <= 0;
1618 }
1619
IsMarginZero(const LengthPercentage & aLength)1620 static bool IsMarginZero(const LengthPercentage& aLength) {
1621 return aLength.Resolve(nscoord_MAX) == 0 && aLength.Resolve(0) == 0;
1622 }
1623
1624 static void MarkDescendantsDirty(nsIFrame* aSubtreeRoot);
1625
1626 static void MarkIntrinsicISizesDirtyIfDependentOnBSize(nsIFrame* aFrame);
1627
1628 /*
1629 * Calculate the used values for 'width' and 'height' when width
1630 * and height are 'auto'. The tentWidth and tentHeight arguments should be
1631 * the result of applying the rules for computing intrinsic sizes and ratios.
1632 * as specified by CSS 2.1 sections 10.3.2 and 10.6.2
1633 */
1634 static nsSize ComputeAutoSizeWithIntrinsicDimensions(
1635 nscoord minWidth, nscoord minHeight, nscoord maxWidth, nscoord maxHeight,
1636 nscoord tentWidth, nscoord tentHeight);
1637
1638 // Implement nsIFrame::GetPrefISize in terms of nsIFrame::AddInlinePrefISize
1639 static nscoord PrefISizeFromInline(nsIFrame* aFrame,
1640 gfxContext* aRenderingContext);
1641
1642 // Implement nsIFrame::GetMinISize in terms of nsIFrame::AddInlineMinISize
1643 static nscoord MinISizeFromInline(nsIFrame* aFrame,
1644 gfxContext* aRenderingContext);
1645
1646 // Get a suitable foreground color for painting aColor for aFrame.
1647 static nscolor DarkenColorIfNeeded(nsIFrame* aFrame, nscolor aColor);
1648
1649 // Get a suitable foreground color for painting aField for aFrame.
1650 // Type of aFrame is made a template parameter because nsIFrame is not
1651 // a complete type in the header. Type-safety is not harmed given that
1652 // DarkenColorIfNeeded requires an nsIFrame pointer.
1653 template <typename Frame, typename T, typename S>
GetColor(Frame * aFrame,T S::* aField)1654 static nscolor GetColor(Frame* aFrame, T S::*aField) {
1655 nscolor color = aFrame->GetVisitedDependentColor(aField);
1656 return DarkenColorIfNeeded(aFrame, color);
1657 }
1658
1659 // Get a baseline y position in app units that is snapped to device pixels.
1660 static gfxFloat GetSnappedBaselineY(nsIFrame* aFrame, gfxContext* aContext,
1661 nscoord aY, nscoord aAscent);
1662 // Ditto for an x position (for vertical text). Note that for vertical-rl
1663 // writing mode, the ascent value should be negated by the caller.
1664 static gfxFloat GetSnappedBaselineX(nsIFrame* aFrame, gfxContext* aContext,
1665 nscoord aX, nscoord aAscent);
1666
AppUnitWidthOfString(char16_t aC,nsFontMetrics & aFontMetrics,DrawTarget * aDrawTarget)1667 static nscoord AppUnitWidthOfString(char16_t aC, nsFontMetrics& aFontMetrics,
1668 DrawTarget* aDrawTarget) {
1669 return AppUnitWidthOfString(&aC, 1, aFontMetrics, aDrawTarget);
1670 }
AppUnitWidthOfString(mozilla::Span<const char16_t> aString,nsFontMetrics & aFontMetrics,DrawTarget * aDrawTarget)1671 static nscoord AppUnitWidthOfString(mozilla::Span<const char16_t> aString,
1672 nsFontMetrics& aFontMetrics,
1673 DrawTarget* aDrawTarget) {
1674 return nsLayoutUtils::AppUnitWidthOfString(
1675 aString.Elements(), aString.Length(), aFontMetrics, aDrawTarget);
1676 }
1677 static nscoord AppUnitWidthOfString(const char16_t* aString, uint32_t aLength,
1678 nsFontMetrics& aFontMetrics,
1679 DrawTarget* aDrawTarget);
AppUnitWidthOfStringBidi(const nsString & aString,const nsIFrame * aFrame,nsFontMetrics & aFontMetrics,gfxContext & aContext)1680 static nscoord AppUnitWidthOfStringBidi(const nsString& aString,
1681 const nsIFrame* aFrame,
1682 nsFontMetrics& aFontMetrics,
1683 gfxContext& aContext) {
1684 return nsLayoutUtils::AppUnitWidthOfStringBidi(
1685 aString.get(), aString.Length(), aFrame, aFontMetrics, aContext);
1686 }
1687 static nscoord AppUnitWidthOfStringBidi(const char16_t* aString,
1688 uint32_t aLength,
1689 const nsIFrame* aFrame,
1690 nsFontMetrics& aFontMetrics,
1691 gfxContext& aContext);
1692
1693 static bool StringWidthIsGreaterThan(const nsString& aString,
1694 nsFontMetrics& aFontMetrics,
1695 DrawTarget* aDrawTarget, nscoord aWidth);
1696
1697 static nsBoundingMetrics AppUnitBoundsOfString(const char16_t* aString,
1698 uint32_t aLength,
1699 nsFontMetrics& aFontMetrics,
1700 DrawTarget* aDrawTarget);
1701
1702 static void DrawString(const nsIFrame* aFrame, nsFontMetrics& aFontMetrics,
1703 gfxContext* aContext, const char16_t* aString,
1704 int32_t aLength, nsPoint aPoint,
1705 ComputedStyle* aComputedStyle = nullptr,
1706 DrawStringFlags aFlags = DrawStringFlags::Default);
1707
1708 static nsPoint GetBackgroundFirstTilePos(const nsPoint& aDest,
1709 const nsPoint& aFill,
1710 const nsSize& aRepeatSize);
1711
1712 /**
1713 * Supports only LTR or RTL. Bidi (mixed direction) is not supported.
1714 */
1715 static void DrawUniDirString(const char16_t* aString, uint32_t aLength,
1716 const nsPoint& aPoint,
1717 nsFontMetrics& aFontMetrics,
1718 gfxContext& aContext);
1719
1720 /**
1721 * Helper function for drawing text-shadow. The callback's job
1722 * is to draw whatever needs to be blurred onto the given context.
1723 */
1724 typedef void (*TextShadowCallback)(gfxContext* aCtx, nsPoint aShadowOffset,
1725 const nscolor& aShadowColor, void* aData);
1726
1727 static void PaintTextShadow(const nsIFrame* aFrame, gfxContext* aContext,
1728 const nsRect& aTextRect, const nsRect& aDirtyRect,
1729 const nscolor& aForegroundColor,
1730 TextShadowCallback aCallback,
1731 void* aCallbackData);
1732
1733 /**
1734 * Gets the baseline to vertically center text from a font within a
1735 * line of specified height.
1736 * aIsInverted: true if the text is inverted relative to the block
1737 * direction, so that the block-dir "ascent" corresponds to font
1738 * descent. (Applies to sideways text in vertical-lr mode.)
1739 *
1740 * Returns the baseline position relative to the top of the line.
1741 */
1742 static nscoord GetCenteredFontBaseline(nsFontMetrics* aFontMetrics,
1743 nscoord aLineHeight, bool aIsInverted);
1744
1745 /**
1746 * Derive a baseline of |aFrame| (measured from its top border edge)
1747 * from its first in-flow line box (not descending into anything with
1748 * 'overflow' not 'visible', potentially including aFrame itself).
1749 *
1750 * Returns true if a baseline was found (and fills in aResult).
1751 * Otherwise returns false.
1752 */
1753 static bool GetFirstLineBaseline(mozilla::WritingMode aWritingMode,
1754 const nsIFrame* aFrame, nscoord* aResult);
1755
1756 /**
1757 * Just like GetFirstLineBaseline, except also returns the top and
1758 * bottom of the line with the baseline.
1759 *
1760 * Returns true if a line was found (and fills in aResult).
1761 * Otherwise returns false.
1762 */
1763 struct LinePosition {
1764 nscoord mBStart, mBaseline, mBEnd;
1765
1766 LinePosition operator+(nscoord aOffset) const {
1767 LinePosition result;
1768 result.mBStart = mBStart + aOffset;
1769 result.mBaseline = mBaseline + aOffset;
1770 result.mBEnd = mBEnd + aOffset;
1771 return result;
1772 }
1773 };
1774 static bool GetFirstLinePosition(mozilla::WritingMode aWritingMode,
1775 const nsIFrame* aFrame,
1776 LinePosition* aResult);
1777
1778 /**
1779 * Derive a baseline of |aFrame| (measured from its top border edge)
1780 * from its last in-flow line box (not descending into anything with
1781 * 'overflow' not 'visible', potentially including aFrame itself).
1782 *
1783 * Returns true if a baseline was found (and fills in aResult).
1784 * Otherwise returns false.
1785 */
1786 static bool GetLastLineBaseline(mozilla::WritingMode aWritingMode,
1787 const nsIFrame* aFrame, nscoord* aResult);
1788
1789 /**
1790 * Returns a block-dir coordinate relative to this frame's origin that
1791 * represents the logical block-end of the frame or its visible content,
1792 * whichever is further from the origin.
1793 * Relative positioning is ignored and margins and glyph bounds are not
1794 * considered.
1795 * This value will be >= mRect.BSize() and <= overflowRect.BEnd() unless
1796 * relative positioning is applied.
1797 */
1798 static nscoord CalculateContentBEnd(mozilla::WritingMode aWritingMode,
1799 nsIFrame* aFrame);
1800
1801 /**
1802 * Gets the closest frame (the frame passed in or one of its parents) that
1803 * qualifies as a "layer"; used in DOM0 methods that depends upon that
1804 * definition. This is the nearest frame that is either positioned or scrolled
1805 * (the child of a scroll frame).
1806 */
1807 static nsIFrame* GetClosestLayer(nsIFrame* aFrame);
1808
1809 /**
1810 * Gets the graphics sampling filter for the frame
1811 */
1812 static SamplingFilter GetSamplingFilterForFrame(nsIFrame* aFrame);
1813
InitDashPattern(StrokeOptions & aStrokeOptions,mozilla::StyleBorderStyle aBorderStyle)1814 static inline void InitDashPattern(StrokeOptions& aStrokeOptions,
1815 mozilla::StyleBorderStyle aBorderStyle) {
1816 if (aBorderStyle == mozilla::StyleBorderStyle::Dotted) {
1817 static Float dot[] = {1.f, 1.f};
1818 aStrokeOptions.mDashLength = MOZ_ARRAY_LENGTH(dot);
1819 aStrokeOptions.mDashPattern = dot;
1820 } else if (aBorderStyle == mozilla::StyleBorderStyle::Dashed) {
1821 static Float dash[] = {5.f, 5.f};
1822 aStrokeOptions.mDashLength = MOZ_ARRAY_LENGTH(dash);
1823 aStrokeOptions.mDashPattern = dash;
1824 } else {
1825 aStrokeOptions.mDashLength = 0;
1826 aStrokeOptions.mDashPattern = nullptr;
1827 }
1828 }
1829
1830 /**
1831 * Convert an nsRect to a gfxRect.
1832 */
1833 static gfxRect RectToGfxRect(const nsRect& aRect,
1834 int32_t aAppUnitsPerDevPixel);
1835
PointToGfxPoint(const nsPoint & aPoint,int32_t aAppUnitsPerPixel)1836 static gfxPoint PointToGfxPoint(const nsPoint& aPoint,
1837 int32_t aAppUnitsPerPixel) {
1838 return gfxPoint(gfxFloat(aPoint.x) / aAppUnitsPerPixel,
1839 gfxFloat(aPoint.y) / aAppUnitsPerPixel);
1840 }
1841
1842 /* N.B. The only difference between variants of the Draw*Image
1843 * functions below is the type of the aImage argument.
1844 */
1845
1846 /**
1847 * Draw a background image. The image's dimensions are as specified in aDest;
1848 * the image itself is not consulted to determine a size.
1849 * See https://wiki.mozilla.org/Gecko:Image_Snapping_and_Rendering
1850 *
1851 * @param aContext
1852 * The context to draw to, already set up with an appropriate scale and
1853 * transform for drawing in app units.
1854 * @param aForFrame
1855 * The nsIFrame that we're drawing this image for.
1856 * @param aImage
1857 * The image.
1858 * @param aDest
1859 * The position and scaled area where one copy of the image should be drawn.
1860 * This area represents the image itself in its correct position as defined
1861 * with the background-position css property.
1862 * @param aFill
1863 * The area to be filled with copies of the image.
1864 * @param aRepeatSize
1865 * The distance between the positions of two subsequent repeats of the image.
1866 * Sizes larger than aDest.Size() create gaps between the images.
1867 * @param aAnchor
1868 * A point in aFill which we will ensure is pixel-aligned in the output.
1869 * @param aDirty
1870 * Pixels outside this area may be skipped.
1871 * @param aImageFlags
1872 * Image flags of the imgIContainer::FLAG_* variety.
1873 * @param aExtendMode
1874 * How to extend the image over the dest rect.
1875 */
1876 static ImgDrawResult DrawBackgroundImage(
1877 gfxContext& aContext, nsIFrame* aForFrame, nsPresContext* aPresContext,
1878 imgIContainer* aImage, SamplingFilter aSamplingFilter,
1879 const nsRect& aDest, const nsRect& aFill, const nsSize& aRepeatSize,
1880 const nsPoint& aAnchor, const nsRect& aDirty, uint32_t aImageFlags,
1881 ExtendMode aExtendMode, float aOpacity);
1882
1883 /**
1884 * Draw an image.
1885 * See https://wiki.mozilla.org/Gecko:Image_Snapping_and_Rendering
1886 * @param aRenderingContext Where to draw the image, set up with an
1887 * appropriate scale and transform for drawing in
1888 * app units.
1889 * @param aComputedStyle The ComputedStyle of the nsIFrame (or
1890 * pseudo-element) for which this image is being
1891 * drawn.
1892 * @param aImage The image.
1893 * @param aDest Where one copy of the image should mapped to.
1894 * @param aFill The area to be filled with copies of the
1895 * image.
1896 * @param aAnchor A point in aFill which we will ensure is
1897 * pixel-aligned in the output.
1898 * @param aDirty Pixels outside this area may be skipped.
1899 * @param aImageFlags Image flags of the imgIContainer::FLAG_* variety
1900 */
1901 static ImgDrawResult DrawImage(gfxContext& aContext,
1902 ComputedStyle* aComputedStyle,
1903 nsPresContext* aPresContext,
1904 imgIContainer* aImage,
1905 const SamplingFilter aSamplingFilter,
1906 const nsRect& aDest, const nsRect& aFill,
1907 const nsPoint& aAnchor, const nsRect& aDirty,
1908 uint32_t aImageFlags, float aOpacity = 1.0);
1909
1910 /**
1911 * Draw a whole image without scaling or tiling.
1912 *
1913 * @param aRenderingContext Where to draw the image, set up with an
1914 * appropriate scale and transform for drawing in
1915 * app units.
1916 * @param aImage The image.
1917 * @param aDest The top-left where the image should be drawn.
1918 * @param aDirty If non-null, then pixels outside this area may
1919 * be skipped.
1920 * @param aSVGContext Optionally provides an SVGImageContext.
1921 * Callers should pass an SVGImageContext with at
1922 * least the viewport size set if aImage may be of
1923 * type imgIContainer::TYPE_VECTOR, or pass
1924 * Nothing() if it is of type
1925 * imgIContainer::TYPE_RASTER (to save cycles
1926 * constructing an SVGImageContext, since this
1927 * argument will be ignored for raster images).
1928 * @param aImageFlags Image flags of the imgIContainer::FLAG_* variety
1929 * @param aSourceArea If non-null, this area is extracted from
1930 * the image and drawn at aDest. It's
1931 * in appunits. For best results it should
1932 * be aligned with image pixels.
1933 */
1934 static ImgDrawResult DrawSingleUnscaledImage(
1935 gfxContext& aContext, nsPresContext* aPresContext, imgIContainer* aImage,
1936 const SamplingFilter aSamplingFilter, const nsPoint& aDest,
1937 const nsRect* aDirty, const mozilla::Maybe<SVGImageContext>& aSVGContext,
1938 uint32_t aImageFlags, const nsRect* aSourceArea = nullptr);
1939
1940 /**
1941 * Draw a whole image without tiling.
1942 *
1943 * @param aRenderingContext Where to draw the image, set up with an
1944 * appropriate scale and transform for drawing in
1945 * app units.
1946 * @param aImage The image.
1947 * @param aDest The area that the image should fill.
1948 * @param aDirty Pixels outside this area may be skipped.
1949 * @param aSVGContext Optionally provides an SVGImageContext.
1950 * Callers should pass an SVGImageContext with at
1951 * least the viewport size set if aImage may be of
1952 * type imgIContainer::TYPE_VECTOR, or pass
1953 * Nothing() if it is of type
1954 * imgIContainer::TYPE_RASTER (to save cycles
1955 * constructing an SVGImageContext, since this
1956 * argument will be ignored for raster images).
1957 * @param aImageFlags Image flags of the imgIContainer::FLAG_*
1958 * variety.
1959 * @param aAnchor If non-null, a point which we will ensure
1960 * is pixel-aligned in the output.
1961 * @param aSourceArea If non-null, this area is extracted from
1962 * the image and drawn in aDest. It's
1963 * in appunits. For best results it should
1964 * be aligned with image pixels.
1965 */
1966 static ImgDrawResult DrawSingleImage(
1967 gfxContext& aContext, nsPresContext* aPresContext, imgIContainer* aImage,
1968 SamplingFilter aSamplingFilter, const nsRect& aDest, const nsRect& aDirty,
1969 const mozilla::Maybe<SVGImageContext>& aSVGContext, uint32_t aImageFlags,
1970 const nsPoint* aAnchorPoint = nullptr,
1971 const nsRect* aSourceArea = nullptr);
1972
1973 /**
1974 * Given an imgIContainer, this method attempts to obtain an intrinsic
1975 * px-valued height & width for it. If the imgIContainer has a non-pixel
1976 * value for either height or width, this method tries to generate a pixel
1977 * value for that dimension using the intrinsic ratio (if available). The
1978 * intrinsic ratio will be assigned to aIntrinsicRatio; if there's no
1979 * intrinsic ratio then (0, 0) will be assigned.
1980 *
1981 * This method will always set aGotWidth and aGotHeight to indicate whether
1982 * we were able to successfully obtain (or compute) a value for each
1983 * dimension.
1984 *
1985 * NOTE: This method is similar to ComputeSizeWithIntrinsicDimensions. The
1986 * difference is that this one is simpler and is suited to places where we
1987 * have less information about the frame tree.
1988 *
1989 * @param aResolution The resolution specified by the author for the image, or
1990 * its intrinsic resolution.
1991 *
1992 * This will affect the intrinsic size size of the image
1993 * (so e.g., if resolution is 2, and the image is 100x100,
1994 * the intrinsic size of the image will be 50x50).
1995 */
1996 static void ComputeSizeForDrawing(imgIContainer* aImage,
1997 const mozilla::image::Resolution&,
1998 CSSIntSize& aImageSize,
1999 AspectRatio& aIntrinsicRatio,
2000 bool& aGotWidth, bool& aGotHeight);
2001
2002 /**
2003 * Given an imgIContainer, this method attempts to obtain an intrinsic
2004 * px-valued height & width for it. If the imgIContainer has a non-pixel
2005 * value for either height or width, this method tries to generate a pixel
2006 * value for that dimension using the intrinsic ratio (if available). If,
2007 * after trying all these methods, no value is available for one or both
2008 * dimensions, the corresponding dimension of aFallbackSize is used instead.
2009 */
2010 static CSSIntSize ComputeSizeForDrawingWithFallback(
2011 imgIContainer* aImage, const mozilla::image::Resolution&,
2012 const nsSize& aFallbackSize);
2013
2014 /**
2015 * Given the image container, frame, and dest rect, determine the best fitting
2016 * size to decode the image at, and calculate any necessary SVG parameters.
2017 */
2018 static mozilla::gfx::IntSize ComputeImageContainerDrawingParameters(
2019 imgIContainer* aImage, nsIFrame* aForFrame,
2020 const LayoutDeviceRect& aDestRect, const LayoutDeviceRect& aFillRect,
2021 const StackingContextHelper& aSc, uint32_t aFlags,
2022 mozilla::Maybe<SVGImageContext>& aSVGContext,
2023 mozilla::Maybe<mozilla::image::ImageIntRegion>& aRegion);
2024
2025 /**
2026 * Given a source area of an image (in appunits) and a destination area
2027 * that we want to map that source area too, computes the area that
2028 * would be covered by the whole image. This is useful for passing to
2029 * the aDest parameter of DrawImage, when we want to draw a subimage
2030 * of an overall image.
2031 */
2032 static nsRect GetWholeImageDestination(const nsSize& aWholeImageSize,
2033 const nsRect& aImageSourceArea,
2034 const nsRect& aDestArea);
2035
2036 /**
2037 * Given an image container and an orientation, returns an image container
2038 * that contains the same image, reoriented appropriately. May return the
2039 * original image container if no changes are needed.
2040 *
2041 * @param aContainer The image container to apply the orientation to.
2042 * @param aOrientation The desired orientation.
2043 */
2044 static already_AddRefed<imgIContainer> OrientImage(
2045 imgIContainer* aContainer,
2046 const mozilla::StyleImageOrientation& aOrientation);
2047
2048 /**
2049 * Determine if any corner radius is of nonzero size
2050 * @param aCorners the |BorderRadius| object to check
2051 * @return true unless all the coordinates are 0%, 0 or null.
2052 *
2053 * A corner radius with one dimension zero and one nonzero is
2054 * treated as a nonzero-radius corner, even though it will end up
2055 * being rendered like a zero-radius corner. This is because such
2056 * corners are not expected to appear outside of test cases, and it's
2057 * simpler to implement the test this way.
2058 */
2059 static bool HasNonZeroCorner(const mozilla::BorderRadius& aCorners);
2060
2061 /**
2062 * Determine if there is any corner radius on corners adjacent to the
2063 * given side.
2064 */
2065 static bool HasNonZeroCornerOnSide(const mozilla::BorderRadius& aCorners,
2066 mozilla::Side aSide);
2067
2068 /**
2069 * Return the border radius size (width, height) based only on the top-left
2070 * corner. This is a special case used for drawing the Windows 10 drop-shadow,
2071 * and only supports a specified length (not percentages) on the top-left
2072 * corner.
2073 */
2074 static LayoutDeviceIntSize GetBorderRadiusForMenuDropShadow(
2075 const nsIFrame* aFrame);
2076
2077 /**
2078 * Determine if a widget is likely to require transparency or translucency.
2079 * @param aBackgroundFrame The frame that the background is set on. For
2080 * <window>s, this will be the canvas frame.
2081 * @param aCSSRootFrame The frame that holds CSS properties affecting
2082 * the widget's transparency. For menupopups,
2083 * aBackgroundFrame and aCSSRootFrame will be the
2084 * same.
2085 * @return a value suitable for passing to SetWindowTranslucency.
2086 */
2087 static nsTransparencyMode GetFrameTransparency(nsIFrame* aBackgroundFrame,
2088 nsIFrame* aCSSRootFrame);
2089
2090 /**
2091 * A frame is a popup if it has its own floating window. Menus, panels
2092 * and combobox dropdowns are popups.
2093 */
2094 static bool IsPopup(const nsIFrame* aFrame);
2095
2096 /**
2097 * Find the nearest "display root". This is the nearest enclosing
2098 * popup frame or the root prescontext's root frame.
2099 */
2100 static nsIFrame* GetDisplayRootFrame(nsIFrame* aFrame);
2101 static const nsIFrame* GetDisplayRootFrame(const nsIFrame* aFrame);
2102
2103 /**
2104 * Get the reference frame that would be used when constructing a
2105 * display item for this frame. Rather than using their own frame
2106 * as a reference frame.)
2107 *
2108 * This duplicates some of the logic of GetDisplayRootFrame above and
2109 * of nsDisplayListBuilder::FindReferenceFrameFor.
2110 *
2111 * If you have an nsDisplayListBuilder, you should get the reference
2112 * frame from it instead of calling this.
2113 */
2114 static nsIFrame* GetReferenceFrame(nsIFrame* aFrame);
2115
2116 /**
2117 * Get textrun construction flags determined by a given style; in particular
2118 * some combination of:
2119 * -- TEXT_DISABLE_OPTIONAL_LIGATURES if letter-spacing is in use
2120 * -- TEXT_OPTIMIZE_SPEED if the text-rendering CSS property and font size
2121 * and prefs indicate we should be optimizing for speed over quality
2122 */
2123 static mozilla::gfx::ShapedTextFlags GetTextRunFlagsForStyle(
2124 ComputedStyle* aComputedStyle, nsPresContext* aPresContext,
2125 const nsStyleFont* aStyleFont, const nsStyleText* aStyleText,
2126 nscoord aLetterSpacing);
2127
2128 /**
2129 * Get orientation flags for textrun construction.
2130 */
2131 static mozilla::gfx::ShapedTextFlags GetTextRunOrientFlagsForStyle(
2132 ComputedStyle* aComputedStyle);
2133
2134 /**
2135 * Takes two rectangles whose origins must be the same, and computes
2136 * the difference between their union and their intersection as two
2137 * rectangles. (This difference is a superset of the difference
2138 * between the two rectangles.)
2139 */
2140 static void GetRectDifferenceStrips(const nsRect& aR1, const nsRect& aR2,
2141 nsRect* aHStrip, nsRect* aVStrip);
2142
2143 /**
2144 * Get a device context that can be used to get up-to-date device
2145 * dimensions for the given window. For some reason, this is more
2146 * complicated than it ought to be in multi-monitor situations.
2147 */
2148 static nsDeviceContext* GetDeviceContextForScreenInfo(
2149 nsPIDOMWindowOuter* aWindow);
2150
2151 /**
2152 * Some frames with 'position: fixed' (nsStyleDisplay::mPosition ==
2153 * StylePositionProperty::Fixed) are not really fixed positioned, since
2154 * they're inside an element with -moz-transform. This function says
2155 * whether such an element is a real fixed-pos element.
2156 */
2157 static bool IsReallyFixedPos(const nsIFrame* aFrame);
2158
2159 /**
2160 * This function says whether `aFrame` would really be a fixed positioned
2161 * frame if the frame was created with StylePositionProperty::Fixed.
2162 *
2163 * It is effectively the same as IsReallyFixedPos, but without asserting the
2164 * position value. Use it only when you know what you're doing, like when
2165 * tearing down the frame tree (where styles may have changed due to
2166 * ::first-line reparenting and rule changes at the same time).
2167 */
2168 static bool MayBeReallyFixedPos(const nsIFrame* aFrame);
2169
2170 /**
2171 * Returns true if |aFrame| is inside position:fixed subtree.
2172 */
2173 static bool IsInPositionFixedSubtree(const nsIFrame* aFrame);
2174
2175 /**
2176 * Obtain a SourceSurface from the given DOM element, if possible.
2177 * This obtains the most natural surface from the element; that
2178 * is, the one that can be obtained with the fewest conversions.
2179 *
2180 * The flags below can modify the behaviour of this function. The
2181 * result is returned as a SurfaceFromElementResult struct, also
2182 * defined below.
2183 *
2184 * Currently, this will do:
2185 * - HTML Canvas elements: will return the underlying canvas surface
2186 * - HTML Video elements: will return the current video frame
2187 * - Image elements: will return the image
2188 *
2189 * The above results are modified by the below flags (copying,
2190 * forcing image surface, etc.).
2191 */
2192
2193 enum {
2194 /* Whether to extract the first frame (as opposed to the
2195 current frame) in the case that the element is an image. */
2196 SFE_WANT_FIRST_FRAME_IF_IMAGE = 1 << 0,
2197 /* Whether we should skip colorspace/gamma conversion */
2198 SFE_NO_COLORSPACE_CONVERSION = 1 << 1,
2199 /* Caller handles SFER::mAlphaType = NonPremult */
2200 SFE_ALLOW_NON_PREMULT = 1 << 2,
2201 /* Whether we should skip getting a surface for vector images and
2202 return a DirectDrawInfo containing an imgIContainer instead. */
2203 SFE_NO_RASTERIZING_VECTORS = 1 << 3,
2204 /* If image type is vector, the return surface size will same as
2205 element size, not image's intrinsic size. */
2206 SFE_USE_ELEMENT_SIZE_IF_VECTOR = 1 << 4,
2207 /* Ensure that the returned surface has a size that matches the
2208 * SurfaceFromElementResult::mSize. This is mostly a convenience thing so
2209 * that callers who want this don't have to deal with it themselves.
2210 * The surface might be different for, e.g., a EXIF-scaled raster image, if
2211 * we don't rescale during decode. */
2212 SFE_EXACT_SIZE_SURFACE = 1 << 6,
2213 };
2214
2215 // This function can be called on any thread.
2216 static mozilla::SurfaceFromElementResult SurfaceFromOffscreenCanvas(
2217 mozilla::dom::OffscreenCanvas* aOffscreenCanvas, uint32_t aSurfaceFlags,
2218 RefPtr<DrawTarget>& aTarget);
2219 static mozilla::SurfaceFromElementResult SurfaceFromOffscreenCanvas(
2220 mozilla::dom::OffscreenCanvas* aOffscreenCanvas,
2221 uint32_t aSurfaceFlags = 0) {
2222 RefPtr<DrawTarget> target = nullptr;
2223 return SurfaceFromOffscreenCanvas(aOffscreenCanvas, aSurfaceFlags, target);
2224 }
2225
2226 static mozilla::SurfaceFromElementResult SurfaceFromElement(
2227 mozilla::dom::Element* aElement, uint32_t aSurfaceFlags,
2228 RefPtr<DrawTarget>& aTarget);
2229 static mozilla::SurfaceFromElementResult SurfaceFromElement(
2230 mozilla::dom::Element* aElement, uint32_t aSurfaceFlags = 0) {
2231 RefPtr<DrawTarget> target = nullptr;
2232 return SurfaceFromElement(aElement, aSurfaceFlags, target);
2233 }
2234
2235 // There are a bunch of callers of SurfaceFromElement. Just mark it as
2236 MOZ_CAN_RUN_SCRIPT_BOUNDARY
2237 static mozilla::SurfaceFromElementResult SurfaceFromElement(
2238 nsIImageLoadingContent* aElement, uint32_t aSurfaceFlags,
2239 RefPtr<DrawTarget>& aTarget);
2240 // Need an HTMLImageElement overload, because otherwise the
2241 // nsIImageLoadingContent and mozilla::dom::Element overloads are ambiguous
2242 // for HTMLImageElement.
2243 static mozilla::SurfaceFromElementResult SurfaceFromElement(
2244 mozilla::dom::HTMLImageElement* aElement, uint32_t aSurfaceFlags,
2245 RefPtr<DrawTarget>& aTarget);
2246 static mozilla::SurfaceFromElementResult SurfaceFromElement(
2247 mozilla::dom::HTMLCanvasElement* aElement, uint32_t aSurfaceFlags,
2248 RefPtr<DrawTarget>& aTarget);
2249 static mozilla::SurfaceFromElementResult SurfaceFromElement(
2250 mozilla::dom::HTMLVideoElement* aElement, uint32_t aSurfaceFlags,
2251 RefPtr<DrawTarget>& aTarget);
2252
2253 /**
2254 * When the document is editable by contenteditable attribute of its root
2255 * content or body content.
2256 *
2257 * Be aware, this returns nullptr if it's in designMode.
2258 *
2259 * For example:
2260 *
2261 * <html contenteditable="true"><body></body></html>
2262 * returns the <html>.
2263 *
2264 * <html><body contenteditable="true"></body></html>
2265 * <body contenteditable="true"></body>
2266 * With these cases, this returns the <body>.
2267 * NOTE: The latter case isn't created normally, however, it can be
2268 * created by script with XHTML.
2269 *
2270 * <body><p contenteditable="true"></p></body>
2271 * returns nullptr because <body> isn't editable.
2272 */
2273 static mozilla::dom::Element* GetEditableRootContentByContentEditable(
2274 mozilla::dom::Document* aDocument);
2275
2276 static void AddExtraBackgroundItems(nsDisplayListBuilder* aBuilder,
2277 nsDisplayList* aList, nsIFrame* aFrame,
2278 const nsRect& aCanvasArea,
2279 const nsRegion& aVisibleRegion,
2280 nscolor aBackstop);
2281
2282 /**
2283 * Returns true if the passed in prescontext needs the dark grey background
2284 * that goes behind the page of a print preview presentation.
2285 */
2286 static bool NeedsPrintPreviewBackground(nsPresContext* aPresContext);
2287
2288 /**
2289 * Types used by the helpers for InspectorUtils.getUsedFontFaces.
2290 * The API returns an array (UsedFontFaceList) that owns the
2291 * InspectorFontFace instances, but during range traversal we also
2292 * want to maintain a mapping from gfxFontEntry to InspectorFontFace
2293 * records, so use a temporary hashtable for that.
2294 */
2295 typedef nsTArray<mozilla::UniquePtr<mozilla::dom::InspectorFontFace>>
2296 UsedFontFaceList;
2297 typedef nsTHashMap<nsPtrHashKey<gfxFontEntry>,
2298 mozilla::dom::InspectorFontFace*>
2299 UsedFontFaceTable;
2300
2301 /**
2302 * Adds all font faces used in the frame tree starting from aFrame
2303 * to the list aFontFaceList.
2304 * aMaxRanges: maximum number of text ranges to record for each face.
2305 */
2306 static nsresult GetFontFacesForFrames(nsIFrame* aFrame,
2307 UsedFontFaceList& aResult,
2308 UsedFontFaceTable& aFontFaces,
2309 uint32_t aMaxRanges,
2310 bool aSkipCollapsedWhitespace);
2311
2312 /**
2313 * Adds all font faces used within the specified range of text in aFrame,
2314 * and optionally its continuations, to the list in aFontFaceList.
2315 * Pass 0 and INT32_MAX for aStartOffset and aEndOffset to specify the
2316 * entire text is to be considered.
2317 * aMaxRanges: maximum number of text ranges to record for each face.
2318 */
2319 static void GetFontFacesForText(nsIFrame* aFrame, int32_t aStartOffset,
2320 int32_t aEndOffset, bool aFollowContinuations,
2321 UsedFontFaceList& aResult,
2322 UsedFontFaceTable& aFontFaces,
2323 uint32_t aMaxRanges,
2324 bool aSkipCollapsedWhitespace);
2325
2326 /**
2327 * Walks the frame tree starting at aFrame looking for textRuns.
2328 * If |clear| is true, just clears the TEXT_RUN_MEMORY_ACCOUNTED flag
2329 * on each textRun found (and |aMallocSizeOf| is not used).
2330 * If |clear| is false, adds the storage used for each textRun to the
2331 * total, and sets the TEXT_RUN_MEMORY_ACCOUNTED flag to avoid double-
2332 * accounting. (Runs with this flag already set will be skipped.)
2333 * Expected usage pattern is therefore to call twice:
2334 * (void)SizeOfTextRunsForFrames(rootFrame, nullptr, true);
2335 * total = SizeOfTextRunsForFrames(rootFrame, mallocSizeOf, false);
2336 */
2337 static size_t SizeOfTextRunsForFrames(nsIFrame* aFrame,
2338 mozilla::MallocSizeOf aMallocSizeOf,
2339 bool clear);
2340
2341 /**
2342 * Returns true if |aFrame| has an animation of a property in |aPropertySet|
2343 * regardless of whether any property in the set is overridden by an
2344 * !important rule.
2345 */
2346 static bool HasAnimationOfPropertySet(const nsIFrame* aFrame,
2347 const nsCSSPropertyIDSet& aPropertySet);
2348
2349 /**
2350 * A variant of the above HasAnimationOfPropertySet that takes an optional
2351 * EffectSet parameter as an optimization to save redundant lookups of the
2352 * EffectSet.
2353 */
2354 static bool HasAnimationOfPropertySet(const nsIFrame* aFrame,
2355 const nsCSSPropertyIDSet& aPropertySet,
2356 mozilla::EffectSet* aEffectSet);
2357
2358 /**
2359 * A variant of the above HasAnimationOfPropertySet. This is especially for
2360 * tranform-like properties with motion-path.
2361 * For transform-like properties with motion-path, we need to check if
2362 * offset-path has effect. If we don't have any animation on offset-path and
2363 * offset-path is none, there is no effective motion-path, and so we don't
2364 * care other offset-* properties. In this case, this function only checks the
2365 * rest of transform-like properties (i.e. transform/translate/rotate/scale).
2366 */
2367 static bool HasAnimationOfTransformAndMotionPath(const nsIFrame* aFrame);
2368
2369 /**
2370 * Returns true if |aFrame| has an animation of |aProperty| which is
2371 * not overridden by !important rules.
2372 */
2373 static bool HasEffectiveAnimation(const nsIFrame* aFrame,
2374 nsCSSPropertyID aProperty);
2375
2376 /**
2377 * Returns true if |aFrame| has an animation where at least one of the
2378 * properties in |aPropertySet| is not overridden by !important rules.
2379 *
2380 * If |aPropertySet| includes transform-like properties (transform, rotate,
2381 * etc.) however, this will return false if any of the transform-like
2382 * properties is overriden by an !important rule since these properties should
2383 * be combined on the compositor.
2384 */
2385 static bool HasEffectiveAnimation(const nsIFrame* aFrame,
2386 const nsCSSPropertyIDSet& aPropertySet);
2387
2388 /**
2389 * Returns all effective animated CSS properties on |aStyleFrame| and its
2390 * corresponding primary frame (for content that makes this distinction,
2391 * notable display:table content) that can be animated on the compositor.
2392 *
2393 * Properties that can be animated on the compositor but which are overridden
2394 * by !important rules are not returned.
2395 *
2396 * Unlike HasEffectiveAnimation, however, this does not check the set of
2397 * transform-like properties to ensure that if any such properties are
2398 * overridden by !important rules, the other transform-like properties are
2399 * not run on the compositor (see bug 1534884).
2400 */
2401 static nsCSSPropertyIDSet GetAnimationPropertiesForCompositor(
2402 const nsIFrame* aStyleFrame);
2403
2404 /**
2405 * Checks if off-main-thread animations are enabled.
2406 */
2407 static bool AreAsyncAnimationsEnabled();
2408
2409 /**
2410 * Checks if retained display lists are enabled.
2411 */
2412 static bool AreRetainedDisplayListsEnabled();
2413
2414 static bool DisplayRootHasRetainedDisplayListBuilder(nsIFrame* aFrame);
2415
2416 /**
2417 * Find a suitable scale for a element (aFrame's content) over the course of
2418 * any animations and transitions of the CSS transform property on the element
2419 * that run on the compositor thread. It will check the maximum and minimum
2420 * scale during the animations and transitions and return a suitable value for
2421 * performance and quality. Will return scale(1,1) if there are no such
2422 * animations. Always returns a positive value.
2423 * @param aVisibleSize is the size of the area we want to paint
2424 * @param aDisplaySize is the size of the display area of the pres context
2425 */
2426 static Size ComputeSuitableScaleForAnimation(const nsIFrame* aFrame,
2427 const nsSize& aVisibleSize,
2428 const nsSize& aDisplaySize);
2429
2430 /**
2431 * Checks whether we want to use the GPU to scale images when
2432 * possible.
2433 */
2434 static bool GPUImageScalingEnabled();
2435
2436 /**
2437 * Unions the overflow areas of the children of aFrame with aOverflowAreas.
2438 * aSkipChildLists specifies any child lists that should be skipped.
2439 * kSelectPopupList and kPopupList are always skipped.
2440 */
2441 static void UnionChildOverflow(
2442 nsIFrame* aFrame, mozilla::OverflowAreas& aOverflowAreas,
2443 mozilla::layout::FrameChildListIDs aSkipChildLists =
2444 mozilla::layout::FrameChildListIDs());
2445
2446 /**
2447 * Return the font size inflation *ratio* for a given frame. This is
2448 * the factor by which font sizes should be inflated; it is never
2449 * smaller than 1.
2450 */
2451 static float FontSizeInflationFor(const nsIFrame* aFrame);
2452
2453 /**
2454 * Perform the first half of the computation of FontSizeInflationFor
2455 * (see above).
2456 * This includes determining whether inflation should be performed
2457 * within this container and returning 0 if it should not be.
2458 *
2459 * The result is guaranteed not to vary between line participants
2460 * (inlines, text frames) within a line.
2461 *
2462 * The result should not be used directly since font sizes slightly
2463 * above the minimum should always be adjusted as done by
2464 * FontSizeInflationInner.
2465 */
2466 static nscoord InflationMinFontSizeFor(const nsIFrame* aFrame);
2467
2468 /**
2469 * Perform the second half of the computation done by
2470 * FontSizeInflationFor (see above).
2471 *
2472 * aMinFontSize must be the result of one of the
2473 * InflationMinFontSizeFor methods above.
2474 */
2475 static float FontSizeInflationInner(const nsIFrame* aFrame,
2476 nscoord aMinFontSize);
2477
2478 static bool FontSizeInflationEnabled(nsPresContext* aPresContext);
2479
2480 /**
2481 * Returns true if the nglayout.debug.invalidation pref is set to true.
2482 */
InvalidationDebuggingIsEnabled()2483 static bool InvalidationDebuggingIsEnabled() {
2484 return mozilla::StaticPrefs::nglayout_debug_invalidation() ||
2485 getenv("MOZ_DUMP_INVALIDATION") != 0;
2486 }
2487
2488 static void Initialize();
2489 static void Shutdown();
2490
2491 /**
2492 * Register an imgIRequest object with a refresh driver.
2493 *
2494 * @param aPresContext The nsPresContext whose refresh driver we want to
2495 * register with.
2496 * @param aRequest A pointer to the imgIRequest object which the client wants
2497 * to register with the refresh driver.
2498 * @param aRequestRegistered A pointer to a boolean value which indicates
2499 * whether the given image request is registered. If
2500 * *aRequestRegistered is true, then this request will not be
2501 * registered again. If the request is registered by this function,
2502 * then *aRequestRegistered will be set to true upon the completion of
2503 * this function.
2504 *
2505 */
2506 static void RegisterImageRequest(nsPresContext* aPresContext,
2507 imgIRequest* aRequest,
2508 bool* aRequestRegistered);
2509
2510 /**
2511 * Register an imgIRequest object with a refresh driver, but only if the
2512 * request is for an image that is animated.
2513 *
2514 * @param aPresContext The nsPresContext whose refresh driver we want to
2515 * register with.
2516 * @param aRequest A pointer to the imgIRequest object which the client wants
2517 * to register with the refresh driver.
2518 * @param aRequestRegistered A pointer to a boolean value which indicates
2519 * whether the given image request is registered. If
2520 * *aRequestRegistered is true, then this request will not be
2521 * registered again. If the request is registered by this function,
2522 * then *aRequestRegistered will be set to true upon the completion of
2523 * this function.
2524 *
2525 */
2526 static void RegisterImageRequestIfAnimated(nsPresContext* aPresContext,
2527 imgIRequest* aRequest,
2528 bool* aRequestRegistered);
2529
2530 /**
2531 * Deregister an imgIRequest object from a refresh driver.
2532 *
2533 * @param aPresContext The nsPresContext whose refresh driver we want to
2534 * deregister from.
2535 * @param aRequest A pointer to the imgIRequest object with which the client
2536 * previously registered and now wants to deregister from the refresh
2537 * driver.
2538 * @param aRequestRegistered A pointer to a boolean value which indicates
2539 * whether the given image request is registered. If
2540 * *aRequestRegistered is false, then this request will not be
2541 * deregistered. If the request is deregistered by this function,
2542 * then *aRequestRegistered will be set to false upon the completion of
2543 * this function.
2544 */
2545 static void DeregisterImageRequest(nsPresContext* aPresContext,
2546 imgIRequest* aRequest,
2547 bool* aRequestRegistered);
2548
2549 /**
2550 * Shim to nsCSSFrameConstructor::PostRestyleEvent. Exists so that we
2551 * can avoid including nsCSSFrameConstructor.h and all its dependencies
2552 * in content files.
2553 */
2554 static void PostRestyleEvent(mozilla::dom::Element*, mozilla::RestyleHint,
2555 nsChangeHint aMinChangeHint);
2556
2557 /**
2558 * Updates a pair of x and y distances if a given point is closer to a given
2559 * rectangle than the original distance values. If aPoint is closer to
2560 * aRect than aClosestXDistance and aClosestYDistance indicate, then those
2561 * two variables are updated with the distance between aPoint and aRect,
2562 * and true is returned. If aPoint is not closer, then aClosestXDistance
2563 * and aClosestYDistance are left unchanged, and false is returned.
2564 *
2565 * Distances are measured in the two dimensions separately; a closer x
2566 * distance beats a closer y distance.
2567 */
2568 template <typename PointType, typename RectType, typename CoordType>
2569 static bool PointIsCloserToRect(PointType aPoint, const RectType& aRect,
2570 CoordType& aClosestXDistance,
2571 CoordType& aClosestYDistance);
2572 /**
2573 * Computes the box shadow rect for the frame, or returns an empty rect if
2574 * there are no shadows.
2575 *
2576 * @param aFrame Frame to compute shadows for.
2577 * @param aFrameSize Size of aFrame (in case it hasn't been set yet).
2578 */
2579 static nsRect GetBoxShadowRectForFrame(nsIFrame* aFrame,
2580 const nsSize& aFrameSize);
2581
2582 #ifdef DEBUG
2583 /**
2584 * Assert that there are no duplicate continuations of the same frame
2585 * within aFrameList. Optimize the tests by assuming that all frames
2586 * in aFrameList have parent aContainer.
2587 */
2588 static void AssertNoDuplicateContinuations(nsIFrame* aContainer,
2589 const nsFrameList& aFrameList);
2590
2591 /**
2592 * Assert that the frame tree rooted at |aSubtreeRoot| is empty, i.e.,
2593 * that it contains no first-in-flows.
2594 */
2595 static void AssertTreeOnlyEmptyNextInFlows(nsIFrame* aSubtreeRoot);
2596 #endif
2597
2598 /**
2599 * Helper method to transform |aBounds| from aFrame to aAncestorFrame,
2600 * and combine it with |aPreciseTargetDest| if it is axis-aligned, or
2601 * combine it with |aImpreciseTargetDest| if not. The transformed rect is
2602 * clipped to |aClip|; if |aClip| has rounded corners, that also causes
2603 * the imprecise target to be used.
2604 */
2605 static void TransformToAncestorAndCombineRegions(
2606 const nsRegion& aRegion, nsIFrame* aFrame, const nsIFrame* aAncestorFrame,
2607 nsRegion* aPreciseTargetDest, nsRegion* aImpreciseTargetDest,
2608 mozilla::Maybe<Matrix4x4Flagged>* aMatrixCache,
2609 const mozilla::DisplayItemClip* aClip);
2610
2611 /**
2612 * Populate aOutSize with the size of the content viewer corresponding
2613 * to the given prescontext. Return true if the size was set, false
2614 * otherwise.
2615 */
2616 enum class SubtractDynamicToolbar { No, Yes };
2617 static bool GetContentViewerSize(
2618 const nsPresContext* aPresContext, LayoutDeviceIntSize& aOutSize,
2619 SubtractDynamicToolbar = SubtractDynamicToolbar::Yes);
2620
2621 private:
2622 static bool UpdateCompositionBoundsForRCDRSF(
2623 mozilla::ParentLayerRect& aCompBounds, const nsPresContext* aPresContext);
2624
2625 public:
2626 /**
2627 * Calculate the compostion size for a frame. See FrameMetrics.h for
2628 * defintion of composition size (or bounds).
2629 * Note that for the root content document's root scroll frame (RCD-RSF),
2630 * the returned size does not change as the document's resolution changes,
2631 * but for all other frames it does. This means that callers that pass in
2632 * a frame that may or may not be the RCD-RSF (which is most callers),
2633 * are likely to need special-case handling of the RCD-RSF.
2634 */
2635 static nsSize CalculateCompositionSizeForFrame(
2636 nsIFrame* aFrame, bool aSubtractScrollbars = true,
2637 const nsSize* aOverrideScrollPortSize = nullptr);
2638
2639 /**
2640 * Calculate a size suitable for bounding the size of the composition bounds
2641 * of scroll frames in the current process. This should be at most the
2642 * composition size of the cross-process RCD-RSF, but it may be a tighter
2643 * bounding size.
2644 * @param aFrame A frame in the (in-process) root content document (or a
2645 * descendant of it).
2646 * @param aIsRootContentDocRootScrollFrame Whether aFrame is the root
2647 * scroll frame of the *cross-process* root content document.
2648 * In this case we just use aFrame's own composition size.
2649 * @param aMetrics A partially populated FrameMetrics for aFrame. Must have at
2650 * least mCompositionBounds, mCumulativeResolution, and
2651 * mDevPixelsPerCSSPixel set.
2652 */
2653 static CSSSize CalculateBoundingCompositionSize(
2654 const nsIFrame* aFrame, bool aIsRootContentDocRootScrollFrame,
2655 const FrameMetrics& aMetrics);
2656
2657 /**
2658 * Calculate the scrollable rect for a frame. See FrameMetrics.h for
2659 * defintion of scrollable rect. aScrollableFrame is the scroll frame to
2660 * calculate the scrollable rect for. If it's null then we calculate the
2661 * scrollable rect as the rect of the root frame.
2662 */
2663 static nsRect CalculateScrollableRectForFrame(
2664 const nsIScrollableFrame* aScrollableFrame, const nsIFrame* aRootFrame);
2665
2666 /**
2667 * Calculate the expanded scrollable rect for a frame. See FrameMetrics.h for
2668 * defintion of expanded scrollable rect.
2669 */
2670 static nsRect CalculateExpandedScrollableRect(nsIFrame* aFrame);
2671
2672 /**
2673 * Returns true if the widget owning the given frame uses asynchronous
2674 * scrolling.
2675 */
2676 static bool UsesAsyncScrolling(nsIFrame* aFrame);
2677
2678 /**
2679 * Returns true if the widget owning the given frame has builtin APZ support
2680 * enabled.
2681 */
2682 static bool AsyncPanZoomEnabled(const nsIFrame* aFrame);
2683
2684 /**
2685 * Returns true if aDocument should be allowed to use resolution
2686 * zooming.
2687 */
2688 static bool AllowZoomingForDocument(const mozilla::dom::Document* aDocument);
2689
2690 /**
2691 * Returns true if we need to disable async scrolling for this particular
2692 * element. Note that this does a partial disabling - the displayport still
2693 * exists but uses a very small margin, and the compositor doesn't apply the
2694 * async transform. However, the content may still be layerized.
2695 */
2696 static bool ShouldDisableApzForElement(nsIContent* aContent);
2697
2698 /**
2699 * Log a key/value pair as "additional data" (not associated with a paint)
2700 * for APZ testing.
2701 * While the data is not associated with a paint, the APZTestData object
2702 * is still owned by {Client,WebRender}LayerManager, so we need to be passed
2703 * something from which we can derive the layer manager.
2704 * This function takes a display list builder as the object to derive the
2705 * layer manager from, to facilitate logging test data during display list
2706 * building, but other overloads that take other objects could be added if
2707 * desired.
2708 */
2709 static void LogAdditionalTestData(nsDisplayListBuilder* aBuilder,
2710 const std::string& aKey,
2711 const std::string& aValue);
2712
2713 /**
2714 * Log a key/value pair for APZ testing during a paint.
2715 * @param aManager The data will be written to the APZTestData associated
2716 * with this layer manager.
2717 * @param aScrollId Identifies the scroll frame to which the data pertains.
2718 * @param aKey The key under which to log the data.
2719 * @param aValue The value of the data to be logged.
2720 */
LogTestDataForPaint(mozilla::layers::WebRenderLayerManager * aManager,ViewID aScrollId,const std::string & aKey,const std::string & aValue)2721 static void LogTestDataForPaint(
2722 mozilla::layers::WebRenderLayerManager* aManager, ViewID aScrollId,
2723 const std::string& aKey, const std::string& aValue) {
2724 DoLogTestDataForPaint(aManager, aScrollId, aKey, aValue);
2725 }
2726
2727 /**
2728 * A convenience overload of LogTestDataForPaint() that accepts any type
2729 * as the value, and passes it through mozilla::ToString() to obtain a string
2730 * value. The type passed must support streaming to an std::ostream.
2731 */
2732 template <typename Value>
LogTestDataForPaint(mozilla::layers::WebRenderLayerManager * aManager,ViewID aScrollId,const std::string & aKey,const Value & aValue)2733 static void LogTestDataForPaint(
2734 mozilla::layers::WebRenderLayerManager* aManager, ViewID aScrollId,
2735 const std::string& aKey, const Value& aValue) {
2736 DoLogTestDataForPaint(aManager, aScrollId, aKey, mozilla::ToString(aValue));
2737 }
2738
2739 /**
2740 * Calculate a basic FrameMetrics with enough fields set to perform some
2741 * layout calculations. The fields set are dev-to-css ratio, pres shell
2742 * resolution, cumulative resolution, zoom, composition size, root
2743 * composition size, scroll offset and scrollable rect.
2744 *
2745 * Note that for the RCD-RSF, the scroll offset returned is the layout
2746 * viewport offset; if you need the visual viewport offset, that needs to
2747 * be queried independently via PresShell::GetVisualViewportOffset().
2748 *
2749 * By contrast, ComputeFrameMetrics() computes all the fields, but requires
2750 * extra inputs and can only be called during frame layer building.
2751 */
2752 static FrameMetrics CalculateBasicFrameMetrics(
2753 nsIScrollableFrame* aScrollFrame);
2754
2755 static nsIScrollableFrame* GetAsyncScrollableAncestorFrame(nsIFrame* aTarget);
2756
2757 static void SetBSizeFromFontMetrics(
2758 const nsIFrame* aFrame, mozilla::ReflowOutput& aMetrics,
2759 const mozilla::LogicalMargin& aFramePadding, mozilla::WritingMode aLineWM,
2760 mozilla::WritingMode aFrameWM);
2761
2762 static bool HasDocumentLevelListenersForApzAwareEvents(PresShell* aPresShell);
2763
2764 /**
2765 * Returns true if the given scroll origin is "higher priority" than APZ.
2766 * In general any content programmatic scrolls (e.g. scrollTo calls) are
2767 * higher priority, and take precedence over APZ scrolling. This function
2768 * returns true for those, and returns false for other origins like APZ
2769 * itself, or scroll position updates from the history restore code.
2770 */
2771 static bool CanScrollOriginClobberApz(ScrollOrigin aScrollOrigin);
2772
2773 static ScrollMetadata ComputeScrollMetadata(
2774 const nsIFrame* aForFrame, const nsIFrame* aScrollFrame,
2775 nsIContent* aContent, const nsIFrame* aItemFrame,
2776 const nsPoint& aOffsetToReferenceFrame,
2777 mozilla::layers::WebRenderLayerManager* aLayerManager,
2778 ViewID aScrollParentId, const nsSize& aScrollPortSize, bool aIsRoot);
2779
2780 /**
2781 * Returns the metadata to put onto the root layer of a layer tree, if one is
2782 * needed. The last argument is a callback function to check if the caller
2783 * already has a metadata for a given scroll id.
2784 */
2785 static mozilla::Maybe<ScrollMetadata> GetRootMetadata(
2786 nsDisplayListBuilder* aBuilder,
2787 mozilla::layers::WebRenderLayerManager* aLayerManager,
2788 const std::function<bool(ViewID& aScrollId)>& aCallback);
2789
2790 /**
2791 * If the given scroll frame needs an area excluded from its composition
2792 * bounds due to scrollbars, return that area, otherwise return an empty
2793 * margin.
2794 * There is no need to exclude scrollbars in the following cases:
2795 * - If the scroll frame is not the RCD-RSF; in that case, the composition
2796 * bounds is calculated based on the scroll port which already excludes
2797 * the scrollbar area.
2798 * - If the scrollbars are overlay, since then they are drawn on top of the
2799 * scrollable content.
2800 */
2801 static nsMargin ScrollbarAreaToExcludeFromCompositionBoundsFor(
2802 const nsIFrame* aScrollFrame);
2803
2804 static bool ShouldUseNoScriptSheet(mozilla::dom::Document*);
2805 static bool ShouldUseNoFramesSheet(mozilla::dom::Document*);
2806
2807 /**
2808 * Get the text content inside the frame. This methods traverse the
2809 * frame tree and collect the content from text frames. Note that this
2810 * method is similiar to nsContentUtils::GetNodeTextContent, but it at
2811 * least differs from that method in the following things:
2812 * 1. it skips text content inside nodes like style, script, textarea
2813 * which don't generate an in-tree text frame for the text;
2814 * 2. it skips elements with display property set to none;
2815 * 3. it skips out-of-flow elements;
2816 * 4. it includes content inside pseudo elements;
2817 * 5. it may include part of text content of a node if a text frame
2818 * inside is split to different continuations.
2819 */
2820 static void GetFrameTextContent(nsIFrame* aFrame, nsAString& aResult);
2821
2822 /**
2823 * Same as GetFrameTextContent but appends the result rather than sets it.
2824 */
2825 static void AppendFrameTextContent(nsIFrame* aFrame, nsAString& aResult);
2826
2827 /**
2828 * Takes a selection, and returns selection's bounding rect which is relative
2829 * to its root frame.
2830 *
2831 * @param aSel Selection to check
2832 */
2833 static nsRect GetSelectionBoundingRect(const mozilla::dom::Selection* aSel);
2834
2835 /**
2836 * Calculate the bounding rect of |aContent|, relative to the origin
2837 * of the scrolled content of |aRootScrollFrame|.
2838 * Where the element is contained inside a scrollable subframe, the
2839 * bounding rect is clipped to the bounds of the subframe.
2840 * If non-null aOutNearestScrollClip will be filled in with the rect of the
2841 * nearest scroll frame (excluding aRootScrollFrame) that is an ancestor of
2842 * the frame of aContent, if such exists, in the same coords are the returned
2843 * rect. This rect is used to clip the result.
2844 */
2845 static CSSRect GetBoundingContentRect(
2846 const nsIContent* aContent, const nsIScrollableFrame* aRootScrollFrame,
2847 mozilla::Maybe<CSSRect>* aOutNearestScrollClip = nullptr);
2848
2849 /**
2850 * Similar to GetBoundingContentRect for nsIFrame.
2851 */
2852 static CSSRect GetBoundingFrameRect(
2853 nsIFrame* aFrame, const nsIScrollableFrame* aRootScrollFrame,
2854 mozilla::Maybe<CSSRect>* aOutNearestScrollClip = nullptr);
2855
2856 /**
2857 * Returns the first ancestor who is a float containing block.
2858 */
2859 static nsBlockFrame* GetFloatContainingBlock(nsIFrame* aFrame);
2860
2861 /**
2862 * Walks up the frame tree from |aForFrame| up to |aTopFrame|, or to the
2863 * root of the frame tree if |aTopFrame| is nullptr, and returns true if
2864 * a transformed frame is encountered.
2865 */
2866 static bool IsTransformed(nsIFrame* aForFrame, nsIFrame* aTopFrame = nullptr);
2867
2868 /**
2869 * Walk up from aFrame to the cross-doc root, accumulating all the APZ
2870 * callback transforms on the content elements encountered along the way.
2871 * Return the accumulated value.
2872 * XXX: Note that this does not take into account CSS transforms, nor
2873 * differences in structure between the frame tree and the layer tree (which
2874 * is probably what we *want* to be computing).
2875 */
2876 static CSSPoint GetCumulativeApzCallbackTransform(nsIFrame* aFrame);
2877
2878 /**
2879 * Compute a rect to pre-render in cases where we want to render more of
2880 * something than what is visible (usually to support async transformation).
2881 * @param aFrame the target frame to be pre-rendered
2882 * @param aDirtyRect the area that's visible in the coordinate system of
2883 * |aFrame|.
2884 * @param aOverflow the total size of the thing we're rendering in the
2885 * coordinate system of |aFrame|.
2886 * @param aPrerenderSize how large of an area we're willing to render in the
2887 * coordinate system of the root frame.
2888 * @return A rectangle that includes |aDirtyRect|, is clamped to |aOverflow|,
2889 * and is no larger than |aPrerenderSize| (unless |aPrerenderSize| is
2890 * smaller than |aDirtyRect|, in which case the returned rect will
2891 * still include |aDirtyRect| and thus be larger than
2892 * |aPrerenderSize|).
2893 */
2894 static nsRect ComputePartialPrerenderArea(nsIFrame* aFrame,
2895 const nsRect& aDirtyRect,
2896 const nsRect& aOverflow,
2897 const nsSize& aPrerenderSize);
2898
2899 /*
2900 * Checks whether a node is an invisible break.
2901 * If not, returns the first frame on the next line if such a next line
2902 * exists.
2903 *
2904 * @return
2905 * true if the node is an invisible break. aNextLineFrame is returned null
2906 * in this case.
2907 *
2908 * false if the node causes a visible break or if the node is no break.
2909 *
2910 * @param aNextLineFrame
2911 * assigned to first frame on the next line if such a next line exists, null
2912 * otherwise.
2913 */
2914 static bool IsInvisibleBreak(nsINode* aNode,
2915 nsIFrame** aNextLineFrame = nullptr);
2916
2917 static nsRect ComputeGeometryBox(nsIFrame*, StyleGeometryBox);
2918
2919 static nsRect ComputeGeometryBox(nsIFrame*,
2920 const mozilla::StyleShapeGeometryBox&);
2921
2922 static nsRect ComputeGeometryBox(nsIFrame*, const mozilla::StyleShapeBox&);
2923
2924 static nsPoint ComputeOffsetToUserSpace(nsDisplayListBuilder* aBuilder,
2925 nsIFrame* aFrame);
2926
2927 // Callers are responsible to ensure the user-font-set is up-to-date if
2928 // aUseUserFontSet is true.
2929 static already_AddRefed<nsFontMetrics> GetMetricsFor(
2930 nsPresContext* aPresContext, bool aIsVertical,
2931 const nsStyleFont* aStyleFont, mozilla::Length aFontSize,
2932 bool aUseUserFontSet);
2933
2934 static void ComputeSystemFont(nsFont* aSystemFont,
2935 mozilla::StyleSystemFont aFontID,
2936 const nsFont& aDefaultVariableFont,
2937 const mozilla::dom::Document* aDocument);
2938
2939 static uint32_t ParseFontLanguageOverride(const nsAString& aLangTag);
2940
2941 /**
2942 * Returns true if there are any preferences or overrides that indicate a
2943 * need to handle <meta name="viewport"> tags.
2944 */
2945 static bool ShouldHandleMetaViewport(const mozilla::dom::Document*);
2946
2947 /**
2948 * Resolve a CSS <length-percentage> value to a definite size.
2949 */
2950 template <bool clampNegativeResultToZero>
ResolveToLength(const LengthPercentage & aLengthPercentage,nscoord aPercentageBasis)2951 static nscoord ResolveToLength(const LengthPercentage& aLengthPercentage,
2952 nscoord aPercentageBasis) {
2953 nscoord value = (aPercentageBasis == NS_UNCONSTRAINEDSIZE)
2954 ? aLengthPercentage.Resolve(0)
2955 : aLengthPercentage.Resolve(aPercentageBasis);
2956 return clampNegativeResultToZero ? std::max(0, value) : value;
2957 }
2958
2959 /**
2960 * Resolve a column-gap/row-gap to a definite size.
2961 * @note This method resolves 'normal' to zero.
2962 * Callers who want different behavior should handle 'normal' on their own.
2963 */
ResolveGapToLength(const mozilla::NonNegativeLengthPercentageOrNormal & aGap,nscoord aPercentageBasis)2964 static nscoord ResolveGapToLength(
2965 const mozilla::NonNegativeLengthPercentageOrNormal& aGap,
2966 nscoord aPercentageBasis) {
2967 if (aGap.IsNormal()) {
2968 return nscoord(0);
2969 }
2970 return ResolveToLength<true>(aGap.AsLengthPercentage(), aPercentageBasis);
2971 }
2972
2973 /**
2974 * Get the computed style from which the scrollbar style should be
2975 * used for the given scrollbar part frame.
2976 */
2977 static ComputedStyle* StyleForScrollbar(nsIFrame* aScrollbarPart);
2978
2979 /**
2980 * Returns true if |aFrame| is scrolled out of view by a scrollable element in
2981 * a cross-process ancestor document.
2982 * Note this function only works for frames in out-of-process iframes.
2983 **/
2984 static bool FrameIsScrolledOutOfViewInCrossProcess(const nsIFrame* aFrame);
2985
2986 /**
2987 * Similar to above FrameIsScrolledOutViewInCrossProcess but returns true even
2988 * if |aFrame| is not fully scrolled out of view and its visible area width or
2989 * height is smaller than |aMargin|.
2990 **/
2991 static bool FrameIsMostlyScrolledOutOfViewInCrossProcess(
2992 const nsIFrame* aFrame, nscoord aMargin);
2993
2994 /**
2995 * Expand the height of |aSize| to the size of `vh` units.
2996 *
2997 * With dynamic toolbar(s) the height for `vh` units is greater than the
2998 * ICB height, we need to expand it in some places.
2999 **/
3000 static nsSize ExpandHeightForViewportUnits(nsPresContext* aPresContext,
3001 const nsSize& aSize);
3002
3003 static CSSSize ExpandHeightForDynamicToolbar(
3004 const nsPresContext* aPresContext, const CSSSize& aSize);
3005 static nsSize ExpandHeightForDynamicToolbar(const nsPresContext* aPresContext,
3006 const nsSize& aSize);
3007
3008 /**
3009 * Returns the nsIFrame which clips overflow regions of the given |aFrame|.
3010 * Note CSS clip or clip-path isn't accounted for.
3011 **/
3012 static nsIFrame* GetNearestOverflowClipFrame(nsIFrame* aFrame);
3013
3014 private:
3015 /**
3016 * Helper function for LogTestDataForPaint().
3017 */
3018 static void DoLogTestDataForPaint(
3019 mozilla::layers::WebRenderLayerManager* aManager, ViewID aScrollId,
3020 const std::string& aKey, const std::string& aValue);
3021
3022 static bool IsAPZTestLoggingEnabled();
3023
3024 static void ConstrainToCoordValues(gfxFloat& aStart, gfxFloat& aSize);
3025 static void ConstrainToCoordValues(float& aStart, float& aSize);
3026 };
3027
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(nsLayoutUtils::PaintFrameFlags)3028 MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(nsLayoutUtils::PaintFrameFlags)
3029
3030 template <typename PointType, typename RectType, typename CoordType>
3031 /* static */ bool nsLayoutUtils::PointIsCloserToRect(
3032 PointType aPoint, const RectType& aRect, CoordType& aClosestXDistance,
3033 CoordType& aClosestYDistance) {
3034 CoordType fromLeft = aPoint.x - aRect.x;
3035 CoordType fromRight = aPoint.x - aRect.XMost();
3036
3037 CoordType xDistance;
3038 if (fromLeft >= 0 && fromRight <= 0) {
3039 xDistance = 0;
3040 } else {
3041 xDistance = std::min(abs(fromLeft), abs(fromRight));
3042 }
3043
3044 if (xDistance <= aClosestXDistance) {
3045 if (xDistance < aClosestXDistance) {
3046 aClosestYDistance = std::numeric_limits<CoordType>::max();
3047 }
3048
3049 CoordType fromTop = aPoint.y - aRect.y;
3050 CoordType fromBottom = aPoint.y - aRect.YMost();
3051
3052 CoordType yDistance;
3053 if (fromTop >= 0 && fromBottom <= 0) {
3054 yDistance = 0;
3055 } else {
3056 yDistance = std::min(abs(fromTop), abs(fromBottom));
3057 }
3058
3059 if (yDistance < aClosestYDistance) {
3060 aClosestXDistance = xDistance;
3061 aClosestYDistance = yDistance;
3062 return true;
3063 }
3064 }
3065
3066 return false;
3067 }
3068
3069 template <typename T>
RoundGfxRectToAppRect(const T & aRect,const float aFactor)3070 nsRect nsLayoutUtils::RoundGfxRectToAppRect(const T& aRect,
3071 const float aFactor) {
3072 // Get a new Rect whose units are app units by scaling by the specified
3073 // factor.
3074 T scaledRect = aRect;
3075 scaledRect.ScaleRoundOut(aFactor);
3076
3077 // We now need to constrain our results to the max and min values for coords.
3078 ConstrainToCoordValues(scaledRect.x, scaledRect.width);
3079 ConstrainToCoordValues(scaledRect.y, scaledRect.height);
3080
3081 if (!aRect.Width()) {
3082 scaledRect.SetWidth(0);
3083 }
3084
3085 if (!aRect.Height()) {
3086 scaledRect.SetHeight(0);
3087 }
3088
3089 // Now typecast everything back. This is guaranteed to be safe.
3090 return nsRect(nscoord(scaledRect.X()), nscoord(scaledRect.Y()),
3091 nscoord(scaledRect.Width()), nscoord(scaledRect.Height()));
3092 }
3093
3094 namespace mozilla {
3095
3096 /**
3097 * Converts an nsPoint in app units to a Moz2D Point in pixels (whether those
3098 * are device pixels or CSS px depends on what the caller chooses to pass as
3099 * aAppUnitsPerPixel).
3100 */
NSPointToPoint(const nsPoint & aPoint,int32_t aAppUnitsPerPixel)3101 inline gfx::Point NSPointToPoint(const nsPoint& aPoint,
3102 int32_t aAppUnitsPerPixel) {
3103 return gfx::Point(gfx::Float(aPoint.x) / aAppUnitsPerPixel,
3104 gfx::Float(aPoint.y) / aAppUnitsPerPixel);
3105 }
3106
3107 /**
3108 * Converts an nsRect in app units to a Moz2D Rect in pixels (whether those
3109 * are device pixels or CSS px depends on what the caller chooses to pass as
3110 * aAppUnitsPerPixel).
3111 */
3112 gfx::Rect NSRectToRect(const nsRect& aRect, double aAppUnitsPerPixel);
3113
3114 /**
3115 * Converts an nsRect in app units to a Moz2D Rect in pixels (whether those
3116 * are device pixels or CSS px depends on what the caller chooses to pass as
3117 * aAppUnitsPerPixel).
3118 *
3119 * The passed DrawTarget is used to additionally snap the returned Rect to
3120 * device pixels, if appropriate (as decided and carried out by Moz2D's
3121 * MaybeSnapToDevicePixels helper, which this function calls to do any
3122 * snapping).
3123 */
3124 gfx::Rect NSRectToSnappedRect(const nsRect& aRect, double aAppUnitsPerPixel,
3125 const gfx::DrawTarget& aSnapDT);
3126
3127 /**
3128 * Converts, where possible, an nsRect in app units to a Moz2D Rect in pixels
3129 * (whether those are device pixels or CSS px depends on what the caller
3130 * chooses to pass as aAppUnitsPerPixel).
3131 *
3132 * If snapping results in a rectangle with zero width or height, the affected
3133 * coordinates are left unsnapped
3134 */
3135 gfx::Rect NSRectToNonEmptySnappedRect(const nsRect& aRect,
3136 double aAppUnitsPerPixel,
3137 const gfx::DrawTarget& aSnapDT);
3138
3139 void StrokeLineWithSnapping(
3140 const nsPoint& aP1, const nsPoint& aP2, int32_t aAppUnitsPerDevPixel,
3141 gfx::DrawTarget& aDrawTarget, const gfx::Pattern& aPattern,
3142 const gfx::StrokeOptions& aStrokeOptions = gfx::StrokeOptions(),
3143 const gfx::DrawOptions& aDrawOptions = gfx::DrawOptions());
3144
3145 namespace layout {
3146
3147 /**
3148 * An RAII class which will, for the duration of its lifetime,
3149 * **if** the frame given is a container for font size inflation,
3150 * set the current inflation container on the pres context to null
3151 * (and then, in its destructor, restore the old value).
3152 */
3153 class AutoMaybeDisableFontInflation {
3154 public:
3155 explicit AutoMaybeDisableFontInflation(nsIFrame* aFrame);
3156
3157 ~AutoMaybeDisableFontInflation();
3158
3159 private:
3160 nsPresContext* mPresContext;
3161 bool mOldValue;
3162 };
3163
3164 } // namespace layout
3165 } // namespace mozilla
3166
3167 class nsSetAttrRunnable : public mozilla::Runnable {
3168 public:
3169 nsSetAttrRunnable(mozilla::dom::Element* aElement, nsAtom* aAttrName,
3170 const nsAString& aValue);
3171 nsSetAttrRunnable(mozilla::dom::Element* aElement, nsAtom* aAttrName,
3172 int32_t aValue);
3173
3174 NS_DECL_NSIRUNNABLE
3175
3176 RefPtr<mozilla::dom::Element> mElement;
3177 RefPtr<nsAtom> mAttrName;
3178 nsAutoString mValue;
3179 };
3180
3181 class nsUnsetAttrRunnable : public mozilla::Runnable {
3182 public:
3183 nsUnsetAttrRunnable(mozilla::dom::Element* aElement, nsAtom* aAttrName);
3184
3185 NS_DECL_NSIRUNNABLE
3186
3187 RefPtr<mozilla::dom::Element> mElement;
3188 RefPtr<nsAtom> mAttrName;
3189 };
3190
3191 // This class allows you to easily set any pointer variable and ensure it's
3192 // set to nullptr when leaving its scope.
3193 template <typename T>
3194 class MOZ_RAII SetAndNullOnExit {
3195 public:
SetAndNullOnExit(T * & aVariable,T * aValue)3196 SetAndNullOnExit(T*& aVariable, T* aValue) {
3197 aVariable = aValue;
3198 mVariable = &aVariable;
3199 }
~SetAndNullOnExit()3200 ~SetAndNullOnExit() { *mVariable = nullptr; }
3201
3202 private:
3203 T** mVariable;
3204 };
3205
3206 #endif // nsLayoutUtils_h__
3207