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