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 /* interface for all rendering objects */
8 
9 #ifndef nsIFrame_h___
10 #define nsIFrame_h___
11 
12 #ifndef MOZILLA_INTERNAL_API
13 #error This header/class should only be used within Mozilla code. It should not be used by extensions.
14 #endif
15 
16 #if (defined(XP_WIN) && !defined(HAVE_64BIT_BUILD)) || defined(ANDROID)
17 // Blink's magic depth limit from its HTML parser (513) plus as much as fits in
18 // the default run-time stack on armv7 Android on Dalvik when using display:
19 // block minus a bit just to be sure. The Dalvik default stack crashes at 588.
20 // ART can do a few frames more. Using the same number for 32-bit Windows for
21 // consistency. Over there, Blink's magic depth of 513 doesn't fit in the
22 // default stack of 1 MB, but this magic depth fits when the default is grown by
23 // mere 192 KB (tested in 64 KB increments).
24 //
25 // 32-bit Windows has a different limit compared to 64-bit desktop, because the
26 // default stack size affects all threads and consumes address space. Fixing
27 // that is bug 1257522.
28 //
29 // 32-bit Android on ARM already happens to have defaults that are close enough
30 // to what makes sense as a temporary measure on Windows, so adjusting the
31 // Android stack can be a follow-up. The stack on 64-bit ARM needs adjusting in
32 // any case before 64-bit ARM can become tier-1. See bug 1400811.
33 //
34 // Ideally, we'd get rid of this smaller limit and make 32-bit Windows and
35 // Android capable of working with the Linux/Mac/Win64 number below.
36 #  define MAX_REFLOW_DEPTH 585
37 #else
38 // Blink's magic depth limit from its HTML parser times two. Also just about
39 // fits within the system default runtime stack limit of 8 MB on 64-bit Mac and
40 // Linux with display: table-cell.
41 #  define MAX_REFLOW_DEPTH 1026
42 #endif
43 
44 /* nsIFrame is in the process of being deCOMtaminated, i.e., this file is
45    eventually going to be eliminated, and all callers will use nsFrame instead.
46    At the moment we're midway through this process, so you will see inlined
47    functions and member variables in this file.  -dwh */
48 
49 #include <algorithm>
50 #include <stdio.h>
51 
52 #include "CaretAssociationHint.h"
53 #include "FrameProperties.h"
54 #include "LayoutConstants.h"
55 #include "mozilla/layout/FrameChildList.h"
56 #include "mozilla/AspectRatio.h"
57 #include "mozilla/Attributes.h"
58 #include "mozilla/EventForwards.h"
59 #include "mozilla/Maybe.h"
60 #include "mozilla/RelativeTo.h"
61 #include "mozilla/Result.h"
62 #include "mozilla/SmallPointerArray.h"
63 #include "mozilla/ToString.h"
64 #include "mozilla/WritingModes.h"
65 #include "nsDirection.h"
66 #include "nsFrameList.h"
67 #include "nsFrameState.h"
68 #include "mozilla/ReflowInput.h"
69 #include "nsIContent.h"
70 #include "nsITheme.h"
71 #include "nsQueryFrame.h"
72 #include "mozilla/ComputedStyle.h"
73 #include "nsStyleStruct.h"
74 #include "Visibility.h"
75 #include "nsChangeHint.h"
76 #include "mozilla/ComputedStyleInlines.h"
77 #include "mozilla/EnumSet.h"
78 #include "mozilla/gfx/2D.h"
79 #include "mozilla/gfx/CompositorHitTestInfo.h"
80 #include "mozilla/gfx/MatrixFwd.h"
81 #include "nsDisplayItemTypes.h"
82 #include "nsPresContext.h"
83 #include "nsTHashSet.h"
84 
85 #ifdef ACCESSIBILITY
86 #  include "mozilla/a11y/AccTypes.h"
87 #endif
88 
89 /**
90  * New rules of reflow:
91  * 1. you get a WillReflow() followed by a Reflow() followed by a DidReflow() in
92  *    order (no separate pass over the tree)
93  * 2. it's the parent frame's responsibility to size/position the child's view
94  *    (not the child frame's responsibility as it is today) during reflow (and
95  *    before sending the DidReflow() notification)
96  * 3. positioning of child frames (and their views) is done on the way down the
97  *    tree, and sizing of child frames (and their views) on the way back up
98  * 4. if you move a frame (outside of the reflow process, or after reflowing
99  *    it), then you must make sure that its view (or its child frame's views)
100  *    are re-positioned as well. It's reasonable to not position the view until
101  *    after all reflowing the entire line, for example, but the frame should
102  *    still be positioned and sized (and the view sized) during the reflow
103  *    (i.e., before sending the DidReflow() notification)
104  * 5. the view system handles moving of widgets, i.e., it's not our problem
105  */
106 
107 class nsAtom;
108 class nsView;
109 class nsFrameSelection;
110 class nsIWidget;
111 class nsIScrollableFrame;
112 class nsISelectionController;
113 class nsBoxLayoutState;
114 class nsBoxLayout;
115 class nsILineIterator;
116 class nsDisplayItem;
117 class nsDisplayItemBase;
118 class nsDisplayListBuilder;
119 class nsDisplayListSet;
120 class nsDisplayList;
121 class gfxSkipChars;
122 class gfxSkipCharsIterator;
123 class gfxContext;
124 class nsLineList_iterator;
125 class nsAbsoluteContainingBlock;
126 class nsContainerFrame;
127 class nsPlaceholderFrame;
128 class nsStyleChangeList;
129 class nsViewManager;
130 class nsWindowSizes;
131 
132 struct nsBoxLayoutMetrics;
133 struct nsPeekOffsetStruct;
134 struct CharacterDataChangeInfo;
135 
136 namespace mozilla {
137 
138 enum class PseudoStyleType : uint8_t;
139 enum class TableSelectionMode : uint32_t;
140 class EventStates;
141 class ServoRestyleState;
142 class DisplayItemData;
143 class EffectSet;
144 class LazyLogModule;
145 class PresShell;
146 class WidgetGUIEvent;
147 class WidgetMouseEvent;
148 
149 namespace layers {
150 class Layer;
151 class LayerManager;
152 }  // namespace layers
153 
154 namespace layout {
155 class ScrollAnchorContainer;
156 }  // namespace layout
157 
158 }  // namespace mozilla
159 
160 //----------------------------------------------------------------------
161 
162 // 1 million CSS pixels less than our max app unit measure.
163 // For reflowing with an "infinite" available inline space per [css-sizing].
164 // (reflowing with an NS_UNCONSTRAINEDSIZE available inline size isn't allowed
165 //  and leads to assertions)
166 #define INFINITE_ISIZE_COORD nscoord(NS_MAXSIZE - (1000000 * 60))
167 
168 //----------------------------------------------------------------------
169 
170 namespace mozilla {
171 
172 enum class LayoutFrameType : uint8_t {
173 #define FRAME_TYPE(ty_, ...) ty_,
174 #include "mozilla/FrameTypeList.h"
175 #undef FRAME_TYPE
176 };
177 
178 }  // namespace mozilla
179 
180 enum nsSelectionAmount {
181   eSelectCharacter = 0,  // a single Unicode character;
182                          // do not use this (prefer Cluster) unless you
183                          // are really sure it's what you want
184   eSelectCluster = 1,    // a grapheme cluster: this is usually the right
185                          // choice for movement or selection by "character"
186                          // as perceived by the user
187   eSelectWord = 2,
188   eSelectWordNoSpace = 3,  // select a "word" without selecting the following
189                            // space, no matter what the default platform
190                            // behavior is
191   eSelectLine = 4,         // previous drawn line in flow.
192   // NOTE that selection code depends on the ordering of the above values,
193   // allowing simple <= tests to check categories of caret movement.
194   // Don't rearrange without checking the usage in nsSelection.cpp!
195 
196   eSelectBeginLine = 5,
197   eSelectEndLine = 6,
198   eSelectNoAmount = 7,  // just bounce back current offset.
199   eSelectParagraph = 8  // select a "paragraph"
200 };
201 
202 //----------------------------------------------------------------------
203 // Reflow status returned by the Reflow() methods.
204 class nsReflowStatus final {
205   using StyleClear = mozilla::StyleClear;
206 
207  public:
nsReflowStatus()208   nsReflowStatus()
209       : mBreakType(StyleClear::None),
210         mInlineBreak(InlineBreak::None),
211         mCompletion(Completion::FullyComplete),
212         mNextInFlowNeedsReflow(false),
213         mTruncated(false),
214         mFirstLetterComplete(false) {}
215 
216   // Reset all the member variables.
Reset()217   void Reset() {
218     mBreakType = StyleClear::None;
219     mInlineBreak = InlineBreak::None;
220     mCompletion = Completion::FullyComplete;
221     mNextInFlowNeedsReflow = false;
222     mTruncated = false;
223     mFirstLetterComplete = false;
224   }
225 
226   // Return true if all member variables have their default values.
IsEmpty()227   bool IsEmpty() const {
228     return (IsFullyComplete() && !IsInlineBreak() && !mNextInFlowNeedsReflow &&
229             !mTruncated && !mFirstLetterComplete);
230   }
231 
232   // There are three possible completion statuses, represented by
233   // mCompletion.
234   //
235   // Incomplete means the frame does *not* map all its content, and the
236   // parent frame should create a continuing frame.
237   //
238   // OverflowIncomplete means that the frame has an overflow that is not
239   // complete, but its own box is complete. (This happens when the content
240   // overflows a fixed-height box.) The reflower should place and size the
241   // frame and continue its reflow, but it needs to create an overflow
242   // container as a continuation for this frame. See "Overflow containers"
243   // documentation in nsContainerFrame.h for more information.
244   //
245   // FullyComplete means the frame is neither Incomplete nor
246   // OverflowIncomplete. This is the default state for a nsReflowStatus.
247   //
248   enum class Completion : uint8_t {
249     // The order of the enum values is important, which represents the
250     // precedence when merging.
251     FullyComplete,
252     OverflowIncomplete,
253     Incomplete,
254   };
255 
IsIncomplete()256   bool IsIncomplete() const { return mCompletion == Completion::Incomplete; }
IsOverflowIncomplete()257   bool IsOverflowIncomplete() const {
258     return mCompletion == Completion::OverflowIncomplete;
259   }
IsFullyComplete()260   bool IsFullyComplete() const {
261     return mCompletion == Completion::FullyComplete;
262   }
263   // Just for convenience; not a distinct state.
IsComplete()264   bool IsComplete() const { return !IsIncomplete(); }
265 
SetIncomplete()266   void SetIncomplete() { mCompletion = Completion::Incomplete; }
SetOverflowIncomplete()267   void SetOverflowIncomplete() { mCompletion = Completion::OverflowIncomplete; }
268 
269   // mNextInFlowNeedsReflow bit flag means that the next-in-flow is dirty,
270   // and also needs to be reflowed. This status only makes sense for a frame
271   // that is not complete, i.e. you wouldn't set mNextInFlowNeedsReflow when
272   // IsComplete() is true.
NextInFlowNeedsReflow()273   bool NextInFlowNeedsReflow() const { return mNextInFlowNeedsReflow; }
SetNextInFlowNeedsReflow()274   void SetNextInFlowNeedsReflow() { mNextInFlowNeedsReflow = true; }
275 
276   // mTruncated bit flag means that the part of the frame before the first
277   // possible break point was unable to fit in the available space.
278   // Therefore, the entire frame should be moved to the next continuation of
279   // the parent frame. A frame that begins at the top of the page must never
280   // be truncated. Doing so would likely cause an infinite loop.
IsTruncated()281   bool IsTruncated() const { return mTruncated; }
282   void UpdateTruncated(const mozilla::ReflowInput& aReflowInput,
283                        const mozilla::ReflowOutput& aMetrics);
284 
285   // Merge the frame completion status bits from aStatus into this.
MergeCompletionStatusFrom(const nsReflowStatus & aStatus)286   void MergeCompletionStatusFrom(const nsReflowStatus& aStatus) {
287     if (mCompletion < aStatus.mCompletion) {
288       mCompletion = aStatus.mCompletion;
289     }
290 
291     // These asserts ensure that the mCompletion merging works as we expect.
292     // (Incomplete beats OverflowIncomplete, which beats FullyComplete.)
293     static_assert(
294         Completion::Incomplete > Completion::OverflowIncomplete &&
295             Completion::OverflowIncomplete > Completion::FullyComplete,
296         "mCompletion merging won't work without this!");
297 
298     mNextInFlowNeedsReflow |= aStatus.mNextInFlowNeedsReflow;
299     mTruncated |= aStatus.mTruncated;
300   }
301 
302   // There are three possible inline-break statuses, represented by
303   // mInlineBreak.
304   //
305   // "None" means no break is requested.
306   // "Before" means the break should occur before the frame.
307   // "After" means the break should occur after the frame.
308   // (Here, "the frame" is the frame whose reflow results are being reported by
309   // this nsReflowStatus.)
310   //
311   enum class InlineBreak : uint8_t {
312     None,
313     Before,
314     After,
315   };
316 
IsInlineBreak()317   bool IsInlineBreak() const { return mInlineBreak != InlineBreak::None; }
IsInlineBreakBefore()318   bool IsInlineBreakBefore() const {
319     return mInlineBreak == InlineBreak::Before;
320   }
IsInlineBreakAfter()321   bool IsInlineBreakAfter() const { return mInlineBreak == InlineBreak::After; }
BreakType()322   StyleClear BreakType() const { return mBreakType; }
323 
324   // Set the inline line-break-before status, and reset other bit flags. The
325   // break type is StyleClear::Line. Note that other frame completion status
326   // isn't expected to matter after calling this method.
SetInlineLineBreakBeforeAndReset()327   void SetInlineLineBreakBeforeAndReset() {
328     Reset();
329     mBreakType = StyleClear::Line;
330     mInlineBreak = InlineBreak::Before;
331   }
332 
333   // Set the inline line-break-after status. The break type can be changed
334   // via the optional aBreakType param.
335   void SetInlineLineBreakAfter(StyleClear aBreakType = StyleClear::Line) {
336     MOZ_ASSERT(aBreakType != StyleClear::None,
337                "Break-after with StyleClear::None is meaningless!");
338     mBreakType = aBreakType;
339     mInlineBreak = InlineBreak::After;
340   }
341 
342   // mFirstLetterComplete bit flag means the break was induced by
343   // completion of a first-letter.
FirstLetterComplete()344   bool FirstLetterComplete() const { return mFirstLetterComplete; }
SetFirstLetterComplete()345   void SetFirstLetterComplete() { mFirstLetterComplete = true; }
346 
347  private:
348   StyleClear mBreakType;
349   InlineBreak mInlineBreak;
350   Completion mCompletion;
351   bool mNextInFlowNeedsReflow : 1;
352   bool mTruncated : 1;
353   bool mFirstLetterComplete : 1;
354 };
355 
356 #define NS_FRAME_SET_TRUNCATION(aStatus, aReflowInput, aMetrics) \
357   aStatus.UpdateTruncated(aReflowInput, aMetrics);
358 
359 // Convert nsReflowStatus to a human-readable string.
360 std::ostream& operator<<(std::ostream& aStream, const nsReflowStatus& aStatus);
361 
362 /**
363  * nsBidiLevel is the type of the level values in our Unicode Bidi
364  * implementation.
365  * It holds an embedding level and indicates the visual direction
366  * by its bit 0 (even/odd value).<p>
367  *
368  * <li><code>aParaLevel</code> can be set to the
369  * pseudo-level values <code>NSBIDI_DEFAULT_LTR</code>
370  * and <code>NSBIDI_DEFAULT_RTL</code>.</li></ul>
371  *
372  * @see nsBidi::SetPara
373  *
374  * <p>The related constants are not real, valid level values.
375  * <code>NSBIDI_DEFAULT_XXX</code> can be used to specify
376  * a default for the paragraph level for
377  * when the <code>SetPara</code> function
378  * shall determine it but there is no
379  * strongly typed character in the input.<p>
380  *
381  * Note that the value for <code>NSBIDI_DEFAULT_LTR</code> is even
382  * and the one for <code>NSBIDI_DEFAULT_RTL</code> is odd,
383  * just like with normal LTR and RTL level values -
384  * these special values are designed that way. Also, the implementation
385  * assumes that NSBIDI_MAX_EXPLICIT_LEVEL is odd.
386  *
387  * @see NSBIDI_DEFAULT_LTR
388  * @see NSBIDI_DEFAULT_RTL
389  * @see NSBIDI_LEVEL_OVERRIDE
390  * @see NSBIDI_MAX_EXPLICIT_LEVEL
391  */
392 typedef uint8_t nsBidiLevel;
393 
394 /**
395  * Paragraph level setting.
396  * If there is no strong character, then set the paragraph level to 0
397  * (left-to-right).
398  */
399 #define NSBIDI_DEFAULT_LTR 0xfe
400 
401 /**
402  * Paragraph level setting.
403  * If there is no strong character, then set the paragraph level to 1
404  * (right-to-left).
405  */
406 #define NSBIDI_DEFAULT_RTL 0xff
407 
408 /**
409  * Maximum explicit embedding level.
410  * (The maximum resolved level can be up to
411  * <code>NSBIDI_MAX_EXPLICIT_LEVEL+1</code>).
412  */
413 #define NSBIDI_MAX_EXPLICIT_LEVEL 125
414 
415 /** Bit flag for level input.
416  *  Overrides directional properties.
417  */
418 #define NSBIDI_LEVEL_OVERRIDE 0x80
419 
420 /**
421  * <code>nsBidiDirection</code> values indicate the text direction.
422  */
423 enum nsBidiDirection {
424   /** All left-to-right text This is a 0 value. */
425   NSBIDI_LTR,
426   /** All right-to-left text This is a 1 value. */
427   NSBIDI_RTL,
428   /** Mixed-directional text. */
429   NSBIDI_MIXED
430 };
431 
432 namespace mozilla {
433 
434 // https://drafts.csswg.org/css-align-3/#baseline-sharing-group
435 enum class BaselineSharingGroup {
436   // NOTE Used as an array index so must be 0 and 1.
437   First = 0,
438   Last = 1,
439 };
440 
441 // Loosely: https://drafts.csswg.org/css-align-3/#shared-alignment-context
442 enum class AlignmentContext {
443   Inline,
444   Table,
445   Flexbox,
446   Grid,
447 };
448 
449 /*
450  * For replaced elements only. Gets the intrinsic dimensions of this element,
451  * which can be specified on a per-axis basis.
452  */
453 struct IntrinsicSize {
454   Maybe<nscoord> width;
455   Maybe<nscoord> height;
456 
457   IntrinsicSize() = default;
458 
IntrinsicSizeIntrinsicSize459   IntrinsicSize(nscoord aWidth, nscoord aHeight)
460       : width(Some(aWidth)), height(Some(aHeight)) {}
461 
IntrinsicSizeIntrinsicSize462   explicit IntrinsicSize(const nsSize& aSize)
463       : IntrinsicSize(aSize.Width(), aSize.Height()) {}
464 
ToSizeIntrinsicSize465   Maybe<nsSize> ToSize() const {
466     return width && height ? Some(nsSize(*width, *height)) : Nothing();
467   }
468 
469   bool operator==(const IntrinsicSize& rhs) const {
470     return width == rhs.width && height == rhs.height;
471   }
472   bool operator!=(const IntrinsicSize& rhs) const { return !(*this == rhs); }
473 };
474 
475 // Pseudo bidi embedding level indicating nonexistence.
476 static const nsBidiLevel kBidiLevelNone = 0xff;
477 
478 struct FrameBidiData {
479   nsBidiLevel baseLevel;
480   nsBidiLevel embeddingLevel;
481   // The embedding level of virtual bidi formatting character before
482   // this frame if any. kBidiLevelNone is used to indicate nonexistence
483   // or unnecessity of such virtual character.
484   nsBidiLevel precedingControl;
485 };
486 
487 }  // namespace mozilla
488 
489 /// Generic destructor for frame properties. Calls delete.
490 template <typename T>
DeleteValue(T * aPropertyValue)491 static void DeleteValue(T* aPropertyValue) {
492   delete aPropertyValue;
493 }
494 
495 /// Generic destructor for frame properties. Calls Release().
496 template <typename T>
ReleaseValue(T * aPropertyValue)497 static void ReleaseValue(T* aPropertyValue) {
498   aPropertyValue->Release();
499 }
500 
501 //----------------------------------------------------------------------
502 
503 /**
504  * nsIFrame logging constants. We redefine the nspr
505  * PRLogModuleInfo.level field to be a bitfield.  Each bit controls a
506  * specific type of logging. Each logging operation has associated
507  * inline methods defined below.
508  *
509  * Due to the redefinition of the level field we cannot use MOZ_LOG directly
510  * as that will cause assertions due to invalid log levels.
511  */
512 #define NS_FRAME_TRACE_CALLS 0x1
513 #define NS_FRAME_TRACE_PUSH_PULL 0x2
514 #define NS_FRAME_TRACE_CHILD_REFLOW 0x4
515 #define NS_FRAME_TRACE_NEW_FRAMES 0x8
516 
517 #define NS_FRAME_LOG_TEST(_lm, _bit) \
518   (int(((mozilla::LogModule*)(_lm))->Level()) & (_bit))
519 
520 #ifdef DEBUG
521 #  define NS_FRAME_LOG(_bit, _args)                           \
522     PR_BEGIN_MACRO                                            \
523     if (NS_FRAME_LOG_TEST(nsIFrame::sFrameLogModule, _bit)) { \
524       printf_stderr _args;                                    \
525     }                                                         \
526     PR_END_MACRO
527 #else
528 #  define NS_FRAME_LOG(_bit, _args)
529 #endif
530 
531 // XXX Need to rework this so that logging is free when it's off
532 #ifdef DEBUG
533 #  define NS_FRAME_TRACE_IN(_method) Trace(_method, true)
534 
535 #  define NS_FRAME_TRACE_OUT(_method) Trace(_method, false)
536 
537 #  define NS_FRAME_TRACE(_bit, _args)                         \
538     PR_BEGIN_MACRO                                            \
539     if (NS_FRAME_LOG_TEST(nsIFrame::sFrameLogModule, _bit)) { \
540       TraceMsg _args;                                         \
541     }                                                         \
542     PR_END_MACRO
543 
544 #  define NS_FRAME_TRACE_REFLOW_IN(_method) Trace(_method, true)
545 
546 #  define NS_FRAME_TRACE_REFLOW_OUT(_method, _status) \
547     Trace(_method, false, _status)
548 
549 #else
550 #  define NS_FRAME_TRACE(_bits, _args)
551 #  define NS_FRAME_TRACE_IN(_method)
552 #  define NS_FRAME_TRACE_OUT(_method)
553 #  define NS_FRAME_TRACE_REFLOW_IN(_method)
554 #  define NS_FRAME_TRACE_REFLOW_OUT(_method, _status)
555 #endif
556 
557 //----------------------------------------------------------------------
558 
559 // Frame allocation boilerplate macros. Every subclass of nsFrame must
560 // either use NS_{DECL,IMPL}_FRAMEARENA_HELPERS pair for allocating
561 // memory correctly, or use NS_DECL_ABSTRACT_FRAME to declare a frame
562 // class abstract and stop it from being instantiated. If a frame class
563 // without its own operator new and GetFrameId gets instantiated, the
564 // per-frame recycler lists in nsPresArena will not work correctly,
565 // with potentially catastrophic consequences (not enough memory is
566 // allocated for a frame object).
567 
568 #define NS_DECL_FRAMEARENA_HELPERS(class)                                      \
569   NS_DECL_QUERYFRAME_TARGET(class)                                             \
570   static constexpr nsIFrame::ClassID kClassID = nsIFrame::ClassID::class##_id; \
571   void* operator new(size_t, mozilla::PresShell*) MOZ_MUST_OVERRIDE;           \
572   nsQueryFrame::FrameIID GetFrameId() const override MOZ_MUST_OVERRIDE {       \
573     return nsQueryFrame::class##_id;                                           \
574   }
575 
576 #define NS_IMPL_FRAMEARENA_HELPERS(class)                             \
577   void* class ::operator new(size_t sz, mozilla::PresShell* aShell) { \
578     return aShell->AllocateFrame(nsQueryFrame::class##_id, sz);       \
579   }
580 
581 #define NS_DECL_ABSTRACT_FRAME(class)                                         \
582   void* operator new(size_t, mozilla::PresShell*) MOZ_MUST_OVERRIDE = delete; \
583   nsQueryFrame::FrameIID GetFrameId() const override MOZ_MUST_OVERRIDE = 0;
584 
585 //----------------------------------------------------------------------
586 
587 /**
588  * A frame in the layout model. This interface is supported by all frame
589  * objects.
590  *
591  * Frames can have multiple child lists: the default child list
592  * (referred to as the <i>principal</i> child list, and additional named
593  * child lists. There is an ordering of frames within a child list, but
594  * there is no order defined between frames in different child lists of
595  * the same parent frame.
596  *
597  * Frames are NOT reference counted. Use the Destroy() member function
598  * to destroy a frame. The lifetime of the frame hierarchy is bounded by the
599  * lifetime of the presentation shell which owns the frames.
600  *
601  * nsIFrame is a private Gecko interface. If you are not Gecko then you
602  * should not use it. If you're not in layout, then you won't be able to
603  * link to many of the functions defined here. Too bad.
604  *
605  * If you're not in layout but you must call functions in here, at least
606  * restrict yourself to calling virtual methods, which won't hurt you as badly.
607  */
608 class nsIFrame : public nsQueryFrame {
609  public:
610   using AlignmentContext = mozilla::AlignmentContext;
611   using BaselineSharingGroup = mozilla::BaselineSharingGroup;
612   template <typename T>
613   using Maybe = mozilla::Maybe<T>;
614   template <typename T, typename E>
615   using Result = mozilla::Result<T, E>;
616   using Nothing = mozilla::Nothing;
617   using OnNonvisible = mozilla::OnNonvisible;
618   using ReflowInput = mozilla::ReflowInput;
619   using ReflowOutput = mozilla::ReflowOutput;
620   using Visibility = mozilla::Visibility;
621   using LengthPercentage = mozilla::LengthPercentage;
622 
623   typedef mozilla::ComputedStyle ComputedStyle;
624   typedef mozilla::FrameProperties FrameProperties;
625   typedef mozilla::layers::Layer Layer;
626   typedef mozilla::layers::LayerManager LayerManager;
627   typedef mozilla::layout::FrameChildList ChildList;
628   typedef mozilla::layout::FrameChildListID ChildListID;
629   typedef mozilla::layout::FrameChildListIDs ChildListIDs;
630   typedef mozilla::gfx::DrawTarget DrawTarget;
631   typedef mozilla::gfx::Matrix Matrix;
632   typedef mozilla::gfx::Matrix4x4 Matrix4x4;
633   typedef mozilla::gfx::Matrix4x4Flagged Matrix4x4Flagged;
634   typedef mozilla::Sides Sides;
635   typedef mozilla::LogicalSides LogicalSides;
636   typedef mozilla::SmallPointerArray<mozilla::DisplayItemData>
637       DisplayItemDataArray;
638   typedef mozilla::SmallPointerArray<nsDisplayItemBase> DisplayItemArray;
639 
640   typedef nsQueryFrame::ClassID ClassID;
641 
642   // nsQueryFrame
643   NS_DECL_QUERYFRAME
NS_DECL_QUERYFRAME_TARGET(nsIFrame)644   NS_DECL_QUERYFRAME_TARGET(nsIFrame)
645 
646   explicit nsIFrame(ComputedStyle* aStyle, nsPresContext* aPresContext,
647                     ClassID aID)
648       : mRect(),
649         mContent(nullptr),
650         mComputedStyle(aStyle),
651         mPresContext(aPresContext),
652         mParent(nullptr),
653         mNextSibling(nullptr),
654         mPrevSibling(nullptr),
655         mState(NS_FRAME_FIRST_REFLOW | NS_FRAME_IS_DIRTY),
656         mWritingMode(aStyle),
657         mClass(aID),
658         mMayHaveRoundedCorners(false),
659         mHasImageRequest(false),
660         mHasFirstLetterChild(false),
661         mParentIsWrapperAnonBox(false),
662         mIsWrapperBoxNeedingRestyle(false),
663         mReflowRequestedForCharDataChange(false),
664         mForceDescendIntoIfVisible(false),
665         mBuiltDisplayList(false),
666         mFrameIsModified(false),
667         mHasOverrideDirtyRegion(false),
668         mMayHaveWillChangeBudget(false),
669         mIsPrimaryFrame(false),
670         mMayHaveTransformAnimation(false),
671         mMayHaveOpacityAnimation(false),
672         mAllDescendantsAreInvisible(false),
673         mHasBSizeChange(false),
674         mInScrollAnchorChain(false),
675         mHasColumnSpanSiblings(false),
676         mDescendantMayDependOnItsStaticPosition(false),
677         mShouldGenerateComputedInfo(false) {
678     MOZ_ASSERT(mComputedStyle);
679     MOZ_ASSERT(mPresContext);
680     mozilla::PodZero(&mOverflow);
681     MOZ_COUNT_CTOR(nsIFrame);
682   }
nsIFrame(ComputedStyle * aStyle,nsPresContext * aPresContext)683   explicit nsIFrame(ComputedStyle* aStyle, nsPresContext* aPresContext)
684       : nsIFrame(aStyle, aPresContext, ClassID::nsIFrame_id) {}
685 
PresContext()686   nsPresContext* PresContext() const { return mPresContext; }
687 
PresShell()688   mozilla::PresShell* PresShell() const { return PresContext()->PresShell(); }
689 
GetFrameId()690   virtual nsQueryFrame::FrameIID GetFrameId() const MOZ_MUST_OVERRIDE {
691     return kFrameIID;
692   }
693 
694   /**
695    * Called to initialize the frame. This is called immediately after creating
696    * the frame.
697    *
698    * If the frame is a continuing frame, then aPrevInFlow indicates the previous
699    * frame (the frame that was split).
700    *
701    * Each subclass that need a view should override this method and call
702    * CreateView() after calling its base class Init().
703    *
704    * @param   aContent the content object associated with the frame
705    * @param   aParent the parent frame
706    * @param   aPrevInFlow the prev-in-flow frame
707    */
708   virtual void Init(nsIContent* aContent, nsContainerFrame* aParent,
709                     nsIFrame* aPrevInFlow);
710 
711   void* operator new(size_t, mozilla::PresShell*) MOZ_MUST_OVERRIDE;
712 
713   using PostDestroyData = mozilla::layout::PostFrameDestroyData;
714   struct MOZ_RAII AutoPostDestroyData {
AutoPostDestroyDataAutoPostDestroyData715     explicit AutoPostDestroyData(nsPresContext* aPresContext)
716         : mPresContext(aPresContext) {}
~AutoPostDestroyDataAutoPostDestroyData717     ~AutoPostDestroyData() {
718       for (auto& content : mozilla::Reversed(mData.mAnonymousContent)) {
719         nsIFrame::DestroyAnonymousContent(mPresContext, content.forget());
720       }
721     }
722     nsPresContext* mPresContext;
723     PostDestroyData mData;
724   };
725   /**
726    * Destroys this frame and each of its child frames (recursively calls
727    * Destroy() for each child). If this frame is a first-continuation, this
728    * also removes the frame from the primary frame map and clears undisplayed
729    * content for its content node.
730    * If the frame is a placeholder, it also ensures the out-of-flow frame's
731    * removal and destruction.
732    */
Destroy()733   void Destroy() {
734     AutoPostDestroyData data(PresContext());
735     DestroyFrom(this, data.mData);
736     // Note that |this| is deleted at this point.
737   }
738 
739   /**
740    * Flags for PeekOffsetCharacter, PeekOffsetNoAmount, PeekOffsetWord return
741    * values.
742    */
743   enum FrameSearchResult {
744     // Peek found a appropriate offset within frame.
745     FOUND = 0x00,
746     // try next frame for offset.
747     CONTINUE = 0x1,
748     // offset not found because the frame was empty of text.
749     CONTINUE_EMPTY = 0x2 | CONTINUE,
750     // offset not found because the frame didn't contain any text that could be
751     // selected.
752     CONTINUE_UNSELECTABLE = 0x4 | CONTINUE,
753   };
754 
755   /**
756    * Options for PeekOffsetCharacter().
757    */
758   struct MOZ_STACK_CLASS PeekOffsetCharacterOptions {
759     // Whether to restrict result to valid cursor locations (between grapheme
760     // clusters) - if this is included, maintains "normal" behavior, otherwise,
761     // used for selection by "code unit" (instead of "character")
762     bool mRespectClusters;
763     // Whether to check user-select style value - if this is included, checks
764     // if user-select is all, then, it may return CONTINUE_UNSELECTABLE.
765     bool mIgnoreUserStyleAll;
766 
PeekOffsetCharacterOptionsPeekOffsetCharacterOptions767     PeekOffsetCharacterOptions()
768         : mRespectClusters(true), mIgnoreUserStyleAll(false) {}
769   };
770 
771  protected:
772   friend class nsBlockFrame;  // for access to DestroyFrom
773 
774   /**
775    * Return true if the frame is part of a Selection.
776    * Helper method to implement the public IsSelected() API.
777    */
778   virtual bool IsFrameSelected() const;
779 
780   /**
781    * Implements Destroy(). Do not call this directly except from within a
782    * DestroyFrom() implementation.
783    *
784    * @note This will always be called, so it is not necessary to override
785    *       Destroy() in subclasses of nsFrame, just DestroyFrom().
786    *
787    * @param  aDestructRoot is the root of the subtree being destroyed
788    */
789   virtual void DestroyFrom(nsIFrame* aDestructRoot,
790                            PostDestroyData& aPostDestroyData);
791   friend class nsFrameList;  // needed to pass aDestructRoot through to children
792   friend class nsLineBox;    // needed to pass aDestructRoot through to children
793   friend class nsContainerFrame;  // needed to pass aDestructRoot through to
794                                   // children
795   template <class Source>
796   friend class do_QueryFrameHelper;  // to read mClass
797 
798   virtual ~nsIFrame();
799 
800   // Overridden to prevent the global delete from being called, since
801   // the memory came out of an arena instead of the heap.
802   //
803   // Ideally this would be private and undefined, like the normal
804   // operator new.  Unfortunately, the C++ standard requires an
805   // overridden operator delete to be accessible to any subclass that
806   // defines a virtual destructor, so we can only make it protected;
807   // worse, some C++ compilers will synthesize calls to this function
808   // from the "deleting destructors" that they emit in case of
809   // delete-expressions, so it can't even be undefined.
810   void operator delete(void* aPtr, size_t sz);
811 
812  private:
813   // Left undefined; nsFrame objects are never allocated from the heap.
814   void* operator new(size_t sz) noexcept(true);
815 
816   // Returns true if this frame has any kind of CSS animations.
817   bool HasCSSAnimations();
818 
819   // Returns true if this frame has any kind of CSS transitions.
820   bool HasCSSTransitions();
821 
822  public:
823   /**
824    * Get the content object associated with this frame. Does not add a
825    * reference.
826    */
GetContent()827   nsIContent* GetContent() const { return mContent; }
828 
829   /**
830    * Get the frame that should be the parent for the frames of child elements
831    * May return nullptr during reflow
832    */
GetContentInsertionFrame()833   virtual nsContainerFrame* GetContentInsertionFrame() { return nullptr; }
834 
835   /**
836    * Move any frames on our overflow list to the end of our principal list.
837    * @return true if there were any overflow frames
838    */
DrainSelfOverflowList()839   virtual bool DrainSelfOverflowList() { return false; }
840 
841   /**
842    * Get the frame that should be scrolled if the content associated
843    * with this frame is targeted for scrolling. For frames implementing
844    * nsIScrollableFrame this will return the frame itself. For frames
845    * like nsTextControlFrame that contain a scrollframe, will return
846    * that scrollframe.
847    */
GetScrollTargetFrame()848   virtual nsIScrollableFrame* GetScrollTargetFrame() const { return nullptr; }
849 
850   /**
851    * Get the offsets of the frame. most will be 0,0
852    *
853    */
854   virtual std::pair<int32_t, int32_t> GetOffsets() const;
855 
856   /**
857    * Reset the offsets when splitting frames during Bidi reordering
858    *
859    */
AdjustOffsetsForBidi(int32_t aStart,int32_t aEnd)860   virtual void AdjustOffsetsForBidi(int32_t aStart, int32_t aEnd) {}
861 
862   /**
863    * Get the style associated with this frame.
864    */
Style()865   ComputedStyle* Style() const { return mComputedStyle; }
866 
867   void AssertNewStyleIsSane(ComputedStyle&)
868 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
869       ;
870 #else
871   {
872   }
873 #endif
874 
SetComputedStyle(ComputedStyle * aStyle)875   void SetComputedStyle(ComputedStyle* aStyle) {
876     if (aStyle != mComputedStyle) {
877       AssertNewStyleIsSane(*aStyle);
878       RefPtr<ComputedStyle> oldComputedStyle = std::move(mComputedStyle);
879       mComputedStyle = aStyle;
880       DidSetComputedStyle(oldComputedStyle);
881     }
882   }
883 
884   /**
885    * SetComputedStyleWithoutNotification is for changes to the style
886    * context that should suppress style change processing, in other
887    * words, those that aren't really changes.  This generally means only
888    * changes that happen during frame construction.
889    */
SetComputedStyleWithoutNotification(ComputedStyle * aStyle)890   void SetComputedStyleWithoutNotification(ComputedStyle* aStyle) {
891     if (aStyle != mComputedStyle) {
892       mComputedStyle = aStyle;
893     }
894   }
895 
896  protected:
897   // Style post processing hook
898   // Attention: the old style is the one we're forgetting,
899   // and hence possibly completely bogus for GetStyle* purposes.
900   // Use PeekStyleData instead.
901   virtual void DidSetComputedStyle(ComputedStyle* aOldComputedStyle);
902 
903  public:
904 /**
905  * Define typesafe getter functions for each style struct by
906  * preprocessing the list of style structs.  These functions are the
907  * preferred way to get style data.  The macro creates functions like:
908  *   const nsStyleBorder* StyleBorder();
909  *   const nsStyleColor* StyleColor();
910  *
911  * Callers outside of libxul should use nsIDOMWindow::GetComputedStyle()
912  * instead of these accessors.
913  *
914  * Callers can use Style*WithOptionalParam if they're in a function that
915  * accepts an *optional* pointer the style struct.
916  */
917 #define STYLE_STRUCT(name_)                                          \
918   const nsStyle##name_* Style##name_() const MOZ_NONNULL_RETURN {    \
919     NS_ASSERTION(mComputedStyle, "No style found!");                 \
920     return mComputedStyle->Style##name_();                           \
921   }                                                                  \
922   const nsStyle##name_* Style##name_##WithOptionalParam(             \
923       const nsStyle##name_* aStyleStruct) const MOZ_NONNULL_RETURN { \
924     if (aStyleStruct) {                                              \
925       MOZ_ASSERT(aStyleStruct == Style##name_());                    \
926       return aStyleStruct;                                           \
927     }                                                                \
928     return Style##name_();                                           \
929   }
930 #include "nsStyleStructList.h"
931 #undef STYLE_STRUCT
932 
933   /** Also forward GetVisitedDependentColor to the style */
934   template <typename T, typename S>
GetVisitedDependentColor(T S::* aField)935   nscolor GetVisitedDependentColor(T S::*aField) {
936     return mComputedStyle->GetVisitedDependentColor(aField);
937   }
938 
939   /**
940    * These methods are to access any additional ComputedStyles that
941    * the frame may be holding.
942    *
943    * These are styles that are children of the frame's primary style and are NOT
944    * used as styles for any child frames.
945    *
946    * These contexts also MUST NOT have any child styles whatsoever. If you need
947    * to insert styles into the style tree, then you should create pseudo element
948    * frames to own them.
949    *
950    * The indicies must be consecutive and implementations MUST return null if
951    * asked for an index that is out of range.
952    */
953   virtual ComputedStyle* GetAdditionalComputedStyle(int32_t aIndex) const;
954 
955   virtual void SetAdditionalComputedStyle(int32_t aIndex,
956                                           ComputedStyle* aComputedStyle);
957 
958   /**
959    * @param aSelectionStatus nsISelectionController::getDisplaySelection.
960    */
961   already_AddRefed<ComputedStyle> ComputeSelectionStyle(
962       int16_t aSelectionStatus) const;
963 
964   /**
965    * Accessor functions for geometric parent.
966    */
GetParent()967   nsContainerFrame* GetParent() const { return mParent; }
968 
969   bool CanBeDynamicReflowRoot() const;
970 
971   /**
972    * Gets the parent of a frame, using the parent of the placeholder for
973    * out-of-flow frames.
974    */
975   inline nsContainerFrame* GetInFlowParent() const;
976 
977   /**
978    * Gets the primary frame of the closest flattened tree ancestor that has a
979    * frame (flattened tree ancestors may not have frames in presence of display:
980    * contents).
981    */
982   inline nsIFrame* GetClosestFlattenedTreeAncestorPrimaryFrame() const;
983 
984   /**
985    * Return the placeholder for this frame (which must be out-of-flow).
986    * @note this will only return non-null if |this| is the first-in-flow
987    * although we don't assert that here for legacy reasons.
988    */
GetPlaceholderFrame()989   inline nsPlaceholderFrame* GetPlaceholderFrame() const {
990     MOZ_ASSERT(HasAnyStateBits(NS_FRAME_OUT_OF_FLOW));
991     return GetProperty(PlaceholderFrameProperty());
992   }
993 
994   /**
995    * Set this frame's parent to aParent.
996    * If the frame may have moved into or out of a scrollframe's
997    * frame subtree,
998    * StickyScrollContainer::NotifyReparentedFrameAcrossScrollFrameBoundary must
999    * also be called.
1000    */
1001   void SetParent(nsContainerFrame* aParent);
1002 
1003   /**
1004    * The frame's writing-mode, used for logical layout computations.
1005    * It's usually the 'writing-mode' computed value, but there are exceptions:
1006    *   * inner table frames copy the value from the table frame
1007    *     (@see nsTableRowGroupFrame::Init, nsTableRowFrame::Init etc)
1008    *   * the root element frame propagates its value to its ancestors.
1009    *     The value may obtain from the principal <body> element.
1010    *     (@see nsCSSFrameConstructor::ConstructDocElementFrame)
1011    *   * the internal anonymous frames of the root element copy their value
1012    *     from the parent.
1013    *     (@see nsIFrame::Init)
1014    *   * a scrolled frame propagates its value to its ancestor scroll frame
1015    *     (@see nsHTMLScrollFrame::ReloadChildFrames)
1016    */
GetWritingMode()1017   mozilla::WritingMode GetWritingMode() const { return mWritingMode; }
1018 
1019   /**
1020    * Construct a writing mode for line layout in this frame.  This is
1021    * the writing mode of this frame, except that if this frame is styled with
1022    * unicode-bidi:plaintext, we reset the direction to the resolved paragraph
1023    * level of the given subframe (typically the first frame on the line),
1024    * because the container frame could be split by hard line breaks into
1025    * multiple paragraphs with different base direction.
1026    * @param aSelfWM the WM of 'this'
1027    */
1028   mozilla::WritingMode WritingModeForLine(mozilla::WritingMode aSelfWM,
1029                                           nsIFrame* aSubFrame) const;
1030 
1031   /**
1032    * Bounding rect of the frame.
1033    *
1034    * For frames that are laid out according to CSS box model rules the values
1035    * are in app units, and the origin is relative to the upper-left of the
1036    * geometric parent.  The size includes the content area, borders, and
1037    * padding.
1038    *
1039    * Frames that are laid out according to SVG's coordinate space based rules
1040    * (frames with the NS_FRAME_SVG_LAYOUT bit set, which *excludes*
1041    * SVGOuterSVGFrame) are different.  Many frames of this type do not set or
1042    * use mRect, in which case the frame rect is undefined.  The exceptions are:
1043    *
1044    *   - SVGInnerSVGFrame
1045    *   - SVGGeometryFrame (used for <path>, <circle>, etc.)
1046    *   - SVGImageFrame
1047    *   - SVGForeignObjectFrame
1048    *
1049    * For these frames the frame rect contains the frame's element's userspace
1050    * bounds including fill, stroke and markers, but converted to app units
1051    * rather than being in user units (CSS px).  In the SVG code "userspace" is
1052    * defined to be the coordinate system for the attributes that define an
1053    * element's geometry (such as the 'cx' attribute for <circle>).  For more
1054    * precise details see these frames' implementations of the ReflowSVG method
1055    * where mRect is set.
1056    *
1057    * Note: moving or sizing the frame does not affect the view's size or
1058    * position.
1059    */
GetRect()1060   nsRect GetRect() const { return mRect; }
GetPosition()1061   nsPoint GetPosition() const { return mRect.TopLeft(); }
GetSize()1062   nsSize GetSize() const { return mRect.Size(); }
GetRectRelativeToSelf()1063   nsRect GetRectRelativeToSelf() const {
1064     return nsRect(nsPoint(0, 0), mRect.Size());
1065   }
1066 
1067   /**
1068    * Like the frame's rect (see |GetRect|), which is the border rect,
1069    * other rectangles of the frame, in app units, relative to the parent.
1070    */
1071   nsRect GetPaddingRect() const;
1072   nsRect GetPaddingRectRelativeToSelf() const;
1073   nsRect GetContentRect() const;
1074   nsRect GetContentRectRelativeToSelf() const;
1075   nsRect GetMarginRect() const;
1076   nsRect GetMarginRectRelativeToSelf() const;
1077 
1078   /**
1079    * Dimensions and position in logical coordinates in the frame's writing mode
1080    *  or another writing mode
1081    */
GetLogicalRect(const nsSize & aContainerSize)1082   mozilla::LogicalRect GetLogicalRect(const nsSize& aContainerSize) const {
1083     return GetLogicalRect(GetWritingMode(), aContainerSize);
1084   }
GetLogicalPosition(const nsSize & aContainerSize)1085   mozilla::LogicalPoint GetLogicalPosition(const nsSize& aContainerSize) const {
1086     return GetLogicalPosition(GetWritingMode(), aContainerSize);
1087   }
GetLogicalSize()1088   mozilla::LogicalSize GetLogicalSize() const {
1089     return GetLogicalSize(GetWritingMode());
1090   }
GetLogicalRect(mozilla::WritingMode aWritingMode,const nsSize & aContainerSize)1091   mozilla::LogicalRect GetLogicalRect(mozilla::WritingMode aWritingMode,
1092                                       const nsSize& aContainerSize) const {
1093     return mozilla::LogicalRect(aWritingMode, GetRect(), aContainerSize);
1094   }
GetLogicalPosition(mozilla::WritingMode aWritingMode,const nsSize & aContainerSize)1095   mozilla::LogicalPoint GetLogicalPosition(mozilla::WritingMode aWritingMode,
1096                                            const nsSize& aContainerSize) const {
1097     return GetLogicalRect(aWritingMode, aContainerSize).Origin(aWritingMode);
1098   }
GetLogicalSize(mozilla::WritingMode aWritingMode)1099   mozilla::LogicalSize GetLogicalSize(mozilla::WritingMode aWritingMode) const {
1100     return mozilla::LogicalSize(aWritingMode, GetSize());
1101   }
IStart(const nsSize & aContainerSize)1102   nscoord IStart(const nsSize& aContainerSize) const {
1103     return IStart(GetWritingMode(), aContainerSize);
1104   }
IStart(mozilla::WritingMode aWritingMode,const nsSize & aContainerSize)1105   nscoord IStart(mozilla::WritingMode aWritingMode,
1106                  const nsSize& aContainerSize) const {
1107     return GetLogicalPosition(aWritingMode, aContainerSize).I(aWritingMode);
1108   }
BStart(const nsSize & aContainerSize)1109   nscoord BStart(const nsSize& aContainerSize) const {
1110     return BStart(GetWritingMode(), aContainerSize);
1111   }
BStart(mozilla::WritingMode aWritingMode,const nsSize & aContainerSize)1112   nscoord BStart(mozilla::WritingMode aWritingMode,
1113                  const nsSize& aContainerSize) const {
1114     return GetLogicalPosition(aWritingMode, aContainerSize).B(aWritingMode);
1115   }
ISize()1116   nscoord ISize() const { return ISize(GetWritingMode()); }
ISize(mozilla::WritingMode aWritingMode)1117   nscoord ISize(mozilla::WritingMode aWritingMode) const {
1118     return GetLogicalSize(aWritingMode).ISize(aWritingMode);
1119   }
BSize()1120   nscoord BSize() const { return BSize(GetWritingMode()); }
BSize(mozilla::WritingMode aWritingMode)1121   nscoord BSize(mozilla::WritingMode aWritingMode) const {
1122     return GetLogicalSize(aWritingMode).BSize(aWritingMode);
1123   }
ContentSize()1124   mozilla::LogicalSize ContentSize() const {
1125     return ContentSize(GetWritingMode());
1126   }
ContentSize(mozilla::WritingMode aWritingMode)1127   mozilla::LogicalSize ContentSize(mozilla::WritingMode aWritingMode) const {
1128     mozilla::WritingMode wm = GetWritingMode();
1129     const auto bp = GetLogicalUsedBorderAndPadding(wm)
1130                         .ApplySkipSides(GetLogicalSkipSides())
1131                         .ConvertTo(aWritingMode, wm);
1132     const auto size = GetLogicalSize(aWritingMode);
1133     return mozilla::LogicalSize(
1134         aWritingMode,
1135         std::max(0, size.ISize(aWritingMode) - bp.IStartEnd(aWritingMode)),
1136         std::max(0, size.BSize(aWritingMode) - bp.BStartEnd(aWritingMode)));
1137   }
1138 
1139   /**
1140    * When we change the size of the frame's border-box rect, we may need to
1141    * reset the overflow rect if it was previously stored as deltas.
1142    * (If it is currently a "large" overflow and could be re-packed as deltas,
1143    * we don't bother as the cost of the allocation has already been paid.)
1144    * @param aRebuildDisplayItems If true, then adds this frame to the
1145    * list of modified frames for display list building if the rect has changed.
1146    * Only pass false if you're sure that the relevant display items will be
1147    * rebuilt already (possibly by an ancestor being in the modified list), or if
1148    * this is a temporary change.
1149    */
1150   void SetRect(const nsRect& aRect, bool aRebuildDisplayItems = true) {
1151     if (aRect == mRect) {
1152       return;
1153     }
1154     if (mOverflow.mType != OverflowStorageType::Large &&
1155         mOverflow.mType != OverflowStorageType::None) {
1156       mozilla::OverflowAreas overflow = GetOverflowAreas();
1157       mRect = aRect;
1158       SetOverflowAreas(overflow);
1159     } else {
1160       mRect = aRect;
1161     }
1162     if (aRebuildDisplayItems) {
1163       MarkNeedsDisplayItemRebuild();
1164     }
1165   }
1166   /**
1167    * Set this frame's rect from a logical rect in its own writing direction
1168    */
SetRect(const mozilla::LogicalRect & aRect,const nsSize & aContainerSize)1169   void SetRect(const mozilla::LogicalRect& aRect,
1170                const nsSize& aContainerSize) {
1171     SetRect(GetWritingMode(), aRect, aContainerSize);
1172   }
1173   /**
1174    * Set this frame's rect from a logical rect in a different writing direction
1175    * (GetPhysicalRect will assert if the writing mode doesn't match)
1176    */
SetRect(mozilla::WritingMode aWritingMode,const mozilla::LogicalRect & aRect,const nsSize & aContainerSize)1177   void SetRect(mozilla::WritingMode aWritingMode,
1178                const mozilla::LogicalRect& aRect,
1179                const nsSize& aContainerSize) {
1180     SetRect(aRect.GetPhysicalRect(aWritingMode, aContainerSize));
1181   }
1182 
1183   /**
1184    * Set this frame's size from a logical size in its own writing direction.
1185    * This leaves the frame's logical position unchanged, which means its
1186    * physical position may change (for right-to-left modes).
1187    */
SetSize(const mozilla::LogicalSize & aSize)1188   void SetSize(const mozilla::LogicalSize& aSize) {
1189     SetSize(GetWritingMode(), aSize);
1190   }
1191   /*
1192    * Set this frame's size from a logical size in a different writing direction.
1193    * This leaves the frame's logical position in the given mode unchanged,
1194    * which means its physical position may change (for right-to-left modes).
1195    */
SetSize(mozilla::WritingMode aWritingMode,const mozilla::LogicalSize & aSize)1196   void SetSize(mozilla::WritingMode aWritingMode,
1197                const mozilla::LogicalSize& aSize) {
1198     if (aWritingMode.IsPhysicalRTL()) {
1199       nscoord oldWidth = mRect.Width();
1200       SetSize(aSize.GetPhysicalSize(aWritingMode));
1201       mRect.x -= mRect.Width() - oldWidth;
1202     } else {
1203       SetSize(aSize.GetPhysicalSize(aWritingMode));
1204     }
1205   }
1206 
1207   /**
1208    * Set this frame's physical size. This leaves the frame's physical position
1209    * (topLeft) unchanged.
1210    * @param aRebuildDisplayItems If true, then adds this frame to the
1211    * list of modified frames for display list building if the size has changed.
1212    * Only pass false if you're sure that the relevant display items will be
1213    * rebuilt already (possibly by an ancestor being in the modified list), or if
1214    * this is a temporary change.
1215    */
1216   void SetSize(const nsSize& aSize, bool aRebuildDisplayItems = true) {
1217     SetRect(nsRect(mRect.TopLeft(), aSize), aRebuildDisplayItems);
1218   }
1219 
SetPosition(const nsPoint & aPt)1220   void SetPosition(const nsPoint& aPt) {
1221     if (mRect.TopLeft() == aPt) {
1222       return;
1223     }
1224     mRect.MoveTo(aPt);
1225     MarkNeedsDisplayItemRebuild();
1226   }
SetPosition(mozilla::WritingMode aWritingMode,const mozilla::LogicalPoint & aPt,const nsSize & aContainerSize)1227   void SetPosition(mozilla::WritingMode aWritingMode,
1228                    const mozilla::LogicalPoint& aPt,
1229                    const nsSize& aContainerSize) {
1230     // We subtract mRect.Size() from the container size to account for
1231     // the fact that logical origins in RTL coordinate systems are at
1232     // the top right of the frame instead of the top left.
1233     SetPosition(
1234         aPt.GetPhysicalPoint(aWritingMode, aContainerSize - mRect.Size()));
1235   }
1236 
1237   /**
1238    * Move the frame, accounting for relative positioning. Use this when
1239    * adjusting the frame's position by a known amount, to properly update its
1240    * saved normal position (see GetNormalPosition below).
1241    *
1242    * This must be used only when moving a frame *after*
1243    * ReflowInput::ApplyRelativePositioning is called.  When moving
1244    * a frame during the reflow process prior to calling
1245    * ReflowInput::ApplyRelativePositioning, the position should
1246    * simply be adjusted directly (e.g., using SetPosition()).
1247    */
1248   void MovePositionBy(const nsPoint& aTranslation);
1249 
1250   /**
1251    * As above, using a logical-point delta in a given writing mode.
1252    */
MovePositionBy(mozilla::WritingMode aWritingMode,const mozilla::LogicalPoint & aTranslation)1253   void MovePositionBy(mozilla::WritingMode aWritingMode,
1254                       const mozilla::LogicalPoint& aTranslation) {
1255     // The LogicalPoint represents a vector rather than a point within a
1256     // rectangular coordinate space, so we use a null containerSize when
1257     // converting logical to physical.
1258     const nsSize nullContainerSize;
1259     MovePositionBy(
1260         aTranslation.GetPhysicalPoint(aWritingMode, nullContainerSize));
1261   }
1262 
1263   /**
1264    * Return frame's rect without relative positioning
1265    */
1266   nsRect GetNormalRect() const;
1267 
1268   /**
1269    * Returns frame's rect as required by the GetBoundingClientRect() DOM API.
1270    */
1271   nsRect GetBoundingClientRect();
1272 
1273   /**
1274    * Return frame's position without relative positioning.
1275    * If aHasProperty is provided, returns whether the normal position
1276    * was stored in a frame property.
1277    */
1278   inline nsPoint GetNormalPosition(bool* aHasProperty = nullptr) const;
1279   inline mozilla::LogicalPoint GetLogicalNormalPosition(
1280       mozilla::WritingMode aWritingMode, const nsSize& aContainerSize) const;
1281 
GetPositionOfChildIgnoringScrolling(const nsIFrame * aChild)1282   virtual nsPoint GetPositionOfChildIgnoringScrolling(const nsIFrame* aChild) {
1283     return aChild->GetPosition();
1284   }
1285 
1286   nsPoint GetPositionIgnoringScrolling() const;
1287 
1288 #define NS_DECLARE_FRAME_PROPERTY_WITH_DTOR(prop, type, dtor)              \
1289   static const mozilla::FramePropertyDescriptor<type>* prop() {            \
1290     /* Use of constexpr caused startup crashes with MSVC2015u1 PGO. */     \
1291     static const auto descriptor =                                         \
1292         mozilla::FramePropertyDescriptor<type>::NewWithDestructor<dtor>(); \
1293     return &descriptor;                                                    \
1294   }
1295 
1296 // Don't use this unless you really know what you're doing!
1297 #define NS_DECLARE_FRAME_PROPERTY_WITH_FRAME_IN_DTOR(prop, type, dtor) \
1298   static const mozilla::FramePropertyDescriptor<type>* prop() {        \
1299     /* Use of constexpr caused startup crashes with MSVC2015u1 PGO. */ \
1300     static const auto descriptor = mozilla::FramePropertyDescriptor<   \
1301         type>::NewWithDestructorWithFrame<dtor>();                     \
1302     return &descriptor;                                                \
1303   }
1304 
1305 #define NS_DECLARE_FRAME_PROPERTY_WITHOUT_DTOR(prop, type)              \
1306   static const mozilla::FramePropertyDescriptor<type>* prop() {         \
1307     /* Use of constexpr caused startup crashes with MSVC2015u1 PGO. */  \
1308     static const auto descriptor =                                      \
1309         mozilla::FramePropertyDescriptor<type>::NewWithoutDestructor(); \
1310     return &descriptor;                                                 \
1311   }
1312 
1313 #define NS_DECLARE_FRAME_PROPERTY_DELETABLE(prop, type) \
1314   NS_DECLARE_FRAME_PROPERTY_WITH_DTOR(prop, type, DeleteValue)
1315 
1316 #define NS_DECLARE_FRAME_PROPERTY_RELEASABLE(prop, type) \
1317   NS_DECLARE_FRAME_PROPERTY_WITH_DTOR(prop, type, ReleaseValue)
1318 
1319 #define NS_DECLARE_FRAME_PROPERTY_WITH_DTOR_NEVER_CALLED(prop, type) \
1320   static void AssertOnDestroyingProperty##prop(type*) {              \
1321     MOZ_ASSERT_UNREACHABLE(                                          \
1322         "Frame property " #prop                                      \
1323         " should never be destroyed by the FrameProperties class");  \
1324   }                                                                  \
1325   NS_DECLARE_FRAME_PROPERTY_WITH_DTOR(prop, type,                    \
1326                                       AssertOnDestroyingProperty##prop)
1327 
1328 #define NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(prop, type) \
1329   NS_DECLARE_FRAME_PROPERTY_WITHOUT_DTOR(prop, mozilla::SmallValueHolder<type>)
1330 
NS_DECLARE_FRAME_PROPERTY_WITHOUT_DTOR(IBSplitSibling,nsContainerFrame)1331   NS_DECLARE_FRAME_PROPERTY_WITHOUT_DTOR(IBSplitSibling, nsContainerFrame)
1332   NS_DECLARE_FRAME_PROPERTY_WITHOUT_DTOR(IBSplitPrevSibling, nsContainerFrame)
1333 
1334   NS_DECLARE_FRAME_PROPERTY_DELETABLE(NormalPositionProperty, nsPoint)
1335   NS_DECLARE_FRAME_PROPERTY_DELETABLE(ComputedOffsetProperty, nsMargin)
1336 
1337   NS_DECLARE_FRAME_PROPERTY_DELETABLE(OutlineInnerRectProperty, nsRect)
1338   NS_DECLARE_FRAME_PROPERTY_DELETABLE(PreEffectsBBoxProperty, nsRect)
1339   NS_DECLARE_FRAME_PROPERTY_DELETABLE(PreTransformOverflowAreasProperty,
1340                                       mozilla::OverflowAreas)
1341 
1342   NS_DECLARE_FRAME_PROPERTY_DELETABLE(CachedBorderImageDataProperty,
1343                                       CachedBorderImageData)
1344 
1345   NS_DECLARE_FRAME_PROPERTY_DELETABLE(OverflowAreasProperty,
1346                                       mozilla::OverflowAreas)
1347 
1348   // The initial overflow area passed to FinishAndStoreOverflow. This is only
1349   // set on frames that Preserve3D() or HasPerspective() or IsTransformed(), and
1350   // when at least one of the overflow areas differs from the frame bound rect.
1351   NS_DECLARE_FRAME_PROPERTY_DELETABLE(InitialOverflowProperty,
1352                                       mozilla::OverflowAreas)
1353 
1354 #ifdef DEBUG
1355   // InitialOverflowPropertyDebug is added to the frame to indicate that either
1356   // the InitialOverflowProperty has been stored or the InitialOverflowProperty
1357   // has been suppressed due to being set to the default value (frame bounds)
1358   NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(DebugInitialOverflowPropertyApplied,
1359                                         bool)
1360 #endif
1361 
1362   NS_DECLARE_FRAME_PROPERTY_DELETABLE(UsedMarginProperty, nsMargin)
1363   NS_DECLARE_FRAME_PROPERTY_DELETABLE(UsedPaddingProperty, nsMargin)
1364   NS_DECLARE_FRAME_PROPERTY_DELETABLE(UsedBorderProperty, nsMargin)
1365 
1366   NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(LineBaselineOffset, nscoord)
1367 
1368   NS_DECLARE_FRAME_PROPERTY_DELETABLE(InvalidationRect, nsRect)
1369 
1370   NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(RefusedAsyncAnimationProperty, bool)
1371 
1372   NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(FragStretchBSizeProperty, nscoord)
1373 
1374   // The block-axis margin-box size associated with eBClampMarginBoxMinSize.
1375   NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(BClampMarginBoxMinSizeProperty, nscoord)
1376 
1377   NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(IBaselinePadProperty, nscoord)
1378   NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(BBaselinePadProperty, nscoord)
1379 
1380   NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(BidiDataProperty,
1381                                         mozilla::FrameBidiData)
1382 
1383   NS_DECLARE_FRAME_PROPERTY_WITHOUT_DTOR(PlaceholderFrameProperty,
1384                                          nsPlaceholderFrame)
1385 
1386   NS_DECLARE_FRAME_PROPERTY_RELEASABLE(OffsetPathCache, mozilla::gfx::Path)
1387 
1388   NS_DECLARE_FRAME_PROPERTY_DELETABLE(DisplayItemDataProperty,
1389                                       DisplayItemDataArray)
1390 
1391   mozilla::FrameBidiData GetBidiData() const {
1392     bool exists;
1393     mozilla::FrameBidiData bidiData = GetProperty(BidiDataProperty(), &exists);
1394     if (!exists) {
1395       bidiData.precedingControl = mozilla::kBidiLevelNone;
1396     }
1397     return bidiData;
1398   }
1399 
GetBaseLevel()1400   nsBidiLevel GetBaseLevel() const { return GetBidiData().baseLevel; }
1401 
GetEmbeddingLevel()1402   nsBidiLevel GetEmbeddingLevel() const { return GetBidiData().embeddingLevel; }
1403 
1404   /**
1405    * Return the distance between the border edge of the frame and the
1406    * margin edge of the frame.  Like GetRect(), returns the dimensions
1407    * as of the most recent reflow.
1408    *
1409    * This doesn't include any margin collapsing that may have occurred.
1410    * It also doesn't consider GetSkipSides()/GetLogicalSkipSides(), so
1411    * may report nonzero values on sides that are actually skipped for
1412    * this fragment.
1413    *
1414    * It also treats 'auto' margins as zero, and treats any margins that
1415    * should have been turned into 'auto' because of overconstraint as
1416    * having their original values.
1417    */
1418   virtual nsMargin GetUsedMargin() const;
GetLogicalUsedMargin(mozilla::WritingMode aWritingMode)1419   virtual mozilla::LogicalMargin GetLogicalUsedMargin(
1420       mozilla::WritingMode aWritingMode) const {
1421     return mozilla::LogicalMargin(aWritingMode, GetUsedMargin());
1422   }
1423 
1424   /**
1425    * Return the distance between the border edge of the frame (which is
1426    * its rect) and the padding edge of the frame. Like GetRect(), returns
1427    * the dimensions as of the most recent reflow.
1428    *
1429    * This doesn't consider GetSkipSides()/GetLogicalSkipSides(), so
1430    * may report nonzero values on sides that are actually skipped for
1431    * this fragment.
1432    *
1433    * Note that this differs from StyleBorder()->GetComputedBorder() in
1434    * that this describes a region of the frame's box, and
1435    * StyleBorder()->GetComputedBorder() describes a border.  They differ
1436    * for tables (particularly border-collapse tables) and themed
1437    * elements.
1438    */
1439   virtual nsMargin GetUsedBorder() const;
GetLogicalUsedBorder(mozilla::WritingMode aWritingMode)1440   virtual mozilla::LogicalMargin GetLogicalUsedBorder(
1441       mozilla::WritingMode aWritingMode) const {
1442     return mozilla::LogicalMargin(aWritingMode, GetUsedBorder());
1443   }
1444 
1445   /**
1446    * Return the distance between the padding edge of the frame and the
1447    * content edge of the frame.  Like GetRect(), returns the dimensions
1448    * as of the most recent reflow.
1449    *
1450    * This doesn't consider GetSkipSides()/GetLogicalSkipSides(), so
1451    * may report nonzero values on sides that are actually skipped for
1452    * this fragment.
1453    */
1454   virtual nsMargin GetUsedPadding() const;
GetLogicalUsedPadding(mozilla::WritingMode aWritingMode)1455   virtual mozilla::LogicalMargin GetLogicalUsedPadding(
1456       mozilla::WritingMode aWritingMode) const {
1457     return mozilla::LogicalMargin(aWritingMode, GetUsedPadding());
1458   }
1459 
GetUsedBorderAndPadding()1460   nsMargin GetUsedBorderAndPadding() const {
1461     return GetUsedBorder() + GetUsedPadding();
1462   }
GetLogicalUsedBorderAndPadding(mozilla::WritingMode aWritingMode)1463   mozilla::LogicalMargin GetLogicalUsedBorderAndPadding(
1464       mozilla::WritingMode aWritingMode) const {
1465     return mozilla::LogicalMargin(aWritingMode, GetUsedBorderAndPadding());
1466   }
1467 
1468   /**
1469    * The area to paint box-shadows around.  The default is the border rect.
1470    * (nsFieldSetFrame overrides this).
1471    */
VisualBorderRectRelativeToSelf()1472   virtual nsRect VisualBorderRectRelativeToSelf() const {
1473     return nsRect(0, 0, mRect.Width(), mRect.Height());
1474   }
1475 
1476   /**
1477    * Get the size, in app units, of the border radii. It returns FALSE iff all
1478    * returned radii == 0 (so no border radii), TRUE otherwise.
1479    * For the aRadii indexes, use the enum HalfCorner constants in gfx/2d/Types.h
1480    * If a side is skipped via aSkipSides, its corners are forced to 0.
1481    *
1482    * All corner radii are then adjusted so they do not require more
1483    * space than aBorderArea, according to the algorithm in css3-background.
1484    *
1485    * aFrameSize is used as the basis for percentage widths and heights.
1486    * aBorderArea is used for the adjustment of radii that might be too
1487    * large.
1488    *
1489    * Return whether any radii are nonzero.
1490    */
1491   static bool ComputeBorderRadii(const mozilla::BorderRadius&,
1492                                  const nsSize& aFrameSize,
1493                                  const nsSize& aBorderArea, Sides aSkipSides,
1494                                  nscoord aRadii[8]);
1495 
1496   /*
1497    * Given a set of border radii for one box (e.g., border box), convert
1498    * it to the equivalent set of radii for another box (e.g., in to
1499    * padding box, out to outline box) by reducing radii or increasing
1500    * nonzero radii as appropriate.
1501    *
1502    * Indices into aRadii are the enum HalfCorner constants in gfx/2d/Types.h
1503    *
1504    * Note that InsetBorderRadii is lossy, since it can turn nonzero
1505    * radii into zero, and OutsetBorderRadii does not inflate zero radii.
1506    * Therefore, callers should always inset or outset directly from the
1507    * original value coming from style.
1508    */
1509   static void InsetBorderRadii(nscoord aRadii[8], const nsMargin& aOffsets);
1510   static void OutsetBorderRadii(nscoord aRadii[8], const nsMargin& aOffsets);
1511 
1512   /**
1513    * Fill in border radii for this frame.  Return whether any are nonzero.
1514    * Indices into aRadii are the enum HalfCorner constants in gfx/2d/Types.h
1515    * aSkipSides is a union of SideBits::eLeft/Right/Top/Bottom bits that says
1516    * which side(s) to skip.
1517    *
1518    * Note: GetMarginBoxBorderRadii() and GetShapeBoxBorderRadii() work only
1519    * on frames that establish block formatting contexts since they don't
1520    * participate in margin-collapsing.
1521    */
1522   virtual bool GetBorderRadii(const nsSize& aFrameSize,
1523                               const nsSize& aBorderArea, Sides aSkipSides,
1524                               nscoord aRadii[8]) const;
1525   bool GetBorderRadii(nscoord aRadii[8]) const;
1526   bool GetMarginBoxBorderRadii(nscoord aRadii[8]) const;
1527   bool GetPaddingBoxBorderRadii(nscoord aRadii[8]) const;
1528   bool GetContentBoxBorderRadii(nscoord aRadii[8]) const;
1529   bool GetBoxBorderRadii(nscoord aRadii[8], nsMargin aOffset,
1530                          bool aIsOutset) const;
1531   bool GetShapeBoxBorderRadii(nscoord aRadii[8]) const;
1532 
1533   /**
1534    * XXX: this method will likely be replaced by GetVerticalAlignBaseline
1535    * Get the position of the frame's baseline, relative to the top of
1536    * the frame (its top border edge).  Only valid when Reflow is not
1537    * needed.
1538    * @note You should only call this on frames with a WM that's parallel to
1539    * aWritingMode.
1540    * @param aWritingMode the writing-mode of the alignment context, with the
1541    * ltr/rtl direction tweak done by nsIFrame::GetWritingMode(nsIFrame*) in
1542    * inline contexts (see that method).
1543    */
1544   virtual nscoord GetLogicalBaseline(mozilla::WritingMode aWritingMode) const;
1545 
1546   /**
1547    * Synthesize a first(last) inline-axis baseline based on our margin-box.
1548    * An alphabetical baseline is at the start(end) edge and a central baseline
1549    * is at the center of our block-axis margin-box (aWM tells which to use).
1550    * https://drafts.csswg.org/css-align-3/#synthesize-baselines
1551    * @note You should only call this on frames with a WM that's parallel to aWM.
1552    * @param aWM the writing-mode of the alignment context
1553    * @return an offset from our border-box block-axis start(end) edge for
1554    * a first(last) baseline respectively
1555    * (implemented in nsIFrameInlines.h)
1556    */
1557   inline nscoord SynthesizeBaselineBOffsetFromMarginBox(
1558       mozilla::WritingMode aWM, BaselineSharingGroup aGroup) const;
1559 
1560   /**
1561    * Synthesize a first(last) inline-axis baseline based on our border-box.
1562    * An alphabetical baseline is at the start(end) edge and a central baseline
1563    * is at the center of our block-axis border-box (aWM tells which to use).
1564    * https://drafts.csswg.org/css-align-3/#synthesize-baselines
1565    * @note The returned value is only valid when reflow is not needed.
1566    * @note You should only call this on frames with a WM that's parallel to aWM.
1567    * @param aWM the writing-mode of the alignment context
1568    * @return an offset from our border-box block-axis start(end) edge for
1569    * a first(last) baseline respectively
1570    * (implemented in nsIFrameInlines.h)
1571    */
1572   inline nscoord SynthesizeBaselineBOffsetFromBorderBox(
1573       mozilla::WritingMode aWM, BaselineSharingGroup aGroup) const;
1574 
1575   /**
1576    * Synthesize a first(last) inline-axis baseline based on our content-box.
1577    * An alphabetical baseline is at the start(end) edge and a central baseline
1578    * is at the center of our block-axis content-box (aWM tells which to use).
1579    * https://drafts.csswg.org/css-align-3/#synthesize-baselines
1580    * @note The returned value is only valid when reflow is not needed.
1581    * @note You should only call this on frames with a WM that's parallel to aWM.
1582    * @param aWM the writing-mode of the alignment context
1583    * @return an offset from our border-box block-axis start(end) edge for
1584    * a first(last) baseline respectively
1585    * (implemented in nsIFrameInlines.h)
1586    */
1587   inline nscoord SynthesizeBaselineBOffsetFromContentBox(
1588       mozilla::WritingMode aWM, BaselineSharingGroup aGroup) const;
1589 
1590   /**
1591    * Return the position of the frame's inline-axis baseline, or synthesize one
1592    * for the given alignment context. The returned baseline is the distance from
1593    * the block-axis border-box start(end) edge for aBaselineGroup ::First(Last).
1594    * @note The returned value is only valid when reflow is not needed.
1595    * @note You should only call this on frames with a WM that's parallel to aWM.
1596    * @param aWM the writing-mode of the alignment context
1597    * @param aBaselineOffset out-param, only valid if the method returns true
1598    * (implemented in nsIFrameInlines.h)
1599    */
1600   inline nscoord BaselineBOffset(mozilla::WritingMode aWM,
1601                                  BaselineSharingGroup aBaselineGroup,
1602                                  AlignmentContext aAlignmentContext) const;
1603 
1604   /**
1605    * XXX: this method is taking over the role that GetLogicalBaseline has.
1606    * Return true if the frame has a CSS2 'vertical-align' baseline.
1607    * If it has, then the returned baseline is the distance from the block-
1608    * axis border-box start edge.
1609    * @note This method should only be used in AlignmentContext::Inline
1610    * contexts.
1611    * @note The returned value is only valid when reflow is not needed.
1612    * @note You should only call this on frames with a WM that's parallel to aWM.
1613    * @param aWM the writing-mode of the alignment context
1614    * @param aBaseline the baseline offset, only valid if the method returns true
1615    */
GetVerticalAlignBaseline(mozilla::WritingMode aWM,nscoord * aBaseline)1616   virtual bool GetVerticalAlignBaseline(mozilla::WritingMode aWM,
1617                                         nscoord* aBaseline) const {
1618     return false;
1619   }
1620 
1621   /**
1622    * Return true if the frame has a first(last) inline-axis natural baseline per
1623    * CSS Box Alignment.  If so, then the returned baseline is the distance from
1624    * the block-axis border-box start(end) edge for aBaselineGroup ::First(Last).
1625    * https://drafts.csswg.org/css-align-3/#natural-baseline
1626    * @note The returned value is only valid when reflow is not needed.
1627    * @note You should only call this on frames with a WM that's parallel to aWM.
1628    * @param aWM the writing-mode of the alignment context
1629    * @param aBaseline the baseline offset, only valid if the method returns true
1630    */
GetNaturalBaselineBOffset(mozilla::WritingMode aWM,BaselineSharingGroup aBaselineGroup,nscoord * aBaseline)1631   virtual bool GetNaturalBaselineBOffset(mozilla::WritingMode aWM,
1632                                          BaselineSharingGroup aBaselineGroup,
1633                                          nscoord* aBaseline) const {
1634     return false;
1635   }
1636 
1637   /**
1638    * Get the position of the baseline on which the caret needs to be placed,
1639    * relative to the top of the frame.  This is mostly needed for frames
1640    * which return a baseline from GetBaseline which is not useful for
1641    * caret positioning.
1642    */
GetCaretBaseline()1643   virtual nscoord GetCaretBaseline() const {
1644     return GetLogicalBaseline(GetWritingMode());
1645   }
1646 
1647   ///////////////////////////////////////////////////////////////////////////////
1648   // The public visibility API.
1649   ///////////////////////////////////////////////////////////////////////////////
1650 
1651   /// @return true if we're tracking visibility for this frame.
TrackingVisibility()1652   bool TrackingVisibility() const {
1653     return HasAnyStateBits(NS_FRAME_VISIBILITY_IS_TRACKED);
1654   }
1655 
1656   /// @return the visibility state of this frame. See the Visibility enum
1657   /// for the possible return values and their meanings.
1658   Visibility GetVisibility() const;
1659 
1660   /// Update the visibility state of this frame synchronously.
1661   /// XXX(seth): Avoid using this method; we should be relying on the refresh
1662   /// driver for visibility updates. This method, which replaces
1663   /// nsLayoutUtils::UpdateApproximateFrameVisibility(), exists purely as a
1664   /// temporary measure to avoid changing behavior during the transition from
1665   /// the old image visibility code.
1666   void UpdateVisibilitySynchronously();
1667 
1668   // A frame property which stores the visibility state of this frame. Right
1669   // now that consists of an approximate visibility counter represented as a
1670   // uint32_t. When the visibility of this frame is not being tracked, this
1671   // property is absent.
1672   NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(VisibilityStateProperty, uint32_t);
1673 
1674  protected:
1675   /**
1676    * Subclasses can call this method to enable visibility tracking for this
1677    * frame.
1678    *
1679    * If visibility tracking was previously disabled, this will schedule an
1680    * update an asynchronous update of visibility.
1681    */
1682   void EnableVisibilityTracking();
1683 
1684   /**
1685    * Subclasses can call this method to disable visibility tracking for this
1686    * frame.
1687    *
1688    * Note that if visibility tracking was previously enabled, disabling
1689    * visibility tracking will cause a synchronous call to OnVisibilityChange().
1690    */
1691   void DisableVisibilityTracking();
1692 
1693   /**
1694    * Called when a frame transitions between visibility states (for example,
1695    * from nonvisible to visible, or from visible to nonvisible).
1696    *
1697    * @param aNewVisibility    The new visibility state.
1698    * @param aNonvisibleAction A requested action if the frame has become
1699    *                          nonvisible. If Nothing(), no action is
1700    *                          requested. If DISCARD_IMAGES is specified, the
1701    *                          frame is requested to ask any images it's
1702    *                          associated with to discard their surfaces if
1703    *                          possible.
1704    *
1705    * Subclasses which override this method should call their parent class's
1706    * implementation.
1707    */
1708   virtual void OnVisibilityChange(
1709       Visibility aNewVisibility,
1710       const Maybe<OnNonvisible>& aNonvisibleAction = Nothing());
1711 
1712  public:
1713   ///////////////////////////////////////////////////////////////////////////////
1714   // Internal implementation for the approximate frame visibility API.
1715   ///////////////////////////////////////////////////////////////////////////////
1716 
1717   /**
1718    * We track the approximate visibility of frames using a counter; if it's
1719    * non-zero, then the frame is considered visible. Using a counter allows us
1720    * to account for situations where the frame may be visible in more than one
1721    * place (for example, via -moz-element), and it simplifies the
1722    * implementation of our approximate visibility tracking algorithms.
1723    *
1724    * @param aNonvisibleAction A requested action if the frame has become
1725    *                          nonvisible. If Nothing(), no action is
1726    *                          requested. If DISCARD_IMAGES is specified, the
1727    *                          frame is requested to ask any images it's
1728    *                          associated with to discard their surfaces if
1729    *                          possible.
1730    */
1731   void DecApproximateVisibleCount(
1732       const Maybe<OnNonvisible>& aNonvisibleAction = Nothing());
1733   void IncApproximateVisibleCount();
1734 
1735   /**
1736    * Get the specified child list.
1737    *
1738    * @param   aListID identifies the requested child list.
1739    * @return  the child list.  If the requested list is unsupported by this
1740    *          frame type, an empty list will be returned.
1741    */
1742   virtual const nsFrameList& GetChildList(ChildListID aListID) const;
PrincipalChildList()1743   const nsFrameList& PrincipalChildList() const {
1744     return GetChildList(kPrincipalList);
1745   }
1746 
1747   /**
1748    * Sub-classes should override this methods if they want to append their own
1749    * child lists into aLists.
1750    */
1751   virtual void GetChildLists(nsTArray<ChildList>* aLists) const;
1752 
1753   /**
1754    * Returns the child lists for this frame.
1755    */
ChildLists()1756   AutoTArray<ChildList, 4> ChildLists() const {
1757     AutoTArray<ChildList, 4> childLists;
1758     GetChildLists(&childLists);
1759     return childLists;
1760   }
1761 
1762   /**
1763    * Returns the child lists for this frame, including ones belong to a child
1764    * document.
1765    */
1766   AutoTArray<ChildList, 4> CrossDocChildLists();
1767 
1768   // The individual concrete child lists.
1769   static const ChildListID kPrincipalList = mozilla::layout::kPrincipalList;
1770   static const ChildListID kAbsoluteList = mozilla::layout::kAbsoluteList;
1771   static const ChildListID kBulletList = mozilla::layout::kBulletList;
1772   static const ChildListID kCaptionList = mozilla::layout::kCaptionList;
1773   static const ChildListID kColGroupList = mozilla::layout::kColGroupList;
1774   static const ChildListID kExcessOverflowContainersList =
1775       mozilla::layout::kExcessOverflowContainersList;
1776   static const ChildListID kFixedList = mozilla::layout::kFixedList;
1777   static const ChildListID kFloatList = mozilla::layout::kFloatList;
1778   static const ChildListID kOverflowContainersList =
1779       mozilla::layout::kOverflowContainersList;
1780   static const ChildListID kOverflowList = mozilla::layout::kOverflowList;
1781   static const ChildListID kOverflowOutOfFlowList =
1782       mozilla::layout::kOverflowOutOfFlowList;
1783   static const ChildListID kPopupList = mozilla::layout::kPopupList;
1784   static const ChildListID kPushedFloatsList =
1785       mozilla::layout::kPushedFloatsList;
1786   static const ChildListID kSelectPopupList = mozilla::layout::kSelectPopupList;
1787   static const ChildListID kBackdropList = mozilla::layout::kBackdropList;
1788   // A special alias for kPrincipalList that do not request reflow.
1789   static const ChildListID kNoReflowPrincipalList =
1790       mozilla::layout::kNoReflowPrincipalList;
1791 
1792   /**
1793    * Child frames are linked together in a doubly-linked list
1794    */
GetNextSibling()1795   nsIFrame* GetNextSibling() const { return mNextSibling; }
SetNextSibling(nsIFrame * aNextSibling)1796   void SetNextSibling(nsIFrame* aNextSibling) {
1797     NS_ASSERTION(this != aNextSibling,
1798                  "Creating a circular frame list, this is very bad.");
1799     if (mNextSibling && mNextSibling->GetPrevSibling() == this) {
1800       mNextSibling->mPrevSibling = nullptr;
1801     }
1802     mNextSibling = aNextSibling;
1803     if (mNextSibling) {
1804       mNextSibling->mPrevSibling = this;
1805     }
1806   }
1807 
GetPrevSibling()1808   nsIFrame* GetPrevSibling() const { return mPrevSibling; }
1809 
1810   /**
1811    * Builds the display lists for the content represented by this frame
1812    * and its descendants. The background+borders of this element must
1813    * be added first, before any other content.
1814    *
1815    * This should only be called by methods in nsFrame. Instead of calling this
1816    * directly, call either BuildDisplayListForStackingContext or
1817    * BuildDisplayListForChild.
1818    *
1819    * See nsDisplayList.h for more information about display lists.
1820    */
BuildDisplayList(nsDisplayListBuilder * aBuilder,const nsDisplayListSet & aLists)1821   virtual void BuildDisplayList(nsDisplayListBuilder* aBuilder,
1822                                 const nsDisplayListSet& aLists) {}
1823   /**
1824    * Displays the caret onto the given display list builder. The caret is
1825    * painted on top of the rest of the display list items.
1826    */
1827   void DisplayCaret(nsDisplayListBuilder* aBuilder, nsDisplayList* aList);
1828 
1829   /**
1830    * Get the preferred caret color at the offset.
1831    *
1832    * @param aOffset is offset of the content.
1833    */
1834   virtual nscolor GetCaretColorAt(int32_t aOffset);
1835 
1836   bool IsThemed(nsITheme::Transparency* aTransparencyState = nullptr) const {
1837     return IsThemed(StyleDisplay(), aTransparencyState);
1838   }
1839   bool IsThemed(const nsStyleDisplay* aDisp,
1840                 nsITheme::Transparency* aTransparencyState = nullptr) const {
1841     if (!aDisp->HasAppearance()) {
1842       return false;
1843     }
1844     nsIFrame* mutable_this = const_cast<nsIFrame*>(this);
1845     nsPresContext* pc = PresContext();
1846     nsITheme* theme = pc->Theme();
1847     if (!theme->ThemeSupportsWidget(pc, mutable_this,
1848                                     aDisp->EffectiveAppearance())) {
1849       return false;
1850     }
1851     if (aTransparencyState) {
1852       *aTransparencyState = theme->GetWidgetTransparency(
1853           mutable_this, aDisp->EffectiveAppearance());
1854     }
1855     return true;
1856   }
1857 
1858   /**
1859    * Builds a display list for the content represented by this frame,
1860    * treating this frame as the root of a stacking context.
1861    * Optionally sets aCreatedContainerItem to true if we created a
1862    * single container display item for the stacking context, and no
1863    * other wrapping items are needed.
1864    */
1865   void BuildDisplayListForStackingContext(
1866       nsDisplayListBuilder* aBuilder, nsDisplayList* aList,
1867       bool* aCreatedContainerItem = nullptr);
1868 
1869   enum class DisplayChildFlag {
1870     ForcePseudoStackingContext,
1871     ForceStackingContext,
1872     Inline,
1873   };
1874   using DisplayChildFlags = mozilla::EnumSet<DisplayChildFlag>;
1875 
1876   /**
1877    * Adjusts aDirtyRect for the child's offset, checks that the dirty rect
1878    * actually intersects the child (or its descendants), calls BuildDisplayList
1879    * on the child if necessary, and puts things in the right lists if the child
1880    * is positioned.
1881    *
1882    * @param aFlags a set of of DisplayChildFlag values that are applicable for
1883    * this operation.
1884    */
1885   void BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
1886                                 nsIFrame* aChild,
1887                                 const nsDisplayListSet& aLists,
1888                                 DisplayChildFlags aFlags = {});
1889 
1890   void BuildDisplayListForSimpleChild(nsDisplayListBuilder* aBuilder,
1891                                       nsIFrame* aChild,
1892                                       const nsDisplayListSet& aLists);
1893 
1894   /**
1895    * Helper for BuildDisplayListForChild, to implement this special-case for
1896    * grid (and flex) items from the spec:
1897    *   The painting order of grid items is exactly the same as inline blocks,
1898    *   except that [...], and 'z-index' values other than 'auto' create a
1899    *   stacking context even if 'position' is 'static' (behaving exactly as if
1900    *   'position' were 'relative'). https://drafts.csswg.org/css-grid/#z-order
1901    *
1902    * Flex items also have the same special-case described in
1903    * https://drafts.csswg.org/css-flexbox/#painting
1904    */
1905   DisplayChildFlag DisplayFlagForFlexOrGridItem() const;
1906 
RefusedAsyncAnimation()1907   bool RefusedAsyncAnimation() const {
1908     return GetProperty(RefusedAsyncAnimationProperty());
1909   }
1910 
1911   /**
1912    * Returns true if this frame is transformed (e.g. has CSS, SVG, or custom
1913    * transforms) or if its parent is an SVG frame that has children-only
1914    * transforms (e.g.  an SVG viewBox attribute) or if its transform-style is
1915    * preserve-3d or the frame has transform animations.
1916    */
1917   bool IsTransformed() const;
1918 
1919   /**
1920    * Same as IsTransformed, except that it doesn't take SVG transforms
1921    * into account.
1922    */
1923   bool IsCSSTransformed() const;
1924 
1925   /**
1926    * True if this frame has any animation of transform in effect.
1927    */
1928   bool HasAnimationOfTransform() const;
1929 
1930   /**
1931    * True if this frame has any animation of opacity in effect.
1932    *
1933    * EffectSet is just an optimization.
1934    */
1935   bool HasAnimationOfOpacity(mozilla::EffectSet* = nullptr) const;
1936 
1937   /**
1938    * Returns true if the frame is translucent or the frame has opacity
1939    * animations for the purposes of creating a stacking context.
1940    *
1941    * @param aStyleDisplay:  This function needs style display struct.
1942    *
1943    * @param aStyleEffects:  This function needs style effects struct.
1944    *
1945    * @param aEffectSet: This function may need to look up EffectSet property.
1946    *   If a caller already have one, pass it in can save property look up
1947    *   time; otherwise, just leave it as nullptr.
1948    */
1949   bool HasOpacity(const nsStyleDisplay* aStyleDisplay,
1950                   const nsStyleEffects* aStyleEffects,
1951                   mozilla::EffectSet* aEffectSet = nullptr) const {
1952     return HasOpacityInternal(1.0f, aStyleDisplay, aStyleEffects, aEffectSet);
1953   }
1954   /**
1955    * Returns true if the frame is translucent for display purposes.
1956    *
1957    * @param aStyleDisplay:  This function needs style display struct.
1958    *
1959    * @param aStyleEffects:  This function needs style effects struct.
1960    *
1961    * @param aEffectSet: This function may need to look up EffectSet property.
1962    *   If a caller already have one, pass it in can save property look up
1963    *   time; otherwise, just leave it as nullptr.
1964    */
1965   bool HasVisualOpacity(const nsStyleDisplay* aStyleDisplay,
1966                         const nsStyleEffects* aStyleEffects,
1967                         mozilla::EffectSet* aEffectSet = nullptr) const {
1968     // Treat an opacity value of 0.99 and above as opaque.  This is an
1969     // optimization aimed at Web content which use opacity:0.99 as a hint for
1970     // creating a stacking context only.
1971     return HasOpacityInternal(0.99f, aStyleDisplay, aStyleEffects, aEffectSet);
1972   }
1973 
1974   /**
1975    * Returns a matrix (in pixels) for the current frame. The matrix should be
1976    * relative to the current frame's coordinate space.
1977    *
1978    * @param aFrame The frame to compute the transform for.
1979    * @param aAppUnitsPerPixel The number of app units per graphics unit.
1980    */
1981   using ComputeTransformFunction = Matrix4x4 (*)(const nsIFrame*,
1982                                                  float aAppUnitsPerPixel);
1983   /** Returns the transform getter of this frame, if any. */
GetTransformGetter()1984   virtual ComputeTransformFunction GetTransformGetter() const {
1985     return nullptr;
1986   }
1987 
1988   /**
1989    * Returns true if this frame is an SVG frame that has SVG transforms applied
1990    * to it, or if its parent frame is an SVG frame that has children-only
1991    * transforms (e.g. an SVG viewBox attribute).
1992    * If aOwnTransforms is non-null and the frame has its own SVG transforms,
1993    * aOwnTransforms will be set to these transforms. If aFromParentTransforms
1994    * is non-null and the frame has an SVG parent with children-only transforms,
1995    * then aFromParentTransforms will be set to these transforms.
1996    */
1997   virtual bool IsSVGTransformed(Matrix* aOwnTransforms = nullptr,
1998                                 Matrix* aFromParentTransforms = nullptr) const;
1999 
2000   /**
2001    * Return true if this frame should form a backdrop root container.
2002    * See: https://drafts.fxtf.org/filter-effects-2/#BackdropRootTriggers
2003    */
2004   bool FormsBackdropRoot(const nsStyleDisplay* aStyleDisplay,
2005                          const nsStyleEffects* aStyleEffects,
2006                          const nsStyleSVGReset* aStyleSvgReset);
2007 
2008   /**
2009    * Returns whether this frame will attempt to extend the 3d transforms of its
2010    * children. This requires transform-style: preserve-3d, as well as no
2011    * clipping or svg effects.
2012    *
2013    * @param aStyleDisplay:  If the caller has this->StyleDisplay(), providing
2014    *   it here will improve performance.
2015    *
2016    * @param aStyleEffects:  If the caller has this->StyleEffects(), providing
2017    *   it here will improve performance.
2018    *
2019    * @param aEffectSetForOpacity: This function may need to look up the
2020    *   EffectSet for opacity animations on this frame.
2021    *   If the caller already has looked up this EffectSet, it may pass it in to
2022    *   save an extra property lookup.
2023    */
2024   bool Extend3DContext(
2025       const nsStyleDisplay* aStyleDisplay, const nsStyleEffects* aStyleEffects,
2026       mozilla::EffectSet* aEffectSetForOpacity = nullptr) const;
2027   bool Extend3DContext(
2028       mozilla::EffectSet* aEffectSetForOpacity = nullptr) const {
2029     return Extend3DContext(StyleDisplay(), StyleEffects(),
2030                            aEffectSetForOpacity);
2031   }
2032 
2033   /**
2034    * Returns whether this frame has a parent that Extend3DContext() and has
2035    * its own transform (or hidden backface) to be combined with the parent's
2036    * transform.
2037    */
2038   bool Combines3DTransformWithAncestors() const;
2039 
2040   /**
2041    * Returns whether this frame has a hidden backface and has a parent that
2042    * Extend3DContext(). This is useful because in some cases the hidden
2043    * backface can safely be ignored if it could not be visible anyway.
2044    *
2045    */
2046   bool In3DContextAndBackfaceIsHidden() const;
2047 
2048   bool IsPreserve3DLeaf(const nsStyleDisplay* aStyleDisplay,
2049                         mozilla::EffectSet* aEffectSet = nullptr) const {
2050     return Combines3DTransformWithAncestors() &&
2051            !Extend3DContext(aStyleDisplay, StyleEffects(), aEffectSet);
2052   }
2053   bool IsPreserve3DLeaf(mozilla::EffectSet* aEffectSet = nullptr) const {
2054     return IsPreserve3DLeaf(StyleDisplay(), aEffectSet);
2055   }
2056 
2057   bool HasPerspective(const nsStyleDisplay* aStyleDisplay) const;
HasPerspective()2058   bool HasPerspective() const { return HasPerspective(StyleDisplay()); }
2059 
2060   bool ChildrenHavePerspective(const nsStyleDisplay* aStyleDisplay) const;
ChildrenHavePerspective()2061   bool ChildrenHavePerspective() const {
2062     return ChildrenHavePerspective(StyleDisplay());
2063   }
2064 
2065   /**
2066    * Includes the overflow area of all descendants that participate in the
2067    * current 3d context into aOverflowAreas.
2068    */
2069   void ComputePreserve3DChildrenOverflow(
2070       mozilla::OverflowAreas& aOverflowAreas);
2071 
2072   void RecomputePerspectiveChildrenOverflow(const nsIFrame* aStartFrame);
2073 
2074   /**
2075    * Returns whether z-index applies to this frame.
2076    */
2077   bool ZIndexApplies() const;
2078 
2079   /**
2080    * Returns the computed z-index for this frame, returning Nothing() for
2081    * z-index: auto, and for frames that don't support z-index.
2082    */
2083   Maybe<int32_t> ZIndex() const;
2084 
2085   /**
2086    * Returns whether this frame is the anchor of some ancestor scroll frame. As
2087    * this frame is moved, the scroll frame will apply adjustments to keep this
2088    * scroll frame in the same relative position.
2089    *
2090    * aOutContainer will optionally be set to the scroll anchor container for
2091    * this frame if this frame is an anchor.
2092    */
2093   bool IsScrollAnchor(
2094       mozilla::layout::ScrollAnchorContainer** aOutContainer = nullptr);
2095 
2096   /**
2097    * Returns whether this frame is the anchor of some ancestor scroll frame, or
2098    * has a descendant which is the scroll anchor.
2099    */
2100   bool IsInScrollAnchorChain() const;
2101   void SetInScrollAnchorChain(bool aInChain);
2102 
2103   /**
2104    * Returns the number of ancestors between this and the root of our frame tree
2105    */
2106   uint32_t GetDepthInFrameTree() const;
2107 
2108   /**
2109    * Event handling of GUI events.
2110    *
2111    * @param aEvent event structure describing the type of event and rge widget
2112    * where the event originated. The |point| member of this is in the coordinate
2113    * system of the view returned by GetOffsetFromView.
2114    *
2115    * @param aEventStatus a return value indicating whether the event was
2116    * handled and whether default processing should be done
2117    *
2118    * XXX From a frame's perspective it's unclear what the effect of the event
2119    * status is. Does it cause the event to continue propagating through the
2120    * frame hierarchy or is it just returned to the widgets?
2121    *
2122    * @see     WidgetGUIEvent
2123    * @see     nsEventStatus
2124    */
2125   MOZ_CAN_RUN_SCRIPT_BOUNDARY
2126   virtual nsresult HandleEvent(nsPresContext* aPresContext,
2127                                mozilla::WidgetGUIEvent* aEvent,
2128                                nsEventStatus* aEventStatus);
2129 
2130   /**
2131    * Search for selectable content at point and attempt to select
2132    * based on the start and end selection behaviours.
2133    *
2134    * @param aPresContext Presentation context
2135    * @param aPoint Point at which selection will occur. Coordinates
2136    * should be relative to this frame.
2137    * @param aBeginAmountType, aEndAmountType Selection behavior, see
2138    * nsIFrame for definitions.
2139    * @param aSelectFlags Selection flags defined in nsIFrame.h.
2140    * @return success or failure at finding suitable content to select.
2141    */
2142   MOZ_CAN_RUN_SCRIPT nsresult
2143   SelectByTypeAtPoint(nsPresContext* aPresContext, const nsPoint& aPoint,
2144                       nsSelectionAmount aBeginAmountType,
2145                       nsSelectionAmount aEndAmountType, uint32_t aSelectFlags);
2146 
2147   MOZ_CAN_RUN_SCRIPT nsresult PeekBackwardAndForward(
2148       nsSelectionAmount aAmountBack, nsSelectionAmount aAmountForward,
2149       int32_t aStartPos, bool aJumpLines, uint32_t aSelectFlags);
2150 
2151   enum { SELECT_ACCUMULATE = 0x01 };
2152 
2153  protected:
2154   // Fire DOM event. If no aContent argument use frame's mContent.
2155   void FireDOMEvent(const nsAString& aDOMEventName,
2156                     nsIContent* aContent = nullptr);
2157 
2158   // Selection Methods
2159 
2160   MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHOD
2161   HandlePress(nsPresContext* aPresContext, mozilla::WidgetGUIEvent* aEvent,
2162               nsEventStatus* aEventStatus);
2163 
2164   /**
2165    * MoveCaretToEventPoint() moves caret at the point of aMouseEvent.
2166    *
2167    * @param aPresContext        Must not be nullptr.
2168    * @param aMouseEvent         Must not be nullptr, the message must be
2169    *                            eMouseDown and its button must be primary or
2170    *                            middle button.
2171    * @param aEventStatus        [out] Must not be nullptr.  This method ignores
2172    *                            its initial value, but callees may refer it.
2173    */
2174   MOZ_CAN_RUN_SCRIPT nsresult MoveCaretToEventPoint(
2175       nsPresContext* aPresContext, mozilla::WidgetMouseEvent* aMouseEvent,
2176       nsEventStatus* aEventStatus);
2177 
2178   MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHOD HandleMultiplePress(
2179       nsPresContext* aPresContext, mozilla::WidgetGUIEvent* aEvent,
2180       nsEventStatus* aEventStatus, bool aControlHeld);
2181 
2182   /**
2183    * @param aPresContext must be non-nullptr.
2184    * @param aEvent must be non-nullptr.
2185    * @param aEventStatus must be non-nullptr.
2186    */
2187   MOZ_CAN_RUN_SCRIPT
2188   NS_IMETHOD HandleDrag(nsPresContext* aPresContext,
2189                         mozilla::WidgetGUIEvent* aEvent,
2190                         nsEventStatus* aEventStatus);
2191 
2192   MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHOD
2193   HandleRelease(nsPresContext* aPresContext, mozilla::WidgetGUIEvent* aEvent,
2194                 nsEventStatus* aEventStatus);
2195 
2196   // Test if we are selecting a table object:
2197   //  Most table/cell selection requires that Ctrl (Cmd on Mac) key is down
2198   //   during a mouse click or drag. Exception is using Shift+click when
2199   //   already in "table/cell selection mode" to extend a block selection
2200   //  Get the parent content node and offset of the frame
2201   //   of the enclosing cell or table (if not inside a cell)
2202   //  aTarget tells us what table element to select (currently only cell and
2203   //  table supported) (enums for this are defined in nsIFrame.h)
2204   nsresult GetDataForTableSelection(const nsFrameSelection* aFrameSelection,
2205                                     mozilla::PresShell* aPresShell,
2206                                     mozilla::WidgetMouseEvent* aMouseEvent,
2207                                     nsIContent** aParentContent,
2208                                     int32_t* aContentOffset,
2209                                     mozilla::TableSelectionMode* aTarget);
2210 
2211   /**
2212    * @return see nsISelectionController.idl's `getDisplaySelection`.
2213    */
2214   int16_t DetermineDisplaySelection();
2215 
2216  public:
2217   virtual nsresult GetContentForEvent(mozilla::WidgetEvent* aEvent,
2218                                       nsIContent** aContent);
2219 
2220   // This structure keeps track of the content node and offsets associated with
2221   // a point; there is a primary and a secondary offset associated with any
2222   // point.  The primary and secondary offsets differ when the point is over a
2223   // non-text object.  The primary offset is the expected position of the
2224   // cursor calculated from a point; the secondary offset, when it is different,
2225   // indicates that the point is in the boundaries of some selectable object.
2226   // Note that the primary offset can be after the secondary offset; for places
2227   // that need the beginning and end of the object, the StartOffset and
2228   // EndOffset helpers can be used.
2229   struct MOZ_STACK_CLASS ContentOffsets {
ContentOffsetsContentOffsets2230     ContentOffsets()
2231         : offset(0),
2232           secondaryOffset(0),
2233           associate(mozilla::CARET_ASSOCIATE_BEFORE) {}
IsNullContentOffsets2234     bool IsNull() { return !content; }
2235     // Helpers for places that need the ends of the offsets and expect them in
2236     // numerical order, as opposed to wanting the primary and secondary offsets
StartOffsetContentOffsets2237     int32_t StartOffset() { return std::min(offset, secondaryOffset); }
EndOffsetContentOffsets2238     int32_t EndOffset() { return std::max(offset, secondaryOffset); }
2239 
2240     nsCOMPtr<nsIContent> content;
2241     int32_t offset;
2242     int32_t secondaryOffset;
2243     // This value indicates whether the associated content is before or after
2244     // the offset; the most visible use is to allow the caret to know which line
2245     // to display on.
2246     mozilla::CaretAssociationHint associate;
2247   };
2248   enum {
2249     IGNORE_SELECTION_STYLE = 0x01,
2250     // Treat visibility:hidden frames as non-selectable
2251     SKIP_HIDDEN = 0x02
2252   };
2253   /**
2254    * This function calculates the content offsets for selection relative to
2255    * a point.  Note that this should generally only be callled on the event
2256    * frame associated with an event because this function does not account
2257    * for frame lists other than the primary one.
2258    * @param aPoint point relative to this frame
2259    */
2260   ContentOffsets GetContentOffsetsFromPoint(const nsPoint& aPoint,
2261                                             uint32_t aFlags = 0);
2262 
2263   virtual ContentOffsets GetContentOffsetsFromPointExternal(
2264       const nsPoint& aPoint, uint32_t aFlags = 0) {
2265     return GetContentOffsetsFromPoint(aPoint, aFlags);
2266   }
2267 
2268   // Helper for GetContentAndOffsetsFromPoint; calculation of content offsets
2269   // in this function assumes there is no child frame that can be targeted.
2270   virtual ContentOffsets CalcContentOffsetsFromFramePoint(
2271       const nsPoint& aPoint);
2272 
2273   /**
2274    * Ensure that `this` gets notifed when `aImage`s underlying image request
2275    * loads or animates.
2276    *
2277    * This in practice is only needed for the canvas frame and table cell
2278    * backgrounds, which are the only cases that should paint a background that
2279    * isn't its own. The canvas paints the background from the root element or
2280    * body, and the table cell paints the background for its row.
2281    *
2282    * For regular frames, this is done in DidSetComputedStyle.
2283    *
2284    * NOTE: It's unclear if we even actually _need_ this for the second case, as
2285    * invalidating the row should invalidate all the cells. For the canvas case
2286    * this is definitely needed as it paints the background from somewhere "down"
2287    * in the frame tree.
2288    *
2289    * Returns whether the image was in fact associated with the frame.
2290    */
2291   [[nodiscard]] bool AssociateImage(const mozilla::StyleImage&);
2292 
2293   /**
2294    * This needs to be called if the above caller returned true, once the above
2295    * caller doesn't care about getting notified anymore.
2296    */
2297   void DisassociateImage(const mozilla::StyleImage&);
2298 
2299   enum class AllowCustomCursorImage {
2300     No,
2301     Yes,
2302   };
2303 
2304   /**
2305    * This structure holds information about a cursor. AllowCustomCursorImage
2306    * is `No`, then no cursor image should be loaded from the style specified on
2307    * `mStyle`, or the frame's style.
2308    *
2309    * The `mStyle` member is used for `<area>` elements.
2310    */
2311   struct MOZ_STACK_CLASS Cursor {
2312     mozilla::StyleCursorKind mCursor = mozilla::StyleCursorKind::Auto;
2313     AllowCustomCursorImage mAllowCustomCursor = AllowCustomCursorImage::Yes;
2314     RefPtr<mozilla::ComputedStyle> mStyle;
2315   };
2316 
2317   /**
2318    * Get the cursor for a given frame.
2319    */
2320   virtual Maybe<Cursor> GetCursor(const nsPoint&);
2321 
2322   /**
2323    * Get a point (in the frame's coordinate space) given an offset into
2324    * the content. This point should be on the baseline of text with
2325    * the correct horizontal offset
2326    */
2327   virtual nsresult GetPointFromOffset(int32_t inOffset, nsPoint* outPoint);
2328 
2329   /**
2330    * Get a list of character rects in a given range.
2331    * This is similar version of GetPointFromOffset.
2332    */
2333   virtual nsresult GetCharacterRectsInRange(int32_t aInOffset, int32_t aLength,
2334                                             nsTArray<nsRect>& aRects);
2335 
2336   /**
2337    * Get the child frame of this frame which contains the given
2338    * content offset. outChildFrame may be this frame, or nullptr on return.
2339    * outContentOffset returns the content offset relative to the start
2340    * of the returned node. You can also pass a hint which tells the method
2341    * to stick to the end of the first found frame or the beginning of the
2342    * next in case the offset falls on a boundary.
2343    */
2344   virtual nsresult GetChildFrameContainingOffset(
2345       int32_t inContentOffset,
2346       bool inHint,  // false stick left
2347       int32_t* outFrameContentOffset, nsIFrame** outChildFrame);
2348 
2349   /**
2350    * Get the current frame-state value for this frame. aResult is
2351    * filled in with the state bits.
2352    */
GetStateBits()2353   nsFrameState GetStateBits() const { return mState; }
2354 
2355   /**
2356    * Update the current frame-state value for this frame.
2357    */
AddStateBits(nsFrameState aBits)2358   void AddStateBits(nsFrameState aBits) { mState |= aBits; }
RemoveStateBits(nsFrameState aBits)2359   void RemoveStateBits(nsFrameState aBits) { mState &= ~aBits; }
AddOrRemoveStateBits(nsFrameState aBits,bool aVal)2360   void AddOrRemoveStateBits(nsFrameState aBits, bool aVal) {
2361     aVal ? AddStateBits(aBits) : RemoveStateBits(aBits);
2362   }
2363 
2364   /**
2365    * Checks if the current frame-state includes all of the listed bits
2366    */
HasAllStateBits(nsFrameState aBits)2367   bool HasAllStateBits(nsFrameState aBits) const {
2368     return (mState & aBits) == aBits;
2369   }
2370 
2371   /**
2372    * Checks if the current frame-state includes any of the listed bits
2373    */
HasAnyStateBits(nsFrameState aBits)2374   bool HasAnyStateBits(nsFrameState aBits) const { return mState & aBits; }
2375 
2376   /**
2377    * Return true if this frame is the primary frame for mContent.
2378    */
IsPrimaryFrame()2379   bool IsPrimaryFrame() const { return mIsPrimaryFrame; }
2380 
SetIsPrimaryFrame(bool aIsPrimary)2381   void SetIsPrimaryFrame(bool aIsPrimary) { mIsPrimaryFrame = aIsPrimary; }
2382 
2383   bool IsPrimaryFrameOfRootOrBodyElement() const;
2384 
2385   /**
2386    * @return true if this frame is used as a fieldset's rendered legend.
2387    */
2388   bool IsRenderedLegend() const;
2389 
2390   /**
2391    * This call is invoked on the primary frame for a character data content
2392    * node, when it is changed in the content tree.
2393    */
2394   virtual nsresult CharacterDataChanged(const CharacterDataChangeInfo&);
2395 
2396   /**
2397    * This call is invoked when the value of a content objects's attribute
2398    * is changed.
2399    * The first frame that maps that content is asked to deal
2400    * with the change by doing whatever is appropriate.
2401    *
2402    * @param aNameSpaceID the namespace of the attribute
2403    * @param aAttribute the atom name of the attribute
2404    * @param aModType Whether or not the attribute was added, changed, or
2405    * removed. The constants are defined in MutationEvent.webidl.
2406    */
2407   virtual nsresult AttributeChanged(int32_t aNameSpaceID, nsAtom* aAttribute,
2408                                     int32_t aModType);
2409 
2410   /**
2411    * When the content states of a content object change, this method is invoked
2412    * on the primary frame of that content object.
2413    *
2414    * @param aStates the changed states
2415    */
2416   virtual void ContentStatesChanged(mozilla::EventStates aStates);
2417 
2418   /**
2419    * Continuation member functions
2420    */
2421   virtual nsIFrame* GetPrevContinuation() const;
2422   virtual void SetPrevContinuation(nsIFrame*);
2423   virtual nsIFrame* GetNextContinuation() const;
2424   virtual void SetNextContinuation(nsIFrame*);
FirstContinuation()2425   virtual nsIFrame* FirstContinuation() const {
2426     return const_cast<nsIFrame*>(this);
2427   }
LastContinuation()2428   virtual nsIFrame* LastContinuation() const {
2429     return const_cast<nsIFrame*>(this);
2430   }
2431 
2432   /**
2433    * GetTailContinuation gets the last non-overflow-container continuation
2434    * in the continuation chain, i.e. where the next sibling element
2435    * should attach).
2436    */
2437   nsIFrame* GetTailContinuation();
2438 
2439   /**
2440    * Flow member functions
2441    */
2442   virtual nsIFrame* GetPrevInFlow() const;
2443   virtual void SetPrevInFlow(nsIFrame*);
2444 
2445   virtual nsIFrame* GetNextInFlow() const;
2446   virtual void SetNextInFlow(nsIFrame*);
2447 
2448   /**
2449    * Return the first frame in our current flow.
2450    */
FirstInFlow()2451   virtual nsIFrame* FirstInFlow() const { return const_cast<nsIFrame*>(this); }
2452 
2453   /**
2454    * Return the last frame in our current flow.
2455    */
LastInFlow()2456   virtual nsIFrame* LastInFlow() const { return const_cast<nsIFrame*>(this); }
2457 
2458   /**
2459    * Note: "width" in the names and comments on the following methods
2460    * means inline-size, which could be height in vertical layout
2461    */
2462 
2463   /**
2464    * Mark any stored intrinsic width information as dirty (requiring
2465    * re-calculation).  Note that this should generally not be called
2466    * directly; PresShell::FrameNeedsReflow() will call it instead.
2467    */
2468   virtual void MarkIntrinsicISizesDirty();
2469 
2470  private:
2471   nsBoxLayoutMetrics* BoxMetrics() const;
2472 
2473  public:
2474   /**
2475    * Make this frame and all descendants dirty (if not already).
2476    * Exceptions: XULBoxFrame and TableColGroupFrame children.
2477    */
2478   void MarkSubtreeDirty();
2479 
2480   /**
2481    * Get the min-content intrinsic inline size of the frame.  This must be
2482    * less than or equal to the max-content intrinsic inline size.
2483    *
2484    * This is *not* affected by the CSS 'min-width', 'width', and
2485    * 'max-width' properties on this frame, but it is affected by the
2486    * values of those properties on this frame's descendants.  (It may be
2487    * called during computation of the values of those properties, so it
2488    * cannot depend on any values in the nsStylePosition for this frame.)
2489    *
2490    * The value returned should **NOT** include the space required for
2491    * padding and border.
2492    *
2493    * Note that many frames will cache the result of this function call
2494    * unless MarkIntrinsicISizesDirty is called.
2495    *
2496    * It is not acceptable for a frame to mark itself dirty when this
2497    * method is called.
2498    *
2499    * This method must not return a negative value.
2500    */
2501   virtual nscoord GetMinISize(gfxContext* aRenderingContext);
2502 
2503   /**
2504    * Get the max-content intrinsic inline size of the frame.  This must be
2505    * greater than or equal to the min-content intrinsic inline size.
2506    *
2507    * Otherwise, all the comments for |GetMinISize| above apply.
2508    */
2509   virtual nscoord GetPrefISize(gfxContext* aRenderingContext);
2510 
2511   /**
2512    * |InlineIntrinsicISize| represents the intrinsic width information
2513    * in inline layout.  Code that determines the intrinsic width of a
2514    * region of inline layout accumulates the result into this structure.
2515    * This pattern is needed because we need to maintain state
2516    * information about whitespace (for both collapsing and trimming).
2517    */
2518   struct InlineIntrinsicISizeData {
InlineIntrinsicISizeDataInlineIntrinsicISizeData2519     InlineIntrinsicISizeData()
2520         : mLine(nullptr),
2521           mLineContainer(nullptr),
2522           mPrevLines(0),
2523           mCurrentLine(0),
2524           mTrailingWhitespace(0),
2525           mSkipWhitespace(true) {}
2526 
2527     // The line. This may be null if the inlines are not associated with
2528     // a block or if we just don't know the line.
2529     const nsLineList_iterator* mLine;
2530 
2531     // The line container. Private, to ensure we always use SetLineContainer
2532     // to update it.
2533     //
2534     // Note that nsContainerFrame::DoInlineIntrinsicISize will clear the
2535     // |mLine| and |mLineContainer| fields when following a next-in-flow link,
2536     // so we must not assume these can always be dereferenced.
2537    private:
2538     nsIFrame* mLineContainer;
2539 
2540     // Setter and getter for the lineContainer field:
2541    public:
SetLineContainerInlineIntrinsicISizeData2542     void SetLineContainer(nsIFrame* aLineContainer) {
2543       mLineContainer = aLineContainer;
2544     }
LineContainerInlineIntrinsicISizeData2545     nsIFrame* LineContainer() const { return mLineContainer; }
2546 
2547     // The maximum intrinsic width for all previous lines.
2548     nscoord mPrevLines;
2549 
2550     // The maximum intrinsic width for the current line.  At a line
2551     // break (mandatory for preferred width; allowed for minimum width),
2552     // the caller should call |Break()|.
2553     nscoord mCurrentLine;
2554 
2555     // This contains the width of the trimmable whitespace at the end of
2556     // |mCurrentLine|; it is zero if there is no such whitespace.
2557     nscoord mTrailingWhitespace;
2558 
2559     // True if initial collapsable whitespace should be skipped.  This
2560     // should be true at the beginning of a block, after hard breaks
2561     // and when the last text ended with whitespace.
2562     bool mSkipWhitespace;
2563 
2564     // Floats encountered in the lines.
2565     class FloatInfo {
2566      public:
FloatInfoInlineIntrinsicISizeData2567       FloatInfo(const nsIFrame* aFrame, nscoord aWidth)
2568           : mFrame(aFrame), mWidth(aWidth) {}
FrameInlineIntrinsicISizeData2569       const nsIFrame* Frame() const { return mFrame; }
WidthInlineIntrinsicISizeData2570       nscoord Width() const { return mWidth; }
2571 
2572      private:
2573       const nsIFrame* mFrame;
2574       nscoord mWidth;
2575     };
2576 
2577     nsTArray<FloatInfo> mFloats;
2578   };
2579 
2580   struct InlineMinISizeData : public InlineIntrinsicISizeData {
InlineMinISizeDataInlineMinISizeData2581     InlineMinISizeData() : mAtStartOfLine(true) {}
2582 
2583     // The default implementation for nsIFrame::AddInlineMinISize.
2584     void DefaultAddInlineMinISize(nsIFrame* aFrame, nscoord aISize,
2585                                   bool aAllowBreak = true);
2586 
2587     // We need to distinguish forced and optional breaks for cases where the
2588     // current line total is negative.  When it is, we need to ignore
2589     // optional breaks to prevent min-width from ending up bigger than
2590     // pref-width.
2591     void ForceBreak();
2592 
2593     // If the break here is actually taken, aHyphenWidth must be added to the
2594     // width of the current line.
2595     void OptionallyBreak(nscoord aHyphenWidth = 0);
2596 
2597     // Whether we're currently at the start of the line.  If we are, we
2598     // can't break (for example, between the text-indent and the first
2599     // word).
2600     bool mAtStartOfLine;
2601   };
2602 
2603   struct InlinePrefISizeData : public InlineIntrinsicISizeData {
2604     typedef mozilla::StyleClear StyleClear;
2605 
InlinePrefISizeDataInlinePrefISizeData2606     InlinePrefISizeData() : mLineIsEmpty(true) {}
2607 
2608     /**
2609      * Finish the current line and start a new line.
2610      *
2611      * @param aBreakType controls whether isize of floats are considered
2612      * and what floats are kept for the next line:
2613      *  * |None| skips handling floats, which means no floats are
2614      *    removed, and isizes of floats are not considered either.
2615      *  * |Both| takes floats into consideration when computing isize
2616      *    of the current line, and removes all floats after that.
2617      *  * |Left| and |Right| do the same as |Both| except that they only
2618      *    remove floats on the given side, and any floats on the other
2619      *    side that are prior to a float on the given side that has a
2620      *    'clear' property that clears them.
2621      * All other values of StyleClear must be converted to the four
2622      * physical values above for this function.
2623      */
2624     void ForceBreak(StyleClear aBreakType = StyleClear::Both);
2625 
2626     // The default implementation for nsIFrame::AddInlinePrefISize.
2627     void DefaultAddInlinePrefISize(nscoord aISize);
2628 
2629     // True if the current line contains nothing other than placeholders.
2630     bool mLineIsEmpty;
2631   };
2632 
2633   /**
2634    * Add the intrinsic minimum width of a frame in a way suitable for
2635    * use in inline layout to an |InlineIntrinsicISizeData| object that
2636    * represents the intrinsic width information of all the previous
2637    * frames in the inline layout region.
2638    *
2639    * All *allowed* breakpoints within the frame determine what counts as
2640    * a line for the |InlineIntrinsicISizeData|.  This means that
2641    * |aData->mTrailingWhitespace| will always be zero (unlike for
2642    * AddInlinePrefISize).
2643    *
2644    * All the comments for |GetMinISize| apply, except that this function
2645    * is responsible for adding padding, border, and margin and for
2646    * considering the effects of 'width', 'min-width', and 'max-width'.
2647    *
2648    * This may be called on any frame.  Frames that do not participate in
2649    * line breaking can inherit the default implementation on nsFrame,
2650    * which calls |GetMinISize|.
2651    */
2652   virtual void AddInlineMinISize(gfxContext* aRenderingContext,
2653                                  InlineMinISizeData* aData);
2654 
2655   /**
2656    * Add the intrinsic preferred width of a frame in a way suitable for
2657    * use in inline layout to an |InlineIntrinsicISizeData| object that
2658    * represents the intrinsic width information of all the previous
2659    * frames in the inline layout region.
2660    *
2661    * All the comments for |AddInlineMinISize| and |GetPrefISize| apply,
2662    * except that this fills in an |InlineIntrinsicISizeData| structure
2663    * based on using all *mandatory* breakpoints within the frame.
2664    */
2665   virtual void AddInlinePrefISize(gfxContext* aRenderingContext,
2666                                   InlinePrefISizeData* aData);
2667 
2668   /**
2669    * Intrinsic size of a frame in a single axis.
2670    *
2671    * This can represent either isize or bsize.
2672    */
2673   struct IntrinsicSizeOffsetData {
2674     nscoord padding = 0;
2675     nscoord border = 0;
2676     nscoord margin = 0;
BorderPaddingIntrinsicSizeOffsetData2677     nscoord BorderPadding() const { return border + padding; };
2678   };
2679 
2680   /**
2681    * Return the isize components of padding, border, and margin
2682    * that contribute to the intrinsic width that applies to the parent.
2683    * @param aPercentageBasis the percentage basis to use for padding/margin -
2684    *   i.e. the Containing Block's inline-size
2685    */
2686   virtual IntrinsicSizeOffsetData IntrinsicISizeOffsets(
2687       nscoord aPercentageBasis = NS_UNCONSTRAINEDSIZE);
2688 
2689   /**
2690    * Return the bsize components of padding, border, and margin
2691    * that contribute to the intrinsic width that applies to the parent.
2692    * @param aPercentageBasis the percentage basis to use for padding/margin -
2693    *   i.e. the Containing Block's inline-size
2694    */
2695   IntrinsicSizeOffsetData IntrinsicBSizeOffsets(
2696       nscoord aPercentageBasis = NS_UNCONSTRAINEDSIZE);
2697 
2698   virtual mozilla::IntrinsicSize GetIntrinsicSize();
2699 
2700   /**
2701    * Get the preferred aspect ratio of this frame, or a default-constructed
2702    * AspectRatio if it has none.
2703    *
2704    * https://drafts.csswg.org/css-sizing-4/#preferred-aspect-ratio
2705    */
2706   mozilla::AspectRatio GetAspectRatio() const;
2707 
2708   /**
2709    * Get the intrinsic aspect ratio of this frame, or a default-constructed
2710    * AspectRatio if it has no intrinsic ratio.
2711    *
2712    * The intrinsic ratio is the ratio of the width/height of a box with an
2713    * intrinsic size or the intrinsic aspect ratio of a scalable vector image
2714    * without an intrinsic size. A frame class implementing a replaced element
2715    * should override this method if it has a intrinsic ratio.
2716    */
2717   virtual mozilla::AspectRatio GetIntrinsicRatio() const;
2718 
2719   /**
2720    * Compute the size that a frame will occupy.  Called while
2721    * constructing the ReflowInput to be used to Reflow the frame,
2722    * in order to fill its mComputedWidth and mComputedHeight member
2723    * variables.
2724    *
2725    * Note that the reason that border and padding need to be passed
2726    * separately is so that the 'box-sizing' property can be handled.
2727    * Thus aMargin includes absolute positioning offsets as well.
2728    *
2729    * @param aWM  The writing mode to use for the returned size (need not match
2730    *             this frame's writing mode). This is also the writing mode of
2731    *             the passed-in LogicalSize parameters.
2732    * @param aCBSize  The size of the element's containing block.  (Well,
2733    *                 the BSize() component isn't really.)
2734    * @param aAvailableISize  The available inline-size for 'auto' inline-size.
2735    *                         This is usually the same as aCBSize.ISize(),
2736    *                         but differs in cases such as block
2737    *                         formatting context roots next to floats, or
2738    *                         in some cases of float reflow in quirks
2739    *                         mode.
2740    * @param aMargin  The sum of the inline / block margins ***AND***
2741    *                 absolute positioning offsets (inset-block and
2742    *                 inset-inline) of the frame, including actual values
2743    *                 resulting from percentages and from the
2744    *                 "hypothetical box" for absolute positioning, but
2745    *                 not including actual values resulting from 'auto'
2746    *                 margins or ignored 'auto' values in absolute
2747    *                 positioning.
2748    * @param aBorderPadding  The sum of the frame's inline / block border-widths
2749    *                        and padding (including actual values resulting from
2750    *                        percentage padding values).
2751    * @param aSizeOverride Optional override values for size properties, which
2752    *                      this function will use internally instead of the
2753    *                      actual property values.
2754    * @param aFlags   Flags to further customize behavior (definitions in
2755    *                 LayoutConstants.h).
2756    *
2757    * The return value includes the computed LogicalSize and AspectRatioUsage
2758    * which indicates whether the inline/block size is affected by aspect-ratio
2759    * or not. The BSize() of the returned LogicalSize may be
2760    * NS_UNCONSTRAINEDSIZE, but the ISize() must not be. We need AspectRatioUsage
2761    * during reflow because the final size may be affected by the content size
2762    * after applying aspect-ratio.
2763    * https://drafts.csswg.org/css-sizing-4/#aspect-ratio-minimum
2764    *
2765    */
2766   enum class AspectRatioUsage : uint8_t {
2767     None,
2768     ToComputeISize,
2769     ToComputeBSize,
2770   };
2771   struct SizeComputationResult {
2772     mozilla::LogicalSize mLogicalSize;
2773     AspectRatioUsage mAspectRatioUsage = AspectRatioUsage::None;
2774   };
2775   virtual SizeComputationResult ComputeSize(
2776       gfxContext* aRenderingContext, mozilla::WritingMode aWM,
2777       const mozilla::LogicalSize& aCBSize, nscoord aAvailableISize,
2778       const mozilla::LogicalSize& aMargin,
2779       const mozilla::LogicalSize& aBorderPadding,
2780       const mozilla::StyleSizeOverrides& aSizeOverrides,
2781       mozilla::ComputeSizeFlags aFlags);
2782 
2783  protected:
2784   /**
2785    * A helper, used by |nsIFrame::ComputeSize| (for frames that need to
2786    * override only this part of ComputeSize), that computes the size
2787    * that should be returned when inline-size, block-size, and
2788    * [min|max]-[inline-size|block-size] are all 'auto' or equivalent.
2789    *
2790    * In general, frames that can accept any computed inline-size/block-size
2791    * should override only ComputeAutoSize, and frames that cannot do so need to
2792    * override ComputeSize to enforce their inline-size/block-size invariants.
2793    *
2794    * Implementations may optimize by returning a garbage inline-size if
2795    * StylePosition()->ISize() is not 'auto' (or inline-size override in
2796    * aSizeOverrides is not 'auto' if provided), and likewise for BSize(), since
2797    * in such cases the result is guaranteed to be unused.
2798    *
2799    * Most of the frame are not expected to check the aSizeOverrides parameter
2800    * apart from checking the inline size override for 'auto' if they want to
2801    * optimize and return garbage inline-size.
2802    */
2803   virtual mozilla::LogicalSize ComputeAutoSize(
2804       gfxContext* aRenderingContext, mozilla::WritingMode aWM,
2805       const mozilla::LogicalSize& aCBSize, nscoord aAvailableISize,
2806       const mozilla::LogicalSize& aMargin,
2807       const mozilla::LogicalSize& aBorderPadding,
2808       const mozilla::StyleSizeOverrides& aSizeOverrides,
2809       mozilla::ComputeSizeFlags aFlags);
2810 
2811   /**
2812    * Utility function for ComputeAutoSize implementations.  Return
2813    * max(GetMinISize(), min(aISizeInCB, GetPrefISize()))
2814    */
2815   nscoord ShrinkWidthToFit(gfxContext* aRenderingContext, nscoord aISizeInCB,
2816                            mozilla::ComputeSizeFlags aFlags);
2817 
2818  public:
2819   /**
2820    * Compute a tight bounding rectangle for the frame. This is a rectangle
2821    * that encloses the pixels that are actually drawn. We're allowed to be
2822    * conservative and currently we don't try very hard. The rectangle is
2823    * in appunits and relative to the origin of this frame.
2824    *
2825    * This probably only needs to include frame bounds, glyph bounds, and
2826    * text decorations, but today it sometimes includes other things that
2827    * contribute to ink overflow.
2828    *
2829    * @param aDrawTarget a draw target that can be used if we need
2830    * to do measurement
2831    */
2832   virtual nsRect ComputeTightBounds(DrawTarget* aDrawTarget) const;
2833 
2834   /**
2835    * This function is similar to GetPrefISize and ComputeTightBounds: it
2836    * computes the left and right coordinates of a preferred tight bounding
2837    * rectangle for the frame. This is a rectangle that would enclose the pixels
2838    * that are drawn if we lay out the element without taking any optional line
2839    * breaks. The rectangle is in appunits and relative to the origin of this
2840    * frame. Currently, this function is only implemented for nsBlockFrame and
2841    * nsTextFrame and is used to determine intrinsic widths of MathML token
2842    * elements.
2843 
2844    * @param aContext a rendering context that can be used if we need
2845    * to do measurement
2846    * @param aX      computed left coordinate of the tight bounding rectangle
2847    * @param aXMost  computed intrinsic width of the tight bounding rectangle
2848    *
2849    */
2850   virtual nsresult GetPrefWidthTightBounds(gfxContext* aContext, nscoord* aX,
2851                                            nscoord* aXMost);
2852 
2853   /**
2854    * The frame is given an available size and asked for its desired
2855    * size.  This is the frame's opportunity to reflow its children.
2856    *
2857    * If the frame has the NS_FRAME_IS_DIRTY bit set then it is
2858    * responsible for completely reflowing itself and all of its
2859    * descendants.
2860    *
2861    * Otherwise, if the frame has the NS_FRAME_HAS_DIRTY_CHILDREN bit
2862    * set, then it is responsible for reflowing at least those
2863    * children that have NS_FRAME_HAS_DIRTY_CHILDREN or NS_FRAME_IS_DIRTY
2864    * set.
2865    *
2866    * If a difference in available size from the previous reflow causes
2867    * the frame's size to change, it should reflow descendants as needed.
2868    *
2869    * Calculates the size of this frame after reflowing (calling Reflow on, and
2870    * updating the size and position of) its children, as necessary.  The
2871    * calculated size is returned to the caller via the ReflowOutput
2872    * outparam.  (The caller is responsible for setting the actual size and
2873    * position of this frame.)
2874    *
2875    * A frame's children must _all_ be reflowed if the frame is dirty (the
2876    * NS_FRAME_IS_DIRTY bit is set on it).  Otherwise, individual children
2877    * must be reflowed if they are dirty or have the NS_FRAME_HAS_DIRTY_CHILDREN
2878    * bit set on them.  Otherwise, whether children need to be reflowed depends
2879    * on the frame's type (it's up to individual Reflow methods), and on what
2880    * has changed.  For example, a change in the width of the frame may require
2881    * all of its children to be reflowed (even those without dirty bits set on
2882    * them), whereas a change in its height might not.
2883    * (ReflowInput::ShouldReflowAllKids may be helpful in deciding whether
2884    * to reflow all the children, but for some frame types it might result in
2885    * over-reflow.)
2886    *
2887    * Note: if it's only the overflow rect(s) of a frame that need to be
2888    * updated, then UpdateOverflow should be called instead of Reflow.
2889    *
2890    * @param aReflowOutput <i>out</i> parameter where you should return the
2891    *          desired size and ascent/descent info. You should include any
2892    *          space you want for border/padding in the desired size you return.
2893    *
2894    *          It's okay to return a desired size that exceeds the avail
2895    *          size if that's the smallest you can be, i.e. it's your
2896    *          minimum size.
2897    *
2898    *          For an incremental reflow you are responsible for invalidating
2899    *          any area within your frame that needs repainting (including
2900    *          borders). If your new desired size is different than your current
2901    *          size, then your parent frame is responsible for making sure that
2902    *          the difference between the two rects is repainted
2903    *
2904    * @param aReflowInput information about your reflow including the reason
2905    *          for the reflow and the available space in which to lay out. Each
2906    *          dimension of the available space can either be constrained or
2907    *          unconstrained (a value of NS_UNCONSTRAINEDSIZE).
2908    *
2909    *          Note that the available space can be negative. In this case you
2910    *          still must return an accurate desired size. If you're a container
2911    *          you must <b>always</b> reflow at least one frame regardless of the
2912    *          available space
2913    *
2914    * @param aStatus a return value indicating whether the frame is complete
2915    *          and whether the next-in-flow is dirty and needs to be reflowed
2916    */
2917   virtual void Reflow(nsPresContext* aPresContext, ReflowOutput& aReflowOutput,
2918                       const ReflowInput& aReflowInput, nsReflowStatus& aStatus);
2919 
2920   // Option flags for ReflowChild(), FinishReflowChild(), and
2921   // SyncFrameViewAfterReflow().
2922   enum class ReflowChildFlags : uint32_t {
2923     Default = 0,
2924 
2925     // Don't position the frame's view. Set this if you don't want to
2926     // automatically sync the frame and view.
2927     NoMoveView = 1 << 0,
2928 
2929     // Don't move the frame. Also implies NoMoveView.
2930     NoMoveFrame = (1 << 1) | NoMoveView,
2931 
2932     // Don't size the frame's view.
2933     NoSizeView = 1 << 2,
2934 
2935     // Only applies to ReflowChild; if true, don't delete the next-in-flow, even
2936     // if the reflow is fully complete.
2937     NoDeleteNextInFlowChild = 1 << 3,
2938 
2939     // Only applies to FinishReflowChild.  Tell it to call
2940     // ApplyRelativePositioning.
2941     ApplyRelativePositioning = 1 << 4,
2942   };
2943 
2944   /**
2945    * Post-reflow hook. After a frame is reflowed this method will be called
2946    * informing the frame that this reflow process is complete, and telling the
2947    * frame the status returned by the Reflow member function.
2948    *
2949    * This call may be invoked many times, while NS_FRAME_IN_REFLOW is set,
2950    * before it is finally called once with a NS_FRAME_REFLOW_COMPLETE value.
2951    * When called with a NS_FRAME_REFLOW_COMPLETE value the NS_FRAME_IN_REFLOW
2952    * bit in the frame state will be cleared.
2953    *
2954    * XXX This doesn't make sense. If the frame is reflowed but not complete,
2955    * then the status should have IsIncomplete() equal to true.
2956    * XXX Don't we want the semantics to dictate that we only call this once for
2957    * a given reflow?
2958    */
2959   virtual void DidReflow(nsPresContext* aPresContext,
2960                          const ReflowInput* aReflowInput);
2961 
2962   void FinishReflowWithAbsoluteFrames(nsPresContext* aPresContext,
2963                                       ReflowOutput& aDesiredSize,
2964                                       const ReflowInput& aReflowInput,
2965                                       nsReflowStatus& aStatus,
2966                                       bool aConstrainBSize = true);
2967 
2968   /**
2969    * Updates the overflow areas of the frame. This can be called if an
2970    * overflow area of the frame's children has changed without reflowing.
2971    * @return true if either of the overflow areas for this frame have changed.
2972    */
2973   bool UpdateOverflow();
2974 
2975   /**
2976    * Computes any overflow area created by the frame itself (outside of the
2977    * frame bounds) and includes it into aOverflowAreas.
2978    *
2979    * Returns false if updating overflow isn't supported for this frame.
2980    * If the frame requires a reflow instead, then it is responsible
2981    * for scheduling one.
2982    */
2983   virtual bool ComputeCustomOverflow(mozilla::OverflowAreas& aOverflowAreas);
2984 
2985   /**
2986    * Computes any overflow area created by children of this frame and
2987    * includes it into aOverflowAreas.
2988    */
2989   virtual void UnionChildOverflow(mozilla::OverflowAreas& aOverflowAreas);
2990 
2991   // Represents zero or more physical axes.
2992   enum class PhysicalAxes : uint8_t {
2993     None = 0x0,
2994     Horizontal = 0x1,
2995     Vertical = 0x2,
2996     Both = Horizontal | Vertical,
2997   };
2998 
2999   /**
3000    * Returns true if this frame should apply overflow clipping.
3001    */
3002   PhysicalAxes ShouldApplyOverflowClipping(const nsStyleDisplay* aDisp) const;
3003 
3004   /**
3005    * Helper method used by block reflow to identify runs of text so
3006    * that proper word-breaking can be done.
3007    *
3008    * @return
3009    *    true if we can continue a "text run" through the frame. A
3010    *    text run is text that should be treated contiguously for line
3011    *    and word breaking.
3012    */
3013   virtual bool CanContinueTextRun() const;
3014 
3015   /**
3016    * Computes an approximation of the rendered text of the frame and its
3017    * continuations. Returns nothing for non-text frames.
3018    * The appended text will often not contain all the whitespace from source,
3019    * depending on CSS white-space processing.
3020    * if aEndOffset goes past end, use the text up to the string's end.
3021    * Call this on the primary frame for a text node.
3022    * aStartOffset and aEndOffset can be content offsets or offsets in the
3023    * rendered text, depending on aOffsetType.
3024    * Returns a string, as well as offsets identifying the start of the text
3025    * within the rendered text for the whole node, and within the text content
3026    * of the node.
3027    */
3028   struct RenderedText {
3029     nsAutoString mString;
3030     uint32_t mOffsetWithinNodeRenderedText;
3031     int32_t mOffsetWithinNodeText;
RenderedTextRenderedText3032     RenderedText()
3033         : mOffsetWithinNodeRenderedText(0), mOffsetWithinNodeText(0) {}
3034   };
3035   enum class TextOffsetType {
3036     // Passed-in start and end offsets are within the content text.
3037     OffsetsInContentText,
3038     // Passed-in start and end offsets are within the rendered text.
3039     OffsetsInRenderedText,
3040   };
3041   enum class TrailingWhitespace {
3042     Trim,
3043     // Spaces preceding a caret at the end of a line should not be trimmed
3044     DontTrim,
3045   };
3046   virtual RenderedText GetRenderedText(
3047       uint32_t aStartOffset = 0, uint32_t aEndOffset = UINT32_MAX,
3048       TextOffsetType aOffsetType = TextOffsetType::OffsetsInContentText,
3049       TrailingWhitespace aTrimTrailingWhitespace = TrailingWhitespace::Trim) {
3050     return RenderedText();
3051   }
3052 
3053   /**
3054    * Returns true if the frame contains any non-collapsed characters.
3055    * This method is only available for text frames, and it will return false
3056    * for all other frame types.
3057    */
HasAnyNoncollapsedCharacters()3058   virtual bool HasAnyNoncollapsedCharacters() { return false; }
3059 
3060   /**
3061    * Returns true if events of the given type targeted at this frame
3062    * should only be dispatched to the system group.
3063    */
OnlySystemGroupDispatch(mozilla::EventMessage aMessage)3064   virtual bool OnlySystemGroupDispatch(mozilla::EventMessage aMessage) const {
3065     return false;
3066   }
3067 
3068   //
3069   // Accessor functions to an associated view object:
3070   //
HasView()3071   bool HasView() const { return !!(mState & NS_FRAME_HAS_VIEW); }
3072 
3073   // Returns true iff this frame's computed block-size property is one of the
3074   // intrinsic-sizing keywords.
HasIntrinsicKeywordForBSize()3075   bool HasIntrinsicKeywordForBSize() const {
3076     const auto& bSize = StylePosition()->BSize(GetWritingMode());
3077     return bSize.IsMozFitContent() || bSize.IsMinContent() ||
3078            bSize.IsMaxContent() || bSize.IsFitContentFunction();
3079   }
3080   /**
3081    * Helper method to create a view for a frame.  Only used by a few sub-classes
3082    * that need a view.
3083    */
3084   void CreateView();
3085 
3086  protected:
GetViewInternal()3087   virtual nsView* GetViewInternal() const {
3088     MOZ_ASSERT_UNREACHABLE("method should have been overridden by subclass");
3089     return nullptr;
3090   }
SetViewInternal(nsView * aView)3091   virtual void SetViewInternal(nsView* aView) {
3092     MOZ_ASSERT_UNREACHABLE("method should have been overridden by subclass");
3093   }
3094 
3095  public:
GetView()3096   nsView* GetView() const {
3097     if (MOZ_LIKELY(!HasView())) {
3098       return nullptr;
3099     }
3100     nsView* view = GetViewInternal();
3101     MOZ_ASSERT(view, "GetViewInternal() should agree with HasView()");
3102     return view;
3103   }
3104   void SetView(nsView* aView);
3105 
3106   /**
3107    * Find the closest view (on |this| or an ancestor).
3108    * If aOffset is non-null, it will be set to the offset of |this|
3109    * from the returned view.
3110    */
3111   nsView* GetClosestView(nsPoint* aOffset = nullptr) const;
3112 
3113   /**
3114    * Find the closest ancestor (excluding |this| !) that has a view
3115    */
3116   nsIFrame* GetAncestorWithView() const;
3117 
3118   /**
3119    * Sets the view's attributes from the frame style.
3120    * Call this for nsChangeHint_SyncFrameView style changes or when the view
3121    * has just been created.
3122    * @param aView the frame's view or use GetView() if nullptr is given
3123    */
3124   void SyncFrameViewProperties(nsView* aView = nullptr);
3125 
3126   /**
3127    * Get the offset between the coordinate systems of |this| and aOther.
3128    * Adding the return value to a point in the coordinate system of |this|
3129    * will transform the point to the coordinate system of aOther.
3130    *
3131    * aOther must be non-null.
3132    *
3133    * This function is fastest when aOther is an ancestor of |this|.
3134    *
3135    * This function _DOES NOT_ work across document boundaries.
3136    * Use this function only when |this| and aOther are in the same document.
3137    *
3138    * NOTE: this actually returns the offset from aOther to |this|, but
3139    * that offset is added to transform _coordinates_ from |this| to
3140    * aOther.
3141    */
3142   nsPoint GetOffsetTo(const nsIFrame* aOther) const;
3143 
3144   /**
3145    * Just like GetOffsetTo, but treats all scrollframes as scrolled to
3146    * their origin.
3147    */
3148   nsPoint GetOffsetToIgnoringScrolling(const nsIFrame* aOther) const;
3149 
3150   /**
3151    * Get the offset between the coordinate systems of |this| and aOther
3152    * expressed in appunits per dev pixel of |this|' document. Adding the return
3153    * value to a point that is relative to the origin of |this| will make the
3154    * point relative to the origin of aOther but in the appunits per dev pixel
3155    * ratio of |this|.
3156    *
3157    * aOther must be non-null.
3158    *
3159    * This function is fastest when aOther is an ancestor of |this|.
3160    *
3161    * This function works across document boundaries.
3162    *
3163    * Because this function may cross document boundaries that have different
3164    * app units per dev pixel ratios it needs to be used very carefully.
3165    *
3166    * NOTE: this actually returns the offset from aOther to |this|, but
3167    * that offset is added to transform _coordinates_ from |this| to
3168    * aOther.
3169    */
3170   nsPoint GetOffsetToCrossDoc(const nsIFrame* aOther) const;
3171 
3172   /**
3173    * Like GetOffsetToCrossDoc, but the caller can specify which appunits
3174    * to return the result in.
3175    */
3176   nsPoint GetOffsetToCrossDoc(const nsIFrame* aOther, const int32_t aAPD) const;
3177 
3178   /**
3179    * Get the rect of the frame relative to the top-left corner of the
3180    * screen in CSS pixels.
3181    * @return the CSS pixel rect of the frame relative to the top-left
3182    *         corner of the screen.
3183    */
3184   mozilla::CSSIntRect GetScreenRect() const;
3185 
3186   /**
3187    * Get the screen rect of the frame in app units.
3188    * @return the app unit rect of the frame in screen coordinates.
3189    */
3190   nsRect GetScreenRectInAppUnits() const;
3191 
3192   /**
3193    * Returns the offset from this frame to the closest geometric parent that
3194    * has a view. Also returns the containing view or null in case of error
3195    */
3196   void GetOffsetFromView(nsPoint& aOffset, nsView** aView) const;
3197 
3198   /**
3199    * Returns the nearest widget containing this frame. If this frame has a
3200    * view and the view has a widget, then this frame's widget is
3201    * returned, otherwise this frame's geometric parent is checked
3202    * recursively upwards.
3203    */
3204   nsIWidget* GetNearestWidget() const;
3205 
3206   /**
3207    * Same as GetNearestWidget() above but uses an outparam to return the offset
3208    * of this frame to the returned widget expressed in appunits of |this| (the
3209    * widget might be in a different document with a different zoom).
3210    */
3211   nsIWidget* GetNearestWidget(nsPoint& aOffset) const;
3212 
3213   /**
3214    * Whether the content for this frame is disabled, used for event handling.
3215    */
3216   bool IsContentDisabled() const;
3217 
3218   /**
3219    * Get the "type" of the frame.
3220    *
3221    * @see mozilla::LayoutFrameType
3222    */
Type()3223   mozilla::LayoutFrameType Type() const {
3224     MOZ_ASSERT(uint8_t(mClass) < mozilla::ArrayLength(sLayoutFrameTypes));
3225     return sLayoutFrameTypes[uint8_t(mClass)];
3226   }
3227 
3228 #ifdef __GNUC__
3229 #  pragma GCC diagnostic push
3230 #  pragma GCC diagnostic ignored "-Wtype-limits"
3231 #endif
3232 #ifdef __clang__
3233 #  pragma clang diagnostic push
3234 #  pragma clang diagnostic ignored "-Wunknown-pragmas"
3235 #  pragma clang diagnostic ignored "-Wtautological-unsigned-zero-compare"
3236 #endif
3237 
3238 #define FRAME_TYPE(name_, first_class_, last_class_)                 \
3239   bool Is##name_##Frame() const {                                    \
3240     return uint8_t(mClass) >= uint8_t(ClassID::first_class_##_id) && \
3241            uint8_t(mClass) <= uint8_t(ClassID::last_class_##_id);    \
3242   }
3243 #include "mozilla/FrameTypeList.h"
3244 #undef FRAME_TYPE
3245 
3246 #ifdef __GNUC__
3247 #  pragma GCC diagnostic pop
3248 #endif
3249 #ifdef __clang__
3250 #  pragma clang diagnostic pop
3251 #endif
3252 
3253   /**
3254    * Returns a transformation matrix that converts points in this frame's
3255    * coordinate space to points in some ancestor frame's coordinate space.
3256    * The frame decides which ancestor it will use as a reference point.
3257    * If this frame has no ancestor, aOutAncestor will be set to null.
3258    *
3259    * @param aViewportType specifies whether the starting point is layout
3260    *   or visual coordinates
3261    * @param aStopAtAncestor don't look further than aStopAtAncestor. If null,
3262    *   all ancestors (including across documents) will be traversed.
3263    * @param aOutAncestor [out] The ancestor frame the frame has chosen.  If
3264    *   this frame has no ancestor, *aOutAncestor will be set to null. If
3265    * this frame is not a root frame, then *aOutAncestor will be in the same
3266    * document as this frame. If this frame IsTransformed(), then *aOutAncestor
3267    * will be the parent frame (if not preserve-3d) or the nearest
3268    * non-transformed ancestor (if preserve-3d).
3269    * @return A Matrix4x4 that converts points in the coordinate space
3270    *   RelativeTo{this, aViewportType} into points in aOutAncestor's
3271    *   coordinate space.
3272    */
3273   enum {
3274     IN_CSS_UNITS = 1 << 0,
3275     STOP_AT_STACKING_CONTEXT_AND_DISPLAY_PORT = 1 << 1
3276   };
3277   Matrix4x4Flagged GetTransformMatrix(mozilla::ViewportType aViewportType,
3278                                       mozilla::RelativeTo aStopAtAncestor,
3279                                       nsIFrame** aOutAncestor,
3280                                       uint32_t aFlags = 0) const;
3281 
3282   /**
3283    * Bit-flags to pass to IsFrameOfType()
3284    */
3285   enum {
3286     eMathML = 1 << 0,
3287     eSVG = 1 << 1,
3288     eSVGContainer = 1 << 2,
3289     eBidiInlineContainer = 1 << 3,
3290     // the frame is for a replaced element, such as an image
3291     eReplaced = 1 << 4,
3292     // Frame that contains a block but looks like a replaced element
3293     // from the outside
3294     eReplacedContainsBlock = 1 << 5,
3295     // A frame that participates in inline reflow, i.e., one that
3296     // requires ReflowInput::mLineLayout.
3297     eLineParticipant = 1 << 6,
3298     eXULBox = 1 << 7,
3299     eCanContainOverflowContainers = 1 << 8,
3300     eTablePart = 1 << 9,
3301     eSupportsCSSTransforms = 1 << 10,
3302 
3303     // A replaced element that has replaced-element sizing
3304     // characteristics (i.e., like images or iframes), as opposed to
3305     // inline-block sizing characteristics (like form controls).
3306     eReplacedSizing = 1 << 11,
3307 
3308     // Does this frame class support 'contain: layout' and
3309     // 'contain:paint' (supporting one is equivalent to supporting the
3310     // other).
3311     eSupportsContainLayoutAndPaint = 1 << 12,
3312 
3313     // Does this frame class support `aspect-ratio` property.
3314     eSupportsAspectRatio = 1 << 13,
3315 
3316     // These are to allow nsIFrame::Init to assert that IsFrameOfType
3317     // implementations all call the base class method.  They are only
3318     // meaningful in DEBUG builds.
3319     eDEBUGAllFrames = 1 << 30,
3320     eDEBUGNoFrames = 1 << 31
3321   };
3322 
3323   /**
3324    * API for doing a quick check if a frame is of a given
3325    * type. Returns true if the frame matches ALL flags passed in.
3326    *
3327    * Implementations should always override with inline virtual
3328    * functions that call the base class's IsFrameOfType method.
3329    */
IsFrameOfType(uint32_t aFlags)3330   virtual bool IsFrameOfType(uint32_t aFlags) const {
3331     return !(aFlags & ~(
3332 #ifdef DEBUG
3333                           nsIFrame::eDEBUGAllFrames |
3334 #endif
3335                           nsIFrame::eSupportsCSSTransforms |
3336                           nsIFrame::eSupportsContainLayoutAndPaint |
3337                           nsIFrame::eSupportsAspectRatio));
3338   }
3339 
3340   /**
3341    * Return true if this frame's preferred size property or max size property
3342    * contains a percentage value that should be resolved against zero when
3343    * calculating its min-content contribution in the corresponding axis.
3344    *
3345    * This is a special case for webcompat required by CSS Sizing 3 §5.2.1c
3346    * https://drafts.csswg.org/css-sizing-3/#replaced-percentage-min-contribution,
3347    * and applies only to some replaced elements and form control elements. See
3348    * CSS Sizing 3 §5.2.2 for the list of elements this rule applies to.
3349    * https://drafts.csswg.org/css-sizing-3/#min-content-zero
3350    *
3351    * Bug 1463700: some callers may not match the spec by resolving the entire
3352    * preferred size property or max size property against zero.
3353    */
3354   bool IsPercentageResolvedAgainstZero(
3355       const mozilla::StyleSize& aStyleSize,
3356       const mozilla::StyleMaxSize& aStyleMaxSize) const;
3357 
3358   // Type of preferred size/min size/max size.
3359   enum class SizeProperty { Size, MinSize, MaxSize };
3360   /**
3361    * This is simliar to the above method but accepts LengthPercentage. Return
3362    * true if the frame's preferred size property or max size property contains
3363    * a percentage value that should be resolved against zero. For min size, it
3364    * always returns true.
3365    */
3366   bool IsPercentageResolvedAgainstZero(const mozilla::LengthPercentage& aSize,
3367                                        SizeProperty aProperty) const;
3368 
3369   /**
3370    * Returns true if the frame is a block wrapper.
3371    */
3372   bool IsBlockWrapper() const;
3373 
3374   /**
3375    * Returns true if the frame is an instance of nsBlockFrame or one of its
3376    * subclasses.
3377    */
3378   bool IsBlockFrameOrSubclass() const;
3379 
3380   /**
3381    * Returns true if the frame is an instance of SVGGeometryFrame or one
3382    * of its subclasses.
3383    */
3384   inline bool IsSVGGeometryFrameOrSubclass() const;
3385 
3386   /**
3387    * Get this frame's CSS containing block.
3388    *
3389    * The algorithm is defined in
3390    * http://www.w3.org/TR/CSS2/visudet.html#containing-block-details.
3391    *
3392    * NOTE: This is guaranteed to return a non-null pointer when invoked on any
3393    * frame other than the root frame.
3394    *
3395    * Requires SKIP_SCROLLED_FRAME to get behaviour matching the spec, otherwise
3396    * it can return anonymous inner scrolled frames. Bug 1204044 is filed for
3397    * investigating whether any of the callers actually require the default
3398    * behaviour.
3399    */
3400   enum {
3401     // If the containing block is an anonymous scrolled frame, then skip over
3402     // this and return the outer scroll frame.
3403     SKIP_SCROLLED_FRAME = 0x01
3404   };
3405   nsIFrame* GetContainingBlock(uint32_t aFlags,
3406                                const nsStyleDisplay* aStyleDisplay) const;
3407   nsIFrame* GetContainingBlock(uint32_t aFlags = 0) const {
3408     return GetContainingBlock(aFlags, StyleDisplay());
3409   }
3410 
3411   /**
3412    * Is this frame a containing block for floating elements?
3413    * Note that very few frames are, so default to false.
3414    */
IsFloatContainingBlock()3415   virtual bool IsFloatContainingBlock() const { return false; }
3416 
3417   /**
3418    * Is this a leaf frame?  Frames that want the frame constructor to be able
3419    * to construct kids for them should return false, all others should return
3420    * true.  Note that returning true here does not mean that the frame _can't_
3421    * have kids.  It could still have kids created via
3422    * nsIAnonymousContentCreator.  Returning true indicates that "normal"
3423    * (non-anonymous, CSS generated content, etc) children should not be
3424    * constructed.
3425    */
IsLeaf()3426   bool IsLeaf() const {
3427     MOZ_ASSERT(uint8_t(mClass) < mozilla::ArrayLength(sFrameClassBits));
3428     FrameClassBits bits = sFrameClassBits[uint8_t(mClass)];
3429     if (MOZ_UNLIKELY(bits & eFrameClassBitsDynamicLeaf)) {
3430       return IsLeafDynamic();
3431     }
3432     return bits & eFrameClassBitsLeaf;
3433   }
3434 
3435   /**
3436    * Marks all display items created by this frame as needing a repaint,
3437    * and calls SchedulePaint() if requested and one is not already pending.
3438    *
3439    * This includes all display items created by this frame, including
3440    * container types.
3441    *
3442    * @param aDisplayItemKey If specified, only issues an invalidate
3443    * if this frame painted a display item of that type during the
3444    * previous paint. SVG rendering observers are always notified.
3445    * @param aRebuildDisplayItems If true, then adds this frame to the
3446    * list of modified frames for display list building. Only pass false
3447    * if you're sure that the relevant display items will be rebuilt
3448    * already (possibly by an ancestor being in the modified list).
3449    */
3450   virtual void InvalidateFrame(uint32_t aDisplayItemKey = 0,
3451                                bool aRebuildDisplayItems = true);
3452 
3453   /**
3454    * Same as InvalidateFrame(), but only mark a fixed rect as needing
3455    * repainting.
3456    *
3457    * @param aRect The rect to invalidate, relative to the TopLeft of the
3458    * frame's border box.
3459    * @param aDisplayItemKey If specified, only issues an invalidate
3460    * if this frame painted a display item of that type during the
3461    * previous paint. SVG rendering observers are always notified.
3462    * @param aRebuildDisplayItems If true, then adds this frame to the
3463    * list of modified frames for display list building. Only pass false
3464    * if you're sure that the relevant display items will be rebuilt
3465    * already (possibly by an ancestor being in the modified list).
3466    */
3467   virtual void InvalidateFrameWithRect(const nsRect& aRect,
3468                                        uint32_t aDisplayItemKey = 0,
3469                                        bool aRebuildDisplayItems = true);
3470 
3471   /**
3472    * Calls InvalidateFrame() on all frames descendant frames (including
3473    * this one).
3474    *
3475    * This function doesn't walk through placeholder frames to invalidate
3476    * the out-of-flow frames.
3477    *
3478    * @param aRebuildDisplayItems If true, then adds this frame to the
3479    * list of modified frames for display list building. Only pass false
3480    * if you're sure that the relevant display items will be rebuilt
3481    * already (possibly by an ancestor being in the modified list).
3482    */
3483   void InvalidateFrameSubtree(bool aRebuildDisplayItems = true);
3484 
3485   /**
3486    * Called when a frame is about to be removed and needs to be invalidated.
3487    * Normally does nothing since DLBI handles removed frames.
3488    */
InvalidateFrameForRemoval()3489   virtual void InvalidateFrameForRemoval() {}
3490 
3491   /**
3492    * When HasUserData(frame->LayerIsPrerenderedDataKey()), then the
3493    * entire overflow area of this frame has been rendered in its
3494    * layer(s).
3495    */
LayerIsPrerenderedDataKey()3496   static void* LayerIsPrerenderedDataKey() {
3497     return &sLayerIsPrerenderedDataKey;
3498   }
3499   static uint8_t sLayerIsPrerenderedDataKey;
3500 
3501   /**
3502    * Try to update this frame's transform without invalidating any
3503    * content.  Return true iff successful.  If unsuccessful, the
3504    * caller is responsible for scheduling an invalidating paint.
3505    *
3506    * If the result is true, aLayerResult will be filled in with the
3507    * transform layer for the frame.
3508    */
3509   bool TryUpdateTransformOnly(Layer** aLayerResult);
3510 
3511   /**
3512    * Checks if a frame has had InvalidateFrame() called on it since the
3513    * last paint.
3514    *
3515    * If true, then the invalid rect is returned in aRect, with an
3516    * empty rect meaning all pixels drawn by this frame should be
3517    * invalidated.
3518    * If false, aRect is left unchanged.
3519    */
3520   bool IsInvalid(nsRect& aRect);
3521 
3522   /**
3523    * Check if any frame within the frame subtree (including this frame)
3524    * returns true for IsInvalid().
3525    */
HasInvalidFrameInSubtree()3526   bool HasInvalidFrameInSubtree() {
3527     return HasAnyStateBits(NS_FRAME_NEEDS_PAINT |
3528                            NS_FRAME_DESCENDANT_NEEDS_PAINT);
3529   }
3530 
3531   /**
3532    * Removes the invalid state from the current frame and all
3533    * descendant frames.
3534    */
3535   void ClearInvalidationStateBits();
3536 
3537   /**
3538    * Ensures that the refresh driver is running, and schedules a view
3539    * manager flush on the next tick.
3540    *
3541    * The view manager flush will update the layer tree, repaint any
3542    * invalid areas in the layer tree and schedule a layer tree
3543    * composite operation to display the layer tree.
3544    *
3545    * In general it is not necessary for frames to call this when they change.
3546    * For example, changes that result in a reflow will have this called for
3547    * them by PresContext::DoReflow when the reflow begins. Style changes that
3548    * do not trigger a reflow should have this called for them by
3549    * DoApplyRenderingChangeToTree.
3550    *
3551    * @param aType PAINT_COMPOSITE_ONLY : No changes have been made
3552    * that require a layer tree update, so only schedule a layer
3553    * tree composite.
3554    * PAINT_DELAYED_COMPRESS : Schedule a paint to be executed after a delay, and
3555    * put FrameLayerBuilder in 'compressed' mode that avoids short cut
3556    * optimizations.
3557    */
3558   enum PaintType {
3559     PAINT_DEFAULT = 0,
3560     PAINT_COMPOSITE_ONLY,
3561     PAINT_DELAYED_COMPRESS
3562   };
3563   void SchedulePaint(PaintType aType = PAINT_DEFAULT,
3564                      bool aFrameChanged = true);
3565 
3566   // Similar to SchedulePaint() but without calling
3567   // InvalidateRenderingObservers() for SVG.
3568   void SchedulePaintWithoutInvalidatingObservers(
3569       PaintType aType = PAINT_DEFAULT);
3570 
3571   /**
3572    * Checks if the layer tree includes a dedicated layer for this
3573    * frame/display item key pair, and invalidates at least aDamageRect
3574    * area within that layer.
3575    *
3576    * If no layer is found, calls InvalidateFrame() instead.
3577    *
3578    * @param aDamageRect Area of the layer to invalidate.
3579    * @param aFrameDamageRect If no layer is found, the area of the frame to
3580    *                         invalidate. If null, the entire frame will be
3581    *                         invalidated.
3582    * @param aDisplayItemKey Display item type.
3583    * @param aFlags UPDATE_IS_ASYNC : Will skip the invalidation
3584    * if the found layer is being composited by a remote
3585    * compositor.
3586    * @return Layer, if found, nullptr otherwise.
3587    */
3588   enum { UPDATE_IS_ASYNC = 1 << 0 };
3589   Layer* InvalidateLayer(DisplayItemType aDisplayItemKey,
3590                          const nsIntRect* aDamageRect = nullptr,
3591                          const nsRect* aFrameDamageRect = nullptr,
3592                          uint32_t aFlags = 0);
3593 
3594   void MarkNeedsDisplayItemRebuild();
3595 
3596   /**
3597    * Returns a rect that encompasses everything that might be painted by
3598    * this frame.  This includes this frame, all its descendant frames, this
3599    * frame's outline, and descendant frames' outline, but does not include
3600    * areas clipped out by the CSS "overflow" and "clip" properties.
3601    *
3602    * HasOverflowAreas() (below) will return true when this overflow
3603    * rect has been explicitly set, even if it matches mRect.
3604    * XXX Note: because of a space optimization using the formula above,
3605    * during reflow this function does not give accurate data if
3606    * FinishAndStoreOverflow has been called but mRect hasn't yet been
3607    * updated yet.  FIXME: This actually isn't true, but it should be.
3608    *
3609    * The ink overflow rect should NEVER be used for things that
3610    * affect layout.  The scrollable overflow rect is permitted to affect
3611    * layout.
3612    *
3613    * @return the rect relative to this frame's origin, but after
3614    * CSS transforms have been applied (i.e. not really this frame's coordinate
3615    * system, and may not contain the frame's border-box, e.g. if there
3616    * is a CSS transform scaling it down)
3617    */
InkOverflowRect()3618   nsRect InkOverflowRect() const {
3619     return GetOverflowRect(mozilla::OverflowType::Ink);
3620   }
3621 
3622   /**
3623    * Returns a rect that encompasses the area of this frame that the
3624    * user should be able to scroll to reach.  This is similar to
3625    * InkOverflowRect, but does not include outline or shadows, and
3626    * may in the future include more margins than ink overflow does.
3627    * It does not include areas clipped out by the CSS "overflow" and
3628    * "clip" properties.
3629    *
3630    * HasOverflowAreas() (below) will return true when this overflow
3631    * rect has been explicitly set, even if it matches mRect.
3632    * XXX Note: because of a space optimization using the formula above,
3633    * during reflow this function does not give accurate data if
3634    * FinishAndStoreOverflow has been called but mRect hasn't yet been
3635    * updated yet.
3636    *
3637    * @return the rect relative to this frame's origin, but after
3638    * CSS transforms have been applied (i.e. not really this frame's coordinate
3639    * system, and may not contain the frame's border-box, e.g. if there
3640    * is a CSS transform scaling it down)
3641    */
ScrollableOverflowRect()3642   nsRect ScrollableOverflowRect() const {
3643     return GetOverflowRect(mozilla::OverflowType::Scrollable);
3644   }
3645 
3646   nsRect GetOverflowRect(mozilla::OverflowType aType) const;
3647 
3648   mozilla::OverflowAreas GetOverflowAreas() const;
3649 
3650   /**
3651    * Same as GetOverflowAreas, except in this frame's coordinate
3652    * system (before transforms are applied).
3653    *
3654    * @return the overflow areas relative to this frame, before any CSS
3655    * transforms have been applied, i.e. in this frame's coordinate system
3656    */
3657   mozilla::OverflowAreas GetOverflowAreasRelativeToSelf() const;
3658 
3659   /**
3660    * Same as GetOverflowAreas, except relative to the parent frame.
3661    *
3662    * @return the overflow area relative to the parent frame, in the parent
3663    * frame's coordinate system
3664    */
3665   mozilla::OverflowAreas GetOverflowAreasRelativeToParent() const;
3666 
3667   /**
3668    * Same as ScrollableOverflowRect, except relative to the parent
3669    * frame.
3670    *
3671    * @return the rect relative to the parent frame, in the parent frame's
3672    * coordinate system
3673    */
3674   nsRect ScrollableOverflowRectRelativeToParent() const;
3675 
3676   /**
3677    * Same as ScrollableOverflowRect, except in this frame's coordinate
3678    * system (before transforms are applied).
3679    *
3680    * @return the rect relative to this frame, before any CSS transforms have
3681    * been applied, i.e. in this frame's coordinate system
3682    */
3683   nsRect ScrollableOverflowRectRelativeToSelf() const;
3684 
3685   /**
3686    * Like InkOverflowRect, except in this frame's
3687    * coordinate system (before transforms are applied).
3688    *
3689    * @return the rect relative to this frame, before any CSS transforms have
3690    * been applied, i.e. in this frame's coordinate system
3691    */
3692   nsRect InkOverflowRectRelativeToSelf() const;
3693 
3694   /**
3695    * Same as InkOverflowRect, except relative to the parent
3696    * frame.
3697    *
3698    * @return the rect relative to the parent frame, in the parent frame's
3699    * coordinate system
3700    */
3701   nsRect InkOverflowRectRelativeToParent() const;
3702 
3703   /**
3704    * Returns this frame's ink overflow rect as it would be before taking
3705    * account of SVG effects or transforms. The rect returned is relative to
3706    * this frame.
3707    */
3708   nsRect PreEffectsInkOverflowRect() const;
3709 
3710   /**
3711    * Store the overflow area in the frame's mOverflow.mInkOverflowDeltas
3712    * fields or as a frame property in OverflowAreasProperty() so that it can
3713    * be retrieved later without reflowing the frame. Returns true if either of
3714    * the overflow areas changed.
3715    */
3716   bool FinishAndStoreOverflow(mozilla::OverflowAreas& aOverflowAreas,
3717                               nsSize aNewSize, nsSize* aOldSize = nullptr,
3718                               const nsStyleDisplay* aStyleDisplay = nullptr);
3719 
3720   bool FinishAndStoreOverflow(ReflowOutput* aMetrics,
3721                               const nsStyleDisplay* aStyleDisplay = nullptr) {
3722     return FinishAndStoreOverflow(aMetrics->mOverflowAreas,
3723                                   nsSize(aMetrics->Width(), aMetrics->Height()),
3724                                   nullptr, aStyleDisplay);
3725   }
3726 
3727   /**
3728    * Returns whether the frame has an overflow rect that is different from
3729    * its border-box.
3730    */
HasOverflowAreas()3731   bool HasOverflowAreas() const {
3732     return mOverflow.mType != OverflowStorageType::None;
3733   }
3734 
3735   /**
3736    * Removes any stored overflow rects (visual and scrollable) from the frame.
3737    * Returns true if the overflow changed.
3738    */
3739   bool ClearOverflowRects();
3740 
3741   /**
3742    * Determine whether borders, padding, margins etc should NOT be applied
3743    * on certain sides of the frame.
3744    * @see mozilla::Sides in gfx/2d/BaseMargin.h
3745    * @see mozilla::LogicalSides in layout/generic/WritingModes.h
3746    *
3747    * @note (See also bug 743402, comment 11) GetSkipSides() checks to see
3748    *       if this frame has a previous or next continuation to determine
3749    *       if a side should be skipped.
3750    *       So this only works after the entire frame tree has been reflowed.
3751    *       During reflow, if this frame can be split in the block axis, you
3752    *       should use nsSplittableFrame::PreReflowBlockLevelLogicalSkipSides().
3753    */
3754   Sides GetSkipSides() const;
GetLogicalSkipSides()3755   virtual LogicalSides GetLogicalSkipSides() const {
3756     return LogicalSides(mWritingMode);
3757   }
3758 
3759   /**
3760    * @returns true if this frame is selected.
3761    */
IsSelected()3762   bool IsSelected() const {
3763     return (GetContent() && GetContent()->IsMaybeSelected()) ? IsFrameSelected()
3764                                                              : false;
3765   }
3766 
3767   /**
3768    * Shouldn't be called if this is a `nsTextFrame`. Call the
3769    * `nsTextFrame::SelectionStateChanged` overload instead.
3770    */
SelectionStateChanged()3771   void SelectionStateChanged() {
3772     MOZ_ASSERT(!IsTextFrame());
3773     InvalidateFrameSubtree();  // TODO: should this deal with continuations?
3774   }
3775 
3776   /**
3777    * Called to discover where this frame, or a parent frame has user-select
3778    * style applied, which affects that way that it is selected.
3779    *
3780    * @param aSelectStyle out param. Returns the type of selection style found
3781    * (using values defined in nsStyleConsts.h).
3782    *
3783    * @return Whether the frame can be selected (i.e. is not affected by
3784    * user-select: none)
3785    */
3786   bool IsSelectable(mozilla::StyleUserSelect* aSelectStyle) const;
3787 
3788   /**
3789    * Returns whether this frame should have the content-block-size of a line,
3790    * even if empty.
3791    */
3792   bool ShouldHaveLineIfEmpty() const;
3793 
3794   /**
3795    * Called to retrieve the SelectionController associated with the frame.
3796    *
3797    * @param aSelCon will contain the selection controller associated with
3798    * the frame.
3799    */
3800   nsresult GetSelectionController(nsPresContext* aPresContext,
3801                                   nsISelectionController** aSelCon);
3802 
3803   /**
3804    * Call to get nsFrameSelection for this frame.
3805    */
3806   already_AddRefed<nsFrameSelection> GetFrameSelection();
3807 
3808   /**
3809    * GetConstFrameSelection returns an object which methods are safe to use for
3810    * example in nsIFrame code.
3811    */
3812   const nsFrameSelection* GetConstFrameSelection() const;
3813 
3814   /**
3815    * called to find the previous/next character, word, or line. Returns the
3816    * actual nsIFrame and the frame offset. THIS DOES NOT CHANGE SELECTION STATE.
3817    * Uses frame's begin selection state to start. If no selection on this frame
3818    * will return NS_ERROR_FAILURE.
3819    *
3820    * @param aPos is defined in nsFrameSelection
3821    */
3822   virtual nsresult PeekOffset(nsPeekOffsetStruct* aPos);
3823 
3824  private:
3825   nsresult PeekOffsetForCharacter(nsPeekOffsetStruct* aPos, int32_t aOffset);
3826   nsresult PeekOffsetForWord(nsPeekOffsetStruct* aPos, int32_t aOffset);
3827   nsresult PeekOffsetForLine(nsPeekOffsetStruct* aPos);
3828   nsresult PeekOffsetForLineEdge(nsPeekOffsetStruct* aPos);
3829 
3830   /**
3831    * Search for the first paragraph boundary before or after the given position
3832    * @param  aPos See description in nsFrameSelection.h. The following fields
3833    *              are used by this method:
3834    *              Input: mDirection
3835    *              Output: mResultContent, mContentOffset
3836    */
3837   nsresult PeekOffsetForParagraph(nsPeekOffsetStruct* aPos);
3838 
3839  public:
3840   // given a frame five me the first/last leaf available
3841   // XXX Robert O'Callahan wants to move these elsewhere
3842   static void GetLastLeaf(nsIFrame** aFrame);
3843   static void GetFirstLeaf(nsIFrame** aFrame);
3844 
3845   static nsresult GetNextPrevLineFromeBlockFrame(nsPresContext* aPresContext,
3846                                                  nsPeekOffsetStruct* aPos,
3847                                                  nsIFrame* aBlockFrame,
3848                                                  int32_t aLineStart,
3849                                                  int8_t aOutSideLimit);
3850 
3851   struct SelectablePeekReport {
3852     /** the previous/next selectable leaf frame */
3853     nsIFrame* mFrame = nullptr;
3854     /**
3855      * 0 indicates that we arrived at the beginning of the output frame; -1
3856      * indicates that we arrived at its end.
3857      */
3858     int32_t mOffset = 0;
3859     /** whether the input frame and the returned frame are on different lines */
3860     bool mJumpedLine = false;
3861     /** whether we met a hard break between the input and the returned frame */
3862     bool mJumpedHardBreak = false;
3863     /** whether we jumped over a non-selectable frame during the search */
3864     bool mMovedOverNonSelectableText = false;
3865     /** whether we met selectable text frame that isn't editable during the
3866      *  search */
3867     bool mHasSelectableFrame = false;
3868     /** whether we ignored a br frame */
3869     bool mIgnoredBrFrame = false;
3870 
PeekOffsetNoAmountSelectablePeekReport3871     FrameSearchResult PeekOffsetNoAmount(bool aForward) {
3872       return mFrame->PeekOffsetNoAmount(aForward, &mOffset);
3873     }
PeekOffsetCharacterSelectablePeekReport3874     FrameSearchResult PeekOffsetCharacter(bool aForward,
3875                                           PeekOffsetCharacterOptions aOptions) {
3876       return mFrame->PeekOffsetCharacter(aForward, &mOffset, aOptions);
3877     };
3878 
3879     /** Transfers frame and offset info for PeekOffset() result */
3880     void TransferTo(nsPeekOffsetStruct& aPos) const;
FailedSelectablePeekReport3881     bool Failed() { return !mFrame; }
3882 
3883     explicit SelectablePeekReport(nsIFrame* aFrame = nullptr,
3884                                   int32_t aOffset = 0)
mFrameSelectablePeekReport3885         : mFrame(aFrame), mOffset(aOffset) {}
3886     MOZ_IMPLICIT SelectablePeekReport(
3887         const mozilla::GenericErrorResult<nsresult>&& aErr);
3888   };
3889 
3890   /**
3891    * Called to find the previous/next non-anonymous selectable leaf frame.
3892    *
3893    * @param aDirection the direction to move in (eDirPrevious or eDirNext)
3894    * @param aVisual whether bidi caret behavior is visual (true) or logical
3895    * (false)
3896    * @param aJumpLines whether to allow jumping across line boundaries
3897    * @param aScrollViewStop whether to stop when reaching a scroll frame
3898    * boundary
3899    */
3900   SelectablePeekReport GetFrameFromDirection(nsDirection aDirection,
3901                                              bool aVisual, bool aJumpLines,
3902                                              bool aScrollViewStop,
3903                                              bool aForceEditableRegion);
3904 
3905   SelectablePeekReport GetFrameFromDirection(const nsPeekOffsetStruct& aPos);
3906 
3907  private:
3908   Result<bool, nsresult> IsVisuallyAtLineEdge(nsILineIterator* aLineIterator,
3909                                               int32_t aLine,
3910                                               nsDirection aDirection);
3911   Result<bool, nsresult> IsLogicallyAtLineEdge(nsILineIterator* aLineIterator,
3912                                                int32_t aLine,
3913                                                nsDirection aDirection);
3914 
3915   // Return the line number of the aFrame, and (optionally) the containing block
3916   // frame.
3917   // If aScrollLock is true, don't break outside scrollframes when looking for a
3918   // containing block frame.
3919   Result<int32_t, nsresult> GetLineNumber(
3920       bool aLockScroll, nsIFrame** aContainingBlock = nullptr);
3921 
3922  public:
3923   /**
3924    * Called to see if the children of the frame are visible from indexstart to
3925    * index end. This does not change any state. Returns true only if the indexes
3926    * are valid and any of the children are visible. For textframes this index
3927    * is the character index. If aStart = aEnd result will be false.
3928    *
3929    * @param aStart start index of first child from 0-N (number of children)
3930    *
3931    * @param aEnd end index of last child from 0-N
3932    *
3933    * @param aRecurse should this frame talk to siblings to get to the contents
3934    * other children?
3935    *
3936    * @param aFinished did this frame have the aEndIndex? or is there more work
3937    * to do
3938    *
3939    * @param _retval return value true or false. false = range is not rendered.
3940    */
3941   virtual nsresult CheckVisibility(nsPresContext* aContext, int32_t aStartIndex,
3942                                    int32_t aEndIndex, bool aRecurse,
3943                                    bool* aFinished, bool* _retval);
3944 
3945   /**
3946    * Called to tell a frame that one of its child frames is dirty (i.e.,
3947    * has the NS_FRAME_IS_DIRTY *or* NS_FRAME_HAS_DIRTY_CHILDREN bit
3948    * set).  This should always set the NS_FRAME_HAS_DIRTY_CHILDREN on
3949    * the frame, and may do other work.
3950    */
3951   virtual void ChildIsDirty(nsIFrame* aChild);
3952 
3953   /**
3954    * Called to retrieve this frame's accessible.
3955    * If this frame implements Accessibility return a valid accessible
3956    * If not return NS_ERROR_NOT_IMPLEMENTED.
3957    * Note: LocalAccessible must be refcountable. Do not implement directly on
3958    * your frame Use a mediatior of some kind.
3959    */
3960 #ifdef ACCESSIBILITY
3961   virtual mozilla::a11y::AccType AccessibleType();
3962 #endif
3963 
3964   /**
3965    * Get the frame whose style should be the parent of this frame's style (i.e.,
3966    * provide the parent style).
3967    *
3968    * This frame must either be an ancestor of this frame or a child.  If
3969    * this returns a child frame, then the child frame must be sure to
3970    * return a grandparent or higher!  Furthermore, if a child frame is
3971    * returned it must have the same GetContent() as this frame.
3972    *
3973    * @param aProviderFrame (out) the frame associated with the returned value
3974    *     or nullptr if the style is for display:contents content.
3975    * @return The style that should be the parent of this frame's style. Null is
3976    *         permitted, and means that this frame's style should be the root of
3977    *         the style tree.
3978    */
GetParentComputedStyle(nsIFrame ** aProviderFrame)3979   virtual ComputedStyle* GetParentComputedStyle(
3980       nsIFrame** aProviderFrame) const {
3981     return DoGetParentComputedStyle(aProviderFrame);
3982   }
3983 
3984   /**
3985    * Do the work for getting the parent ComputedStyle frame so that
3986    * other frame's |GetParentComputedStyle| methods can call this
3987    * method on *another* frame.  (This function handles out-of-flow
3988    * frames by using the frame manager's placeholder map and it also
3989    * handles block-within-inline and generated content wrappers.)
3990    *
3991    * @param aProviderFrame (out) the frame associated with the returned value
3992    *   or null if the ComputedStyle is for display:contents content.
3993    * @return The ComputedStyle that should be the parent of this frame's
3994    *   ComputedStyle.  Null is permitted, and means that this frame's
3995    *   ComputedStyle should be the root of the ComputedStyle tree.
3996    */
3997   ComputedStyle* DoGetParentComputedStyle(nsIFrame** aProviderFrame) const;
3998 
3999   /**
4000    * Adjust the given parent frame to the right ComputedStyle parent frame for
4001    * the child, given the pseudo-type of the prospective child.  This handles
4002    * things like walking out of table pseudos and so forth.
4003    *
4004    * @param aProspectiveParent what GetParent() on the child returns.
4005    *                           Must not be null.
4006    * @param aChildPseudo the child's pseudo type, if any.
4007    */
4008   static nsIFrame* CorrectStyleParentFrame(
4009       nsIFrame* aProspectiveParent, mozilla::PseudoStyleType aChildPseudo);
4010 
4011   /**
4012    * Called by RestyleManager to update the style of anonymous boxes
4013    * directly associated with this frame.
4014    *
4015    * The passed-in ServoRestyleState can be used to create new ComputedStyles as
4016    * needed, as well as posting changes to the change list.
4017    *
4018    * It's guaranteed to already have a change in it for this frame and this
4019    * frame's content.
4020    *
4021    * This function will be called after this frame's style has already been
4022    * updated.  This function will only be called on frames which have the
4023    * NS_FRAME_OWNS_ANON_BOXES bit set.
4024    */
UpdateStyleOfOwnedAnonBoxes(mozilla::ServoRestyleState & aRestyleState)4025   void UpdateStyleOfOwnedAnonBoxes(mozilla::ServoRestyleState& aRestyleState) {
4026     if (HasAnyStateBits(NS_FRAME_OWNS_ANON_BOXES)) {
4027       DoUpdateStyleOfOwnedAnonBoxes(aRestyleState);
4028     }
4029   }
4030 
4031  protected:
4032   // This does the actual work of UpdateStyleOfOwnedAnonBoxes.  It calls
4033   // AppendDirectlyOwnedAnonBoxes to find all of the anonymous boxes
4034   // owned by this frame, and then updates styles on each of them.
4035   void DoUpdateStyleOfOwnedAnonBoxes(mozilla::ServoRestyleState& aRestyleState);
4036 
4037   // A helper for DoUpdateStyleOfOwnedAnonBoxes for the specific case
4038   // of the owned anon box being a child of this frame.
4039   void UpdateStyleOfChildAnonBox(nsIFrame* aChildFrame,
4040                                  mozilla::ServoRestyleState& aRestyleState);
4041 
4042   // Allow ServoRestyleState to call UpdateStyleOfChildAnonBox.
4043   friend class mozilla::ServoRestyleState;
4044 
4045  public:
4046   // A helper both for UpdateStyleOfChildAnonBox, and to update frame-backed
4047   // pseudo-elements in RestyleManager.
4048   //
4049   // This gets a ComputedStyle that will be the new style for `aChildFrame`, and
4050   // takes care of updating it, calling CalcStyleDifference, and adding to the
4051   // change list as appropriate.
4052   //
4053   // If aContinuationComputedStyle is not Nothing, it should be used for
4054   // continuations instead of aNewComputedStyle.  In either case, changehints
4055   // are only computed based on aNewComputedStyle.
4056   //
4057   // Returns the generated change hint for the frame.
4058   static nsChangeHint UpdateStyleOfOwnedChildFrame(
4059       nsIFrame* aChildFrame, ComputedStyle* aNewComputedStyle,
4060       mozilla::ServoRestyleState& aRestyleState,
4061       const Maybe<ComputedStyle*>& aContinuationComputedStyle = Nothing());
4062 
4063   struct OwnedAnonBox {
4064     typedef void (*UpdateStyleFn)(nsIFrame* aOwningFrame, nsIFrame* aAnonBox,
4065                                   mozilla::ServoRestyleState& aRestyleState);
4066 
4067     explicit OwnedAnonBox(nsIFrame* aAnonBoxFrame,
4068                           UpdateStyleFn aUpdateStyleFn = nullptr)
mAnonBoxFrameOwnedAnonBox4069         : mAnonBoxFrame(aAnonBoxFrame), mUpdateStyleFn(aUpdateStyleFn) {}
4070 
4071     nsIFrame* mAnonBoxFrame;
4072     UpdateStyleFn mUpdateStyleFn;
4073   };
4074 
4075   /**
4076    * Appends information about all of the anonymous boxes owned by this frame,
4077    * including other anonymous boxes owned by those which this frame owns
4078    * directly.
4079    */
AppendOwnedAnonBoxes(nsTArray<OwnedAnonBox> & aResult)4080   void AppendOwnedAnonBoxes(nsTArray<OwnedAnonBox>& aResult) {
4081     if (HasAnyStateBits(NS_FRAME_OWNS_ANON_BOXES)) {
4082       if (IsInlineFrame()) {
4083         // See comment in nsIFrame::DoUpdateStyleOfOwnedAnonBoxes for why
4084         // we skip nsInlineFrames.
4085         return;
4086       }
4087       DoAppendOwnedAnonBoxes(aResult);
4088     }
4089   }
4090 
4091  protected:
4092   // This does the actual work of AppendOwnedAnonBoxes.
4093   void DoAppendOwnedAnonBoxes(nsTArray<OwnedAnonBox>& aResult);
4094 
4095  public:
4096   /**
4097    * Hook subclasses can override to return their owned anonymous boxes.
4098    *
4099    * This function only appends anonymous boxes that are directly owned by
4100    * this frame, i.e. direct children or (for certain frames) a wrapper
4101    * parent, unlike AppendOwnedAnonBoxes, which will append all anonymous
4102    * boxes transitively owned by this frame.
4103    */
4104   virtual void AppendDirectlyOwnedAnonBoxes(nsTArray<OwnedAnonBox>& aResult);
4105 
4106   /**
4107    * Determines whether a frame is visible for painting;
4108    * taking into account whether it is painting a selection or printing.
4109    */
4110   bool IsVisibleForPainting();
4111   /**
4112    * Determines whether a frame is visible for painting or collapsed;
4113    * taking into account whether it is painting a selection or printing,
4114    */
4115   bool IsVisibleOrCollapsedForPainting();
4116 
4117   /**
4118    * Determines if this frame is a stacking context.
4119    */
4120   bool IsStackingContext(const nsStyleDisplay*, const nsStyleEffects*);
4121   bool IsStackingContext();
4122 
HonorPrintBackgroundSettings()4123   virtual bool HonorPrintBackgroundSettings() const { return true; }
4124 
4125   // Whether we should paint backgrounds or not.
4126   struct ShouldPaintBackground {
4127     bool mColor = false;
4128     bool mImage = false;
4129   };
4130   ShouldPaintBackground ComputeShouldPaintBackground() const;
4131 
4132   /**
4133    * Determine whether the frame is logically empty, which is roughly
4134    * whether the layout would be the same whether or not the frame is
4135    * present.  Placeholder frames should return true.  Block frames
4136    * should be considered empty whenever margins collapse through them,
4137    * even though those margins are relevant.  Text frames containing
4138    * only whitespace that does not contribute to the height of the line
4139    * should return true.
4140    */
4141   virtual bool IsEmpty();
4142   /**
4143    * Return the same as IsEmpty(). This may only be called after the frame
4144    * has been reflowed and before any further style or content changes.
4145    */
4146   virtual bool CachedIsEmpty();
4147   /**
4148    * Determine whether the frame is logically empty, assuming that all
4149    * its children are empty.
4150    */
4151   virtual bool IsSelfEmpty();
4152 
4153   /**
4154    * IsGeneratedContentFrame returns whether a frame corresponds to
4155    * generated content
4156    *
4157    * @return whether the frame correspods to generated content
4158    */
IsGeneratedContentFrame()4159   bool IsGeneratedContentFrame() const {
4160     return (mState & NS_FRAME_GENERATED_CONTENT) != 0;
4161   }
4162 
4163   /**
4164    * IsPseudoFrame returns whether a frame is a pseudo frame (eg an
4165    * anonymous table-row frame created for a CSS table-cell without an
4166    * enclosing table-row.
4167    *
4168    * @param aParentContent the content node corresponding to the parent frame
4169    * @return whether the frame is a pseudo frame
4170    */
IsPseudoFrame(const nsIContent * aParentContent)4171   bool IsPseudoFrame(const nsIContent* aParentContent) {
4172     return mContent == aParentContent;
4173   }
4174 
4175   /**
4176    * Support for reading and writing properties on the frame.
4177    * These call through to the frame's FrameProperties object, if it
4178    * exists, but avoid creating it if no property is ever set.
4179    */
4180   template <typename T>
4181   FrameProperties::PropertyType<T> GetProperty(
4182       FrameProperties::Descriptor<T> aProperty,
4183       bool* aFoundResult = nullptr) const {
4184     return mProperties.Get(aProperty, aFoundResult);
4185   }
4186 
4187   template <typename T>
HasProperty(FrameProperties::Descriptor<T> aProperty)4188   bool HasProperty(FrameProperties::Descriptor<T> aProperty) const {
4189     return mProperties.Has(aProperty);
4190   }
4191 
4192   /**
4193    * Add a property, or update an existing property for the given descriptor.
4194    *
4195    * Note: This function asserts if updating an existing nsFrameList property.
4196    */
4197   template <typename T>
SetProperty(FrameProperties::Descriptor<T> aProperty,FrameProperties::PropertyType<T> aValue)4198   void SetProperty(FrameProperties::Descriptor<T> aProperty,
4199                    FrameProperties::PropertyType<T> aValue) {
4200     if constexpr (std::is_same_v<T, nsFrameList>) {
4201       MOZ_ASSERT(aValue, "Shouldn't set nullptr to a nsFrameList property!");
4202       MOZ_ASSERT(!HasProperty(aProperty),
4203                  "Shouldn't update an existing nsFrameList property!");
4204     }
4205     mProperties.Set(aProperty, aValue, this);
4206   }
4207 
4208   // Unconditionally add a property; use ONLY if the descriptor is known
4209   // to NOT already be present.
4210   template <typename T>
AddProperty(FrameProperties::Descriptor<T> aProperty,FrameProperties::PropertyType<T> aValue)4211   void AddProperty(FrameProperties::Descriptor<T> aProperty,
4212                    FrameProperties::PropertyType<T> aValue) {
4213     mProperties.Add(aProperty, aValue);
4214   }
4215 
4216   /**
4217    * Remove a property and return its value without destroying it. May return
4218    * nullptr.
4219    *
4220    * Note: The caller is responsible for handling the life cycle of the returned
4221    * value.
4222    */
4223   template <typename T>
4224   [[nodiscard]] FrameProperties::PropertyType<T> TakeProperty(
4225       FrameProperties::Descriptor<T> aProperty, bool* aFoundResult = nullptr) {
4226     return mProperties.Take(aProperty, aFoundResult);
4227   }
4228 
4229   template <typename T>
RemoveProperty(FrameProperties::Descriptor<T> aProperty)4230   void RemoveProperty(FrameProperties::Descriptor<T> aProperty) {
4231     mProperties.Remove(aProperty, this);
4232   }
4233 
RemoveAllProperties()4234   void RemoveAllProperties() { mProperties.RemoveAll(this); }
4235 
4236   // nsIFrames themselves are in the nsPresArena, and so are not measured here.
4237   // Instead, this measures heap-allocated things hanging off the nsIFrame, and
4238   // likewise for its descendants.
4239   virtual void AddSizeOfExcludingThisForTree(nsWindowSizes& aWindowSizes) const;
4240 
4241   /**
4242    * Return true if and only if this frame obeys visibility:hidden.
4243    * if it does not, then nsContainerFrame will hide its view even though
4244    * this means children can't be made visible again.
4245    */
SupportsVisibilityHidden()4246   virtual bool SupportsVisibilityHidden() { return true; }
4247 
4248   /**
4249    * Returns the clip rect set via the 'clip' property, if the 'clip' property
4250    * applies to this frame; otherwise returns Nothing(). The 'clip' property
4251    * applies to HTML frames if they are absolutely positioned. The 'clip'
4252    * property applies to SVG frames regardless of the value of the 'position'
4253    * property.
4254    *
4255    * The coordinates of the returned rectangle are relative to this frame's
4256    * origin.
4257    */
4258   Maybe<nsRect> GetClipPropClipRect(const nsStyleDisplay* aDisp,
4259                                     const nsStyleEffects* aEffects,
4260                                     const nsSize& aSize) const;
4261 
4262   struct Focusable {
4263     bool mFocusable = false;
4264     // The computed tab index:
4265     //         < 0 if not tabbable
4266     //         == 0 if in normal tab order
4267     //         > 0 can be tabbed to in the order specified by this value
4268     int32_t mTabIndex = -1;
4269 
4270     explicit operator bool() const { return mFocusable; }
4271   };
4272 
4273   /**
4274    * Check if this frame is focusable and in the current tab order.
4275    * Tabbable is indicated by a nonnegative tabindex & is a subset of focusable.
4276    * For example, only the selected radio button in a group is in the
4277    * tab order, unless the radio group has no selection in which case
4278    * all of the visible, non-disabled radio buttons in the group are
4279    * in the tab order. On the other hand, all of the visible, non-disabled
4280    * radio buttons are always focusable via clicking or script.
4281    * Also, depending on the pref accessibility.tabfocus some widgets may be
4282    * focusable but removed from the tab order. This is the default on
4283    * Mac OS X, where fewer items are focusable.
4284    * @param  [in, optional] aWithMouse, is this focus query for mouse clicking
4285    * @return whether the frame is focusable via mouse, kbd or script.
4286    */
4287   [[nodiscard]] Focusable IsFocusable(bool aWithMouse = false);
4288 
4289   // BOX LAYOUT METHODS
4290   // These methods have been migrated from nsIBox and are in the process of
4291   // being refactored. DO NOT USE OUTSIDE OF XUL.
IsXULBoxFrame()4292   bool IsXULBoxFrame() const { return IsFrameOfType(nsIFrame::eXULBox); }
4293 
4294   enum Halignment { hAlign_Left, hAlign_Right, hAlign_Center };
4295 
4296   enum Valignment { vAlign_Top, vAlign_Middle, vAlign_BaseLine, vAlign_Bottom };
4297 
4298   /**
4299    * This calculates the minimum size required for a box based on its state
4300    * @param[in] aBoxLayoutState The desired state to calculate for
4301    * @return The minimum size
4302    */
4303   virtual nsSize GetXULMinSize(nsBoxLayoutState& aBoxLayoutState);
4304 
4305   /**
4306    * This calculates the preferred size of a box based on its state
4307    * @param[in] aBoxLayoutState The desired state to calculate for
4308    * @return The preferred size
4309    */
4310   virtual nsSize GetXULPrefSize(nsBoxLayoutState& aBoxLayoutState);
4311 
4312   /**
4313    * This calculates the maximum size for a box based on its state
4314    * @param[in] aBoxLayoutState The desired state to calculate for
4315    * @return The maximum size
4316    */
4317   virtual nsSize GetXULMaxSize(nsBoxLayoutState& aBoxLayoutState);
4318 
4319   /**
4320    * This returns the minimum size for the scroll area if this frame is
4321    * being scrolled. Usually it's (0,0).
4322    */
4323   virtual nsSize GetXULMinSizeForScrollArea(nsBoxLayoutState& aBoxLayoutState);
4324 
4325   virtual nscoord GetXULFlex();
4326   virtual nscoord GetXULBoxAscent(nsBoxLayoutState& aBoxLayoutState);
4327   virtual bool IsXULCollapsed();
4328   // This does not alter the overflow area. If the caller is changing
4329   // the box size, the caller is responsible for updating the overflow
4330   // area. It's enough to just call XULLayout or SyncXULLayout on the
4331   // box. You can pass true to aRemoveOverflowArea as a
4332   // convenience.
4333   virtual void SetXULBounds(nsBoxLayoutState& aBoxLayoutState,
4334                             const nsRect& aRect,
4335                             bool aRemoveOverflowAreas = false);
4336   nsresult XULLayout(nsBoxLayoutState& aBoxLayoutState);
4337   // Box methods.  Note that these do NOT just get the CSS border, padding,
4338   // etc.  They also talk to nsITheme.
4339   virtual nsresult GetXULBorderAndPadding(nsMargin& aBorderAndPadding);
4340   virtual nsresult GetXULBorder(nsMargin& aBorder);
4341   virtual nsresult GetXULPadding(nsMargin& aBorderAndPadding);
4342   virtual nsresult GetXULMargin(nsMargin& aMargin);
SetXULLayoutManager(nsBoxLayout * aLayout)4343   virtual void SetXULLayoutManager(nsBoxLayout* aLayout) {}
GetXULLayoutManager()4344   virtual nsBoxLayout* GetXULLayoutManager() { return nullptr; }
4345   nsresult GetXULClientRect(nsRect& aContentRect);
4346 
GetXULLayoutFlags()4347   virtual ReflowChildFlags GetXULLayoutFlags() {
4348     return ReflowChildFlags::Default;
4349   }
4350 
4351   // For nsSprocketLayout
GetXULVAlign()4352   virtual Valignment GetXULVAlign() const { return vAlign_Top; }
GetXULHAlign()4353   virtual Halignment GetXULHAlign() const { return hAlign_Left; }
4354 
IsXULHorizontal()4355   bool IsXULHorizontal() const {
4356     return (mState & NS_STATE_IS_HORIZONTAL) != 0;
4357   }
IsXULNormalDirection()4358   bool IsXULNormalDirection() const {
4359     return (mState & NS_STATE_IS_DIRECTION_NORMAL) != 0;
4360   }
4361 
4362   nsresult XULRedraw(nsBoxLayoutState& aState);
4363 
4364   static bool AddXULPrefSize(nsIFrame* aBox, nsSize& aSize, bool& aWidth,
4365                              bool& aHeightSet);
4366   static bool AddXULMinSize(nsIFrame* aBox, nsSize& aSize, bool& aWidth,
4367                             bool& aHeightSet);
4368   static bool AddXULMaxSize(nsIFrame* aBox, nsSize& aSize, bool& aWidth,
4369                             bool& aHeightSet);
4370   static bool AddXULFlex(nsIFrame* aBox, nscoord& aFlex);
4371 
4372   void AddXULBorderAndPadding(nsSize& aSize);
4373 
4374   static void AddXULBorderAndPadding(nsIFrame* aBox, nsSize& aSize);
4375   static void AddXULMargin(nsIFrame* aChild, nsSize& aSize);
4376   static void AddXULMargin(nsSize& aSize, const nsMargin& aMargin);
4377 
4378   static nsSize XULBoundsCheckMinMax(const nsSize& aMinSize,
4379                                      const nsSize& aMaxSize);
4380   static nsSize XULBoundsCheck(const nsSize& aMinSize, const nsSize& aPrefSize,
4381                                const nsSize& aMaxSize);
4382   static nscoord XULBoundsCheck(nscoord aMinSize, nscoord aPrefSize,
4383                                 nscoord aMaxSize);
4384 
4385   static nsIFrame* GetChildXULBox(const nsIFrame* aFrame);
4386   static nsIFrame* GetNextXULBox(const nsIFrame* aFrame);
4387   static nsIFrame* GetParentXULBox(const nsIFrame* aFrame);
4388 
4389  protected:
4390   // Helper for IsFocusable.
4391   bool IsFocusableDueToScrollFrame();
4392 
4393   /**
4394    * Returns true if this box clips its children, e.g., if this box is an
4395    * scrollbox.
4396    */
4397   virtual bool DoesClipChildrenInBothAxes();
4398 
4399   // We compute and store the HTML content's overflow area. So don't
4400   // try to compute it in the box code.
XULComputesOwnOverflowArea()4401   virtual bool XULComputesOwnOverflowArea() { return true; }
4402 
4403   nsresult SyncXULLayout(nsBoxLayoutState& aBoxLayoutState);
4404 
4405   bool XULNeedsRecalc(const nsSize& aSize);
4406   bool XULNeedsRecalc(nscoord aCoord);
4407   void XULSizeNeedsRecalc(nsSize& aSize);
4408   void XULCoordNeedsRecalc(nscoord& aCoord);
4409 
4410   nsresult BeginXULLayout(nsBoxLayoutState& aState);
4411   NS_IMETHOD DoXULLayout(nsBoxLayoutState& aBoxLayoutState);
4412   nsresult EndXULLayout(nsBoxLayoutState& aState);
4413 
4414   nsSize GetUncachedXULMinSize(nsBoxLayoutState& aBoxLayoutState);
4415   nsSize GetUncachedXULPrefSize(nsBoxLayoutState& aBoxLayoutState);
4416   nsSize GetUncachedXULMaxSize(nsBoxLayoutState& aBoxLayoutState);
4417 
4418   // END OF BOX LAYOUT METHODS
4419   // The above methods have been migrated from nsIBox and are in the process of
4420   // being refactored. DO NOT USE OUTSIDE OF XUL.
4421 
4422   /**
4423    * NOTE: aStatus is assumed to be already-initialized. The reflow statuses of
4424    * any reflowed absolute children will be merged into aStatus; aside from
4425    * that, this method won't modify aStatus.
4426    */
4427   void ReflowAbsoluteFrames(nsPresContext* aPresContext,
4428                             ReflowOutput& aDesiredSize,
4429                             const ReflowInput& aReflowInput,
4430                             nsReflowStatus& aStatus,
4431                             bool aConstrainBSize = true);
4432 
4433  private:
4434   void BoxReflow(nsBoxLayoutState& aState, nsPresContext* aPresContext,
4435                  ReflowOutput& aDesiredSize, gfxContext* aRenderingContext,
4436                  nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight,
4437                  bool aMoveFrame = true);
4438 
4439   NS_IMETHODIMP RefreshSizeCache(nsBoxLayoutState& aState);
4440 
4441   Maybe<nscoord> ComputeInlineSizeFromAspectRatio(
4442       mozilla::WritingMode aWM, const mozilla::LogicalSize& aCBSize,
4443       const mozilla::LogicalSize& aContentEdgeToBoxSizing,
4444       const mozilla::StyleSizeOverrides& aSizeOverrides,
4445       mozilla::ComputeSizeFlags aFlags) const;
4446 
4447  public:
4448   /**
4449    * @return true if this text frame ends with a newline character.  It
4450    * should return false if this is not a text frame.
4451    */
4452   virtual bool HasSignificantTerminalNewline() const;
4453 
4454   struct CaretPosition {
4455     CaretPosition();
4456     ~CaretPosition();
4457 
4458     nsCOMPtr<nsIContent> mResultContent;
4459     int32_t mContentOffset;
4460   };
4461 
4462   /**
4463    * gets the first or last possible caret position within the frame
4464    *
4465    * @param  [in] aStart
4466    *         true  for getting the first possible caret position
4467    *         false for getting the last possible caret position
4468    * @return The caret position in a CaretPosition.
4469    *         the returned value is a 'best effort' in case errors
4470    *         are encountered rummaging through the frame.
4471    */
4472   CaretPosition GetExtremeCaretPosition(bool aStart);
4473 
4474   /**
4475    * Get a line iterator for this frame, if supported.
4476    *
4477    * @return nullptr if no line iterator is supported.
4478    * @note dispose the line iterator using nsILineIterator::DisposeLineIterator
4479    */
GetLineIterator()4480   virtual nsILineIterator* GetLineIterator() { return nullptr; }
4481 
4482   /**
4483    * If this frame is a next-in-flow, and its prev-in-flow has something on its
4484    * overflow list, pull those frames into the child list of this one.
4485    */
PullOverflowsFromPrevInFlow()4486   virtual void PullOverflowsFromPrevInFlow() {}
4487 
4488   /**
4489    * Clear the list of child PresShells generated during the last paint
4490    * so that we can begin generating a new one.
4491    */
ClearPresShellsFromLastPaint()4492   void ClearPresShellsFromLastPaint() { PaintedPresShellList()->Clear(); }
4493 
4494   /**
4495    * Flag a child PresShell as painted so that it will get its paint count
4496    * incremented during empty transactions.
4497    */
4498   void AddPaintedPresShell(mozilla::PresShell* aPresShell);
4499 
4500   /**
4501    * Increment the paint count of all child PresShells that were painted during
4502    * the last repaint.
4503    */
4504   void UpdatePaintCountForPaintedPresShells();
4505 
4506   /**
4507    * @return true if we painted @aPresShell during the last repaint.
4508    */
4509   bool DidPaintPresShell(mozilla::PresShell* aPresShell);
4510 
4511   /**
4512    * Accessors for the absolute containing block.
4513    */
IsAbsoluteContainer()4514   bool IsAbsoluteContainer() const {
4515     return !!(mState & NS_FRAME_HAS_ABSPOS_CHILDREN);
4516   }
4517   bool HasAbsolutelyPositionedChildren() const;
4518   nsAbsoluteContainingBlock* GetAbsoluteContainingBlock() const;
4519   void MarkAsAbsoluteContainingBlock();
4520   void MarkAsNotAbsoluteContainingBlock();
4521   // Child frame types override this function to select their own child list
4522   // name
GetAbsoluteListID()4523   virtual mozilla::layout::FrameChildListID GetAbsoluteListID() const {
4524     return kAbsoluteList;
4525   }
4526 
4527   // Checks if we (or any of our descendents) have NS_FRAME_PAINTED_THEBES set,
4528   // and clears this bit if so.
4529   bool CheckAndClearPaintedState();
4530 
4531   // Checks if we (or any of our descendents) have mBuiltDisplayList set, and
4532   // clears this bit if so.
4533   bool CheckAndClearDisplayListState();
4534 
4535   // CSS visibility just doesn't cut it because it doesn't inherit through
4536   // documents. Also if this frame is in a hidden card of a deck then it isn't
4537   // visible either and that isn't expressed using CSS visibility. Also if it
4538   // is in a hidden view (there are a few cases left and they are hopefully
4539   // going away soon).
4540   // If the VISIBILITY_CROSS_CHROME_CONTENT_BOUNDARY flag is passed then we
4541   // ignore the chrome/content boundary, otherwise we stop looking when we
4542   // reach it.
4543   enum { VISIBILITY_CROSS_CHROME_CONTENT_BOUNDARY = 0x01 };
4544   bool IsVisibleConsideringAncestors(uint32_t aFlags = 0) const;
4545 
4546   struct FrameWithDistance {
4547     nsIFrame* mFrame;
4548     nscoord mXDistance;
4549     nscoord mYDistance;
4550   };
4551 
4552   /**
4553    * Finds a frame that is closer to a specified point than a current
4554    * distance.  Distance is measured as for text selection -- a closer x
4555    * distance beats a closer y distance.
4556    *
4557    * Normally, this function will only check the distance between this
4558    * frame's rectangle and the specified point.  SVGTextFrame overrides
4559    * this so that it can manage all of its descendant frames and take
4560    * into account any SVG text layout.
4561    *
4562    * If aPoint is closer to this frame's rectangle than aCurrentBestFrame
4563    * indicates, then aCurrentBestFrame is updated with the distance between
4564    * aPoint and this frame's rectangle, and with a pointer to this frame.
4565    * If aPoint is not closer, then aCurrentBestFrame is left unchanged.
4566    *
4567    * @param aPoint The point to check for its distance to this frame.
4568    * @param aCurrentBestFrame Pointer to a struct that will be updated with
4569    *   a pointer to this frame and its distance to aPoint, if this frame
4570    *   is indeed closer than the current distance in aCurrentBestFrame.
4571    */
4572   virtual void FindCloserFrameForSelection(
4573       const nsPoint& aPoint, FrameWithDistance* aCurrentBestFrame);
4574 
4575   /**
4576    * Is this a flex item? (i.e. a non-abs-pos child of a flex container)
4577    */
4578   inline bool IsFlexItem() const;
4579   /**
4580    * Is this a grid item? (i.e. a non-abs-pos child of a grid container)
4581    */
4582   inline bool IsGridItem() const;
4583   /**
4584    * Is this a flex or grid item? (i.e. a non-abs-pos child of a flex/grid
4585    * container)
4586    */
4587   inline bool IsFlexOrGridItem() const;
4588   inline bool IsFlexOrGridContainer() const;
4589 
4590   /**
4591    * Return true if this frame has masonry layout in aAxis.
4592    * @note only valid to call on nsGridContainerFrames
4593    */
4594   inline bool IsMasonry(mozilla::LogicalAxis aAxis) const;
4595 
4596   /**
4597    * @return true if this frame is used as a table caption.
4598    */
4599   inline bool IsTableCaption() const;
4600 
4601   inline bool IsBlockOutside() const;
4602   inline bool IsInlineOutside() const;
4603   inline mozilla::StyleDisplay GetDisplay() const;
4604   inline bool IsFloating() const;
4605   inline bool IsAbsPosContainingBlock() const;
4606   inline bool IsFixedPosContainingBlock() const;
4607   inline bool IsRelativelyPositioned() const;
4608   inline bool IsStickyPositioned() const;
4609   inline bool IsAbsolutelyPositioned(
4610       const nsStyleDisplay* aStyleDisplay = nullptr) const;
4611   inline bool IsTrueOverflowContainer() const;
4612 
4613   // Does this frame have "column-span: all" style.
4614   //
4615   // Note this only checks computed style, but not testing whether the
4616   // containing block formatting context was established by a multicol. Callers
4617   // need to use IsColumnSpanInMulticolSubtree() to check whether multi-column
4618   // effects apply or not.
4619   inline bool IsColumnSpan() const;
4620 
4621   // Like IsColumnSpan(), but this also checks whether the frame has a
4622   // multi-column ancestor or not.
4623   inline bool IsColumnSpanInMulticolSubtree() const;
4624 
4625   /**
4626    * Returns the vertical-align value to be used for layout, if it is one
4627    * of the enumerated values.  If this is an SVG text frame, it returns a value
4628    * that corresponds to the value of dominant-baseline.  If the
4629    * vertical-align property has length or percentage value, this returns
4630    * Nothing().
4631    */
4632   Maybe<mozilla::StyleVerticalAlignKeyword> VerticalAlignEnum() const;
4633 
4634   void CreateOwnLayerIfNeeded(nsDisplayListBuilder* aBuilder,
4635                               nsDisplayList* aList, uint16_t aType,
4636                               bool* aCreatedContainerItem = nullptr);
4637 
4638   /**
4639    * Adds the NS_FRAME_IN_POPUP state bit to aFrame, and
4640    * all descendant frames (including cross-doc ones).
4641    */
4642   static void AddInPopupStateBitToDescendants(nsIFrame* aFrame);
4643   /**
4644    * Removes the NS_FRAME_IN_POPUP state bit from aFrame and
4645    * all descendant frames (including cross-doc ones), unless
4646    * the frame is a popup itself.
4647    */
4648   static void RemoveInPopupStateBitFromDescendants(nsIFrame* aFrame);
4649 
4650   /**
4651    * Return true if aFrame is in an {ib} split and is NOT one of the
4652    * continuations of the first inline in it.
4653    */
FrameIsNonFirstInIBSplit()4654   bool FrameIsNonFirstInIBSplit() const {
4655     return HasAnyStateBits(NS_FRAME_PART_OF_IBSPLIT) &&
4656            FirstContinuation()->GetProperty(nsIFrame::IBSplitPrevSibling());
4657   }
4658 
4659   /**
4660    * Return true if aFrame is in an {ib} split and is NOT one of the
4661    * continuations of the last inline in it.
4662    */
FrameIsNonLastInIBSplit()4663   bool FrameIsNonLastInIBSplit() const {
4664     return HasAnyStateBits(NS_FRAME_PART_OF_IBSPLIT) &&
4665            FirstContinuation()->GetProperty(nsIFrame::IBSplitSibling());
4666   }
4667 
4668   /**
4669    * Return whether this is a frame whose width is used when computing
4670    * the font size inflation of its descendants.
4671    */
IsContainerForFontSizeInflation()4672   bool IsContainerForFontSizeInflation() const {
4673     return HasAnyStateBits(NS_FRAME_FONT_INFLATION_CONTAINER);
4674   }
4675 
4676   /**
4677    * Return whether this frame or any of its children is dirty.
4678    */
IsSubtreeDirty()4679   bool IsSubtreeDirty() const {
4680     return HasAnyStateBits(NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN);
4681   }
4682 
4683   /**
4684    * Return whether this frame keeps track of overflow areas. (Frames for
4685    * non-display SVG elements -- e.g. <clipPath> -- do not maintain overflow
4686    * areas, because they're never painted.)
4687    */
FrameMaintainsOverflow()4688   bool FrameMaintainsOverflow() const {
4689     return !HasAllStateBits(NS_FRAME_SVG_LAYOUT | NS_FRAME_IS_NONDISPLAY) &&
4690            !(IsSVGOuterSVGFrame() && HasAnyStateBits(NS_FRAME_IS_NONDISPLAY));
4691   }
4692 
4693   /*
4694    * @param aStyleDisplay:  If the caller has this->StyleDisplay(), providing
4695    *   it here will improve performance.
4696    */
BackfaceIsHidden(const nsStyleDisplay * aStyleDisplay)4697   bool BackfaceIsHidden(const nsStyleDisplay* aStyleDisplay) const {
4698     MOZ_ASSERT(aStyleDisplay == StyleDisplay());
4699     return aStyleDisplay->BackfaceIsHidden();
4700   }
BackfaceIsHidden()4701   bool BackfaceIsHidden() const { return StyleDisplay()->BackfaceIsHidden(); }
4702 
4703   /**
4704    * Returns true if the frame is scrolled out of view.
4705    */
4706   bool IsScrolledOutOfView() const;
4707 
4708   /**
4709    * Computes a 2D matrix from the -moz-window-transform and
4710    * -moz-window-transform-origin properties on aFrame.
4711    * Values that don't result in a 2D matrix will be ignored and an identity
4712    * matrix will be returned instead.
4713    */
4714   Matrix ComputeWidgetTransform();
4715 
4716   /**
4717    * @return true iff this frame has one or more associated image requests.
4718    * @see mozilla::css::ImageLoader.
4719    */
HasImageRequest()4720   bool HasImageRequest() const { return mHasImageRequest; }
4721 
4722   /**
4723    * Update this frame's image request state.
4724    */
SetHasImageRequest(bool aHasRequest)4725   void SetHasImageRequest(bool aHasRequest) { mHasImageRequest = aHasRequest; }
4726 
4727   /**
4728    * Whether this frame has a first-letter child.  If it does, the frame is
4729    * actually an nsContainerFrame and the first-letter frame can be gotten by
4730    * walking up to the nearest ancestor blockframe and getting its first
4731    * continuation's nsContainerFrame::FirstLetterProperty() property.  This will
4732    * only return true for the first continuation of the first-letter's parent.
4733    */
HasFirstLetterChild()4734   bool HasFirstLetterChild() const { return mHasFirstLetterChild; }
4735 
4736   /**
4737    * Whether this frame's parent is a wrapper anonymous box.  See documentation
4738    * for mParentIsWrapperAnonBox.
4739    */
ParentIsWrapperAnonBox()4740   bool ParentIsWrapperAnonBox() const { return mParentIsWrapperAnonBox; }
SetParentIsWrapperAnonBox()4741   void SetParentIsWrapperAnonBox() { mParentIsWrapperAnonBox = true; }
4742 
4743   /**
4744    * Whether this is a wrapper anonymous box needing a restyle.
4745    */
IsWrapperAnonBoxNeedingRestyle()4746   bool IsWrapperAnonBoxNeedingRestyle() const {
4747     return mIsWrapperBoxNeedingRestyle;
4748   }
SetIsWrapperAnonBoxNeedingRestyle(bool aNeedsRestyle)4749   void SetIsWrapperAnonBoxNeedingRestyle(bool aNeedsRestyle) {
4750     mIsWrapperBoxNeedingRestyle = aNeedsRestyle;
4751   }
4752 
MayHaveTransformAnimation()4753   bool MayHaveTransformAnimation() const { return mMayHaveTransformAnimation; }
SetMayHaveTransformAnimation()4754   void SetMayHaveTransformAnimation() {
4755     AddStateBits(NS_FRAME_MAY_BE_TRANSFORMED);
4756     mMayHaveTransformAnimation = true;
4757   }
MayHaveOpacityAnimation()4758   bool MayHaveOpacityAnimation() const { return mMayHaveOpacityAnimation; }
SetMayHaveOpacityAnimation()4759   void SetMayHaveOpacityAnimation() { mMayHaveOpacityAnimation = true; }
4760 
4761   // Returns true if this frame is visible or may have visible descendants.
4762   // Note: This function is accurate only on primary frames, because
4763   // mAllDescendantsAreInvisible is not updated on continuations.
IsVisibleOrMayHaveVisibleDescendants()4764   bool IsVisibleOrMayHaveVisibleDescendants() const {
4765     return !mAllDescendantsAreInvisible || StyleVisibility()->IsVisible();
4766   }
4767   // Update mAllDescendantsAreInvisible flag for this frame and ancestors.
4768   void UpdateVisibleDescendantsState();
4769 
4770   /**
4771    * If this returns true, the frame it's called on should get the
4772    * NS_FRAME_HAS_DIRTY_CHILDREN bit set on it by the caller; either directly
4773    * if it's already in reflow, or via calling FrameNeedsReflow() to schedule a
4774    * reflow.
4775    */
RenumberFrameAndDescendants(int32_t * aOrdinal,int32_t aDepth,int32_t aIncrement,bool aForCounting)4776   virtual bool RenumberFrameAndDescendants(int32_t* aOrdinal, int32_t aDepth,
4777                                            int32_t aIncrement,
4778                                            bool aForCounting) {
4779     return false;
4780   }
4781 
4782   enum class ExtremumLength {
4783     MinContent,
4784     MaxContent,
4785     MozAvailable,
4786     MozFitContent,
4787     FitContentFunction,
4788   };
4789 
4790   template <typename SizeOrMaxSize>
ToExtremumLength(const SizeOrMaxSize & aSize)4791   static Maybe<ExtremumLength> ToExtremumLength(const SizeOrMaxSize& aSize) {
4792     switch (aSize.tag) {
4793       case SizeOrMaxSize::Tag::MinContent:
4794         return mozilla::Some(ExtremumLength::MinContent);
4795       case SizeOrMaxSize::Tag::MaxContent:
4796         return mozilla::Some(ExtremumLength::MaxContent);
4797       case SizeOrMaxSize::Tag::MozAvailable:
4798         return mozilla::Some(ExtremumLength::MozAvailable);
4799       case SizeOrMaxSize::Tag::MozFitContent:
4800         return mozilla::Some(ExtremumLength::MozFitContent);
4801       case SizeOrMaxSize::Tag::FitContentFunction:
4802         return mozilla::Some(ExtremumLength::FitContentFunction);
4803       default:
4804         return mozilla::Nothing();
4805     }
4806   }
4807 
4808   /**
4809    * Helper function - computes the content-box inline size for aSize, which is
4810    * a more complex version to resolve a StyleExtremumLength.
4811    * @param aAvailableISizeOverride If this has a value, it is used as the
4812    *                                available inline-size instead of
4813    *                                aContainingBlockSize.ISize(aWM) when
4814    *                                resolving fit-content.
4815    */
4816   struct ISizeComputationResult {
4817     nscoord mISize = 0;
4818     AspectRatioUsage mAspectRatioUsage = AspectRatioUsage::None;
4819   };
4820   ISizeComputationResult ComputeISizeValue(
4821       gfxContext* aRenderingContext, const mozilla::WritingMode aWM,
4822       const mozilla::LogicalSize& aContainingBlockSize,
4823       const mozilla::LogicalSize& aContentEdgeToBoxSizing,
4824       nscoord aBoxSizingToMarginEdge, ExtremumLength aSize,
4825       Maybe<nscoord> aAvailableISizeOverride,
4826       const mozilla::StyleSizeOverrides& aSizeOverrides,
4827       mozilla::ComputeSizeFlags aFlags);
4828 
4829   /**
4830    * Helper function - computes the content-box inline size for aSize, which is
4831    * a simpler version to resolve a LengthPercentage.
4832    */
4833   nscoord ComputeISizeValue(const mozilla::WritingMode aWM,
4834                             const mozilla::LogicalSize& aContainingBlockSize,
4835                             const mozilla::LogicalSize& aContentEdgeToBoxSizing,
4836                             const LengthPercentage& aSize);
4837 
4838   template <typename SizeOrMaxSize>
4839   ISizeComputationResult ComputeISizeValue(
4840       gfxContext* aRenderingContext, const mozilla::WritingMode aWM,
4841       const mozilla::LogicalSize& aContainingBlockSize,
4842       const mozilla::LogicalSize& aContentEdgeToBoxSizing,
4843       nscoord aBoxSizingToMarginEdge, const SizeOrMaxSize& aSize,
4844       const mozilla::StyleSizeOverrides& aSizeOverrides = {},
4845       mozilla::ComputeSizeFlags aFlags = {}) {
4846     if (aSize.IsLengthPercentage()) {
4847       return {ComputeISizeValue(aWM, aContainingBlockSize,
4848                                 aContentEdgeToBoxSizing,
4849                                 aSize.AsLengthPercentage())};
4850     }
4851     auto length = ToExtremumLength(aSize);
4852     MOZ_ASSERT(length, "This doesn't handle none / auto");
4853     Maybe<nscoord> availbleISizeOverride;
4854     if (aSize.IsFitContentFunction()) {
4855       availbleISizeOverride.emplace(aSize.AsFitContentFunction().Resolve(
4856           aContainingBlockSize.ISize(aWM)));
4857     }
4858     return ComputeISizeValue(aRenderingContext, aWM, aContainingBlockSize,
4859                              aContentEdgeToBoxSizing, aBoxSizingToMarginEdge,
4860                              length.valueOr(ExtremumLength::MinContent),
4861                              availbleISizeOverride, aSizeOverrides, aFlags);
4862   }
4863 
DisplayItemData()4864   DisplayItemDataArray* DisplayItemData() const {
4865     return GetProperty(nsIFrame::DisplayItemDataProperty());
4866   }
4867 
DisplayItems()4868   DisplayItemArray& DisplayItems() { return mDisplayItems; }
DisplayItems()4869   const DisplayItemArray& DisplayItems() const { return mDisplayItems; }
4870 
4871   void AddDisplayItem(nsDisplayItemBase* aItem);
4872   bool RemoveDisplayItem(nsDisplayItemBase* aItem);
4873   void RemoveDisplayItemDataForDeletion();
4874   bool HasDisplayItems();
4875   bool HasDisplayItem(nsDisplayItemBase* aItem);
4876   bool HasDisplayItem(uint32_t aKey);
4877 
4878   static void PrintDisplayList(nsDisplayListBuilder* aBuilder,
4879                                const nsDisplayList& aList,
4880                                bool aDumpHtml = false);
4881   static void PrintDisplayList(nsDisplayListBuilder* aBuilder,
4882                                const nsDisplayList& aList,
4883                                std::stringstream& aStream,
4884                                bool aDumpHtml = false);
4885   static void PrintDisplayItem(nsDisplayListBuilder* aBuilder,
4886                                nsDisplayItem* aItem, std::stringstream& aStream,
4887                                uint32_t aIndent = 0, bool aDumpSublist = false,
4888                                bool aDumpHtml = false);
4889 #ifdef MOZ_DUMP_PAINTING
4890   static void PrintDisplayListSet(nsDisplayListBuilder* aBuilder,
4891                                   const nsDisplayListSet& aSet,
4892                                   std::stringstream& aStream,
4893                                   bool aDumpHtml = false);
4894 #endif
4895 
4896   /**
4897    * Adds display items for standard CSS background if necessary.
4898    * Does not check IsVisibleForPainting.
4899    * @param aForceBackground draw the background even if the frame
4900    * background style appears to have no background --- this is useful
4901    * for frames that might receive a propagated background via
4902    * nsCSSRendering::FindBackground
4903    * @return whether a themed background item was created.
4904    */
4905   bool DisplayBackgroundUnconditional(nsDisplayListBuilder* aBuilder,
4906                                       const nsDisplayListSet& aLists,
4907                                       bool aForceBackground);
4908   /**
4909    * Adds display items for standard CSS borders, background and outline for
4910    * for this frame, as necessary. Checks IsVisibleForPainting and won't
4911    * display anything if the frame is not visible.
4912    * @param aForceBackground draw the background even if the frame
4913    * background style appears to have no background --- this is useful
4914    * for frames that might receive a propagated background via
4915    * nsCSSRendering::FindBackground
4916    */
4917   void DisplayBorderBackgroundOutline(nsDisplayListBuilder* aBuilder,
4918                                       const nsDisplayListSet& aLists,
4919                                       bool aForceBackground = false);
4920   /**
4921    * Add a display item for the CSS outline. Does not check visibility.
4922    */
4923   void DisplayOutlineUnconditional(nsDisplayListBuilder* aBuilder,
4924                                    const nsDisplayListSet& aLists);
4925   /**
4926    * Add a display item for the CSS outline, after calling
4927    * IsVisibleForPainting to confirm we are visible.
4928    */
4929   void DisplayOutline(nsDisplayListBuilder* aBuilder,
4930                       const nsDisplayListSet& aLists);
4931 
4932   /**
4933    * Add a display item for CSS inset box shadows. Does not check visibility.
4934    */
4935   void DisplayInsetBoxShadowUnconditional(nsDisplayListBuilder* aBuilder,
4936                                           nsDisplayList* aList);
4937 
4938   /**
4939    * Add a display item for CSS inset box shadow, after calling
4940    * IsVisibleForPainting to confirm we are visible.
4941    */
4942   void DisplayInsetBoxShadow(nsDisplayListBuilder* aBuilder,
4943                              nsDisplayList* aList);
4944 
4945   /**
4946    * Add a display item for CSS outset box shadows. Does not check visibility.
4947    */
4948   void DisplayOutsetBoxShadowUnconditional(nsDisplayListBuilder* aBuilder,
4949                                            nsDisplayList* aList);
4950 
4951   /**
4952    * Add a display item for CSS outset box shadow, after calling
4953    * IsVisibleForPainting to confirm we are visible.
4954    */
4955   void DisplayOutsetBoxShadow(nsDisplayListBuilder* aBuilder,
4956                               nsDisplayList* aList);
4957 
ForceDescendIntoIfVisible()4958   bool ForceDescendIntoIfVisible() const { return mForceDescendIntoIfVisible; }
SetForceDescendIntoIfVisible(bool aForce)4959   void SetForceDescendIntoIfVisible(bool aForce) {
4960     mForceDescendIntoIfVisible = aForce;
4961   }
4962 
BuiltDisplayList()4963   bool BuiltDisplayList() const { return mBuiltDisplayList; }
SetBuiltDisplayList(const bool aBuilt)4964   void SetBuiltDisplayList(const bool aBuilt) { mBuiltDisplayList = aBuilt; }
4965 
IsFrameModified()4966   bool IsFrameModified() const { return mFrameIsModified; }
SetFrameIsModified(const bool aFrameIsModified)4967   void SetFrameIsModified(const bool aFrameIsModified) {
4968     mFrameIsModified = aFrameIsModified;
4969   }
4970 
HasOverrideDirtyRegion()4971   bool HasOverrideDirtyRegion() const { return mHasOverrideDirtyRegion; }
SetHasOverrideDirtyRegion(const bool aHasDirtyRegion)4972   void SetHasOverrideDirtyRegion(const bool aHasDirtyRegion) {
4973     mHasOverrideDirtyRegion = aHasDirtyRegion;
4974   }
4975 
MayHaveWillChangeBudget()4976   bool MayHaveWillChangeBudget() const { return mMayHaveWillChangeBudget; }
SetMayHaveWillChangeBudget(const bool aHasBudget)4977   void SetMayHaveWillChangeBudget(const bool aHasBudget) {
4978     mMayHaveWillChangeBudget = aHasBudget;
4979   }
4980 
HasBSizeChange()4981   bool HasBSizeChange() const { return mHasBSizeChange; }
SetHasBSizeChange(const bool aHasBSizeChange)4982   void SetHasBSizeChange(const bool aHasBSizeChange) {
4983     mHasBSizeChange = aHasBSizeChange;
4984   }
4985 
HasColumnSpanSiblings()4986   bool HasColumnSpanSiblings() const { return mHasColumnSpanSiblings; }
SetHasColumnSpanSiblings(bool aHasColumnSpanSiblings)4987   void SetHasColumnSpanSiblings(bool aHasColumnSpanSiblings) {
4988     mHasColumnSpanSiblings = aHasColumnSpanSiblings;
4989   }
4990 
DescendantMayDependOnItsStaticPosition()4991   bool DescendantMayDependOnItsStaticPosition() const {
4992     return mDescendantMayDependOnItsStaticPosition;
4993   }
SetDescendantMayDependOnItsStaticPosition(bool aValue)4994   void SetDescendantMayDependOnItsStaticPosition(bool aValue) {
4995     mDescendantMayDependOnItsStaticPosition = aValue;
4996   }
4997 
ShouldGenerateComputedInfo()4998   bool ShouldGenerateComputedInfo() const {
4999     return mShouldGenerateComputedInfo;
5000   }
SetShouldGenerateComputedInfo(bool aValue)5001   void SetShouldGenerateComputedInfo(bool aValue) {
5002     mShouldGenerateComputedInfo = aValue;
5003   }
5004 
5005   /**
5006    * Returns the hit test area of the frame.
5007    */
5008   nsRect GetCompositorHitTestArea(nsDisplayListBuilder* aBuilder);
5009 
5010   /**
5011    * Returns the set of flags indicating the properties of the frame that the
5012    * compositor might care about for hit-testing purposes. Note that this
5013    * function must be called during Gecko display list construction time (i.e
5014    * while the frame tree is being traversed) because that is when the display
5015    * list builder has the necessary state set up correctly.
5016    */
5017   mozilla::gfx::CompositorHitTestInfo GetCompositorHitTestInfo(
5018       nsDisplayListBuilder* aBuilder);
5019 
5020   /**
5021    * Copies aWM to mWritingMode on 'this' and all its ancestors.
5022    */
5023   inline void PropagateWritingModeToSelfAndAncestors(mozilla::WritingMode aWM);
5024 
5025  protected:
5026   static void DestroyAnonymousContent(nsPresContext* aPresContext,
5027                                       already_AddRefed<nsIContent>&& aContent);
5028 
5029   /**
5030    * Reparent this frame's view if it has one.
5031    */
5032   void ReparentFrameViewTo(nsViewManager* aViewManager, nsView* aNewParentView,
5033                            nsView* aOldParentView);
5034 
5035   /**
5036    * To be overridden by frame classes that have a varying IsLeaf() state and
5037    * is indicating that with DynamicLeaf in FrameIdList.h.
5038    * @see IsLeaf()
5039    */
IsLeafDynamic()5040   virtual bool IsLeafDynamic() const { return false; }
5041 
5042   // Members
5043   nsRect mRect;
5044   nsCOMPtr<nsIContent> mContent;
5045   RefPtr<ComputedStyle> mComputedStyle;
5046 
5047  private:
5048   nsPresContext* const mPresContext;
5049   nsContainerFrame* mParent;
5050   nsIFrame* mNextSibling;  // doubly-linked list of frames
5051   nsIFrame* mPrevSibling;  // Do not touch outside SetNextSibling!
5052 
5053   DisplayItemArray mDisplayItems;
5054 
5055   void MarkAbsoluteFramesForDisplayList(nsDisplayListBuilder* aBuilder);
5056 
5057   // Stores weak references to all the PresShells that were painted during
5058   // the last paint event so that we can increment their paint count during
5059   // empty transactions
NS_DECLARE_FRAME_PROPERTY_DELETABLE(PaintedPresShellsProperty,nsTArray<nsWeakPtr>)5060   NS_DECLARE_FRAME_PROPERTY_DELETABLE(PaintedPresShellsProperty,
5061                                       nsTArray<nsWeakPtr>)
5062 
5063   nsTArray<nsWeakPtr>* PaintedPresShellList() {
5064     bool found;
5065     nsTArray<nsWeakPtr>* list =
5066         GetProperty(PaintedPresShellsProperty(), &found);
5067 
5068     if (!found) {
5069       list = new nsTArray<nsWeakPtr>();
5070       AddProperty(PaintedPresShellsProperty(), list);
5071     } else {
5072       MOZ_ASSERT(list, "this property should only store non-null values");
5073     }
5074 
5075     return list;
5076   }
5077 
5078  protected:
MarkInReflow()5079   void MarkInReflow() {
5080 #ifdef DEBUG_dbaron_off
5081     // bug 81268
5082     NS_ASSERTION(!(mState & NS_FRAME_IN_REFLOW), "frame is already in reflow");
5083 #endif
5084     AddStateBits(NS_FRAME_IN_REFLOW);
5085   }
5086 
5087   nsFrameState mState;
5088 
5089   /**
5090    * List of properties attached to the frame.
5091    */
5092   FrameProperties mProperties;
5093 
5094   // When there is no scrollable overflow area, and the ink overflow area only
5095   // slightly larger than mRect, the ink overflow area may be stored a set of
5096   // four 1-byte deltas from the edges of mRect rather than allocating a whole
5097   // separate rectangle property. If all four deltas are zero, this means that
5098   // no overflow area has actually been set (this is the initial state of
5099   // newly-created frames).
5100   //
5101   // Note that these are unsigned values, all measured "outwards" from the edges
5102   // of mRect, so mLeft and mTop are reversed from our normal coordinate system.
5103   struct InkOverflowDeltas {
5104     // The maximum delta value we can store in any of the four edges.
5105     static constexpr uint8_t kMax = 0xfe;
5106 
5107     uint8_t mLeft;
5108     uint8_t mTop;
5109     uint8_t mRight;
5110     uint8_t mBottom;
5111     bool operator==(const InkOverflowDeltas& aOther) const {
5112       return mLeft == aOther.mLeft && mTop == aOther.mTop &&
5113              mRight == aOther.mRight && mBottom == aOther.mBottom;
5114     }
5115     bool operator!=(const InkOverflowDeltas& aOther) const {
5116       return !(*this == aOther);
5117     }
5118   };
5119   enum class OverflowStorageType : uint32_t {
5120     // No overflow area; code relies on this being an all-zero value.
5121     None = 0x00000000u,
5122 
5123     // Ink overflow is too large to stored in InkOverflowDeltas.
5124     Large = 0x000000ffu,
5125   };
5126   // If mOverflow.mType is OverflowStorageType::Large, then the delta values are
5127   // not meaningful and the overflow area is stored in OverflowAreasProperty()
5128   // instead.
5129   union {
5130     OverflowStorageType mType;
5131     InkOverflowDeltas mInkOverflowDeltas;
5132   } mOverflow;
5133 
5134   /** @see GetWritingMode() */
5135   mozilla::WritingMode mWritingMode;
5136 
5137   /** The ClassID of the concrete class of this instance. */
5138   ClassID mClass;  // 1 byte
5139 
5140   bool mMayHaveRoundedCorners : 1;
5141 
5142   /**
5143    * True iff this frame has one or more associated image requests.
5144    * @see mozilla::css::ImageLoader.
5145    */
5146   bool mHasImageRequest : 1;
5147 
5148   /**
5149    * True if this frame has a continuation that has a first-letter frame, or its
5150    * placeholder, as a child.  In that case this frame has a blockframe ancestor
5151    * that has the first-letter frame hanging off it in the
5152    * nsContainerFrame::FirstLetterProperty() property.
5153    */
5154   bool mHasFirstLetterChild : 1;
5155 
5156   /**
5157    * True if this frame's parent is a wrapper anonymous box (e.g. a table
5158    * anonymous box as specified at
5159    * <https://www.w3.org/TR/CSS21/tables.html#anonymous-boxes>).
5160    *
5161    * We could compute this information directly when we need it, but it wouldn't
5162    * be all that cheap, and since this information is immutable for the lifetime
5163    * of the frame we might as well cache it.
5164    *
5165    * Note that our parent may itself have mParentIsWrapperAnonBox set to true.
5166    */
5167   bool mParentIsWrapperAnonBox : 1;
5168 
5169   /**
5170    * True if this is a wrapper anonymous box needing a restyle.  This is used to
5171    * track, during stylo post-traversal, whether we've already recomputed the
5172    * style of this anonymous box, if we end up seeing it twice.
5173    */
5174   bool mIsWrapperBoxNeedingRestyle : 1;
5175 
5176   /**
5177    * This bit is used in nsTextFrame::CharacterDataChanged() as an optimization
5178    * to skip redundant reflow-requests when the character data changes multiple
5179    * times between reflows. If this flag is set, then it implies that the
5180    * NS_FRAME_IS_DIRTY state bit is also set (and that intrinsic sizes have
5181    * been marked as dirty on our ancestor chain).
5182    *
5183    * XXXdholbert This bit is *only* used on nsTextFrame, but it lives here on
5184    * nsIFrame simply because this is where we've got unused state bits
5185    * available in a gap. If bits become more scarce, we should perhaps consider
5186    * expanding the range of frame-specific state bits in nsFrameStateBits.h and
5187    * moving this to be one of those (e.g. by swapping one of the adjacent
5188    * general-purpose bits to take the place of this bool:1 here, so we can grow
5189    * that range of frame-specific bits by 1).
5190    */
5191   bool mReflowRequestedForCharDataChange : 1;
5192 
5193   /**
5194    * This bit is used during BuildDisplayList to mark frames that need to
5195    * have display items rebuilt. We will descend into them if they are
5196    * currently visible, even if they don't intersect the dirty area.
5197    */
5198   bool mForceDescendIntoIfVisible : 1;
5199 
5200   /**
5201    * True if we have built display items for this frame since
5202    * the last call to CheckAndClearDisplayListState, false
5203    * otherwise. Used for the reftest harness to verify minimal
5204    * display list building.
5205    */
5206   bool mBuiltDisplayList : 1;
5207 
5208   bool mFrameIsModified : 1;
5209 
5210   bool mHasOverrideDirtyRegion : 1;
5211 
5212   /**
5213    * True if frame has will-change, and currently has display
5214    * items consuming some of the will-change budget.
5215    */
5216   bool mMayHaveWillChangeBudget : 1;
5217 
5218  private:
5219   /**
5220    * True if this is the primary frame for mContent.
5221    */
5222   bool mIsPrimaryFrame : 1;
5223 
5224   bool mMayHaveTransformAnimation : 1;
5225   bool mMayHaveOpacityAnimation : 1;
5226 
5227   /**
5228    * True if we are certain that all descendants are not visible.
5229    *
5230    * This flag is conservative in that it might sometimes be false even if, in
5231    * fact, all descendants are invisible.
5232    * For example; an element is visibility:visible and has a visibility:hidden
5233    * child. This flag is stil false in such case.
5234    */
5235   bool mAllDescendantsAreInvisible : 1;
5236 
5237   bool mHasBSizeChange : 1;
5238 
5239   /**
5240    * True if we are or contain the scroll anchor for a scrollable frame.
5241    */
5242   bool mInScrollAnchorChain : 1;
5243 
5244   /**
5245    * Suppose a frame was split into multiple parts to separate parts containing
5246    * column-spans from parts not containing column-spans. This bit is set on all
5247    * continuations *not* containing column-spans except for the those after the
5248    * last column-span/non-column-span boundary (i.e., the bit really means it
5249    * has a *later* sibling across a split). Note that the last part is always
5250    * created to containing no columns-spans even if it has no children. See
5251    * nsCSSFrameConstructor::CreateColumnSpanSiblings() for the implementation.
5252    *
5253    * If the frame having this bit set is removed, we need to reframe the
5254    * multi-column container.
5255    */
5256   bool mHasColumnSpanSiblings : 1;
5257 
5258   /**
5259    * True if we may have any descendant whose positioning may depend on its
5260    * static position (and thus which we need to recompute the position for if we
5261    * move).
5262    */
5263   bool mDescendantMayDependOnItsStaticPosition : 1;
5264 
5265   /**
5266    * True if the next reflow of this frame should generate computed info
5267    * metrics. These are used by devtools to reveal details of the layout
5268    * process.
5269    */
5270   bool mShouldGenerateComputedInfo : 1;
5271 
5272  protected:
5273   // Helpers
5274   /**
5275    * Can we stop inside this frame when we're skipping non-rendered whitespace?
5276    *
5277    * @param aForward [in] Are we moving forward (or backward) in content order.
5278    *
5279    * @param aOffset [in/out] At what offset into the frame to start looking.
5280    * at offset was reached (whether or not we found a place to stop).
5281    *
5282    * @return
5283    *   * STOP: An appropriate offset was found within this frame,
5284    *     and is given by aOffset.
5285    *   * CONTINUE: Not found within this frame, need to try the next frame.
5286    *     See enum FrameSearchResult for more details.
5287    */
5288   virtual FrameSearchResult PeekOffsetNoAmount(bool aForward, int32_t* aOffset);
5289 
5290   /**
5291    * Search the frame for the next character
5292    *
5293    * @param aForward [in] Are we moving forward (or backward) in content order.
5294    *
5295    * @param aOffset [in/out] At what offset into the frame to start looking.
5296    * on output - what offset was reached (whether or not we found a place to
5297    * stop).
5298    *
5299    * @param aOptions [in] Options, see the comment in PeekOffsetCharacterOptions
5300    * for the detail.
5301    *
5302    * @return
5303    *   * STOP: An appropriate offset was found within this frame, and is given
5304    *     by aOffset.
5305    *   * CONTINUE: Not found within this frame, need to try the next frame. See
5306    *     enum FrameSearchResult for more details.
5307    */
5308   virtual FrameSearchResult PeekOffsetCharacter(
5309       bool aForward, int32_t* aOffset,
5310       PeekOffsetCharacterOptions aOptions = PeekOffsetCharacterOptions());
5311   static_assert(sizeof(PeekOffsetCharacterOptions) <= sizeof(intptr_t),
5312                 "aOptions should be changed to const reference");
5313 
5314   struct PeekWordState {
5315     // true when we're still at the start of the search, i.e., we can't return
5316     // this point as a valid offset!
5317     bool mAtStart;
5318     // true when we've encountered at least one character of the type before the
5319     // boundary we're looking for:
5320     // 1. If we're moving forward and eating whitepace, looking for a word
5321     //    beginning (i.e. a boundary between whitespace and non-whitespace),
5322     //    then mSawBeforeType==true means "we already saw some whitespace".
5323     // 2. Otherwise, looking for a word beginning (i.e. a boundary between
5324     //    non-whitespace and whitespace), then mSawBeforeType==true means "we
5325     //    already saw some non-whitespace".
5326     bool mSawBeforeType;
5327     // true when we've encountered at least one non-newline character
5328     bool mSawInlineCharacter;
5329     // true when the last character encountered was punctuation
5330     bool mLastCharWasPunctuation;
5331     // true when the last character encountered was whitespace
5332     bool mLastCharWasWhitespace;
5333     // true when we've seen non-punctuation since the last whitespace
5334     bool mSeenNonPunctuationSinceWhitespace;
5335     // text that's *before* the current frame when aForward is true, *after*
5336     // the current frame when aForward is false. Only includes the text
5337     // on the current line.
5338     nsAutoString mContext;
5339 
PeekWordStatePeekWordState5340     PeekWordState()
5341         : mAtStart(true),
5342           mSawBeforeType(false),
5343           mSawInlineCharacter(false),
5344           mLastCharWasPunctuation(false),
5345           mLastCharWasWhitespace(false),
5346           mSeenNonPunctuationSinceWhitespace(false) {}
SetSawBeforeTypePeekWordState5347     void SetSawBeforeType() { mSawBeforeType = true; }
SetSawInlineCharacterPeekWordState5348     void SetSawInlineCharacter() { mSawInlineCharacter = true; }
UpdatePeekWordState5349     void Update(bool aAfterPunctuation, bool aAfterWhitespace) {
5350       mLastCharWasPunctuation = aAfterPunctuation;
5351       mLastCharWasWhitespace = aAfterWhitespace;
5352       if (aAfterWhitespace) {
5353         mSeenNonPunctuationSinceWhitespace = false;
5354       } else if (!aAfterPunctuation) {
5355         mSeenNonPunctuationSinceWhitespace = true;
5356       }
5357       mAtStart = false;
5358     }
5359   };
5360 
5361   /**
5362    * Search the frame for the next word boundary
5363    * @param  aForward [in] Are we moving forward (or backward) in content order.
5364    * @param  aWordSelectEatSpace [in] true: look for non-whitespace following
5365    *         whitespace (in the direction of movement).
5366    *         false: look for whitespace following non-whitespace (in the
5367    *         direction  of movement).
5368    * @param  aIsKeyboardSelect [in] Was the action initiated by a keyboard
5369    * operation? If true, punctuation immediately following a word is considered
5370    * part of that word. Otherwise, a sequence of punctuation is always
5371    * considered as a word on its own.
5372    * @param  aOffset [in/out] At what offset into the frame to start looking.
5373    *         on output - what offset was reached (whether or not we found a
5374    * place to stop).
5375    * @param  aState [in/out] the state that is carried from frame to frame
5376    */
5377   virtual FrameSearchResult PeekOffsetWord(
5378       bool aForward, bool aWordSelectEatSpace, bool aIsKeyboardSelect,
5379       int32_t* aOffset, PeekWordState* aState, bool aTrimSpaces);
5380 
5381  protected:
5382   /**
5383    * Check whether we should break at a boundary between punctuation and
5384    * non-punctuation. Only call it at a punctuation boundary
5385    * (i.e. exactly one of the previous and next characters are punctuation).
5386    * @param aForward true if we're moving forward in content order
5387    * @param aPunctAfter true if the next character is punctuation
5388    * @param aWhitespaceAfter true if the next character is whitespace
5389    */
5390   static bool BreakWordBetweenPunctuation(const PeekWordState* aState,
5391                                           bool aForward, bool aPunctAfter,
5392                                           bool aWhitespaceAfter,
5393                                           bool aIsKeyboardSelect);
5394 
5395  private:
5396   // Get a pointer to the overflow areas property attached to the frame.
GetOverflowAreasProperty()5397   mozilla::OverflowAreas* GetOverflowAreasProperty() const {
5398     MOZ_ASSERT(mOverflow.mType == OverflowStorageType::Large);
5399     mozilla::OverflowAreas* overflow = GetProperty(OverflowAreasProperty());
5400     MOZ_ASSERT(overflow);
5401     return overflow;
5402   }
5403 
InkOverflowFromDeltas()5404   nsRect InkOverflowFromDeltas() const {
5405     MOZ_ASSERT(mOverflow.mType != OverflowStorageType::Large,
5406                "should not be called when overflow is in a property");
5407     // Calculate the rect using deltas from the frame's border rect.
5408     // Note that the mOverflow.mInkOverflowDeltas fields are unsigned, but we
5409     // will often need to return negative values for the left and top, so take
5410     // care to cast away the unsigned-ness.
5411     return nsRect(-(int32_t)mOverflow.mInkOverflowDeltas.mLeft,
5412                   -(int32_t)mOverflow.mInkOverflowDeltas.mTop,
5413                   mRect.Width() + mOverflow.mInkOverflowDeltas.mRight +
5414                       mOverflow.mInkOverflowDeltas.mLeft,
5415                   mRect.Height() + mOverflow.mInkOverflowDeltas.mBottom +
5416                       mOverflow.mInkOverflowDeltas.mTop);
5417   }
5418 
5419   /**
5420    * Set the OverflowArea rect, storing it as deltas or a separate rect
5421    * depending on its size in relation to the primary frame rect.
5422    *
5423    * @return true if any overflow changed.
5424    */
5425   bool SetOverflowAreas(const mozilla::OverflowAreas& aOverflowAreas);
5426 
5427   bool HasOpacityInternal(float aThreshold, const nsStyleDisplay* aStyleDisplay,
5428                           const nsStyleEffects* aStyleEffects,
5429                           mozilla::EffectSet* aEffectSet = nullptr) const;
5430 
5431   // Maps mClass to LayoutFrameType.
5432   static const mozilla::LayoutFrameType sLayoutFrameTypes[
5433 #define FRAME_ID(...) 1 +
5434 #define ABSTRACT_FRAME_ID(...)
5435 #include "mozilla/FrameIdList.h"
5436 #undef FRAME_ID
5437 #undef ABSTRACT_FRAME_ID
5438       0];
5439 
5440   enum FrameClassBits {
5441     eFrameClassBitsNone = 0x0,
5442     eFrameClassBitsLeaf = 0x1,
5443     eFrameClassBitsDynamicLeaf = 0x2,
5444   };
5445   // Maps mClass to IsLeaf() flags.
5446   static const FrameClassBits sFrameClassBits[
5447 #define FRAME_ID(...) 1 +
5448 #define ABSTRACT_FRAME_ID(...)
5449 #include "mozilla/FrameIdList.h"
5450 #undef FRAME_ID
5451 #undef ABSTRACT_FRAME_ID
5452       0];
5453 
5454 #ifdef DEBUG_FRAME_DUMP
5455  public:
IndentBy(FILE * out,int32_t aIndent)5456   static void IndentBy(FILE* out, int32_t aIndent) {
5457     while (--aIndent >= 0) fputs("  ", out);
5458   }
ListTag(FILE * out)5459   void ListTag(FILE* out) const { fputs(ListTag().get(), out); }
5460   nsAutoCString ListTag() const;
5461 
5462   enum class ListFlag{TraverseSubdocumentFrames, DisplayInCSSPixels};
5463   using ListFlags = mozilla::EnumSet<ListFlag>;
5464 
5465   template <typename T>
ConvertToString(const T & aValue,ListFlags aFlags)5466   static std::string ConvertToString(const T& aValue, ListFlags aFlags) {
5467     // This method can convert all physical types in app units to CSS pixels.
5468     return aFlags.contains(ListFlag::DisplayInCSSPixels)
5469                ? mozilla::ToString(mozilla::CSSPixel::FromAppUnits(aValue))
5470                : mozilla::ToString(aValue);
5471   }
5472   static std::string ConvertToString(const mozilla::LogicalRect& aRect,
5473                                      const mozilla::WritingMode aWM,
5474                                      ListFlags aFlags);
5475   static std::string ConvertToString(const mozilla::LogicalSize& aSize,
5476                                      const mozilla::WritingMode aWM,
5477                                      ListFlags aFlags);
5478 
5479   void ListGeneric(nsACString& aTo, const char* aPrefix = "",
5480                    ListFlags aFlags = ListFlags()) const;
5481   virtual void List(FILE* out = stderr, const char* aPrefix = "",
5482                     ListFlags aFlags = ListFlags()) const;
5483 
5484   void ListTextRuns(FILE* out = stderr) const;
5485   virtual void ListTextRuns(FILE* out, nsTHashSet<const void*>& aSeen) const;
5486 
5487   virtual void ListWithMatchedRules(FILE* out = stderr,
5488                                     const char* aPrefix = "") const;
5489   void ListMatchedRules(FILE* out, const char* aPrefix) const;
5490 
5491   /**
5492    * Dump the frame tree beginning from the root frame.
5493    */
5494   void DumpFrameTree() const;
5495   void DumpFrameTreeInCSSPixels() const;
5496 
5497   /**
5498    * Dump the frame tree beginning from ourselves.
5499    */
5500   void DumpFrameTreeLimited() const;
5501   void DumpFrameTreeLimitedInCSSPixels() const;
5502 
5503   /**
5504    * Get a printable from of the name of the frame type.
5505    * XXX This should be eliminated and we use GetType() instead...
5506    */
5507   virtual nsresult GetFrameName(nsAString& aResult) const;
5508   nsresult MakeFrameName(const nsAString& aType, nsAString& aResult) const;
5509   // Helper function to return the index in parent of the frame's content
5510   // object. Returns -1 on error or if the frame doesn't have a content object
5511   static int32_t ContentIndexInContainer(const nsIFrame* aFrame);
5512 #endif
5513 
5514 #ifdef DEBUG
5515   /**
5516    * Tracing method that writes a method enter/exit routine to the
5517    * nspr log using the nsIFrame log module. The tracing is only
5518    * done when the NS_FRAME_TRACE_CALLS bit is set in the log module's
5519    * level field.
5520    */
5521   void Trace(const char* aMethod, bool aEnter);
5522   void Trace(const char* aMethod, bool aEnter, const nsReflowStatus& aStatus);
5523   void TraceMsg(const char* aFormatString, ...) MOZ_FORMAT_PRINTF(2, 3);
5524 
5525   // Helper function that verifies that each frame in the list has the
5526   // NS_FRAME_IS_DIRTY bit set
5527   static void VerifyDirtyBitSet(const nsFrameList& aFrameList);
5528 
5529   // Display Reflow Debugging
5530   static void* DisplayReflowEnter(nsPresContext* aPresContext, nsIFrame* aFrame,
5531                                   const ReflowInput& aReflowInput);
5532   static void* DisplayLayoutEnter(nsIFrame* aFrame);
5533   static void* DisplayIntrinsicISizeEnter(nsIFrame* aFrame, const char* aType);
5534   static void* DisplayIntrinsicSizeEnter(nsIFrame* aFrame, const char* aType);
5535   static void DisplayReflowExit(nsPresContext* aPresContext, nsIFrame* aFrame,
5536                                 ReflowOutput& aMetrics,
5537                                 const nsReflowStatus& aStatus,
5538                                 void* aFrameTreeNode);
5539   static void DisplayLayoutExit(nsIFrame* aFrame, void* aFrameTreeNode);
5540   static void DisplayIntrinsicISizeExit(nsIFrame* aFrame, const char* aType,
5541                                         nscoord aResult, void* aFrameTreeNode);
5542   static void DisplayIntrinsicSizeExit(nsIFrame* aFrame, const char* aType,
5543                                        nsSize aResult, void* aFrameTreeNode);
5544 
5545   static void DisplayReflowStartup();
5546   static void DisplayReflowShutdown();
5547 
5548   static mozilla::LazyLogModule sFrameLogModule;
5549 
5550   // Show frame borders when rendering
5551   static void ShowFrameBorders(bool aEnable);
5552   static bool GetShowFrameBorders();
5553 
5554   // Show frame border of event target
5555   static void ShowEventTargetFrameBorder(bool aEnable);
5556   static bool GetShowEventTargetFrameBorder();
5557 #endif
5558 };
5559 
5560 MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(nsIFrame::PhysicalAxes)
5561 MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(nsIFrame::ReflowChildFlags)
5562 
5563 //----------------------------------------------------------------------
5564 
5565 /**
5566  * AutoWeakFrame can be used to keep a reference to a nsIFrame in a safe way.
5567  * Whenever an nsIFrame object is deleted, the AutoWeakFrames pointing
5568  * to it will be cleared.  AutoWeakFrame is for variables on the stack or
5569  * in static storage only, there is also a WeakFrame below for heap uses.
5570  *
5571  * Create AutoWeakFrame object when it is sure that nsIFrame object
5572  * is alive and after some operations which may destroy the nsIFrame
5573  * (for example any DOM modifications) use IsAlive() or GetFrame() methods to
5574  * check whether it is safe to continue to use the nsIFrame object.
5575  *
5576  * @note The usage of this class should be kept to a minimum.
5577  */
5578 class WeakFrame;
5579 class MOZ_NONHEAP_CLASS AutoWeakFrame {
5580  public:
AutoWeakFrame()5581   explicit AutoWeakFrame() : mPrev(nullptr), mFrame(nullptr) {}
5582 
AutoWeakFrame(const AutoWeakFrame & aOther)5583   AutoWeakFrame(const AutoWeakFrame& aOther) : mPrev(nullptr), mFrame(nullptr) {
5584     Init(aOther.GetFrame());
5585   }
5586 
5587   MOZ_IMPLICIT AutoWeakFrame(const WeakFrame& aOther);
5588 
AutoWeakFrame(nsIFrame * aFrame)5589   MOZ_IMPLICIT AutoWeakFrame(nsIFrame* aFrame)
5590       : mPrev(nullptr), mFrame(nullptr) {
5591     Init(aFrame);
5592   }
5593 
5594   AutoWeakFrame& operator=(AutoWeakFrame& aOther) {
5595     Init(aOther.GetFrame());
5596     return *this;
5597   }
5598 
5599   AutoWeakFrame& operator=(nsIFrame* aFrame) {
5600     Init(aFrame);
5601     return *this;
5602   }
5603 
5604   nsIFrame* operator->() { return mFrame; }
5605 
5606   operator nsIFrame*() { return mFrame; }
5607 
5608   void Clear(mozilla::PresShell* aPresShell);
5609 
IsAlive()5610   bool IsAlive() const { return !!mFrame; }
5611 
GetFrame()5612   nsIFrame* GetFrame() const { return mFrame; }
5613 
GetPreviousWeakFrame()5614   AutoWeakFrame* GetPreviousWeakFrame() { return mPrev; }
5615 
SetPreviousWeakFrame(AutoWeakFrame * aPrev)5616   void SetPreviousWeakFrame(AutoWeakFrame* aPrev) { mPrev = aPrev; }
5617 
5618   ~AutoWeakFrame();
5619 
5620  private:
5621   // Not available for the heap!
5622   void* operator new(size_t) = delete;
5623   void* operator new[](size_t) = delete;
5624   void operator delete(void*) = delete;
5625   void operator delete[](void*) = delete;
5626 
5627   void Init(nsIFrame* aFrame);
5628 
5629   AutoWeakFrame* mPrev;
5630   nsIFrame* mFrame;
5631 };
5632 
5633 // Use nsIFrame's fast-path to avoid QueryFrame:
do_QueryFrame(AutoWeakFrame & s)5634 inline do_QueryFrameHelper<nsIFrame> do_QueryFrame(AutoWeakFrame& s) {
5635   return do_QueryFrameHelper<nsIFrame>(s.GetFrame());
5636 }
5637 
5638 /**
5639  * @see AutoWeakFrame
5640  */
5641 class MOZ_HEAP_CLASS WeakFrame {
5642  public:
WeakFrame()5643   WeakFrame() : mFrame(nullptr) {}
5644 
WeakFrame(const WeakFrame & aOther)5645   WeakFrame(const WeakFrame& aOther) : mFrame(nullptr) {
5646     Init(aOther.GetFrame());
5647   }
5648 
WeakFrame(const AutoWeakFrame & aOther)5649   MOZ_IMPLICIT WeakFrame(const AutoWeakFrame& aOther) : mFrame(nullptr) {
5650     Init(aOther.GetFrame());
5651   }
5652 
WeakFrame(nsIFrame * aFrame)5653   MOZ_IMPLICIT WeakFrame(nsIFrame* aFrame) : mFrame(nullptr) { Init(aFrame); }
5654 
~WeakFrame()5655   ~WeakFrame() {
5656     Clear(mFrame ? mFrame->PresContext()->GetPresShell() : nullptr);
5657   }
5658 
5659   WeakFrame& operator=(WeakFrame& aOther) {
5660     Init(aOther.GetFrame());
5661     return *this;
5662   }
5663 
5664   WeakFrame& operator=(nsIFrame* aFrame) {
5665     Init(aFrame);
5666     return *this;
5667   }
5668 
5669   nsIFrame* operator->() { return mFrame; }
5670   operator nsIFrame*() { return mFrame; }
5671 
5672   void Clear(mozilla::PresShell* aPresShell);
5673 
IsAlive()5674   bool IsAlive() const { return !!mFrame; }
GetFrame()5675   nsIFrame* GetFrame() const { return mFrame; }
5676 
5677  private:
5678   void Init(nsIFrame* aFrame);
5679 
5680   nsIFrame* mFrame;
5681 };
5682 
5683 // Use nsIFrame's fast-path to avoid QueryFrame:
do_QueryFrame(WeakFrame & s)5684 inline do_QueryFrameHelper<nsIFrame> do_QueryFrame(WeakFrame& s) {
5685   return do_QueryFrameHelper<nsIFrame>(s.GetFrame());
5686 }
5687 
ContinueRemoveFrame(nsIFrame * aFrame)5688 inline bool nsFrameList::ContinueRemoveFrame(nsIFrame* aFrame) {
5689   MOZ_ASSERT(!aFrame->GetPrevSibling() || !aFrame->GetNextSibling(),
5690              "Forgot to call StartRemoveFrame?");
5691   if (aFrame == mLastChild) {
5692     MOZ_ASSERT(!aFrame->GetNextSibling(), "broken frame list");
5693     nsIFrame* prevSibling = aFrame->GetPrevSibling();
5694     if (!prevSibling) {
5695       MOZ_ASSERT(aFrame == mFirstChild, "broken frame list");
5696       mFirstChild = mLastChild = nullptr;
5697       return true;
5698     }
5699     MOZ_ASSERT(prevSibling->GetNextSibling() == aFrame, "Broken frame linkage");
5700     prevSibling->SetNextSibling(nullptr);
5701     mLastChild = prevSibling;
5702     return true;
5703   }
5704   if (aFrame == mFirstChild) {
5705     MOZ_ASSERT(!aFrame->GetPrevSibling(), "broken frame list");
5706     mFirstChild = aFrame->GetNextSibling();
5707     aFrame->SetNextSibling(nullptr);
5708     MOZ_ASSERT(mFirstChild, "broken frame list");
5709     return true;
5710   }
5711   return false;
5712 }
5713 
StartRemoveFrame(nsIFrame * aFrame)5714 inline bool nsFrameList::StartRemoveFrame(nsIFrame* aFrame) {
5715   if (aFrame->GetPrevSibling() && aFrame->GetNextSibling()) {
5716     UnhookFrameFromSiblings(aFrame);
5717     return true;
5718   }
5719   return ContinueRemoveFrame(aFrame);
5720 }
5721 
Next()5722 inline void nsFrameList::Enumerator::Next() {
5723   NS_ASSERTION(!AtEnd(), "Should have checked AtEnd()!");
5724   mFrame = mFrame->GetNextSibling();
5725 }
5726 
FrameLinkEnumerator(const nsFrameList & aList,nsIFrame * aPrevFrame)5727 inline nsFrameList::FrameLinkEnumerator::FrameLinkEnumerator(
5728     const nsFrameList& aList, nsIFrame* aPrevFrame)
5729     : Enumerator(aList) {
5730   mPrev = aPrevFrame;
5731   mFrame = aPrevFrame ? aPrevFrame->GetNextSibling() : aList.FirstChild();
5732 }
5733 
Next()5734 inline void nsFrameList::FrameLinkEnumerator::Next() {
5735   mPrev = mFrame;
5736   Enumerator::Next();
5737 }
5738 
5739 template <typename Predicate>
Find(Predicate && aPredicate)5740 inline void nsFrameList::FrameLinkEnumerator::Find(Predicate&& aPredicate) {
5741   static_assert(
5742       std::is_same<typename mozilla::FunctionTypeTraits<Predicate>::ReturnType,
5743                    bool>::value &&
5744           mozilla::FunctionTypeTraits<Predicate>::arity == 1 &&
5745           std::is_same<typename mozilla::FunctionTypeTraits<
5746                            Predicate>::template ParameterType<0>,
5747                        nsIFrame*>::value,
5748       "aPredicate should be of this function signature: bool(nsIFrame*)");
5749 
5750   for (; !AtEnd(); Next()) {
5751     if (aPredicate(mFrame)) {
5752       return;
5753     }
5754   }
5755 }
5756 
5757 // Operators of nsFrameList::Iterator
5758 // ---------------------------------------------------
5759 
5760 inline nsFrameList::Iterator& nsFrameList::Iterator::operator++() {
5761   mCurrent = mCurrent->GetNextSibling();
5762   return *this;
5763 }
5764 
5765 inline nsFrameList::Iterator& nsFrameList::Iterator::operator--() {
5766   if (!mCurrent) {
5767     mCurrent = mList.LastChild();
5768   } else {
5769     mCurrent = mCurrent->GetPrevSibling();
5770   }
5771   return *this;
5772 }
5773 
5774 #endif /* nsIFrame_h___ */
5775