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