Bug 1568157 - Part 5: Move the NodePicker initialization into a getter. r=yulia
[gecko.git] / layout / generic / nsIFrame.h
blob5b5343c3461a24db0894bd5a55921fe15f7614f7
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/. */
7 /* interface for all rendering objects */
9 #ifndef nsIFrame_h___
10 #define nsIFrame_h___
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
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).
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.
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.
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
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 */
49 #include <algorithm>
50 #include <stdio.h>
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/Maybe.h"
58 #include "mozilla/SmallPointerArray.h"
59 #include "mozilla/WritingModes.h"
60 #include "nsDirection.h"
61 #include "nsFrameList.h"
62 #include "nsFrameState.h"
63 #include "mozilla/ReflowOutput.h"
64 #include "nsITheme.h"
65 #include "nsLayoutUtils.h"
66 #include "nsQueryFrame.h"
67 #include "nsString.h"
68 #include "mozilla/ComputedStyle.h"
69 #include "nsStyleStruct.h"
70 #include "Visibility.h"
71 #include "nsChangeHint.h"
72 #include "mozilla/ComputedStyleInlines.h"
73 #include "mozilla/gfx/CompositorHitTestInfo.h"
74 #include "mozilla/gfx/MatrixFwd.h"
75 #include "nsDisplayItemTypes.h"
77 #ifdef ACCESSIBILITY
78 # include "mozilla/a11y/AccTypes.h"
79 #endif
81 /**
82 * New rules of reflow:
83 * 1. you get a WillReflow() followed by a Reflow() followed by a DidReflow() in
84 * order (no separate pass over the tree)
85 * 2. it's the parent frame's responsibility to size/position the child's view
86 * (not the child frame's responsibility as it is today) during reflow (and
87 * before sending the DidReflow() notification)
88 * 3. positioning of child frames (and their views) is done on the way down the
89 * tree, and sizing of child frames (and their views) on the way back up
90 * 4. if you move a frame (outside of the reflow process, or after reflowing
91 * it), then you must make sure that its view (or its child frame's views)
92 * are re-positioned as well. It's reasonable to not position the view until
93 * after all reflowing the entire line, for example, but the frame should
94 * still be positioned and sized (and the view sized) during the reflow
95 * (i.e., before sending the DidReflow() notification)
96 * 5. the view system handles moving of widgets, i.e., it's not our problem
99 class nsAtom;
100 class nsPresContext;
101 class nsView;
102 class nsIWidget;
103 class nsISelectionController;
104 class nsBoxLayoutState;
105 class nsBoxLayout;
106 class nsILineIterator;
107 class nsDisplayItemBase;
108 class nsDisplayListBuilder;
109 class nsDisplayListSet;
110 class nsDisplayList;
111 class gfxSkipChars;
112 class gfxSkipCharsIterator;
113 class gfxContext;
114 class nsLineList_iterator;
115 class nsAbsoluteContainingBlock;
116 class nsIContent;
117 class nsContainerFrame;
118 class nsPlaceholderFrame;
119 class nsStyleChangeList;
120 class nsWindowSizes;
122 struct nsPeekOffsetStruct;
123 struct nsPoint;
124 struct nsRect;
125 struct nsSize;
126 struct nsMargin;
127 struct CharacterDataChangeInfo;
129 namespace mozilla {
131 enum class PseudoStyleType : uint8_t;
132 class EventStates;
133 class PresShell;
134 struct ReflowInput;
135 class ReflowOutput;
136 class ServoRestyleState;
137 class DisplayItemData;
138 class EffectSet;
140 namespace layers {
141 class Layer;
142 class LayerManager;
143 } // namespace layers
145 namespace layout {
146 class ScrollAnchorContainer;
147 } // namespace layout
149 namespace dom {
150 class Selection;
151 } // namespace dom
153 } // namespace mozilla
155 //----------------------------------------------------------------------
157 #define NS_SUBTREE_DIRTY(_frame) \
158 (((_frame)->GetStateBits() & \
159 (NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN)) != 0)
161 // 1 million CSS pixels less than our max app unit measure.
162 // For reflowing with an "infinite" available inline space per [css-sizing].
163 // (reflowing with an NS_UNCONSTRAINEDSIZE available inline size isn't allowed
164 // and leads to assertions)
165 #define INFINITE_ISIZE_COORD nscoord(NS_MAXSIZE - (1000000 * 60))
167 //----------------------------------------------------------------------
169 namespace mozilla {
171 enum class LayoutFrameType : uint8_t {
172 #define FRAME_TYPE(ty_, ...) ty_,
173 #include "mozilla/FrameTypeList.h"
174 #undef FRAME_TYPE
177 } // namespace mozilla
179 enum nsSelectionAmount {
180 eSelectCharacter = 0, // a single Unicode character;
181 // do not use this (prefer Cluster) unless you
182 // are really sure it's what you want
183 eSelectCluster = 1, // a grapheme cluster: this is usually the right
184 // choice for movement or selection by "character"
185 // as perceived by the user
186 eSelectWord = 2,
187 eSelectWordNoSpace = 3, // select a "word" without selecting the following
188 // space, no matter what the default platform
189 // behavior is
190 eSelectLine = 4, // previous drawn line in flow.
191 // NOTE that selection code depends on the ordering of the above values,
192 // allowing simple <= tests to check categories of caret movement.
193 // Don't rearrange without checking the usage in nsSelection.cpp!
195 eSelectBeginLine = 5,
196 eSelectEndLine = 6,
197 eSelectNoAmount = 7, // just bounce back current offset.
198 eSelectParagraph = 8 // select a "paragraph"
201 //----------------------------------------------------------------------
202 // Reflow status returned by the Reflow() methods.
203 class nsReflowStatus final {
204 using StyleClear = mozilla::StyleClear;
206 public:
207 nsReflowStatus()
208 : mBreakType(StyleClear::None),
209 mInlineBreak(InlineBreak::None),
210 mCompletion(Completion::FullyComplete),
211 mNextInFlowNeedsReflow(false),
212 mTruncated(false),
213 mFirstLetterComplete(false) {}
215 // Reset all the member variables.
216 void Reset() {
217 mBreakType = StyleClear::None;
218 mInlineBreak = InlineBreak::None;
219 mCompletion = Completion::FullyComplete;
220 mNextInFlowNeedsReflow = false;
221 mTruncated = false;
222 mFirstLetterComplete = false;
225 // Return true if all member variables have their default values.
226 bool IsEmpty() const {
227 return (IsFullyComplete() && !IsInlineBreak() && !mNextInFlowNeedsReflow &&
228 !mTruncated && !mFirstLetterComplete);
231 // There are three possible completion statuses, represented by
232 // mCompletion.
234 // Incomplete means the frame does *not* map all its content, and the
235 // parent frame should create a continuing frame.
237 // OverflowIncomplete means that the frame has an overflow that is not
238 // complete, but its own box is complete. (This happens when the content
239 // overflows a fixed-height box.) The reflower should place and size the
240 // frame and continue its reflow, but it needs to create an overflow
241 // container as a continuation for this frame. See "Overflow containers"
242 // documentation in nsContainerFrame.h for more information.
244 // FullyComplete means the frame is neither Incomplete nor
245 // OverflowIncomplete. This is the default state for a nsReflowStatus.
247 enum class Completion : uint8_t {
248 // The order of the enum values is important, which represents the
249 // precedence when merging.
250 FullyComplete,
251 OverflowIncomplete,
252 Incomplete,
255 bool IsIncomplete() const { return mCompletion == Completion::Incomplete; }
256 bool IsOverflowIncomplete() const {
257 return mCompletion == Completion::OverflowIncomplete;
259 bool IsFullyComplete() const {
260 return mCompletion == Completion::FullyComplete;
262 // Just for convenience; not a distinct state.
263 bool IsComplete() const { return !IsIncomplete(); }
265 void SetIncomplete() { mCompletion = Completion::Incomplete; }
266 void SetOverflowIncomplete() { mCompletion = Completion::OverflowIncomplete; }
268 // mNextInFlowNeedsReflow bit flag means that the next-in-flow is dirty,
269 // and also needs to be reflowed. This status only makes sense for a frame
270 // that is not complete, i.e. you wouldn't set mNextInFlowNeedsReflow when
271 // IsComplete() is true.
272 bool NextInFlowNeedsReflow() const { return mNextInFlowNeedsReflow; }
273 void SetNextInFlowNeedsReflow() { mNextInFlowNeedsReflow = true; }
275 // mTruncated bit flag means that the part of the frame before the first
276 // possible break point was unable to fit in the available space.
277 // Therefore, the entire frame should be moved to the next continuation of
278 // the parent frame. A frame that begins at the top of the page must never
279 // be truncated. Doing so would likely cause an infinite loop.
280 bool IsTruncated() const { return mTruncated; }
281 void UpdateTruncated(const mozilla::ReflowInput& aReflowInput,
282 const mozilla::ReflowOutput& aMetrics);
284 // Merge the frame completion status bits from aStatus into this.
285 void MergeCompletionStatusFrom(const nsReflowStatus& aStatus) {
286 if (mCompletion < aStatus.mCompletion) {
287 mCompletion = aStatus.mCompletion;
290 // These asserts ensure that the mCompletion merging works as we expect.
291 // (Incomplete beats OverflowIncomplete, which beats FullyComplete.)
292 static_assert(
293 Completion::Incomplete > Completion::OverflowIncomplete &&
294 Completion::OverflowIncomplete > Completion::FullyComplete,
295 "mCompletion merging won't work without this!");
297 mNextInFlowNeedsReflow |= aStatus.mNextInFlowNeedsReflow;
298 mTruncated |= aStatus.mTruncated;
301 // There are three possible inline-break statuses, represented by
302 // mInlineBreak.
304 // "None" means no break is requested.
305 // "Before" means the break should occur before the frame.
306 // "After" means the break should occur after the frame.
307 // (Here, "the frame" is the frame whose reflow results are being reported by
308 // this nsReflowStatus.)
310 enum class InlineBreak : uint8_t {
311 None,
312 Before,
313 After,
316 bool IsInlineBreak() const { return mInlineBreak != InlineBreak::None; }
317 bool IsInlineBreakBefore() const {
318 return mInlineBreak == InlineBreak::Before;
320 bool IsInlineBreakAfter() const { return mInlineBreak == InlineBreak::After; }
321 StyleClear BreakType() const { return mBreakType; }
323 // Set the inline line-break-before status, and reset other bit flags. The
324 // break type is StyleClear::Line. Note that other frame completion status
325 // isn't expected to matter after calling this method.
326 void SetInlineLineBreakBeforeAndReset() {
327 Reset();
328 mBreakType = StyleClear::Line;
329 mInlineBreak = InlineBreak::Before;
332 // Set the inline line-break-after status. The break type can be changed
333 // via the optional aBreakType param.
334 void SetInlineLineBreakAfter(StyleClear aBreakType = StyleClear::Line) {
335 MOZ_ASSERT(aBreakType != StyleClear::None,
336 "Break-after with StyleClear::None is meaningless!");
337 mBreakType = aBreakType;
338 mInlineBreak = InlineBreak::After;
341 // mFirstLetterComplete bit flag means the break was induced by
342 // completion of a first-letter.
343 bool FirstLetterComplete() const { return mFirstLetterComplete; }
344 void SetFirstLetterComplete() { mFirstLetterComplete = true; }
346 private:
347 StyleClear mBreakType;
348 InlineBreak mInlineBreak;
349 Completion mCompletion;
350 bool mNextInFlowNeedsReflow : 1;
351 bool mTruncated : 1;
352 bool mFirstLetterComplete : 1;
355 #define NS_FRAME_SET_TRUNCATION(aStatus, aReflowInput, aMetrics) \
356 aStatus.UpdateTruncated(aReflowInput, aMetrics);
358 // Convert nsReflowStatus to a human-readable string.
359 std::ostream& operator<<(std::ostream& aStream, const nsReflowStatus& aStatus);
361 //----------------------------------------------------------------------
364 * When there is no scrollable overflow rect, the visual overflow rect
365 * may be stored as four 1-byte deltas each strictly LESS THAN 0xff, for
366 * the four edges of the rectangle, or the four bytes may be read as a
367 * single 32-bit "overflow-rect type" value including at least one 0xff
368 * byte as an indicator that the value does NOT represent four deltas.
369 * If all four deltas are zero, this means that no overflow rect has
370 * actually been set (this is the initial state of newly-created frames).
373 // max delta we can store
374 #define NS_FRAME_OVERFLOW_DELTA_MAX 0xfe
376 // there are no overflow rects; code relies on this being the all-zero value
377 #define NS_FRAME_OVERFLOW_NONE 0x00000000
379 // overflow is stored as a separate rect property
380 #define NS_FRAME_OVERFLOW_LARGE 0x000000ff
383 * nsBidiLevel is the type of the level values in our Unicode Bidi
384 * implementation.
385 * It holds an embedding level and indicates the visual direction
386 * by its bit 0 (even/odd value).<p>
388 * <li><code>aParaLevel</code> can be set to the
389 * pseudo-level values <code>NSBIDI_DEFAULT_LTR</code>
390 * and <code>NSBIDI_DEFAULT_RTL</code>.</li></ul>
392 * @see nsBidi::SetPara
394 * <p>The related constants are not real, valid level values.
395 * <code>NSBIDI_DEFAULT_XXX</code> can be used to specify
396 * a default for the paragraph level for
397 * when the <code>SetPara</code> function
398 * shall determine it but there is no
399 * strongly typed character in the input.<p>
401 * Note that the value for <code>NSBIDI_DEFAULT_LTR</code> is even
402 * and the one for <code>NSBIDI_DEFAULT_RTL</code> is odd,
403 * just like with normal LTR and RTL level values -
404 * these special values are designed that way. Also, the implementation
405 * assumes that NSBIDI_MAX_EXPLICIT_LEVEL is odd.
407 * @see NSBIDI_DEFAULT_LTR
408 * @see NSBIDI_DEFAULT_RTL
409 * @see NSBIDI_LEVEL_OVERRIDE
410 * @see NSBIDI_MAX_EXPLICIT_LEVEL
412 typedef uint8_t nsBidiLevel;
415 * Paragraph level setting.
416 * If there is no strong character, then set the paragraph level to 0
417 * (left-to-right).
419 #define NSBIDI_DEFAULT_LTR 0xfe
422 * Paragraph level setting.
423 * If there is no strong character, then set the paragraph level to 1
424 * (right-to-left).
426 #define NSBIDI_DEFAULT_RTL 0xff
429 * Maximum explicit embedding level.
430 * (The maximum resolved level can be up to
431 * <code>NSBIDI_MAX_EXPLICIT_LEVEL+1</code>).
433 #define NSBIDI_MAX_EXPLICIT_LEVEL 125
435 /** Bit flag for level input.
436 * Overrides directional properties.
438 #define NSBIDI_LEVEL_OVERRIDE 0x80
441 * <code>nsBidiDirection</code> values indicate the text direction.
443 enum nsBidiDirection {
444 /** All left-to-right text This is a 0 value. */
445 NSBIDI_LTR,
446 /** All right-to-left text This is a 1 value. */
447 NSBIDI_RTL,
448 /** Mixed-directional text. */
449 NSBIDI_MIXED
452 namespace mozilla {
454 // https://drafts.csswg.org/css-align-3/#baseline-sharing-group
455 enum class BaselineSharingGroup {
456 // NOTE Used as an array index so must be 0 and 1.
457 First = 0,
458 Last = 1,
461 // Loosely: https://drafts.csswg.org/css-align-3/#shared-alignment-context
462 enum class AlignmentContext {
463 Inline,
464 Table,
465 Flexbox,
466 Grid,
470 * For replaced elements only. Gets the intrinsic dimensions of this element,
471 * which can be specified on a per-axis basis.
473 struct IntrinsicSize {
474 Maybe<nscoord> width;
475 Maybe<nscoord> height;
477 IntrinsicSize() = default;
479 IntrinsicSize(nscoord aWidth, nscoord aHeight)
480 : width(Some(aWidth)), height(Some(aHeight)) {}
482 bool operator==(const IntrinsicSize& rhs) {
483 return width == rhs.width && height == rhs.height;
485 bool operator!=(const IntrinsicSize& rhs) { return !(*this == rhs); }
488 // Pseudo bidi embedding level indicating nonexistence.
489 static const nsBidiLevel kBidiLevelNone = 0xff;
491 struct FrameBidiData {
492 nsBidiLevel baseLevel;
493 nsBidiLevel embeddingLevel;
494 // The embedding level of virtual bidi formatting character before
495 // this frame if any. kBidiLevelNone is used to indicate nonexistence
496 // or unnecessity of such virtual character.
497 nsBidiLevel precedingControl;
500 } // namespace mozilla
502 /// Generic destructor for frame properties. Calls delete.
503 template <typename T>
504 static void DeleteValue(T* aPropertyValue) {
505 delete aPropertyValue;
508 /// Generic destructor for frame properties. Calls Release().
509 template <typename T>
510 static void ReleaseValue(T* aPropertyValue) {
511 aPropertyValue->Release();
514 //----------------------------------------------------------------------
517 * A frame in the layout model. This interface is supported by all frame
518 * objects.
520 * Frames can have multiple child lists: the default child list
521 * (referred to as the <i>principal</i> child list, and additional named
522 * child lists. There is an ordering of frames within a child list, but
523 * there is no order defined between frames in different child lists of
524 * the same parent frame.
526 * Frames are NOT reference counted. Use the Destroy() member function
527 * to destroy a frame. The lifetime of the frame hierarchy is bounded by the
528 * lifetime of the presentation shell which owns the frames.
530 * nsIFrame is a private Gecko interface. If you are not Gecko then you
531 * should not use it. If you're not in layout, then you won't be able to
532 * link to many of the functions defined here. Too bad.
534 * If you're not in layout but you must call functions in here, at least
535 * restrict yourself to calling virtual methods, which won't hurt you as badly.
537 class nsIFrame : public nsQueryFrame {
538 public:
539 using AlignmentContext = mozilla::AlignmentContext;
540 using BaselineSharingGroup = mozilla::BaselineSharingGroup;
541 template <typename T>
542 using Maybe = mozilla::Maybe<T>;
543 using Nothing = mozilla::Nothing;
544 using OnNonvisible = mozilla::OnNonvisible;
545 template <typename T = void>
546 using PropertyDescriptor = const mozilla::FramePropertyDescriptor<T>*;
547 using ReflowInput = mozilla::ReflowInput;
548 using ReflowOutput = mozilla::ReflowOutput;
549 using Visibility = mozilla::Visibility;
550 using StyleFlexBasis = mozilla::StyleFlexBasis;
551 using StyleSize = mozilla::StyleSize;
552 using LengthPercentage = mozilla::LengthPercentage;
553 using StyleExtremumLength = mozilla::StyleExtremumLength;
555 typedef mozilla::ComputedStyle ComputedStyle;
556 typedef mozilla::FrameProperties FrameProperties;
557 typedef mozilla::layers::Layer Layer;
558 typedef mozilla::layers::LayerManager LayerManager;
559 typedef mozilla::layout::FrameChildList ChildList;
560 typedef mozilla::layout::FrameChildListID ChildListID;
561 typedef mozilla::layout::FrameChildListIDs ChildListIDs;
562 typedef mozilla::layout::FrameChildListIterator ChildListIterator;
563 typedef mozilla::layout::FrameChildListArrayIterator ChildListArrayIterator;
564 typedef mozilla::gfx::DrawTarget DrawTarget;
565 typedef mozilla::gfx::Matrix Matrix;
566 typedef mozilla::gfx::Matrix4x4 Matrix4x4;
567 typedef mozilla::gfx::Matrix4x4Flagged Matrix4x4Flagged;
568 typedef mozilla::Sides Sides;
569 typedef mozilla::LogicalSides LogicalSides;
570 typedef mozilla::SmallPointerArray<mozilla::DisplayItemData>
571 DisplayItemDataArray;
572 typedef nsQueryFrame::ClassID ClassID;
574 NS_DECL_QUERYFRAME_TARGET(nsIFrame)
576 explicit nsIFrame(ComputedStyle* aStyle, nsPresContext* aPresContext,
577 ClassID aID)
578 : mRect(),
579 mContent(nullptr),
580 mComputedStyle(aStyle),
581 mPresContext(aPresContext),
582 mParent(nullptr),
583 mNextSibling(nullptr),
584 mPrevSibling(nullptr),
585 mState(NS_FRAME_FIRST_REFLOW | NS_FRAME_IS_DIRTY),
586 mWritingMode(aStyle),
587 mClass(aID),
588 mMayHaveRoundedCorners(false),
589 mHasImageRequest(false),
590 mHasFirstLetterChild(false),
591 mParentIsWrapperAnonBox(false),
592 mIsWrapperBoxNeedingRestyle(false),
593 mReflowRequestedForCharDataChange(false),
594 mForceDescendIntoIfVisible(false),
595 mBuiltDisplayList(false),
596 mFrameIsModified(false),
597 mHasOverrideDirtyRegion(false),
598 mMayHaveWillChangeBudget(false),
599 mIsPrimaryFrame(false),
600 mMayHaveTransformAnimation(false),
601 mMayHaveOpacityAnimation(false),
602 mAllDescendantsAreInvisible(false),
603 mHasBSizeChange(false),
604 mInScrollAnchorChain(false),
605 mHasColumnSpanSiblings(false),
606 mDescendantMayDependOnItsStaticPosition(false) {
607 MOZ_ASSERT(mComputedStyle);
608 MOZ_ASSERT(mPresContext);
609 mozilla::PodZero(&mOverflow);
612 nsPresContext* PresContext() const { return mPresContext; }
614 mozilla::PresShell* PresShell() const { return PresContext()->PresShell(); }
617 * Called to initialize the frame. This is called immediately after creating
618 * the frame.
620 * If the frame is a continuing frame, then aPrevInFlow indicates the previous
621 * frame (the frame that was split).
623 * Each subclass that need a view should override this method and call
624 * CreateView() after calling its base class Init().
626 * @param aContent the content object associated with the frame
627 * @param aParent the parent frame
628 * @param aPrevInFlow the prev-in-flow frame
630 virtual void Init(nsIContent* aContent, nsContainerFrame* aParent,
631 nsIFrame* aPrevInFlow) = 0;
633 using PostDestroyData = mozilla::layout::PostFrameDestroyData;
634 struct MOZ_RAII AutoPostDestroyData {
635 explicit AutoPostDestroyData(nsPresContext* aPresContext)
636 : mPresContext(aPresContext) {}
637 ~AutoPostDestroyData() {
638 for (auto& content : mozilla::Reversed(mData.mAnonymousContent)) {
639 nsIFrame::DestroyAnonymousContent(mPresContext, content.forget());
642 nsPresContext* mPresContext;
643 PostDestroyData mData;
646 * Destroys this frame and each of its child frames (recursively calls
647 * Destroy() for each child). If this frame is a first-continuation, this
648 * also removes the frame from the primary frame map and clears undisplayed
649 * content for its content node.
650 * If the frame is a placeholder, it also ensures the out-of-flow frame's
651 * removal and destruction.
653 void Destroy() {
654 AutoPostDestroyData data(PresContext());
655 DestroyFrom(this, data.mData);
656 // Note that |this| is deleted at this point.
660 * Flags for PeekOffsetCharacter, PeekOffsetNoAmount, PeekOffsetWord return
661 * values.
663 enum FrameSearchResult {
664 // Peek found a appropriate offset within frame.
665 FOUND = 0x00,
666 // try next frame for offset.
667 CONTINUE = 0x1,
668 // offset not found because the frame was empty of text.
669 CONTINUE_EMPTY = 0x2 | CONTINUE,
670 // offset not found because the frame didn't contain any text that could be
671 // selected.
672 CONTINUE_UNSELECTABLE = 0x4 | CONTINUE,
676 * Options for PeekOffsetCharacter().
678 struct MOZ_STACK_CLASS PeekOffsetCharacterOptions {
679 // Whether to restrict result to valid cursor locations (between grapheme
680 // clusters) - if this is included, maintains "normal" behavior, otherwise,
681 // used for selection by "code unit" (instead of "character")
682 bool mRespectClusters;
683 // Whether to check user-select style value - if this is included, checks
684 // if user-select is all, then, it may return CONTINUE_UNSELECTABLE.
685 bool mIgnoreUserStyleAll;
687 PeekOffsetCharacterOptions()
688 : mRespectClusters(true), mIgnoreUserStyleAll(false) {}
691 protected:
692 friend class nsBlockFrame; // for access to DestroyFrom
695 * Return true if the frame is part of a Selection.
696 * Helper method to implement the public IsSelected() API.
698 virtual bool IsFrameSelected() const;
701 * Implements Destroy(). Do not call this directly except from within a
702 * DestroyFrom() implementation.
704 * @note This will always be called, so it is not necessary to override
705 * Destroy() in subclasses of nsFrame, just DestroyFrom().
707 * @param aDestructRoot is the root of the subtree being destroyed
709 virtual void DestroyFrom(nsIFrame* aDestructRoot,
710 PostDestroyData& aPostDestroyData) = 0;
711 friend class nsFrameList; // needed to pass aDestructRoot through to children
712 friend class nsLineBox; // needed to pass aDestructRoot through to children
713 friend class nsContainerFrame; // needed to pass aDestructRoot through to
714 // children
715 friend class nsFrame; // need to assign mParent
716 template <class Source>
717 friend class do_QueryFrameHelper; // to read mClass
718 public:
720 * Get the content object associated with this frame. Does not add a
721 * reference.
723 nsIContent* GetContent() const { return mContent; }
726 * Get the frame that should be the parent for the frames of child elements
727 * May return nullptr during reflow
729 virtual nsContainerFrame* GetContentInsertionFrame() { return nullptr; }
732 * Move any frames on our overflow list to the end of our principal list.
733 * @return true if there were any overflow frames
735 virtual bool DrainSelfOverflowList() { return false; }
738 * Get the frame that should be scrolled if the content associated
739 * with this frame is targeted for scrolling. For frames implementing
740 * nsIScrollableFrame this will return the frame itself. For frames
741 * like nsTextControlFrame that contain a scrollframe, will return
742 * that scrollframe.
744 virtual nsIScrollableFrame* GetScrollTargetFrame() { return nullptr; }
747 * Get the offsets of the frame. most will be 0,0
750 virtual nsresult GetOffsets(int32_t& start, int32_t& end) const = 0;
753 * Reset the offsets when splitting frames during Bidi reordering
756 virtual void AdjustOffsetsForBidi(int32_t aStart, int32_t aEnd) {}
759 * Get the style associated with this frame.
761 ComputedStyle* Style() const { return mComputedStyle; }
763 void AssertNewStyleIsSane(ComputedStyle&)
764 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
766 #else
769 #endif
771 void SetComputedStyle(ComputedStyle* aStyle) {
772 if (aStyle != mComputedStyle) {
773 AssertNewStyleIsSane(*aStyle);
774 RefPtr<ComputedStyle> oldComputedStyle = mComputedStyle.forget();
775 mComputedStyle = aStyle;
776 DidSetComputedStyle(oldComputedStyle);
781 * SetComputedStyleWithoutNotification is for changes to the style
782 * context that should suppress style change processing, in other
783 * words, those that aren't really changes. This generally means only
784 * changes that happen during frame construction.
786 void SetComputedStyleWithoutNotification(ComputedStyle* aStyle) {
787 if (aStyle != mComputedStyle) {
788 mComputedStyle = aStyle;
792 // Style post processing hook
793 // Attention: the old style is the one we're forgetting,
794 // and hence possibly completely bogus for GetStyle* purposes.
795 // Use PeekStyleData instead.
796 virtual void DidSetComputedStyle(ComputedStyle* aOldComputedStyle) = 0;
799 * Define typesafe getter functions for each style struct by
800 * preprocessing the list of style structs. These functions are the
801 * preferred way to get style data. The macro creates functions like:
802 * const nsStyleBorder* StyleBorder();
803 * const nsStyleColor* StyleColor();
805 * Callers outside of libxul should use nsIDOMWindow::GetComputedStyle()
806 * instead of these accessors.
808 * Callers can use Style*WithOptionalParam if they're in a function that
809 * accepts an *optional* pointer the style struct.
811 #define STYLE_STRUCT(name_) \
812 const nsStyle##name_* Style##name_() const MOZ_NONNULL_RETURN { \
813 NS_ASSERTION(mComputedStyle, "No style found!"); \
814 return mComputedStyle->Style##name_(); \
816 const nsStyle##name_* Style##name_##WithOptionalParam( \
817 const nsStyle##name_* aStyleStruct) const MOZ_NONNULL_RETURN { \
818 if (aStyleStruct) { \
819 MOZ_ASSERT(aStyleStruct == Style##name_()); \
820 return aStyleStruct; \
822 return Style##name_(); \
824 #include "nsStyleStructList.h"
825 #undef STYLE_STRUCT
827 /** Also forward GetVisitedDependentColor to the style */
828 template <typename T, typename S>
829 nscolor GetVisitedDependentColor(T S::*aField) {
830 return mComputedStyle->GetVisitedDependentColor(aField);
834 * These methods are to access any additional ComputedStyles that
835 * the frame may be holding.
837 * These are styles that are children of the frame's primary style and are NOT
838 * used as styles for any child frames.
840 * These contexts also MUST NOT have any child styles whatsoever. If you need
841 * to insert styles into the style tree, then you should create pseudo element
842 * frames to own them.
844 * The indicies must be consecutive and implementations MUST return null if
845 * asked for an index that is out of range.
847 virtual ComputedStyle* GetAdditionalComputedStyle(int32_t aIndex) const = 0;
849 virtual void SetAdditionalComputedStyle(int32_t aIndex,
850 ComputedStyle* aComputedStyle) = 0;
852 already_AddRefed<ComputedStyle> ComputeSelectionStyle(
853 int16_t aSelectionStatus) const;
856 * Accessor functions for geometric parent.
858 nsContainerFrame* GetParent() const { return mParent; }
861 * Gets the parent of a frame, using the parent of the placeholder for
862 * out-of-flow frames.
864 inline nsContainerFrame* GetInFlowParent() const;
867 * Gets the primary frame of the closest flattened tree ancestor that has a
868 * frame (flattened tree ancestors may not have frames in presence of display:
869 * contents).
871 inline nsIFrame* GetClosestFlattenedTreeAncestorPrimaryFrame() const;
874 * Return the placeholder for this frame (which must be out-of-flow).
875 * @note this will only return non-null if |this| is the first-in-flow
876 * although we don't assert that here for legacy reasons.
878 inline nsPlaceholderFrame* GetPlaceholderFrame() const {
879 MOZ_ASSERT(HasAnyStateBits(NS_FRAME_OUT_OF_FLOW));
880 return GetProperty(PlaceholderFrameProperty());
884 * Set this frame's parent to aParent.
885 * If the frame may have moved into or out of a scrollframe's
886 * frame subtree,
887 * StickyScrollContainer::NotifyReparentedFrameAcrossScrollFrameBoundary must
888 * also be called.
890 void SetParent(nsContainerFrame* aParent);
893 * The frame's writing-mode, used for logical layout computations.
894 * It's usually the 'writing-mode' computed value, but there are exceptions:
895 * * inner table frames copy the value from the table frame
896 * (@see nsTableRowGroupFrame::Init, nsTableRowFrame::Init etc)
897 * * the root element frame propagates its value to its ancestors
898 * (@see nsCanvasFrame::MaybePropagateRootElementWritingMode)
899 * * a scrolled frame propagates its value to its ancestor scroll frame
900 * (@see nsHTMLScrollFrame::ReloadChildFrames)
902 mozilla::WritingMode GetWritingMode() const { return mWritingMode; }
905 * Construct a writing mode for line layout in this frame. This is
906 * the writing mode of this frame, except that if this frame is styled with
907 * unicode-bidi:plaintext, we reset the direction to the resolved paragraph
908 * level of the given subframe (typically the first frame on the line),
909 * because the container frame could be split by hard line breaks into
910 * multiple paragraphs with different base direction.
911 * @param aSelfWM the WM of 'this'
913 mozilla::WritingMode WritingModeForLine(mozilla::WritingMode aSelfWM,
914 nsIFrame* aSubFrame) const;
917 * Bounding rect of the frame.
919 * For frames that are laid out according to CSS box model rules the values
920 * are in app units, and the origin is relative to the upper-left of the
921 * geometric parent. The size includes the content area, borders, and
922 * padding.
924 * Frames that are laid out according to SVG's coordinate space based rules
925 * (frames with the NS_FRAME_SVG_LAYOUT bit set, which *excludes*
926 * nsSVGOuterSVGFrame) are different. Many frames of this type do not set or
927 * use mRect, in which case the frame rect is undefined. The exceptions are:
929 * - nsSVGInnerSVGFrame
930 * - SVGGeometryFrame (used for <path>, <circle>, etc.)
931 * - nsSVGImageFrame
932 * - nsSVGForeignObjectFrame
934 * For these frames the frame rect contains the frame's element's userspace
935 * bounds including fill, stroke and markers, but converted to app units
936 * rather than being in user units (CSS px). In the SVG code "userspace" is
937 * defined to be the coordinate system for the attributes that define an
938 * element's geometry (such as the 'cx' attribute for <circle>). For more
939 * precise details see these frames' implementations of the ReflowSVG method
940 * where mRect is set.
942 * Note: moving or sizing the frame does not affect the view's size or
943 * position.
945 nsRect GetRect() const { return mRect; }
946 nsPoint GetPosition() const { return mRect.TopLeft(); }
947 nsSize GetSize() const { return mRect.Size(); }
948 nsRect GetRectRelativeToSelf() const {
949 return nsRect(nsPoint(0, 0), mRect.Size());
952 * Dimensions and position in logical coordinates in the frame's writing mode
953 * or another writing mode
955 mozilla::LogicalRect GetLogicalRect(const nsSize& aContainerSize) const {
956 return GetLogicalRect(GetWritingMode(), aContainerSize);
958 mozilla::LogicalPoint GetLogicalPosition(const nsSize& aContainerSize) const {
959 return GetLogicalPosition(GetWritingMode(), aContainerSize);
961 mozilla::LogicalSize GetLogicalSize() const {
962 return GetLogicalSize(GetWritingMode());
964 mozilla::LogicalRect GetLogicalRect(mozilla::WritingMode aWritingMode,
965 const nsSize& aContainerSize) const {
966 return mozilla::LogicalRect(aWritingMode, GetRect(), aContainerSize);
968 mozilla::LogicalPoint GetLogicalPosition(mozilla::WritingMode aWritingMode,
969 const nsSize& aContainerSize) const {
970 return GetLogicalRect(aWritingMode, aContainerSize).Origin(aWritingMode);
972 mozilla::LogicalSize GetLogicalSize(mozilla::WritingMode aWritingMode) const {
973 return mozilla::LogicalSize(aWritingMode, GetSize());
975 nscoord IStart(const nsSize& aContainerSize) const {
976 return IStart(GetWritingMode(), aContainerSize);
978 nscoord IStart(mozilla::WritingMode aWritingMode,
979 const nsSize& aContainerSize) const {
980 return GetLogicalPosition(aWritingMode, aContainerSize).I(aWritingMode);
982 nscoord BStart(const nsSize& aContainerSize) const {
983 return BStart(GetWritingMode(), aContainerSize);
985 nscoord BStart(mozilla::WritingMode aWritingMode,
986 const nsSize& aContainerSize) const {
987 return GetLogicalPosition(aWritingMode, aContainerSize).B(aWritingMode);
989 nscoord ISize() const { return ISize(GetWritingMode()); }
990 nscoord ISize(mozilla::WritingMode aWritingMode) const {
991 return GetLogicalSize(aWritingMode).ISize(aWritingMode);
993 nscoord BSize() const { return BSize(GetWritingMode()); }
994 nscoord BSize(mozilla::WritingMode aWritingMode) const {
995 return GetLogicalSize(aWritingMode).BSize(aWritingMode);
997 nscoord ContentBSize() const { return ContentBSize(GetWritingMode()); }
998 nscoord ContentBSize(mozilla::WritingMode aWritingMode) const {
999 auto bp = GetLogicalUsedBorderAndPadding(aWritingMode);
1000 bp.ApplySkipSides(GetLogicalSkipSides());
1001 return std::max(0, BSize(aWritingMode) - bp.BStartEnd(aWritingMode));
1005 * When we change the size of the frame's border-box rect, we may need to
1006 * reset the overflow rect if it was previously stored as deltas.
1007 * (If it is currently a "large" overflow and could be re-packed as deltas,
1008 * we don't bother as the cost of the allocation has already been paid.)
1009 * @param aRebuildDisplayItems If true, then adds this frame to the
1010 * list of modified frames for display list building if the rect has changed.
1011 * Only pass false if you're sure that the relevant display items will be
1012 * rebuilt already (possibly by an ancestor being in the modified list), or if
1013 * this is a temporary change.
1015 void SetRect(const nsRect& aRect, bool aRebuildDisplayItems = true) {
1016 if (aRect == mRect) {
1017 return;
1019 if (mOverflow.mType != NS_FRAME_OVERFLOW_LARGE &&
1020 mOverflow.mType != NS_FRAME_OVERFLOW_NONE) {
1021 nsOverflowAreas overflow = GetOverflowAreas();
1022 mRect = aRect;
1023 SetOverflowAreas(overflow);
1024 } else {
1025 mRect = aRect;
1027 if (aRebuildDisplayItems) {
1028 MarkNeedsDisplayItemRebuild();
1032 * Set this frame's rect from a logical rect in its own writing direction
1034 void SetRect(const mozilla::LogicalRect& aRect,
1035 const nsSize& aContainerSize) {
1036 SetRect(GetWritingMode(), aRect, aContainerSize);
1039 * Set this frame's rect from a logical rect in a different writing direction
1040 * (GetPhysicalRect will assert if the writing mode doesn't match)
1042 void SetRect(mozilla::WritingMode aWritingMode,
1043 const mozilla::LogicalRect& aRect,
1044 const nsSize& aContainerSize) {
1045 SetRect(aRect.GetPhysicalRect(aWritingMode, aContainerSize));
1049 * Set this frame's size from a logical size in its own writing direction.
1050 * This leaves the frame's logical position unchanged, which means its
1051 * physical position may change (for right-to-left modes).
1053 void SetSize(const mozilla::LogicalSize& aSize) {
1054 SetSize(GetWritingMode(), aSize);
1057 * Set this frame's size from a logical size in a different writing direction.
1058 * This leaves the frame's logical position in the given mode unchanged,
1059 * which means its physical position may change (for right-to-left modes).
1061 void SetSize(mozilla::WritingMode aWritingMode,
1062 const mozilla::LogicalSize& aSize) {
1063 if ((!aWritingMode.IsVertical() && !aWritingMode.IsBidiLTR()) ||
1064 aWritingMode.IsVerticalRL()) {
1065 nscoord oldWidth = mRect.Width();
1066 SetSize(aSize.GetPhysicalSize(aWritingMode));
1067 mRect.x -= mRect.Width() - oldWidth;
1068 } else {
1069 SetSize(aSize.GetPhysicalSize(aWritingMode));
1074 * Set this frame's physical size. This leaves the frame's physical position
1075 * (topLeft) unchanged.
1076 * @param aRebuildDisplayItems If true, then adds this frame to the
1077 * list of modified frames for display list building if the size has changed.
1078 * Only pass false if you're sure that the relevant display items will be
1079 * rebuilt already (possibly by an ancestor being in the modified list), or if
1080 * this is a temporary change.
1082 void SetSize(const nsSize& aSize, bool aRebuildDisplayItems = true) {
1083 SetRect(nsRect(mRect.TopLeft(), aSize), aRebuildDisplayItems);
1086 void SetPosition(const nsPoint& aPt) {
1087 if (mRect.TopLeft() == aPt) {
1088 return;
1090 mRect.MoveTo(aPt);
1091 MarkNeedsDisplayItemRebuild();
1093 void SetPosition(mozilla::WritingMode aWritingMode,
1094 const mozilla::LogicalPoint& aPt,
1095 const nsSize& aContainerSize) {
1096 // We subtract mRect.Size() from the container size to account for
1097 // the fact that logical origins in RTL coordinate systems are at
1098 // the top right of the frame instead of the top left.
1099 SetPosition(
1100 aPt.GetPhysicalPoint(aWritingMode, aContainerSize - mRect.Size()));
1104 * Move the frame, accounting for relative positioning. Use this when
1105 * adjusting the frame's position by a known amount, to properly update its
1106 * saved normal position (see GetNormalPosition below).
1108 * This must be used only when moving a frame *after*
1109 * ReflowInput::ApplyRelativePositioning is called. When moving
1110 * a frame during the reflow process prior to calling
1111 * ReflowInput::ApplyRelativePositioning, the position should
1112 * simply be adjusted directly (e.g., using SetPosition()).
1114 void MovePositionBy(const nsPoint& aTranslation);
1117 * As above, using a logical-point delta in a given writing mode.
1119 void MovePositionBy(mozilla::WritingMode aWritingMode,
1120 const mozilla::LogicalPoint& aTranslation) {
1121 // The LogicalPoint represents a vector rather than a point within a
1122 // rectangular coordinate space, so we use a null containerSize when
1123 // converting logical to physical.
1124 const nsSize nullContainerSize;
1125 MovePositionBy(
1126 aTranslation.GetPhysicalPoint(aWritingMode, nullContainerSize));
1130 * Return frame's rect without relative positioning
1132 nsRect GetNormalRect() const;
1135 * Return frame's position without relative positioning.
1136 * If aHasProperty is provided, returns whether the normal position
1137 * was stored in a frame property.
1139 inline nsPoint GetNormalPosition(bool* aHasProperty = nullptr) const;
1141 mozilla::LogicalPoint GetLogicalNormalPosition(
1142 mozilla::WritingMode aWritingMode, const nsSize& aContainerSize) const {
1143 // Subtract the size of this frame from the container size to get
1144 // the correct position in rtl frames where the origin is on the
1145 // right instead of the left
1146 return mozilla::LogicalPoint(aWritingMode, GetNormalPosition(),
1147 aContainerSize - mRect.Size());
1150 virtual nsPoint GetPositionOfChildIgnoringScrolling(const nsIFrame* aChild) {
1151 return aChild->GetPosition();
1154 nsPoint GetPositionIgnoringScrolling() const;
1156 typedef AutoTArray<nsDisplayItemBase*, 4> DisplayItemArray;
1158 #define NS_DECLARE_FRAME_PROPERTY_WITH_DTOR(prop, type, dtor) \
1159 static const mozilla::FramePropertyDescriptor<type>* prop() { \
1160 /* Use of constexpr caused startup crashes with MSVC2015u1 PGO. */ \
1161 static const auto descriptor = \
1162 mozilla::FramePropertyDescriptor<type>::NewWithDestructor<dtor>(); \
1163 return &descriptor; \
1166 // Don't use this unless you really know what you're doing!
1167 #define NS_DECLARE_FRAME_PROPERTY_WITH_FRAME_IN_DTOR(prop, type, dtor) \
1168 static const mozilla::FramePropertyDescriptor<type>* prop() { \
1169 /* Use of constexpr caused startup crashes with MSVC2015u1 PGO. */ \
1170 static const auto descriptor = mozilla::FramePropertyDescriptor< \
1171 type>::NewWithDestructorWithFrame<dtor>(); \
1172 return &descriptor; \
1175 #define NS_DECLARE_FRAME_PROPERTY_WITHOUT_DTOR(prop, type) \
1176 static const mozilla::FramePropertyDescriptor<type>* prop() { \
1177 /* Use of constexpr caused startup crashes with MSVC2015u1 PGO. */ \
1178 static const auto descriptor = \
1179 mozilla::FramePropertyDescriptor<type>::NewWithoutDestructor(); \
1180 return &descriptor; \
1183 #define NS_DECLARE_FRAME_PROPERTY_DELETABLE(prop, type) \
1184 NS_DECLARE_FRAME_PROPERTY_WITH_DTOR(prop, type, DeleteValue)
1186 #define NS_DECLARE_FRAME_PROPERTY_RELEASABLE(prop, type) \
1187 NS_DECLARE_FRAME_PROPERTY_WITH_DTOR(prop, type, ReleaseValue)
1189 #define NS_DECLARE_FRAME_PROPERTY_WITH_DTOR_NEVER_CALLED(prop, type) \
1190 static void AssertOnDestroyingProperty##prop(type*) { \
1191 MOZ_ASSERT_UNREACHABLE( \
1192 "Frame property " #prop \
1193 " should never be destroyed by the FrameProperties class"); \
1195 NS_DECLARE_FRAME_PROPERTY_WITH_DTOR(prop, type, \
1196 AssertOnDestroyingProperty##prop)
1198 #define NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(prop, type) \
1199 NS_DECLARE_FRAME_PROPERTY_WITHOUT_DTOR(prop, mozilla::SmallValueHolder<type>)
1201 NS_DECLARE_FRAME_PROPERTY_WITHOUT_DTOR(IBSplitSibling, nsContainerFrame)
1202 NS_DECLARE_FRAME_PROPERTY_WITHOUT_DTOR(IBSplitPrevSibling, nsContainerFrame)
1204 NS_DECLARE_FRAME_PROPERTY_DELETABLE(NormalPositionProperty, nsPoint)
1205 NS_DECLARE_FRAME_PROPERTY_DELETABLE(ComputedOffsetProperty, nsMargin)
1207 NS_DECLARE_FRAME_PROPERTY_DELETABLE(OutlineInnerRectProperty, nsRect)
1208 NS_DECLARE_FRAME_PROPERTY_DELETABLE(PreEffectsBBoxProperty, nsRect)
1209 NS_DECLARE_FRAME_PROPERTY_DELETABLE(PreTransformOverflowAreasProperty,
1210 nsOverflowAreas)
1212 NS_DECLARE_FRAME_PROPERTY_DELETABLE(OverflowAreasProperty, nsOverflowAreas)
1214 // The initial overflow area passed to FinishAndStoreOverflow. This is only
1215 // set on frames that Preserve3D() or HasPerspective() or IsTransformed(), and
1216 // when at least one of the overflow areas differs from the frame bound rect.
1217 NS_DECLARE_FRAME_PROPERTY_DELETABLE(InitialOverflowProperty, nsOverflowAreas)
1219 #ifdef DEBUG
1220 // InitialOverflowPropertyDebug is added to the frame to indicate that either
1221 // the InitialOverflowProperty has been stored or the InitialOverflowProperty
1222 // has been suppressed due to being set to the default value (frame bounds)
1223 NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(DebugInitialOverflowPropertyApplied,
1224 bool)
1225 #endif
1227 NS_DECLARE_FRAME_PROPERTY_DELETABLE(UsedMarginProperty, nsMargin)
1228 NS_DECLARE_FRAME_PROPERTY_DELETABLE(UsedPaddingProperty, nsMargin)
1229 NS_DECLARE_FRAME_PROPERTY_DELETABLE(UsedBorderProperty, nsMargin)
1231 NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(LineBaselineOffset, nscoord)
1233 // Temporary override for a flex item's main-size property (either width
1234 // or height), imposed by its flex container.
1235 NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(FlexItemMainSizeOverride, nscoord)
1237 NS_DECLARE_FRAME_PROPERTY_DELETABLE(InvalidationRect, nsRect)
1239 NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(RefusedAsyncAnimationProperty, bool)
1241 NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(FragStretchBSizeProperty, nscoord)
1243 // The block-axis margin-box size associated with eBClampMarginBoxMinSize.
1244 NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(BClampMarginBoxMinSizeProperty, nscoord)
1246 NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(IBaselinePadProperty, nscoord)
1247 NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(BBaselinePadProperty, nscoord)
1249 NS_DECLARE_FRAME_PROPERTY_DELETABLE(DisplayItems, DisplayItemArray)
1251 NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(BidiDataProperty,
1252 mozilla::FrameBidiData)
1254 NS_DECLARE_FRAME_PROPERTY_WITHOUT_DTOR(PlaceholderFrameProperty,
1255 nsPlaceholderFrame)
1257 mozilla::FrameBidiData GetBidiData() const {
1258 bool exists;
1259 mozilla::FrameBidiData bidiData = GetProperty(BidiDataProperty(), &exists);
1260 if (!exists) {
1261 bidiData.precedingControl = mozilla::kBidiLevelNone;
1263 return bidiData;
1266 nsBidiLevel GetBaseLevel() const { return GetBidiData().baseLevel; }
1268 nsBidiLevel GetEmbeddingLevel() const { return GetBidiData().embeddingLevel; }
1271 * Return the distance between the border edge of the frame and the
1272 * margin edge of the frame. Like GetRect(), returns the dimensions
1273 * as of the most recent reflow.
1275 * This doesn't include any margin collapsing that may have occurred.
1277 * It also treats 'auto' margins as zero, and treats any margins that
1278 * should have been turned into 'auto' because of overconstraint as
1279 * having their original values.
1281 virtual nsMargin GetUsedMargin() const;
1282 virtual mozilla::LogicalMargin GetLogicalUsedMargin(
1283 mozilla::WritingMode aWritingMode) const {
1284 return mozilla::LogicalMargin(aWritingMode, GetUsedMargin());
1288 * Return the distance between the border edge of the frame (which is
1289 * its rect) and the padding edge of the frame. Like GetRect(), returns
1290 * the dimensions as of the most recent reflow.
1292 * Note that this differs from StyleBorder()->GetComputedBorder() in
1293 * that this describes a region of the frame's box, and
1294 * StyleBorder()->GetComputedBorder() describes a border. They differ
1295 * for tables (particularly border-collapse tables) and themed
1296 * elements.
1298 virtual nsMargin GetUsedBorder() const;
1299 virtual mozilla::LogicalMargin GetLogicalUsedBorder(
1300 mozilla::WritingMode aWritingMode) const {
1301 return mozilla::LogicalMargin(aWritingMode, GetUsedBorder());
1305 * Return the distance between the padding edge of the frame and the
1306 * content edge of the frame. Like GetRect(), returns the dimensions
1307 * as of the most recent reflow.
1309 virtual nsMargin GetUsedPadding() const;
1310 virtual mozilla::LogicalMargin GetLogicalUsedPadding(
1311 mozilla::WritingMode aWritingMode) const {
1312 return mozilla::LogicalMargin(aWritingMode, GetUsedPadding());
1315 nsMargin GetUsedBorderAndPadding() const {
1316 return GetUsedBorder() + GetUsedPadding();
1318 mozilla::LogicalMargin GetLogicalUsedBorderAndPadding(
1319 mozilla::WritingMode aWritingMode) const {
1320 return mozilla::LogicalMargin(aWritingMode, GetUsedBorderAndPadding());
1324 * Like the frame's rect (see |GetRect|), which is the border rect,
1325 * other rectangles of the frame, in app units, relative to the parent.
1327 nsRect GetPaddingRect() const;
1328 nsRect GetPaddingRectRelativeToSelf() const;
1329 nsRect GetContentRect() const;
1330 nsRect GetContentRectRelativeToSelf() const;
1331 nsRect GetMarginRectRelativeToSelf() const;
1334 * The area to paint box-shadows around. The default is the border rect.
1335 * (nsFieldSetFrame overrides this).
1337 virtual nsRect VisualBorderRectRelativeToSelf() const {
1338 return nsRect(0, 0, mRect.Width(), mRect.Height());
1342 * Get the size, in app units, of the border radii. It returns FALSE iff all
1343 * returned radii == 0 (so no border radii), TRUE otherwise.
1344 * For the aRadii indexes, use the enum HalfCorner constants in gfx/2d/Types.h
1345 * If a side is skipped via aSkipSides, its corners are forced to 0.
1347 * All corner radii are then adjusted so they do not require more
1348 * space than aBorderArea, according to the algorithm in css3-background.
1350 * aFrameSize is used as the basis for percentage widths and heights.
1351 * aBorderArea is used for the adjustment of radii that might be too
1352 * large.
1353 * FIXME: In the long run, we can probably get away with only one of
1354 * these, especially if we change the way we handle outline-radius (by
1355 * removing it and inflating the border radius)
1357 * Return whether any radii are nonzero.
1359 static bool ComputeBorderRadii(const mozilla::BorderRadius&,
1360 const nsSize& aFrameSize,
1361 const nsSize& aBorderArea, Sides aSkipSides,
1362 nscoord aRadii[8]);
1365 * Given a set of border radii for one box (e.g., border box), convert
1366 * it to the equivalent set of radii for another box (e.g., in to
1367 * padding box, out to outline box) by reducing radii or increasing
1368 * nonzero radii as appropriate.
1370 * Indices into aRadii are the enum HalfCorner constants in gfx/2d/Types.h
1372 * Note that InsetBorderRadii is lossy, since it can turn nonzero
1373 * radii into zero, and OutsetBorderRadii does not inflate zero radii.
1374 * Therefore, callers should always inset or outset directly from the
1375 * original value coming from style.
1377 static void InsetBorderRadii(nscoord aRadii[8], const nsMargin& aOffsets);
1378 static void OutsetBorderRadii(nscoord aRadii[8], const nsMargin& aOffsets);
1381 * Fill in border radii for this frame. Return whether any are nonzero.
1382 * Indices into aRadii are the enum HalfCorner constants in gfx/2d/Types.h
1383 * aSkipSides is a union of eSideBitsLeft/Right/Top/Bottom bits that says
1384 * which side(s) to skip.
1386 * Note: GetMarginBoxBorderRadii() and GetShapeBoxBorderRadii() work only
1387 * on frames that establish block formatting contexts since they don't
1388 * participate in margin-collapsing.
1390 virtual bool GetBorderRadii(const nsSize& aFrameSize,
1391 const nsSize& aBorderArea, Sides aSkipSides,
1392 nscoord aRadii[8]) const;
1393 bool GetBorderRadii(nscoord aRadii[8]) const;
1394 bool GetMarginBoxBorderRadii(nscoord aRadii[8]) const;
1395 bool GetPaddingBoxBorderRadii(nscoord aRadii[8]) const;
1396 bool GetContentBoxBorderRadii(nscoord aRadii[8]) const;
1397 bool GetBoxBorderRadii(nscoord aRadii[8], nsMargin aOffset,
1398 bool aIsOutset) const;
1399 bool GetShapeBoxBorderRadii(nscoord aRadii[8]) const;
1402 * XXX: this method will likely be replaced by GetVerticalAlignBaseline
1403 * Get the position of the frame's baseline, relative to the top of
1404 * the frame (its top border edge). Only valid when Reflow is not
1405 * needed.
1406 * @note You should only call this on frames with a WM that's parallel to aWM.
1407 * @param aWM the writing-mode of the alignment context, with the ltr/rtl
1408 * direction tweak done by nsIFrame::GetWritingMode(nsIFrame*) in inline
1409 * contexts (see that method).
1411 virtual nscoord GetLogicalBaseline(mozilla::WritingMode aWM) const = 0;
1414 * Synthesize a first(last) inline-axis baseline from our margin-box.
1415 * An alphabetical baseline is at the start(end) edge and a central baseline
1416 * is at the center of our block-axis margin-box (aWM tells which to use).
1417 * https://drafts.csswg.org/css-align-3/#synthesize-baselines
1418 * @note You should only call this on frames with a WM that's parallel to aWM.
1419 * @param aWM the writing-mode of the alignment context
1420 * @return an offset from our border-box block-axis start(end) edge for
1421 * a first(last) baseline respectively
1422 * (implemented in nsIFrameInlines.h)
1424 inline nscoord SynthesizeBaselineBOffsetFromMarginBox(
1425 mozilla::WritingMode aWM, BaselineSharingGroup aGroup) const;
1428 * Synthesize a first(last) inline-axis baseline from our border-box.
1429 * An alphabetical baseline is at the start(end) edge and a central baseline
1430 * is at the center of our block-axis border-box (aWM tells which to use).
1431 * https://drafts.csswg.org/css-align-3/#synthesize-baselines
1432 * @note The returned value is only valid when reflow is not needed.
1433 * @note You should only call this on frames with a WM that's parallel to aWM.
1434 * @param aWM the writing-mode of the alignment context
1435 * @return an offset from our border-box block-axis start(end) edge for
1436 * a first(last) baseline respectively
1437 * (implemented in nsIFrameInlines.h)
1439 inline nscoord SynthesizeBaselineBOffsetFromBorderBox(
1440 mozilla::WritingMode aWM, BaselineSharingGroup aGroup) const;
1443 * Return the position of the frame's inline-axis baseline, or synthesize one
1444 * for the given alignment context. The returned baseline is the distance from
1445 * the block-axis border-box start(end) edge for aBaselineGroup eFirst(eLast).
1446 * @note The returned value is only valid when reflow is not needed.
1447 * @note You should only call this on frames with a WM that's parallel to aWM.
1448 * @param aWM the writing-mode of the alignment context
1449 * @param aBaselineOffset out-param, only valid if the method returns true
1450 * (implemented in nsIFrameInlines.h)
1452 inline nscoord BaselineBOffset(mozilla::WritingMode aWM,
1453 BaselineSharingGroup aBaselineGroup,
1454 AlignmentContext aAlignmentContext) const;
1457 * XXX: this method is taking over the role that GetLogicalBaseline has.
1458 * Return true if the frame has a CSS2 'vertical-align' baseline.
1459 * If it has, then the returned baseline is the distance from the block-
1460 * axis border-box start edge.
1461 * @note This method should only be used in AlignmentContext::Inline
1462 * contexts.
1463 * @note The returned value is only valid when reflow is not needed.
1464 * @note You should only call this on frames with a WM that's parallel to aWM.
1465 * @param aWM the writing-mode of the alignment context
1466 * @param aBaseline the baseline offset, only valid if the method returns true
1468 virtual bool GetVerticalAlignBaseline(mozilla::WritingMode aWM,
1469 nscoord* aBaseline) const {
1470 return false;
1474 * Return true if the frame has a first(last) inline-axis natural baseline per
1475 * CSS Box Alignment. If so, then the returned baseline is the distance from
1476 * the block-axis border-box start(end) edge for aBaselineGroup eFirst(eLast).
1477 * https://drafts.csswg.org/css-align-3/#natural-baseline
1478 * @note The returned value is only valid when reflow is not needed.
1479 * @note You should only call this on frames with a WM that's parallel to aWM.
1480 * @param aWM the writing-mode of the alignment context
1481 * @param aBaseline the baseline offset, only valid if the method returns true
1483 virtual bool GetNaturalBaselineBOffset(mozilla::WritingMode aWM,
1484 BaselineSharingGroup aBaselineGroup,
1485 nscoord* aBaseline) const {
1486 return false;
1490 * Get the position of the baseline on which the caret needs to be placed,
1491 * relative to the top of the frame. This is mostly needed for frames
1492 * which return a baseline from GetBaseline which is not useful for
1493 * caret positioning.
1495 virtual nscoord GetCaretBaseline() const {
1496 return GetLogicalBaseline(GetWritingMode());
1499 ///////////////////////////////////////////////////////////////////////////////
1500 // The public visibility API.
1501 ///////////////////////////////////////////////////////////////////////////////
1503 /// @return true if we're tracking visibility for this frame.
1504 bool TrackingVisibility() const {
1505 return bool(GetStateBits() & NS_FRAME_VISIBILITY_IS_TRACKED);
1508 /// @return the visibility state of this frame. See the Visibility enum
1509 /// for the possible return values and their meanings.
1510 Visibility GetVisibility() const;
1512 /// Update the visibility state of this frame synchronously.
1513 /// XXX(seth): Avoid using this method; we should be relying on the refresh
1514 /// driver for visibility updates. This method, which replaces
1515 /// nsLayoutUtils::UpdateApproximateFrameVisibility(), exists purely as a
1516 /// temporary measure to avoid changing behavior during the transition from
1517 /// the old image visibility code.
1518 void UpdateVisibilitySynchronously();
1520 // A frame property which stores the visibility state of this frame. Right
1521 // now that consists of an approximate visibility counter represented as a
1522 // uint32_t. When the visibility of this frame is not being tracked, this
1523 // property is absent.
1524 NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(VisibilityStateProperty, uint32_t);
1526 protected:
1528 * Subclasses can call this method to enable visibility tracking for this
1529 * frame.
1531 * If visibility tracking was previously disabled, this will schedule an
1532 * update an asynchronous update of visibility.
1534 void EnableVisibilityTracking();
1537 * Subclasses can call this method to disable visibility tracking for this
1538 * frame.
1540 * Note that if visibility tracking was previously enabled, disabling
1541 * visibility tracking will cause a synchronous call to OnVisibilityChange().
1543 void DisableVisibilityTracking();
1546 * Called when a frame transitions between visibility states (for example,
1547 * from nonvisible to visible, or from visible to nonvisible).
1549 * @param aNewVisibility The new visibility state.
1550 * @param aNonvisibleAction A requested action if the frame has become
1551 * nonvisible. If Nothing(), no action is
1552 * requested. If DISCARD_IMAGES is specified, the
1553 * frame is requested to ask any images it's
1554 * associated with to discard their surfaces if
1555 * possible.
1557 * Subclasses which override this method should call their parent class's
1558 * implementation.
1560 virtual void OnVisibilityChange(
1561 Visibility aNewVisibility,
1562 const Maybe<OnNonvisible>& aNonvisibleAction = Nothing());
1564 public:
1565 ///////////////////////////////////////////////////////////////////////////////
1566 // Internal implementation for the approximate frame visibility API.
1567 ///////////////////////////////////////////////////////////////////////////////
1570 * We track the approximate visibility of frames using a counter; if it's
1571 * non-zero, then the frame is considered visible. Using a counter allows us
1572 * to account for situations where the frame may be visible in more than one
1573 * place (for example, via -moz-element), and it simplifies the
1574 * implementation of our approximate visibility tracking algorithms.
1576 * @param aNonvisibleAction A requested action if the frame has become
1577 * nonvisible. If Nothing(), no action is
1578 * requested. If DISCARD_IMAGES is specified, the
1579 * frame is requested to ask any images it's
1580 * associated with to discard their surfaces if
1581 * possible.
1583 void DecApproximateVisibleCount(
1584 const Maybe<OnNonvisible>& aNonvisibleAction = Nothing());
1585 void IncApproximateVisibleCount();
1588 * Get the specified child list.
1590 * @param aListID identifies the requested child list.
1591 * @return the child list. If the requested list is unsupported by this
1592 * frame type, an empty list will be returned.
1594 virtual const nsFrameList& GetChildList(ChildListID aListID) const = 0;
1595 const nsFrameList& PrincipalChildList() const {
1596 return GetChildList(kPrincipalList);
1598 virtual void GetChildLists(nsTArray<ChildList>* aLists) const = 0;
1601 * Gets the child lists for this frame, including
1602 * ones belong to a child document.
1604 void GetCrossDocChildLists(nsTArray<ChildList>* aLists);
1606 // The individual concrete child lists.
1607 static const ChildListID kPrincipalList = mozilla::layout::kPrincipalList;
1608 static const ChildListID kAbsoluteList = mozilla::layout::kAbsoluteList;
1609 static const ChildListID kBulletList = mozilla::layout::kBulletList;
1610 static const ChildListID kCaptionList = mozilla::layout::kCaptionList;
1611 static const ChildListID kColGroupList = mozilla::layout::kColGroupList;
1612 static const ChildListID kExcessOverflowContainersList =
1613 mozilla::layout::kExcessOverflowContainersList;
1614 static const ChildListID kFixedList = mozilla::layout::kFixedList;
1615 static const ChildListID kFloatList = mozilla::layout::kFloatList;
1616 static const ChildListID kOverflowContainersList =
1617 mozilla::layout::kOverflowContainersList;
1618 static const ChildListID kOverflowList = mozilla::layout::kOverflowList;
1619 static const ChildListID kOverflowOutOfFlowList =
1620 mozilla::layout::kOverflowOutOfFlowList;
1621 static const ChildListID kPopupList = mozilla::layout::kPopupList;
1622 static const ChildListID kPushedFloatsList =
1623 mozilla::layout::kPushedFloatsList;
1624 static const ChildListID kSelectPopupList = mozilla::layout::kSelectPopupList;
1625 static const ChildListID kBackdropList = mozilla::layout::kBackdropList;
1626 // A special alias for kPrincipalList that do not request reflow.
1627 static const ChildListID kNoReflowPrincipalList =
1628 mozilla::layout::kNoReflowPrincipalList;
1631 * Child frames are linked together in a doubly-linked list
1633 nsIFrame* GetNextSibling() const { return mNextSibling; }
1634 void SetNextSibling(nsIFrame* aNextSibling) {
1635 NS_ASSERTION(this != aNextSibling,
1636 "Creating a circular frame list, this is very bad.");
1637 if (mNextSibling && mNextSibling->GetPrevSibling() == this) {
1638 mNextSibling->mPrevSibling = nullptr;
1640 mNextSibling = aNextSibling;
1641 if (mNextSibling) {
1642 mNextSibling->mPrevSibling = this;
1646 nsIFrame* GetPrevSibling() const { return mPrevSibling; }
1649 * Builds the display lists for the content represented by this frame
1650 * and its descendants. The background+borders of this element must
1651 * be added first, before any other content.
1653 * This should only be called by methods in nsFrame. Instead of calling this
1654 * directly, call either BuildDisplayListForStackingContext or
1655 * BuildDisplayListForChild.
1657 * See nsDisplayList.h for more information about display lists.
1659 virtual void BuildDisplayList(nsDisplayListBuilder* aBuilder,
1660 const nsDisplayListSet& aLists) {}
1662 * Displays the caret onto the given display list builder. The caret is
1663 * painted on top of the rest of the display list items.
1665 void DisplayCaret(nsDisplayListBuilder* aBuilder, nsDisplayList* aList);
1668 * Get the preferred caret color at the offset.
1670 * @param aOffset is offset of the content.
1672 virtual nscolor GetCaretColorAt(int32_t aOffset);
1674 bool IsThemed(nsITheme::Transparency* aTransparencyState = nullptr) const {
1675 return IsThemed(StyleDisplay(), aTransparencyState);
1677 bool IsThemed(const nsStyleDisplay* aDisp,
1678 nsITheme::Transparency* aTransparencyState = nullptr) const {
1679 if (!aDisp->HasAppearance()) {
1680 return false;
1682 nsIFrame* mutable_this = const_cast<nsIFrame*>(this);
1683 nsPresContext* pc = PresContext();
1684 nsITheme* theme = pc->GetTheme();
1685 if (!theme ||
1686 !theme->ThemeSupportsWidget(pc, mutable_this, aDisp->mAppearance))
1687 return false;
1688 if (aTransparencyState) {
1689 *aTransparencyState =
1690 theme->GetWidgetTransparency(mutable_this, aDisp->mAppearance);
1692 return true;
1696 * Builds a display list for the content represented by this frame,
1697 * treating this frame as the root of a stacking context.
1698 * Optionally sets aCreatedContainerItem to true if we created a
1699 * single container display item for the stacking context, and no
1700 * other wrapping items are needed.
1702 void BuildDisplayListForStackingContext(
1703 nsDisplayListBuilder* aBuilder, nsDisplayList* aList,
1704 bool* aCreatedContainerItem = nullptr);
1706 enum {
1707 DISPLAY_CHILD_FORCE_PSEUDO_STACKING_CONTEXT = 0x01,
1708 DISPLAY_CHILD_FORCE_STACKING_CONTEXT = 0x02,
1709 DISPLAY_CHILD_INLINE = 0x04
1712 * Adjusts aDirtyRect for the child's offset, checks that the dirty rect
1713 * actually intersects the child (or its descendants), calls BuildDisplayList
1714 * on the child if necessary, and puts things in the right lists if the child
1715 * is positioned.
1717 * @param aFlags combination of DISPLAY_CHILD_FORCE_PSEUDO_STACKING_CONTEXT,
1718 * DISPLAY_CHILD_FORCE_STACKING_CONTEXT and DISPLAY_CHILD_INLINE
1720 void BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
1721 nsIFrame* aChild,
1722 const nsDisplayListSet& aLists,
1723 uint32_t aFlags = 0);
1725 void BuildDisplayListForSimpleChild(nsDisplayListBuilder* aBuilder,
1726 nsIFrame* aChild,
1727 const nsDisplayListSet& aLists);
1729 bool RefusedAsyncAnimation() const {
1730 return GetProperty(RefusedAsyncAnimationProperty());
1734 * Returns true if this frame is transformed (e.g. has CSS or SVG transforms)
1735 * or if its parent is an SVG frame that has children-only transforms (e.g.
1736 * an SVG viewBox attribute) or if its transform-style is preserve-3d or
1737 * the frame has transform animations.
1739 * @param aStyleDisplay: If the caller has this->StyleDisplay(), providing
1740 * it here will improve performance.
1742 bool IsTransformed(const nsStyleDisplay* aStyleDisplay) const;
1743 bool IsTransformed() const { return IsTransformed(StyleDisplay()); }
1746 * Same as IsTransformed, except that it doesn't take SVG transforms
1747 * into account.
1749 bool IsCSSTransformed(const nsStyleDisplay* aStyleDisplay) const;
1752 * True if this frame has any animation of transform in effect.
1755 bool HasAnimationOfTransform() const;
1758 * Returns true if the frame is translucent or the frame has opacity
1759 * animations for the purposes of creating a stacking context.
1761 * @param aStyleDisplay: This function needs style display struct.
1763 * @param aStyleEffects: This function needs style effects struct.
1765 * @param aEffectSet: This function may need to look up EffectSet property.
1766 * If a caller already have one, pass it in can save property look up
1767 * time; otherwise, just leave it as nullptr.
1769 bool HasOpacity(const nsStyleDisplay* aStyleDisplay,
1770 const nsStyleEffects* aStyleEffects,
1771 mozilla::EffectSet* aEffectSet = nullptr) const {
1772 return HasOpacityInternal(1.0f, aStyleDisplay, aStyleEffects, aEffectSet);
1775 * Returns true if the frame is translucent for display purposes.
1777 * @param aStyleDisplay: This function needs style display struct.
1779 * @param aStyleEffects: This function needs style effects struct.
1781 * @param aEffectSet: This function may need to look up EffectSet property.
1782 * If a caller already have one, pass it in can save property look up
1783 * time; otherwise, just leave it as nullptr.
1785 bool HasVisualOpacity(const nsStyleDisplay* aStyleDisplay,
1786 const nsStyleEffects* aStyleEffects,
1787 mozilla::EffectSet* aEffectSet = nullptr) const {
1788 // Treat an opacity value of 0.99 and above as opaque. This is an
1789 // optimization aimed at Web content which use opacity:0.99 as a hint for
1790 // creating a stacking context only.
1791 return HasOpacityInternal(0.99f, aStyleDisplay, aStyleEffects, aEffectSet);
1795 * Return true if this frame might be using a transform getter.
1797 virtual bool HasTransformGetter() const { return false; }
1800 * Returns true if this frame is an SVG frame that has SVG transforms applied
1801 * to it, or if its parent frame is an SVG frame that has children-only
1802 * transforms (e.g. an SVG viewBox attribute).
1803 * If aOwnTransforms is non-null and the frame has its own SVG transforms,
1804 * aOwnTransforms will be set to these transforms. If aFromParentTransforms
1805 * is non-null and the frame has an SVG parent with children-only transforms,
1806 * then aFromParentTransforms will be set to these transforms.
1808 virtual bool IsSVGTransformed(Matrix* aOwnTransforms = nullptr,
1809 Matrix* aFromParentTransforms = nullptr) const;
1812 * Return true if this frame should form a backdrop root container.
1813 * See: https://drafts.fxtf.org/filter-effects-2/#BackdropRootTriggers
1815 bool FormsBackdropRoot(const nsStyleDisplay* aStyleDisplay,
1816 const nsStyleEffects* aStyleEffects,
1817 const nsStyleSVGReset* aStyleSvgReset);
1820 * Returns whether this frame will attempt to extend the 3d transforms of its
1821 * children. This requires transform-style: preserve-3d, as well as no
1822 * clipping or svg effects.
1824 * @param aStyleDisplay: If the caller has this->StyleDisplay(), providing
1825 * it here will improve performance.
1827 * @param aStyleEffects: If the caller has this->StyleEffects(), providing
1828 * it here will improve performance.
1830 * @param aEffectSetForOpacity: This function may need to look up the
1831 * EffectSet for opacity animations on this frame.
1832 * If the caller already has looked up this EffectSet, it may pass it in to
1833 * save an extra property lookup.
1835 bool Extend3DContext(
1836 const nsStyleDisplay* aStyleDisplay, const nsStyleEffects* aStyleEffects,
1837 mozilla::EffectSet* aEffectSetForOpacity = nullptr) const;
1838 bool Extend3DContext(
1839 mozilla::EffectSet* aEffectSetForOpacity = nullptr) const {
1840 return Extend3DContext(StyleDisplay(), StyleEffects(),
1841 aEffectSetForOpacity);
1845 * Returns whether this frame has a parent that Extend3DContext() and has
1846 * its own transform (or hidden backface) to be combined with the parent's
1847 * transform.
1849 * @param aStyleDisplay: If the caller has this->StyleDisplay(), providing
1850 * it here will improve performance.
1852 bool Combines3DTransformWithAncestors(
1853 const nsStyleDisplay* aStyleDisplay) const;
1854 bool Combines3DTransformWithAncestors() const {
1855 return Combines3DTransformWithAncestors(StyleDisplay());
1859 * Returns whether this frame has a hidden backface and has a parent that
1860 * Extend3DContext(). This is useful because in some cases the hidden
1861 * backface can safely be ignored if it could not be visible anyway.
1864 bool In3DContextAndBackfaceIsHidden() const;
1866 bool IsPreserve3DLeaf(const nsStyleDisplay* aStyleDisplay,
1867 mozilla::EffectSet* aEffectSet = nullptr) const {
1868 return Combines3DTransformWithAncestors(aStyleDisplay) &&
1869 !Extend3DContext(aStyleDisplay, StyleEffects(), aEffectSet);
1871 bool IsPreserve3DLeaf(mozilla::EffectSet* aEffectSet = nullptr) const {
1872 return IsPreserve3DLeaf(StyleDisplay(), aEffectSet);
1875 bool HasPerspective(const nsStyleDisplay* aStyleDisplay) const;
1876 bool HasPerspective() const { return HasPerspective(StyleDisplay()); }
1878 bool ChildrenHavePerspective(const nsStyleDisplay* aStyleDisplay) const;
1879 bool ChildrenHavePerspective() const {
1880 return ChildrenHavePerspective(StyleDisplay());
1884 * Includes the overflow area of all descendants that participate in the
1885 * current 3d context into aOverflowAreas.
1887 void ComputePreserve3DChildrenOverflow(nsOverflowAreas& aOverflowAreas);
1889 void RecomputePerspectiveChildrenOverflow(const nsIFrame* aStartFrame);
1892 * Returns the computed z-index for this frame, returning 0 for z-index:auto
1893 * and frames that don't support z-index.
1895 int32_t ZIndex() const;
1898 * Returns whether this frame is the anchor of some ancestor scroll frame. As
1899 * this frame is moved, the scroll frame will apply adjustments to keep this
1900 * scroll frame in the same relative position.
1902 * aOutContainer will optionally be set to the scroll anchor container for
1903 * this frame if this frame is an anchor.
1905 bool IsScrollAnchor(
1906 mozilla::layout::ScrollAnchorContainer** aOutContainer = nullptr);
1909 * Returns whether this frame is the anchor of some ancestor scroll frame, or
1910 * has a descendant which is the scroll anchor.
1912 bool IsInScrollAnchorChain() const;
1913 void SetInScrollAnchorChain(bool aInChain);
1916 * Returns the number of ancestors between this and the root of our frame tree
1918 uint32_t GetDepthInFrameTree() const;
1921 * Event handling of GUI events.
1923 * @param aEvent event structure describing the type of event and rge widget
1924 * where the event originated. The |point| member of this is in the coordinate
1925 * system of the view returned by GetOffsetFromView.
1927 * @param aEventStatus a return value indicating whether the event was
1928 * handled and whether default processing should be done
1930 * XXX From a frame's perspective it's unclear what the effect of the event
1931 * status is. Does it cause the event to continue propagating through the
1932 * frame hierarchy or is it just returned to the widgets?
1934 * @see WidgetGUIEvent
1935 * @see nsEventStatus
1937 virtual nsresult HandleEvent(nsPresContext* aPresContext,
1938 mozilla::WidgetGUIEvent* aEvent,
1939 nsEventStatus* aEventStatus) = 0;
1941 virtual nsresult GetContentForEvent(mozilla::WidgetEvent* aEvent,
1942 nsIContent** aContent) = 0;
1944 // This structure keeps track of the content node and offsets associated with
1945 // a point; there is a primary and a secondary offset associated with any
1946 // point. The primary and secondary offsets differ when the point is over a
1947 // non-text object. The primary offset is the expected position of the
1948 // cursor calculated from a point; the secondary offset, when it is different,
1949 // indicates that the point is in the boundaries of some selectable object.
1950 // Note that the primary offset can be after the secondary offset; for places
1951 // that need the beginning and end of the object, the StartOffset and
1952 // EndOffset helpers can be used.
1953 struct MOZ_STACK_CLASS ContentOffsets {
1954 ContentOffsets()
1955 : offset(0),
1956 secondaryOffset(0),
1957 associate(mozilla::CARET_ASSOCIATE_BEFORE) {}
1958 bool IsNull() { return !content; }
1959 // Helpers for places that need the ends of the offsets and expect them in
1960 // numerical order, as opposed to wanting the primary and secondary offsets
1961 int32_t StartOffset() { return std::min(offset, secondaryOffset); }
1962 int32_t EndOffset() { return std::max(offset, secondaryOffset); }
1964 nsCOMPtr<nsIContent> content;
1965 int32_t offset;
1966 int32_t secondaryOffset;
1967 // This value indicates whether the associated content is before or after
1968 // the offset; the most visible use is to allow the caret to know which line
1969 // to display on.
1970 mozilla::CaretAssociationHint associate;
1972 enum {
1973 IGNORE_SELECTION_STYLE = 0x01,
1974 // Treat visibility:hidden frames as non-selectable
1975 SKIP_HIDDEN = 0x02
1978 * This function calculates the content offsets for selection relative to
1979 * a point. Note that this should generally only be callled on the event
1980 * frame associated with an event because this function does not account
1981 * for frame lists other than the primary one.
1982 * @param aPoint point relative to this frame
1984 ContentOffsets GetContentOffsetsFromPoint(const nsPoint& aPoint,
1985 uint32_t aFlags = 0);
1987 virtual ContentOffsets GetContentOffsetsFromPointExternal(
1988 const nsPoint& aPoint, uint32_t aFlags = 0) {
1989 return GetContentOffsetsFromPoint(aPoint, aFlags);
1993 * Ensure that aImage gets notifed when the underlying image request loads
1994 * or animates.
1996 void AssociateImage(const nsStyleImage& aImage, nsPresContext* aPresContext,
1997 uint32_t aImageLoaderFlags);
1999 enum class AllowCustomCursorImage {
2001 Yes,
2005 * This structure holds information about a cursor. AllowCustomCursorImage
2006 * is `No`, then no cursor image should be loaded from the style specified on
2007 * `mStyle`, or the frame's style.
2009 * The `mStyle` member is used for `<area>` elements.
2011 struct MOZ_STACK_CLASS Cursor {
2012 mozilla::StyleCursorKind mCursor = mozilla::StyleCursorKind::Auto;
2013 AllowCustomCursorImage mAllowCustomCursor = AllowCustomCursorImage::Yes;
2014 RefPtr<mozilla::ComputedStyle> mStyle;
2018 * Get the cursor for a given frame.
2020 virtual mozilla::Maybe<Cursor> GetCursor(const nsPoint&);
2023 * Get a point (in the frame's coordinate space) given an offset into
2024 * the content. This point should be on the baseline of text with
2025 * the correct horizontal offset
2027 virtual nsresult GetPointFromOffset(int32_t inOffset, nsPoint* outPoint) = 0;
2030 * Get a list of character rects in a given range.
2031 * This is similar version of GetPointFromOffset.
2033 virtual nsresult GetCharacterRectsInRange(int32_t aInOffset, int32_t aLength,
2034 nsTArray<nsRect>& aRects) = 0;
2037 * Get the child frame of this frame which contains the given
2038 * content offset. outChildFrame may be this frame, or nullptr on return.
2039 * outContentOffset returns the content offset relative to the start
2040 * of the returned node. You can also pass a hint which tells the method
2041 * to stick to the end of the first found frame or the beginning of the
2042 * next in case the offset falls on a boundary.
2044 virtual nsresult GetChildFrameContainingOffset(
2045 int32_t inContentOffset,
2046 bool inHint, // false stick left
2047 int32_t* outFrameContentOffset, nsIFrame** outChildFrame) = 0;
2050 * Get the current frame-state value for this frame. aResult is
2051 * filled in with the state bits.
2053 nsFrameState GetStateBits() const { return mState; }
2056 * Update the current frame-state value for this frame.
2058 void AddStateBits(nsFrameState aBits) { mState |= aBits; }
2059 void RemoveStateBits(nsFrameState aBits) { mState &= ~aBits; }
2060 void AddOrRemoveStateBits(nsFrameState aBits, bool aVal) {
2061 aVal ? AddStateBits(aBits) : RemoveStateBits(aBits);
2065 * Checks if the current frame-state includes all of the listed bits
2067 bool HasAllStateBits(nsFrameState aBits) const {
2068 return (mState & aBits) == aBits;
2072 * Checks if the current frame-state includes any of the listed bits
2074 bool HasAnyStateBits(nsFrameState aBits) const { return mState & aBits; }
2077 * Return true if this frame is the primary frame for mContent.
2079 bool IsPrimaryFrame() const { return mIsPrimaryFrame; }
2081 void SetIsPrimaryFrame(bool aIsPrimary) { mIsPrimaryFrame = aIsPrimary; }
2084 * This call is invoked on the primary frame for a character data content
2085 * node, when it is changed in the content tree.
2087 virtual nsresult CharacterDataChanged(const CharacterDataChangeInfo&) = 0;
2090 * This call is invoked when the value of a content objects's attribute
2091 * is changed.
2092 * The first frame that maps that content is asked to deal
2093 * with the change by doing whatever is appropriate.
2095 * @param aNameSpaceID the namespace of the attribute
2096 * @param aAttribute the atom name of the attribute
2097 * @param aModType Whether or not the attribute was added, changed, or
2098 * removed. The constants are defined in MutationEvent.webidl.
2100 virtual nsresult AttributeChanged(int32_t aNameSpaceID, nsAtom* aAttribute,
2101 int32_t aModType) = 0;
2104 * When the content states of a content object change, this method is invoked
2105 * on the primary frame of that content object.
2107 * @param aStates the changed states
2109 virtual void ContentStatesChanged(mozilla::EventStates aStates);
2112 * Continuation member functions
2114 virtual nsIFrame* GetPrevContinuation() const = 0;
2115 virtual void SetPrevContinuation(nsIFrame*) = 0;
2116 virtual nsIFrame* GetNextContinuation() const = 0;
2117 virtual void SetNextContinuation(nsIFrame*) = 0;
2118 virtual nsIFrame* FirstContinuation() const {
2119 return const_cast<nsIFrame*>(this);
2121 virtual nsIFrame* LastContinuation() const {
2122 return const_cast<nsIFrame*>(this);
2126 * GetTailContinuation gets the last non-overflow-container continuation
2127 * in the continuation chain, i.e. where the next sibling element
2128 * should attach).
2130 nsIFrame* GetTailContinuation();
2133 * Flow member functions
2135 virtual nsIFrame* GetPrevInFlow() const = 0;
2136 virtual void SetPrevInFlow(nsIFrame*) = 0;
2138 virtual nsIFrame* GetNextInFlow() const = 0;
2139 virtual void SetNextInFlow(nsIFrame*) = 0;
2142 * Return the first frame in our current flow.
2144 virtual nsIFrame* FirstInFlow() const { return const_cast<nsIFrame*>(this); }
2147 * Return the last frame in our current flow.
2149 virtual nsIFrame* LastInFlow() const { return const_cast<nsIFrame*>(this); }
2152 * Note: "width" in the names and comments on the following methods
2153 * means inline-size, which could be height in vertical layout
2157 * Mark any stored intrinsic width information as dirty (requiring
2158 * re-calculation). Note that this should generally not be called
2159 * directly; PresShell::FrameNeedsReflow() will call it instead.
2161 virtual void MarkIntrinsicISizesDirty() = 0;
2164 * Make this frame and all descendants dirty (if not already).
2165 * Exceptions: XULBoxFrame and TableColGroupFrame children.
2167 void MarkSubtreeDirty();
2170 * Get the min-content intrinsic inline size of the frame. This must be
2171 * less than or equal to the max-content intrinsic inline size.
2173 * This is *not* affected by the CSS 'min-width', 'width', and
2174 * 'max-width' properties on this frame, but it is affected by the
2175 * values of those properties on this frame's descendants. (It may be
2176 * called during computation of the values of those properties, so it
2177 * cannot depend on any values in the nsStylePosition for this frame.)
2179 * The value returned should **NOT** include the space required for
2180 * padding and border.
2182 * Note that many frames will cache the result of this function call
2183 * unless MarkIntrinsicISizesDirty is called.
2185 * It is not acceptable for a frame to mark itself dirty when this
2186 * method is called.
2188 * This method must not return a negative value.
2190 virtual nscoord GetMinISize(gfxContext* aRenderingContext) = 0;
2193 * Get the max-content intrinsic inline size of the frame. This must be
2194 * greater than or equal to the min-content intrinsic inline size.
2196 * Otherwise, all the comments for |GetMinISize| above apply.
2198 virtual nscoord GetPrefISize(gfxContext* aRenderingContext) = 0;
2201 * |InlineIntrinsicISize| represents the intrinsic width information
2202 * in inline layout. Code that determines the intrinsic width of a
2203 * region of inline layout accumulates the result into this structure.
2204 * This pattern is needed because we need to maintain state
2205 * information about whitespace (for both collapsing and trimming).
2207 struct InlineIntrinsicISizeData {
2208 InlineIntrinsicISizeData()
2209 : mLine(nullptr),
2210 mLineContainer(nullptr),
2211 mPrevLines(0),
2212 mCurrentLine(0),
2213 mTrailingWhitespace(0),
2214 mSkipWhitespace(true) {}
2216 // The line. This may be null if the inlines are not associated with
2217 // a block or if we just don't know the line.
2218 const nsLineList_iterator* mLine;
2220 // The line container. Private, to ensure we always use SetLineContainer
2221 // to update it.
2223 // Note that nsContainerFrame::DoInlineIntrinsicISize will clear the
2224 // |mLine| and |mLineContainer| fields when following a next-in-flow link,
2225 // so we must not assume these can always be dereferenced.
2226 private:
2227 nsIFrame* mLineContainer;
2229 // Setter and getter for the lineContainer field:
2230 public:
2231 void SetLineContainer(nsIFrame* aLineContainer) {
2232 mLineContainer = aLineContainer;
2234 nsIFrame* LineContainer() const { return mLineContainer; }
2236 // The maximum intrinsic width for all previous lines.
2237 nscoord mPrevLines;
2239 // The maximum intrinsic width for the current line. At a line
2240 // break (mandatory for preferred width; allowed for minimum width),
2241 // the caller should call |Break()|.
2242 nscoord mCurrentLine;
2244 // This contains the width of the trimmable whitespace at the end of
2245 // |mCurrentLine|; it is zero if there is no such whitespace.
2246 nscoord mTrailingWhitespace;
2248 // True if initial collapsable whitespace should be skipped. This
2249 // should be true at the beginning of a block, after hard breaks
2250 // and when the last text ended with whitespace.
2251 bool mSkipWhitespace;
2253 // Floats encountered in the lines.
2254 class FloatInfo {
2255 public:
2256 FloatInfo(const nsIFrame* aFrame, nscoord aWidth)
2257 : mFrame(aFrame), mWidth(aWidth) {}
2258 const nsIFrame* Frame() const { return mFrame; }
2259 nscoord Width() const { return mWidth; }
2261 private:
2262 const nsIFrame* mFrame;
2263 nscoord mWidth;
2266 nsTArray<FloatInfo> mFloats;
2269 struct InlineMinISizeData : public InlineIntrinsicISizeData {
2270 InlineMinISizeData() : mAtStartOfLine(true) {}
2272 // The default implementation for nsIFrame::AddInlineMinISize.
2273 void DefaultAddInlineMinISize(nsIFrame* aFrame, nscoord aISize,
2274 bool aAllowBreak = true);
2276 // We need to distinguish forced and optional breaks for cases where the
2277 // current line total is negative. When it is, we need to ignore
2278 // optional breaks to prevent min-width from ending up bigger than
2279 // pref-width.
2280 void ForceBreak();
2282 // If the break here is actually taken, aHyphenWidth must be added to the
2283 // width of the current line.
2284 void OptionallyBreak(nscoord aHyphenWidth = 0);
2286 // Whether we're currently at the start of the line. If we are, we
2287 // can't break (for example, between the text-indent and the first
2288 // word).
2289 bool mAtStartOfLine;
2292 struct InlinePrefISizeData : public InlineIntrinsicISizeData {
2293 typedef mozilla::StyleClear StyleClear;
2295 InlinePrefISizeData() : mLineIsEmpty(true) {}
2298 * Finish the current line and start a new line.
2300 * @param aBreakType controls whether isize of floats are considered
2301 * and what floats are kept for the next line:
2302 * * |None| skips handling floats, which means no floats are
2303 * removed, and isizes of floats are not considered either.
2304 * * |Both| takes floats into consideration when computing isize
2305 * of the current line, and removes all floats after that.
2306 * * |Left| and |Right| do the same as |Both| except that they only
2307 * remove floats on the given side, and any floats on the other
2308 * side that are prior to a float on the given side that has a
2309 * 'clear' property that clears them.
2310 * All other values of StyleClear must be converted to the four
2311 * physical values above for this function.
2313 void ForceBreak(StyleClear aBreakType = StyleClear::Both);
2315 // The default implementation for nsIFrame::AddInlinePrefISize.
2316 void DefaultAddInlinePrefISize(nscoord aISize);
2318 // True if the current line contains nothing other than placeholders.
2319 bool mLineIsEmpty;
2323 * Add the intrinsic minimum width of a frame in a way suitable for
2324 * use in inline layout to an |InlineIntrinsicISizeData| object that
2325 * represents the intrinsic width information of all the previous
2326 * frames in the inline layout region.
2328 * All *allowed* breakpoints within the frame determine what counts as
2329 * a line for the |InlineIntrinsicISizeData|. This means that
2330 * |aData->mTrailingWhitespace| will always be zero (unlike for
2331 * AddInlinePrefISize).
2333 * All the comments for |GetMinISize| apply, except that this function
2334 * is responsible for adding padding, border, and margin and for
2335 * considering the effects of 'width', 'min-width', and 'max-width'.
2337 * This may be called on any frame. Frames that do not participate in
2338 * line breaking can inherit the default implementation on nsFrame,
2339 * which calls |GetMinISize|.
2341 virtual void AddInlineMinISize(gfxContext* aRenderingContext,
2342 InlineMinISizeData* aData) = 0;
2345 * Add the intrinsic preferred width of a frame in a way suitable for
2346 * use in inline layout to an |InlineIntrinsicISizeData| object that
2347 * represents the intrinsic width information of all the previous
2348 * frames in the inline layout region.
2350 * All the comments for |AddInlineMinISize| and |GetPrefISize| apply,
2351 * except that this fills in an |InlineIntrinsicISizeData| structure
2352 * based on using all *mandatory* breakpoints within the frame.
2354 virtual void AddInlinePrefISize(gfxContext* aRenderingContext,
2355 InlinePrefISizeData* aData) = 0;
2358 * Return the horizontal components of padding, border, and margin
2359 * that contribute to the intrinsic width that applies to the parent.
2360 * @param aPercentageBasis the percentage basis to use for padding/margin -
2361 * i.e. the Containing Block's inline-size
2363 struct IntrinsicISizeOffsetData {
2364 nscoord hPadding, hBorder, hMargin;
2366 IntrinsicISizeOffsetData() : hPadding(0), hBorder(0), hMargin(0) {}
2368 virtual IntrinsicISizeOffsetData IntrinsicISizeOffsets(
2369 nscoord aPercentageBasis = NS_UNCONSTRAINEDSIZE) = 0;
2372 * Return the bsize components of padding, border, and margin
2373 * that contribute to the intrinsic width that applies to the parent.
2374 * @param aPercentageBasis the percentage basis to use for padding/margin -
2375 * i.e. the Containing Block's inline-size
2377 IntrinsicISizeOffsetData IntrinsicBSizeOffsets(
2378 nscoord aPercentageBasis = NS_UNCONSTRAINEDSIZE);
2380 virtual mozilla::IntrinsicSize GetIntrinsicSize() = 0;
2383 * Get the intrinsic ratio of this element, or a default-constructed
2384 * AspectRatio if it has no intrinsic ratio.
2386 * The intrinsic ratio is the ratio of the width/height of a box with an
2387 * intrinsic size or the intrinsic aspect ratio of a scalable vector image
2388 * without an intrinsic size.
2390 virtual mozilla::AspectRatio GetIntrinsicRatio() = 0;
2393 * Bit-flags to pass to ComputeSize in |aFlags| parameter.
2395 enum ComputeSizeFlags {
2396 eDefault = 0,
2398 * Set if the frame is in a context where non-replaced blocks should
2399 * shrink-wrap (e.g., it's floating, absolutely positioned, or
2400 * inline-block).
2402 eShrinkWrap = 1 << 0,
2404 * Set if we'd like to compute our 'auto' bsize, regardless of our actual
2405 * corresponding computed value. (e.g. to get an intrinsic height for flex
2406 * items with "min-height: auto" to use during flexbox layout.)
2408 eUseAutoBSize = 1 << 1,
2410 * Indicates that we should clamp the margin-box min-size to the given CB
2411 * size. This is used for implementing the grid area clamping here:
2412 * https://drafts.csswg.org/css-grid/#min-size-auto
2414 eIClampMarginBoxMinSize = 1 << 2, // clamp in our inline axis
2415 eBClampMarginBoxMinSize = 1 << 3, // clamp in our block axis
2417 * The frame is stretching (per CSS Box Alignment) and doesn't have an
2418 * Automatic Minimum Size in the indicated axis.
2419 * (may be used for both flex/grid items, but currently only used for Grid)
2420 * https://drafts.csswg.org/css-grid/#min-size-auto
2421 * https://drafts.csswg.org/css-align-3/#valdef-justify-self-stretch
2423 eIApplyAutoMinSize = 1 << 4, // only has an effect when eShrinkWrap is
2424 // false
2428 * Compute the size that a frame will occupy. Called while
2429 * constructing the ReflowInput to be used to Reflow the frame,
2430 * in order to fill its mComputedWidth and mComputedHeight member
2431 * variables.
2433 * The |height| member of the return value may be
2434 * NS_UNCONSTRAINEDSIZE, but the |width| member must not be.
2436 * Note that the reason that border and padding need to be passed
2437 * separately is so that the 'box-sizing' property can be handled.
2438 * Thus aMargin includes absolute positioning offsets as well.
2440 * @param aWritingMode The writing mode to use for the returned size
2441 * (need not match this frame's writing mode).
2442 * This is also the writing mode of the passed-in
2443 * LogicalSize parameters.
2444 * @param aCBSize The size of the element's containing block. (Well,
2445 * the |height| component isn't really.)
2446 * @param aAvailableWidth The available width for 'auto' widths.
2447 * This is usually the same as aCBSize.width,
2448 * but differs in cases such as block
2449 * formatting context roots next to floats, or
2450 * in some cases of float reflow in quirks
2451 * mode.
2452 * @param aMargin The sum of the vertical / horizontal margins
2453 * ***AND*** absolute positioning offsets (top, right,
2454 * bottom, left) of the frame, including actual values
2455 * resulting from percentages and from the
2456 * "hypothetical box" for absolute positioning, but
2457 * not including actual values resulting from 'auto'
2458 * margins or ignored 'auto' values in absolute
2459 * positioning.
2460 * @param aBorder The sum of the vertical / horizontal border widths
2461 * of the frame.
2462 * @param aPadding The sum of the vertical / horizontal margins of
2463 * the frame, including actual values resulting from
2464 * percentages.
2465 * @param aFlags Flags to further customize behavior (definitions above).
2467 virtual mozilla::LogicalSize ComputeSize(
2468 gfxContext* aRenderingContext, mozilla::WritingMode aWritingMode,
2469 const mozilla::LogicalSize& aCBSize, nscoord aAvailableISize,
2470 const mozilla::LogicalSize& aMargin, const mozilla::LogicalSize& aBorder,
2471 const mozilla::LogicalSize& aPadding, ComputeSizeFlags aFlags) = 0;
2474 * Compute a tight bounding rectangle for the frame. This is a rectangle
2475 * that encloses the pixels that are actually drawn. We're allowed to be
2476 * conservative and currently we don't try very hard. The rectangle is
2477 * in appunits and relative to the origin of this frame.
2479 * This probably only needs to include frame bounds, glyph bounds, and
2480 * text decorations, but today it sometimes includes other things that
2481 * contribute to visual overflow.
2483 * @param aDrawTarget a draw target that can be used if we need
2484 * to do measurement
2486 virtual nsRect ComputeTightBounds(DrawTarget* aDrawTarget) const;
2489 * This function is similar to GetPrefISize and ComputeTightBounds: it
2490 * computes the left and right coordinates of a preferred tight bounding
2491 * rectangle for the frame. This is a rectangle that would enclose the pixels
2492 * that are drawn if we lay out the element without taking any optional line
2493 * breaks. The rectangle is in appunits and relative to the origin of this
2494 * frame. Currently, this function is only implemented for nsBlockFrame and
2495 * nsTextFrame and is used to determine intrinsic widths of MathML token
2496 * elements.
2498 * @param aContext a rendering context that can be used if we need
2499 * to do measurement
2500 * @param aX computed left coordinate of the tight bounding rectangle
2501 * @param aXMost computed intrinsic width of the tight bounding rectangle
2504 virtual nsresult GetPrefWidthTightBounds(gfxContext* aContext, nscoord* aX,
2505 nscoord* aXMost);
2508 * The frame is given an available size and asked for its desired
2509 * size. This is the frame's opportunity to reflow its children.
2511 * If the frame has the NS_FRAME_IS_DIRTY bit set then it is
2512 * responsible for completely reflowing itself and all of its
2513 * descendants.
2515 * Otherwise, if the frame has the NS_FRAME_HAS_DIRTY_CHILDREN bit
2516 * set, then it is responsible for reflowing at least those
2517 * children that have NS_FRAME_HAS_DIRTY_CHILDREN or NS_FRAME_IS_DIRTY
2518 * set.
2520 * If a difference in available size from the previous reflow causes
2521 * the frame's size to change, it should reflow descendants as needed.
2523 * @param aReflowOutput <i>out</i> parameter where you should return the
2524 * desired size and ascent/descent info. You should include any
2525 * space you want for border/padding in the desired size you return.
2527 * It's okay to return a desired size that exceeds the avail
2528 * size if that's the smallest you can be, i.e. it's your
2529 * minimum size.
2531 * For an incremental reflow you are responsible for invalidating
2532 * any area within your frame that needs repainting (including
2533 * borders). If your new desired size is different than your current
2534 * size, then your parent frame is responsible for making sure that
2535 * the difference between the two rects is repainted
2537 * @param aReflowInput information about your reflow including the reason
2538 * for the reflow and the available space in which to lay out. Each
2539 * dimension of the available space can either be constrained or
2540 * unconstrained (a value of NS_UNCONSTRAINEDSIZE).
2542 * Note that the available space can be negative. In this case you
2543 * still must return an accurate desired size. If you're a container
2544 * you must <b>always</b> reflow at least one frame regardless of the
2545 * available space
2547 * @param aStatus a return value indicating whether the frame is complete
2548 * and whether the next-in-flow is dirty and needs to be reflowed
2550 virtual void Reflow(nsPresContext* aPresContext, ReflowOutput& aReflowOutput,
2551 const ReflowInput& aReflowInput,
2552 nsReflowStatus& aStatus) = 0;
2554 // Option flags for ReflowChild() and FinishReflowChild()
2555 // member functions
2556 enum class ReflowChildFlags : uint32_t {
2557 Default = 0,
2558 NoMoveView = 1 << 0,
2559 NoMoveFrame = (1 << 1) | NoMoveView,
2560 NoSizeView = 1 << 2,
2561 NoVisibility = 1 << 3,
2563 // Only applies to ReflowChild; if true, don't delete the next-in-flow, even
2564 // if the reflow is fully complete.
2565 NoDeleteNextInFlowChild = 1 << 4,
2567 // Only applies to FinishReflowChild. Tell it to call
2568 // ApplyRelativePositioning.
2569 ApplyRelativePositioning = 1 << 5
2573 * Post-reflow hook. After a frame is reflowed this method will be called
2574 * informing the frame that this reflow process is complete, and telling the
2575 * frame the status returned by the Reflow member function.
2577 * This call may be invoked many times, while NS_FRAME_IN_REFLOW is set,
2578 * before it is finally called once with a NS_FRAME_REFLOW_COMPLETE value.
2579 * When called with a NS_FRAME_REFLOW_COMPLETE value the NS_FRAME_IN_REFLOW
2580 * bit in the frame state will be cleared.
2582 * XXX This doesn't make sense. If the frame is reflowed but not complete,
2583 * then the status should have IsIncomplete() equal to true.
2584 * XXX Don't we want the semantics to dictate that we only call this once for
2585 * a given reflow?
2587 virtual void DidReflow(nsPresContext* aPresContext,
2588 const ReflowInput* aReflowInput) = 0;
2591 * Updates the overflow areas of the frame. This can be called if an
2592 * overflow area of the frame's children has changed without reflowing.
2593 * @return true if either of the overflow areas for this frame have changed.
2595 bool UpdateOverflow();
2598 * Computes any overflow area created by the frame itself (outside of the
2599 * frame bounds) and includes it into aOverflowAreas.
2601 * Returns false if updating overflow isn't supported for this frame.
2602 * If the frame requires a reflow instead, then it is responsible
2603 * for scheduling one.
2605 virtual bool ComputeCustomOverflow(nsOverflowAreas& aOverflowAreas) = 0;
2608 * Computes any overflow area created by children of this frame and
2609 * includes it into aOverflowAreas.
2611 virtual void UnionChildOverflow(nsOverflowAreas& aOverflowAreas) = 0;
2614 * Helper method used by block reflow to identify runs of text so
2615 * that proper word-breaking can be done.
2617 * @return
2618 * true if we can continue a "text run" through the frame. A
2619 * text run is text that should be treated contiguously for line
2620 * and word breaking.
2622 virtual bool CanContinueTextRun() const = 0;
2625 * Computes an approximation of the rendered text of the frame and its
2626 * continuations. Returns nothing for non-text frames.
2627 * The appended text will often not contain all the whitespace from source,
2628 * depending on CSS white-space processing.
2629 * if aEndOffset goes past end, use the text up to the string's end.
2630 * Call this on the primary frame for a text node.
2631 * aStartOffset and aEndOffset can be content offsets or offsets in the
2632 * rendered text, depending on aOffsetType.
2633 * Returns a string, as well as offsets identifying the start of the text
2634 * within the rendered text for the whole node, and within the text content
2635 * of the node.
2637 struct RenderedText {
2638 nsAutoString mString;
2639 uint32_t mOffsetWithinNodeRenderedText;
2640 int32_t mOffsetWithinNodeText;
2641 RenderedText()
2642 : mOffsetWithinNodeRenderedText(0), mOffsetWithinNodeText(0) {}
2644 enum class TextOffsetType {
2645 // Passed-in start and end offsets are within the content text.
2646 OffsetsInContentText,
2647 // Passed-in start and end offsets are within the rendered text.
2648 OffsetsInRenderedText,
2650 enum class TrailingWhitespace {
2651 Trim,
2652 // Spaces preceding a caret at the end of a line should not be trimmed
2653 DontTrim,
2655 virtual RenderedText GetRenderedText(
2656 uint32_t aStartOffset = 0, uint32_t aEndOffset = UINT32_MAX,
2657 TextOffsetType aOffsetType = TextOffsetType::OffsetsInContentText,
2658 TrailingWhitespace aTrimTrailingWhitespace = TrailingWhitespace::Trim) {
2659 return RenderedText();
2663 * Returns true if the frame contains any non-collapsed characters.
2664 * This method is only available for text frames, and it will return false
2665 * for all other frame types.
2667 virtual bool HasAnyNoncollapsedCharacters() { return false; }
2670 * Returns true if events of the given type targeted at this frame
2671 * should only be dispatched to the system group.
2673 virtual bool OnlySystemGroupDispatch(mozilla::EventMessage aMessage) const {
2674 return false;
2678 // Accessor functions to an associated view object:
2680 bool HasView() const { return !!(mState & NS_FRAME_HAS_VIEW); }
2682 protected:
2683 virtual nsView* GetViewInternal() const {
2684 MOZ_ASSERT_UNREACHABLE("method should have been overridden by subclass");
2685 return nullptr;
2687 virtual void SetViewInternal(nsView* aView) {
2688 MOZ_ASSERT_UNREACHABLE("method should have been overridden by subclass");
2691 public:
2692 nsView* GetView() const {
2693 if (MOZ_LIKELY(!HasView())) {
2694 return nullptr;
2696 nsView* view = GetViewInternal();
2697 MOZ_ASSERT(view, "GetViewInternal() should agree with HasView()");
2698 return view;
2700 void SetView(nsView* aView);
2703 * Find the closest view (on |this| or an ancestor).
2704 * If aOffset is non-null, it will be set to the offset of |this|
2705 * from the returned view.
2707 nsView* GetClosestView(nsPoint* aOffset = nullptr) const;
2710 * Find the closest ancestor (excluding |this| !) that has a view
2712 nsIFrame* GetAncestorWithView() const;
2715 * Sets the view's attributes from the frame style.
2716 * Call this for nsChangeHint_SyncFrameView style changes or when the view
2717 * has just been created.
2718 * @param aView the frame's view or use GetView() if nullptr is given
2720 void SyncFrameViewProperties(nsView* aView = nullptr);
2723 * Get the offset between the coordinate systems of |this| and aOther.
2724 * Adding the return value to a point in the coordinate system of |this|
2725 * will transform the point to the coordinate system of aOther.
2727 * aOther must be non-null.
2729 * This function is fastest when aOther is an ancestor of |this|.
2731 * This function _DOES NOT_ work across document boundaries.
2732 * Use this function only when |this| and aOther are in the same document.
2734 * NOTE: this actually returns the offset from aOther to |this|, but
2735 * that offset is added to transform _coordinates_ from |this| to
2736 * aOther.
2738 nsPoint GetOffsetTo(const nsIFrame* aOther) const;
2741 * Just like GetOffsetTo, but treats all scrollframes as scrolled to
2742 * their origin.
2744 nsPoint GetOffsetToIgnoringScrolling(const nsIFrame* aOther) const;
2747 * Get the offset between the coordinate systems of |this| and aOther
2748 * expressed in appunits per dev pixel of |this|' document. Adding the return
2749 * value to a point that is relative to the origin of |this| will make the
2750 * point relative to the origin of aOther but in the appunits per dev pixel
2751 * ratio of |this|.
2753 * aOther must be non-null.
2755 * This function is fastest when aOther is an ancestor of |this|.
2757 * This function works across document boundaries.
2759 * Because this function may cross document boundaries that have different
2760 * app units per dev pixel ratios it needs to be used very carefully.
2762 * NOTE: this actually returns the offset from aOther to |this|, but
2763 * that offset is added to transform _coordinates_ from |this| to
2764 * aOther.
2766 nsPoint GetOffsetToCrossDoc(const nsIFrame* aOther) const;
2769 * Like GetOffsetToCrossDoc, but the caller can specify which appunits
2770 * to return the result in.
2772 nsPoint GetOffsetToCrossDoc(const nsIFrame* aOther, const int32_t aAPD) const;
2775 * Get the rect of the frame relative to the top-left corner of the
2776 * screen in CSS pixels.
2777 * @return the CSS pixel rect of the frame relative to the top-left
2778 * corner of the screen.
2780 mozilla::CSSIntRect GetScreenRect() const;
2783 * Get the screen rect of the frame in app units.
2784 * @return the app unit rect of the frame in screen coordinates.
2786 nsRect GetScreenRectInAppUnits() const;
2789 * Returns the offset from this frame to the closest geometric parent that
2790 * has a view. Also returns the containing view or null in case of error
2792 void GetOffsetFromView(nsPoint& aOffset, nsView** aView) const;
2795 * Returns the nearest widget containing this frame. If this frame has a
2796 * view and the view has a widget, then this frame's widget is
2797 * returned, otherwise this frame's geometric parent is checked
2798 * recursively upwards.
2800 nsIWidget* GetNearestWidget() const;
2803 * Same as GetNearestWidget() above but uses an outparam to return the offset
2804 * of this frame to the returned widget expressed in appunits of |this| (the
2805 * widget might be in a different document with a different zoom).
2807 nsIWidget* GetNearestWidget(nsPoint& aOffset) const;
2810 * Whether the content for this frame is disabled, used for event handling.
2812 bool IsContentDisabled() const;
2815 * Get the "type" of the frame.
2817 * @see mozilla::LayoutFrameType
2819 mozilla::LayoutFrameType Type() const {
2820 MOZ_ASSERT(uint8_t(mClass) < mozilla::ArrayLength(sLayoutFrameTypes));
2821 return sLayoutFrameTypes[uint8_t(mClass)];
2824 #ifdef __GNUC__
2825 # pragma GCC diagnostic push
2826 # pragma GCC diagnostic ignored "-Wtype-limits"
2827 #endif
2828 #ifdef __clang__
2829 # pragma clang diagnostic push
2830 # pragma clang diagnostic ignored "-Wunknown-pragmas"
2831 # pragma clang diagnostic ignored "-Wtautological-unsigned-zero-compare"
2832 #endif
2834 #define FRAME_TYPE(name_, first_class_, last_class_) \
2835 bool Is##name_##Frame() const { \
2836 return uint8_t(mClass) >= uint8_t(ClassID::first_class_##_id) && \
2837 uint8_t(mClass) <= uint8_t(ClassID::last_class_##_id); \
2839 #include "mozilla/FrameTypeList.h"
2840 #undef FRAME_TYPE
2842 #ifdef __GNUC__
2843 # pragma GCC diagnostic pop
2844 #endif
2845 #ifdef __clang__
2846 # pragma clang diagnostic pop
2847 #endif
2850 * Returns a transformation matrix that converts points in this frame's
2851 * coordinate space to points in some ancestor frame's coordinate space.
2852 * The frame decides which ancestor it will use as a reference point.
2853 * If this frame has no ancestor, aOutAncestor will be set to null.
2855 * @param aStopAtAncestor don't look further than aStopAtAncestor. If null,
2856 * all ancestors (including across documents) will be traversed.
2857 * @param aOutAncestor [out] The ancestor frame the frame has chosen. If
2858 * this frame has no ancestor, *aOutAncestor will be set to null. If
2859 * this frame is not a root frame, then *aOutAncestor will be in the same
2860 * document as this frame. If this frame IsTransformed(), then *aOutAncestor
2861 * will be the parent frame (if not preserve-3d) or the nearest
2862 * non-transformed ancestor (if preserve-3d).
2863 * @return A Matrix4x4 that converts points in this frame's coordinate space
2864 * into points in aOutAncestor's coordinate space.
2866 enum {
2867 IN_CSS_UNITS = 1 << 0,
2868 STOP_AT_STACKING_CONTEXT_AND_DISPLAY_PORT = 1 << 1
2870 Matrix4x4Flagged GetTransformMatrix(const nsIFrame* aStopAtAncestor,
2871 nsIFrame** aOutAncestor,
2872 uint32_t aFlags = 0) const;
2875 * Bit-flags to pass to IsFrameOfType()
2877 enum {
2878 eMathML = 1 << 0,
2879 eSVG = 1 << 1,
2880 eSVGForeignObject = 1 << 2,
2881 eSVGContainer = 1 << 3,
2882 eSVGGeometry = 1 << 4,
2883 eSVGPaintServer = 1 << 5,
2884 eBidiInlineContainer = 1 << 6,
2885 // the frame is for a replaced element, such as an image
2886 eReplaced = 1 << 7,
2887 // Frame that contains a block but looks like a replaced element
2888 // from the outside
2889 eReplacedContainsBlock = 1 << 8,
2890 // A frame that participates in inline reflow, i.e., one that
2891 // requires ReflowInput::mLineLayout.
2892 eLineParticipant = 1 << 9,
2893 eXULBox = 1 << 10,
2894 eCanContainOverflowContainers = 1 << 11,
2895 eTablePart = 1 << 12,
2896 // If this bit is set, the frame doesn't allow ignorable whitespace as
2897 // children. For example, the whitespace between <table>\n<tr>\n<td>
2898 // will be excluded during the construction of children.
2899 eExcludesIgnorableWhitespace = 1 << 13,
2900 eSupportsCSSTransforms = 1 << 14,
2902 // A replaced element that has replaced-element sizing
2903 // characteristics (i.e., like images or iframes), as opposed to
2904 // inline-block sizing characteristics (like form controls).
2905 eReplacedSizing = 1 << 15,
2907 // Does this frame class support 'contain: layout' and
2908 // 'contain:paint' (supporting one is equivalent to supporting the
2909 // other).
2910 eSupportsContainLayoutAndPaint = 1 << 16,
2912 // These are to allow nsFrame::Init to assert that IsFrameOfType
2913 // implementations all call the base class method. They are only
2914 // meaningful in DEBUG builds.
2915 eDEBUGAllFrames = 1 << 30,
2916 eDEBUGNoFrames = 1 << 31
2920 * API for doing a quick check if a frame is of a given
2921 * type. Returns true if the frame matches ALL flags passed in.
2923 * Implementations should always override with inline virtual
2924 * functions that call the base class's IsFrameOfType method.
2926 virtual bool IsFrameOfType(uint32_t aFlags) const {
2927 return !(aFlags & ~(
2928 #ifdef DEBUG
2929 nsIFrame::eDEBUGAllFrames |
2930 #endif
2931 nsIFrame::eSupportsCSSTransforms |
2932 nsIFrame::eSupportsContainLayoutAndPaint));
2936 * Returns true if the frame is a block wrapper.
2938 bool IsBlockWrapper() const;
2941 * Returns true if the frame is an instance of nsBlockFrame or one of its
2942 * subclasses.
2944 bool IsBlockFrameOrSubclass() const;
2947 * Get this frame's CSS containing block.
2949 * The algorithm is defined in
2950 * http://www.w3.org/TR/CSS2/visudet.html#containing-block-details.
2952 * NOTE: This is guaranteed to return a non-null pointer when invoked on any
2953 * frame other than the root frame.
2955 * Requires SKIP_SCROLLED_FRAME to get behaviour matching the spec, otherwise
2956 * it can return anonymous inner scrolled frames. Bug 1204044 is filed for
2957 * investigating whether any of the callers actually require the default
2958 * behaviour.
2960 enum {
2961 // If the containing block is an anonymous scrolled frame, then skip over
2962 // this and return the outer scroll frame.
2963 SKIP_SCROLLED_FRAME = 0x01
2965 nsIFrame* GetContainingBlock(uint32_t aFlags,
2966 const nsStyleDisplay* aStyleDisplay) const;
2967 nsIFrame* GetContainingBlock(uint32_t aFlags = 0) const {
2968 return GetContainingBlock(aFlags, StyleDisplay());
2972 * Is this frame a containing block for floating elements?
2973 * Note that very few frames are, so default to false.
2975 virtual bool IsFloatContainingBlock() const { return false; }
2978 * Is this a leaf frame? Frames that want the frame constructor to be able
2979 * to construct kids for them should return false, all others should return
2980 * true. Note that returning true here does not mean that the frame _can't_
2981 * have kids. It could still have kids created via
2982 * nsIAnonymousContentCreator. Returning true indicates that "normal"
2983 * (non-anonymous, XBL-bound, CSS generated content, etc) children should not
2984 * be constructed.
2986 bool IsLeaf() const {
2987 MOZ_ASSERT(uint8_t(mClass) < mozilla::ArrayLength(sFrameClassBits));
2988 FrameClassBits bits = sFrameClassBits[uint8_t(mClass)];
2989 if (MOZ_UNLIKELY(bits & eFrameClassBitsDynamicLeaf)) {
2990 return IsLeafDynamic();
2992 return bits & eFrameClassBitsLeaf;
2996 * Marks all display items created by this frame as needing a repaint,
2997 * and calls SchedulePaint() if requested and one is not already pending.
2999 * This includes all display items created by this frame, including
3000 * container types.
3002 * @param aDisplayItemKey If specified, only issues an invalidate
3003 * if this frame painted a display item of that type during the
3004 * previous paint. SVG rendering observers are always notified.
3005 * @param aRebuildDisplayItems If true, then adds this frame to the
3006 * list of modified frames for display list building. Only pass false
3007 * if you're sure that the relevant display items will be rebuilt
3008 * already (possibly by an ancestor being in the modified list).
3010 virtual void InvalidateFrame(uint32_t aDisplayItemKey = 0,
3011 bool aRebuildDisplayItems = true);
3014 * Same as InvalidateFrame(), but only mark a fixed rect as needing
3015 * repainting.
3017 * @param aRect The rect to invalidate, relative to the TopLeft of the
3018 * frame's border box.
3019 * @param aDisplayItemKey If specified, only issues an invalidate
3020 * if this frame painted a display item of that type during the
3021 * previous paint. SVG rendering observers are always notified.
3022 * @param aRebuildDisplayItems If true, then adds this frame to the
3023 * list of modified frames for display list building. Only pass false
3024 * if you're sure that the relevant display items will be rebuilt
3025 * already (possibly by an ancestor being in the modified list).
3027 virtual void InvalidateFrameWithRect(const nsRect& aRect,
3028 uint32_t aDisplayItemKey = 0,
3029 bool aRebuildDisplayItems = true);
3032 * Calls InvalidateFrame() on all frames descendant frames (including
3033 * this one).
3035 * This function doesn't walk through placeholder frames to invalidate
3036 * the out-of-flow frames.
3038 * @param aRebuildDisplayItems If true, then adds this frame to the
3039 * list of modified frames for display list building. Only pass false
3040 * if you're sure that the relevant display items will be rebuilt
3041 * already (possibly by an ancestor being in the modified list).
3043 void InvalidateFrameSubtree(bool aRebuildDisplayItems = true);
3046 * Called when a frame is about to be removed and needs to be invalidated.
3047 * Normally does nothing since DLBI handles removed frames.
3049 virtual void InvalidateFrameForRemoval() {}
3052 * When HasUserData(frame->LayerIsPrerenderedDataKey()), then the
3053 * entire overflow area of this frame has been rendered in its
3054 * layer(s).
3056 static void* LayerIsPrerenderedDataKey() {
3057 return &sLayerIsPrerenderedDataKey;
3059 static uint8_t sLayerIsPrerenderedDataKey;
3062 * Try to update this frame's transform without invalidating any
3063 * content. Return true iff successful. If unsuccessful, the
3064 * caller is responsible for scheduling an invalidating paint.
3066 * If the result is true, aLayerResult will be filled in with the
3067 * transform layer for the frame.
3069 bool TryUpdateTransformOnly(Layer** aLayerResult);
3072 * Checks if a frame has had InvalidateFrame() called on it since the
3073 * last paint.
3075 * If true, then the invalid rect is returned in aRect, with an
3076 * empty rect meaning all pixels drawn by this frame should be
3077 * invalidated.
3078 * If false, aRect is left unchanged.
3080 bool IsInvalid(nsRect& aRect);
3083 * Check if any frame within the frame subtree (including this frame)
3084 * returns true for IsInvalid().
3086 bool HasInvalidFrameInSubtree() {
3087 return HasAnyStateBits(NS_FRAME_NEEDS_PAINT |
3088 NS_FRAME_DESCENDANT_NEEDS_PAINT);
3092 * Removes the invalid state from the current frame and all
3093 * descendant frames.
3095 void ClearInvalidationStateBits();
3098 * Ensures that the refresh driver is running, and schedules a view
3099 * manager flush on the next tick.
3101 * The view manager flush will update the layer tree, repaint any
3102 * invalid areas in the layer tree and schedule a layer tree
3103 * composite operation to display the layer tree.
3105 * In general it is not necessary for frames to call this when they change.
3106 * For example, changes that result in a reflow will have this called for
3107 * them by PresContext::DoReflow when the reflow begins. Style changes that
3108 * do not trigger a reflow should have this called for them by
3109 * DoApplyRenderingChangeToTree.
3111 * @param aType PAINT_COMPOSITE_ONLY : No changes have been made
3112 * that require a layer tree update, so only schedule a layer
3113 * tree composite.
3114 * PAINT_DELAYED_COMPRESS : Schedule a paint to be executed after a delay, and
3115 * put FrameLayerBuilder in 'compressed' mode that avoids short cut
3116 * optimizations.
3118 enum PaintType {
3119 PAINT_DEFAULT = 0,
3120 PAINT_COMPOSITE_ONLY,
3121 PAINT_DELAYED_COMPRESS
3123 void SchedulePaint(PaintType aType = PAINT_DEFAULT,
3124 bool aFrameChanged = true);
3126 // Similar to SchedulePaint() but without calling
3127 // InvalidateRenderingObservers() for SVG.
3128 void SchedulePaintWithoutInvalidatingObservers(
3129 PaintType aType = PAINT_DEFAULT);
3132 * Checks if the layer tree includes a dedicated layer for this
3133 * frame/display item key pair, and invalidates at least aDamageRect
3134 * area within that layer.
3136 * If no layer is found, calls InvalidateFrame() instead.
3138 * @param aDamageRect Area of the layer to invalidate.
3139 * @param aFrameDamageRect If no layer is found, the area of the frame to
3140 * invalidate. If null, the entire frame will be
3141 * invalidated.
3142 * @param aDisplayItemKey Display item type.
3143 * @param aFlags UPDATE_IS_ASYNC : Will skip the invalidation
3144 * if the found layer is being composited by a remote
3145 * compositor.
3146 * @return Layer, if found, nullptr otherwise.
3148 enum { UPDATE_IS_ASYNC = 1 << 0 };
3149 Layer* InvalidateLayer(DisplayItemType aDisplayItemKey,
3150 const nsIntRect* aDamageRect = nullptr,
3151 const nsRect* aFrameDamageRect = nullptr,
3152 uint32_t aFlags = 0);
3154 void MarkNeedsDisplayItemRebuild();
3157 * Returns a rect that encompasses everything that might be painted by
3158 * this frame. This includes this frame, all its descendant frames, this
3159 * frame's outline, and descendant frames' outline, but does not include
3160 * areas clipped out by the CSS "overflow" and "clip" properties.
3162 * HasOverflowAreas() (below) will return true when this overflow
3163 * rect has been explicitly set, even if it matches mRect.
3164 * XXX Note: because of a space optimization using the formula above,
3165 * during reflow this function does not give accurate data if
3166 * FinishAndStoreOverflow has been called but mRect hasn't yet been
3167 * updated yet. FIXME: This actually isn't true, but it should be.
3169 * The visual overflow rect should NEVER be used for things that
3170 * affect layout. The scrollable overflow rect is permitted to affect
3171 * layout.
3173 * @return the rect relative to this frame's origin, but after
3174 * CSS transforms have been applied (i.e. not really this frame's coordinate
3175 * system, and may not contain the frame's border-box, e.g. if there
3176 * is a CSS transform scaling it down)
3178 nsRect GetVisualOverflowRect() const {
3179 return GetOverflowRect(eVisualOverflow);
3183 * Returns a rect that encompasses the area of this frame that the
3184 * user should be able to scroll to reach. This is similar to
3185 * GetVisualOverflowRect, but does not include outline or shadows, and
3186 * may in the future include more margins than visual overflow does.
3187 * It does not include areas clipped out by the CSS "overflow" and
3188 * "clip" properties.
3190 * HasOverflowAreas() (below) will return true when this overflow
3191 * rect has been explicitly set, even if it matches mRect.
3192 * XXX Note: because of a space optimization using the formula above,
3193 * during reflow this function does not give accurate data if
3194 * FinishAndStoreOverflow has been called but mRect hasn't yet been
3195 * updated yet.
3197 * @return the rect relative to this frame's origin, but after
3198 * CSS transforms have been applied (i.e. not really this frame's coordinate
3199 * system, and may not contain the frame's border-box, e.g. if there
3200 * is a CSS transform scaling it down)
3202 nsRect GetScrollableOverflowRect() const {
3203 return GetOverflowRect(eScrollableOverflow);
3206 nsRect GetOverflowRect(nsOverflowType aType) const;
3208 nsOverflowAreas GetOverflowAreas() const;
3211 * Same as GetOverflowAreas, except in this frame's coordinate
3212 * system (before transforms are applied).
3214 * @return the overflow areas relative to this frame, before any CSS
3215 * transforms have been applied, i.e. in this frame's coordinate system
3217 nsOverflowAreas GetOverflowAreasRelativeToSelf() const;
3220 * Same as GetScrollableOverflowRect, except relative to the parent
3221 * frame.
3223 * @return the rect relative to the parent frame, in the parent frame's
3224 * coordinate system
3226 nsRect GetScrollableOverflowRectRelativeToParent() const;
3229 * Same as GetScrollableOverflowRect, except in this frame's coordinate
3230 * system (before transforms are applied).
3232 * @return the rect relative to this frame, before any CSS transforms have
3233 * been applied, i.e. in this frame's coordinate system
3235 nsRect GetScrollableOverflowRectRelativeToSelf() const;
3238 * Like GetVisualOverflowRect, except in this frame's
3239 * coordinate system (before transforms are applied).
3241 * @return the rect relative to this frame, before any CSS transforms have
3242 * been applied, i.e. in this frame's coordinate system
3244 nsRect GetVisualOverflowRectRelativeToSelf() const;
3247 * Same as GetVisualOverflowRect, except relative to the parent
3248 * frame.
3250 * @return the rect relative to the parent frame, in the parent frame's
3251 * coordinate system
3253 nsRect GetVisualOverflowRectRelativeToParent() const;
3256 * Returns this frame's visual overflow rect as it would be before taking
3257 * account of SVG effects or transforms. The rect returned is relative to
3258 * this frame.
3260 nsRect GetPreEffectsVisualOverflowRect() const;
3263 * Store the overflow area in the frame's mOverflow.mVisualDeltas
3264 * fields or as a frame property in the frame manager so that it can
3265 * be retrieved later without reflowing the frame. Returns true if either of
3266 * the overflow areas changed.
3268 bool FinishAndStoreOverflow(nsOverflowAreas& aOverflowAreas, nsSize aNewSize,
3269 nsSize* aOldSize = nullptr,
3270 const nsStyleDisplay* aStyleDisplay = nullptr);
3272 bool FinishAndStoreOverflow(ReflowOutput* aMetrics,
3273 const nsStyleDisplay* aStyleDisplay = nullptr) {
3274 return FinishAndStoreOverflow(aMetrics->mOverflowAreas,
3275 nsSize(aMetrics->Width(), aMetrics->Height()),
3276 nullptr, aStyleDisplay);
3280 * Returns whether the frame has an overflow rect that is different from
3281 * its border-box.
3283 bool HasOverflowAreas() const {
3284 return mOverflow.mType != NS_FRAME_OVERFLOW_NONE;
3288 * Removes any stored overflow rects (visual and scrollable) from the frame.
3289 * Returns true if the overflow changed.
3291 bool ClearOverflowRects();
3294 * Determine whether borders, padding, margins etc should NOT be applied
3295 * on certain sides of the frame.
3296 * @see mozilla::Sides in gfx/2d/BaseMargin.h
3297 * @see mozilla::LogicalSides in layout/generic/WritingModes.h
3299 * @note (See also bug 743402, comment 11) GetSkipSides() checks to see
3300 * if this frame has a previous or next continuation to determine
3301 * if a side should be skipped.
3302 * Unfortunately, this only works after reflow has been completed. In
3303 * lieu of this, during reflow, an ReflowInput parameter can be
3304 * passed in, indicating that it should be used to determine if sides
3305 * should be skipped during reflow.
3307 Sides GetSkipSides(const ReflowInput* aReflowInput = nullptr) const;
3308 virtual LogicalSides GetLogicalSkipSides(
3309 const ReflowInput* aReflowInput = nullptr) const {
3310 return LogicalSides();
3314 * @returns true if this frame is selected.
3316 bool IsSelected() const {
3317 return (GetContent() && GetContent()->IsSelectionDescendant())
3318 ? IsFrameSelected()
3319 : false;
3323 * Called to discover where this frame, or a parent frame has user-select
3324 * style applied, which affects that way that it is selected.
3326 * @param aSelectStyle out param. Returns the type of selection style found
3327 * (using values defined in nsStyleConsts.h).
3329 * @return Whether the frame can be selected (i.e. is not affected by
3330 * user-select: none)
3332 bool IsSelectable(mozilla::StyleUserSelect* aSelectStyle) const;
3335 * Called to retrieve the SelectionController associated with the frame.
3337 * @param aSelCon will contain the selection controller associated with
3338 * the frame.
3340 virtual nsresult GetSelectionController(nsPresContext* aPresContext,
3341 nsISelectionController** aSelCon) = 0;
3344 * Call to get nsFrameSelection for this frame.
3346 already_AddRefed<nsFrameSelection> GetFrameSelection();
3349 * GetConstFrameSelection returns an object which methods are safe to use for
3350 * example in nsIFrame code.
3352 const nsFrameSelection* GetConstFrameSelection() const;
3355 * called to find the previous/next character, word, or line. Returns the
3356 * actual nsIFrame and the frame offset. THIS DOES NOT CHANGE SELECTION STATE.
3357 * Uses frame's begin selection state to start. If no selection on this frame
3358 * will return NS_ERROR_FAILURE.
3360 * @param aPOS is defined in nsFrameSelection
3362 virtual nsresult PeekOffset(nsPeekOffsetStruct* aPos);
3365 * Called to find the previous/next non-anonymous selectable leaf frame.
3367 * @param aDirection [in] the direction to move in (eDirPrevious or eDirNext)
3369 * @param aVisual [in] whether bidi caret behavior is visual (true) or
3370 * logical (false)
3372 * @param aJumpLines [in] whether to allow jumping across line boundaries
3373 * @param aScrollViewStop [in] whether to stop when reaching a scroll frame
3374 * boundary
3376 * @param aOutFrame [out] the previous/next selectable leaf frame
3378 * @param aOutOffset [out] 0 indicates that we arrived at the beginning of
3379 * the output frame; -1 indicates that we arrived at its end.
3381 * @param aOutJumpedLine [out] whether this frame and the returned frame are
3382 * on different lines
3384 * @param aOutMovedOverNonSelectableText [out] whether we jumped over a
3385 * non-selectable frame during the search
3387 nsresult GetFrameFromDirection(nsDirection aDirection, bool aVisual,
3388 bool aJumpLines, bool aScrollViewStop,
3389 bool aForceEditableRegion,
3390 nsIFrame** aOutFrame, int32_t* aOutOffset,
3391 bool* aOutJumpedLine,
3392 bool* aOutMovedOverNonSelectableText);
3395 * Called to see if the children of the frame are visible from indexstart to
3396 * index end. This does not change any state. Returns true only if the indexes
3397 * are valid and any of the children are visible. For textframes this index
3398 * is the character index. If aStart = aEnd result will be false.
3400 * @param aStart start index of first child from 0-N (number of children)
3402 * @param aEnd end index of last child from 0-N
3404 * @param aRecurse should this frame talk to siblings to get to the contents
3405 * other children?
3407 * @param aFinished did this frame have the aEndIndex? or is there more work
3408 * to do
3410 * @param _retval return value true or false. false = range is not rendered.
3412 virtual nsresult CheckVisibility(nsPresContext* aContext, int32_t aStartIndex,
3413 int32_t aEndIndex, bool aRecurse,
3414 bool* aFinished, bool* _retval) = 0;
3417 * Called to tell a frame that one of its child frames is dirty (i.e.,
3418 * has the NS_FRAME_IS_DIRTY *or* NS_FRAME_HAS_DIRTY_CHILDREN bit
3419 * set). This should always set the NS_FRAME_HAS_DIRTY_CHILDREN on
3420 * the frame, and may do other work.
3422 virtual void ChildIsDirty(nsIFrame* aChild) = 0;
3425 * Called to retrieve this frame's accessible.
3426 * If this frame implements Accessibility return a valid accessible
3427 * If not return NS_ERROR_NOT_IMPLEMENTED.
3428 * Note: Accessible must be refcountable. Do not implement directly on your
3429 * frame Use a mediatior of some kind.
3431 #ifdef ACCESSIBILITY
3432 virtual mozilla::a11y::AccType AccessibleType() = 0;
3433 #endif
3436 * Get the frame whose style should be the parent of this frame's style (i.e.,
3437 * provide the parent style).
3439 * This frame must either be an ancestor of this frame or a child. If
3440 * this returns a child frame, then the child frame must be sure to
3441 * return a grandparent or higher! Furthermore, if a child frame is
3442 * returned it must have the same GetContent() as this frame.
3444 * @param aProviderFrame (out) the frame associated with the returned value
3445 * or nullptr if the style is for display:contents content.
3446 * @return The style that should be the parent of this frame's style. Null is
3447 * permitted, and means that this frame's style should be the root of
3448 * the style tree.
3450 virtual ComputedStyle* GetParentComputedStyle(
3451 nsIFrame** aProviderFrame) const = 0;
3454 * Called by RestyleManager to update the style of anonymous boxes
3455 * directly associated with this frame.
3457 * The passed-in ServoRestyleState can be used to create new ComputedStyles as
3458 * needed, as well as posting changes to the change list.
3460 * It's guaranteed to already have a change in it for this frame and this
3461 * frame's content.
3463 * This function will be called after this frame's style has already been
3464 * updated. This function will only be called on frames which have the
3465 * NS_FRAME_OWNS_ANON_BOXES bit set.
3467 void UpdateStyleOfOwnedAnonBoxes(mozilla::ServoRestyleState& aRestyleState) {
3468 if (GetStateBits() & NS_FRAME_OWNS_ANON_BOXES) {
3469 DoUpdateStyleOfOwnedAnonBoxes(aRestyleState);
3473 protected:
3474 // This does the actual work of UpdateStyleOfOwnedAnonBoxes. It calls
3475 // AppendDirectlyOwnedAnonBoxes to find all of the anonymous boxes
3476 // owned by this frame, and then updates styles on each of them.
3477 void DoUpdateStyleOfOwnedAnonBoxes(mozilla::ServoRestyleState& aRestyleState);
3479 // A helper for DoUpdateStyleOfOwnedAnonBoxes for the specific case
3480 // of the owned anon box being a child of this frame.
3481 void UpdateStyleOfChildAnonBox(nsIFrame* aChildFrame,
3482 mozilla::ServoRestyleState& aRestyleState);
3484 // Allow ServoRestyleState to call UpdateStyleOfChildAnonBox.
3485 friend class mozilla::ServoRestyleState;
3487 public:
3488 // A helper both for UpdateStyleOfChildAnonBox, and to update frame-backed
3489 // pseudo-elements in RestyleManager.
3491 // This gets a ComputedStyle that will be the new style for `aChildFrame`, and
3492 // takes care of updating it, calling CalcStyleDifference, and adding to the
3493 // change list as appropriate.
3495 // If aContinuationComputedStyle is not Nothing, it should be used for
3496 // continuations instead of aNewComputedStyle. In either case, changehints
3497 // are only computed based on aNewComputedStyle.
3499 // Returns the generated change hint for the frame.
3500 static nsChangeHint UpdateStyleOfOwnedChildFrame(
3501 nsIFrame* aChildFrame, ComputedStyle* aNewComputedStyle,
3502 mozilla::ServoRestyleState& aRestyleState,
3503 const Maybe<ComputedStyle*>& aContinuationComputedStyle = Nothing());
3505 struct OwnedAnonBox {
3506 typedef void (*UpdateStyleFn)(nsIFrame* aOwningFrame, nsIFrame* aAnonBox,
3507 mozilla::ServoRestyleState& aRestyleState);
3509 explicit OwnedAnonBox(nsIFrame* aAnonBoxFrame,
3510 UpdateStyleFn aUpdateStyleFn = nullptr)
3511 : mAnonBoxFrame(aAnonBoxFrame), mUpdateStyleFn(aUpdateStyleFn) {}
3513 nsIFrame* mAnonBoxFrame;
3514 UpdateStyleFn mUpdateStyleFn;
3518 * Appends information about all of the anonymous boxes owned by this frame,
3519 * including other anonymous boxes owned by those which this frame owns
3520 * directly.
3522 void AppendOwnedAnonBoxes(nsTArray<OwnedAnonBox>& aResult) {
3523 if (GetStateBits() & NS_FRAME_OWNS_ANON_BOXES) {
3524 if (IsInlineFrame()) {
3525 // See comment in nsIFrame::DoUpdateStyleOfOwnedAnonBoxes for why
3526 // we skip nsInlineFrames.
3527 return;
3529 DoAppendOwnedAnonBoxes(aResult);
3533 protected:
3534 // This does the actual work of AppendOwnedAnonBoxes.
3535 void DoAppendOwnedAnonBoxes(nsTArray<OwnedAnonBox>& aResult);
3537 public:
3539 * Hook subclasses can override to return their owned anonymous boxes.
3541 * This function only appends anonymous boxes that are directly owned by
3542 * this frame, i.e. direct children or (for certain frames) a wrapper
3543 * parent, unlike AppendOwnedAnonBoxes, which will append all anonymous
3544 * boxes transitively owned by this frame.
3546 virtual void AppendDirectlyOwnedAnonBoxes(nsTArray<OwnedAnonBox>& aResult);
3549 * Determines whether a frame is visible for painting;
3550 * taking into account whether it is painting a selection or printing.
3552 bool IsVisibleForPainting();
3554 * Determines whether a frame is visible for painting or collapsed;
3555 * taking into account whether it is painting a selection or printing,
3557 bool IsVisibleOrCollapsedForPainting();
3560 * Determines if this frame is a stacking context.
3562 * @param aIsPositioned The precomputed result of IsAbsPosContainingBlock
3563 * on the StyleDisplay().
3565 bool IsStackingContext(const nsStyleDisplay* aStyleDisplay,
3566 const nsStylePosition* aStylePosition,
3567 const nsStyleEffects* aStyleEffects,
3568 bool aIsPositioned);
3569 bool IsStackingContext();
3571 virtual bool HonorPrintBackgroundSettings() { return true; }
3574 * Determine whether the frame is logically empty, which is roughly
3575 * whether the layout would be the same whether or not the frame is
3576 * present. Placeholder frames should return true. Block frames
3577 * should be considered empty whenever margins collapse through them,
3578 * even though those margins are relevant. Text frames containing
3579 * only whitespace that does not contribute to the height of the line
3580 * should return true.
3582 virtual bool IsEmpty() = 0;
3584 * Return the same as IsEmpty(). This may only be called after the frame
3585 * has been reflowed and before any further style or content changes.
3587 virtual bool CachedIsEmpty();
3589 * Determine whether the frame is logically empty, assuming that all
3590 * its children are empty.
3592 virtual bool IsSelfEmpty() = 0;
3595 * IsGeneratedContentFrame returns whether a frame corresponds to
3596 * generated content
3598 * @return whether the frame correspods to generated content
3600 bool IsGeneratedContentFrame() const {
3601 return (mState & NS_FRAME_GENERATED_CONTENT) != 0;
3605 * IsPseudoFrame returns whether a frame is a pseudo frame (eg an
3606 * anonymous table-row frame created for a CSS table-cell without an
3607 * enclosing table-row.
3609 * @param aParentContent the content node corresponding to the parent frame
3610 * @return whether the frame is a pseudo frame
3612 bool IsPseudoFrame(const nsIContent* aParentContent) {
3613 return mContent == aParentContent;
3617 * Support for reading and writing properties on the frame.
3618 * These call through to the frame's FrameProperties object, if it
3619 * exists, but avoid creating it if no property is ever set.
3621 template <typename T>
3622 FrameProperties::PropertyType<T> GetProperty(
3623 FrameProperties::Descriptor<T> aProperty,
3624 bool* aFoundResult = nullptr) const {
3625 return mProperties.Get(aProperty, aFoundResult);
3628 template <typename T>
3629 bool HasProperty(FrameProperties::Descriptor<T> aProperty) const {
3630 return mProperties.Has(aProperty);
3633 // Add a property, or update an existing property for the given descriptor.
3634 template <typename T>
3635 void SetProperty(FrameProperties::Descriptor<T> aProperty,
3636 FrameProperties::PropertyType<T> aValue) {
3637 mProperties.Set(aProperty, aValue, this);
3640 // Unconditionally add a property; use ONLY if the descriptor is known
3641 // to NOT already be present.
3642 template <typename T>
3643 void AddProperty(FrameProperties::Descriptor<T> aProperty,
3644 FrameProperties::PropertyType<T> aValue) {
3645 mProperties.Add(aProperty, aValue);
3648 template <typename T>
3649 FrameProperties::PropertyType<T> RemoveProperty(
3650 FrameProperties::Descriptor<T> aProperty, bool* aFoundResult = nullptr) {
3651 return mProperties.Remove(aProperty, aFoundResult);
3654 template <typename T>
3655 void DeleteProperty(FrameProperties::Descriptor<T> aProperty) {
3656 mProperties.Delete(aProperty, this);
3659 void DeleteAllProperties() { mProperties.DeleteAll(this); }
3661 // nsIFrames themselves are in the nsPresArena, and so are not measured here.
3662 // Instead, this measures heap-allocated things hanging off the nsIFrame, and
3663 // likewise for its descendants.
3664 virtual void AddSizeOfExcludingThisForTree(nsWindowSizes& aWindowSizes) const;
3667 * Return true if and only if this frame obeys visibility:hidden.
3668 * if it does not, then nsContainerFrame will hide its view even though
3669 * this means children can't be made visible again.
3671 virtual bool SupportsVisibilityHidden() { return true; }
3674 * Returns the clip rect set via the 'clip' property, if the 'clip' property
3675 * applies to this frame; otherwise returns Nothing(). The 'clip' property
3676 * applies to HTML frames if they are absolutely positioned. The 'clip'
3677 * property applies to SVG frames regardless of the value of the 'position'
3678 * property.
3680 * The coordinates of the returned rectangle are relative to this frame's
3681 * origin.
3683 Maybe<nsRect> GetClipPropClipRect(const nsStyleDisplay* aDisp,
3684 const nsStyleEffects* aEffects,
3685 const nsSize& aSize) const;
3688 * Check if this frame is focusable and in the current tab order.
3689 * Tabbable is indicated by a nonnegative tabindex & is a subset of focusable.
3690 * For example, only the selected radio button in a group is in the
3691 * tab order, unless the radio group has no selection in which case
3692 * all of the visible, non-disabled radio buttons in the group are
3693 * in the tab order. On the other hand, all of the visible, non-disabled
3694 * radio buttons are always focusable via clicking or script.
3695 * Also, depending on the pref accessibility.tabfocus some widgets may be
3696 * focusable but removed from the tab order. This is the default on
3697 * Mac OS X, where fewer items are focusable.
3698 * @param [in, optional] aTabIndex the computed tab index
3699 * < 0 if not tabbable
3700 * == 0 if in normal tab order
3701 * > 0 can be tabbed to in the order specified by this value
3702 * @param [in, optional] aWithMouse, is this focus query for mouse clicking
3703 * @return whether the frame is focusable via mouse, kbd or script.
3705 virtual bool IsFocusable(int32_t* aTabIndex = nullptr,
3706 bool aWithMouse = false);
3708 // BOX LAYOUT METHODS
3709 // These methods have been migrated from nsIBox and are in the process of
3710 // being refactored. DO NOT USE OUTSIDE OF XUL.
3711 bool IsXULBoxFrame() const { return IsFrameOfType(nsIFrame::eXULBox); }
3713 enum Halignment { hAlign_Left, hAlign_Right, hAlign_Center };
3715 enum Valignment { vAlign_Top, vAlign_Middle, vAlign_BaseLine, vAlign_Bottom };
3718 * This calculates the minimum size required for a box based on its state
3719 * @param[in] aBoxLayoutState The desired state to calculate for
3720 * @return The minimum size
3722 virtual nsSize GetXULMinSize(nsBoxLayoutState& aBoxLayoutState) = 0;
3725 * This calculates the preferred size of a box based on its state
3726 * @param[in] aBoxLayoutState The desired state to calculate for
3727 * @return The preferred size
3729 virtual nsSize GetXULPrefSize(nsBoxLayoutState& aBoxLayoutState) = 0;
3732 * This calculates the maximum size for a box based on its state
3733 * @param[in] aBoxLayoutState The desired state to calculate for
3734 * @return The maximum size
3736 virtual nsSize GetXULMaxSize(nsBoxLayoutState& aBoxLayoutState) = 0;
3739 * This returns the minimum size for the scroll area if this frame is
3740 * being scrolled. Usually it's (0,0).
3742 virtual nsSize GetXULMinSizeForScrollArea(
3743 nsBoxLayoutState& aBoxLayoutState) = 0;
3745 // Implemented in nsBox, used in nsBoxFrame
3746 int32_t GetXULOrdinal();
3748 virtual nscoord GetXULFlex() = 0;
3749 virtual nscoord GetXULBoxAscent(nsBoxLayoutState& aBoxLayoutState) = 0;
3750 virtual bool IsXULCollapsed() = 0;
3751 // This does not alter the overflow area. If the caller is changing
3752 // the box size, the caller is responsible for updating the overflow
3753 // area. It's enough to just call XULLayout or SyncLayout on the
3754 // box. You can pass true to aRemoveOverflowArea as a
3755 // convenience.
3756 virtual void SetXULBounds(nsBoxLayoutState& aBoxLayoutState,
3757 const nsRect& aRect,
3758 bool aRemoveOverflowAreas = false) = 0;
3759 nsresult XULLayout(nsBoxLayoutState& aBoxLayoutState);
3760 // Box methods. Note that these do NOT just get the CSS border, padding,
3761 // etc. They also talk to nsITheme.
3762 virtual nsresult GetXULBorderAndPadding(nsMargin& aBorderAndPadding);
3763 virtual nsresult GetXULBorder(nsMargin& aBorder) = 0;
3764 virtual nsresult GetXULPadding(nsMargin& aBorderAndPadding) = 0;
3765 virtual nsresult GetXULMargin(nsMargin& aMargin) = 0;
3766 virtual void SetXULLayoutManager(nsBoxLayout* aLayout) {}
3767 virtual nsBoxLayout* GetXULLayoutManager() { return nullptr; }
3768 nsresult GetXULClientRect(nsRect& aContentRect);
3770 virtual ReflowChildFlags GetXULLayoutFlags() {
3771 return ReflowChildFlags::Default;
3774 // For nsSprocketLayout
3775 virtual Valignment GetXULVAlign() const = 0;
3776 virtual Halignment GetXULHAlign() const = 0;
3778 bool IsXULHorizontal() const {
3779 return (mState & NS_STATE_IS_HORIZONTAL) != 0;
3781 bool IsXULNormalDirection() const {
3782 return (mState & NS_STATE_IS_DIRECTION_NORMAL) != 0;
3785 nsresult XULRedraw(nsBoxLayoutState& aState);
3786 virtual nsresult XULRelayoutChildAtOrdinal(nsIFrame* aChild) = 0;
3788 static bool AddXULPrefSize(nsIFrame* aBox, nsSize& aSize, bool& aWidth,
3789 bool& aHeightSet);
3790 static bool AddXULMinSize(nsBoxLayoutState& aState, nsIFrame* aBox,
3791 nsSize& aSize, bool& aWidth, bool& aHeightSet);
3792 static bool AddXULMaxSize(nsIFrame* aBox, nsSize& aSize, bool& aWidth,
3793 bool& aHeightSet);
3794 static bool AddXULFlex(nsIFrame* aBox, nscoord& aFlex);
3796 // END OF BOX LAYOUT METHODS
3797 // The above methods have been migrated from nsIBox and are in the process of
3798 // being refactored. DO NOT USE OUTSIDE OF XUL.
3801 * @return true if this text frame ends with a newline character. It
3802 * should return false if this is not a text frame.
3804 virtual bool HasSignificantTerminalNewline() const;
3806 struct CaretPosition {
3807 CaretPosition();
3808 ~CaretPosition();
3810 nsCOMPtr<nsIContent> mResultContent;
3811 int32_t mContentOffset;
3815 * gets the first or last possible caret position within the frame
3817 * @param [in] aStart
3818 * true for getting the first possible caret position
3819 * false for getting the last possible caret position
3820 * @return The caret position in a CaretPosition.
3821 * the returned value is a 'best effort' in case errors
3822 * are encountered rummaging through the frame.
3824 CaretPosition GetExtremeCaretPosition(bool aStart);
3827 * Get a line iterator for this frame, if supported.
3829 * @return nullptr if no line iterator is supported.
3830 * @note dispose the line iterator using nsILineIterator::DisposeLineIterator
3832 virtual nsILineIterator* GetLineIterator() = 0;
3835 * If this frame is a next-in-flow, and its prev-in-flow has something on its
3836 * overflow list, pull those frames into the child list of this one.
3838 virtual void PullOverflowsFromPrevInFlow() {}
3841 * Clear the list of child PresShells generated during the last paint
3842 * so that we can begin generating a new one.
3844 void ClearPresShellsFromLastPaint() { PaintedPresShellList()->Clear(); }
3847 * Flag a child PresShell as painted so that it will get its paint count
3848 * incremented during empty transactions.
3850 void AddPaintedPresShell(mozilla::PresShell* aPresShell) {
3851 PaintedPresShellList()->AppendElement(do_GetWeakReference(aPresShell));
3855 * Increment the paint count of all child PresShells that were painted during
3856 * the last repaint.
3858 void UpdatePaintCountForPaintedPresShells() {
3859 for (nsWeakPtr& item : *PaintedPresShellList()) {
3860 if (RefPtr<mozilla::PresShell> presShell = do_QueryReferent(item)) {
3861 presShell->IncrementPaintCount();
3867 * @return true if we painted @aPresShell during the last repaint.
3869 bool DidPaintPresShell(mozilla::PresShell* aPresShell) {
3870 for (nsWeakPtr& item : *PaintedPresShellList()) {
3871 RefPtr<mozilla::PresShell> presShell = do_QueryReferent(item);
3872 if (presShell == aPresShell) {
3873 return true;
3876 return false;
3880 * Accessors for the absolute containing block.
3882 bool IsAbsoluteContainer() const {
3883 return !!(mState & NS_FRAME_HAS_ABSPOS_CHILDREN);
3885 bool HasAbsolutelyPositionedChildren() const;
3886 nsAbsoluteContainingBlock* GetAbsoluteContainingBlock() const;
3887 void MarkAsAbsoluteContainingBlock();
3888 void MarkAsNotAbsoluteContainingBlock();
3889 // Child frame types override this function to select their own child list
3890 // name
3891 virtual mozilla::layout::FrameChildListID GetAbsoluteListID() const {
3892 return kAbsoluteList;
3895 // Checks if we (or any of our descendents) have NS_FRAME_PAINTED_THEBES set,
3896 // and clears this bit if so.
3897 bool CheckAndClearPaintedState();
3899 // Checks if we (or any of our descendents) have mBuiltDisplayList set, and
3900 // clears this bit if so.
3901 bool CheckAndClearDisplayListState();
3903 // CSS visibility just doesn't cut it because it doesn't inherit through
3904 // documents. Also if this frame is in a hidden card of a deck then it isn't
3905 // visible either and that isn't expressed using CSS visibility. Also if it
3906 // is in a hidden view (there are a few cases left and they are hopefully
3907 // going away soon).
3908 // If the VISIBILITY_CROSS_CHROME_CONTENT_BOUNDARY flag is passed then we
3909 // ignore the chrome/content boundary, otherwise we stop looking when we
3910 // reach it.
3911 enum { VISIBILITY_CROSS_CHROME_CONTENT_BOUNDARY = 0x01 };
3912 bool IsVisibleConsideringAncestors(uint32_t aFlags = 0) const;
3914 struct FrameWithDistance {
3915 nsIFrame* mFrame;
3916 nscoord mXDistance;
3917 nscoord mYDistance;
3921 * Finds a frame that is closer to a specified point than a current
3922 * distance. Distance is measured as for text selection -- a closer x
3923 * distance beats a closer y distance.
3925 * Normally, this function will only check the distance between this
3926 * frame's rectangle and the specified point. SVGTextFrame overrides
3927 * this so that it can manage all of its descendant frames and take
3928 * into account any SVG text layout.
3930 * If aPoint is closer to this frame's rectangle than aCurrentBestFrame
3931 * indicates, then aCurrentBestFrame is updated with the distance between
3932 * aPoint and this frame's rectangle, and with a pointer to this frame.
3933 * If aPoint is not closer, then aCurrentBestFrame is left unchanged.
3935 * @param aPoint The point to check for its distance to this frame.
3936 * @param aCurrentBestFrame Pointer to a struct that will be updated with
3937 * a pointer to this frame and its distance to aPoint, if this frame
3938 * is indeed closer than the current distance in aCurrentBestFrame.
3940 virtual void FindCloserFrameForSelection(
3941 const nsPoint& aPoint, FrameWithDistance* aCurrentBestFrame);
3944 * Is this a flex item? (i.e. a non-abs-pos child of a flex container)
3946 inline bool IsFlexItem() const;
3948 * Is this a grid item? (i.e. a non-abs-pos child of a grid container)
3950 inline bool IsGridItem() const;
3952 * Is this a flex or grid item? (i.e. a non-abs-pos child of a flex/grid
3953 * container)
3955 inline bool IsFlexOrGridItem() const;
3956 inline bool IsFlexOrGridContainer() const;
3959 * @return true if this frame is used as a table caption.
3961 inline bool IsTableCaption() const;
3963 inline bool IsBlockOutside() const;
3964 inline bool IsInlineOutside() const;
3965 inline mozilla::StyleDisplay GetDisplay() const;
3966 inline bool IsFloating() const;
3967 inline bool IsAbsPosContainingBlock() const;
3968 inline bool IsFixedPosContainingBlock() const;
3969 inline bool IsRelativelyPositioned() const;
3970 inline bool IsStickyPositioned() const;
3971 inline bool IsAbsolutelyPositioned(
3972 const nsStyleDisplay* aStyleDisplay = nullptr) const;
3974 // Does this frame have "column-span: all" style.
3976 // Note this only checks computed style, but not testing whether the
3977 // containing block formatting context was established by a multicol. Callers
3978 // need to use IsColumnSpanInMulticolSubtree() to check whether multi-column
3979 // effects apply or not.
3980 inline bool IsColumnSpan() const;
3982 // Like IsColumnSpan(), but this also checks whether the frame has a
3983 // multi-column ancestor or not.
3984 inline bool IsColumnSpanInMulticolSubtree() const;
3987 * Returns the vertical-align value to be used for layout, if it is one
3988 * of the enumerated values. If this is an SVG text frame, it returns a value
3989 * that corresponds to the value of dominant-baseline. If the
3990 * vertical-align property has length or percentage value, this returns
3991 * Nothing().
3993 Maybe<mozilla::StyleVerticalAlignKeyword> VerticalAlignEnum() const;
3995 void CreateOwnLayerIfNeeded(nsDisplayListBuilder* aBuilder,
3996 nsDisplayList* aList,
3997 bool* aCreatedContainerItem = nullptr);
4000 * Adds the NS_FRAME_IN_POPUP state bit to aFrame, and
4001 * all descendant frames (including cross-doc ones).
4003 static void AddInPopupStateBitToDescendants(nsIFrame* aFrame);
4005 * Removes the NS_FRAME_IN_POPUP state bit from aFrame and
4006 * all descendant frames (including cross-doc ones), unless
4007 * the frame is a popup itself.
4009 static void RemoveInPopupStateBitFromDescendants(nsIFrame* aFrame);
4012 * Sorts the given nsFrameList, so that for every two adjacent frames in the
4013 * list, the former is less than or equal to the latter, according to the
4014 * templated IsLessThanOrEqual method.
4016 * Note: this method uses a stable merge-sort algorithm.
4018 template <bool IsLessThanOrEqual(nsIFrame*, nsIFrame*)>
4019 static void SortFrameList(nsFrameList& aFrameList);
4022 * Returns true if the given frame list is already sorted, according to the
4023 * templated IsLessThanOrEqual function.
4025 template <bool IsLessThanOrEqual(nsIFrame*, nsIFrame*)>
4026 static bool IsFrameListSorted(nsFrameList& aFrameList);
4029 * Return true if aFrame is in an {ib} split and is NOT one of the
4030 * continuations of the first inline in it.
4032 bool FrameIsNonFirstInIBSplit() const {
4033 return (GetStateBits() & NS_FRAME_PART_OF_IBSPLIT) &&
4034 FirstContinuation()->GetProperty(nsIFrame::IBSplitPrevSibling());
4038 * Return true if aFrame is in an {ib} split and is NOT one of the
4039 * continuations of the last inline in it.
4041 bool FrameIsNonLastInIBSplit() const {
4042 return (GetStateBits() & NS_FRAME_PART_OF_IBSPLIT) &&
4043 FirstContinuation()->GetProperty(nsIFrame::IBSplitSibling());
4047 * Return whether this is a frame whose width is used when computing
4048 * the font size inflation of its descendants.
4050 bool IsContainerForFontSizeInflation() const {
4051 return GetStateBits() & NS_FRAME_FONT_INFLATION_CONTAINER;
4055 * Return whether this frame keeps track of overflow areas. (Frames for
4056 * non-display SVG elements -- e.g. <clipPath> -- do not maintain overflow
4057 * areas, because they're never painted.)
4059 bool FrameMaintainsOverflow() const {
4060 return !HasAllStateBits(NS_FRAME_SVG_LAYOUT | NS_FRAME_IS_NONDISPLAY) &&
4061 !(IsSVGOuterSVGFrame() && HasAnyStateBits(NS_FRAME_IS_NONDISPLAY));
4065 * @param aStyleDisplay: If the caller has this->StyleDisplay(), providing
4066 * it here will improve performance.
4068 bool BackfaceIsHidden(const nsStyleDisplay* aStyleDisplay) const {
4069 MOZ_ASSERT(aStyleDisplay == StyleDisplay());
4070 return aStyleDisplay->BackfaceIsHidden();
4072 bool BackfaceIsHidden() const { return StyleDisplay()->BackfaceIsHidden(); }
4075 * Returns true if the frame is scrolled out of view.
4077 bool IsScrolledOutOfView() const;
4080 * Computes a 2D matrix from the -moz-window-transform and
4081 * -moz-window-transform-origin properties on aFrame.
4082 * Values that don't result in a 2D matrix will be ignored and an identity
4083 * matrix will be returned instead.
4085 Matrix ComputeWidgetTransform();
4088 * Applies the values from the -moz-window-* properties to the widget.
4090 virtual void UpdateWidgetProperties();
4093 * @return true iff this frame has one or more associated image requests.
4094 * @see mozilla::css::ImageLoader.
4096 bool HasImageRequest() const { return mHasImageRequest; }
4099 * Update this frame's image request state.
4101 void SetHasImageRequest(bool aHasRequest) { mHasImageRequest = aHasRequest; }
4104 * Whether this frame has a first-letter child. If it does, the frame is
4105 * actually an nsContainerFrame and the first-letter frame can be gotten by
4106 * walking up to the nearest ancestor blockframe and getting its first
4107 * continuation's nsContainerFrame::FirstLetterProperty() property. This will
4108 * only return true for the first continuation of the first-letter's parent.
4110 bool HasFirstLetterChild() const { return mHasFirstLetterChild; }
4113 * Whether this frame's parent is a wrapper anonymous box. See documentation
4114 * for mParentIsWrapperAnonBox.
4116 bool ParentIsWrapperAnonBox() const { return mParentIsWrapperAnonBox; }
4117 void SetParentIsWrapperAnonBox() { mParentIsWrapperAnonBox = true; }
4120 * Whether this is a wrapper anonymous box needing a restyle.
4122 bool IsWrapperAnonBoxNeedingRestyle() const {
4123 return mIsWrapperBoxNeedingRestyle;
4125 void SetIsWrapperAnonBoxNeedingRestyle(bool aNeedsRestyle) {
4126 mIsWrapperBoxNeedingRestyle = aNeedsRestyle;
4129 bool MayHaveTransformAnimation() const { return mMayHaveTransformAnimation; }
4130 void SetMayHaveTransformAnimation() { mMayHaveTransformAnimation = true; }
4131 bool MayHaveOpacityAnimation() const { return mMayHaveOpacityAnimation; }
4132 void SetMayHaveOpacityAnimation() { mMayHaveOpacityAnimation = true; }
4134 // Returns true if this frame is visible or may have visible descendants.
4135 // Note: This function is accurate only on primary frames, because
4136 // mAllDescendantsAreInvisible is not updated on continuations.
4137 bool IsVisibleOrMayHaveVisibleDescendants() const {
4138 return !mAllDescendantsAreInvisible || StyleVisibility()->IsVisible();
4140 // Update mAllDescendantsAreInvisible flag for this frame and ancestors.
4141 void UpdateVisibleDescendantsState();
4144 * If this returns true, the frame it's called on should get the
4145 * NS_FRAME_HAS_DIRTY_CHILDREN bit set on it by the caller; either directly
4146 * if it's already in reflow, or via calling FrameNeedsReflow() to schedule a
4147 * reflow.
4149 virtual bool RenumberFrameAndDescendants(int32_t* aOrdinal, int32_t aDepth,
4150 int32_t aIncrement,
4151 bool aForCounting) {
4152 return false;
4156 * Helper function - computes the content-box inline size for aSize.
4158 nscoord ComputeISizeValue(gfxContext* aRenderingContext,
4159 nscoord aContainingBlockISize,
4160 nscoord aContentEdgeToBoxSizing,
4161 nscoord aBoxSizingToMarginEdge,
4162 StyleExtremumLength aSize, ComputeSizeFlags aFlags);
4164 nscoord ComputeISizeValue(gfxContext* aRenderingContext,
4165 nscoord aContainingBlockISize,
4166 nscoord aContentEdgeToBoxSizing,
4167 nscoord aBoxSizingToMarginEdge,
4168 const LengthPercentage& aSize,
4169 ComputeSizeFlags aFlags);
4171 template <typename SizeOrMaxSize>
4172 nscoord ComputeISizeValue(gfxContext* aRenderingContext,
4173 nscoord aContainingBlockISize,
4174 nscoord aContentEdgeToBoxSizing,
4175 nscoord aBoxSizingToMarginEdge,
4176 const SizeOrMaxSize& aSize,
4177 ComputeSizeFlags aFlags = eDefault) {
4178 MOZ_ASSERT(aSize.IsExtremumLength() || aSize.IsLengthPercentage(),
4179 "This doesn't handle auto / none");
4180 if (aSize.IsLengthPercentage()) {
4181 return ComputeISizeValue(aRenderingContext, aContainingBlockISize,
4182 aContentEdgeToBoxSizing, aBoxSizingToMarginEdge,
4183 aSize.AsLengthPercentage(), aFlags);
4185 return ComputeISizeValue(aRenderingContext, aContainingBlockISize,
4186 aContentEdgeToBoxSizing, aBoxSizingToMarginEdge,
4187 aSize.AsExtremumLength(), aFlags);
4190 DisplayItemDataArray& DisplayItemData() { return mDisplayItemData; }
4191 const DisplayItemDataArray& DisplayItemData() const {
4192 return mDisplayItemData;
4195 void AddDisplayItem(nsDisplayItemBase* aItem);
4196 bool RemoveDisplayItem(nsDisplayItemBase* aItem);
4197 void RemoveDisplayItemDataForDeletion();
4198 bool HasDisplayItems();
4199 bool HasDisplayItem(nsDisplayItemBase* aItem);
4200 bool HasDisplayItem(uint32_t aKey);
4201 void DiscardOldItems();
4203 bool ForceDescendIntoIfVisible() const { return mForceDescendIntoIfVisible; }
4204 void SetForceDescendIntoIfVisible(bool aForce) {
4205 mForceDescendIntoIfVisible = aForce;
4208 bool BuiltDisplayList() { return mBuiltDisplayList; }
4209 void SetBuiltDisplayList(bool aBuilt) { mBuiltDisplayList = aBuilt; }
4211 bool IsFrameModified() { return mFrameIsModified; }
4212 void SetFrameIsModified(bool aFrameIsModified) {
4213 mFrameIsModified = aFrameIsModified;
4216 bool HasOverrideDirtyRegion() { return mHasOverrideDirtyRegion; }
4217 void SetHasOverrideDirtyRegion(bool aHasDirtyRegion) {
4218 mHasOverrideDirtyRegion = aHasDirtyRegion;
4221 bool MayHaveWillChangeBudget() { return mMayHaveWillChangeBudget; }
4222 void SetMayHaveWillChangeBudget(bool aHasBudget) {
4223 mMayHaveWillChangeBudget = aHasBudget;
4226 bool HasBSizeChange() const { return mHasBSizeChange; }
4227 void SetHasBSizeChange(bool aHasBSizeChange) {
4228 mHasBSizeChange = aHasBSizeChange;
4231 bool HasColumnSpanSiblings() const { return mHasColumnSpanSiblings; }
4232 void SetHasColumnSpanSiblings(bool aHasColumnSpanSiblings) {
4233 mHasColumnSpanSiblings = aHasColumnSpanSiblings;
4236 bool DescendantMayDependOnItsStaticPosition() const {
4237 return mDescendantMayDependOnItsStaticPosition;
4239 void SetDescendantMayDependOnItsStaticPosition(bool aValue) {
4240 mDescendantMayDependOnItsStaticPosition = aValue;
4244 * Returns the hit test area of the frame.
4246 nsRect GetCompositorHitTestArea(nsDisplayListBuilder* aBuilder);
4249 * Returns the set of flags indicating the properties of the frame that the
4250 * compositor might care about for hit-testing purposes. Note that this
4251 * function must be called during Gecko display list construction time (i.e
4252 * while the frame tree is being traversed) because that is when the display
4253 * list builder has the necessary state set up correctly.
4255 mozilla::gfx::CompositorHitTestInfo GetCompositorHitTestInfo(
4256 nsDisplayListBuilder* aBuilder);
4258 protected:
4259 static void DestroyAnonymousContent(nsPresContext* aPresContext,
4260 already_AddRefed<nsIContent>&& aContent);
4263 * Reparent this frame's view if it has one.
4265 void ReparentFrameViewTo(nsViewManager* aViewManager, nsView* aNewParentView,
4266 nsView* aOldParentView);
4269 * To be overridden by frame classes that have a varying IsLeaf() state and
4270 * is indicating that with DynamicLeaf in FrameIdList.h.
4271 * @see IsLeaf()
4273 virtual bool IsLeafDynamic() const { return false; }
4275 // Members
4276 nsRect mRect;
4277 nsCOMPtr<nsIContent> mContent;
4278 RefPtr<ComputedStyle> mComputedStyle;
4280 private:
4281 nsPresContext* const mPresContext;
4282 nsContainerFrame* mParent;
4283 nsIFrame* mNextSibling; // doubly-linked list of frames
4284 nsIFrame* mPrevSibling; // Do not touch outside SetNextSibling!
4286 DisplayItemDataArray mDisplayItemData;
4288 void MarkAbsoluteFramesForDisplayList(nsDisplayListBuilder* aBuilder);
4290 // Stores weak references to all the PresShells that were painted during
4291 // the last paint event so that we can increment their paint count during
4292 // empty transactions
4293 NS_DECLARE_FRAME_PROPERTY_DELETABLE(PaintedPresShellsProperty,
4294 nsTArray<nsWeakPtr>)
4296 nsTArray<nsWeakPtr>* PaintedPresShellList() {
4297 bool found;
4298 nsTArray<nsWeakPtr>* list =
4299 GetProperty(PaintedPresShellsProperty(), &found);
4301 if (!found) {
4302 list = new nsTArray<nsWeakPtr>();
4303 AddProperty(PaintedPresShellsProperty(), list);
4304 } else {
4305 MOZ_ASSERT(list, "this property should only store non-null values");
4308 return list;
4311 protected:
4313 * Copies aRootElemWM to mWritingMode on 'this' and all its ancestors.
4315 inline void PropagateRootElementWritingMode(mozilla::WritingMode aRootElemWM);
4317 void MarkInReflow() {
4318 #ifdef DEBUG_dbaron_off
4319 // bug 81268
4320 NS_ASSERTION(!(mState & NS_FRAME_IN_REFLOW), "frame is already in reflow");
4321 #endif
4322 AddStateBits(NS_FRAME_IN_REFLOW);
4325 nsFrameState mState;
4328 * List of properties attached to the frame.
4330 FrameProperties mProperties;
4332 // When there is an overflow area only slightly larger than mRect,
4333 // we store a set of four 1-byte deltas from the edges of mRect
4334 // rather than allocating a whole separate rectangle property.
4335 // Note that these are unsigned values, all measured "outwards"
4336 // from the edges of mRect, so /mLeft/ and /mTop/ are reversed from
4337 // our normal coordinate system.
4338 // If mOverflow.mType == NS_FRAME_OVERFLOW_LARGE, then the
4339 // delta values are not meaningful and the overflow area is stored
4340 // as a separate rect property.
4341 struct VisualDeltas {
4342 uint8_t mLeft;
4343 uint8_t mTop;
4344 uint8_t mRight;
4345 uint8_t mBottom;
4346 bool operator==(const VisualDeltas& aOther) const {
4347 return mLeft == aOther.mLeft && mTop == aOther.mTop &&
4348 mRight == aOther.mRight && mBottom == aOther.mBottom;
4350 bool operator!=(const VisualDeltas& aOther) const {
4351 return !(*this == aOther);
4354 union {
4355 uint32_t mType;
4356 VisualDeltas mVisualDeltas;
4357 } mOverflow;
4359 /** @see GetWritingMode() */
4360 mozilla::WritingMode mWritingMode;
4362 /** The ClassID of the concrete class of this instance. */
4363 ClassID mClass; // 1 byte
4365 bool mMayHaveRoundedCorners : 1;
4368 * True iff this frame has one or more associated image requests.
4369 * @see mozilla::css::ImageLoader.
4371 bool mHasImageRequest : 1;
4374 * True if this frame has a continuation that has a first-letter frame, or its
4375 * placeholder, as a child. In that case this frame has a blockframe ancestor
4376 * that has the first-letter frame hanging off it in the
4377 * nsContainerFrame::FirstLetterProperty() property.
4379 bool mHasFirstLetterChild : 1;
4382 * True if this frame's parent is a wrapper anonymous box (e.g. a table
4383 * anonymous box as specified at
4384 * <https://www.w3.org/TR/CSS21/tables.html#anonymous-boxes>).
4386 * We could compute this information directly when we need it, but it wouldn't
4387 * be all that cheap, and since this information is immutable for the lifetime
4388 * of the frame we might as well cache it.
4390 * Note that our parent may itself have mParentIsWrapperAnonBox set to true.
4392 bool mParentIsWrapperAnonBox : 1;
4395 * True if this is a wrapper anonymous box needing a restyle. This is used to
4396 * track, during stylo post-traversal, whether we've already recomputed the
4397 * style of this anonymous box, if we end up seeing it twice.
4399 bool mIsWrapperBoxNeedingRestyle : 1;
4402 * This bit is used in nsTextFrame::CharacterDataChanged() as an optimization
4403 * to skip redundant reflow-requests when the character data changes multiple
4404 * times between reflows. If this flag is set, then it implies that the
4405 * NS_FRAME_IS_DIRTY state bit is also set (and that intrinsic sizes have
4406 * been marked as dirty on our ancestor chain).
4408 * XXXdholbert This bit is *only* used on nsTextFrame, but it lives here on
4409 * nsIFrame simply because this is where we've got unused state bits
4410 * available in a gap. If bits become more scarce, we should perhaps consider
4411 * expanding the range of frame-specific state bits in nsFrameStateBits.h and
4412 * moving this to be one of those (e.g. by swapping one of the adjacent
4413 * general-purpose bits to take the place of this bool:1 here, so we can grow
4414 * that range of frame-specific bits by 1).
4416 bool mReflowRequestedForCharDataChange : 1;
4419 * This bit is used during BuildDisplayList to mark frames that need to
4420 * have display items rebuilt. We will descend into them if they are
4421 * currently visible, even if they don't intersect the dirty area.
4423 bool mForceDescendIntoIfVisible : 1;
4426 * True if we have built display items for this frame since
4427 * the last call to CheckAndClearDisplayListState, false
4428 * otherwise. Used for the reftest harness to verify minimal
4429 * display list building.
4431 bool mBuiltDisplayList : 1;
4433 bool mFrameIsModified : 1;
4435 bool mHasOverrideDirtyRegion : 1;
4438 * True if frame has will-change, and currently has display
4439 * items consuming some of the will-change budget.
4441 bool mMayHaveWillChangeBudget : 1;
4443 private:
4445 * True if this is the primary frame for mContent.
4447 bool mIsPrimaryFrame : 1;
4449 bool mMayHaveTransformAnimation : 1;
4450 bool mMayHaveOpacityAnimation : 1;
4453 * True if we are certain that all descendants are not visible.
4455 * This flag is conservative in that it might sometimes be false even if, in
4456 * fact, all descendants are invisible.
4457 * For example; an element is visibility:visible and has a visibility:hidden
4458 * child. This flag is stil false in such case.
4460 bool mAllDescendantsAreInvisible : 1;
4462 bool mHasBSizeChange : 1;
4465 * True if we are or contain the scroll anchor for a scrollable frame.
4467 bool mInScrollAnchorChain : 1;
4470 * Suppose a frame was split into multiple parts to separate parts containing
4471 * column-spans from parts not containing column-spans. This bit is set on all
4472 * continuations *not* containing column-spans except for the those after the
4473 * last column-span/non-column-span boundary (i.e., the bit really means it
4474 * has a *later* sibling across a split). Note that the last part is always
4475 * created to containing no columns-spans even if it has no children. See
4476 * nsCSSFrameConstructor::CreateColumnSpanSiblings() for the implementation.
4478 * If the frame having this bit set is removed, we need to reframe the
4479 * multi-column container.
4481 bool mHasColumnSpanSiblings : 1;
4484 * True if we may have any descendant whose positioning may depend on its
4485 * static position (and thus which we need to recompute the position for if we
4486 * move).
4488 bool mDescendantMayDependOnItsStaticPosition : 1;
4490 protected:
4491 // Helpers
4493 * Can we stop inside this frame when we're skipping non-rendered whitespace?
4495 * @param aForward [in] Are we moving forward (or backward) in content order.
4497 * @param aOffset [in/out] At what offset into the frame to start looking.
4498 * at offset was reached (whether or not we found a place to stop).
4500 * @return
4501 * * STOP: An appropriate offset was found within this frame,
4502 * and is given by aOffset.
4503 * * CONTINUE: Not found within this frame, need to try the next frame.
4504 * See enum FrameSearchResult for more details.
4506 virtual FrameSearchResult PeekOffsetNoAmount(bool aForward,
4507 int32_t* aOffset) = 0;
4510 * Search the frame for the next character
4512 * @param aForward [in] Are we moving forward (or backward) in content order.
4514 * @param aOffset [in/out] At what offset into the frame to start looking.
4515 * on output - what offset was reached (whether or not we found a place to
4516 * stop).
4518 * @param aOptions [in] Options, see the comment in PeekOffsetCharacterOptions
4519 * for the detail.
4521 * @return
4522 * * STOP: An appropriate offset was found within this frame, and is given
4523 * by aOffset.
4524 * * CONTINUE: Not found within this frame, need to try the next frame. See
4525 * enum FrameSearchResult for more details.
4527 virtual FrameSearchResult PeekOffsetCharacter(
4528 bool aForward, int32_t* aOffset,
4529 PeekOffsetCharacterOptions aOptions = PeekOffsetCharacterOptions()) = 0;
4530 static_assert(sizeof(PeekOffsetCharacterOptions) <= sizeof(intptr_t),
4531 "aOptions should be changed to const reference");
4534 * Search the frame for the next word boundary
4535 * @param aForward [in] Are we moving forward (or backward) in content order.
4536 * @param aWordSelectEatSpace [in] true: look for non-whitespace following
4537 * whitespace (in the direction of movement).
4538 * false: look for whitespace following non-whitespace (in the
4539 * direction of movement).
4540 * @param aIsKeyboardSelect [in] Was the action initiated by a keyboard
4541 * operation? If true, punctuation immediately following a word is considered
4542 * part of that word. Otherwise, a sequence of punctuation is always
4543 * considered as a word on its own.
4544 * @param aOffset [in/out] At what offset into the frame to start looking.
4545 * on output - what offset was reached (whether or not we found a
4546 * place to stop).
4547 * @param aState [in/out] the state that is carried from frame to frame
4548 * @return true: An appropriate offset was found within this frame,
4549 * and is given by aOffset.
4550 * false: Not found within this frame, need to try the next frame.
4552 struct PeekWordState {
4553 // true when we're still at the start of the search, i.e., we can't return
4554 // this point as a valid offset!
4555 bool mAtStart;
4556 // true when we've encountered at least one character of the pre-boundary
4557 // type (whitespace if aWordSelectEatSpace is true, non-whitespace
4558 // otherwise)
4559 bool mSawBeforeType;
4560 // true when the last character encountered was punctuation
4561 bool mLastCharWasPunctuation;
4562 // true when the last character encountered was whitespace
4563 bool mLastCharWasWhitespace;
4564 // true when we've seen non-punctuation since the last whitespace
4565 bool mSeenNonPunctuationSinceWhitespace;
4566 // text that's *before* the current frame when aForward is true, *after*
4567 // the current frame when aForward is false. Only includes the text
4568 // on the current line.
4569 nsAutoString mContext;
4571 PeekWordState()
4572 : mAtStart(true),
4573 mSawBeforeType(false),
4574 mLastCharWasPunctuation(false),
4575 mLastCharWasWhitespace(false),
4576 mSeenNonPunctuationSinceWhitespace(false) {}
4577 void SetSawBeforeType() { mSawBeforeType = true; }
4578 void Update(bool aAfterPunctuation, bool aAfterWhitespace) {
4579 mLastCharWasPunctuation = aAfterPunctuation;
4580 mLastCharWasWhitespace = aAfterWhitespace;
4581 if (aAfterWhitespace) {
4582 mSeenNonPunctuationSinceWhitespace = false;
4583 } else if (!aAfterPunctuation) {
4584 mSeenNonPunctuationSinceWhitespace = true;
4586 mAtStart = false;
4589 virtual FrameSearchResult PeekOffsetWord(
4590 bool aForward, bool aWordSelectEatSpace, bool aIsKeyboardSelect,
4591 int32_t* aOffset, PeekWordState* aState, bool aTrimSpaces) = 0;
4594 * Search for the first paragraph boundary before or after the given position
4595 * @param aPos See description in nsFrameSelection.h. The following fields
4596 * are used by this method:
4597 * Input: mDirection
4598 * Output: mResultContent, mContentOffset
4600 nsresult PeekOffsetParagraph(nsPeekOffsetStruct* aPos);
4602 private:
4603 // Get a pointer to the overflow areas property attached to the frame.
4604 nsOverflowAreas* GetOverflowAreasProperty() const {
4605 MOZ_ASSERT(mOverflow.mType == NS_FRAME_OVERFLOW_LARGE);
4606 nsOverflowAreas* overflow = GetProperty(OverflowAreasProperty());
4607 MOZ_ASSERT(overflow);
4608 return overflow;
4611 nsRect GetVisualOverflowFromDeltas() const {
4612 MOZ_ASSERT(mOverflow.mType != NS_FRAME_OVERFLOW_LARGE,
4613 "should not be called when overflow is in a property");
4614 // Calculate the rect using deltas from the frame's border rect.
4615 // Note that the mOverflow.mDeltas fields are unsigned, but we will often
4616 // need to return negative values for the left and top, so take care
4617 // to cast away the unsigned-ness.
4618 return nsRect(-(int32_t)mOverflow.mVisualDeltas.mLeft,
4619 -(int32_t)mOverflow.mVisualDeltas.mTop,
4620 mRect.Width() + mOverflow.mVisualDeltas.mRight +
4621 mOverflow.mVisualDeltas.mLeft,
4622 mRect.Height() + mOverflow.mVisualDeltas.mBottom +
4623 mOverflow.mVisualDeltas.mTop);
4626 * Returns true if any overflow changed.
4628 bool SetOverflowAreas(const nsOverflowAreas& aOverflowAreas);
4630 // Helper-functions for SortFrameList():
4631 template <bool IsLessThanOrEqual(nsIFrame*, nsIFrame*)>
4632 static nsIFrame* SortedMerge(nsIFrame* aLeft, nsIFrame* aRight);
4634 template <bool IsLessThanOrEqual(nsIFrame*, nsIFrame*)>
4635 static nsIFrame* MergeSort(nsIFrame* aSource);
4637 bool HasOpacityInternal(float aThreshold, const nsStyleDisplay* aStyleDisplay,
4638 const nsStyleEffects* aStyleEffects,
4639 mozilla::EffectSet* aEffectSet = nullptr) const;
4641 // Maps mClass to LayoutFrameType.
4642 static const mozilla::LayoutFrameType sLayoutFrameTypes[
4643 #define FRAME_ID(...) 1 +
4644 #define ABSTRACT_FRAME_ID(...)
4645 #include "mozilla/FrameIdList.h"
4646 #undef FRAME_ID
4647 #undef ABSTRACT_FRAME_ID
4650 enum FrameClassBits {
4651 eFrameClassBitsNone = 0x0,
4652 eFrameClassBitsLeaf = 0x1,
4653 eFrameClassBitsDynamicLeaf = 0x2,
4655 // Maps mClass to IsLeaf() flags.
4656 static const FrameClassBits sFrameClassBits[
4657 #define FRAME_ID(...) 1 +
4658 #define ABSTRACT_FRAME_ID(...)
4659 #include "mozilla/FrameIdList.h"
4660 #undef FRAME_ID
4661 #undef ABSTRACT_FRAME_ID
4664 #ifdef DEBUG_FRAME_DUMP
4665 public:
4666 static void IndentBy(FILE* out, int32_t aIndent) {
4667 while (--aIndent >= 0) fputs(" ", out);
4669 void ListTag(FILE* out) const { fputs(ListTag().get(), out); }
4670 nsAutoCString ListTag() const;
4671 void ListGeneric(nsACString& aTo, const char* aPrefix = "",
4672 uint32_t aFlags = 0) const;
4673 enum {TRAVERSE_SUBDOCUMENT_FRAMES = 0x01};
4674 virtual void List(FILE* out = stderr, const char* aPrefix = "",
4675 uint32_t aFlags = 0) const;
4676 virtual void ListWithMatchedRules(FILE* out = stderr,
4677 const char* aPrefix = "") const;
4678 void ListMatchedRules(FILE* out, const char* aPrefix) const;
4680 * lists the frames beginning from the root frame
4681 * - calls root frame's List(...)
4683 static void RootFrameList(nsPresContext* aPresContext, FILE* out = stderr,
4684 const char* aPrefix = "");
4685 virtual void DumpFrameTree() const;
4686 void DumpFrameTreeLimited() const;
4688 virtual nsresult GetFrameName(nsAString& aResult) const = 0;
4689 #endif
4692 MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(nsIFrame::ReflowChildFlags)
4694 //----------------------------------------------------------------------
4697 * AutoWeakFrame can be used to keep a reference to a nsIFrame in a safe way.
4698 * Whenever an nsIFrame object is deleted, the AutoWeakFrames pointing
4699 * to it will be cleared. AutoWeakFrame is for variables on the stack or
4700 * in static storage only, there is also a WeakFrame below for heap uses.
4702 * Create AutoWeakFrame object when it is sure that nsIFrame object
4703 * is alive and after some operations which may destroy the nsIFrame
4704 * (for example any DOM modifications) use IsAlive() or GetFrame() methods to
4705 * check whether it is safe to continue to use the nsIFrame object.
4707 * @note The usage of this class should be kept to a minimum.
4709 class WeakFrame;
4710 class MOZ_NONHEAP_CLASS AutoWeakFrame {
4711 public:
4712 explicit AutoWeakFrame() : mPrev(nullptr), mFrame(nullptr) {}
4714 AutoWeakFrame(const AutoWeakFrame& aOther) : mPrev(nullptr), mFrame(nullptr) {
4715 Init(aOther.GetFrame());
4718 MOZ_IMPLICIT AutoWeakFrame(const WeakFrame& aOther);
4720 MOZ_IMPLICIT AutoWeakFrame(nsIFrame* aFrame)
4721 : mPrev(nullptr), mFrame(nullptr) {
4722 Init(aFrame);
4725 AutoWeakFrame& operator=(AutoWeakFrame& aOther) {
4726 Init(aOther.GetFrame());
4727 return *this;
4730 AutoWeakFrame& operator=(nsIFrame* aFrame) {
4731 Init(aFrame);
4732 return *this;
4735 nsIFrame* operator->() { return mFrame; }
4737 operator nsIFrame*() { return mFrame; }
4739 void Clear(mozilla::PresShell* aPresShell) {
4740 if (aPresShell) {
4741 aPresShell->RemoveAutoWeakFrame(this);
4743 mFrame = nullptr;
4744 mPrev = nullptr;
4747 bool IsAlive() { return !!mFrame; }
4749 nsIFrame* GetFrame() const { return mFrame; }
4751 AutoWeakFrame* GetPreviousWeakFrame() { return mPrev; }
4753 void SetPreviousWeakFrame(AutoWeakFrame* aPrev) { mPrev = aPrev; }
4755 ~AutoWeakFrame() {
4756 Clear(mFrame ? mFrame->PresContext()->GetPresShell() : nullptr);
4759 private:
4760 // Not available for the heap!
4761 void* operator new(size_t) = delete;
4762 void* operator new[](size_t) = delete;
4763 void operator delete(void*) = delete;
4764 void operator delete[](void*) = delete;
4766 void Init(nsIFrame* aFrame);
4768 AutoWeakFrame* mPrev;
4769 nsIFrame* mFrame;
4772 // Use nsIFrame's fast-path to avoid QueryFrame:
4773 inline do_QueryFrameHelper<nsIFrame> do_QueryFrame(AutoWeakFrame& s) {
4774 return do_QueryFrameHelper<nsIFrame>(s.GetFrame());
4778 * @see AutoWeakFrame
4780 class MOZ_HEAP_CLASS WeakFrame {
4781 public:
4782 WeakFrame() : mFrame(nullptr) {}
4784 WeakFrame(const WeakFrame& aOther) : mFrame(nullptr) {
4785 Init(aOther.GetFrame());
4788 MOZ_IMPLICIT WeakFrame(const AutoWeakFrame& aOther) : mFrame(nullptr) {
4789 Init(aOther.GetFrame());
4792 MOZ_IMPLICIT WeakFrame(nsIFrame* aFrame) : mFrame(nullptr) { Init(aFrame); }
4794 ~WeakFrame() {
4795 Clear(mFrame ? mFrame->PresContext()->GetPresShell() : nullptr);
4798 WeakFrame& operator=(WeakFrame& aOther) {
4799 Init(aOther.GetFrame());
4800 return *this;
4803 WeakFrame& operator=(nsIFrame* aFrame) {
4804 Init(aFrame);
4805 return *this;
4808 nsIFrame* operator->() { return mFrame; }
4809 operator nsIFrame*() { return mFrame; }
4811 void Clear(mozilla::PresShell* aPresShell) {
4812 if (aPresShell) {
4813 aPresShell->RemoveWeakFrame(this);
4815 mFrame = nullptr;
4818 bool IsAlive() { return !!mFrame; }
4819 nsIFrame* GetFrame() const { return mFrame; }
4821 private:
4822 void Init(nsIFrame* aFrame);
4824 nsIFrame* mFrame;
4827 // Use nsIFrame's fast-path to avoid QueryFrame:
4828 inline do_QueryFrameHelper<nsIFrame> do_QueryFrame(WeakFrame& s) {
4829 return do_QueryFrameHelper<nsIFrame>(s.GetFrame());
4832 inline bool nsFrameList::ContinueRemoveFrame(nsIFrame* aFrame) {
4833 MOZ_ASSERT(!aFrame->GetPrevSibling() || !aFrame->GetNextSibling(),
4834 "Forgot to call StartRemoveFrame?");
4835 if (aFrame == mLastChild) {
4836 MOZ_ASSERT(!aFrame->GetNextSibling(), "broken frame list");
4837 nsIFrame* prevSibling = aFrame->GetPrevSibling();
4838 if (!prevSibling) {
4839 MOZ_ASSERT(aFrame == mFirstChild, "broken frame list");
4840 mFirstChild = mLastChild = nullptr;
4841 return true;
4843 MOZ_ASSERT(prevSibling->GetNextSibling() == aFrame, "Broken frame linkage");
4844 prevSibling->SetNextSibling(nullptr);
4845 mLastChild = prevSibling;
4846 return true;
4848 if (aFrame == mFirstChild) {
4849 MOZ_ASSERT(!aFrame->GetPrevSibling(), "broken frame list");
4850 mFirstChild = aFrame->GetNextSibling();
4851 aFrame->SetNextSibling(nullptr);
4852 MOZ_ASSERT(mFirstChild, "broken frame list");
4853 return true;
4855 return false;
4858 inline bool nsFrameList::StartRemoveFrame(nsIFrame* aFrame) {
4859 if (aFrame->GetPrevSibling() && aFrame->GetNextSibling()) {
4860 UnhookFrameFromSiblings(aFrame);
4861 return true;
4863 return ContinueRemoveFrame(aFrame);
4866 inline void nsFrameList::Enumerator::Next() {
4867 NS_ASSERTION(!AtEnd(), "Should have checked AtEnd()!");
4868 mFrame = mFrame->GetNextSibling();
4871 inline nsFrameList::FrameLinkEnumerator::FrameLinkEnumerator(
4872 const nsFrameList& aList, nsIFrame* aPrevFrame)
4873 : Enumerator(aList) {
4874 mPrev = aPrevFrame;
4875 mFrame = aPrevFrame ? aPrevFrame->GetNextSibling() : aList.FirstChild();
4878 inline void nsFrameList::FrameLinkEnumerator::Next() {
4879 mPrev = mFrame;
4880 Enumerator::Next();
4883 template <typename Predicate>
4884 inline void nsFrameList::FrameLinkEnumerator::Find(Predicate&& aPredicate) {
4885 static_assert(
4886 std::is_same<typename mozilla::FunctionTypeTraits<Predicate>::ReturnType,
4887 bool>::value &&
4888 mozilla::FunctionTypeTraits<Predicate>::arity == 1 &&
4889 std::is_same<typename mozilla::FunctionTypeTraits<
4890 Predicate>::template ParameterType<0>,
4891 nsIFrame*>::value,
4892 "aPredicate should be of this function signature: bool(nsIFrame*)");
4894 for (; !AtEnd(); Next()) {
4895 if (aPredicate(mFrame)) {
4896 return;
4901 // Operators of nsFrameList::Iterator
4902 // ---------------------------------------------------
4904 inline nsFrameList::Iterator& nsFrameList::Iterator::operator++() {
4905 mCurrent = mCurrent->GetNextSibling();
4906 return *this;
4909 inline nsFrameList::Iterator& nsFrameList::Iterator::operator--() {
4910 if (!mCurrent) {
4911 mCurrent = mList.LastChild();
4912 } else {
4913 mCurrent = mCurrent->GetPrevSibling();
4915 return *this;
4918 // Helper-functions for nsIFrame::SortFrameList()
4919 // ---------------------------------------------------
4921 template <bool IsLessThanOrEqual(nsIFrame*, nsIFrame*)>
4922 /* static */ nsIFrame* nsIFrame::SortedMerge(nsIFrame* aLeft,
4923 nsIFrame* aRight) {
4924 MOZ_ASSERT(aLeft && aRight, "SortedMerge must have non-empty lists");
4926 nsIFrame* result;
4927 // Unroll first iteration to avoid null-check 'result' inside the loop.
4928 if (IsLessThanOrEqual(aLeft, aRight)) {
4929 result = aLeft;
4930 aLeft = aLeft->GetNextSibling();
4931 if (!aLeft) {
4932 result->SetNextSibling(aRight);
4933 return result;
4935 } else {
4936 result = aRight;
4937 aRight = aRight->GetNextSibling();
4938 if (!aRight) {
4939 result->SetNextSibling(aLeft);
4940 return result;
4944 nsIFrame* last = result;
4945 for (;;) {
4946 if (IsLessThanOrEqual(aLeft, aRight)) {
4947 last->SetNextSibling(aLeft);
4948 last = aLeft;
4949 aLeft = aLeft->GetNextSibling();
4950 if (!aLeft) {
4951 last->SetNextSibling(aRight);
4952 return result;
4954 } else {
4955 last->SetNextSibling(aRight);
4956 last = aRight;
4957 aRight = aRight->GetNextSibling();
4958 if (!aRight) {
4959 last->SetNextSibling(aLeft);
4960 return result;
4966 template <bool IsLessThanOrEqual(nsIFrame*, nsIFrame*)>
4967 /* static */ nsIFrame* nsIFrame::MergeSort(nsIFrame* aSource) {
4968 MOZ_ASSERT(aSource, "MergeSort null arg");
4970 nsIFrame* sorted[32] = {nullptr};
4971 nsIFrame** fill = &sorted[0];
4972 nsIFrame** left;
4973 nsIFrame* rest = aSource;
4975 do {
4976 nsIFrame* current = rest;
4977 rest = rest->GetNextSibling();
4978 current->SetNextSibling(nullptr);
4980 // Merge it with sorted[0] if present; then merge the result with sorted[1]
4981 // etc. sorted[0] is a list of length 1 (or nullptr). sorted[1] is a list of
4982 // length 2 (or nullptr). sorted[2] is a list of length 4 (or nullptr). etc.
4983 for (left = &sorted[0]; left != fill && *left; ++left) {
4984 current = SortedMerge<IsLessThanOrEqual>(*left, current);
4985 *left = nullptr;
4988 // Fill the empty slot that we couldn't merge with the last result.
4989 *left = current;
4991 if (left == fill) ++fill;
4992 } while (rest);
4994 // Collect and merge the results.
4995 nsIFrame* result = nullptr;
4996 for (left = &sorted[0]; left != fill; ++left) {
4997 if (*left) {
4998 result = result ? SortedMerge<IsLessThanOrEqual>(*left, result) : *left;
5001 return result;
5004 template <bool IsLessThanOrEqual(nsIFrame*, nsIFrame*)>
5005 /* static */ void nsIFrame::SortFrameList(nsFrameList& aFrameList) {
5006 nsIFrame* head = MergeSort<IsLessThanOrEqual>(aFrameList.FirstChild());
5007 aFrameList = nsFrameList(head, nsLayoutUtils::GetLastSibling(head));
5008 MOZ_ASSERT(IsFrameListSorted<IsLessThanOrEqual>(aFrameList),
5009 "After we sort a frame list, it should be in sorted order...");
5012 template <bool IsLessThanOrEqual(nsIFrame*, nsIFrame*)>
5013 /* static */ bool nsIFrame::IsFrameListSorted(nsFrameList& aFrameList) {
5014 if (aFrameList.IsEmpty()) {
5015 // empty lists are trivially sorted.
5016 return true;
5019 // We'll walk through the list with two iterators, one trailing behind the
5020 // other. The list is sorted IFF trailingIter <= iter, across the whole list.
5021 nsFrameList::Enumerator trailingIter(aFrameList);
5022 nsFrameList::Enumerator iter(aFrameList);
5023 iter.Next(); // Skip |iter| past first frame. (List is nonempty, so we can.)
5025 // Now, advance the iterators in parallel, comparing each adjacent pair.
5026 while (!iter.AtEnd()) {
5027 MOZ_ASSERT(!trailingIter.AtEnd(), "trailing iter shouldn't finish first");
5028 if (!IsLessThanOrEqual(trailingIter.get(), iter.get())) {
5029 return false;
5031 trailingIter.Next();
5032 iter.Next();
5035 // We made it to the end without returning early, so the list is sorted.
5036 return true;
5039 // Needs to be defined here rather than nsIFrameInlines.h, because it is used
5040 // within this header.
5041 nsPoint nsIFrame::GetNormalPosition(bool* aHasProperty) const {
5042 nsPoint* normalPosition = GetProperty(NormalPositionProperty());
5043 if (normalPosition) {
5044 if (aHasProperty) {
5045 *aHasProperty = true;
5047 return *normalPosition;
5049 if (aHasProperty) {
5050 *aHasProperty = false;
5052 return GetPosition();
5055 #endif /* nsIFrame_h___ */