Merge mozilla-central to autoland. a=merge
[gecko.git] / layout / generic / nsIFrame.h
blob90653d9927f6d7dd3d7a43a287ea179c8e5a1fac
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 "FrameProperties.h"
53 #include "LayoutConstants.h"
54 #include "mozilla/AspectRatio.h"
55 #include "mozilla/Attributes.h"
56 #include "mozilla/Baseline.h"
57 #include "mozilla/EnumSet.h"
58 #include "mozilla/EventForwards.h"
59 #include "mozilla/Maybe.h"
60 #include "mozilla/RelativeTo.h"
61 #include "mozilla/Result.h"
62 #include "mozilla/SmallPointerArray.h"
63 #include "mozilla/ToString.h"
64 #include "mozilla/WritingModes.h"
65 #include "nsDirection.h"
66 #include "nsFrameList.h"
67 #include "nsFrameState.h"
68 #include "mozilla/ReflowInput.h"
69 #include "nsIContent.h"
70 #include "nsITheme.h"
71 #include "nsQueryFrame.h"
72 #include "mozilla/ComputedStyle.h"
73 #include "nsStyleStruct.h"
74 #include "Visibility.h"
75 #include "nsChangeHint.h"
76 #include "mozilla/EnumSet.h"
77 #include "mozilla/gfx/2D.h"
78 #include "mozilla/gfx/CompositorHitTestInfo.h"
79 #include "mozilla/gfx/MatrixFwd.h"
80 #include "mozilla/intl/BidiEmbeddingLevel.h"
81 #include "nsDisplayItemTypes.h"
82 #include "nsPresContext.h"
83 #include "nsTHashSet.h"
85 #ifdef ACCESSIBILITY
86 # include "mozilla/a11y/AccTypes.h"
87 #endif
89 /**
90 * New rules of reflow:
91 * 1. you get a WillReflow() followed by a Reflow() followed by a DidReflow() in
92 * order (no separate pass over the tree)
93 * 2. it's the parent frame's responsibility to size/position the child's view
94 * (not the child frame's responsibility as it is today) during reflow (and
95 * before sending the DidReflow() notification)
96 * 3. positioning of child frames (and their views) is done on the way down the
97 * tree, and sizing of child frames (and their views) on the way back up
98 * 4. if you move a frame (outside of the reflow process, or after reflowing
99 * it), then you must make sure that its view (or its child frame's views)
100 * are re-positioned as well. It's reasonable to not position the view until
101 * after all reflowing the entire line, for example, but the frame should
102 * still be positioned and sized (and the view sized) during the reflow
103 * (i.e., before sending the DidReflow() notification)
104 * 5. the view system handles moving of widgets, i.e., it's not our problem
107 class nsAtom;
108 class nsView;
109 class nsFrameSelection;
110 class nsIWidget;
111 class nsIScrollableFrame;
112 class nsISelectionController;
113 class nsILineIterator;
114 class gfxSkipChars;
115 class gfxSkipCharsIterator;
116 class gfxContext;
117 class nsLineList_iterator;
118 class nsAbsoluteContainingBlock;
119 class nsContainerFrame;
120 class nsPlaceholderFrame;
121 class nsStyleChangeList;
122 class nsViewManager;
123 class nsWindowSizes;
125 struct CharacterDataChangeInfo;
127 namespace mozilla {
129 enum class CaretAssociationHint;
130 enum class PeekOffsetOption : uint16_t;
131 enum class PseudoStyleType : uint8_t;
132 enum class TableSelectionMode : uint32_t;
134 class nsDisplayItem;
135 class nsDisplayList;
136 class nsDisplayListBuilder;
137 class nsDisplayListSet;
139 class ServoRestyleState;
140 class EffectSet;
141 class LazyLogModule;
142 class PresShell;
143 class WidgetGUIEvent;
144 class WidgetMouseEvent;
146 struct PeekOffsetStruct;
148 namespace layers {
149 class Layer;
150 class LayerManager;
151 } // namespace layers
153 namespace layout {
154 class ScrollAnchorContainer;
155 } // namespace layout
157 } // namespace mozilla
159 //----------------------------------------------------------------------
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 public:
205 nsReflowStatus()
206 : mFloatClearType(mozilla::StyleClear::None),
207 mInlineBreak(InlineBreak::None),
208 mCompletion(Completion::FullyComplete),
209 mNextInFlowNeedsReflow(false),
210 mFirstLetterComplete(false) {}
212 // Reset all the member variables.
213 void Reset() {
214 mFloatClearType = mozilla::StyleClear::None;
215 mInlineBreak = InlineBreak::None;
216 mCompletion = Completion::FullyComplete;
217 mNextInFlowNeedsReflow = false;
218 mFirstLetterComplete = false;
221 // Return true if all member variables have their default values.
222 bool IsEmpty() const {
223 return (IsFullyComplete() && !IsInlineBreak() && !mNextInFlowNeedsReflow &&
224 !mFirstLetterComplete);
227 // There are three possible completion statuses, represented by
228 // mCompletion.
230 // Incomplete means the frame does *not* map all its content, and the
231 // parent frame should create a continuing frame.
233 // OverflowIncomplete means that the frame has an overflow that is not
234 // complete, but its own box is complete. (This happens when the content
235 // overflows a fixed-height box.) The reflower should place and size the
236 // frame and continue its reflow, but it needs to create an overflow
237 // container as a continuation for this frame. See "Overflow containers"
238 // documentation in nsContainerFrame.h for more information.
240 // FullyComplete means the frame is neither Incomplete nor
241 // OverflowIncomplete. This is the default state for a nsReflowStatus.
243 enum class Completion : uint8_t {
244 // The order of the enum values is important, which represents the
245 // precedence when merging.
246 FullyComplete,
247 OverflowIncomplete,
248 Incomplete,
251 bool IsIncomplete() const { return mCompletion == Completion::Incomplete; }
252 bool IsOverflowIncomplete() const {
253 return mCompletion == Completion::OverflowIncomplete;
255 bool IsFullyComplete() const {
256 return mCompletion == Completion::FullyComplete;
258 // Just for convenience; not a distinct state.
259 bool IsComplete() const { return !IsIncomplete(); }
261 void SetIncomplete() { mCompletion = Completion::Incomplete; }
262 void SetOverflowIncomplete() { mCompletion = Completion::OverflowIncomplete; }
264 // mNextInFlowNeedsReflow bit flag means that the next-in-flow is dirty,
265 // and also needs to be reflowed. This status only makes sense for a frame
266 // that is not complete, i.e. you wouldn't set mNextInFlowNeedsReflow when
267 // IsComplete() is true.
268 bool NextInFlowNeedsReflow() const { return mNextInFlowNeedsReflow; }
269 void SetNextInFlowNeedsReflow() { mNextInFlowNeedsReflow = true; }
271 // Merge the frame completion status bits from aStatus into this.
272 void MergeCompletionStatusFrom(const nsReflowStatus& aStatus) {
273 if (mCompletion < aStatus.mCompletion) {
274 mCompletion = aStatus.mCompletion;
277 // These asserts ensure that the mCompletion merging works as we expect.
278 // (Incomplete beats OverflowIncomplete, which beats FullyComplete.)
279 static_assert(
280 Completion::Incomplete > Completion::OverflowIncomplete &&
281 Completion::OverflowIncomplete > Completion::FullyComplete,
282 "mCompletion merging won't work without this!");
284 mNextInFlowNeedsReflow |= aStatus.mNextInFlowNeedsReflow;
287 // There are three possible inline-break statuses, represented by
288 // mInlineBreak.
290 // "None" means no break is requested.
291 // "Before" means the break should occur before the frame.
292 // "After" means the break should occur after the frame.
293 // (Here, "the frame" is the frame whose reflow results are being reported by
294 // this nsReflowStatus.)
296 enum class InlineBreak : uint8_t {
297 None,
298 Before,
299 After,
302 bool IsInlineBreak() const { return mInlineBreak != InlineBreak::None; }
303 bool IsInlineBreakBefore() const {
304 return mInlineBreak == InlineBreak::Before;
306 bool IsInlineBreakAfter() const { return mInlineBreak == InlineBreak::After; }
307 mozilla::StyleClear FloatClearType() const { return mFloatClearType; }
309 // Set the inline line-break-before status, and reset other bit flags. Note
310 // that other frame completion status isn't expected to matter after calling
311 // this method.
313 // Here's one scenario where a child frame would report this status. Suppose
314 // the child has "break-inside:avoid" in its style, and the child (and its
315 // content) won't fit in the available block-size. This child would want to
316 // report this status so that it gets pushed (in its entirety) to the next
317 // column/page where it will hopefully fit.
318 void SetInlineLineBreakBeforeAndReset() {
319 Reset();
320 mFloatClearType = mozilla::StyleClear::None;
321 mInlineBreak = InlineBreak::Before;
324 // Set the inline line-break-after status. The clear type can be changed
325 // via the optional aClearType param.
326 void SetInlineLineBreakAfter(
327 mozilla::StyleClear aClearType = mozilla::StyleClear::None) {
328 mFloatClearType = aClearType;
329 mInlineBreak = InlineBreak::After;
332 // mFirstLetterComplete bit flag means the break was induced by
333 // completion of a first-letter.
334 bool FirstLetterComplete() const { return mFirstLetterComplete; }
335 void SetFirstLetterComplete() { mFirstLetterComplete = true; }
337 private:
338 mozilla::StyleClear mFloatClearType;
339 InlineBreak mInlineBreak;
340 Completion mCompletion;
341 bool mNextInFlowNeedsReflow : 1;
342 bool mFirstLetterComplete : 1;
345 // Convert nsReflowStatus to a human-readable string.
346 std::ostream& operator<<(std::ostream& aStream, const nsReflowStatus& aStatus);
348 namespace mozilla {
350 // Loosely: https://drafts.csswg.org/css-align-3/#shared-alignment-context
351 enum class AlignmentContext {
352 Inline,
353 Table,
354 Flexbox,
355 Grid,
359 * For replaced elements only. Gets the intrinsic dimensions of this element,
360 * which can be specified on a per-axis basis.
362 struct IntrinsicSize {
363 Maybe<nscoord> width;
364 Maybe<nscoord> height;
366 IntrinsicSize() = default;
368 IntrinsicSize(nscoord aWidth, nscoord aHeight)
369 : width(Some(aWidth)), height(Some(aHeight)) {}
371 explicit IntrinsicSize(const nsSize& aSize)
372 : IntrinsicSize(aSize.Width(), aSize.Height()) {}
374 Maybe<nsSize> ToSize() const {
375 return width && height ? Some(nsSize(*width, *height)) : Nothing();
378 void Zoom(const StyleZoom& aZoom) {
379 if (width) {
380 *width = aZoom.ZoomCoord(*width);
382 if (height) {
383 *height = aZoom.ZoomCoord(*height);
387 bool operator==(const IntrinsicSize& rhs) const {
388 return width == rhs.width && height == rhs.height;
390 bool operator!=(const IntrinsicSize& rhs) const { return !(*this == rhs); }
393 // Pseudo bidi embedding level indicating nonexistence.
394 constexpr mozilla::intl::BidiEmbeddingLevel kBidiLevelNone(0xff);
396 struct FrameBidiData {
397 mozilla::intl::BidiEmbeddingLevel baseLevel;
398 mozilla::intl::BidiEmbeddingLevel embeddingLevel;
399 // The embedding level of virtual bidi formatting character before
400 // this frame if any. kBidiLevelNone is used to indicate nonexistence
401 // or unnecessity of such virtual character.
402 mozilla::intl::BidiEmbeddingLevel precedingControl;
405 } // namespace mozilla
407 /// Generic destructor for frame properties. Calls delete.
408 template <typename T>
409 static void DeleteValue(T* aPropertyValue) {
410 delete aPropertyValue;
413 /// Generic destructor for frame properties. Calls Release().
414 template <typename T>
415 static void ReleaseValue(T* aPropertyValue) {
416 aPropertyValue->Release();
419 //----------------------------------------------------------------------
422 * nsIFrame logging constants. We redefine the nspr
423 * PRLogModuleInfo.level field to be a bitfield. Each bit controls a
424 * specific type of logging. Each logging operation has associated
425 * inline methods defined below.
427 * Due to the redefinition of the level field we cannot use MOZ_LOG directly
428 * as that will cause assertions due to invalid log levels.
430 #define NS_FRAME_TRACE_CALLS 0x1
431 #define NS_FRAME_TRACE_PUSH_PULL 0x2
432 #define NS_FRAME_TRACE_CHILD_REFLOW 0x4
433 #define NS_FRAME_TRACE_NEW_FRAMES 0x8
435 #define NS_FRAME_LOG_TEST(_lm, _bit) \
436 (int(((mozilla::LogModule*)(_lm))->Level()) & (_bit))
438 #ifdef DEBUG
439 # define NS_FRAME_LOG(_bit, _args) \
440 PR_BEGIN_MACRO \
441 if (NS_FRAME_LOG_TEST(nsIFrame::sFrameLogModule, _bit)) { \
442 printf_stderr _args; \
444 PR_END_MACRO
445 #else
446 # define NS_FRAME_LOG(_bit, _args)
447 #endif
449 // XXX Need to rework this so that logging is free when it's off
450 #ifdef DEBUG
451 # define NS_FRAME_TRACE_IN(_method) Trace(_method, true)
453 # define NS_FRAME_TRACE_OUT(_method) Trace(_method, false)
455 # define NS_FRAME_TRACE(_bit, _args) \
456 PR_BEGIN_MACRO \
457 if (NS_FRAME_LOG_TEST(nsIFrame::sFrameLogModule, _bit)) { \
458 TraceMsg _args; \
460 PR_END_MACRO
462 # define NS_FRAME_TRACE_REFLOW_IN(_method) Trace(_method, true)
464 # define NS_FRAME_TRACE_REFLOW_OUT(_method, _status) \
465 Trace(_method, false, _status)
467 #else
468 # define NS_FRAME_TRACE(_bits, _args)
469 # define NS_FRAME_TRACE_IN(_method)
470 # define NS_FRAME_TRACE_OUT(_method)
471 # define NS_FRAME_TRACE_REFLOW_IN(_method)
472 # define NS_FRAME_TRACE_REFLOW_OUT(_method, _status)
473 #endif
475 //----------------------------------------------------------------------
477 // Frame allocation boilerplate macros. Every subclass of nsFrame must
478 // either use NS_{DECL,IMPL}_FRAMEARENA_HELPERS pair for allocating
479 // memory correctly, or use NS_DECL_ABSTRACT_FRAME to declare a frame
480 // class abstract and stop it from being instantiated. If a frame class
481 // without its own operator new and GetFrameId gets instantiated, the
482 // per-frame recycler lists in nsPresArena will not work correctly,
483 // with potentially catastrophic consequences (not enough memory is
484 // allocated for a frame object).
486 #define NS_DECL_FRAMEARENA_HELPERS(class) \
487 NS_DECL_QUERYFRAME_TARGET(class) \
488 static constexpr nsIFrame::ClassID kClassID = nsIFrame::ClassID::class##_id; \
489 void* operator new(size_t, mozilla::PresShell*) MOZ_MUST_OVERRIDE; \
490 nsQueryFrame::FrameIID GetFrameId() const override MOZ_MUST_OVERRIDE { \
491 return nsQueryFrame::class##_id; \
494 #define NS_IMPL_FRAMEARENA_HELPERS(class) \
495 void* class ::operator new(size_t sz, mozilla::PresShell * aShell) { \
496 return aShell->AllocateFrame(nsQueryFrame::class##_id, sz); \
499 #define NS_DECL_ABSTRACT_FRAME(class) \
500 void* operator new(size_t, mozilla::PresShell*) MOZ_MUST_OVERRIDE = delete; \
501 nsQueryFrame::FrameIID GetFrameId() const override MOZ_MUST_OVERRIDE = 0;
503 //----------------------------------------------------------------------
505 namespace mozilla {
507 // A simple class to group stuff that we need to keep around when tearing down
508 // a frame tree.
510 // Native anonymous content created by the frames need to get unbound _after_
511 // the frame has been destroyed, see bug 1400618.
513 // We destroy the anonymous content bottom-up (so, in reverse order), because
514 // it's a bit simpler, though we generally don't have that much nested anonymous
515 // content (except for scrollbars).
516 struct MOZ_RAII FrameDestroyContext {
517 explicit FrameDestroyContext(PresShell* aPs) : mPresShell(aPs) {}
519 void AddAnonymousContent(already_AddRefed<nsIContent>&& aContent) {
520 if (RefPtr<nsIContent> content = aContent) {
521 mAnonymousContent.AppendElement(std::move(content));
525 ~FrameDestroyContext();
527 private:
528 PresShell* const mPresShell;
529 AutoTArray<RefPtr<nsIContent>, 100> mAnonymousContent;
533 * Bit-flags specific to a given layout class id.
535 enum class LayoutFrameClassFlags : uint16_t {
536 None = 0,
537 Leaf = 1 << 0,
538 LeafDynamic = 1 << 1,
539 MathML = 1 << 2,
540 SVG = 1 << 3,
541 SVGContainer = 1 << 4,
542 BidiInlineContainer = 1 << 5,
543 // The frame is for a replaced element, such as an image
544 Replaced = 1 << 6,
545 // Frame that contains a block but looks like a replaced element from the
546 // outside.
547 ReplacedContainsBlock = 1 << 7,
548 // A replaced element that has replaced-element sizing characteristics (i.e.,
549 // like images or iframes), as opposed to inline-block sizing characteristics
550 // (like form controls).
551 ReplacedSizing = 1 << 8,
552 // A frame that participates in inline reflow, i.e., one that requires
553 // ReflowInput::mLineLayout.
554 LineParticipant = 1 << 9,
555 // Whether this frame is a table part (but not a table or table wrapper).
556 TablePart = 1 << 10,
557 CanContainOverflowContainers = 1 << 11,
558 // Whether the frame supports CSS transforms.
559 SupportsCSSTransforms = 1 << 12,
560 // Whether this frame class supports 'contain: layout' and 'contain: paint'
561 // (supporting one is equivalent to supporting the other).
562 SupportsContainLayoutAndPaint = 1 << 13,
563 // Whether this frame class supports the `aspect-ratio` property.
564 SupportsAspectRatio = 1 << 14,
565 // Whether this frame class is always a BFC.
566 BlockFormattingContext = 1 << 15,
569 MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(LayoutFrameClassFlags)
571 } // namespace mozilla
574 * A frame in the layout model. This interface is supported by all frame
575 * objects.
577 * Frames can have multiple child lists: the default child list
578 * (referred to as the <i>principal</i> child list, and additional named
579 * child lists. There is an ordering of frames within a child list, but
580 * there is no order defined between frames in different child lists of
581 * the same parent frame.
583 * Frames are NOT reference counted. Use the Destroy() member function
584 * to destroy a frame. The lifetime of the frame hierarchy is bounded by the
585 * lifetime of the presentation shell which owns the frames.
587 * nsIFrame is a private Gecko interface. If you are not Gecko then you
588 * should not use it. If you're not in layout, then you won't be able to
589 * link to many of the functions defined here. Too bad.
591 * If you're not in layout but you must call functions in here, at least
592 * restrict yourself to calling virtual methods, which won't hurt you as badly.
594 class nsIFrame : public nsQueryFrame {
595 public:
596 using AlignmentContext = mozilla::AlignmentContext;
597 using BaselineSharingGroup = mozilla::BaselineSharingGroup;
598 using BaselineExportContext = mozilla::BaselineExportContext;
599 template <typename T>
600 using Maybe = mozilla::Maybe<T>;
601 template <typename T, typename E>
602 using Result = mozilla::Result<T, E>;
603 using Nothing = mozilla::Nothing;
604 using OnNonvisible = mozilla::OnNonvisible;
605 using ReflowInput = mozilla::ReflowInput;
606 using ReflowOutput = mozilla::ReflowOutput;
607 using Visibility = mozilla::Visibility;
608 using LengthPercentage = mozilla::LengthPercentage;
609 using ContentRelevancy = mozilla::ContentRelevancy;
611 using nsDisplayItem = mozilla::nsDisplayItem;
612 using nsDisplayList = mozilla::nsDisplayList;
613 using nsDisplayListSet = mozilla::nsDisplayListSet;
614 using nsDisplayListBuilder = mozilla::nsDisplayListBuilder;
616 typedef mozilla::ComputedStyle ComputedStyle;
617 typedef mozilla::FrameProperties FrameProperties;
618 typedef mozilla::layers::LayerManager LayerManager;
619 typedef mozilla::gfx::DrawTarget DrawTarget;
620 typedef mozilla::gfx::Matrix Matrix;
621 typedef mozilla::gfx::Matrix4x4 Matrix4x4;
622 typedef mozilla::gfx::Matrix4x4Flagged Matrix4x4Flagged;
623 typedef mozilla::Sides Sides;
624 typedef mozilla::LogicalSides LogicalSides;
625 typedef mozilla::SmallPointerArray<nsDisplayItem> DisplayItemArray;
627 typedef nsQueryFrame::ClassID ClassID;
629 using ClassFlags = mozilla::LayoutFrameClassFlags;
631 protected:
632 using ChildList = mozilla::FrameChildList;
633 using ChildListID = mozilla::FrameChildListID;
634 using ChildListIDs = mozilla::FrameChildListIDs;
636 public:
637 // nsQueryFrame
638 NS_DECL_QUERYFRAME
639 NS_DECL_QUERYFRAME_TARGET(nsIFrame)
641 explicit nsIFrame(ComputedStyle* aStyle, nsPresContext* aPresContext,
642 ClassID aID)
643 : mContent(nullptr),
644 mComputedStyle(aStyle),
645 mPresContext(aPresContext),
646 mParent(nullptr),
647 mNextSibling(nullptr),
648 mPrevSibling(nullptr),
649 mState(NS_FRAME_FIRST_REFLOW | NS_FRAME_IS_DIRTY),
650 mWritingMode(aStyle),
651 mClass(aID),
652 mMayHaveRoundedCorners(false),
653 mHasImageRequest(false),
654 mHasFirstLetterChild(false),
655 mParentIsWrapperAnonBox(false),
656 mIsWrapperBoxNeedingRestyle(false),
657 mReflowRequestedForCharDataChange(false),
658 mForceDescendIntoIfVisible(false),
659 mBuiltDisplayList(false),
660 mFrameIsModified(false),
661 mHasModifiedDescendants(false),
662 mHasOverrideDirtyRegion(false),
663 mMayHaveWillChangeBudget(false),
664 #ifdef DEBUG
665 mWasVisitedByAutoFrameConstructionPageName(false),
666 #endif
667 mIsPrimaryFrame(false),
668 mMayHaveTransformAnimation(false),
669 mMayHaveOpacityAnimation(false),
670 mAllDescendantsAreInvisible(false),
671 mHasBSizeChange(false),
672 mHasPaddingChange(false),
673 mInScrollAnchorChain(false),
674 mHasColumnSpanSiblings(false),
675 mDescendantMayDependOnItsStaticPosition(false) {
676 MOZ_ASSERT(mComputedStyle);
677 MOZ_ASSERT(mPresContext);
678 mozilla::PodZero(&mOverflow);
679 MOZ_COUNT_CTOR(nsIFrame);
681 explicit nsIFrame(ComputedStyle* aStyle, nsPresContext* aPresContext)
682 : nsIFrame(aStyle, aPresContext, ClassID::nsIFrame_id) {}
684 nsPresContext* PresContext() const { return mPresContext; }
686 mozilla::PresShell* PresShell() const { return PresContext()->PresShell(); }
688 virtual nsQueryFrame::FrameIID GetFrameId() const MOZ_MUST_OVERRIDE {
689 return kFrameIID;
693 * Called to initialize the frame. This is called immediately after creating
694 * the frame.
696 * If the frame is a continuing frame, then aPrevInFlow indicates the previous
697 * frame (the frame that was split).
699 * Each subclass that need a view should override this method and call
700 * CreateView() after calling its base class Init().
702 * @param aContent the content object associated with the frame
703 * @param aParent the parent frame
704 * @param aPrevInFlow the prev-in-flow frame
706 virtual void Init(nsIContent* aContent, nsContainerFrame* aParent,
707 nsIFrame* aPrevInFlow);
709 void* operator new(size_t, mozilla::PresShell*) MOZ_MUST_OVERRIDE;
711 using DestroyContext = mozilla::FrameDestroyContext;
714 * Flags for PeekOffsetCharacter, PeekOffsetNoAmount, PeekOffsetWord return
715 * values.
717 enum FrameSearchResult {
718 // Peek found a appropriate offset within frame.
719 FOUND = 0x00,
720 // try next frame for offset.
721 CONTINUE = 0x1,
722 // offset not found because the frame was empty of text.
723 CONTINUE_EMPTY = 0x2 | CONTINUE,
724 // offset not found because the frame didn't contain any text that could be
725 // selected.
726 CONTINUE_UNSELECTABLE = 0x4 | CONTINUE,
730 * Options for PeekOffsetCharacter().
732 struct MOZ_STACK_CLASS PeekOffsetCharacterOptions {
733 // Whether to restrict result to valid cursor locations (between grapheme
734 // clusters) - if this is included, maintains "normal" behavior, otherwise,
735 // used for selection by "code unit" (instead of "character")
736 bool mRespectClusters;
737 // Whether to check user-select style value - if this is included, checks
738 // if user-select is all, then, it may return CONTINUE_UNSELECTABLE.
739 bool mIgnoreUserStyleAll;
741 PeekOffsetCharacterOptions()
742 : mRespectClusters(true), mIgnoreUserStyleAll(false) {}
745 virtual void Destroy(DestroyContext&);
747 protected:
749 * Return true if the frame is part of a Selection.
750 * Helper method to implement the public IsSelected() API.
752 virtual bool IsFrameSelected() const;
754 template <class Source>
755 friend class do_QueryFrameHelper; // to read mClass
756 friend class nsBlockFrame; // for GetCaretBaseline
757 friend class nsContainerFrame; // for ReparentFrameViewTo
759 virtual ~nsIFrame();
761 // Overridden to prevent the global delete from being called, since
762 // the memory came out of an arena instead of the heap.
764 // Ideally this would be private and undefined, like the normal
765 // operator new. Unfortunately, the C++ standard requires an
766 // overridden operator delete to be accessible to any subclass that
767 // defines a virtual destructor, so we can only make it protected;
768 // worse, some C++ compilers will synthesize calls to this function
769 // from the "deleting destructors" that they emit in case of
770 // delete-expressions, so it can't even be undefined.
771 void operator delete(void* aPtr, size_t sz);
773 private:
774 // Left undefined; nsFrame objects are never allocated from the heap.
775 void* operator new(size_t sz) noexcept(true);
777 // Returns true if this frame has any kind of CSS animations.
778 bool HasCSSAnimations();
780 // Returns true if this frame has any kind of CSS transitions.
781 bool HasCSSTransitions();
783 public:
785 * Get the content object associated with this frame. Does not add a
786 * reference.
788 nsIContent* GetContent() const { return mContent; }
791 * @brief Get the closest native anonymous subtree root if the content is in a
792 * native anonymous subtree.
794 * @return The root of native anonymous subtree which the content belongs to.
795 * Otherwise, nullptr.
797 nsIContent* GetClosestNativeAnonymousSubtreeRoot() const {
798 return mContent ? mContent->GetClosestNativeAnonymousSubtreeRoot()
799 : nullptr;
803 * Get the frame that should be the parent for the frames of child elements
804 * May return nullptr during reflow
806 virtual nsContainerFrame* GetContentInsertionFrame() { return nullptr; }
809 * Move any frames on our overflow list to the end of our principal list.
810 * @return true if there were any overflow frames
812 virtual bool DrainSelfOverflowList() { return false; }
815 * Get the frame that should be scrolled if the content associated
816 * with this frame is targeted for scrolling. For frames implementing
817 * nsIScrollableFrame this will return the frame itself. For frames
818 * like nsTextControlFrame that contain a scrollframe, will return
819 * that scrollframe.
821 virtual nsIScrollableFrame* GetScrollTargetFrame() const { return nullptr; }
824 * Get the offsets of the frame. most will be 0,0
827 virtual std::pair<int32_t, int32_t> GetOffsets() const;
830 * Reset the offsets when splitting frames during Bidi reordering
833 virtual void AdjustOffsetsForBidi(int32_t aStart, int32_t aEnd) {}
836 * Get the style associated with this frame.
838 ComputedStyle* Style() const { return mComputedStyle; }
840 void AssertNewStyleIsSane(ComputedStyle&)
841 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
843 #else
846 #endif
848 void SetComputedStyle(ComputedStyle* aStyle) {
849 if (aStyle != mComputedStyle) {
850 AssertNewStyleIsSane(*aStyle);
851 RefPtr<ComputedStyle> oldComputedStyle = std::move(mComputedStyle);
852 mComputedStyle = aStyle;
853 DidSetComputedStyle(oldComputedStyle);
858 * SetComputedStyleWithoutNotification is for changes to the style
859 * context that should suppress style change processing, in other
860 * words, those that aren't really changes. This generally means only
861 * changes that happen during frame construction.
863 void SetComputedStyleWithoutNotification(ComputedStyle* aStyle) {
864 if (aStyle != mComputedStyle) {
865 mComputedStyle = aStyle;
869 protected:
870 // Style post processing hook
871 // Attention: the old style is the one we're forgetting,
872 // and hence possibly completely bogus for GetStyle* purposes.
873 // Use PeekStyleData instead.
874 virtual void DidSetComputedStyle(ComputedStyle* aOldComputedStyle);
876 public:
878 * Define typesafe getter functions for each style struct by
879 * preprocessing the list of style structs. These functions are the
880 * preferred way to get style data. The macro creates functions like:
881 * const nsStyleBorder* StyleBorder();
882 * const nsStyleColor* StyleColor();
884 * Callers outside of libxul should use nsIDOMWindow::GetComputedStyle()
885 * instead of these accessors.
887 * Callers can use Style*WithOptionalParam if they're in a function that
888 * accepts an *optional* pointer the style struct.
890 #define STYLE_STRUCT(name_) \
891 const nsStyle##name_* Style##name_() const MOZ_NONNULL_RETURN { \
892 NS_ASSERTION(mComputedStyle, "No style found!"); \
893 return mComputedStyle->Style##name_(); \
895 const nsStyle##name_* Style##name_##WithOptionalParam( \
896 const nsStyle##name_* aStyleStruct) const MOZ_NONNULL_RETURN { \
897 if (aStyleStruct) { \
898 MOZ_ASSERT(aStyleStruct == Style##name_()); \
899 return aStyleStruct; \
901 return Style##name_(); \
903 #include "nsStyleStructList.h"
904 #undef STYLE_STRUCT
906 /** Also forward GetVisitedDependentColor to the style */
907 template <typename T, typename S>
908 nscolor GetVisitedDependentColor(T S::*aField) {
909 return mComputedStyle->GetVisitedDependentColor(aField);
913 * These methods are to access any additional ComputedStyles that
914 * the frame may be holding.
916 * These are styles that are children of the frame's primary style and are NOT
917 * used as styles for any child frames.
919 * These contexts also MUST NOT have any child styles whatsoever. If you need
920 * to insert styles into the style tree, then you should create pseudo element
921 * frames to own them.
923 * The indicies must be consecutive and implementations MUST return null if
924 * asked for an index that is out of range.
926 virtual ComputedStyle* GetAdditionalComputedStyle(int32_t aIndex) const;
928 virtual void SetAdditionalComputedStyle(int32_t aIndex,
929 ComputedStyle* aComputedStyle);
932 * @param aSelectionStatus nsISelectionController::getDisplaySelection.
934 already_AddRefed<ComputedStyle> ComputeSelectionStyle(
935 int16_t aSelectionStatus) const;
937 already_AddRefed<ComputedStyle> ComputeHighlightSelectionStyle(
938 nsAtom* aHighlightName);
941 * Accessor functions for geometric parent.
943 nsContainerFrame* GetParent() const { return mParent; }
945 bool CanBeDynamicReflowRoot() const;
948 * Gets the parent of a frame, using the parent of the placeholder for
949 * out-of-flow frames.
951 inline nsContainerFrame* GetInFlowParent() const;
954 * Gets the primary frame of the closest flattened tree ancestor that has a
955 * frame (flattened tree ancestors may not have frames in presence of display:
956 * contents).
958 inline nsIFrame* GetClosestFlattenedTreeAncestorPrimaryFrame() const;
961 * Return the placeholder for this frame (which must be out-of-flow).
962 * @note this will only return non-null if |this| is the first-in-flow
963 * although we don't assert that here for legacy reasons.
965 inline nsPlaceholderFrame* GetPlaceholderFrame() const {
966 MOZ_ASSERT(HasAnyStateBits(NS_FRAME_OUT_OF_FLOW));
967 return GetProperty(PlaceholderFrameProperty());
971 * Set this frame's parent to aParent.
972 * If the frame may have moved into or out of a scrollframe's
973 * frame subtree,
974 * StickyScrollContainer::NotifyReparentedFrameAcrossScrollFrameBoundary must
975 * also be called.
977 void SetParent(nsContainerFrame* aParent);
980 * The frame's writing-mode, used for logical layout computations.
981 * It's usually the 'writing-mode' computed value, but there are exceptions:
982 * * inner table frames copy the value from the table frame
983 * (@see nsTableRowGroupFrame::Init, nsTableRowFrame::Init etc)
984 * * the root element frame propagates its value to its ancestors.
985 * The value may obtain from the principal <body> element.
986 * (@see nsCSSFrameConstructor::ConstructDocElementFrame)
987 * * the internal anonymous frames of the root element copy their value
988 * from the parent.
989 * (@see nsIFrame::Init)
990 * * a scrolled frame propagates its value to its ancestor scroll frame
991 * (@see nsHTMLScrollFrame::ReloadChildFrames)
993 mozilla::WritingMode GetWritingMode() const { return mWritingMode; }
996 * Construct a writing mode for line layout in this frame. This is
997 * the writing mode of this frame, except that if this frame is styled with
998 * unicode-bidi:plaintext, we reset the direction to the resolved paragraph
999 * level of the given subframe (typically the first frame on the line),
1000 * because the container frame could be split by hard line breaks into
1001 * multiple paragraphs with different base direction.
1002 * @param aSelfWM the WM of 'this'
1004 mozilla::WritingMode WritingModeForLine(mozilla::WritingMode aSelfWM,
1005 nsIFrame* aSubFrame) const;
1008 * Bounding rect of the frame.
1010 * For frames that are laid out according to CSS box model rules the values
1011 * are in app units, and the origin is relative to the upper-left of the
1012 * geometric parent. The size includes the content area, borders, and
1013 * padding.
1015 * Frames that are laid out according to SVG's coordinate space based rules
1016 * (frames with the NS_FRAME_SVG_LAYOUT bit set, which *excludes*
1017 * SVGOuterSVGFrame) are different. Many frames of this type do not set or
1018 * use mRect, in which case the frame rect is undefined. The exceptions are:
1020 * - SVGInnerSVGFrame
1021 * - SVGGeometryFrame (used for <path>, <circle>, etc.)
1022 * - SVGImageFrame
1023 * - SVGForeignObjectFrame
1025 * For these frames the frame rect contains the frame's element's userspace
1026 * bounds including fill, stroke and markers, but converted to app units
1027 * rather than being in user units (CSS px). In the SVG code "userspace" is
1028 * defined to be the coordinate system for the attributes that define an
1029 * element's geometry (such as the 'cx' attribute for <circle>). For more
1030 * precise details see these frames' implementations of the ReflowSVG method
1031 * where mRect is set.
1033 * Note: moving or sizing the frame does not affect the view's size or
1034 * position.
1036 nsRect GetRect() const { return mRect; }
1037 nsPoint GetPosition() const { return mRect.TopLeft(); }
1038 nsSize GetSize() const { return mRect.Size(); }
1039 nsRect GetRectRelativeToSelf() const {
1040 return nsRect(nsPoint(0, 0), mRect.Size());
1044 * Like the frame's rect (see |GetRect|), which is the border rect,
1045 * other rectangles of the frame, in app units, relative to the parent.
1047 nsRect GetPaddingRect() const;
1048 nsRect GetPaddingRectRelativeToSelf() const;
1049 nsRect GetContentRect() const;
1050 nsRect GetContentRectRelativeToSelf() const;
1051 nsRect GetMarginRect() const;
1052 nsRect GetMarginRectRelativeToSelf() const;
1055 * Dimensions and position in logical coordinates in the frame's writing mode
1056 * or another writing mode
1058 mozilla::LogicalRect GetLogicalRect(const nsSize& aContainerSize) const {
1059 return GetLogicalRect(GetWritingMode(), aContainerSize);
1061 mozilla::LogicalPoint GetLogicalPosition(const nsSize& aContainerSize) const {
1062 return GetLogicalPosition(GetWritingMode(), aContainerSize);
1064 mozilla::LogicalSize GetLogicalSize() const {
1065 return GetLogicalSize(GetWritingMode());
1067 mozilla::LogicalRect GetLogicalRect(mozilla::WritingMode aWritingMode,
1068 const nsSize& aContainerSize) const {
1069 return mozilla::LogicalRect(aWritingMode, GetRect(), aContainerSize);
1071 mozilla::LogicalPoint GetLogicalPosition(mozilla::WritingMode aWritingMode,
1072 const nsSize& aContainerSize) const {
1073 return GetLogicalRect(aWritingMode, aContainerSize).Origin(aWritingMode);
1075 mozilla::LogicalSize GetLogicalSize(mozilla::WritingMode aWritingMode) const {
1076 return mozilla::LogicalSize(aWritingMode, GetSize());
1078 nscoord IStart(const nsSize& aContainerSize) const {
1079 return IStart(GetWritingMode(), aContainerSize);
1081 nscoord IStart(mozilla::WritingMode aWritingMode,
1082 const nsSize& aContainerSize) const {
1083 return GetLogicalPosition(aWritingMode, aContainerSize).I(aWritingMode);
1085 nscoord BStart(const nsSize& aContainerSize) const {
1086 return BStart(GetWritingMode(), aContainerSize);
1088 nscoord BStart(mozilla::WritingMode aWritingMode,
1089 const nsSize& aContainerSize) const {
1090 return GetLogicalPosition(aWritingMode, aContainerSize).B(aWritingMode);
1092 nscoord ISize() const { return ISize(GetWritingMode()); }
1093 nscoord ISize(mozilla::WritingMode aWritingMode) const {
1094 return GetLogicalSize(aWritingMode).ISize(aWritingMode);
1096 nscoord BSize() const { return BSize(GetWritingMode()); }
1097 nscoord BSize(mozilla::WritingMode aWritingMode) const {
1098 return GetLogicalSize(aWritingMode).BSize(aWritingMode);
1100 mozilla::LogicalSize ContentSize() const {
1101 return ContentSize(GetWritingMode());
1103 mozilla::LogicalSize ContentSize(mozilla::WritingMode aWritingMode) const {
1104 mozilla::WritingMode wm = GetWritingMode();
1105 const auto bp = GetLogicalUsedBorderAndPadding(wm)
1106 .ApplySkipSides(GetLogicalSkipSides())
1107 .ConvertTo(aWritingMode, wm);
1108 const auto size = GetLogicalSize(aWritingMode);
1109 return mozilla::LogicalSize(
1110 aWritingMode,
1111 std::max(0, size.ISize(aWritingMode) - bp.IStartEnd(aWritingMode)),
1112 std::max(0, size.BSize(aWritingMode) - bp.BStartEnd(aWritingMode)));
1114 nscoord ContentISize(mozilla::WritingMode aWritingMode) const {
1115 return ContentSize(aWritingMode).ISize(aWritingMode);
1117 nscoord ContentBSize(mozilla::WritingMode aWritingMode) const {
1118 return ContentSize(aWritingMode).BSize(aWritingMode);
1122 * When we change the size of the frame's border-box rect, we may need to
1123 * reset the overflow rect if it was previously stored as deltas.
1124 * (If it is currently a "large" overflow and could be re-packed as deltas,
1125 * we don't bother as the cost of the allocation has already been paid.)
1126 * @param aRebuildDisplayItems If true, then adds this frame to the
1127 * list of modified frames for display list building if the rect has changed.
1128 * Only pass false if you're sure that the relevant display items will be
1129 * rebuilt already (possibly by an ancestor being in the modified list), or if
1130 * this is a temporary change.
1132 void SetRect(const nsRect& aRect, bool aRebuildDisplayItems = true) {
1133 if (aRect == mRect) {
1134 return;
1136 if (mOverflow.mType != OverflowStorageType::Large &&
1137 mOverflow.mType != OverflowStorageType::None) {
1138 mozilla::OverflowAreas overflow = GetOverflowAreas();
1139 mRect = aRect;
1140 SetOverflowAreas(overflow);
1141 } else {
1142 mRect = aRect;
1144 if (aRebuildDisplayItems) {
1145 MarkNeedsDisplayItemRebuild();
1149 * Set this frame's rect from a logical rect in its own writing direction
1151 void SetRect(const mozilla::LogicalRect& aRect,
1152 const nsSize& aContainerSize) {
1153 SetRect(GetWritingMode(), aRect, aContainerSize);
1156 * Set this frame's rect from a logical rect in a different writing direction
1157 * (GetPhysicalRect will assert if the writing mode doesn't match)
1159 void SetRect(mozilla::WritingMode aWritingMode,
1160 const mozilla::LogicalRect& aRect,
1161 const nsSize& aContainerSize) {
1162 SetRect(aRect.GetPhysicalRect(aWritingMode, aContainerSize));
1166 * Set this frame's size from a logical size in its own writing direction.
1167 * This leaves the frame's logical position unchanged, which means its
1168 * physical position may change (for right-to-left modes).
1170 void SetSize(const mozilla::LogicalSize& aSize) {
1171 SetSize(GetWritingMode(), aSize);
1174 * Set this frame's size from a logical size in a different writing direction.
1175 * This leaves the frame's logical position in the given mode unchanged,
1176 * which means its physical position may change (for right-to-left modes).
1178 void SetSize(mozilla::WritingMode aWritingMode,
1179 const mozilla::LogicalSize& aSize) {
1180 if (aWritingMode.IsPhysicalRTL()) {
1181 nscoord oldWidth = mRect.Width();
1182 SetSize(aSize.GetPhysicalSize(aWritingMode));
1183 mRect.x -= mRect.Width() - oldWidth;
1184 } else {
1185 SetSize(aSize.GetPhysicalSize(aWritingMode));
1190 * Set this frame's physical size. This leaves the frame's physical position
1191 * (topLeft) unchanged.
1192 * @param aRebuildDisplayItems If true, then adds this frame to the
1193 * list of modified frames for display list building if the size has changed.
1194 * Only pass false if you're sure that the relevant display items will be
1195 * rebuilt already (possibly by an ancestor being in the modified list), or if
1196 * this is a temporary change.
1198 void SetSize(const nsSize& aSize, bool aRebuildDisplayItems = true) {
1199 SetRect(nsRect(mRect.TopLeft(), aSize), aRebuildDisplayItems);
1202 void SetPosition(const nsPoint& aPt);
1203 void SetPosition(mozilla::WritingMode aWritingMode,
1204 const mozilla::LogicalPoint& aPt,
1205 const nsSize& aContainerSize) {
1206 // We subtract mRect.Size() from the container size to account for
1207 // the fact that logical origins in RTL coordinate systems are at
1208 // the top right of the frame instead of the top left.
1209 SetPosition(
1210 aPt.GetPhysicalPoint(aWritingMode, aContainerSize - mRect.Size()));
1214 * Move the frame, accounting for relative positioning. Use this when
1215 * adjusting the frame's position by a known amount, to properly update its
1216 * saved normal position (see GetNormalPosition below).
1218 * This must be used only when moving a frame *after*
1219 * ReflowInput::ApplyRelativePositioning is called. When moving
1220 * a frame during the reflow process prior to calling
1221 * ReflowInput::ApplyRelativePositioning, the position should
1222 * simply be adjusted directly (e.g., using SetPosition()).
1224 void MovePositionBy(const nsPoint& aTranslation);
1227 * As above, using a logical-point delta in a given writing mode.
1229 void MovePositionBy(mozilla::WritingMode aWritingMode,
1230 const mozilla::LogicalPoint& aTranslation) {
1231 // The LogicalPoint represents a vector rather than a point within a
1232 // rectangular coordinate space, so we use a null containerSize when
1233 // converting logical to physical.
1234 const nsSize nullContainerSize;
1235 MovePositionBy(
1236 aTranslation.GetPhysicalPoint(aWritingMode, nullContainerSize));
1240 * Return frame's rect without relative positioning
1242 nsRect GetNormalRect() const;
1243 mozilla::LogicalRect GetLogicalNormalRect(
1244 mozilla::WritingMode aWritingMode, const nsSize& aContainerSize) const {
1245 return mozilla::LogicalRect(aWritingMode, GetNormalRect(), aContainerSize);
1249 * Returns frame's rect as required by the GetBoundingClientRect() DOM API.
1251 nsRect GetBoundingClientRect();
1254 * Return frame's position without relative positioning.
1255 * If aHasProperty is provided, returns whether the normal position
1256 * was stored in a frame property.
1258 inline nsPoint GetNormalPosition(bool* aHasProperty = nullptr) const;
1259 inline mozilla::LogicalPoint GetLogicalNormalPosition(
1260 mozilla::WritingMode aWritingMode, const nsSize& aContainerSize) const;
1262 virtual nsPoint GetPositionOfChildIgnoringScrolling(const nsIFrame* aChild) {
1263 return aChild->GetPosition();
1266 nsPoint GetPositionIgnoringScrolling() const;
1268 #define NS_DECLARE_FRAME_PROPERTY_WITH_DTOR(prop, type, dtor) \
1269 static const mozilla::FramePropertyDescriptor<type>* prop() { \
1270 /* Use of constexpr caused startup crashes with MSVC2015u1 PGO. */ \
1271 static const auto descriptor = \
1272 mozilla::FramePropertyDescriptor<type>::NewWithDestructor<dtor>(); \
1273 return &descriptor; \
1276 // Don't use this unless you really know what you're doing!
1277 #define NS_DECLARE_FRAME_PROPERTY_WITH_FRAME_IN_DTOR(prop, type, dtor) \
1278 static const mozilla::FramePropertyDescriptor<type>* prop() { \
1279 /* Use of constexpr caused startup crashes with MSVC2015u1 PGO. */ \
1280 static const auto descriptor = mozilla::FramePropertyDescriptor< \
1281 type>::NewWithDestructorWithFrame<dtor>(); \
1282 return &descriptor; \
1285 #define NS_DECLARE_FRAME_PROPERTY_WITHOUT_DTOR(prop, type) \
1286 static const mozilla::FramePropertyDescriptor<type>* prop() { \
1287 /* Use of constexpr caused startup crashes with MSVC2015u1 PGO. */ \
1288 static const auto descriptor = \
1289 mozilla::FramePropertyDescriptor<type>::NewWithoutDestructor(); \
1290 return &descriptor; \
1293 #define NS_DECLARE_FRAME_PROPERTY_DELETABLE(prop, type) \
1294 NS_DECLARE_FRAME_PROPERTY_WITH_DTOR(prop, type, DeleteValue)
1296 #define NS_DECLARE_FRAME_PROPERTY_RELEASABLE(prop, type) \
1297 NS_DECLARE_FRAME_PROPERTY_WITH_DTOR(prop, type, ReleaseValue)
1299 #define NS_DECLARE_FRAME_PROPERTY_WITH_DTOR_NEVER_CALLED(prop, type) \
1300 static void AssertOnDestroyingProperty##prop(type*) { \
1301 MOZ_ASSERT_UNREACHABLE( \
1302 "Frame property " #prop \
1303 " should never be destroyed by the FrameProperties class"); \
1305 NS_DECLARE_FRAME_PROPERTY_WITH_DTOR(prop, type, \
1306 AssertOnDestroyingProperty##prop)
1308 #define NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(prop, type) \
1309 NS_DECLARE_FRAME_PROPERTY_WITHOUT_DTOR(prop, mozilla::SmallValueHolder<type>)
1311 NS_DECLARE_FRAME_PROPERTY_WITHOUT_DTOR(IBSplitSibling, nsContainerFrame)
1312 NS_DECLARE_FRAME_PROPERTY_WITHOUT_DTOR(IBSplitPrevSibling, nsContainerFrame)
1314 NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(NormalPositionProperty, nsPoint)
1315 NS_DECLARE_FRAME_PROPERTY_DELETABLE(ComputedOffsetProperty, nsMargin)
1317 NS_DECLARE_FRAME_PROPERTY_DELETABLE(OutlineInnerRectProperty, nsRect)
1318 NS_DECLARE_FRAME_PROPERTY_DELETABLE(PreEffectsBBoxProperty, nsRect)
1319 NS_DECLARE_FRAME_PROPERTY_DELETABLE(PreTransformOverflowAreasProperty,
1320 mozilla::OverflowAreas)
1322 NS_DECLARE_FRAME_PROPERTY_DELETABLE(OverflowAreasProperty,
1323 mozilla::OverflowAreas)
1325 // The initial overflow area passed to FinishAndStoreOverflow. This is only
1326 // set on frames that Preserve3D() or HasPerspective() or IsTransformed(), and
1327 // when at least one of the overflow areas differs from the frame bound rect.
1328 NS_DECLARE_FRAME_PROPERTY_DELETABLE(InitialOverflowProperty,
1329 mozilla::OverflowAreas)
1331 #ifdef DEBUG
1332 // InitialOverflowPropertyDebug is added to the frame to indicate that either
1333 // the InitialOverflowProperty has been stored or the InitialOverflowProperty
1334 // has been suppressed due to being set to the default value (frame bounds)
1335 NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(DebugInitialOverflowPropertyApplied,
1336 bool)
1337 #endif
1339 NS_DECLARE_FRAME_PROPERTY_DELETABLE(UsedMarginProperty, nsMargin)
1340 NS_DECLARE_FRAME_PROPERTY_DELETABLE(UsedPaddingProperty, nsMargin)
1342 // This tracks the start and end page value for a frame.
1344 // https://www.w3.org/TR/css-page-3/#using-named-pages
1346 // This is only tracked during paginated frame construction.
1347 // This is used to implement fragmentation based on CSS page names. During
1348 // frame construction, we insert page breaks when we begin a new page box and
1349 // the previous page box had a different name.
1350 struct PageValues {
1351 // A value of null indicates that the value is equal to what auto resolves
1352 // to for this frame.
1353 RefPtr<const nsAtom> mStartPageValue = nullptr;
1354 RefPtr<const nsAtom> mEndPageValue = nullptr;
1356 NS_DECLARE_FRAME_PROPERTY_DELETABLE(PageValuesProperty, PageValues)
1358 const nsAtom* GetStartPageValue() const {
1359 if (const PageValues* const values =
1360 FirstInFlow()->GetProperty(PageValuesProperty())) {
1361 return values->mStartPageValue;
1363 return nullptr;
1366 const nsAtom* GetEndPageValue() const {
1367 if (const PageValues* const values =
1368 FirstInFlow()->GetProperty(PageValuesProperty())) {
1369 return values->mEndPageValue;
1371 return nullptr;
1374 // Returns the page name based on style information for this frame, or null
1375 // if the value is auto.
1376 const nsAtom* GetStylePageName() const {
1377 const mozilla::StylePageName& pageName = StylePage()->mPage;
1378 if (pageName.IsPageName()) {
1379 return pageName.AsPageName().AsAtom();
1381 MOZ_ASSERT(pageName.IsAuto(), "Impossible page name");
1382 return nullptr;
1385 bool HasUnreflowedContainerQueryAncestor() const;
1387 private:
1388 // The value that the CSS page-name "auto" keyword resolves to for children
1389 // of this frame.
1391 // A missing value for this property indicates that the auto value is the
1392 // empty string, which is the default if no ancestors of a frame specify a
1393 // page name. This avoids ever storing this property if the document doesn't
1394 // use named pages.
1396 // https://www.w3.org/TR/css-page-3/#using-named-pages
1398 // Ideally this would be a const atom, but that isn't possible with the
1399 // Release() call. This isn't too bad, since it's hidden behind constness-
1400 // preserving getter/setter.
1401 NS_DECLARE_FRAME_PROPERTY_RELEASABLE(AutoPageValueProperty, nsAtom)
1403 public:
1404 // Get the value that the CSS page-name "auto" keyword resolves to for
1405 // children of this frame.
1406 // This is needed when propagating page-name values up the frame tree.
1407 const nsAtom* GetAutoPageValue() const {
1408 if (const nsAtom* const atom = GetProperty(AutoPageValueProperty())) {
1409 return atom;
1411 return nsGkAtoms::_empty;
1413 void SetAutoPageValue(const nsAtom* aAtom) {
1414 MOZ_ASSERT(aAtom, "Atom must not be null");
1415 nsAtom* const atom = const_cast<nsAtom*>(aAtom);
1416 if (atom != nsGkAtoms::_empty) {
1417 SetProperty(AutoPageValueProperty(), do_AddRef(atom).take());
1421 NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(LineBaselineOffset, nscoord)
1423 NS_DECLARE_FRAME_PROPERTY_DELETABLE(InvalidationRect, nsRect)
1425 NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(RefusedAsyncAnimationProperty, bool)
1427 NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(FragStretchBSizeProperty, nscoord)
1429 // The block-axis margin-box size associated with eBClampMarginBoxMinSize.
1430 NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(BClampMarginBoxMinSizeProperty, nscoord)
1432 NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(IBaselinePadProperty, nscoord)
1433 NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(BBaselinePadProperty, nscoord)
1435 NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(BidiDataProperty,
1436 mozilla::FrameBidiData)
1438 NS_DECLARE_FRAME_PROPERTY_WITHOUT_DTOR(PlaceholderFrameProperty,
1439 nsPlaceholderFrame)
1441 NS_DECLARE_FRAME_PROPERTY_RELEASABLE(OffsetPathCache, mozilla::gfx::Path)
1443 mozilla::FrameBidiData GetBidiData() const {
1444 bool exists;
1445 mozilla::FrameBidiData bidiData = GetProperty(BidiDataProperty(), &exists);
1446 if (!exists) {
1447 bidiData.precedingControl = mozilla::kBidiLevelNone;
1449 return bidiData;
1452 mozilla::intl::BidiEmbeddingLevel GetBaseLevel() const {
1453 return GetBidiData().baseLevel;
1456 mozilla::intl::BidiEmbeddingLevel GetEmbeddingLevel() const {
1457 return GetBidiData().embeddingLevel;
1461 * Return the distance between the border edge of the frame and the
1462 * margin edge of the frame. Like GetRect(), returns the dimensions
1463 * as of the most recent reflow.
1465 * This doesn't include any margin collapsing that may have occurred.
1466 * It also doesn't consider GetSkipSides()/GetLogicalSkipSides(), so
1467 * may report nonzero values on sides that are actually skipped for
1468 * this fragment.
1470 * It also treats 'auto' margins as zero, and treats any margins that
1471 * should have been turned into 'auto' because of overconstraint as
1472 * having their original values.
1474 virtual nsMargin GetUsedMargin() const;
1475 virtual mozilla::LogicalMargin GetLogicalUsedMargin(
1476 mozilla::WritingMode aWritingMode) const {
1477 return mozilla::LogicalMargin(aWritingMode, GetUsedMargin());
1481 * Return the distance between the border edge of the frame (which is
1482 * its rect) and the padding edge of the frame. Like GetRect(), returns
1483 * the dimensions as of the most recent reflow.
1485 * This doesn't consider GetSkipSides()/GetLogicalSkipSides(), so
1486 * may report nonzero values on sides that are actually skipped for
1487 * this fragment.
1489 * Note that this differs from StyleBorder()->GetComputedBorder() in
1490 * that this describes a region of the frame's box, and
1491 * StyleBorder()->GetComputedBorder() describes a border. They differ
1492 * for tables (particularly border-collapse tables) and themed
1493 * elements.
1495 virtual nsMargin GetUsedBorder() const;
1496 virtual mozilla::LogicalMargin GetLogicalUsedBorder(
1497 mozilla::WritingMode aWritingMode) const {
1498 return mozilla::LogicalMargin(aWritingMode, GetUsedBorder());
1502 * Return the distance between the padding edge of the frame and the
1503 * content edge of the frame. Like GetRect(), returns the dimensions
1504 * as of the most recent reflow.
1506 * This doesn't consider GetSkipSides()/GetLogicalSkipSides(), so
1507 * may report nonzero values on sides that are actually skipped for
1508 * this fragment.
1510 virtual nsMargin GetUsedPadding() const;
1511 virtual mozilla::LogicalMargin GetLogicalUsedPadding(
1512 mozilla::WritingMode aWritingMode) const {
1513 return mozilla::LogicalMargin(aWritingMode, GetUsedPadding());
1516 nsMargin GetUsedBorderAndPadding() const {
1517 return GetUsedBorder() + GetUsedPadding();
1519 mozilla::LogicalMargin GetLogicalUsedBorderAndPadding(
1520 mozilla::WritingMode aWritingMode) const {
1521 return mozilla::LogicalMargin(aWritingMode, GetUsedBorderAndPadding());
1525 * The area to paint box-shadows around. The default is the border rect.
1526 * (nsFieldSetFrame overrides this).
1528 virtual nsRect VisualBorderRectRelativeToSelf() const {
1529 return nsRect(0, 0, mRect.Width(), mRect.Height());
1533 * Get the size, in app units, of the border radii. It returns FALSE iff all
1534 * returned radii == 0 (so no border radii), TRUE otherwise.
1535 * For the aRadii indexes, use the enum HalfCorner constants in gfx/2d/Types.h
1536 * If a side is skipped via aSkipSides, its corners are forced to 0.
1538 * All corner radii are then adjusted so they do not require more
1539 * space than aBorderArea, according to the algorithm in css3-background.
1541 * aFrameSize is used as the basis for percentage widths and heights.
1542 * aBorderArea is used for the adjustment of radii that might be too
1543 * large.
1545 * Return whether any radii are nonzero.
1547 static bool ComputeBorderRadii(const mozilla::BorderRadius&,
1548 const nsSize& aFrameSize,
1549 const nsSize& aBorderArea, Sides aSkipSides,
1550 nscoord aRadii[8]);
1553 * Given a set of border radii for one box (e.g., border box), convert
1554 * it to the equivalent set of radii for another box (e.g., in to
1555 * padding box, out to outline box) by reducing radii or increasing
1556 * nonzero radii as appropriate.
1558 * Indices into aRadii are the enum HalfCorner constants in gfx/2d/Types.h
1560 * Note that insetting the radii is lossy, since it can turn nonzero radii
1561 * into zero, and re-adjusting does not inflate zero radii.
1563 * Therefore, callers should always adjust directly from the original value
1564 * coming from style.
1566 static void AdjustBorderRadii(nscoord aRadii[8], const nsMargin& aOffsets);
1569 * Fill in border radii for this frame. Return whether any are nonzero.
1570 * Indices into aRadii are the enum HalfCorner constants in gfx/2d/Types.h
1571 * aSkipSides is a union of SideBits::eLeft/Right/Top/Bottom bits that says
1572 * which side(s) to skip.
1574 * Note: GetMarginBoxBorderRadii() and GetShapeBoxBorderRadii() work only
1575 * on frames that establish block formatting contexts since they don't
1576 * participate in margin-collapsing.
1578 virtual bool GetBorderRadii(const nsSize& aFrameSize,
1579 const nsSize& aBorderArea, Sides aSkipSides,
1580 nscoord aRadii[8]) const;
1581 bool GetBorderRadii(nscoord aRadii[8]) const;
1582 bool GetMarginBoxBorderRadii(nscoord aRadii[8]) const;
1583 bool GetPaddingBoxBorderRadii(nscoord aRadii[8]) const;
1584 bool GetContentBoxBorderRadii(nscoord aRadii[8]) const;
1585 bool GetBoxBorderRadii(nscoord aRadii[8], const nsMargin& aOffset) const;
1586 bool GetShapeBoxBorderRadii(nscoord aRadii[8]) const;
1589 * Returns one em unit, adjusted for font inflation if needed, in app units.
1591 nscoord OneEmInAppUnits() const;
1594 * `GetNaturalBaselineBOffset`, but determines the baseline sharing group
1595 * through `GetDefaultBaselineSharingGroup` (If not specified), assuming line
1596 * layout context, and never fails, returning a synthesized baseline through
1597 * `SynthesizeFallbackBaseline`. Unlike `GetNaturalBaselineBOffset`, Result is
1598 * always relative to the block start of the frame.
1600 nscoord GetLogicalBaseline(mozilla::WritingMode aWM) const;
1602 * Same as the above, but with baseline sharing group & export
1603 * context specified.
1605 nscoord GetLogicalBaseline(mozilla::WritingMode aWM,
1606 BaselineSharingGroup aBaselineGroup,
1607 BaselineExportContext aExportContext) const;
1610 * Return true if the frame has a first(last) inline-axis baseline per
1611 * CSS Box Alignment. If so, the returned baseline is the distance from
1612 * the relevant block-axis border-box edge (Start for
1613 * BaselineSharingGroup::First, end for BaselineSharingGroup::Last), where
1614 * a positive value points towards the content-box.
1615 * Some frames can export different baselines depending if it's in a line
1616 * layout context or any other context (e.g. Flex, grid).
1617 * https://drafts.csswg.org/css-align-3/#baseline-export
1618 * @note The returned value is only valid when reflow is not needed.
1619 * @note You should only call this on frames with a WM that's parallel to aWM.
1620 * @note We're approaching `nsLayoutUtils::Get(First|Last)LineBaseline` ==
1621 * `GetNaturalBaselineBOffset(aWM, (First|Last), Other)`. Grid relies on
1622 * baseline synthesis behaviour in `nsLayoutUtils` implementations (bug
1623 * 1609403), which blocks its removal.
1624 * @param aWM the writing-mode of the alignment context.
1625 * @return the baseline offset, if one exists
1627 virtual Maybe<nscoord> GetNaturalBaselineBOffset(
1628 mozilla::WritingMode aWM, BaselineSharingGroup aBaselineGroup,
1629 BaselineExportContext aExportContext) const {
1630 return Nothing{};
1633 struct CaretBlockAxisMetrics {
1634 nscoord mOffset = 0;
1635 nscoord mExtent = 0;
1638 * Get the offset (Block start of the caret) and extent of the caret in this
1639 * frame. The returned offset is corrected for vertical & line-inverted
1640 * writing modes.
1642 CaretBlockAxisMetrics GetCaretBlockAxisMetrics(mozilla::WritingMode,
1643 const nsFontMetrics&) const;
1644 // Gets the page-name value to be used for the page that contains this frame
1645 // during paginated reflow.
1646 // This only inspects the first in-flow child of this frame, and if that
1647 // is a container frame then its first in-flow child, until it reaches the
1648 // deepest child of the tree.
1649 // This will resolve auto values, including the case where no frame has a
1650 // page-name set in which case it will return the empty atom. It will never
1651 // return null.
1652 // This is intended to be used either on the root frame to find the first
1653 // page's page-name, or on a newly created continuation to find what the new
1654 // page's page-name will be.
1656 // The auto page value can be set by the caller. This is useful when trying
1657 // to compute a page value in the middle of a frame tree. In that case the
1658 // auto value can be found from the AutoPageValue frame property of the
1659 // parent frame. A null auto value is interpreted as the empty-string atom.
1660 const nsAtom* ComputePageValue(const nsAtom* aAutoValue = nullptr) const
1661 MOZ_NONNULL_RETURN;
1663 ///////////////////////////////////////////////////////////////////////////////
1664 // The public visibility API.
1665 ///////////////////////////////////////////////////////////////////////////////
1667 /// @return true if we're tracking visibility for this frame.
1668 bool TrackingVisibility() const {
1669 return HasAnyStateBits(NS_FRAME_VISIBILITY_IS_TRACKED);
1672 /// @return the visibility state of this frame. See the Visibility enum
1673 /// for the possible return values and their meanings.
1674 Visibility GetVisibility() const;
1676 /// Update the visibility state of this frame synchronously.
1677 /// XXX(seth): Avoid using this method; we should be relying on the refresh
1678 /// driver for visibility updates. This method, which replaces
1679 /// nsLayoutUtils::UpdateApproximateFrameVisibility(), exists purely as a
1680 /// temporary measure to avoid changing behavior during the transition from
1681 /// the old image visibility code.
1682 void UpdateVisibilitySynchronously();
1684 // A frame property which stores the visibility state of this frame. Right
1685 // now that consists of an approximate visibility counter represented as a
1686 // uint32_t. When the visibility of this frame is not being tracked, this
1687 // property is absent.
1688 NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(VisibilityStateProperty, uint32_t);
1690 protected:
1692 * Get the position of the baseline on which the caret needs to be placed,
1693 * relative to the top of the frame. This is mostly needed for frames
1694 * which return a baseline from GetBaseline which is not useful for
1695 * caret positioning.
1697 virtual nscoord GetCaretBaseline() const {
1698 return GetLogicalBaseline(GetWritingMode());
1702 * Subclasses can call this method to enable visibility tracking for this
1703 * frame.
1705 * If visibility tracking was previously disabled, this will schedule an
1706 * update an asynchronous update of visibility.
1708 void EnableVisibilityTracking();
1711 * Subclasses can call this method to disable visibility tracking for this
1712 * frame.
1714 * Note that if visibility tracking was previously enabled, disabling
1715 * visibility tracking will cause a synchronous call to OnVisibilityChange().
1717 void DisableVisibilityTracking();
1720 * Called when a frame transitions between visibility states (for example,
1721 * from nonvisible to visible, or from visible to nonvisible).
1723 * @param aNewVisibility The new visibility state.
1724 * @param aNonvisibleAction A requested action if the frame has become
1725 * nonvisible. If Nothing(), no action is
1726 * requested. If DISCARD_IMAGES is specified, the
1727 * frame is requested to ask any images it's
1728 * associated with to discard their surfaces if
1729 * possible.
1731 * Subclasses which override this method should call their parent class's
1732 * implementation.
1734 virtual void OnVisibilityChange(
1735 Visibility aNewVisibility,
1736 const Maybe<OnNonvisible>& aNonvisibleAction = Nothing());
1739 * Synthesize a baseline for this element. The returned baseline is the
1740 * distance from the relevant block-axis border-box edge (Start for
1741 * BaselineSharingGroup::First, end for BaselineSharingGroup::Last), where a
1742 * positive value points towards the content-box.
1743 * @note This always returns a synthesized baseline, even if the element may
1744 * have an actual baseline.
1746 virtual nscoord SynthesizeFallbackBaseline(
1747 mozilla::WritingMode aWM, BaselineSharingGroup aBaselineGroup) const;
1749 public:
1751 * Get the suitable baseline sharing group for this element, assuming line
1752 * layout.
1754 virtual BaselineSharingGroup GetDefaultBaselineSharingGroup() const {
1755 return BaselineSharingGroup::First;
1758 ///////////////////////////////////////////////////////////////////////////////
1759 // Internal implementation for the approximate frame visibility API.
1760 ///////////////////////////////////////////////////////////////////////////////
1763 * We track the approximate visibility of frames using a counter; if it's
1764 * non-zero, then the frame is considered visible. Using a counter allows us
1765 * to account for situations where the frame may be visible in more than one
1766 * place (for example, via -moz-element), and it simplifies the
1767 * implementation of our approximate visibility tracking algorithms.
1769 * @param aNonvisibleAction A requested action if the frame has become
1770 * nonvisible. If Nothing(), no action is
1771 * requested. If DISCARD_IMAGES is specified, the
1772 * frame is requested to ask any images it's
1773 * associated with to discard their surfaces if
1774 * possible.
1776 void DecApproximateVisibleCount(
1777 const Maybe<OnNonvisible>& aNonvisibleAction = Nothing());
1778 void IncApproximateVisibleCount();
1781 * Get the specified child list.
1783 * @param aListID identifies the requested child list.
1784 * @return the child list. If the requested list is unsupported by this
1785 * frame type, an empty list will be returned.
1787 virtual const nsFrameList& GetChildList(ChildListID aListID) const;
1788 const nsFrameList& PrincipalChildList() const {
1789 return GetChildList(mozilla::FrameChildListID::Principal);
1793 * Sub-classes should override this methods if they want to append their own
1794 * child lists into aLists.
1796 virtual void GetChildLists(nsTArray<ChildList>* aLists) const;
1799 * Returns the child lists for this frame.
1801 AutoTArray<ChildList, 4> ChildLists() const {
1802 AutoTArray<ChildList, 4> childLists;
1803 GetChildLists(&childLists);
1804 return childLists;
1808 * Returns the child lists for this frame, including ones belong to a child
1809 * document.
1811 AutoTArray<ChildList, 4> CrossDocChildLists();
1814 * Child frames are linked together in a doubly-linked list
1816 nsIFrame* GetNextSibling() const { return mNextSibling; }
1817 void SetNextSibling(nsIFrame* aNextSibling) {
1818 NS_ASSERTION(this != aNextSibling,
1819 "Creating a circular frame list, this is very bad.");
1820 if (mNextSibling && mNextSibling->GetPrevSibling() == this) {
1821 mNextSibling->mPrevSibling = nullptr;
1823 mNextSibling = aNextSibling;
1824 if (mNextSibling) {
1825 mNextSibling->mPrevSibling = this;
1829 nsIFrame* GetPrevSibling() const { return mPrevSibling; }
1832 * Builds the display lists for the content represented by this frame
1833 * and its descendants. The background+borders of this element must
1834 * be added first, before any other content.
1836 * This should only be called by methods in nsFrame. Instead of calling this
1837 * directly, call either BuildDisplayListForStackingContext or
1838 * BuildDisplayListForChild.
1840 * See nsDisplayList.h for more information about display lists.
1842 virtual void BuildDisplayList(nsDisplayListBuilder* aBuilder,
1843 const nsDisplayListSet& aLists) {}
1845 * Displays the caret onto the given display list builder. The caret is
1846 * painted on top of the rest of the display list items.
1848 void DisplayCaret(nsDisplayListBuilder* aBuilder, nsDisplayList* aList);
1851 * Get the preferred caret color at the offset.
1853 * @param aOffset is offset of the content.
1855 virtual nscolor GetCaretColorAt(int32_t aOffset);
1857 bool IsThemed(nsITheme::Transparency* aTransparencyState = nullptr) const {
1858 return IsThemed(StyleDisplay(), aTransparencyState);
1860 bool IsThemed(const nsStyleDisplay* aDisp,
1861 nsITheme::Transparency* aTransparencyState = nullptr) const {
1862 if (!aDisp->HasAppearance()) {
1863 return false;
1865 nsIFrame* mutable_this = const_cast<nsIFrame*>(this);
1866 nsPresContext* pc = PresContext();
1867 nsITheme* theme = pc->Theme();
1868 if (!theme->ThemeSupportsWidget(pc, mutable_this,
1869 aDisp->EffectiveAppearance())) {
1870 return false;
1872 if (aTransparencyState) {
1873 *aTransparencyState = theme->GetWidgetTransparency(
1874 mutable_this, aDisp->EffectiveAppearance());
1876 return true;
1880 * Builds a display list for the content represented by this frame,
1881 * treating this frame as the root of a stacking context.
1882 * Optionally sets aCreatedContainerItem to true if we created a
1883 * single container display item for the stacking context, and no
1884 * other wrapping items are needed.
1886 void BuildDisplayListForStackingContext(
1887 nsDisplayListBuilder* aBuilder, nsDisplayList* aList,
1888 bool* aCreatedContainerItem = nullptr);
1890 enum class DisplayChildFlag {
1891 ForcePseudoStackingContext,
1892 ForceStackingContext,
1893 Inline,
1895 using DisplayChildFlags = mozilla::EnumSet<DisplayChildFlag>;
1898 * Adjusts aDirtyRect for the child's offset, checks that the dirty rect
1899 * actually intersects the child (or its descendants), calls BuildDisplayList
1900 * on the child if necessary, and puts things in the right lists if the child
1901 * is positioned.
1903 * @param aFlags a set of of DisplayChildFlag values that are applicable for
1904 * this operation.
1906 void BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
1907 nsIFrame* aChild,
1908 const nsDisplayListSet& aLists,
1909 DisplayChildFlags aFlags = {});
1911 void BuildDisplayListForSimpleChild(nsDisplayListBuilder* aBuilder,
1912 nsIFrame* aChild,
1913 const nsDisplayListSet& aLists);
1916 * Helper for BuildDisplayListForChild, to implement this special-case for
1917 * grid (and flex) items from the spec:
1918 * The painting order of grid items is exactly the same as inline blocks,
1919 * except that [...], and 'z-index' values other than 'auto' create a
1920 * stacking context even if 'position' is 'static' (behaving exactly as if
1921 * 'position' were 'relative'). https://drafts.csswg.org/css-grid/#z-order
1923 * Flex items also have the same special-case described in
1924 * https://drafts.csswg.org/css-flexbox/#painting
1926 static DisplayChildFlags DisplayFlagsForFlexOrGridItem() {
1927 return DisplayChildFlags{DisplayChildFlag::ForcePseudoStackingContext};
1930 bool RefusedAsyncAnimation() const {
1931 return GetProperty(RefusedAsyncAnimationProperty());
1935 * Returns true if this frame is transformed (e.g. has CSS, SVG, or custom
1936 * transforms) or if its parent is an SVG frame that has children-only
1937 * transforms (e.g. an SVG viewBox attribute) or if its transform-style is
1938 * preserve-3d or the frame has transform animations.
1940 bool IsTransformed() const;
1943 * Same as IsTransformed, except that it doesn't take SVG transforms
1944 * into account.
1946 bool IsCSSTransformed() const;
1949 * True if this frame has any animation of transform in effect.
1951 bool HasAnimationOfTransform() const;
1954 * True if this frame has any animation of opacity in effect.
1956 * EffectSet is just an optimization.
1958 bool HasAnimationOfOpacity(mozilla::EffectSet* = nullptr) const;
1961 * Returns true if the frame is translucent or the frame has opacity
1962 * animations for the purposes of creating a stacking context.
1964 * @param aStyleDisplay: This function needs style display struct.
1966 * @param aStyleEffects: This function needs style effects struct.
1968 * @param aEffectSet: This function may need to look up EffectSet property.
1969 * If a caller already have one, pass it in can save property look up
1970 * time; otherwise, just leave it as nullptr.
1972 bool HasOpacity(const nsStyleDisplay* aStyleDisplay,
1973 const nsStyleEffects* aStyleEffects,
1974 mozilla::EffectSet* aEffectSet = nullptr) const {
1975 return HasOpacityInternal(1.0f, aStyleDisplay, aStyleEffects, aEffectSet);
1978 * Returns true if the frame is translucent for display purposes.
1980 * @param aStyleDisplay: This function needs style display struct.
1982 * @param aStyleEffects: This function needs style effects struct.
1984 * @param aEffectSet: This function may need to look up EffectSet property.
1985 * If a caller already have one, pass it in can save property look up
1986 * time; otherwise, just leave it as nullptr.
1988 bool HasVisualOpacity(const nsStyleDisplay* aStyleDisplay,
1989 const nsStyleEffects* aStyleEffects,
1990 mozilla::EffectSet* aEffectSet = nullptr) const {
1991 // Treat an opacity value of 0.99 and above as opaque. This is an
1992 // optimization aimed at Web content which use opacity:0.99 as a hint for
1993 // creating a stacking context only.
1994 return HasOpacityInternal(0.99f, aStyleDisplay, aStyleEffects, aEffectSet);
1998 * Returns a matrix (in pixels) for the current frame. The matrix should be
1999 * relative to the current frame's coordinate space.
2001 * @param aFrame The frame to compute the transform for.
2002 * @param aAppUnitsPerPixel The number of app units per graphics unit.
2004 using ComputeTransformFunction = Matrix4x4 (*)(const nsIFrame*,
2005 float aAppUnitsPerPixel);
2006 /** Returns the transform getter of this frame, if any. */
2007 virtual ComputeTransformFunction GetTransformGetter() const {
2008 return nullptr;
2012 * Returns true if this frame is an SVG frame that has SVG transforms applied
2013 * to it, or if its parent frame is an SVG frame that has children-only
2014 * transforms (e.g. an SVG viewBox attribute).
2015 * If aOwnTransforms is non-null and the frame has its own SVG transforms,
2016 * aOwnTransforms will be set to these transforms. If aFromParentTransforms
2017 * is non-null and the frame has an SVG parent with children-only transforms,
2018 * then aFromParentTransforms will be set to these transforms.
2020 virtual bool IsSVGTransformed(Matrix* aOwnTransforms = nullptr,
2021 Matrix* aFromParentTransforms = nullptr) const;
2024 * Returns whether this frame will attempt to extend the 3d transforms of its
2025 * children. This requires transform-style: preserve-3d, as well as no
2026 * clipping or svg effects.
2028 * @param aStyleDisplay: If the caller has this->StyleDisplay(), providing
2029 * it here will improve performance.
2031 * @param aStyleEffects: If the caller has this->StyleEffects(), providing
2032 * it here will improve performance.
2034 * @param aEffectSetForOpacity: This function may need to look up the
2035 * EffectSet for opacity animations on this frame.
2036 * If the caller already has looked up this EffectSet, it may pass it in to
2037 * save an extra property lookup.
2039 bool Extend3DContext(
2040 const nsStyleDisplay* aStyleDisplay, const nsStyleEffects* aStyleEffects,
2041 mozilla::EffectSet* aEffectSetForOpacity = nullptr) const;
2042 bool Extend3DContext(
2043 mozilla::EffectSet* aEffectSetForOpacity = nullptr) const {
2044 return Extend3DContext(StyleDisplay(), StyleEffects(),
2045 aEffectSetForOpacity);
2049 * Returns whether this frame has a parent that Extend3DContext() and has
2050 * its own transform (or hidden backface) to be combined with the parent's
2051 * transform.
2053 bool Combines3DTransformWithAncestors() const;
2056 * Returns whether this frame has a hidden backface and has a parent that
2057 * Extend3DContext(). This is useful because in some cases the hidden
2058 * backface can safely be ignored if it could not be visible anyway.
2061 bool In3DContextAndBackfaceIsHidden() const;
2063 bool IsPreserve3DLeaf(const nsStyleDisplay* aStyleDisplay,
2064 mozilla::EffectSet* aEffectSet = nullptr) const {
2065 return Combines3DTransformWithAncestors() &&
2066 !Extend3DContext(aStyleDisplay, StyleEffects(), aEffectSet);
2068 bool IsPreserve3DLeaf(mozilla::EffectSet* aEffectSet = nullptr) const {
2069 return IsPreserve3DLeaf(StyleDisplay(), aEffectSet);
2072 bool HasPerspective() const;
2074 bool ChildrenHavePerspective(const nsStyleDisplay* aStyleDisplay) const;
2075 bool ChildrenHavePerspective() const {
2076 return ChildrenHavePerspective(StyleDisplay());
2080 * Includes the overflow area of all descendants that participate in the
2081 * current 3d context into aOverflowAreas.
2083 void ComputePreserve3DChildrenOverflow(
2084 mozilla::OverflowAreas& aOverflowAreas);
2086 void RecomputePerspectiveChildrenOverflow(const nsIFrame* aStartFrame);
2089 * Returns whether z-index applies to this frame.
2091 bool ZIndexApplies() const;
2094 * Returns the computed z-index for this frame, returning Nothing() for
2095 * z-index: auto, and for frames that don't support z-index.
2097 Maybe<int32_t> ZIndex() const;
2100 * Returns whether this frame is the anchor of some ancestor scroll frame. As
2101 * this frame is moved, the scroll frame will apply adjustments to keep this
2102 * scroll frame in the same relative position.
2104 * aOutContainer will optionally be set to the scroll anchor container for
2105 * this frame if this frame is an anchor.
2107 bool IsScrollAnchor(
2108 mozilla::layout::ScrollAnchorContainer** aOutContainer = nullptr);
2111 * Returns whether this frame is the anchor of some ancestor scroll frame, or
2112 * has a descendant which is the scroll anchor.
2114 bool IsInScrollAnchorChain() const;
2115 void SetInScrollAnchorChain(bool aInChain);
2118 * Returns the number of ancestors between this and the root of our frame tree
2120 uint32_t GetDepthInFrameTree() const;
2123 * Event handling of GUI events.
2125 * @param aEvent event structure describing the type of event and rge widget
2126 * where the event originated. The |point| member of this is in the coordinate
2127 * system of the view returned by GetOffsetFromView.
2129 * @param aEventStatus a return value indicating whether the event was
2130 * handled and whether default processing should be done
2132 * XXX From a frame's perspective it's unclear what the effect of the event
2133 * status is. Does it cause the event to continue propagating through the
2134 * frame hierarchy or is it just returned to the widgets?
2136 * @see WidgetGUIEvent
2137 * @see nsEventStatus
2139 MOZ_CAN_RUN_SCRIPT_BOUNDARY
2140 virtual nsresult HandleEvent(nsPresContext* aPresContext,
2141 mozilla::WidgetGUIEvent* aEvent,
2142 nsEventStatus* aEventStatus);
2145 * Search for selectable content at point and attempt to select
2146 * based on the start and end selection behaviours.
2148 * @param aPresContext Presentation context
2149 * @param aPoint Point at which selection will occur. Coordinates
2150 * should be relative to this frame.
2151 * @param aBeginAmountType, aEndAmountType Selection behavior, see
2152 * nsIFrame for definitions.
2153 * @param aSelectFlags Selection flags defined in nsIFrame.h.
2154 * @return success or failure at finding suitable content to select.
2156 MOZ_CAN_RUN_SCRIPT nsresult
2157 SelectByTypeAtPoint(nsPresContext* aPresContext, const nsPoint& aPoint,
2158 nsSelectionAmount aBeginAmountType,
2159 nsSelectionAmount aEndAmountType, uint32_t aSelectFlags);
2161 MOZ_CAN_RUN_SCRIPT nsresult PeekBackwardAndForward(
2162 nsSelectionAmount aAmountBack, nsSelectionAmount aAmountForward,
2163 int32_t aStartPos, bool aJumpLines, uint32_t aSelectFlags);
2165 enum { SELECT_ACCUMULATE = 0x01 };
2167 protected:
2168 // Fire DOM event. If no aContent argument use frame's mContent.
2169 void FireDOMEvent(const nsAString& aDOMEventName,
2170 nsIContent* aContent = nullptr);
2172 // Selection Methods
2174 MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHOD
2175 HandlePress(nsPresContext* aPresContext, mozilla::WidgetGUIEvent* aEvent,
2176 nsEventStatus* aEventStatus);
2179 * MoveCaretToEventPoint() moves caret at the point of aMouseEvent.
2181 * @param aPresContext Must not be nullptr.
2182 * @param aMouseEvent Must not be nullptr, the message must be
2183 * eMouseDown and its button must be primary or
2184 * middle button.
2185 * @param aEventStatus [out] Must not be nullptr. This method ignores
2186 * its initial value, but callees may refer it.
2188 MOZ_CAN_RUN_SCRIPT nsresult MoveCaretToEventPoint(
2189 nsPresContext* aPresContext, mozilla::WidgetMouseEvent* aMouseEvent,
2190 nsEventStatus* aEventStatus);
2193 * Check whether aSecondaryButtonMouseEvent should or should not cause moving
2194 * caret at event point. This is designed only for the secondary mouse button
2195 * event (i.e., right button event in general).
2197 * @param aFrameSelection The nsFrameSelection which should handle the
2198 * caret move with.
2199 * @param aSecondaryButtonEvent Must be the button value is
2200 * MouseButton::eSecondary.
2201 * @param aContentAtEventPoint The content node at the event point.
2202 * @param aOffsetAtEventPoint The offset in aContentAtEventPoint where
2203 * aSecondaryButtonEvent clicked.
2205 [[nodiscard]] bool MovingCaretToEventPointAllowedIfSecondaryButtonEvent(
2206 const nsFrameSelection& aFrameSelection,
2207 mozilla::WidgetMouseEvent& aSecondaryButtonEvent,
2208 const nsIContent& aContentAtEventPoint,
2209 int32_t aOffsetAtEventPoint) const;
2211 MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHOD HandleMultiplePress(
2212 nsPresContext* aPresContext, mozilla::WidgetGUIEvent* aEvent,
2213 nsEventStatus* aEventStatus, bool aControlHeld);
2216 * @param aPresContext must be non-nullptr.
2217 * @param aEvent must be non-nullptr.
2218 * @param aEventStatus must be non-nullptr.
2220 MOZ_CAN_RUN_SCRIPT
2221 NS_IMETHOD HandleDrag(nsPresContext* aPresContext,
2222 mozilla::WidgetGUIEvent* aEvent,
2223 nsEventStatus* aEventStatus);
2225 MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHOD
2226 HandleRelease(nsPresContext* aPresContext, mozilla::WidgetGUIEvent* aEvent,
2227 nsEventStatus* aEventStatus);
2229 // Test if we are selecting a table object:
2230 // Most table/cell selection requires that Ctrl (Cmd on Mac) key is down
2231 // during a mouse click or drag. Exception is using Shift+click when
2232 // already in "table/cell selection mode" to extend a block selection
2233 // Get the parent content node and offset of the frame
2234 // of the enclosing cell or table (if not inside a cell)
2235 // aTarget tells us what table element to select (currently only cell and
2236 // table supported) (enums for this are defined in nsIFrame.h)
2237 nsresult GetDataForTableSelection(const nsFrameSelection* aFrameSelection,
2238 mozilla::PresShell* aPresShell,
2239 mozilla::WidgetMouseEvent* aMouseEvent,
2240 nsIContent** aParentContent,
2241 int32_t* aContentOffset,
2242 mozilla::TableSelectionMode* aTarget);
2245 * @return see nsISelectionController.idl's `getDisplaySelection`.
2247 int16_t DetermineDisplaySelection();
2249 public:
2250 virtual nsresult GetContentForEvent(const mozilla::WidgetEvent* aEvent,
2251 nsIContent** aContent);
2253 // This structure keeps track of the content node and offsets associated with
2254 // a point; there is a primary and a secondary offset associated with any
2255 // point. The primary and secondary offsets differ when the point is over a
2256 // non-text object. The primary offset is the expected position of the
2257 // cursor calculated from a point; the secondary offset, when it is different,
2258 // indicates that the point is in the boundaries of some selectable object.
2259 // Note that the primary offset can be after the secondary offset; for places
2260 // that need the beginning and end of the object, the StartOffset and
2261 // EndOffset helpers can be used.
2262 struct MOZ_STACK_CLASS ContentOffsets {
2263 ContentOffsets() = default;
2264 bool IsNull() { return !content; }
2265 // Helpers for places that need the ends of the offsets and expect them in
2266 // numerical order, as opposed to wanting the primary and secondary offsets
2267 int32_t StartOffset() { return std::min(offset, secondaryOffset); }
2268 int32_t EndOffset() { return std::max(offset, secondaryOffset); }
2270 nsCOMPtr<nsIContent> content;
2271 int32_t offset = 0;
2272 int32_t secondaryOffset = 0;
2273 // This value indicates whether the associated content is before or after
2274 // the offset; the most visible use is to allow the caret to know which line
2275 // to display on.
2276 mozilla::CaretAssociationHint associate{0}; // Before
2278 enum {
2279 IGNORE_SELECTION_STYLE = 1 << 0,
2280 // Treat visibility:hidden frames as non-selectable
2281 SKIP_HIDDEN = 1 << 1,
2282 // Do not return content in native anonymous subtree (if the frame is in a
2283 // native anonymous subtree, the method may return content in same subtree).
2284 IGNORE_NATIVE_ANONYMOUS_SUBTREE = 1 << 2,
2287 * This function calculates the content offsets for selection relative to
2288 * a point. Note that this should generally only be callled on the event
2289 * frame associated with an event because this function does not account
2290 * for frame lists other than the primary one.
2291 * @param aPoint point relative to this frame
2293 ContentOffsets GetContentOffsetsFromPoint(const nsPoint& aPoint,
2294 uint32_t aFlags = 0);
2296 virtual ContentOffsets GetContentOffsetsFromPointExternal(
2297 const nsPoint& aPoint, uint32_t aFlags = 0) {
2298 return GetContentOffsetsFromPoint(aPoint, aFlags);
2301 // Helper for GetContentAndOffsetsFromPoint; calculation of content offsets
2302 // in this function assumes there is no child frame that can be targeted.
2303 virtual ContentOffsets CalcContentOffsetsFromFramePoint(
2304 const nsPoint& aPoint);
2307 * Ensure that `this` gets notifed when `aImage`s underlying image request
2308 * loads or animates.
2310 * This in practice is only needed for the canvas frame and table cell
2311 * backgrounds, which are the only cases that should paint a background that
2312 * isn't its own. The canvas paints the background from the root element or
2313 * body, and the table cell paints the background for its row.
2315 * For regular frames, this is done in DidSetComputedStyle.
2317 * NOTE: It's unclear if we even actually _need_ this for the second case, as
2318 * invalidating the row should invalidate all the cells. For the canvas case
2319 * this is definitely needed as it paints the background from somewhere "down"
2320 * in the frame tree.
2322 * Returns whether the image was in fact associated with the frame.
2324 [[nodiscard]] bool AssociateImage(const mozilla::StyleImage&);
2327 * This needs to be called if the above caller returned true, once the above
2328 * caller doesn't care about getting notified anymore.
2330 void DisassociateImage(const mozilla::StyleImage&);
2332 mozilla::StyleImageRendering UsedImageRendering() const;
2333 mozilla::StyleTouchAction UsedTouchAction() const;
2335 enum class AllowCustomCursorImage {
2337 Yes,
2341 * This structure holds information about a cursor. AllowCustomCursorImage
2342 * is `No`, then no cursor image should be loaded from the style specified on
2343 * `mStyle`, or the frame's style.
2345 * The `mStyle` member is used for `<area>` elements.
2347 struct MOZ_STACK_CLASS Cursor {
2348 mozilla::StyleCursorKind mCursor = mozilla::StyleCursorKind::Auto;
2349 AllowCustomCursorImage mAllowCustomCursor = AllowCustomCursorImage::Yes;
2350 RefPtr<mozilla::ComputedStyle> mStyle;
2354 * Get the cursor for a given frame.
2356 virtual Cursor GetCursor(const nsPoint&);
2359 * Get a point (in the frame's coordinate space) given an offset into
2360 * the content. This point should be on the baseline of text with
2361 * the correct horizontal offset
2363 virtual nsresult GetPointFromOffset(int32_t inOffset, nsPoint* outPoint);
2366 * Get a list of character rects in a given range.
2367 * This is similar version of GetPointFromOffset.
2369 virtual nsresult GetCharacterRectsInRange(int32_t aInOffset, int32_t aLength,
2370 nsTArray<nsRect>& aRects);
2373 * Get the child frame of this frame which contains the given
2374 * content offset. outChildFrame may be this frame, or nullptr on return.
2375 * outContentOffset returns the content offset relative to the start
2376 * of the returned node. You can also pass a hint which tells the method
2377 * to stick to the end of the first found frame or the beginning of the
2378 * next in case the offset falls on a boundary.
2380 virtual nsresult GetChildFrameContainingOffset(
2381 int32_t inContentOffset,
2382 bool inHint, // false stick left
2383 int32_t* outFrameContentOffset, nsIFrame** outChildFrame);
2386 * Get the current frame-state value for this frame. aResult is
2387 * filled in with the state bits.
2389 nsFrameState GetStateBits() const { return mState; }
2392 * Update the current frame-state value for this frame.
2394 void AddStateBits(nsFrameState aBits) { mState |= aBits; }
2395 void RemoveStateBits(nsFrameState aBits) { mState &= ~aBits; }
2396 void AddOrRemoveStateBits(nsFrameState aBits, bool aVal) {
2397 aVal ? AddStateBits(aBits) : RemoveStateBits(aBits);
2401 * Checks if the current frame-state includes all of the listed bits
2403 bool HasAllStateBits(nsFrameState aBits) const {
2404 return (mState & aBits) == aBits;
2408 * Checks if the current frame-state includes any of the listed bits
2410 bool HasAnyStateBits(nsFrameState aBits) const { return mState & aBits; }
2412 private:
2414 * Called when this frame becomes primary for mContent.
2416 void InitPrimaryFrame();
2418 * Called when the primary frame style changes.
2420 * Kind of like DidSetComputedStyle, but the first computed style is set
2421 * before SetPrimaryFrame, so we need this tweak.
2423 void HandlePrimaryFrameStyleChange(ComputedStyle* aOldStyle);
2425 public:
2427 * Return true if this frame is the primary frame for mContent.
2429 bool IsPrimaryFrame() const { return mIsPrimaryFrame; }
2431 void SetIsPrimaryFrame(bool aIsPrimary) {
2432 mIsPrimaryFrame = aIsPrimary;
2433 if (aIsPrimary) {
2434 InitPrimaryFrame();
2438 bool IsPrimaryFrameOfRootOrBodyElement() const;
2441 * @return true if this frame is used as a fieldset's rendered legend.
2443 bool IsRenderedLegend() const;
2446 * This call is invoked on the primary frame for a character data content
2447 * node, when it is changed in the content tree.
2449 virtual nsresult CharacterDataChanged(const CharacterDataChangeInfo&);
2452 * This call is invoked when the value of a content objects's attribute
2453 * is changed.
2454 * The first frame that maps that content is asked to deal
2455 * with the change by doing whatever is appropriate.
2457 * @param aNameSpaceID the namespace of the attribute
2458 * @param aAttribute the atom name of the attribute
2459 * @param aModType Whether or not the attribute was added, changed, or
2460 * removed. The constants are defined in MutationEvent.webidl.
2462 virtual nsresult AttributeChanged(int32_t aNameSpaceID, nsAtom* aAttribute,
2463 int32_t aModType);
2466 * When the element states of mContent change, this method is invoked on the
2467 * primary frame of that element.
2469 * @param aStates the changed states
2471 virtual void ElementStateChanged(mozilla::dom::ElementState aStates);
2474 * Continuation member functions
2476 virtual nsIFrame* GetPrevContinuation() const;
2477 virtual void SetPrevContinuation(nsIFrame*);
2478 virtual nsIFrame* GetNextContinuation() const;
2479 virtual void SetNextContinuation(nsIFrame*);
2480 virtual nsIFrame* FirstContinuation() const {
2481 return const_cast<nsIFrame*>(this);
2483 virtual nsIFrame* LastContinuation() const {
2484 return const_cast<nsIFrame*>(this);
2488 * GetTailContinuation gets the last non-overflow-container continuation
2489 * in the continuation chain, i.e. where the next sibling element
2490 * should attach).
2492 nsIFrame* GetTailContinuation();
2495 * Flow member functions
2497 virtual nsIFrame* GetPrevInFlow() const;
2498 virtual void SetPrevInFlow(nsIFrame*);
2500 virtual nsIFrame* GetNextInFlow() const;
2501 virtual void SetNextInFlow(nsIFrame*);
2504 * Return the first frame in our current flow.
2506 virtual nsIFrame* FirstInFlow() const { return const_cast<nsIFrame*>(this); }
2509 * Return the last frame in our current flow.
2511 virtual nsIFrame* LastInFlow() const { return const_cast<nsIFrame*>(this); }
2514 * Note: "width" in the names and comments on the following methods
2515 * means inline-size, which could be height in vertical layout
2519 * Mark any stored intrinsic width information as dirty (requiring
2520 * re-calculation). Note that this should generally not be called
2521 * directly; PresShell::FrameNeedsReflow() will call it instead.
2523 virtual void MarkIntrinsicISizesDirty();
2525 public:
2527 * Make this frame and all descendants dirty (if not already).
2528 * Exceptions: TableColGroupFrame children.
2530 void MarkSubtreeDirty();
2533 * Get the min-content intrinsic inline size of the frame. This must be
2534 * less than or equal to the max-content intrinsic inline size.
2536 * This is *not* affected by the CSS 'min-width', 'width', and
2537 * 'max-width' properties on this frame, but it is affected by the
2538 * values of those properties on this frame's descendants. (It may be
2539 * called during computation of the values of those properties, so it
2540 * cannot depend on any values in the nsStylePosition for this frame.)
2542 * The value returned should **NOT** include the space required for
2543 * padding and border.
2545 * Note that many frames will cache the result of this function call
2546 * unless MarkIntrinsicISizesDirty is called.
2548 * It is not acceptable for a frame to mark itself dirty when this
2549 * method is called.
2551 * This method must not return a negative value.
2553 virtual nscoord GetMinISize(gfxContext* aRenderingContext);
2556 * Get the max-content intrinsic inline size of the frame. This must be
2557 * greater than or equal to the min-content intrinsic inline size.
2559 * Otherwise, all the comments for |GetMinISize| above apply.
2561 virtual nscoord GetPrefISize(gfxContext* aRenderingContext);
2564 * |InlineIntrinsicISize| represents the intrinsic width information
2565 * in inline layout. Code that determines the intrinsic width of a
2566 * region of inline layout accumulates the result into this structure.
2567 * This pattern is needed because we need to maintain state
2568 * information about whitespace (for both collapsing and trimming).
2570 struct InlineIntrinsicISizeData {
2571 InlineIntrinsicISizeData()
2572 : mLine(nullptr),
2573 mLineContainer(nullptr),
2574 mPrevLines(0),
2575 mCurrentLine(0),
2576 mTrailingWhitespace(0),
2577 mSkipWhitespace(true) {}
2579 // The line. This may be null if the inlines are not associated with
2580 // a block or if we just don't know the line.
2581 const nsLineList_iterator* mLine;
2583 // The line container. Private, to ensure we always use SetLineContainer
2584 // to update it.
2586 // Note that nsContainerFrame::DoInlineIntrinsicISize will clear the
2587 // |mLine| and |mLineContainer| fields when following a next-in-flow link,
2588 // so we must not assume these can always be dereferenced.
2589 private:
2590 nsIFrame* mLineContainer;
2592 // Setter and getter for the lineContainer field:
2593 public:
2594 void SetLineContainer(nsIFrame* aLineContainer) {
2595 mLineContainer = aLineContainer;
2597 nsIFrame* LineContainer() const { return mLineContainer; }
2599 // The maximum intrinsic width for all previous lines.
2600 nscoord mPrevLines;
2602 // The maximum intrinsic width for the current line. At a line
2603 // break (mandatory for preferred width; allowed for minimum width),
2604 // the caller should call |Break()|.
2605 nscoord mCurrentLine;
2607 // This contains the width of the trimmable whitespace at the end of
2608 // |mCurrentLine|; it is zero if there is no such whitespace.
2609 nscoord mTrailingWhitespace;
2611 // True if initial collapsable whitespace should be skipped. This
2612 // should be true at the beginning of a block, after hard breaks
2613 // and when the last text ended with whitespace.
2614 bool mSkipWhitespace;
2616 // Floats encountered in the lines.
2617 class FloatInfo {
2618 public:
2619 FloatInfo(const nsIFrame* aFrame, nscoord aWidth)
2620 : mFrame(aFrame), mWidth(aWidth) {}
2621 const nsIFrame* Frame() const { return mFrame; }
2622 nscoord Width() const { return mWidth; }
2624 private:
2625 const nsIFrame* mFrame;
2626 nscoord mWidth;
2629 nsTArray<FloatInfo> mFloats;
2632 struct InlineMinISizeData : public InlineIntrinsicISizeData {
2633 InlineMinISizeData() : mAtStartOfLine(true) {}
2635 // The default implementation for nsIFrame::AddInlineMinISize.
2636 void DefaultAddInlineMinISize(nsIFrame* aFrame, nscoord aISize,
2637 bool aAllowBreak = true);
2639 // We need to distinguish forced and optional breaks for cases where the
2640 // current line total is negative. When it is, we need to ignore
2641 // optional breaks to prevent min-width from ending up bigger than
2642 // pref-width.
2643 void ForceBreak();
2645 // If the break here is actually taken, aHyphenWidth must be added to the
2646 // width of the current line.
2647 void OptionallyBreak(nscoord aHyphenWidth = 0);
2649 // Whether we're currently at the start of the line. If we are, we
2650 // can't break (for example, between the text-indent and the first
2651 // word).
2652 bool mAtStartOfLine;
2655 struct InlinePrefISizeData : public InlineIntrinsicISizeData {
2656 InlinePrefISizeData() : mLineIsEmpty(true) {}
2659 * Finish the current line and start a new line.
2661 * @param aClearType controls whether isize of floats are considered
2662 * and what floats are kept for the next line:
2663 * * |None| skips handling floats, which means no floats are
2664 * removed, and isizes of floats are not considered either.
2665 * * |Both| takes floats into consideration when computing isize
2666 * of the current line, and removes all floats after that.
2667 * * |Left| and |Right| do the same as |Both| except that they only
2668 * remove floats on the given side, and any floats on the other
2669 * side that are prior to a float on the given side that has a
2670 * 'clear' property that clears them.
2672 void ForceBreak(mozilla::StyleClear aClearType = mozilla::StyleClear::Both);
2674 // The default implementation for nsIFrame::AddInlinePrefISize.
2675 void DefaultAddInlinePrefISize(nscoord aISize);
2677 // True if the current line contains nothing other than placeholders.
2678 bool mLineIsEmpty;
2682 * Add the intrinsic minimum width of a frame in a way suitable for
2683 * use in inline layout to an |InlineIntrinsicISizeData| object that
2684 * represents the intrinsic width information of all the previous
2685 * frames in the inline layout region.
2687 * All *allowed* breakpoints within the frame determine what counts as
2688 * a line for the |InlineIntrinsicISizeData|. This means that
2689 * |aData->mTrailingWhitespace| will always be zero (unlike for
2690 * AddInlinePrefISize).
2692 * All the comments for |GetMinISize| apply, except that this function
2693 * is responsible for adding padding, border, and margin and for
2694 * considering the effects of 'width', 'min-width', and 'max-width'.
2696 * This may be called on any frame. Frames that do not participate in
2697 * line breaking can inherit the default implementation on nsFrame,
2698 * which calls |GetMinISize|.
2700 virtual void AddInlineMinISize(gfxContext* aRenderingContext,
2701 InlineMinISizeData* aData);
2704 * Add the intrinsic preferred width of a frame in a way suitable for
2705 * use in inline layout to an |InlineIntrinsicISizeData| object that
2706 * represents the intrinsic width information of all the previous
2707 * frames in the inline layout region.
2709 * All the comments for |AddInlineMinISize| and |GetPrefISize| apply,
2710 * except that this fills in an |InlineIntrinsicISizeData| structure
2711 * based on using all *mandatory* breakpoints within the frame.
2713 virtual void AddInlinePrefISize(gfxContext* aRenderingContext,
2714 InlinePrefISizeData* aData);
2717 * Intrinsic size of a frame in a single axis.
2719 * This can represent either isize or bsize.
2721 struct IntrinsicSizeOffsetData {
2722 nscoord padding = 0;
2723 nscoord border = 0;
2724 nscoord margin = 0;
2725 nscoord BorderPadding() const { return border + padding; };
2729 * Return the isize components of padding, border, and margin
2730 * that contribute to the intrinsic width that applies to the parent.
2731 * @param aPercentageBasis the percentage basis to use for padding/margin -
2732 * i.e. the Containing Block's inline-size
2734 virtual IntrinsicSizeOffsetData IntrinsicISizeOffsets(
2735 nscoord aPercentageBasis = NS_UNCONSTRAINEDSIZE);
2738 * Return the bsize components of padding, border, and margin
2739 * that contribute to the intrinsic width that applies to the parent.
2740 * @param aPercentageBasis the percentage basis to use for padding/margin -
2741 * i.e. the Containing Block's inline-size
2743 IntrinsicSizeOffsetData IntrinsicBSizeOffsets(
2744 nscoord aPercentageBasis = NS_UNCONSTRAINEDSIZE);
2746 virtual mozilla::IntrinsicSize GetIntrinsicSize();
2749 * Get the preferred aspect ratio of this frame, or a default-constructed
2750 * AspectRatio if it has none.
2752 * https://drafts.csswg.org/css-sizing-4/#preferred-aspect-ratio
2754 mozilla::AspectRatio GetAspectRatio() const;
2757 * Get the intrinsic aspect ratio of this frame, or a default-constructed
2758 * AspectRatio if it has no intrinsic ratio.
2760 * The intrinsic ratio is the ratio of the width/height of a box with an
2761 * intrinsic size or the intrinsic aspect ratio of a scalable vector image
2762 * without an intrinsic size. A frame class implementing a replaced element
2763 * should override this method if it has a intrinsic ratio.
2765 virtual mozilla::AspectRatio GetIntrinsicRatio() const;
2768 * Compute the size that a frame will occupy. Called while
2769 * constructing the ReflowInput to be used to Reflow the frame,
2770 * in order to fill its mComputedWidth and mComputedHeight member
2771 * variables.
2773 * Note that the reason that border and padding need to be passed
2774 * separately is so that the 'box-sizing' property can be handled.
2775 * Thus aMargin includes absolute positioning offsets as well.
2777 * @param aWM The writing mode to use for the returned size (need not match
2778 * this frame's writing mode). This is also the writing mode of
2779 * the passed-in LogicalSize parameters.
2780 * @param aCBSize The size of the element's containing block. (Well,
2781 * the BSize() component isn't really.)
2782 * @param aAvailableISize The available inline-size for 'auto' inline-size.
2783 * This is usually the same as aCBSize.ISize(),
2784 * but differs in cases such as block
2785 * formatting context roots next to floats, or
2786 * in some cases of float reflow in quirks
2787 * mode.
2788 * @param aMargin The sum of the inline / block margins ***AND***
2789 * absolute positioning offsets (inset-block and
2790 * inset-inline) of the frame, including actual values
2791 * resulting from percentages and from the
2792 * "hypothetical box" for absolute positioning, but
2793 * not including actual values resulting from 'auto'
2794 * margins or ignored 'auto' values in absolute
2795 * positioning.
2796 * @param aBorderPadding The sum of the frame's inline / block border-widths
2797 * and padding (including actual values resulting from
2798 * percentage padding values).
2799 * @param aSizeOverride Optional override values for size properties, which
2800 * this function will use internally instead of the
2801 * actual property values.
2802 * @param aFlags Flags to further customize behavior (definitions in
2803 * LayoutConstants.h).
2805 * The return value includes the computed LogicalSize and AspectRatioUsage
2806 * which indicates whether the inline/block size is affected by aspect-ratio
2807 * or not. The BSize() of the returned LogicalSize may be
2808 * NS_UNCONSTRAINEDSIZE, but the ISize() must not be. We need AspectRatioUsage
2809 * during reflow because the final size may be affected by the content size
2810 * after applying aspect-ratio.
2811 * https://drafts.csswg.org/css-sizing-4/#aspect-ratio-minimum
2814 enum class AspectRatioUsage : uint8_t {
2815 None,
2816 ToComputeISize,
2817 ToComputeBSize,
2819 struct SizeComputationResult {
2820 mozilla::LogicalSize mLogicalSize;
2821 AspectRatioUsage mAspectRatioUsage = AspectRatioUsage::None;
2823 virtual SizeComputationResult ComputeSize(
2824 gfxContext* aRenderingContext, mozilla::WritingMode aWM,
2825 const mozilla::LogicalSize& aCBSize, nscoord aAvailableISize,
2826 const mozilla::LogicalSize& aMargin,
2827 const mozilla::LogicalSize& aBorderPadding,
2828 const mozilla::StyleSizeOverrides& aSizeOverrides,
2829 mozilla::ComputeSizeFlags aFlags);
2831 protected:
2833 * A helper, used by |nsIFrame::ComputeSize| (for frames that need to
2834 * override only this part of ComputeSize), that computes the size
2835 * that should be returned when inline-size, block-size, and
2836 * [min|max]-[inline-size|block-size] are all 'auto' or equivalent.
2838 * In general, frames that can accept any computed inline-size/block-size
2839 * should override only ComputeAutoSize, and frames that cannot do so need to
2840 * override ComputeSize to enforce their inline-size/block-size invariants.
2842 * Implementations may optimize by returning a garbage inline-size if
2843 * StylePosition()->ISize() is not 'auto' (or inline-size override in
2844 * aSizeOverrides is not 'auto' if provided), and likewise for BSize(), since
2845 * in such cases the result is guaranteed to be unused.
2847 * Most of the frame are not expected to check the aSizeOverrides parameter
2848 * apart from checking the inline size override for 'auto' if they want to
2849 * optimize and return garbage inline-size.
2851 virtual mozilla::LogicalSize ComputeAutoSize(
2852 gfxContext* aRenderingContext, mozilla::WritingMode aWM,
2853 const mozilla::LogicalSize& aCBSize, nscoord aAvailableISize,
2854 const mozilla::LogicalSize& aMargin,
2855 const mozilla::LogicalSize& aBorderPadding,
2856 const mozilla::StyleSizeOverrides& aSizeOverrides,
2857 mozilla::ComputeSizeFlags aFlags);
2860 * Utility function for ComputeAutoSize implementations. Return
2861 * max(GetMinISize(), min(aISizeInCB, GetPrefISize()))
2863 nscoord ShrinkISizeToFit(gfxContext* aRenderingContext, nscoord aISizeInCB,
2864 mozilla::ComputeSizeFlags aFlags);
2866 public:
2868 * Compute a tight bounding rectangle for the frame. This is a rectangle
2869 * that encloses the pixels that are actually drawn. We're allowed to be
2870 * conservative and currently we don't try very hard. The rectangle is
2871 * in appunits and relative to the origin of this frame.
2873 * This probably only needs to include frame bounds, glyph bounds, and
2874 * text decorations, but today it sometimes includes other things that
2875 * contribute to ink overflow.
2877 * @param aDrawTarget a draw target that can be used if we need
2878 * to do measurement
2880 virtual nsRect ComputeTightBounds(DrawTarget* aDrawTarget) const;
2883 * This function is similar to GetPrefISize and ComputeTightBounds: it
2884 * computes the left and right coordinates of a preferred tight bounding
2885 * rectangle for the frame. This is a rectangle that would enclose the pixels
2886 * that are drawn if we lay out the element without taking any optional line
2887 * breaks. The rectangle is in appunits and relative to the origin of this
2888 * frame. Currently, this function is only implemented for nsBlockFrame and
2889 * nsTextFrame and is used to determine intrinsic widths of MathML token
2890 * elements.
2892 * @param aContext a rendering context that can be used if we need
2893 * to do measurement
2894 * @param aX computed left coordinate of the tight bounding rectangle
2895 * @param aXMost computed intrinsic width of the tight bounding rectangle
2898 virtual nsresult GetPrefWidthTightBounds(gfxContext* aContext, nscoord* aX,
2899 nscoord* aXMost);
2902 * The frame is given an available size and asked for its desired
2903 * size. This is the frame's opportunity to reflow its children.
2905 * If the frame has the NS_FRAME_IS_DIRTY bit set then it is
2906 * responsible for completely reflowing itself and all of its
2907 * descendants.
2909 * Otherwise, if the frame has the NS_FRAME_HAS_DIRTY_CHILDREN bit
2910 * set, then it is responsible for reflowing at least those
2911 * children that have NS_FRAME_HAS_DIRTY_CHILDREN or NS_FRAME_IS_DIRTY
2912 * set.
2914 * If a difference in available size from the previous reflow causes
2915 * the frame's size to change, it should reflow descendants as needed.
2917 * Calculates the size of this frame after reflowing (calling Reflow on, and
2918 * updating the size and position of) its children, as necessary. The
2919 * calculated size is returned to the caller via the ReflowOutput
2920 * outparam. (The caller is responsible for setting the actual size and
2921 * position of this frame.)
2923 * A frame's children must _all_ be reflowed if the frame is dirty (the
2924 * NS_FRAME_IS_DIRTY bit is set on it). Otherwise, individual children
2925 * must be reflowed if they are dirty or have the NS_FRAME_HAS_DIRTY_CHILDREN
2926 * bit set on them. Otherwise, whether children need to be reflowed depends
2927 * on the frame's type (it's up to individual Reflow methods), and on what
2928 * has changed. For example, a change in the width of the frame may require
2929 * all of its children to be reflowed (even those without dirty bits set on
2930 * them), whereas a change in its height might not.
2931 * (ReflowInput::ShouldReflowAllKids may be helpful in deciding whether
2932 * to reflow all the children, but for some frame types it might result in
2933 * over-reflow.)
2935 * Note: if it's only the overflow rect(s) of a frame that need to be
2936 * updated, then UpdateOverflow should be called instead of Reflow.
2938 * @param aReflowOutput <i>out</i> parameter where you should return the
2939 * desired size and ascent/descent info. You should include any
2940 * space you want for border/padding in the desired size you return.
2942 * It's okay to return a desired size that exceeds the avail
2943 * size if that's the smallest you can be, i.e. it's your
2944 * minimum size.
2946 * For an incremental reflow you are responsible for invalidating
2947 * any area within your frame that needs repainting (including
2948 * borders). If your new desired size is different than your current
2949 * size, then your parent frame is responsible for making sure that
2950 * the difference between the two rects is repainted
2952 * @param aReflowInput information about your reflow including the reason
2953 * for the reflow and the available space in which to lay out. Each
2954 * dimension of the available space can either be constrained or
2955 * unconstrained (a value of NS_UNCONSTRAINEDSIZE).
2957 * Note that the available space can be negative. In this case you
2958 * still must return an accurate desired size. If you're a container
2959 * you must <b>always</b> reflow at least one frame regardless of the
2960 * available space
2962 * @param aStatus a return value indicating whether the frame is complete
2963 * and whether the next-in-flow is dirty and needs to be reflowed
2965 virtual void Reflow(nsPresContext* aPresContext, ReflowOutput& aReflowOutput,
2966 const ReflowInput& aReflowInput, nsReflowStatus& aStatus);
2968 // Option flags for ReflowChild(), FinishReflowChild(), and
2969 // SyncFrameViewAfterReflow().
2970 enum class ReflowChildFlags : uint32_t {
2971 Default = 0,
2973 // Don't position the frame's view. Set this if you don't want to
2974 // automatically sync the frame and view.
2975 NoMoveView = 1 << 0,
2977 // Don't move the frame. Also implies NoMoveView.
2978 NoMoveFrame = (1 << 1) | NoMoveView,
2980 // Don't size the frame's view.
2981 NoSizeView = 1 << 2,
2983 // Only applies to ReflowChild; if true, don't delete the next-in-flow, even
2984 // if the reflow is fully complete.
2985 NoDeleteNextInFlowChild = 1 << 3,
2987 // Only applies to FinishReflowChild. Tell it to call
2988 // ApplyRelativePositioning.
2989 ApplyRelativePositioning = 1 << 4,
2993 * Post-reflow hook. After a frame is reflowed this method will be called
2994 * informing the frame that this reflow process is complete, and telling the
2995 * frame the status returned by the Reflow member function.
2997 * This call may be invoked many times, while NS_FRAME_IN_REFLOW is set,
2998 * before it is finally called once with a NS_FRAME_REFLOW_COMPLETE value.
2999 * When called with a NS_FRAME_REFLOW_COMPLETE value the NS_FRAME_IN_REFLOW
3000 * bit in the frame state will be cleared.
3002 * XXX This doesn't make sense. If the frame is reflowed but not complete,
3003 * then the status should have IsIncomplete() equal to true.
3004 * XXX Don't we want the semantics to dictate that we only call this once for
3005 * a given reflow?
3007 virtual void DidReflow(nsPresContext* aPresContext,
3008 const ReflowInput* aReflowInput);
3010 void FinishReflowWithAbsoluteFrames(nsPresContext* aPresContext,
3011 ReflowOutput& aDesiredSize,
3012 const ReflowInput& aReflowInput,
3013 nsReflowStatus& aStatus,
3014 bool aConstrainBSize = true);
3017 * Updates the overflow areas of the frame. This can be called if an
3018 * overflow area of the frame's children has changed without reflowing.
3019 * @return true if either of the overflow areas for this frame have changed.
3021 bool UpdateOverflow();
3024 * Computes any overflow area created by the frame itself (outside of the
3025 * frame bounds) and includes it into aOverflowAreas.
3027 * Returns false if updating overflow isn't supported for this frame.
3028 * If the frame requires a reflow instead, then it is responsible
3029 * for scheduling one.
3031 virtual bool ComputeCustomOverflow(mozilla::OverflowAreas& aOverflowAreas);
3034 * Computes any overflow area created by children of this frame and
3035 * includes it into aOverflowAreas.
3037 virtual void UnionChildOverflow(mozilla::OverflowAreas& aOverflowAreas);
3039 // Returns the applicable overflow-clip-margin values.
3040 using PhysicalAxes = mozilla::PhysicalAxes;
3042 nsSize OverflowClipMargin(PhysicalAxes aClipAxes) const;
3043 // Returns the axes on which this frame should apply overflow clipping.
3044 PhysicalAxes ShouldApplyOverflowClipping(const nsStyleDisplay* aDisp) const;
3045 // Returns whether this frame is a block that was supposed to be a
3046 // scrollframe, but that was suppressed for print.
3047 bool IsSuppressedScrollableBlockForPrint() const;
3050 * Helper method used by block reflow to identify runs of text so
3051 * that proper word-breaking can be done.
3053 * @return
3054 * true if we can continue a "text run" through the frame. A
3055 * text run is text that should be treated contiguously for line
3056 * and word breaking.
3058 virtual bool CanContinueTextRun() const;
3061 * Computes an approximation of the rendered text of the frame and its
3062 * continuations. Returns nothing for non-text frames.
3063 * The appended text will often not contain all the whitespace from source,
3064 * depending on CSS white-space processing.
3065 * if aEndOffset goes past end, use the text up to the string's end.
3066 * Call this on the primary frame for a text node.
3067 * aStartOffset and aEndOffset can be content offsets or offsets in the
3068 * rendered text, depending on aOffsetType.
3069 * Returns a string, as well as offsets identifying the start of the text
3070 * within the rendered text for the whole node, and within the text content
3071 * of the node.
3073 struct RenderedText {
3074 nsAutoString mString;
3075 uint32_t mOffsetWithinNodeRenderedText;
3076 int32_t mOffsetWithinNodeText;
3077 RenderedText()
3078 : mOffsetWithinNodeRenderedText(0), mOffsetWithinNodeText(0) {}
3080 enum class TextOffsetType {
3081 // Passed-in start and end offsets are within the content text.
3082 OffsetsInContentText,
3083 // Passed-in start and end offsets are within the rendered text.
3084 OffsetsInRenderedText,
3086 enum class TrailingWhitespace {
3087 Trim,
3088 // Spaces preceding a caret at the end of a line should not be trimmed
3089 DontTrim,
3091 virtual RenderedText GetRenderedText(
3092 uint32_t aStartOffset = 0, uint32_t aEndOffset = UINT32_MAX,
3093 TextOffsetType aOffsetType = TextOffsetType::OffsetsInContentText,
3094 TrailingWhitespace aTrimTrailingWhitespace = TrailingWhitespace::Trim) {
3095 return RenderedText();
3099 * Returns true if the frame contains any non-collapsed characters.
3100 * This method is only available for text frames, and it will return false
3101 * for all other frame types.
3103 virtual bool HasAnyNoncollapsedCharacters() { return false; }
3106 * Returns true if events of the given type targeted at this frame
3107 * should only be dispatched to the system group.
3109 virtual bool OnlySystemGroupDispatch(mozilla::EventMessage aMessage) const {
3110 return false;
3114 // Accessor functions to an associated view object:
3116 bool HasView() const { return !!(mState & NS_FRAME_HAS_VIEW); }
3118 // Returns true iff this frame's computed block-size property is one of the
3119 // intrinsic-sizing keywords.
3120 bool HasIntrinsicKeywordForBSize() const {
3121 const auto& bSize = StylePosition()->BSize(GetWritingMode());
3122 return bSize.IsFitContent() || bSize.IsMinContent() ||
3123 bSize.IsMaxContent() || bSize.IsFitContentFunction();
3126 * Helper method to create a view for a frame. Only used by a few sub-classes
3127 * that need a view.
3129 void CreateView();
3131 protected:
3132 virtual nsView* GetViewInternal() const {
3133 MOZ_ASSERT_UNREACHABLE("method should have been overridden by subclass");
3134 return nullptr;
3136 virtual void SetViewInternal(nsView* aView) {
3137 MOZ_ASSERT_UNREACHABLE("method should have been overridden by subclass");
3140 public:
3141 nsView* GetView() const {
3142 if (MOZ_LIKELY(!HasView())) {
3143 return nullptr;
3145 nsView* view = GetViewInternal();
3146 MOZ_ASSERT(view, "GetViewInternal() should agree with HasView()");
3147 return view;
3149 void SetView(nsView* aView);
3152 * Find the closest view (on |this| or an ancestor).
3153 * If aOffset is non-null, it will be set to the offset of |this|
3154 * from the returned view.
3156 nsView* GetClosestView(nsPoint* aOffset = nullptr) const;
3159 * Find the closest ancestor (excluding |this| !) that has a view
3161 nsIFrame* GetAncestorWithView() const;
3164 * Sets the view's attributes from the frame style.
3165 * Call this for nsChangeHint_SyncFrameView style changes or when the view
3166 * has just been created.
3167 * @param aView the frame's view or use GetView() if nullptr is given
3169 void SyncFrameViewProperties(nsView* aView = nullptr);
3172 * Get the offset between the coordinate systems of |this| and aOther.
3173 * Adding the return value to a point in the coordinate system of |this|
3174 * will transform the point to the coordinate system of aOther.
3176 * aOther must be non-null.
3178 * This function is fastest when aOther is an ancestor of |this|.
3180 * This function _DOES NOT_ work across document boundaries.
3181 * Use this function only when |this| and aOther are in the same document.
3183 * NOTE: this actually returns the offset from aOther to |this|, but
3184 * that offset is added to transform _coordinates_ from |this| to
3185 * aOther.
3187 nsPoint GetOffsetTo(const nsIFrame* aOther) const;
3190 * Just like GetOffsetTo, but treats all scrollframes as scrolled to
3191 * their origin.
3193 nsPoint GetOffsetToIgnoringScrolling(const nsIFrame* aOther) const;
3196 * Get the offset between the coordinate systems of |this| and aOther
3197 * expressed in appunits per dev pixel of |this|' document. Adding the return
3198 * value to a point that is relative to the origin of |this| will make the
3199 * point relative to the origin of aOther but in the appunits per dev pixel
3200 * ratio of |this|.
3202 * aOther must be non-null.
3204 * This function is fastest when aOther is an ancestor of |this|.
3206 * This function works across document boundaries.
3208 * Because this function may cross document boundaries that have different
3209 * app units per dev pixel ratios it needs to be used very carefully.
3211 * NOTE: this actually returns the offset from aOther to |this|, but
3212 * that offset is added to transform _coordinates_ from |this| to
3213 * aOther.
3215 nsPoint GetOffsetToCrossDoc(const nsIFrame* aOther) const;
3218 * Like GetOffsetToCrossDoc, but the caller can specify which appunits
3219 * to return the result in.
3221 nsPoint GetOffsetToCrossDoc(const nsIFrame* aOther, const int32_t aAPD) const;
3224 * Get the rect of the frame relative to the top-left corner of the
3225 * screen in CSS pixels.
3226 * @return the CSS pixel rect of the frame relative to the top-left
3227 * corner of the screen.
3229 mozilla::CSSIntRect GetScreenRect() const;
3232 * Get the screen rect of the frame in app units.
3233 * @return the app unit rect of the frame in screen coordinates.
3235 nsRect GetScreenRectInAppUnits() const;
3238 * Returns the offset from this frame to the closest geometric parent that
3239 * has a view. Also returns the containing view or null in case of error
3241 void GetOffsetFromView(nsPoint& aOffset, nsView** aView) const;
3244 * Returns the nearest widget containing this frame. If this frame has a
3245 * view and the view has a widget, then this frame's widget is
3246 * returned, otherwise this frame's geometric parent is checked
3247 * recursively upwards.
3249 nsIWidget* GetNearestWidget() const;
3252 * Whether the frame is a subgrid right now.
3254 bool IsSubgrid() const;
3257 * Same as GetNearestWidget() above but uses an outparam to return the offset
3258 * of this frame to the returned widget expressed in appunits of |this| (the
3259 * widget might be in a different document with a different zoom).
3261 nsIWidget* GetNearestWidget(nsPoint& aOffset) const;
3264 * Whether the content for this frame is disabled, used for event handling.
3266 bool IsContentDisabled() const;
3268 enum class IncludeContentVisibility {
3269 Auto,
3270 Hidden,
3273 constexpr static mozilla::EnumSet<IncludeContentVisibility>
3274 IncludeAllContentVisibility() {
3275 return {IncludeContentVisibility::Auto, IncludeContentVisibility::Hidden};
3279 * Returns true if this frame's `content-visibility: auto` element is
3280 * considered relevant content.
3282 bool IsContentRelevant() const;
3285 * Whether this frame hides its contents via the `content-visibility`
3286 * property.
3287 * @param aInclude specifies what kind of `content-visibility` to include.
3289 bool HidesContent(const mozilla::EnumSet<IncludeContentVisibility>& =
3290 IncludeAllContentVisibility()) const;
3293 * Whether this frame hides its contents via the `content-visibility`
3294 * property, while doing layout. This might be true when `HidesContent()` is
3295 * true in the case that hidden content is being forced to lay out by position
3296 * or size queries from script.
3298 bool HidesContentForLayout() const;
3301 * returns the closest ancestor with `content-visibility` property.
3302 * @param aInclude specifies what kind of `content-visibility` to include.
3304 nsIFrame* GetClosestContentVisibilityAncestor(
3305 const mozilla::EnumSet<IncludeContentVisibility>& =
3306 IncludeAllContentVisibility()) const;
3309 * Returns true if this frame is entirely hidden due the `content-visibility`
3310 * property on an ancestor.
3311 * @param aInclude specifies what kind of `content-visibility` to include.
3313 bool IsHiddenByContentVisibilityOnAnyAncestor(
3314 const mozilla::EnumSet<IncludeContentVisibility>& =
3315 IncludeAllContentVisibility()) const;
3318 * Returns true is this frame is hidden by its first unskipped in flow
3319 * ancestor due to `content-visibility`.
3321 bool IsHiddenByContentVisibilityOfInFlowParentForLayout() const;
3324 * Returns true if this frame has a SelectionType::eNormal type selection in
3325 * somewhere in its subtree of frames. This is used to determine content
3326 * relevancy for `content-visibility: auto`.
3328 bool HasSelectionInSubtree();
3331 * Update the whether or not this frame is considered relevant content for the
3332 * purposes of `content-visibility: auto` according to the rules specified in
3333 * https://drafts.csswg.org/css-contain-2/#relevant-to-the-user.
3334 * Returns true if the over-all relevancy changed.
3336 bool UpdateIsRelevantContent(const ContentRelevancy& aRelevancyToUpdate);
3339 * Get the "type" of the frame.
3341 * @see mozilla::LayoutFrameType
3343 mozilla::LayoutFrameType Type() const {
3344 MOZ_ASSERT(uint8_t(mClass) < mozilla::ArrayLength(sLayoutFrameTypes));
3345 return sLayoutFrameTypes[uint8_t(mClass)];
3349 * Get the type flags of the frame.
3351 * @see mozilla::LayoutFrameType
3353 ClassFlags GetClassFlags() const {
3354 MOZ_ASSERT(uint8_t(mClass) < mozilla::ArrayLength(sLayoutFrameClassFlags));
3355 return sLayoutFrameClassFlags[uint8_t(mClass)];
3358 bool HasAnyClassFlag(ClassFlags aFlag) const {
3359 return bool(GetClassFlags() & aFlag);
3363 * Is this a leaf frame? Frames that want the frame constructor to be able to
3364 * construct kids for them should return false, all others should return true.
3366 * Note that returning true here does not mean that the frame _can't_ have
3367 * kids. It could still have kids created via nsIAnonymousContentCreator.
3369 * Returning true indicates that "normal" (non-anonymous, CSS generated
3370 * content, etc) children should not be constructed.
3372 bool IsLeaf() const {
3373 auto bits = GetClassFlags();
3374 if (MOZ_UNLIKELY(bits & ClassFlags::LeafDynamic)) {
3375 return IsLeafDynamic();
3377 return bool(bits & ClassFlags::Leaf);
3379 virtual bool IsLeafDynamic() const { return false; }
3381 #define CLASS_FLAG_METHOD(name_, flag_) \
3382 bool name_() const { return HasAnyClassFlag(ClassFlags::flag_); }
3383 #define CLASS_FLAG_METHOD0(name_) CLASS_FLAG_METHOD(name_, name_)
3385 CLASS_FLAG_METHOD(IsMathMLFrame, MathML);
3386 CLASS_FLAG_METHOD(IsSVGFrame, SVG);
3387 CLASS_FLAG_METHOD(IsSVGContainerFrame, SVGContainer);
3388 CLASS_FLAG_METHOD(IsBidiInlineContainer, BidiInlineContainer);
3389 CLASS_FLAG_METHOD(IsLineParticipant, LineParticipant);
3390 CLASS_FLAG_METHOD(IsReplaced, Replaced);
3391 CLASS_FLAG_METHOD(IsReplacedWithBlock, ReplacedContainsBlock);
3392 CLASS_FLAG_METHOD(HasReplacedSizing, ReplacedSizing);
3393 CLASS_FLAG_METHOD(IsTablePart, TablePart);
3394 CLASS_FLAG_METHOD0(CanContainOverflowContainers)
3395 CLASS_FLAG_METHOD0(SupportsCSSTransforms);
3396 CLASS_FLAG_METHOD0(SupportsContainLayoutAndPaint)
3397 CLASS_FLAG_METHOD0(SupportsAspectRatio)
3399 #undef CLASS_FLAG_METHOD
3400 #undef CLASS_FLAG_METHOD0
3402 #ifdef __GNUC__
3403 # pragma GCC diagnostic push
3404 # pragma GCC diagnostic ignored "-Wtype-limits"
3405 #endif
3406 #ifdef __clang__
3407 # pragma clang diagnostic push
3408 # pragma clang diagnostic ignored "-Wunknown-pragmas"
3409 # pragma clang diagnostic ignored "-Wtautological-unsigned-zero-compare"
3410 #endif
3412 #define FRAME_TYPE(name_, first_class_, last_class_) \
3413 bool Is##name_##Frame() const { \
3414 return uint8_t(mClass) >= uint8_t(ClassID::first_class_##_id) && \
3415 uint8_t(mClass) <= uint8_t(ClassID::last_class_##_id); \
3417 #include "mozilla/FrameTypeList.h"
3418 #undef FRAME_TYPE
3420 #ifdef __GNUC__
3421 # pragma GCC diagnostic pop
3422 #endif
3423 #ifdef __clang__
3424 # pragma clang diagnostic pop
3425 #endif
3428 * Returns a transformation matrix that converts points in this frame's
3429 * coordinate space to points in some ancestor frame's coordinate space.
3430 * The frame decides which ancestor it will use as a reference point.
3431 * If this frame has no ancestor, aOutAncestor will be set to null.
3433 * @param aViewportType specifies whether the starting point is layout
3434 * or visual coordinates
3435 * @param aStopAtAncestor don't look further than aStopAtAncestor. If null,
3436 * all ancestors (including across documents) will be traversed.
3437 * @param aOutAncestor [out] The ancestor frame the frame has chosen. If
3438 * this frame has no ancestor, *aOutAncestor will be set to null. If
3439 * this frame is not a root frame, then *aOutAncestor will be in the same
3440 * document as this frame. If this frame IsTransformed(), then *aOutAncestor
3441 * will be the parent frame (if not preserve-3d) or the nearest
3442 * non-transformed ancestor (if preserve-3d).
3443 * @return A Matrix4x4 that converts points in the coordinate space
3444 * RelativeTo{this, aViewportType} into points in aOutAncestor's
3445 * coordinate space.
3447 enum {
3448 IN_CSS_UNITS = 1 << 0,
3449 STOP_AT_STACKING_CONTEXT_AND_DISPLAY_PORT = 1 << 1
3451 Matrix4x4Flagged GetTransformMatrix(mozilla::ViewportType aViewportType,
3452 mozilla::RelativeTo aStopAtAncestor,
3453 nsIFrame** aOutAncestor,
3454 uint32_t aFlags = 0) const;
3457 * Return true if this frame's preferred size property or max size property
3458 * contains a percentage value that should be resolved against zero when
3459 * calculating its min-content contribution in the corresponding axis.
3461 * This is a special case for webcompat required by CSS Sizing 3 §5.2.1c
3462 * https://drafts.csswg.org/css-sizing-3/#replaced-percentage-min-contribution,
3463 * and applies only to some replaced elements and form control elements. See
3464 * CSS Sizing 3 §5.2.2 for the list of elements this rule applies to.
3465 * https://drafts.csswg.org/css-sizing-3/#min-content-zero
3467 * Bug 1463700: some callers may not match the spec by resolving the entire
3468 * preferred size property or max size property against zero.
3470 bool IsPercentageResolvedAgainstZero(
3471 const mozilla::StyleSize& aStyleSize,
3472 const mozilla::StyleMaxSize& aStyleMaxSize) const;
3474 // Type of preferred size/min size/max size.
3475 enum class SizeProperty { Size, MinSize, MaxSize };
3477 * This is simliar to the above method but accepts LengthPercentage. Return
3478 * true if the frame's preferred size property or max size property contains
3479 * a percentage value that should be resolved against zero. For min size, it
3480 * always returns true.
3482 bool IsPercentageResolvedAgainstZero(const mozilla::LengthPercentage& aSize,
3483 SizeProperty aProperty) const;
3486 * Returns true if the frame is a block wrapper.
3488 bool IsBlockWrapper() const;
3491 * Returns true if the frame is an instance of nsBlockFrame or one of its
3492 * subclasses.
3494 bool IsBlockFrameOrSubclass() const;
3497 * Returns true if the frame is an instance of nsImageFrame or one of its
3498 * subclasses.
3500 bool IsImageFrameOrSubclass() const;
3503 * Get this frame's CSS containing block.
3505 * The algorithm is defined in
3506 * http://www.w3.org/TR/CSS2/visudet.html#containing-block-details.
3508 * NOTE: This is guaranteed to return a non-null pointer when invoked on any
3509 * frame other than the root frame.
3511 * Requires SKIP_SCROLLED_FRAME to get behaviour matching the spec, otherwise
3512 * it can return anonymous inner scrolled frames. Bug 1204044 is filed for
3513 * investigating whether any of the callers actually require the default
3514 * behaviour.
3516 enum {
3517 // If the containing block is an anonymous scrolled frame, then skip over
3518 // this and return the outer scroll frame.
3519 SKIP_SCROLLED_FRAME = 0x01
3521 nsIFrame* GetContainingBlock(uint32_t aFlags,
3522 const nsStyleDisplay* aStyleDisplay) const;
3523 nsIFrame* GetContainingBlock(uint32_t aFlags = 0) const {
3524 return GetContainingBlock(aFlags, StyleDisplay());
3528 * If this frame can be a block container, i.e. whether it can serve as a
3529 * containing block for its descendants. See also GetNearestBlockContainer()
3530 * and GetContainingBlock().
3532 bool IsBlockContainer() const;
3535 * Is this frame a containing block for floating elements?
3536 * Note that very few frames are, so default to false.
3538 virtual bool IsFloatContainingBlock() const { return false; }
3541 * Marks all display items created by this frame as needing a repaint,
3542 * and calls SchedulePaint() if requested and one is not already pending.
3544 * This includes all display items created by this frame, including
3545 * container types.
3547 * @param aDisplayItemKey If specified, only issues an invalidate
3548 * if this frame painted a display item of that type during the
3549 * previous paint. SVG rendering observers are always notified.
3550 * @param aRebuildDisplayItems If true, then adds this frame to the
3551 * list of modified frames for display list building. Only pass false
3552 * if you're sure that the relevant display items will be rebuilt
3553 * already (possibly by an ancestor being in the modified list).
3555 virtual void InvalidateFrame(uint32_t aDisplayItemKey = 0,
3556 bool aRebuildDisplayItems = true);
3559 * Same as InvalidateFrame(), but only mark a fixed rect as needing
3560 * repainting.
3562 * @param aRect The rect to invalidate, relative to the TopLeft of the
3563 * frame's border box.
3564 * @param aDisplayItemKey If specified, only issues an invalidate
3565 * if this frame painted a display item of that type during the
3566 * previous paint. SVG rendering observers are always notified.
3567 * @param aRebuildDisplayItems If true, then adds this frame to the
3568 * list of modified frames for display list building. Only pass false
3569 * if you're sure that the relevant display items will be rebuilt
3570 * already (possibly by an ancestor being in the modified list).
3572 virtual void InvalidateFrameWithRect(const nsRect& aRect,
3573 uint32_t aDisplayItemKey = 0,
3574 bool aRebuildDisplayItems = true);
3577 * Calls InvalidateFrame() on all frames descendant frames (including
3578 * this one).
3580 * This function doesn't walk through placeholder frames to invalidate
3581 * the out-of-flow frames.
3583 * @param aRebuildDisplayItems If true, then adds this frame to the
3584 * list of modified frames for display list building. Only pass false
3585 * if you're sure that the relevant display items will be rebuilt
3586 * already (possibly by an ancestor being in the modified list).
3588 void InvalidateFrameSubtree(bool aRebuildDisplayItems = true);
3591 * Called when a frame is about to be removed and needs to be invalidated.
3592 * Normally does nothing since DLBI handles removed frames.
3594 virtual void InvalidateFrameForRemoval() {}
3597 * When HasUserData(frame->LayerIsPrerenderedDataKey()), then the
3598 * entire overflow area of this frame has been rendered in its
3599 * layer(s).
3601 static void* LayerIsPrerenderedDataKey() {
3602 return &sLayerIsPrerenderedDataKey;
3604 static uint8_t sLayerIsPrerenderedDataKey;
3607 * Checks if a frame has had InvalidateFrame() called on it since the
3608 * last paint.
3610 * If true, then the invalid rect is returned in aRect, with an
3611 * empty rect meaning all pixels drawn by this frame should be
3612 * invalidated.
3613 * If false, aRect is left unchanged.
3615 bool IsInvalid(nsRect& aRect);
3618 * Check if any frame within the frame subtree (including this frame)
3619 * returns true for IsInvalid().
3621 bool HasInvalidFrameInSubtree() {
3622 return HasAnyStateBits(NS_FRAME_NEEDS_PAINT |
3623 NS_FRAME_DESCENDANT_NEEDS_PAINT);
3627 * Removes the invalid state from the current frame and all
3628 * descendant frames.
3630 void ClearInvalidationStateBits();
3633 * Ensures that the refresh driver is running, and schedules a view
3634 * manager flush on the next tick.
3636 * The view manager flush will update the layer tree, repaint any
3637 * invalid areas in the layer tree and schedule a layer tree
3638 * composite operation to display the layer tree.
3640 * In general it is not necessary for frames to call this when they change.
3641 * For example, changes that result in a reflow will have this called for
3642 * them by PresContext::DoReflow when the reflow begins. Style changes that
3643 * do not trigger a reflow should have this called for them by
3644 * DoApplyRenderingChangeToTree.
3646 * @param aType PAINT_COMPOSITE_ONLY : No changes have been made
3647 * that require a layer tree update, so only schedule a layer
3648 * tree composite.
3650 enum PaintType { PAINT_DEFAULT = 0, PAINT_COMPOSITE_ONLY };
3651 void SchedulePaint(PaintType aType = PAINT_DEFAULT,
3652 bool aFrameChanged = true);
3654 // Similar to SchedulePaint() but without calling
3655 // InvalidateRenderingObservers() for SVG.
3656 void SchedulePaintWithoutInvalidatingObservers(
3657 PaintType aType = PAINT_DEFAULT);
3660 * Checks if the layer tree includes a dedicated layer for this
3661 * frame/display item key pair, and invalidates at least aDamageRect
3662 * area within that layer.
3664 * If no layer is found, calls InvalidateFrame() instead.
3666 * @param aDamageRect Area of the layer to invalidate.
3667 * @param aFrameDamageRect If no layer is found, the area of the frame to
3668 * invalidate. If null, the entire frame will be
3669 * invalidated.
3670 * @param aDisplayItemKey Display item type.
3671 * @param aFlags UPDATE_IS_ASYNC : Will skip the invalidation
3672 * if the found layer is being composited by a remote
3673 * compositor.
3674 * @return Layer, if found, nullptr otherwise.
3676 enum { UPDATE_IS_ASYNC = 1 << 0 };
3677 void InvalidateLayer(DisplayItemType aDisplayItemKey,
3678 const nsIntRect* aDamageRect = nullptr,
3679 const nsRect* aFrameDamageRect = nullptr,
3680 uint32_t aFlags = 0);
3682 void MarkNeedsDisplayItemRebuild();
3685 * Returns a rect that encompasses everything that might be painted by
3686 * this frame. This includes this frame, all its descendant frames, this
3687 * frame's outline, and descendant frames' outline, but does not include
3688 * areas clipped out by the CSS "overflow" and "clip" properties.
3690 * HasOverflowAreas() (below) will return true when this overflow
3691 * rect has been explicitly set, even if it matches mRect.
3692 * XXX Note: because of a space optimization using the formula above,
3693 * during reflow this function does not give accurate data if
3694 * FinishAndStoreOverflow has been called but mRect hasn't yet been
3695 * updated yet. FIXME: This actually isn't true, but it should be.
3697 * The ink overflow rect should NEVER be used for things that
3698 * affect layout. The scrollable overflow rect is permitted to affect
3699 * layout.
3701 * @return the rect relative to this frame's origin, but after
3702 * CSS transforms have been applied (i.e. not really this frame's coordinate
3703 * system, and may not contain the frame's border-box, e.g. if there
3704 * is a CSS transform scaling it down)
3706 nsRect InkOverflowRect() const {
3707 return GetOverflowRect(mozilla::OverflowType::Ink);
3711 * Returns a rect that encompasses the area of this frame that the
3712 * user should be able to scroll to reach. This is similar to
3713 * InkOverflowRect, but does not include outline or shadows, and
3714 * may in the future include more margins than ink overflow does.
3715 * It does not include areas clipped out by the CSS "overflow" and
3716 * "clip" properties.
3718 * HasOverflowAreas() (below) will return true when this overflow
3719 * rect has been explicitly set, even if it matches mRect.
3720 * XXX Note: because of a space optimization using the formula above,
3721 * during reflow this function does not give accurate data if
3722 * FinishAndStoreOverflow has been called but mRect hasn't yet been
3723 * updated yet.
3725 * @return the rect relative to this frame's origin, but after
3726 * CSS transforms have been applied (i.e. not really this frame's coordinate
3727 * system, and may not contain the frame's border-box, e.g. if there
3728 * is a CSS transform scaling it down)
3730 nsRect ScrollableOverflowRect() const {
3731 return GetOverflowRect(mozilla::OverflowType::Scrollable);
3734 mozilla::OverflowAreas GetOverflowAreas() const;
3737 * Same as GetOverflowAreas, except in this frame's coordinate
3738 * system (before transforms are applied).
3740 * @return the overflow areas relative to this frame, before any CSS
3741 * transforms have been applied, i.e. in this frame's coordinate system
3743 mozilla::OverflowAreas GetOverflowAreasRelativeToSelf() const;
3746 * Same as GetOverflowAreas, except relative to the parent frame.
3748 * @return the overflow area relative to the parent frame, in the parent
3749 * frame's coordinate system
3751 mozilla::OverflowAreas GetOverflowAreasRelativeToParent() const;
3754 * Same as GetOverflowAreasRelativeToParent(), except that it also unions in
3755 * the normal position overflow area if this frame is relatively or sticky
3756 * positioned.
3758 * @return the overflow area relative to the parent frame, in the parent
3759 * frame's coordinate system
3761 mozilla::OverflowAreas GetActualAndNormalOverflowAreasRelativeToParent()
3762 const;
3765 * Same as ScrollableOverflowRect, except relative to the parent
3766 * frame.
3768 * @return the rect relative to the parent frame, in the parent frame's
3769 * coordinate system
3771 nsRect ScrollableOverflowRectRelativeToParent() const;
3774 * Same as ScrollableOverflowRect, except in this frame's coordinate
3775 * system (before transforms are applied).
3777 * @return the rect relative to this frame, before any CSS transforms have
3778 * been applied, i.e. in this frame's coordinate system
3780 nsRect ScrollableOverflowRectRelativeToSelf() const;
3783 * Like InkOverflowRect, except in this frame's
3784 * coordinate system (before transforms are applied).
3786 * @return the rect relative to this frame, before any CSS transforms have
3787 * been applied, i.e. in this frame's coordinate system
3789 nsRect InkOverflowRectRelativeToSelf() const;
3792 * Same as InkOverflowRect, except relative to the parent
3793 * frame.
3795 * @return the rect relative to the parent frame, in the parent frame's
3796 * coordinate system
3798 nsRect InkOverflowRectRelativeToParent() const;
3801 * Returns this frame's ink overflow rect as it would be before taking
3802 * account of SVG effects or transforms. The rect returned is relative to
3803 * this frame.
3805 nsRect PreEffectsInkOverflowRect() const;
3808 * Store the overflow area in the frame's mOverflow.mInkOverflowDeltas
3809 * fields or as a frame property in OverflowAreasProperty() so that it can
3810 * be retrieved later without reflowing the frame. Returns true if either of
3811 * the overflow areas changed.
3813 bool FinishAndStoreOverflow(mozilla::OverflowAreas& aOverflowAreas,
3814 nsSize aNewSize, nsSize* aOldSize = nullptr,
3815 const nsStyleDisplay* aStyleDisplay = nullptr);
3817 bool FinishAndStoreOverflow(ReflowOutput* aMetrics,
3818 const nsStyleDisplay* aStyleDisplay = nullptr) {
3819 return FinishAndStoreOverflow(aMetrics->mOverflowAreas,
3820 nsSize(aMetrics->Width(), aMetrics->Height()),
3821 nullptr, aStyleDisplay);
3825 * Returns whether the frame has an overflow rect that is different from
3826 * its border-box.
3828 bool HasOverflowAreas() const {
3829 return mOverflow.mType != OverflowStorageType::None;
3833 * Removes any stored overflow rects (visual and scrollable) from the frame.
3834 * Returns true if the overflow changed.
3836 bool ClearOverflowRects();
3839 * Determine whether borders, padding, margins etc should NOT be applied
3840 * on certain sides of the frame.
3841 * @see mozilla::Sides in gfx/2d/BaseMargin.h
3842 * @see mozilla::LogicalSides in layout/generic/WritingModes.h
3844 * @note (See also bug 743402, comment 11) GetSkipSides() checks to see
3845 * if this frame has a previous or next continuation to determine
3846 * if a side should be skipped.
3847 * So this only works after the entire frame tree has been reflowed.
3848 * During reflow, if this frame can be split in the block axis, you
3849 * should use nsSplittableFrame::PreReflowBlockLevelLogicalSkipSides().
3851 Sides GetSkipSides() const;
3852 virtual LogicalSides GetLogicalSkipSides() const {
3853 return LogicalSides(mWritingMode);
3857 * @returns true if this frame is selected.
3859 bool IsSelected() const {
3860 return (GetContent() && GetContent()->IsMaybeSelected()) ? IsFrameSelected()
3861 : false;
3865 * Shouldn't be called if this is a `nsTextFrame`. Call the
3866 * `nsTextFrame::SelectionStateChanged` overload instead.
3868 void SelectionStateChanged() {
3869 MOZ_ASSERT(!IsTextFrame());
3870 InvalidateFrameSubtree(); // TODO: should this deal with continuations?
3874 * Called to discover where this frame, or a parent frame has user-select
3875 * style applied, which affects that way that it is selected.
3877 * @param aSelectStyle out param. Returns the type of selection style found
3878 * (using values defined in nsStyleConsts.h).
3880 * @return Whether the frame can be selected (i.e. is not affected by
3881 * user-select: none)
3883 bool IsSelectable(mozilla::StyleUserSelect* aSelectStyle) const;
3886 * Returns whether this frame should have the content-block-size of a line,
3887 * even if empty.
3889 bool ShouldHaveLineIfEmpty() const;
3892 * Called to retrieve the SelectionController associated with the frame.
3894 * @param aSelCon will contain the selection controller associated with
3895 * the frame.
3897 nsresult GetSelectionController(nsPresContext* aPresContext,
3898 nsISelectionController** aSelCon);
3901 * Call to get nsFrameSelection for this frame.
3903 already_AddRefed<nsFrameSelection> GetFrameSelection();
3906 * GetConstFrameSelection returns an object which methods are safe to use for
3907 * example in nsIFrame code.
3909 const nsFrameSelection* GetConstFrameSelection() const;
3912 * called to find the previous/next character, word, or line. Returns the
3913 * actual nsIFrame and the frame offset. THIS DOES NOT CHANGE SELECTION STATE.
3914 * Uses frame's begin selection state to start. If no selection on this frame
3915 * will return NS_ERROR_FAILURE.
3917 * @param aPos is defined in nsFrameSelection
3919 virtual nsresult PeekOffset(mozilla::PeekOffsetStruct* aPos);
3921 private:
3922 nsresult PeekOffsetForCharacter(mozilla::PeekOffsetStruct* aPos,
3923 int32_t aOffset);
3924 nsresult PeekOffsetForWord(mozilla::PeekOffsetStruct* aPos, int32_t aOffset);
3925 nsresult PeekOffsetForLine(mozilla::PeekOffsetStruct* aPos);
3926 nsresult PeekOffsetForLineEdge(mozilla::PeekOffsetStruct* aPos);
3929 * Search for the first paragraph boundary before or after the given position
3930 * @param aPos See description in nsFrameSelection.h. The following fields
3931 * are used by this method:
3932 * Input: mDirection
3933 * Output: mResultContent, mContentOffset
3935 nsresult PeekOffsetForParagraph(mozilla::PeekOffsetStruct* aPos);
3937 public:
3938 // given a frame five me the first/last leaf available
3939 // XXX Robert O'Callahan wants to move these elsewhere
3940 // FIXME: Only GetLastLeaf() never returns a leaf frame in native anonymous
3941 // subtrees under aFrame. However, GetFirstLeaf() may return a leaf frame
3942 // in a native anonymous subtree.
3943 static void GetLastLeaf(nsIFrame** aFrame);
3944 static void GetFirstLeaf(nsIFrame** aFrame);
3946 struct SelectablePeekReport {
3947 /** the previous/next selectable leaf frame */
3948 nsIFrame* mFrame = nullptr;
3950 * 0 indicates that we arrived at the beginning of the output frame; -1
3951 * indicates that we arrived at its end.
3953 int32_t mOffset = 0;
3954 /** whether the input frame and the returned frame are on different lines */
3955 bool mJumpedLine = false;
3956 /** whether we met a hard break between the input and the returned frame */
3957 bool mJumpedHardBreak = false;
3958 /** whether we met a child placeholder frame */
3959 bool mFoundPlaceholder = false;
3960 /** whether we jumped over a non-selectable frame during the search */
3961 bool mMovedOverNonSelectableText = false;
3962 /** whether we met selectable text frame that isn't editable during the
3963 * search */
3964 bool mHasSelectableFrame = false;
3965 /** whether we ignored a br frame */
3966 bool mIgnoredBrFrame = false;
3968 FrameSearchResult PeekOffsetNoAmount(bool aForward) {
3969 return mFrame->PeekOffsetNoAmount(aForward, &mOffset);
3971 FrameSearchResult PeekOffsetCharacter(bool aForward,
3972 PeekOffsetCharacterOptions aOptions) {
3973 return mFrame->PeekOffsetCharacter(aForward, &mOffset, aOptions);
3976 /** Transfers frame and offset info for PeekOffset() result */
3977 void TransferTo(mozilla::PeekOffsetStruct& aPos) const;
3978 bool Failed() { return !mFrame; }
3980 explicit SelectablePeekReport(nsIFrame* aFrame = nullptr,
3981 int32_t aOffset = 0)
3982 : mFrame(aFrame), mOffset(aOffset) {}
3983 MOZ_IMPLICIT SelectablePeekReport(
3984 const mozilla::GenericErrorResult<nsresult>&& aErr);
3988 * Called to find the previous/next non-anonymous selectable leaf frame.
3990 * @param aDirection the direction to move in (eDirPrevious or eDirNext)
3991 * @param aOptions the other options which is same as
3992 * PeekOffsetStruct::mOptions.
3993 * FIXME: Due to the include hell, we cannot use the alias, PeekOffsetOptions
3994 * is not available in this header file.
3996 SelectablePeekReport GetFrameFromDirection(
3997 nsDirection aDirection,
3998 const mozilla::EnumSet<mozilla::PeekOffsetOption>& aOptions);
3999 SelectablePeekReport GetFrameFromDirection(
4000 const mozilla::PeekOffsetStruct& aPos);
4003 * Return:
4004 * (1) the containing block frame for a line; i.e. the frame which
4005 * supports a line iterator, or null if none can be found; and
4006 * (2) the frame to use to get a line number, which will be direct child of
4007 * the returned containing block.
4008 * @param aLockScroll true to avoid breaking outside scrollframes.
4010 std::pair<nsIFrame*, nsIFrame*> GetContainingBlockForLine(
4011 bool aLockScroll) const;
4013 private:
4014 Result<bool, nsresult> IsVisuallyAtLineEdge(nsILineIterator* aLineIterator,
4015 int32_t aLine,
4016 nsDirection aDirection);
4017 Result<bool, nsresult> IsLogicallyAtLineEdge(nsILineIterator* aLineIterator,
4018 int32_t aLine,
4019 nsDirection aDirection);
4021 public:
4023 * Called to tell a frame that one of its child frames is dirty (i.e.,
4024 * has the NS_FRAME_IS_DIRTY *or* NS_FRAME_HAS_DIRTY_CHILDREN bit
4025 * set). This should always set the NS_FRAME_HAS_DIRTY_CHILDREN on
4026 * the frame, and may do other work.
4028 virtual void ChildIsDirty(nsIFrame* aChild);
4031 * Called to retrieve this frame's accessible.
4032 * If this frame implements Accessibility return a valid accessible
4033 * If not return NS_ERROR_NOT_IMPLEMENTED.
4034 * Note: LocalAccessible must be refcountable. Do not implement directly on
4035 * your frame Use a mediatior of some kind.
4037 #ifdef ACCESSIBILITY
4038 virtual mozilla::a11y::AccType AccessibleType();
4039 #endif
4042 * Get the frame whose style should be the parent of this frame's style (i.e.,
4043 * provide the parent style).
4045 * This frame must either be an ancestor of this frame or a child. If
4046 * this returns a child frame, then the child frame must be sure to
4047 * return a grandparent or higher! Furthermore, if a child frame is
4048 * returned it must have the same GetContent() as this frame.
4050 * @param aProviderFrame (out) the frame associated with the returned value
4051 * or nullptr if the style is for display:contents content.
4052 * @return The style that should be the parent of this frame's style. Null is
4053 * permitted, and means that this frame's style should be the root of
4054 * the style tree.
4056 virtual ComputedStyle* GetParentComputedStyle(
4057 nsIFrame** aProviderFrame) const {
4058 return DoGetParentComputedStyle(aProviderFrame);
4062 * Do the work for getting the parent ComputedStyle frame so that
4063 * other frame's |GetParentComputedStyle| methods can call this
4064 * method on *another* frame. (This function handles out-of-flow
4065 * frames by using the frame manager's placeholder map and it also
4066 * handles block-within-inline and generated content wrappers.)
4068 * @param aProviderFrame (out) the frame associated with the returned value
4069 * or null if the ComputedStyle is for display:contents content.
4070 * @return The ComputedStyle that should be the parent of this frame's
4071 * ComputedStyle. Null is permitted, and means that this frame's
4072 * ComputedStyle should be the root of the ComputedStyle tree.
4074 ComputedStyle* DoGetParentComputedStyle(nsIFrame** aProviderFrame) const;
4077 * Adjust the given parent frame to the right ComputedStyle parent frame for
4078 * the child, given the pseudo-type of the prospective child. This handles
4079 * things like walking out of table pseudos and so forth.
4081 * @param aProspectiveParent what GetParent() on the child returns.
4082 * Must not be null.
4083 * @param aChildPseudo the child's pseudo type, if any.
4085 static nsIFrame* CorrectStyleParentFrame(
4086 nsIFrame* aProspectiveParent, mozilla::PseudoStyleType aChildPseudo);
4089 * Called by RestyleManager to update the style of anonymous boxes
4090 * directly associated with this frame.
4092 * The passed-in ServoRestyleState can be used to create new ComputedStyles as
4093 * needed, as well as posting changes to the change list.
4095 * It's guaranteed to already have a change in it for this frame and this
4096 * frame's content.
4098 * This function will be called after this frame's style has already been
4099 * updated. This function will only be called on frames which have the
4100 * NS_FRAME_OWNS_ANON_BOXES bit set.
4102 void UpdateStyleOfOwnedAnonBoxes(mozilla::ServoRestyleState& aRestyleState) {
4103 if (HasAnyStateBits(NS_FRAME_OWNS_ANON_BOXES)) {
4104 DoUpdateStyleOfOwnedAnonBoxes(aRestyleState);
4108 mozilla::ContainSizeAxes GetContainSizeAxes() const {
4109 return StyleDisplay()->GetContainSizeAxes(*this);
4112 // Common steps to all replaced elements given an unconstrained intrinsic
4113 // size.
4114 mozilla::IntrinsicSize FinishIntrinsicSize(
4115 const mozilla::ContainSizeAxes& aAxes,
4116 const mozilla::IntrinsicSize& aUncontainedSize) const {
4117 auto result = aAxes.ContainIntrinsicSize(aUncontainedSize, *this);
4118 result.Zoom(Style()->EffectiveZoom());
4119 return result;
4122 Maybe<nscoord> ContainIntrinsicBSize(nscoord aNoneValue = 0) const {
4123 return GetContainSizeAxes().ContainIntrinsicBSize(*this, aNoneValue);
4126 Maybe<nscoord> ContainIntrinsicISize(nscoord aNoneValue = 0) const {
4127 return GetContainSizeAxes().ContainIntrinsicISize(*this, aNoneValue);
4130 protected:
4131 // This does the actual work of UpdateStyleOfOwnedAnonBoxes. It calls
4132 // AppendDirectlyOwnedAnonBoxes to find all of the anonymous boxes
4133 // owned by this frame, and then updates styles on each of them.
4134 void DoUpdateStyleOfOwnedAnonBoxes(mozilla::ServoRestyleState& aRestyleState);
4136 // A helper for DoUpdateStyleOfOwnedAnonBoxes for the specific case
4137 // of the owned anon box being a child of this frame.
4138 void UpdateStyleOfChildAnonBox(nsIFrame* aChildFrame,
4139 mozilla::ServoRestyleState& aRestyleState);
4141 // Allow ServoRestyleState to call UpdateStyleOfChildAnonBox.
4142 friend class mozilla::ServoRestyleState;
4144 public:
4145 // A helper both for UpdateStyleOfChildAnonBox, and to update frame-backed
4146 // pseudo-elements in RestyleManager.
4148 // This gets a ComputedStyle that will be the new style for `aChildFrame`, and
4149 // takes care of updating it, calling CalcStyleDifference, and adding to the
4150 // change list as appropriate.
4152 // If aContinuationComputedStyle is not Nothing, it should be used for
4153 // continuations instead of aNewComputedStyle. In either case, changehints
4154 // are only computed based on aNewComputedStyle.
4156 // Returns the generated change hint for the frame.
4157 static nsChangeHint UpdateStyleOfOwnedChildFrame(
4158 nsIFrame* aChildFrame, ComputedStyle* aNewComputedStyle,
4159 mozilla::ServoRestyleState& aRestyleState,
4160 const Maybe<ComputedStyle*>& aContinuationComputedStyle = Nothing());
4162 struct OwnedAnonBox {
4163 typedef void (*UpdateStyleFn)(nsIFrame* aOwningFrame, nsIFrame* aAnonBox,
4164 mozilla::ServoRestyleState& aRestyleState);
4166 explicit OwnedAnonBox(nsIFrame* aAnonBoxFrame,
4167 UpdateStyleFn aUpdateStyleFn = nullptr)
4168 : mAnonBoxFrame(aAnonBoxFrame), mUpdateStyleFn(aUpdateStyleFn) {}
4170 nsIFrame* mAnonBoxFrame;
4171 UpdateStyleFn mUpdateStyleFn;
4175 * Appends information about all of the anonymous boxes owned by this frame,
4176 * including other anonymous boxes owned by those which this frame owns
4177 * directly.
4179 void AppendOwnedAnonBoxes(nsTArray<OwnedAnonBox>& aResult) {
4180 if (HasAnyStateBits(NS_FRAME_OWNS_ANON_BOXES)) {
4181 if (IsInlineFrame()) {
4182 // See comment in nsIFrame::DoUpdateStyleOfOwnedAnonBoxes for why
4183 // we skip nsInlineFrames.
4184 return;
4186 DoAppendOwnedAnonBoxes(aResult);
4190 protected:
4191 // This does the actual work of AppendOwnedAnonBoxes.
4192 void DoAppendOwnedAnonBoxes(nsTArray<OwnedAnonBox>& aResult);
4194 public:
4196 * Hook subclasses can override to return their owned anonymous boxes.
4198 * This function only appends anonymous boxes that are directly owned by
4199 * this frame, i.e. direct children or (for certain frames) a wrapper
4200 * parent, unlike AppendOwnedAnonBoxes, which will append all anonymous
4201 * boxes transitively owned by this frame.
4203 virtual void AppendDirectlyOwnedAnonBoxes(nsTArray<OwnedAnonBox>& aResult);
4206 * Determines whether a frame is visible for painting;
4207 * taking into account whether it is painting a selection or printing.
4209 bool IsVisibleForPainting() const;
4211 * Determines whether a frame is visible for painting or collapsed;
4212 * taking into account whether it is painting a selection or printing,
4214 bool IsVisibleOrCollapsedForPainting() const;
4217 * Determines if this frame is a stacking context.
4219 bool IsStackingContext(const nsStyleDisplay*, const nsStyleEffects*);
4220 bool IsStackingContext();
4222 // Whether we should paint backgrounds or not.
4223 struct ShouldPaintBackground {
4224 bool mColor = false;
4225 bool mImage = false;
4227 ShouldPaintBackground ComputeShouldPaintBackground() const;
4230 * Determine whether the frame is logically empty, which is roughly
4231 * whether the layout would be the same whether or not the frame is
4232 * present. Placeholder frames should return true. Block frames
4233 * should be considered empty whenever margins collapse through them,
4234 * even though those margins are relevant. Text frames containing
4235 * only whitespace that does not contribute to the height of the line
4236 * should return true.
4238 virtual bool IsEmpty();
4240 * Return the same as IsEmpty(). This may only be called after the frame
4241 * has been reflowed and before any further style or content changes.
4243 virtual bool CachedIsEmpty();
4245 * Determine whether the frame is logically empty, assuming that all
4246 * its children are empty.
4248 virtual bool IsSelfEmpty();
4251 * IsGeneratedContentFrame returns whether a frame corresponds to
4252 * generated content
4254 * @return whether the frame correspods to generated content
4256 bool IsGeneratedContentFrame() const {
4257 return HasAnyStateBits(NS_FRAME_GENERATED_CONTENT);
4261 * IsPseudoFrame returns whether a frame is a pseudo frame (eg an
4262 * anonymous table-row frame created for a CSS table-cell without an
4263 * enclosing table-row.
4265 * @param aParentContent the content node corresponding to the parent frame
4266 * @return whether the frame is a pseudo frame
4268 bool IsPseudoFrame(const nsIContent* aParentContent) {
4269 return mContent == aParentContent;
4273 * Support for reading and writing properties on the frame.
4274 * These call through to the frame's FrameProperties object, if it
4275 * exists, but avoid creating it if no property is ever set.
4277 template <typename T>
4278 FrameProperties::PropertyType<T> GetProperty(
4279 FrameProperties::Descriptor<T> aProperty,
4280 bool* aFoundResult = nullptr) const {
4281 return mProperties.Get(aProperty, aFoundResult);
4284 template <typename T>
4285 bool HasProperty(FrameProperties::Descriptor<T> aProperty) const {
4286 return mProperties.Has(aProperty);
4290 * Add a property, or update an existing property for the given descriptor.
4292 * Note: This function asserts if updating an existing nsFrameList property.
4294 template <typename T>
4295 void SetProperty(FrameProperties::Descriptor<T> aProperty,
4296 FrameProperties::PropertyType<T> aValue) {
4297 if constexpr (std::is_same_v<T, nsFrameList>) {
4298 MOZ_ASSERT(aValue, "Shouldn't set nullptr to a nsFrameList property!");
4299 MOZ_ASSERT(!HasProperty(aProperty),
4300 "Shouldn't update an existing nsFrameList property!");
4302 mProperties.Set(aProperty, aValue, this);
4305 // Unconditionally add a property; use ONLY if the descriptor is known
4306 // to NOT already be present.
4307 template <typename T>
4308 void AddProperty(FrameProperties::Descriptor<T> aProperty,
4309 FrameProperties::PropertyType<T> aValue) {
4310 mProperties.Add(aProperty, aValue);
4314 * Remove a property and return its value without destroying it. May return
4315 * nullptr.
4317 * Note: The caller is responsible for handling the life cycle of the returned
4318 * value.
4320 template <typename T>
4321 [[nodiscard]] FrameProperties::PropertyType<T> TakeProperty(
4322 FrameProperties::Descriptor<T> aProperty, bool* aFoundResult = nullptr) {
4323 return mProperties.Take(aProperty, aFoundResult);
4326 template <typename T>
4327 void RemoveProperty(FrameProperties::Descriptor<T> aProperty) {
4328 mProperties.Remove(aProperty, this);
4331 void RemoveAllProperties() { mProperties.RemoveAll(this); }
4333 // nsIFrames themselves are in the nsPresArena, and so are not measured here.
4334 // Instead, this measures heap-allocated things hanging off the nsIFrame, and
4335 // likewise for its descendants.
4336 virtual void AddSizeOfExcludingThisForTree(nsWindowSizes& aWindowSizes) const;
4339 * Return true if and only if this frame obeys visibility:hidden.
4340 * if it does not, then nsContainerFrame will hide its view even though
4341 * this means children can't be made visible again.
4343 virtual bool SupportsVisibilityHidden() { return true; }
4346 * Returns the clip rect set via the 'clip' property, if the 'clip' property
4347 * applies to this frame; otherwise returns Nothing(). The 'clip' property
4348 * applies to HTML frames if they are absolutely positioned. The 'clip'
4349 * property applies to SVG frames regardless of the value of the 'position'
4350 * property.
4352 * The coordinates of the returned rectangle are relative to this frame's
4353 * origin.
4355 Maybe<nsRect> GetClipPropClipRect(const nsStyleDisplay* aDisp,
4356 const nsStyleEffects* aEffects,
4357 const nsSize& aSize) const;
4360 * Check if this frame is focusable and in the current tab order.
4361 * Tabbable is indicated by a nonnegative tabindex & is a subset of focusable.
4362 * For example, only the selected radio button in a group is in the
4363 * tab order, unless the radio group has no selection in which case
4364 * all of the visible, non-disabled radio buttons in the group are
4365 * in the tab order. On the other hand, all of the visible, non-disabled
4366 * radio buttons are always focusable via clicking or script.
4367 * Also, depending on the pref accessibility.tabfocus some widgets may be
4368 * focusable but removed from the tab order. This is the default on
4369 * Mac OS X, where fewer items are focusable.
4370 * @param [in, optional] aWithMouse, is this focus query for mouse clicking
4371 * @param [in, optional] aCheckVisibility, whether to treat an invisible
4372 * frame as not focusable
4373 * @return whether the frame is focusable via mouse, kbd or script.
4375 [[nodiscard]] Focusable IsFocusable(bool aWithMouse = false,
4376 bool aCheckVisibility = true);
4378 protected:
4379 // Helper for IsFocusable.
4380 bool IsFocusableDueToScrollFrame();
4383 * Returns true if this box clips its children, e.g., if this box is an
4384 * scrollbox or has overflow: clip in both axes.
4386 bool DoesClipChildrenInBothAxes() const;
4389 * NOTE: aStatus is assumed to be already-initialized. The reflow statuses of
4390 * any reflowed absolute children will be merged into aStatus; aside from
4391 * that, this method won't modify aStatus.
4393 void ReflowAbsoluteFrames(nsPresContext* aPresContext,
4394 ReflowOutput& aDesiredSize,
4395 const ReflowInput& aReflowInput,
4396 nsReflowStatus& aStatus,
4397 bool aConstrainBSize = true);
4399 private:
4400 Maybe<nscoord> ComputeInlineSizeFromAspectRatio(
4401 mozilla::WritingMode aWM, const mozilla::LogicalSize& aCBSize,
4402 const mozilla::LogicalSize& aContentEdgeToBoxSizing,
4403 const mozilla::StyleSizeOverrides& aSizeOverrides,
4404 mozilla::ComputeSizeFlags aFlags) const;
4406 public:
4408 * @return true if this text frame ends with a newline character. It
4409 * should return false if this is not a text frame.
4411 virtual bool HasSignificantTerminalNewline() const;
4413 struct CaretPosition {
4414 CaretPosition();
4415 ~CaretPosition();
4417 nsCOMPtr<nsIContent> mResultContent;
4418 int32_t mContentOffset;
4422 * gets the first or last possible caret position within the frame
4424 * @param [in] aStart
4425 * true for getting the first possible caret position
4426 * false for getting the last possible caret position
4427 * @return The caret position in a CaretPosition.
4428 * the returned value is a 'best effort' in case errors
4429 * are encountered rummaging through the frame.
4431 CaretPosition GetExtremeCaretPosition(bool aStart);
4434 * Query whether this frame supports getting a line iterator.
4435 * @return true if a line iterator is supported.
4437 virtual bool CanProvideLineIterator() const { return false; }
4440 * Get a line iterator for this frame, if supported.
4442 * @return nullptr if no line iterator is supported.
4443 * @note dispose the line iterator using nsILineIterator::DisposeLineIterator
4445 virtual nsILineIterator* GetLineIterator() { return nullptr; }
4448 * If this frame is a next-in-flow, and its prev-in-flow has something on its
4449 * overflow list, pull those frames into the child list of this one.
4451 virtual void PullOverflowsFromPrevInFlow() {}
4454 * Accessors for the absolute containing block.
4456 bool IsAbsoluteContainer() const {
4457 return !!(mState & NS_FRAME_HAS_ABSPOS_CHILDREN);
4459 bool HasAbsolutelyPositionedChildren() const;
4460 nsAbsoluteContainingBlock* GetAbsoluteContainingBlock() const;
4461 void MarkAsAbsoluteContainingBlock();
4462 void MarkAsNotAbsoluteContainingBlock();
4463 // Child frame types override this function to select their own child list
4464 // name
4465 virtual mozilla::FrameChildListID GetAbsoluteListID() const {
4466 return mozilla::FrameChildListID::Absolute;
4469 // Checks if we (or any of our descendants) have NS_FRAME_PAINTED_THEBES set,
4470 // and clears this bit if so.
4471 bool CheckAndClearPaintedState();
4473 // Checks if we (or any of our descendents) have mBuiltDisplayList set, and
4474 // clears this bit if so.
4475 bool CheckAndClearDisplayListState();
4477 // CSS visibility just doesn't cut it because it doesn't inherit through
4478 // documents. Also if this frame is in a hidden card of a deck then it isn't
4479 // visible either and that isn't expressed using CSS visibility. Also if it
4480 // is in a hidden view (there are a few cases left and they are hopefully
4481 // going away soon).
4482 // If the VISIBILITY_CROSS_CHROME_CONTENT_BOUNDARY flag is passed then we
4483 // ignore the chrome/content boundary, otherwise we stop looking when we
4484 // reach it.
4485 enum { VISIBILITY_CROSS_CHROME_CONTENT_BOUNDARY = 0x01 };
4486 bool IsVisibleConsideringAncestors(uint32_t aFlags = 0) const;
4488 struct FrameWithDistance {
4489 nsIFrame* mFrame;
4490 nscoord mXDistance;
4491 nscoord mYDistance;
4495 * Finds a frame that is closer to a specified point than a current
4496 * distance. Distance is measured as for text selection -- a closer x
4497 * distance beats a closer y distance.
4499 * Normally, this function will only check the distance between this
4500 * frame's rectangle and the specified point. SVGTextFrame overrides
4501 * this so that it can manage all of its descendant frames and take
4502 * into account any SVG text layout.
4504 * If aPoint is closer to this frame's rectangle than aCurrentBestFrame
4505 * indicates, then aCurrentBestFrame is updated with the distance between
4506 * aPoint and this frame's rectangle, and with a pointer to this frame.
4507 * If aPoint is not closer, then aCurrentBestFrame is left unchanged.
4509 * @param aPoint The point to check for its distance to this frame.
4510 * @param aCurrentBestFrame Pointer to a struct that will be updated with
4511 * a pointer to this frame and its distance to aPoint, if this frame
4512 * is indeed closer than the current distance in aCurrentBestFrame.
4514 virtual void FindCloserFrameForSelection(
4515 const nsPoint& aPoint, FrameWithDistance* aCurrentBestFrame);
4518 * Is this a flex item? (i.e. a non-abs-pos child of a flex container)
4520 inline bool IsFlexItem() const;
4522 * Is this a grid item? (i.e. a non-abs-pos child of a grid container)
4524 inline bool IsGridItem() const;
4526 * Is this a flex or grid item? (i.e. a non-abs-pos child of a flex/grid
4527 * container)
4529 inline bool IsFlexOrGridItem() const;
4530 inline bool IsFlexOrGridContainer() const;
4533 * Return true if this frame has masonry layout in aAxis.
4534 * @note only valid to call on nsGridContainerFrames
4536 inline bool IsMasonry(mozilla::LogicalAxis aAxis) const;
4539 * @return true if this frame is used as a table caption.
4541 inline bool IsTableCaption() const;
4543 inline bool IsBlockOutside() const;
4544 inline bool IsInlineOutside() const;
4545 inline mozilla::StyleDisplay GetDisplay() const;
4546 inline bool IsFloating() const;
4547 inline bool IsAbsPosContainingBlock() const;
4548 inline bool IsFixedPosContainingBlock() const;
4549 inline bool IsRelativelyOrStickyPositioned() const;
4551 // Note: In general, you'd want to call IsRelativelyOrStickyPositioned()
4552 // unless you want to deal with "position:relative" and "position:sticky"
4553 // differently.
4554 inline bool IsRelativelyPositioned() const;
4555 inline bool IsStickyPositioned() const;
4557 inline bool IsAbsolutelyPositioned(
4558 const nsStyleDisplay* aStyleDisplay = nullptr) const;
4559 inline bool IsTrueOverflowContainer() const;
4561 // Does this frame have "column-span: all" style.
4563 // Note this only checks computed style, but not testing whether the
4564 // containing block formatting context was established by a multicol. Callers
4565 // need to use IsColumnSpanInMulticolSubtree() to check whether multi-column
4566 // effects apply or not.
4567 inline bool IsColumnSpan() const;
4569 // Like IsColumnSpan(), but this also checks whether the frame has a
4570 // multi-column ancestor or not.
4571 inline bool IsColumnSpanInMulticolSubtree() const;
4574 * Returns the vertical-align value to be used for layout, if it is one
4575 * of the enumerated values. If this is an SVG text frame, it returns a value
4576 * that corresponds to the value of dominant-baseline. If the
4577 * vertical-align property has length or percentage value, this returns
4578 * Nothing().
4580 Maybe<mozilla::StyleVerticalAlignKeyword> VerticalAlignEnum() const;
4583 * Adds the NS_FRAME_IN_POPUP state bit to aFrame, and
4584 * all descendant frames (including cross-doc ones).
4586 static void AddInPopupStateBitToDescendants(nsIFrame* aFrame);
4588 * Removes the NS_FRAME_IN_POPUP state bit from aFrame and
4589 * all descendant frames (including cross-doc ones), unless
4590 * the frame is a popup itself.
4592 static void RemoveInPopupStateBitFromDescendants(nsIFrame* aFrame);
4595 * Return true if aFrame is in an {ib} split and is NOT one of the
4596 * continuations of the first inline in it.
4598 bool FrameIsNonFirstInIBSplit() const {
4599 return HasAnyStateBits(NS_FRAME_PART_OF_IBSPLIT) &&
4600 FirstContinuation()->GetProperty(nsIFrame::IBSplitPrevSibling());
4604 * Return true if aFrame is in an {ib} split and is NOT one of the
4605 * continuations of the last inline in it.
4607 bool FrameIsNonLastInIBSplit() const {
4608 return HasAnyStateBits(NS_FRAME_PART_OF_IBSPLIT) &&
4609 FirstContinuation()->GetProperty(nsIFrame::IBSplitSibling());
4613 * Return whether this is a frame whose width is used when computing
4614 * the font size inflation of its descendants.
4616 bool IsContainerForFontSizeInflation() const {
4617 return HasAnyStateBits(NS_FRAME_FONT_INFLATION_CONTAINER);
4621 * Return whether this frame or any of its children is dirty.
4623 bool IsSubtreeDirty() const {
4624 return HasAnyStateBits(NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN);
4628 * Returns true if the frame is an SVGTextFrame or one of its descendants.
4630 bool IsInSVGTextSubtree() const {
4631 return HasAnyStateBits(NS_FRAME_IS_SVG_TEXT);
4634 // https://drafts.csswg.org/css-overflow-3/#scroll-container
4635 bool IsScrollContainer() const {
4636 const bool result = IsScrollFrame() || IsListControlFrame();
4637 MOZ_ASSERT(result == !!GetAsScrollContainer());
4638 return result;
4640 nsIScrollableFrame* GetAsScrollContainer() const;
4643 * Returns true if the frame is an SVG Rendering Observer container.
4645 bool IsRenderingObserverContainer() const {
4646 // NS_FRAME_SVG_LAYOUT is used as a proxy to check for an SVG frame because
4647 // NS_STATE_SVG_RENDERING_OBSERVER_CONTAINER is an SVG specific state bit.
4648 return HasAllStateBits(NS_FRAME_SVG_LAYOUT |
4649 NS_STATE_SVG_RENDERING_OBSERVER_CONTAINER) ||
4650 IsSVGOuterSVGFrame();
4654 * Return whether this frame keeps track of overflow areas. (Frames for
4655 * non-display SVG elements -- e.g. <clipPath> -- do not maintain overflow
4656 * areas, because they're never painted.)
4658 bool FrameMaintainsOverflow() const {
4659 return !HasAllStateBits(NS_FRAME_SVG_LAYOUT | NS_FRAME_IS_NONDISPLAY) &&
4660 !(IsSVGOuterSVGFrame() && HasAnyStateBits(NS_FRAME_IS_NONDISPLAY));
4664 * @param aStyleDisplay: If the caller has this->StyleDisplay(), providing
4665 * it here will improve performance.
4667 bool BackfaceIsHidden(const nsStyleDisplay* aStyleDisplay) const {
4668 MOZ_ASSERT(aStyleDisplay == StyleDisplay());
4669 return aStyleDisplay->BackfaceIsHidden();
4671 bool BackfaceIsHidden() const { return StyleDisplay()->BackfaceIsHidden(); }
4674 * Returns true if the frame is scrolled out of view.
4676 bool IsScrolledOutOfView() const;
4679 * Computes a 2D matrix from the -moz-window-transform and
4680 * -moz-window-transform-origin properties on aFrame.
4681 * Values that don't result in a 2D matrix will be ignored and an identity
4682 * matrix will be returned instead.
4684 Matrix ComputeWidgetTransform() const;
4687 * @return true iff this frame has one or more associated image requests.
4688 * @see mozilla::css::ImageLoader.
4690 bool HasImageRequest() const { return mHasImageRequest; }
4693 * Update this frame's image request state.
4695 void SetHasImageRequest(bool aHasRequest) { mHasImageRequest = aHasRequest; }
4698 * Whether this frame has a first-letter child. If it does, the frame is
4699 * actually an nsContainerFrame and the first-letter frame can be gotten by
4700 * walking up to the nearest ancestor blockframe and getting its first
4701 * continuation's nsContainerFrame::FirstLetterProperty() property. This will
4702 * only return true for the first continuation of the first-letter's parent.
4704 bool HasFirstLetterChild() const { return mHasFirstLetterChild; }
4707 * Whether this frame's parent is a wrapper anonymous box. See documentation
4708 * for mParentIsWrapperAnonBox.
4710 bool ParentIsWrapperAnonBox() const { return mParentIsWrapperAnonBox; }
4711 void SetParentIsWrapperAnonBox() { mParentIsWrapperAnonBox = true; }
4714 * Whether this is a wrapper anonymous box needing a restyle.
4716 bool IsWrapperAnonBoxNeedingRestyle() const {
4717 return mIsWrapperBoxNeedingRestyle;
4719 void SetIsWrapperAnonBoxNeedingRestyle(bool aNeedsRestyle) {
4720 mIsWrapperBoxNeedingRestyle = aNeedsRestyle;
4723 bool MayHaveTransformAnimation() const { return mMayHaveTransformAnimation; }
4724 void SetMayHaveTransformAnimation() {
4725 AddStateBits(NS_FRAME_MAY_BE_TRANSFORMED);
4726 mMayHaveTransformAnimation = true;
4728 bool MayHaveOpacityAnimation() const { return mMayHaveOpacityAnimation; }
4729 void SetMayHaveOpacityAnimation() { mMayHaveOpacityAnimation = true; }
4731 // Returns true if this frame is visible or may have visible descendants.
4732 // Note: This function is accurate only on primary frames, because
4733 // mAllDescendantsAreInvisible is not updated on continuations.
4734 bool IsVisibleOrMayHaveVisibleDescendants() const {
4735 return !mAllDescendantsAreInvisible || StyleVisibility()->IsVisible();
4737 // Update mAllDescendantsAreInvisible flag for this frame and ancestors.
4738 void UpdateVisibleDescendantsState();
4741 * If this returns true, the frame it's called on should get the
4742 * NS_FRAME_HAS_DIRTY_CHILDREN bit set on it by the caller; either directly
4743 * if it's already in reflow, or via calling FrameNeedsReflow() to schedule a
4744 * reflow.
4746 virtual bool RenumberFrameAndDescendants(int32_t* aOrdinal, int32_t aDepth,
4747 int32_t aIncrement,
4748 bool aForCounting) {
4749 return false;
4752 enum class ExtremumLength {
4753 MinContent,
4754 MaxContent,
4755 MozAvailable,
4756 FitContent,
4757 FitContentFunction,
4760 template <typename SizeOrMaxSize>
4761 static Maybe<ExtremumLength> ToExtremumLength(const SizeOrMaxSize& aSize) {
4762 switch (aSize.tag) {
4763 case SizeOrMaxSize::Tag::MinContent:
4764 return mozilla::Some(ExtremumLength::MinContent);
4765 case SizeOrMaxSize::Tag::MaxContent:
4766 return mozilla::Some(ExtremumLength::MaxContent);
4767 case SizeOrMaxSize::Tag::MozAvailable:
4768 return mozilla::Some(ExtremumLength::MozAvailable);
4769 case SizeOrMaxSize::Tag::FitContent:
4770 return mozilla::Some(ExtremumLength::FitContent);
4771 case SizeOrMaxSize::Tag::FitContentFunction:
4772 return mozilla::Some(ExtremumLength::FitContentFunction);
4773 default:
4774 return mozilla::Nothing();
4779 * Helper function - computes the content-box inline size for aSize, which is
4780 * a more complex version to resolve a StyleExtremumLength.
4781 * @param aAvailableISizeOverride If this has a value, it is used as the
4782 * available inline-size instead of
4783 * aContainingBlockSize.ISize(aWM) when
4784 * resolving fit-content.
4786 struct ISizeComputationResult {
4787 nscoord mISize = 0;
4788 AspectRatioUsage mAspectRatioUsage = AspectRatioUsage::None;
4790 ISizeComputationResult ComputeISizeValue(
4791 gfxContext* aRenderingContext, const mozilla::WritingMode aWM,
4792 const mozilla::LogicalSize& aContainingBlockSize,
4793 const mozilla::LogicalSize& aContentEdgeToBoxSizing,
4794 nscoord aBoxSizingToMarginEdge, ExtremumLength aSize,
4795 Maybe<nscoord> aAvailableISizeOverride,
4796 const mozilla::StyleSizeOverrides& aSizeOverrides,
4797 mozilla::ComputeSizeFlags aFlags);
4800 * Helper function - computes the content-box inline size for aSize, which is
4801 * a simpler version to resolve a LengthPercentage.
4803 nscoord ComputeISizeValue(const mozilla::WritingMode aWM,
4804 const mozilla::LogicalSize& aContainingBlockSize,
4805 const mozilla::LogicalSize& aContentEdgeToBoxSizing,
4806 const LengthPercentage& aSize);
4808 template <typename SizeOrMaxSize>
4809 ISizeComputationResult ComputeISizeValue(
4810 gfxContext* aRenderingContext, const mozilla::WritingMode aWM,
4811 const mozilla::LogicalSize& aContainingBlockSize,
4812 const mozilla::LogicalSize& aContentEdgeToBoxSizing,
4813 nscoord aBoxSizingToMarginEdge, const SizeOrMaxSize& aSize,
4814 const mozilla::StyleSizeOverrides& aSizeOverrides = {},
4815 mozilla::ComputeSizeFlags aFlags = {}) {
4816 if (aSize.IsLengthPercentage()) {
4817 return {ComputeISizeValue(aWM, aContainingBlockSize,
4818 aContentEdgeToBoxSizing,
4819 aSize.AsLengthPercentage())};
4821 auto length = ToExtremumLength(aSize);
4822 MOZ_ASSERT(length, "This doesn't handle none / auto");
4823 Maybe<nscoord> availbleISizeOverride;
4824 if (aSize.IsFitContentFunction()) {
4825 availbleISizeOverride.emplace(aSize.AsFitContentFunction().Resolve(
4826 aContainingBlockSize.ISize(aWM)));
4828 return ComputeISizeValue(aRenderingContext, aWM, aContainingBlockSize,
4829 aContentEdgeToBoxSizing, aBoxSizingToMarginEdge,
4830 length.valueOr(ExtremumLength::MinContent),
4831 availbleISizeOverride, aSizeOverrides, aFlags);
4834 DisplayItemArray& DisplayItems() { return mDisplayItems; }
4835 const DisplayItemArray& DisplayItems() const { return mDisplayItems; }
4837 void AddDisplayItem(nsDisplayItem* aItem);
4838 bool RemoveDisplayItem(nsDisplayItem* aItem);
4839 void RemoveDisplayItemDataForDeletion();
4840 bool HasDisplayItems();
4841 bool HasDisplayItem(nsDisplayItem* aItem);
4842 bool HasDisplayItem(uint32_t aKey);
4844 static void PrintDisplayList(nsDisplayListBuilder* aBuilder,
4845 const nsDisplayList& aList,
4846 bool aDumpHtml = false);
4847 static void PrintDisplayList(nsDisplayListBuilder* aBuilder,
4848 const nsDisplayList& aList,
4849 std::stringstream& aStream,
4850 bool aDumpHtml = false);
4851 static void PrintDisplayItem(nsDisplayListBuilder* aBuilder,
4852 nsDisplayItem* aItem, std::stringstream& aStream,
4853 uint32_t aIndent = 0, bool aDumpSublist = false,
4854 bool aDumpHtml = false);
4855 #ifdef MOZ_DUMP_PAINTING
4856 static void PrintDisplayListSet(nsDisplayListBuilder* aBuilder,
4857 const nsDisplayListSet& aSet,
4858 std::stringstream& aStream,
4859 bool aDumpHtml = false);
4860 #endif
4863 * Adds display items for standard CSS background if necessary.
4864 * Does not check IsVisibleForPainting.
4865 * @return whether a themed background item was created.
4867 bool DisplayBackgroundUnconditional(nsDisplayListBuilder* aBuilder,
4868 const nsDisplayListSet& aLists);
4870 * Adds display items for standard CSS borders, background and outline for
4871 * for this frame, as necessary. Checks IsVisibleForPainting and won't
4872 * display anything if the frame is not visible.
4874 void DisplayBorderBackgroundOutline(nsDisplayListBuilder* aBuilder,
4875 const nsDisplayListSet& aLists);
4877 * Add a display item for the CSS outline. Does not check visibility.
4879 void DisplayOutlineUnconditional(nsDisplayListBuilder* aBuilder,
4880 const nsDisplayListSet& aLists);
4882 * Add a display item for the CSS outline, after calling
4883 * IsVisibleForPainting to confirm we are visible.
4885 void DisplayOutline(nsDisplayListBuilder* aBuilder,
4886 const nsDisplayListSet& aLists);
4889 * Add a display item for CSS inset box shadows. Does not check visibility.
4891 void DisplayInsetBoxShadowUnconditional(nsDisplayListBuilder* aBuilder,
4892 nsDisplayList* aList);
4895 * Add a display item for CSS inset box shadow, after calling
4896 * IsVisibleForPainting to confirm we are visible.
4898 void DisplayInsetBoxShadow(nsDisplayListBuilder* aBuilder,
4899 nsDisplayList* aList);
4902 * Add a display item for CSS outset box shadows. Does not check visibility.
4904 void DisplayOutsetBoxShadowUnconditional(nsDisplayListBuilder* aBuilder,
4905 nsDisplayList* aList);
4908 * Add a display item for CSS outset box shadow, after calling
4909 * IsVisibleForPainting to confirm we are visible.
4911 void DisplayOutsetBoxShadow(nsDisplayListBuilder* aBuilder,
4912 nsDisplayList* aList);
4914 bool ForceDescendIntoIfVisible() const { return mForceDescendIntoIfVisible; }
4915 void SetForceDescendIntoIfVisible(bool aForce) {
4916 mForceDescendIntoIfVisible = aForce;
4919 bool BuiltDisplayList() const { return mBuiltDisplayList; }
4920 void SetBuiltDisplayList(const bool aBuilt) { mBuiltDisplayList = aBuilt; }
4922 bool IsFrameModified() const { return mFrameIsModified; }
4923 void SetFrameIsModified(const bool aFrameIsModified) {
4924 mFrameIsModified = aFrameIsModified;
4927 bool HasModifiedDescendants() const { return mHasModifiedDescendants; }
4928 void SetHasModifiedDescendants(const bool aHasModifiedDescendants) {
4929 mHasModifiedDescendants = aHasModifiedDescendants;
4932 bool HasOverrideDirtyRegion() const { return mHasOverrideDirtyRegion; }
4933 void SetHasOverrideDirtyRegion(const bool aHasDirtyRegion) {
4934 mHasOverrideDirtyRegion = aHasDirtyRegion;
4937 bool MayHaveWillChangeBudget() const { return mMayHaveWillChangeBudget; }
4938 void SetMayHaveWillChangeBudget(const bool aHasBudget) {
4939 mMayHaveWillChangeBudget = aHasBudget;
4942 bool HasBSizeChange() const { return mHasBSizeChange; }
4943 void SetHasBSizeChange(const bool aHasBSizeChange) {
4944 mHasBSizeChange = aHasBSizeChange;
4947 bool HasPaddingChange() const { return mHasPaddingChange; }
4948 void SetHasPaddingChange(const bool aHasPaddingChange) {
4949 mHasPaddingChange = aHasPaddingChange;
4952 bool HasColumnSpanSiblings() const { return mHasColumnSpanSiblings; }
4953 void SetHasColumnSpanSiblings(bool aHasColumnSpanSiblings) {
4954 mHasColumnSpanSiblings = aHasColumnSpanSiblings;
4957 bool DescendantMayDependOnItsStaticPosition() const {
4958 return mDescendantMayDependOnItsStaticPosition;
4960 void SetDescendantMayDependOnItsStaticPosition(bool aValue) {
4961 mDescendantMayDependOnItsStaticPosition = aValue;
4965 * Returns the hit test area of the frame.
4967 nsRect GetCompositorHitTestArea(nsDisplayListBuilder* aBuilder);
4970 * Returns the set of flags indicating the properties of the frame that the
4971 * compositor might care about for hit-testing purposes. Note that this
4972 * function must be called during Gecko display list construction time (i.e
4973 * while the frame tree is being traversed) because that is when the display
4974 * list builder has the necessary state set up correctly.
4976 mozilla::gfx::CompositorHitTestInfo GetCompositorHitTestInfo(
4977 nsDisplayListBuilder* aBuilder);
4980 * Copies aWM to mWritingMode on 'this' and all its ancestors.
4982 inline void PropagateWritingModeToSelfAndAncestors(mozilla::WritingMode aWM);
4985 * Observes or unobserves the element with an internal ResizeObserver,
4986 * depending on whether it needs to update its last remembered size.
4987 * Also removes a previously stored last remembered size if the element
4988 * can no longer have it.
4989 * @see {@link https://drafts.csswg.org/css-sizing-4/#last-remembered}
4991 void HandleLastRememberedSize();
4993 protected:
4995 * Reparent this frame's view if it has one.
4997 void ReparentFrameViewTo(nsViewManager* aViewManager, nsView* aNewParentView);
4999 // Members
5000 nsRect mRect;
5001 nsCOMPtr<nsIContent> mContent;
5002 RefPtr<ComputedStyle> mComputedStyle;
5004 private:
5005 nsPresContext* const mPresContext;
5006 nsContainerFrame* mParent;
5007 nsIFrame* mNextSibling; // doubly-linked list of frames
5008 nsIFrame* mPrevSibling; // Do not touch outside SetNextSibling!
5010 DisplayItemArray mDisplayItems;
5012 void MarkAbsoluteFramesForDisplayList(nsDisplayListBuilder* aBuilder);
5014 protected:
5015 void MarkInReflow() {
5016 #ifdef DEBUG_dbaron_off
5017 // bug 81268
5018 NS_ASSERTION(!(mState & NS_FRAME_IN_REFLOW), "frame is already in reflow");
5019 #endif
5020 AddStateBits(NS_FRAME_IN_REFLOW);
5023 private:
5024 nsFrameState mState;
5026 protected:
5028 * List of properties attached to the frame.
5030 FrameProperties mProperties;
5032 // When there is no scrollable overflow area, and the ink overflow area only
5033 // slightly larger than mRect, the ink overflow area may be stored a set of
5034 // four 1-byte deltas from the edges of mRect rather than allocating a whole
5035 // separate rectangle property. If all four deltas are zero, this means that
5036 // no overflow area has actually been set (this is the initial state of
5037 // newly-created frames).
5039 // Note that these are unsigned values, all measured "outwards" from the edges
5040 // of mRect, so mLeft and mTop are reversed from our normal coordinate system.
5041 struct InkOverflowDeltas {
5042 // The maximum delta value we can store in any of the four edges.
5043 static constexpr uint8_t kMax = 0xfe;
5045 uint8_t mLeft;
5046 uint8_t mTop;
5047 uint8_t mRight;
5048 uint8_t mBottom;
5049 bool operator==(const InkOverflowDeltas& aOther) const {
5050 return mLeft == aOther.mLeft && mTop == aOther.mTop &&
5051 mRight == aOther.mRight && mBottom == aOther.mBottom;
5053 bool operator!=(const InkOverflowDeltas& aOther) const {
5054 return !(*this == aOther);
5057 enum class OverflowStorageType : uint32_t {
5058 // No overflow area; code relies on this being an all-zero value.
5059 None = 0x00000000u,
5061 // Ink overflow is too large to stored in InkOverflowDeltas.
5062 Large = 0x000000ffu,
5064 // If mOverflow.mType is OverflowStorageType::Large, then the delta values are
5065 // not meaningful and the overflow area is stored in OverflowAreasProperty()
5066 // instead.
5067 union {
5068 OverflowStorageType mType;
5069 InkOverflowDeltas mInkOverflowDeltas;
5070 } mOverflow;
5072 /** @see GetWritingMode() */
5073 mozilla::WritingMode mWritingMode;
5075 /** The ClassID of the concrete class of this instance. */
5076 ClassID mClass; // 1 byte
5078 bool mMayHaveRoundedCorners : 1;
5081 * True iff this frame has one or more associated image requests.
5082 * @see mozilla::css::ImageLoader.
5084 bool mHasImageRequest : 1;
5087 * True if this frame has a continuation that has a first-letter frame, or its
5088 * placeholder, as a child. In that case this frame has a blockframe ancestor
5089 * that has the first-letter frame hanging off it in the
5090 * nsContainerFrame::FirstLetterProperty() property.
5092 bool mHasFirstLetterChild : 1;
5095 * True if this frame's parent is a wrapper anonymous box (e.g. a table
5096 * anonymous box as specified at
5097 * <https://www.w3.org/TR/CSS21/tables.html#anonymous-boxes>).
5099 * We could compute this information directly when we need it, but it wouldn't
5100 * be all that cheap, and since this information is immutable for the lifetime
5101 * of the frame we might as well cache it.
5103 * Note that our parent may itself have mParentIsWrapperAnonBox set to true.
5105 bool mParentIsWrapperAnonBox : 1;
5108 * True if this is a wrapper anonymous box needing a restyle. This is used to
5109 * track, during stylo post-traversal, whether we've already recomputed the
5110 * style of this anonymous box, if we end up seeing it twice.
5112 bool mIsWrapperBoxNeedingRestyle : 1;
5115 * This bit is used in nsTextFrame::CharacterDataChanged() as an optimization
5116 * to skip redundant reflow-requests when the character data changes multiple
5117 * times between reflows. If this flag is set, then it implies that the
5118 * NS_FRAME_IS_DIRTY state bit is also set (and that intrinsic sizes have
5119 * been marked as dirty on our ancestor chain).
5121 * XXXdholbert This bit is *only* used on nsTextFrame, but it lives here on
5122 * nsIFrame simply because this is where we've got unused state bits
5123 * available in a gap. If bits become more scarce, we should perhaps consider
5124 * expanding the range of frame-specific state bits in nsFrameStateBits.h and
5125 * moving this to be one of those (e.g. by swapping one of the adjacent
5126 * general-purpose bits to take the place of this bool:1 here, so we can grow
5127 * that range of frame-specific bits by 1).
5129 bool mReflowRequestedForCharDataChange : 1;
5132 * This bit is used during BuildDisplayList to mark frames that need to
5133 * have display items rebuilt. We will descend into them if they are
5134 * currently visible, even if they don't intersect the dirty area.
5136 bool mForceDescendIntoIfVisible : 1;
5139 * True if we have built display items for this frame since
5140 * the last call to CheckAndClearDisplayListState, false
5141 * otherwise. Used for the reftest harness to verify minimal
5142 * display list building.
5144 bool mBuiltDisplayList : 1;
5147 * True if the frame has been marked modified by
5148 * |MarkNeedsDisplayItemRebuild()|, usually due to a style change or reflow.
5150 bool mFrameIsModified : 1;
5153 * True if the frame has modified descendants. Set before display list
5154 * preprocessing and only used during partial display list builds.
5156 bool mHasModifiedDescendants : 1;
5159 * Used by merging based retained display lists to restrict the dirty area
5160 * during partial display list builds.
5162 bool mHasOverrideDirtyRegion : 1;
5165 * True if frame has will-change, and currently has display
5166 * items consuming some of the will-change budget.
5168 bool mMayHaveWillChangeBudget : 1;
5170 #ifdef DEBUG
5171 public:
5173 * True if this frame has already been been visited by
5174 * nsCSSFrameConstructor::AutoFrameConstructionPageName.
5176 * This is used to assert that we have visited each frame only once, and is
5177 * not useful otherwise.
5179 bool mWasVisitedByAutoFrameConstructionPageName : 1;
5180 #endif
5182 private:
5184 * True if this is the primary frame for mContent.
5186 bool mIsPrimaryFrame : 1;
5188 bool mMayHaveTransformAnimation : 1;
5189 bool mMayHaveOpacityAnimation : 1;
5192 * True if we are certain that all descendants are not visible.
5194 * This flag is conservative in that it might sometimes be false even if, in
5195 * fact, all descendants are invisible.
5196 * For example; an element is visibility:visible and has a visibility:hidden
5197 * child. This flag is stil false in such case.
5199 bool mAllDescendantsAreInvisible : 1;
5201 bool mHasBSizeChange : 1;
5204 * True if the frame seems to be in the process of being reflowed with a
5205 * different amount of inline-axis padding as compared to its most recent
5206 * reflow. This flag's purpose is to detect cases where the frame's
5207 * inline-axis content-box-size has changed, without any style change or any
5208 * change to the border-box size, so that we can mark/invalidate things
5209 * appropriately in ReflowInput::InitResizeFlags().
5211 * This flag is set in SizeComputationResult::InitOffsets() and cleared in
5212 * nsIFrame::DidReflow().
5214 bool mHasPaddingChange : 1;
5217 * True if we are or contain the scroll anchor for a scrollable frame.
5219 bool mInScrollAnchorChain : 1;
5222 * Suppose a frame was split into multiple parts to separate parts containing
5223 * column-spans from parts not containing column-spans. This bit is set on all
5224 * continuations *not* containing column-spans except for the those after the
5225 * last column-span/non-column-span boundary (i.e., the bit really means it
5226 * has a *later* sibling across a split). Note that the last part is always
5227 * created to containing no columns-spans even if it has no children. See
5228 * nsCSSFrameConstructor::CreateColumnSpanSiblings() for the implementation.
5230 * If the frame having this bit set is removed, we need to reframe the
5231 * multi-column container.
5233 bool mHasColumnSpanSiblings : 1;
5236 * True if we may have any descendant whose positioning may depend on its
5237 * static position (and thus which we need to recompute the position for if we
5238 * move).
5240 bool mDescendantMayDependOnItsStaticPosition : 1;
5242 protected:
5243 // Helpers
5245 * Can we stop inside this frame when we're skipping non-rendered whitespace?
5247 * @param aForward [in] Are we moving forward (or backward) in content order.
5249 * @param aOffset [in/out] At what offset into the frame to start looking.
5250 * at offset was reached (whether or not we found a place to stop).
5252 * @return
5253 * * STOP: An appropriate offset was found within this frame,
5254 * and is given by aOffset.
5255 * * CONTINUE: Not found within this frame, need to try the next frame.
5256 * See enum FrameSearchResult for more details.
5258 virtual FrameSearchResult PeekOffsetNoAmount(bool aForward, int32_t* aOffset);
5261 * Search the frame for the next character
5263 * @param aForward [in] Are we moving forward (or backward) in content order.
5265 * @param aOffset [in/out] At what offset into the frame to start looking.
5266 * on output - what offset was reached (whether or not we found a place to
5267 * stop).
5269 * @param aOptions [in] Options, see the comment in PeekOffsetCharacterOptions
5270 * for the detail.
5272 * @return
5273 * * STOP: An appropriate offset was found within this frame, and is given
5274 * by aOffset.
5275 * * CONTINUE: Not found within this frame, need to try the next frame. See
5276 * enum FrameSearchResult for more details.
5278 virtual FrameSearchResult PeekOffsetCharacter(
5279 bool aForward, int32_t* aOffset,
5280 PeekOffsetCharacterOptions aOptions = PeekOffsetCharacterOptions());
5281 static_assert(sizeof(PeekOffsetCharacterOptions) <= sizeof(intptr_t),
5282 "aOptions should be changed to const reference");
5284 struct PeekWordState {
5285 // true when we're still at the start of the search, i.e., we can't return
5286 // this point as a valid offset!
5287 bool mAtStart;
5288 // true when we've encountered at least one character of the type before the
5289 // boundary we're looking for:
5290 // 1. If we're moving forward and eating whitepace, looking for a word
5291 // beginning (i.e. a boundary between whitespace and non-whitespace),
5292 // then mSawBeforeType==true means "we already saw some whitespace".
5293 // 2. Otherwise, looking for a word beginning (i.e. a boundary between
5294 // non-whitespace and whitespace), then mSawBeforeType==true means "we
5295 // already saw some non-whitespace".
5296 bool mSawBeforeType;
5297 // true when we've encountered at least one non-newline character
5298 bool mSawInlineCharacter;
5299 // true when the last character encountered was punctuation
5300 bool mLastCharWasPunctuation;
5301 // true when the last character encountered was whitespace
5302 bool mLastCharWasWhitespace;
5303 // true when we've seen non-punctuation since the last whitespace
5304 bool mSeenNonPunctuationSinceWhitespace;
5305 // text that's *before* the current frame when aForward is true, *after*
5306 // the current frame when aForward is false. Only includes the text
5307 // on the current line.
5308 nsAutoString mContext;
5310 PeekWordState()
5311 : mAtStart(true),
5312 mSawBeforeType(false),
5313 mSawInlineCharacter(false),
5314 mLastCharWasPunctuation(false),
5315 mLastCharWasWhitespace(false),
5316 mSeenNonPunctuationSinceWhitespace(false) {}
5317 void SetSawBeforeType() { mSawBeforeType = true; }
5318 void SetSawInlineCharacter() { mSawInlineCharacter = true; }
5319 void Update(bool aAfterPunctuation, bool aAfterWhitespace) {
5320 mLastCharWasPunctuation = aAfterPunctuation;
5321 mLastCharWasWhitespace = aAfterWhitespace;
5322 if (aAfterWhitespace) {
5323 mSeenNonPunctuationSinceWhitespace = false;
5324 } else if (!aAfterPunctuation) {
5325 mSeenNonPunctuationSinceWhitespace = true;
5327 mAtStart = false;
5332 * Search the frame for the next word boundary
5333 * @param aForward [in] Are we moving forward (or backward) in content order.
5334 * @param aWordSelectEatSpace [in] true: look for non-whitespace following
5335 * whitespace (in the direction of movement).
5336 * false: look for whitespace following non-whitespace (in the
5337 * direction of movement).
5338 * @param aIsKeyboardSelect [in] Was the action initiated by a keyboard
5339 * operation? If true, punctuation immediately following a word is considered
5340 * part of that word. Otherwise, a sequence of punctuation is always
5341 * considered as a word on its own.
5342 * @param aOffset [in/out] At what offset into the frame to start looking.
5343 * on output - what offset was reached (whether or not we found a
5344 * place to stop).
5345 * @param aState [in/out] the state that is carried from frame to frame
5347 virtual FrameSearchResult PeekOffsetWord(
5348 bool aForward, bool aWordSelectEatSpace, bool aIsKeyboardSelect,
5349 int32_t* aOffset, PeekWordState* aState, bool aTrimSpaces);
5351 protected:
5353 * Check whether we should break at a boundary between punctuation and
5354 * non-punctuation. Only call it at a punctuation boundary
5355 * (i.e. exactly one of the previous and next characters are punctuation).
5356 * @param aForward true if we're moving forward in content order
5357 * @param aPunctAfter true if the next character is punctuation
5358 * @param aWhitespaceAfter true if the next character is whitespace
5360 static bool BreakWordBetweenPunctuation(const PeekWordState* aState,
5361 bool aForward, bool aPunctAfter,
5362 bool aWhitespaceAfter,
5363 bool aIsKeyboardSelect);
5365 private:
5366 nsRect GetOverflowRect(mozilla::OverflowType aType) const;
5368 // Get a pointer to the overflow areas property attached to the frame.
5369 mozilla::OverflowAreas* GetOverflowAreasProperty() const {
5370 MOZ_ASSERT(mOverflow.mType == OverflowStorageType::Large);
5371 mozilla::OverflowAreas* overflow = GetProperty(OverflowAreasProperty());
5372 MOZ_ASSERT(overflow);
5373 return overflow;
5376 nsRect InkOverflowFromDeltas() const {
5377 MOZ_ASSERT(mOverflow.mType != OverflowStorageType::Large,
5378 "should not be called when overflow is in a property");
5379 // Calculate the rect using deltas from the frame's border rect.
5380 // Note that the mOverflow.mInkOverflowDeltas fields are unsigned, but we
5381 // will often need to return negative values for the left and top, so take
5382 // care to cast away the unsigned-ness.
5383 return nsRect(-(int32_t)mOverflow.mInkOverflowDeltas.mLeft,
5384 -(int32_t)mOverflow.mInkOverflowDeltas.mTop,
5385 mRect.Width() + mOverflow.mInkOverflowDeltas.mRight +
5386 mOverflow.mInkOverflowDeltas.mLeft,
5387 mRect.Height() + mOverflow.mInkOverflowDeltas.mBottom +
5388 mOverflow.mInkOverflowDeltas.mTop);
5392 * Set the OverflowArea rect, storing it as deltas or a separate rect
5393 * depending on its size in relation to the primary frame rect.
5395 * @return true if any overflow changed.
5397 bool SetOverflowAreas(const mozilla::OverflowAreas& aOverflowAreas);
5399 bool HasOpacityInternal(float aThreshold, const nsStyleDisplay* aStyleDisplay,
5400 const nsStyleEffects* aStyleEffects,
5401 mozilla::EffectSet* aEffectSet = nullptr) const;
5403 static constexpr size_t kFrameClassCount =
5404 #define FRAME_ID(...) 1 +
5405 #define ABSTRACT_FRAME_ID(...)
5406 #include "mozilla/FrameIdList.h"
5407 #undef FRAME_ID
5408 #undef ABSTRACT_FRAME_ID
5411 // Maps mClass to LayoutFrameType.
5412 static const mozilla::LayoutFrameType sLayoutFrameTypes[kFrameClassCount];
5413 // Maps mClass to LayoutFrameTypeFlags.
5414 static const ClassFlags sLayoutFrameClassFlags[kFrameClassCount];
5416 #ifdef DEBUG_FRAME_DUMP
5417 public:
5418 static void IndentBy(FILE* out, int32_t aIndent) {
5419 while (--aIndent >= 0) fputs(" ", out);
5421 void ListTag(FILE* out) const { fputs(ListTag().get(), out); }
5422 nsAutoCString ListTag() const;
5424 enum class ListFlag{TraverseSubdocumentFrames, DisplayInCSSPixels};
5425 using ListFlags = mozilla::EnumSet<ListFlag>;
5427 template <typename T>
5428 static std::string ConvertToString(const T& aValue, ListFlags aFlags) {
5429 // This method can convert all physical types in app units to CSS pixels.
5430 return aFlags.contains(ListFlag::DisplayInCSSPixels)
5431 ? mozilla::ToString(mozilla::CSSPixel::FromAppUnits(aValue))
5432 : mozilla::ToString(aValue);
5434 static std::string ConvertToString(const mozilla::LogicalRect& aRect,
5435 const mozilla::WritingMode aWM,
5436 ListFlags aFlags);
5437 static std::string ConvertToString(const mozilla::LogicalSize& aSize,
5438 const mozilla::WritingMode aWM,
5439 ListFlags aFlags);
5441 void ListGeneric(nsACString& aTo, const char* aPrefix = "",
5442 ListFlags aFlags = ListFlags()) const;
5443 virtual void List(FILE* out = stderr, const char* aPrefix = "",
5444 ListFlags aFlags = ListFlags()) const;
5446 void ListTextRuns(FILE* out = stderr) const;
5447 virtual void ListTextRuns(FILE* out, nsTHashSet<const void*>& aSeen) const;
5449 virtual void ListWithMatchedRules(FILE* out = stderr,
5450 const char* aPrefix = "") const;
5451 void ListMatchedRules(FILE* out, const char* aPrefix) const;
5454 * Dump the frame tree beginning from the root frame.
5456 void DumpFrameTree() const;
5457 void DumpFrameTreeInCSSPixels() const;
5460 * Dump the frame tree beginning from ourselves.
5462 void DumpFrameTreeLimited() const;
5463 void DumpFrameTreeLimitedInCSSPixels() const;
5466 * Get a printable from of the name of the frame type.
5467 * XXX This should be eliminated and we use GetType() instead...
5469 virtual nsresult GetFrameName(nsAString& aResult) const;
5470 nsresult MakeFrameName(const nsAString& aType, nsAString& aResult) const;
5471 // Helper function to return the index in parent of the frame's content
5472 // object. Returns Nothing on error or if the frame doesn't have a content
5473 // object
5474 static mozilla::Maybe<uint32_t> ContentIndexInContainer(
5475 const nsIFrame* aFrame);
5476 #endif
5478 #ifdef DEBUG
5480 * Tracing method that writes a method enter/exit routine to the
5481 * nspr log using the nsIFrame log module. The tracing is only
5482 * done when the NS_FRAME_TRACE_CALLS bit is set in the log module's
5483 * level field.
5485 void Trace(const char* aMethod, bool aEnter);
5486 void Trace(const char* aMethod, bool aEnter, const nsReflowStatus& aStatus);
5487 void TraceMsg(const char* aFormatString, ...) MOZ_FORMAT_PRINTF(2, 3);
5489 // Helper function that verifies that each frame in the list has the
5490 // NS_FRAME_IS_DIRTY bit set
5491 static void VerifyDirtyBitSet(const nsFrameList& aFrameList);
5493 static mozilla::LazyLogModule sFrameLogModule;
5494 #endif
5497 MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(nsIFrame::ReflowChildFlags)
5499 //----------------------------------------------------------------------
5502 * AutoWeakFrame can be used to keep a reference to a nsIFrame in a safe way.
5503 * Whenever an nsIFrame object is deleted, the AutoWeakFrames pointing
5504 * to it will be cleared. AutoWeakFrame is for variables on the stack or
5505 * in static storage only, there is also a WeakFrame below for heap uses.
5507 * Create AutoWeakFrame object when it is sure that nsIFrame object
5508 * is alive and after some operations which may destroy the nsIFrame
5509 * (for example any DOM modifications) use IsAlive() or GetFrame() methods to
5510 * check whether it is safe to continue to use the nsIFrame object.
5512 * @note The usage of this class should be kept to a minimum.
5514 class WeakFrame;
5515 class MOZ_NONHEAP_CLASS AutoWeakFrame {
5516 public:
5517 explicit AutoWeakFrame() : mPrev(nullptr), mFrame(nullptr) {}
5519 AutoWeakFrame(const AutoWeakFrame& aOther) : mPrev(nullptr), mFrame(nullptr) {
5520 Init(aOther.GetFrame());
5523 MOZ_IMPLICIT AutoWeakFrame(const WeakFrame& aOther);
5525 MOZ_IMPLICIT AutoWeakFrame(nsIFrame* aFrame)
5526 : mPrev(nullptr), mFrame(nullptr) {
5527 Init(aFrame);
5530 AutoWeakFrame& operator=(AutoWeakFrame& aOther) {
5531 Init(aOther.GetFrame());
5532 return *this;
5535 AutoWeakFrame& operator=(nsIFrame* aFrame) {
5536 Init(aFrame);
5537 return *this;
5540 nsIFrame* operator->() { return mFrame; }
5542 operator nsIFrame*() { return mFrame; }
5544 void Clear(mozilla::PresShell* aPresShell);
5546 bool IsAlive() const { return !!mFrame; }
5548 nsIFrame* GetFrame() const { return mFrame; }
5550 AutoWeakFrame* GetPreviousWeakFrame() { return mPrev; }
5552 void SetPreviousWeakFrame(AutoWeakFrame* aPrev) { mPrev = aPrev; }
5554 ~AutoWeakFrame();
5556 private:
5557 // Not available for the heap!
5558 void* operator new(size_t) = delete;
5559 void* operator new[](size_t) = delete;
5560 void operator delete(void*) = delete;
5561 void operator delete[](void*) = delete;
5563 void Init(nsIFrame* aFrame);
5565 AutoWeakFrame* mPrev;
5566 nsIFrame* mFrame;
5569 // Use nsIFrame's fast-path to avoid QueryFrame:
5570 inline do_QueryFrameHelper<nsIFrame> do_QueryFrame(AutoWeakFrame& s) {
5571 return do_QueryFrameHelper<nsIFrame>(s.GetFrame());
5575 * @see AutoWeakFrame
5577 class MOZ_HEAP_CLASS WeakFrame {
5578 public:
5579 WeakFrame() : mFrame(nullptr) {}
5581 WeakFrame(const WeakFrame& aOther) : mFrame(nullptr) {
5582 Init(aOther.GetFrame());
5585 MOZ_IMPLICIT WeakFrame(const AutoWeakFrame& aOther) : mFrame(nullptr) {
5586 Init(aOther.GetFrame());
5589 MOZ_IMPLICIT WeakFrame(nsIFrame* aFrame) : mFrame(nullptr) { Init(aFrame); }
5591 ~WeakFrame() {
5592 Clear(mFrame ? mFrame->PresContext()->GetPresShell() : nullptr);
5595 WeakFrame& operator=(WeakFrame& aOther) {
5596 Init(aOther.GetFrame());
5597 return *this;
5600 WeakFrame& operator=(nsIFrame* aFrame) {
5601 Init(aFrame);
5602 return *this;
5605 nsIFrame* operator->() { return mFrame; }
5606 operator nsIFrame*() { return mFrame; }
5608 bool operator==(nsIFrame* const aOther) const { return mFrame == aOther; }
5610 void Clear(mozilla::PresShell* aPresShell);
5612 bool IsAlive() const { return !!mFrame; }
5613 nsIFrame* GetFrame() const { return mFrame; }
5615 private:
5616 void Init(nsIFrame* aFrame);
5618 nsIFrame* mFrame;
5621 // Use nsIFrame's fast-path to avoid QueryFrame:
5622 inline do_QueryFrameHelper<nsIFrame> do_QueryFrame(WeakFrame& s) {
5623 return do_QueryFrameHelper<nsIFrame>(s.GetFrame());
5626 inline bool nsFrameList::ContinueRemoveFrame(nsIFrame* aFrame) {
5627 MOZ_ASSERT(!aFrame->GetPrevSibling() || !aFrame->GetNextSibling(),
5628 "Forgot to call StartRemoveFrame?");
5629 if (aFrame == mLastChild) {
5630 MOZ_ASSERT(!aFrame->GetNextSibling(), "broken frame list");
5631 nsIFrame* prevSibling = aFrame->GetPrevSibling();
5632 if (!prevSibling) {
5633 MOZ_ASSERT(aFrame == mFirstChild, "broken frame list");
5634 mFirstChild = mLastChild = nullptr;
5635 return true;
5637 MOZ_ASSERT(prevSibling->GetNextSibling() == aFrame, "Broken frame linkage");
5638 prevSibling->SetNextSibling(nullptr);
5639 mLastChild = prevSibling;
5640 return true;
5642 if (aFrame == mFirstChild) {
5643 MOZ_ASSERT(!aFrame->GetPrevSibling(), "broken frame list");
5644 mFirstChild = aFrame->GetNextSibling();
5645 aFrame->SetNextSibling(nullptr);
5646 MOZ_ASSERT(mFirstChild, "broken frame list");
5647 return true;
5649 return false;
5652 inline bool nsFrameList::StartRemoveFrame(nsIFrame* aFrame) {
5653 if (aFrame->GetPrevSibling() && aFrame->GetNextSibling()) {
5654 UnhookFrameFromSiblings(aFrame);
5655 return true;
5657 return ContinueRemoveFrame(aFrame);
5660 // Operators of nsFrameList::Iterator
5661 // ---------------------------------------------------
5663 inline nsIFrame* nsFrameList::ForwardFrameTraversal::Next(nsIFrame* aFrame) {
5664 MOZ_ASSERT(aFrame);
5665 return aFrame->GetNextSibling();
5667 inline nsIFrame* nsFrameList::ForwardFrameTraversal::Prev(nsIFrame* aFrame) {
5668 MOZ_ASSERT(aFrame);
5669 return aFrame->GetPrevSibling();
5672 inline nsIFrame* nsFrameList::BackwardFrameTraversal::Next(nsIFrame* aFrame) {
5673 MOZ_ASSERT(aFrame);
5674 return aFrame->GetPrevSibling();
5676 inline nsIFrame* nsFrameList::BackwardFrameTraversal::Prev(nsIFrame* aFrame) {
5677 MOZ_ASSERT(aFrame);
5678 return aFrame->GetNextSibling();
5681 #endif /* nsIFrame_h___ */