tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

nsTextFrame.h (48030B)


      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 #ifndef nsTextFrame_h__
      8 #define nsTextFrame_h__
      9 
     10 #include "JustificationUtils.h"
     11 #include "gfxSkipChars.h"
     12 #include "gfxTextRun.h"
     13 #include "mozilla/Attributes.h"
     14 #include "mozilla/UniquePtr.h"
     15 #include "mozilla/dom/Text.h"
     16 #include "mozilla/gfx/2D.h"
     17 #include "nsIFrame.h"
     18 #include "nsISelectionController.h"
     19 #include "nsSplittableFrame.h"
     20 
     21 // Undo the windows.h damage
     22 #if defined(XP_WIN) && defined(DrawText)
     23 #  undef DrawText
     24 #endif
     25 
     26 struct SelectionDetails;
     27 class nsBlockFrame;
     28 class nsTextPaintStyle;
     29 
     30 namespace mozilla {
     31 class SVGContextPaint;
     32 class SVGTextFrame;
     33 class nsDisplayTextGeometry;
     34 class nsDisplayText;
     35 namespace dom {
     36 class CharacterDataBuffer;
     37 }
     38 
     39 /**
     40 * Helper for CSS text-autospace, used by nsTextFrame::PropertyProvider.
     41 */
     42 class MOZ_STACK_CLASS TextAutospace final {
     43 public:
     44  enum class CharClass : uint8_t {
     45    Other,
     46    CombiningMark,
     47    Ideograph,
     48    NonIdeographicLetter,
     49    NonIdeographicNumeral,
     50  };
     51 
     52  enum class Boundary : uint8_t {
     53    IdeographAlpha,
     54    IdeographNumeric,
     55  };
     56  using BoundarySet = EnumSet<Boundary>;
     57 
     58  // Returns true if inter-script spacing may be added at boundaries.
     59  static bool Enabled(const StyleTextAutospace& aStyleTextAutospace,
     60                      const nsTextFrame* aFrame);
     61 
     62  TextAutospace(const StyleTextAutospace& aStyleTextAutospace,
     63                nscoord aSpacing);
     64 
     65  nscoord InterScriptSpacing() const { return mInterScriptSpacing; }
     66 
     67  // Return true if inter-script spacing should be applied between aPrevClass
     68  // and aCurrClass.
     69  bool ShouldApplySpacing(CharClass aPrevClass, CharClass aCurrClass) const;
     70 
     71  // Returns true when non-ideographic letters/numerals should not participate
     72  // in autospace boundaries for aFrame.
     73  static bool ShouldSuppressLetterNumeralSpacing(const nsIFrame* aFrame);
     74 
     75  // Return true if aChar is an ideograph.
     76  // https://drafts.csswg.org/css-text-4/#ideographs
     77  static bool IsIdeograph(char32_t aChar);
     78 
     79  // Get character class for aChar.
     80  // https://drafts.csswg.org/css-text-4/#text-spacing-classes
     81  static CharClass GetCharClass(char32_t aChar);
     82 
     83 private:
     84  BoundarySet InitBoundarySet(
     85      const StyleTextAutospace& aStyleTextAutospace) const;
     86 
     87  // Enabled boundaries. When non-empty, insert spacing at these class
     88  // boundaries (e.g. ideograph-alpha, ideograph-numeric).
     89  BoundarySet mBoundarySet;
     90 
     91  // Inter-script spacing amount to add at boundaries.
     92  nscoord mInterScriptSpacing{};
     93 };
     94 
     95 }  // namespace mozilla
     96 
     97 class nsTextFrame : public nsIFrame {
     98  using DrawTarget = mozilla::gfx::DrawTarget;
     99  using LayoutDeviceRect = mozilla::LayoutDeviceRect;
    100  using Point = mozilla::gfx::Point;
    101  using Range = gfxTextRun::Range;
    102  using Rect = mozilla::gfx::Rect;
    103  using SelectionType = mozilla::SelectionType;
    104  using SelectionTypeMask = mozilla::SelectionTypeMask;
    105  using Size = mozilla::gfx::Size;
    106  using TextRangeStyle = mozilla::TextRangeStyle;
    107 
    108 public:
    109  enum TextRunType : uint8_t;
    110  struct TabWidthStore;
    111 
    112  /**
    113   * An implementation of gfxTextRun::PropertyProvider that computes spacing and
    114   * hyphenation based on CSS properties for a text frame.
    115   *
    116   * nsTextFrame normally creates a PropertyProvider as a temporary object on
    117   * on the stack, but this is not marked MOZ_STACK_CLASS because SVGTextFrame
    118   * wants to cache an instance across multiple calls using the same textframe.
    119   */
    120  class PropertyProvider final : public gfxTextRun::PropertyProvider {
    121    using HyphenType = gfxTextRun::HyphenType;
    122 
    123   public:
    124    /**
    125     * Use this constructor for reflow, when we don't know what text is
    126     * really mapped by the frame and we have a lot of other data around.
    127     *
    128     * @param aLength can be INT32_MAX to indicate we cover all the text
    129     * associated with aFrame up to where its flow chain ends in the given
    130     * textrun. If INT32_MAX is passed, justification and hyphen-related methods
    131     * cannot be called, nor can GetOriginalLength().
    132     */
    133    PropertyProvider(gfxTextRun* aTextRun, const nsStyleText* aTextStyle,
    134                     const mozilla::dom::CharacterDataBuffer& aBuffer,
    135                     nsTextFrame* aFrame, const gfxSkipCharsIterator& aStart,
    136                     int32_t aLength, nsIFrame* aLineContainer,
    137                     nscoord aOffsetFromBlockOriginForTabs,
    138                     nsTextFrame::TextRunType aWhichTextRun,
    139                     bool aAtStartOfLine);
    140 
    141    /**
    142     * Use this constructor after the frame has been reflowed and we don't
    143     * have other data around. Gets everything from the frame. EnsureTextRun
    144     * *must* be called before this!!!
    145     */
    146    PropertyProvider(nsTextFrame* aFrame, const gfxSkipCharsIterator& aStart,
    147                     nsTextFrame::TextRunType aWhichTextRun,
    148                     nsFontMetrics* aFontMetrics);
    149 
    150    /**
    151     * As above, but assuming we want the inflated text run and associated
    152     * metrics.
    153     */
    154    PropertyProvider(nsTextFrame* aFrame, const gfxSkipCharsIterator& aStart)
    155        : PropertyProvider(aFrame, aStart, nsTextFrame::eInflated,
    156                           aFrame->InflatedFontMetrics()) {}
    157 
    158    // Call this after construction if you're not going to reflow the text
    159    void InitializeForDisplay(bool aTrimAfter);
    160 
    161    void InitializeForMeasure();
    162 
    163    bool GetSpacing(Range aRange, Spacing* aSpacing) const final;
    164    gfxFloat GetHyphenWidth() const final;
    165    void GetHyphenationBreaks(Range aRange,
    166                              HyphenType* aBreakBefore) const final;
    167    mozilla::StyleHyphens GetHyphensOption() const final {
    168      return mTextStyle->mHyphens;
    169    }
    170    mozilla::gfx::ShapedTextFlags GetShapedTextFlags() const final;
    171 
    172    already_AddRefed<DrawTarget> GetDrawTarget() const final;
    173 
    174    uint32_t GetAppUnitsPerDevUnit() const final {
    175      return mTextRun->GetAppUnitsPerDevUnit();
    176    }
    177 
    178    bool GetSpacingInternal(Range aRange, Spacing* aSpacing,
    179                            bool aIgnoreTabs) const;
    180 
    181    /**
    182     * Compute the justification information in given DOM range, return
    183     * justification info and assignments if requested.
    184     */
    185    mozilla::JustificationInfo ComputeJustification(
    186        Range aRange,
    187        nsTArray<mozilla::JustificationAssignment>* aAssignments = nullptr);
    188 
    189    const nsTextFrame* GetFrame() const { return mFrame; }
    190    // This may not be equal to the frame offset/length in because we may have
    191    // adjusted for whitespace trimming according to the state bits set in the
    192    // frame (for the static provider)
    193    const gfxSkipCharsIterator& GetStart() const { return mStart; }
    194    // May return INT32_MAX if that was given to the constructor
    195    uint32_t GetOriginalLength() const {
    196      NS_ASSERTION(mLength != INT32_MAX, "Length not known");
    197      return mLength;
    198    }
    199    const mozilla::dom::CharacterDataBuffer& GetCharacterDataBuffer() const {
    200      return mCharacterDataBuffer;
    201    }
    202 
    203    gfxFontGroup* GetFontGroup() const {
    204      if (!mFontGroup) {
    205        mFontGroup = GetFontMetrics()->GetThebesFontGroup();
    206      }
    207      return mFontGroup;
    208    }
    209 
    210    nsFontMetrics* GetFontMetrics() const {
    211      if (!mFontMetrics) {
    212        InitFontGroupAndFontMetrics();
    213      }
    214      return mFontMetrics;
    215    }
    216 
    217    void CalcTabWidths(Range aTransformedRange, gfxFloat aTabWidth) const;
    218 
    219    gfxFloat MinTabAdvance() const;
    220 
    221    const gfxSkipCharsIterator& GetEndHint() const { return mTempIterator; }
    222 
    223    // Set a position that should be treated as start-of-line (for trimming
    224    // potential letter-spacing).
    225    void SetStartOfLine(const gfxSkipCharsIterator& aPosition) {
    226      mStartOfLineOffset = aPosition.GetSkippedOffset();
    227    }
    228 
    229   protected:
    230    void SetupJustificationSpacing(bool aPostReflow);
    231 
    232    void InitFontGroupAndFontMetrics() const;
    233 
    234    // Initialize TextAutospace, if inter-script spacing applies.
    235    void InitTextAutospace();
    236 
    237    const RefPtr<gfxTextRun> mTextRun;
    238    mutable gfxFontGroup* mFontGroup;
    239    mutable RefPtr<nsFontMetrics> mFontMetrics;
    240    const nsStyleText* mTextStyle;
    241    const mozilla::dom::CharacterDataBuffer& mCharacterDataBuffer;
    242    const nsIFrame* mLineContainer;
    243    nsTextFrame* mFrame;
    244 
    245    // Offset in original and transformed string
    246    gfxSkipCharsIterator mStart;
    247 
    248    const gfxSkipCharsIterator mTempIterator;
    249 
    250    // Either null, or pointing to the frame's TabWidthProperty.
    251    mutable nsTextFrame::TabWidthStore* mTabWidths;
    252 
    253    // How far we've done tab-width calculation; this is ONLY valid when
    254    // mTabWidths is nullptr (otherwise rely on mTabWidths->mLimit instead).
    255    // It's a DOM offset relative to the current frame's offset.
    256    mutable uint32_t mTabWidthsAnalyzedLimit;
    257 
    258    // DOM string length, may be INT32_MAX
    259    int32_t mLength;
    260 
    261    // space for each whitespace char
    262    const nscoord mWordSpacing;
    263 
    264    // space for each letter
    265    const nscoord mLetterSpacing;
    266 
    267    // If TextAutospace exists, inter-script spacing applies.
    268    Maybe<mozilla::TextAutospace> mTextAutospace;
    269 
    270    // min advance for <tab> char
    271    mutable gfxFloat mMinTabAdvance;
    272 
    273    mutable gfxFloat mHyphenWidth;
    274    mutable gfxFloat mOffsetFromBlockOriginForTabs;
    275 
    276    // The values in mJustificationSpacings corresponds to unskipped
    277    // characters start from mJustificationArrayStart.
    278    uint32_t mJustificationArrayStart;
    279    nsTArray<Spacing> mJustificationSpacings;
    280 
    281    const bool mReflowing;
    282    const nsTextFrame::TextRunType mWhichTextRun;
    283    uint32_t mStartOfLineOffset = UINT32_MAX;
    284  };
    285 
    286  explicit nsTextFrame(ComputedStyle* aStyle, nsPresContext* aPresContext,
    287                       ClassID aID = kClassID)
    288      : nsIFrame(aStyle, aPresContext, aID) {}
    289 
    290  NS_DECL_FRAMEARENA_HELPERS(nsTextFrame)
    291 
    292  friend class nsContinuingTextFrame;
    293 
    294  // nsQueryFrame
    295  NS_DECL_QUERYFRAME
    296 
    297  NS_DECLARE_FRAME_PROPERTY_DELETABLE(ContinuationsProperty,
    298                                      nsTArray<nsTextFrame*>)
    299 
    300  // nsIFrame
    301  void BuildDisplayList(nsDisplayListBuilder* aBuilder,
    302                        const nsDisplayListSet& aLists) final;
    303 
    304  void Init(nsIContent* aContent, nsContainerFrame* aParent,
    305            nsIFrame* aPrevInFlow) override;
    306 
    307  void Destroy(DestroyContext&) override;
    308 
    309  Cursor GetCursor(const nsPoint&) final;
    310 
    311  nsresult CharacterDataChanged(const CharacterDataChangeInfo&) final;
    312 
    313  nsTextFrame* FirstContinuation() const override {
    314    return const_cast<nsTextFrame*>(this);
    315  }
    316  nsTextFrame* GetPrevContinuation() const override { return nullptr; }
    317  nsTextFrame* GetNextContinuation() const final { return mNextContinuation; }
    318  void SetNextContinuation(nsIFrame* aNextContinuation) final {
    319    NS_ASSERTION(!aNextContinuation || Type() == aNextContinuation->Type(),
    320                 "setting a next continuation with incorrect type!");
    321    NS_ASSERTION(
    322        !nsSplittableFrame::IsInNextContinuationChain(aNextContinuation, this),
    323        "creating a loop in continuation chain!");
    324    mNextContinuation = static_cast<nsTextFrame*>(aNextContinuation);
    325    if (aNextContinuation) {
    326      aNextContinuation->RemoveStateBits(NS_FRAME_IS_FLUID_CONTINUATION);
    327    }
    328    // Setting a non-fluid continuation might affect our flow length (they're
    329    // quite rare so we assume it always does) so we delete our cached value:
    330    if (GetContent()->HasFlag(NS_HAS_FLOWLENGTH_PROPERTY)) {
    331      GetContent()->RemoveProperty(nsGkAtoms::flowlength);
    332      GetContent()->UnsetFlags(NS_HAS_FLOWLENGTH_PROPERTY);
    333    }
    334  }
    335  nsTextFrame* GetNextInFlow() const final {
    336    return mNextContinuation && mNextContinuation->HasAnyStateBits(
    337                                    NS_FRAME_IS_FLUID_CONTINUATION)
    338               ? mNextContinuation
    339               : nullptr;
    340  }
    341  void SetNextInFlow(nsIFrame* aNextInFlow) final {
    342    NS_ASSERTION(!aNextInFlow || Type() == aNextInFlow->Type(),
    343                 "setting a next in flow with incorrect type!");
    344    NS_ASSERTION(
    345        !nsSplittableFrame::IsInNextContinuationChain(aNextInFlow, this),
    346        "creating a loop in continuation chain!");
    347    mNextContinuation = static_cast<nsTextFrame*>(aNextInFlow);
    348    if (mNextContinuation &&
    349        !mNextContinuation->HasAnyStateBits(NS_FRAME_IS_FLUID_CONTINUATION)) {
    350      // Changing from non-fluid to fluid continuation might affect our flow
    351      // length, so we delete our cached value:
    352      if (GetContent()->HasFlag(NS_HAS_FLOWLENGTH_PROPERTY)) {
    353        GetContent()->RemoveProperty(nsGkAtoms::flowlength);
    354        GetContent()->UnsetFlags(NS_HAS_FLOWLENGTH_PROPERTY);
    355      }
    356    }
    357    if (aNextInFlow) {
    358      aNextInFlow->AddStateBits(NS_FRAME_IS_FLUID_CONTINUATION);
    359    }
    360  }
    361  nsTextFrame* LastInFlow() const final;
    362  nsTextFrame* LastContinuation() const final;
    363 
    364  bool ShouldSuppressLineBreak() const;
    365 
    366  void InvalidateFrame(uint32_t aDisplayItemKey = 0,
    367                       bool aRebuildDisplayItems = true) final;
    368  void InvalidateFrameWithRect(const nsRect& aRect,
    369                               uint32_t aDisplayItemKey = 0,
    370                               bool aRebuildDisplayItems = true) final;
    371 
    372 #ifdef DEBUG_FRAME_DUMP
    373  void List(FILE* out = stderr, const char* aPrefix = "",
    374            ListFlags aFlags = ListFlags()) const final;
    375  nsresult GetFrameName(nsAString& aResult) const final;
    376  void ToCString(nsCString& aBuf) const;
    377  void ListTextRuns(FILE* out, nsTHashSet<const void*>& aSeen) const final;
    378 #endif
    379 
    380  // Returns this text frame's content's text fragment.
    381  //
    382  // Assertions in Init() ensure we only ever get a Text node as content.
    383  const mozilla::dom::CharacterDataBuffer& CharacterDataBuffer() const {
    384    return mContent->AsText()->DataBuffer();
    385  }
    386 
    387  /**
    388   * Check that the text in this frame is entirely whitespace. Importantly,
    389   * this function considers non-breaking spaces (0xa0) to be whitespace,
    390   * whereas nsTextFrame::IsEmpty does not. It also considers both one and
    391   * two-byte chars.
    392   */
    393  bool IsEntirelyWhitespace() const;
    394 
    395  ContentOffsets CalcContentOffsetsFromFramePoint(const nsPoint& aPoint) final;
    396  ContentOffsets GetCharacterOffsetAtFramePoint(const nsPoint& aPoint);
    397 
    398  /**
    399   * This is called only on the primary text frame. It indicates that
    400   * the selection state of the given character range has changed.
    401   * Frames corresponding to the character range are unconditionally invalidated
    402   * (Selection::Repaint depends on this).
    403   * @param aStart start of character range.
    404   * @param aEnd end (exclusive) of character range.
    405   * @param aSelected true iff the character range is now selected.
    406   * @param aType the type of the changed selection.
    407   */
    408  void SelectionStateChanged(uint32_t aStart, uint32_t aEnd, bool aSelected,
    409                             SelectionType aSelectionType);
    410 
    411  FrameSearchResult PeekOffsetNoAmount(bool aForward, int32_t* aOffset) final;
    412  FrameSearchResult PeekOffsetCharacter(
    413      bool aForward, int32_t* aOffset,
    414      PeekOffsetCharacterOptions aOptions = PeekOffsetCharacterOptions()) final;
    415  FrameSearchResult PeekOffsetWord(bool aForward, bool aWordSelectEatSpace,
    416                                   bool aIsKeyboardSelect, int32_t* aOffset,
    417                                   PeekWordState* aState,
    418                                   bool aTrimSpaces) final;
    419 
    420  // Helper method that editor code uses to test for visibility.
    421  [[nodiscard]] bool HasVisibleText();
    422 
    423  // Flags for aSetLengthFlags
    424  enum { ALLOW_FRAME_CREATION_AND_DESTRUCTION = 0x01 };
    425 
    426  // Update offsets to account for new length. This may clear mTextRun.
    427  void SetLength(int32_t aLength, nsLineLayout* aLineLayout,
    428                 uint32_t aSetLengthFlags = 0);
    429 
    430  std::pair<int32_t, int32_t> GetOffsets() const final;
    431 
    432  void AdjustOffsetsForBidi(int32_t start, int32_t end) final;
    433 
    434  nsresult GetPointFromOffset(int32_t inOffset, nsPoint* outPoint) final;
    435  nsresult GetCharacterRectsInRange(int32_t aInOffset, int32_t aLength,
    436                                    nsTArray<nsRect>& aRects) final;
    437 
    438  nsresult GetChildFrameContainingOffset(int32_t inContentOffset, bool inHint,
    439                                         int32_t* outFrameContentOffset,
    440                                         nsIFrame** outChildFrame) final;
    441 
    442  bool IsEmpty() final;
    443  bool IsSelfEmpty() final { return IsEmpty(); }
    444  Maybe<nscoord> GetNaturalBaselineBOffset(
    445      mozilla::WritingMode aWM, BaselineSharingGroup aBaselineGroup,
    446      BaselineExportContext) const override;
    447  nscoord GetCaretBaseline() const override;
    448 
    449  bool HasSignificantTerminalNewline() const final;
    450 
    451  /**
    452   * Returns true if this text frame is logically adjacent to the end of the
    453   * line.
    454   */
    455  bool IsAtEndOfLine() const;
    456 
    457  /**
    458   * Call this only after reflow the frame. Returns true if non-collapsed
    459   * characters are present.
    460   */
    461  bool HasNoncollapsedCharacters() const {
    462    return HasAnyStateBits(TEXT_HAS_NONCOLLAPSED_CHARACTERS);
    463  }
    464 
    465 #ifdef ACCESSIBILITY
    466  mozilla::a11y::AccType AccessibleType() final;
    467 #endif
    468 
    469  float GetFontSizeInflation() const;
    470  bool IsCurrentFontInflation(float aInflation) const;
    471  bool HasFontSizeInflation() const {
    472    return HasAnyStateBits(TEXT_HAS_FONT_INFLATION);
    473  }
    474  void SetFontSizeInflation(float aInflation);
    475 
    476  void MarkIntrinsicISizesDirty() final;
    477 
    478  nscoord IntrinsicISize(const mozilla::IntrinsicSizeInput& aInput,
    479                         mozilla::IntrinsicISizeType aType) final;
    480 
    481  void AddInlineMinISize(const mozilla::IntrinsicSizeInput& aInput,
    482                         InlineMinISizeData* aData) override;
    483  void AddInlinePrefISize(const mozilla::IntrinsicSizeInput& aInput,
    484                          InlinePrefISizeData* aData) override;
    485  SizeComputationResult ComputeSize(
    486      const SizeComputationInput& aSizingInput, mozilla::WritingMode aWM,
    487      const mozilla::LogicalSize& aCBSize, nscoord aAvailableISize,
    488      const mozilla::LogicalSize& aMargin,
    489      const mozilla::LogicalSize& aBorderPadding,
    490      const mozilla::StyleSizeOverrides& aSizeOverrides,
    491      mozilla::ComputeSizeFlags aFlags) final;
    492  nsRect ComputeTightBounds(DrawTarget* aDrawTarget) const final;
    493  nsresult GetPrefWidthTightBounds(gfxContext* aContext, nscoord* aX,
    494                                   nscoord* aXMost) final;
    495  void Reflow(nsPresContext* aPresContext, ReflowOutput& aMetrics,
    496              const ReflowInput& aReflowInput, nsReflowStatus& aStatus) final;
    497  bool CanContinueTextRun() const final;
    498  // Method that is called for a text frame that is logically
    499  // adjacent to the end of the line (i.e. followed only by empty text frames,
    500  // placeholders or inlines containing such).
    501  struct TrimOutput {
    502    // true if we trimmed some space or changed metrics in some other way.
    503    // In this case, we should call RecomputeOverflow on this frame.
    504    bool mChanged;
    505    // an amount to *subtract* from the frame's width (zero if !mChanged)
    506    nscoord mDeltaWidth;
    507  };
    508  TrimOutput TrimTrailingWhiteSpace(DrawTarget* aDrawTarget);
    509  RenderedText GetRenderedText(
    510      uint32_t aStartOffset = 0, uint32_t aEndOffset = UINT32_MAX,
    511      TextOffsetType aOffsetType = TextOffsetType::OffsetsInContentText,
    512      TrailingWhitespace aTrimTrailingWhitespace =
    513          TrailingWhitespace::Trim) final;
    514 
    515  mozilla::OverflowAreas RecomputeOverflow(nsIFrame* aBlockFrame,
    516                                           bool aIncludeShadows = true);
    517 
    518  enum TextRunType : uint8_t {
    519    // Anything in reflow (but not intrinsic width calculation) or
    520    // painting should use the inflated text run (i.e., with font size
    521    // inflation applied).
    522    eInflated,
    523    // Intrinsic width calculation should use the non-inflated text run.
    524    // When there is font size inflation, it will be different.
    525    eNotInflated
    526  };
    527 
    528  void AddInlineMinISizeForFlow(gfxContext* aRenderingContext,
    529                                InlineMinISizeData* aData,
    530                                TextRunType aTextRunType);
    531  void AddInlinePrefISizeForFlow(gfxContext* aRenderingContext,
    532                                 InlinePrefISizeData* aData,
    533                                 TextRunType aTextRunType);
    534 
    535  /**
    536   * Calculate the horizontal bounds of the grapheme clusters that fit entirely
    537   * inside the given left[top]/right[bottom] edges (which are positive lengths
    538   * from the respective frame edge).  If an input value is zero it is ignored
    539   * and the result for that edge is zero.  All out parameter values are
    540   * undefined when the method returns false.
    541   * @return true if at least one whole grapheme cluster fit between the edges
    542   */
    543  bool MeasureCharClippedText(nscoord aVisIStartEdge, nscoord aVisIEndEdge,
    544                              nscoord* aSnappedStartEdge,
    545                              nscoord* aSnappedEndEdge);
    546  /**
    547   * Same as above; this method also the returns the corresponding text run
    548   * offset and number of characters that fit.  All out parameter values are
    549   * undefined when the method returns false.
    550   * @return true if at least one whole grapheme cluster fit between the edges
    551   */
    552  bool MeasureCharClippedText(PropertyProvider& aProvider,
    553                              nscoord aVisIStartEdge, nscoord aVisIEndEdge,
    554                              uint32_t* aStartOffset, uint32_t* aMaxLength,
    555                              nscoord* aSnappedStartEdge,
    556                              nscoord* aSnappedEndEdge);
    557 
    558  /**
    559   * Return true if this box has some text to display.
    560   * It returns false if at least one of these conditions are met:
    561   * a. the frame hasn't been reflowed yet
    562   * b. GetContentLength() == 0
    563   * c. it contains only non-significant white-space
    564   */
    565  bool HasNonSuppressedText() const;
    566 
    567  /**
    568   * Object with various callbacks for PaintText() to invoke for different parts
    569   * of the frame's text rendering, when we're generating paths rather than
    570   * painting.
    571   *
    572   * Callbacks are invoked in the following order:
    573   *
    574   *   NotifySelectionBackgroundNeedsFill?
    575   *   PaintDecorationLine*
    576   *   NotifyBeforeText
    577   *   NotifyGlyphPathEmitted*
    578   *   NotifyAfterText
    579   *   PaintDecorationLine*
    580   *   PaintSelectionDecorationLine*
    581   *
    582   * The color of each part of the frame's text rendering is passed as an
    583   * argument to the NotifyBefore* callback for that part.  The nscolor can take
    584   * on one of the three selection special colors defined in LookAndFeel.h --
    585   * NS_TRANSPARENT, NS_SAME_AS_FOREGROUND_COLOR and
    586   * NS_40PERCENT_FOREGROUND_COLOR.
    587   */
    588  struct DrawPathCallbacks : gfxTextRunDrawCallbacks {
    589    /**
    590     * @param aShouldPaintSVGGlyphs Whether SVG glyphs should be painted.
    591     */
    592    explicit DrawPathCallbacks(bool aShouldPaintSVGGlyphs = false)
    593        : gfxTextRunDrawCallbacks(aShouldPaintSVGGlyphs) {}
    594 
    595    /**
    596     * Called to have the selection highlight drawn before the text is drawn
    597     * over the top.
    598     */
    599    virtual void NotifySelectionBackgroundNeedsFill(const Rect& aBackgroundRect,
    600                                                    nscolor aColor,
    601                                                    DrawTarget& aDrawTarget) {}
    602 
    603    /**
    604     * Called before (for under/over-line) or after (for line-through) the text
    605     * is drawn to have a text decoration line drawn.
    606     */
    607    virtual void PaintDecorationLine(Rect aPath, bool aPaintingShadows,
    608                                     nscolor aColor) {}
    609 
    610    /**
    611     * Called after selected text is drawn to have a decoration line drawn over
    612     * the text. (All types of text decoration are drawn after the text when
    613     * text is selected.)
    614     */
    615    virtual void PaintSelectionDecorationLine(Rect aPath, bool aPaintingShadows,
    616                                              nscolor aColor) {}
    617 
    618    /**
    619     * Called just before any paths have been emitted to the gfxContext
    620     * for the glyphs of the frame's text.
    621     */
    622    virtual void NotifyBeforeText(bool aPaintingShadows, nscolor aColor) {}
    623 
    624    /**
    625     * Called just after all the paths have been emitted to the gfxContext
    626     * for the glyphs of the frame's text.
    627     */
    628    virtual void NotifyAfterText() {}
    629 
    630    /**
    631     * Called just before a path corresponding to a selection decoration line
    632     * has been emitted to the gfxContext.
    633     */
    634    virtual void NotifyBeforeSelectionDecorationLine(nscolor aColor) {}
    635 
    636    /**
    637     * Called just after a path corresponding to a selection decoration line
    638     * has been emitted to the gfxContext.
    639     */
    640    virtual void NotifySelectionDecorationLinePathEmitted() {}
    641  };
    642 
    643  struct MOZ_STACK_CLASS PaintTextParams {
    644    gfxContext* context;
    645    Point framePt;
    646    LayoutDeviceRect dirtyRect;
    647    mozilla::SVGContextPaint* contextPaint = nullptr;
    648    DrawPathCallbacks* callbacks = nullptr;
    649    enum {
    650      PaintText,        // Normal text painting.
    651      GenerateTextMask  // To generate a mask from a text frame. Should
    652                        // only paint text itself with opaque color.
    653                        // Text shadow, text selection color and text
    654                        // decoration are all discarded in this state.
    655    };
    656    uint8_t state = PaintText;
    657    explicit PaintTextParams(gfxContext* aContext) : context(aContext) {}
    658 
    659    bool IsPaintText() const { return state == PaintText; }
    660    bool IsGenerateTextMask() const { return state == GenerateTextMask; }
    661  };
    662 
    663  struct PaintTextSelectionParams;
    664  struct DrawTextRunParams;
    665  struct DrawTextParams;
    666  struct ClipEdges;
    667  struct PaintShadowParams;
    668  struct PaintDecorationLineParams;
    669 
    670  struct PriorityOrderedSelectionsForRange {
    671    /// List of Selection Details active for the given range.
    672    /// Ordered by priority, i.e. the last element has the highest priority.
    673    nsTArray<const SelectionDetails*> mSelectionRanges;
    674    Range mRange;
    675  };
    676 
    677  // Primary frame paint method called from nsDisplayText.  Can also be used
    678  // to generate paths rather than paint the frame's text by passing a callback
    679  // object.  The private DrawText() is what applies the text to a graphics
    680  // context.
    681  void PaintText(const PaintTextParams& aParams, const nscoord aVisIStartEdge,
    682                 const nscoord aVisIEndEdge, const nsPoint& aToReferenceFrame,
    683                 const bool aIsSelected, float aOpacity = 1.0f);
    684  // helper: paint text frame when we're impacted by at least one selection.
    685  // Return false if the text was not painted and we should continue with
    686  // the fast path.
    687  bool PaintTextWithSelection(const PaintTextSelectionParams& aParams,
    688                              const ClipEdges& aClipEdges);
    689  // helper: paint text with foreground and background colors determined
    690  // by selection(s). Also computes a mask of all selection types applying to
    691  // our text, returned in aAllSelectionTypeMask.
    692  // Return false if the text was not painted and we should continue with
    693  // the fast path.
    694  bool PaintTextWithSelectionColors(
    695      const PaintTextSelectionParams& aParams,
    696      const mozilla::UniquePtr<SelectionDetails>& aDetails,
    697      SelectionTypeMask* aAllSelectionTypeMask, const ClipEdges& aClipEdges);
    698  // helper: paint text decorations for text selected by aSelectionType
    699  void PaintTextSelectionDecorations(
    700      const PaintTextSelectionParams& aParams,
    701      const mozilla::UniquePtr<SelectionDetails>& aDetails,
    702      SelectionType aSelectionType);
    703 
    704  SelectionTypeMask ResolveSelections(
    705      const PaintTextSelectionParams& aParams, const SelectionDetails* aDetails,
    706      nsTArray<PriorityOrderedSelectionsForRange>& aResult,
    707      SelectionType aSelectionType, bool* aAnyBackgrounds = nullptr) const;
    708 
    709  void DrawEmphasisMarks(gfxContext* aContext, mozilla::WritingMode aWM,
    710                         const mozilla::gfx::Point& aTextBaselinePt,
    711                         const mozilla::gfx::Point& aFramePt, Range aRange,
    712                         const nscolor* aDecorationOverrideColor,
    713                         PropertyProvider* aProvider);
    714 
    715  nscolor GetCaretColorAt(int32_t aOffset) final;
    716 
    717  // @param aSelectionFlags may be multiple of nsISelectionDisplay::DISPLAY_*.
    718  // @return nsISelectionController.idl's `getDisplaySelection`.
    719  int16_t GetSelectionStatus(int16_t* aSelectionFlags);
    720 
    721  int32_t GetContentOffset() const { return mContentOffset; }
    722  int32_t GetContentLength() const {
    723    NS_ASSERTION(GetContentEnd() - mContentOffset >= 0, "negative length");
    724    return GetContentEnd() - mContentOffset;
    725  }
    726  int32_t GetContentEnd() const;
    727  // This returns the length the frame thinks it *should* have after it was
    728  // last reflowed (0 if it hasn't been reflowed yet). This should be used only
    729  // when setting up the text offsets for a new continuation frame.
    730  int32_t GetContentLengthHint() const { return mContentLengthHint; }
    731 
    732  // Compute the length of the content mapped by this frame
    733  // and all its in-flow siblings. Basically this means starting at
    734  // mContentOffset and going to the end of the text node or the next bidi
    735  // continuation boundary.
    736  int32_t GetInFlowContentLength();
    737 
    738  /**
    739   * Acquires the text run for this content, if necessary.
    740   * @param aWhichTextRun indicates whether to get an inflated or non-inflated
    741   * text run
    742   * @param aRefDrawTarget the DrawTarget to use as a reference for creating the
    743   * textrun, if available (if not, we'll create one which will just be slower)
    744   * @param aLineContainer the block ancestor for this frame, or nullptr if
    745   * unknown
    746   * @param aFlowEndInTextRun if non-null, this returns the textrun offset of
    747   * end of the text associated with this frame and its in-flow siblings
    748   * @return a gfxSkipCharsIterator set up to map DOM offsets for this frame
    749   * to offsets into the textrun; its initial offset is set to this frame's
    750   * content offset
    751   */
    752  gfxSkipCharsIterator EnsureTextRun(TextRunType aWhichTextRun,
    753                                     DrawTarget* aRefDrawTarget = nullptr,
    754                                     nsIFrame* aLineContainer = nullptr,
    755                                     const LineListIterator* aLine = nullptr,
    756                                     uint32_t* aFlowEndInTextRun = nullptr);
    757 
    758  gfxTextRun* GetTextRun(TextRunType aWhichTextRun) const {
    759    if (aWhichTextRun == eInflated || !HasFontSizeInflation()) {
    760      return mTextRun;
    761    }
    762    return GetUninflatedTextRun();
    763  }
    764  gfxTextRun* GetUninflatedTextRun() const;
    765  void SetTextRun(gfxTextRun* aTextRun, TextRunType aWhichTextRun,
    766                  float aInflation);
    767  bool IsInTextRunUserData() const {
    768    return HasAnyStateBits(TEXT_IN_TEXTRUN_USER_DATA |
    769                           TEXT_IN_UNINFLATED_TEXTRUN_USER_DATA);
    770  }
    771  /**
    772   * Notify the frame that it should drop its pointer to a text run.
    773   * Returns whether the text run was removed (i.e., whether it was
    774   * associated with this frame, either as its inflated or non-inflated
    775   * text run.
    776   */
    777  bool RemoveTextRun(gfxTextRun* aTextRun);
    778  /**
    779   * Clears out |mTextRun| (or the uninflated text run, when aInflated
    780   * is nsTextFrame::eNotInflated and there is inflation) from all frames that
    781   * hold a reference to it, starting at |aStartContinuation|, or if it's
    782   * nullptr, starting at |this|.  Deletes the text run if all references
    783   * were cleared and it's not cached.
    784   */
    785  void ClearTextRun(nsTextFrame* aStartContinuation, TextRunType aWhichTextRun);
    786 
    787  void ClearTextRuns() {
    788    ClearTextRun(nullptr, nsTextFrame::eInflated);
    789    if (HasFontSizeInflation()) {
    790      ClearTextRun(nullptr, nsTextFrame::eNotInflated);
    791    }
    792  }
    793 
    794  /**
    795   * Wipe out references to textrun(s) without deleting the textruns.
    796   */
    797  void DisconnectTextRuns();
    798 
    799  // Get the DOM content range mapped by this frame after excluding
    800  // whitespace subject to start-of-line and end-of-line trimming.
    801  // The textrun must have been created before calling this.
    802  struct TrimmedOffsets {
    803    int32_t mStart;
    804    int32_t mLength;
    805    int32_t GetEnd() const { return mStart + mLength; }
    806  };
    807  enum class TrimmedOffsetFlags : uint8_t {
    808    Default = 0,
    809    NotPostReflow = 1 << 0,
    810    NoTrimAfter = 1 << 1,
    811    NoTrimBefore = 1 << 2
    812  };
    813  TrimmedOffsets GetTrimmedOffsets(
    814      const mozilla::dom::CharacterDataBuffer& aBuffer,
    815      TrimmedOffsetFlags aFlags = TrimmedOffsetFlags::Default) const;
    816 
    817  // Similar to Reflow(), but for use from nsLineLayout
    818  void ReflowText(nsLineLayout& aLineLayout, nscoord aAvailableWidth,
    819                  DrawTarget* aDrawTarget, ReflowOutput& aMetrics,
    820                  nsReflowStatus& aStatus);
    821 
    822  nscoord ComputeLineHeight() const;
    823 
    824  bool IsFloatingFirstLetterChild() const;
    825 
    826  bool IsInitialLetterChild() const;
    827 
    828  bool ComputeCustomOverflow(mozilla::OverflowAreas& aOverflowAreas) final;
    829  bool ComputeCustomOverflowInternal(mozilla::OverflowAreas& aOverflowAreas,
    830                                     bool aIncludeShadows);
    831 
    832  void AssignJustificationGaps(const mozilla::JustificationAssignment& aAssign);
    833  mozilla::JustificationAssignment GetJustificationAssignment() const;
    834 
    835  uint32_t CountGraphemeClusters() const;
    836 
    837  bool HasAnyNoncollapsedCharacters() final;
    838 
    839  /**
    840   * Call this after you have manually changed the text node contents without
    841   * notifying that change.  This behaves as if all the text contents changed.
    842   * (You should only use this for native anonymous content.)
    843   */
    844  void NotifyNativeAnonymousTextnodeChange(uint32_t aOldLength);
    845 
    846  nsFontMetrics* InflatedFontMetrics() const;
    847 
    848  nsRect WebRenderBounds();
    849 
    850  // Find the continuation (which may be this frame itself) containing the
    851  // given offset. Note that this may return null, if the offset is beyond the
    852  // text covered by the continuation chain.
    853  // (To be used only on the first textframe in the chain.)
    854  nsTextFrame* FindContinuationForOffset(int32_t aOffset);
    855 
    856  void SetHangableISize(nscoord aISize);
    857  nscoord GetHangableISize() const;
    858  void ClearHangableISize();
    859 
    860  void SetTrimmableWS(gfxTextRun::TrimmableWS aTrimmableWS);
    861  gfxTextRun::TrimmableWS GetTrimmableWS() const;
    862  void ClearTrimmableWS();
    863 
    864  // Return ShapedTextFlags::TEXT_ENABLE_SPACING if spacing is needed due to
    865  // letter-spacing, word-spacing, etc.
    866  mozilla::gfx::ShapedTextFlags GetSpacingFlags() const;
    867 
    868 protected:
    869  virtual ~nsTextFrame();
    870 
    871  friend class mozilla::nsDisplayTextGeometry;
    872  friend class mozilla::nsDisplayText;
    873 
    874  mutable RefPtr<nsFontMetrics> mFontMetrics;
    875  RefPtr<gfxTextRun> mTextRun;
    876  nsTextFrame* mNextContinuation = nullptr;
    877  // The key invariant here is that mContentOffset never decreases along
    878  // a next-continuation chain. And of course mContentOffset is always <= the
    879  // the text node's content length, and the mContentOffset for the first frame
    880  // is always 0. Furthermore the text mapped by a frame is determined by
    881  // GetContentOffset() and GetContentLength()/GetContentEnd(), which get
    882  // the length from the difference between this frame's offset and the next
    883  // frame's offset, or the text length if there is no next frame. This means
    884  // the frames always map the text node without overlapping or leaving any
    885  // gaps.
    886  int32_t mContentOffset = 0;
    887  // This does *not* indicate the length of text currently mapped by the frame;
    888  // instead it's a hint saying that this frame *wants* to map this much text
    889  // so if we create a new continuation, this is where that continuation should
    890  // start.
    891  int32_t mContentLengthHint = 0;
    892  nscoord mAscent = 0;
    893 
    894  // Cached selection state.
    895  enum class SelectionState : uint8_t {
    896    Unknown,
    897    Selected,
    898    NotSelected,
    899  };
    900  mutable SelectionState mIsSelected = SelectionState::Unknown;
    901 
    902  // Flags used to track whether certain properties are present.
    903  // (Public to keep MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS happy.)
    904 public:
    905  enum class PropertyFlags : uint8_t {
    906    // Whether a cached continuations array is present.
    907    Continuations = 1 << 0,
    908    // Whether a HangableWhitespace property is present.
    909    HangableWS = 1 << 1,
    910    // Whether a TrimmableWhitespace property is present.
    911    TrimmableWS = 2 << 1,
    912  };
    913 
    914 protected:
    915  PropertyFlags mPropertyFlags = PropertyFlags(0);
    916 
    917  /**
    918   * Return true if the frame is part of a Selection.
    919   * Helper method to implement the public IsSelected() API.
    920   */
    921  bool IsFrameSelected() const final;
    922 
    923  void InvalidateSelectionState() { mIsSelected = SelectionState::Unknown; }
    924 
    925  mozilla::UniquePtr<SelectionDetails> GetSelectionDetails();
    926 
    927  void UnionAdditionalOverflow(nsPresContext* aPresContext, nsIFrame* aBlock,
    928                               PropertyProvider& aProvider,
    929                               nsRect* aInkOverflowRect,
    930                               bool aIncludeTextDecorations,
    931                               bool aIncludeShadows);
    932 
    933  // Update information of emphasis marks, and return the visial
    934  // overflow rect of the emphasis marks.
    935  nsRect UpdateTextEmphasis(mozilla::WritingMode aWM,
    936                            PropertyProvider& aProvider);
    937 
    938  void PaintOneShadow(const PaintShadowParams& aParams,
    939                      const mozilla::StyleSimpleShadow& aShadowDetails,
    940                      gfxRect& aBoundingBox, uint32_t aBlurFlags);
    941 
    942  void PaintShadows(mozilla::Span<const mozilla::StyleSimpleShadow>,
    943                    const PaintShadowParams& aParams);
    944 
    945  struct LineDecoration {
    946    nsIFrame* const mFrame;
    947 
    948    // This is represents the offset from our baseline to mFrame's baseline;
    949    // positive offsets are *above* the baseline and negative offsets below
    950    const nscoord mBaselineOffset;
    951 
    952    // This represents the offset from the initial position of the underline
    953    const mozilla::LengthPercentageOrAuto mTextUnderlineOffset;
    954 
    955    // for CSS property text-decoration-thickness, the width refers to the
    956    // thickness of the decoration line
    957    const mozilla::StyleTextDecorationLength mTextDecorationThickness;
    958    const nscolor mColor;
    959    const mozilla::StyleTextDecorationStyle mStyle;
    960 
    961    // The text-underline-position property; affects the underline offset only
    962    // if mTextUnderlineOffset is auto.
    963    const mozilla::StyleTextUnderlinePosition mTextUnderlinePosition;
    964 
    965    const bool mAllowInkSkipping;
    966 
    967    LineDecoration(nsIFrame* const aFrame, const nscoord aOff,
    968                   const mozilla::StyleTextUnderlinePosition aUnderlinePosition,
    969                   const mozilla::LengthPercentageOrAuto& aUnderlineOffset,
    970                   const mozilla::StyleTextDecorationLength& aDecThickness,
    971                   const nscolor aColor,
    972                   const mozilla::StyleTextDecorationStyle aStyle,
    973                   const bool aAllowInkSkipping)
    974        : mFrame(aFrame),
    975          mBaselineOffset(aOff),
    976          mTextUnderlineOffset(aUnderlineOffset),
    977          mTextDecorationThickness(aDecThickness),
    978          mColor(aColor),
    979          mStyle(aStyle),
    980          mTextUnderlinePosition(aUnderlinePosition),
    981          mAllowInkSkipping(aAllowInkSkipping) {}
    982 
    983    LineDecoration(const LineDecoration& aOther) = default;
    984 
    985    bool operator==(const LineDecoration& aOther) const = default;
    986    bool operator!=(const LineDecoration& aOther) const = default;
    987  };
    988  struct TextDecorations {
    989    AutoTArray<LineDecoration, 1> mOverlines, mUnderlines, mStrikes;
    990 
    991    TextDecorations() = default;
    992 
    993    bool HasDecorationLines() const {
    994      return HasUnderline() || HasOverline() || HasStrikeout();
    995    }
    996    bool HasUnderline() const { return !mUnderlines.IsEmpty(); }
    997    bool HasOverline() const { return !mOverlines.IsEmpty(); }
    998    bool HasStrikeout() const { return !mStrikes.IsEmpty(); }
    999    bool operator==(const TextDecorations& aOther) const = default;
   1000    bool operator!=(const TextDecorations& aOther) const = default;
   1001  };
   1002  enum TextDecorationColorResolution { eResolvedColors, eUnresolvedColors };
   1003  void GetTextDecorations(nsPresContext* aPresContext,
   1004                          TextDecorationColorResolution aColorResolution,
   1005                          TextDecorations& aDecorations);
   1006 
   1007  void DrawTextRun(Range aRange, const mozilla::gfx::Point& aTextBaselinePt,
   1008                   const DrawTextRunParams& aParams);
   1009 
   1010  void DrawTextRunAndDecorations(Range aRange,
   1011                                 const mozilla::gfx::Point& aTextBaselinePt,
   1012                                 const DrawTextParams& aParams,
   1013                                 const TextDecorations& aDecorations);
   1014 
   1015  void DrawText(Range aRange, const mozilla::gfx::Point& aTextBaselinePt,
   1016                const DrawTextParams& aParams);
   1017 
   1018  // Set non empty rect to aRect, it should be overflow rect or frame rect.
   1019  // If the result rect is larger than the given rect, this returns true.
   1020  bool CombineSelectionUnderlineRect(nsPresContext* aPresContext,
   1021                                     nsRect& aRect);
   1022 
   1023  // This sets *aShadows to the appropriate shadows, if any, for the given
   1024  // type of selection.
   1025  // If text-shadow was not specified, *aShadows is left untouched.
   1026  // Note that the returned shadow(s) will only be valid as long as the
   1027  // textPaintStyle remains in scope.
   1028  void GetSelectionTextShadow(
   1029      SelectionType aSelectionType, nsTextPaintStyle& aTextPaintStyle,
   1030      mozilla::Span<const mozilla::StyleSimpleShadow>* aShadows);
   1031 
   1032  /**
   1033   * Utility methods to paint selection.
   1034   */
   1035  void DrawSelectionDecorations(
   1036      gfxContext* aContext, const LayoutDeviceRect& aDirtyRect,
   1037      mozilla::SelectionType aSelectionType, nsAtom* aHighlightName,
   1038      nsTextPaintStyle& aTextPaintStyle, const TextRangeStyle& aRangeStyle,
   1039      const Point& aPt, gfxFloat aICoordInFrame, gfxFloat aWidth,
   1040      gfxFloat aAscent, const gfxFont::Metrics& aFontMetrics,
   1041      DrawPathCallbacks* aCallbacks, bool aVertical,
   1042      mozilla::StyleTextDecorationLine aDecoration, const Range& aGlyphRange,
   1043      PropertyProvider* aProvider);
   1044 
   1045  void PaintDecorationLine(const PaintDecorationLineParams& aParams);
   1046  /**
   1047   * ComputeDescentLimitForSelectionUnderline() computes the most far position
   1048   * where we can put selection underline.
   1049   *
   1050   * @return The maximum underline offset from the baseline (positive value
   1051   *         means that the underline can put below the baseline).
   1052   */
   1053  gfxFloat ComputeDescentLimitForSelectionUnderline(
   1054      nsPresContext* aPresContext, const gfxFont::Metrics& aFontMetrics);
   1055  /**
   1056   * This function encapsulates all knowledge of how selections affect
   1057   * foreground and background colors.
   1058   * @param aForeground the foreground color to use
   1059   * @param aBackground the background color to use, or RGBA(0,0,0,0) if no
   1060   *                    background should be painted
   1061   * @return            true if the selection affects colors, false otherwise
   1062   */
   1063  static bool GetSelectionTextColors(SelectionType aSelectionType,
   1064                                     nsAtom* aHighlightName,
   1065                                     nsTextPaintStyle& aTextPaintStyle,
   1066                                     const TextRangeStyle& aRangeStyle,
   1067                                     nscolor* aForeground,
   1068                                     nscolor* aBackground);
   1069  /**
   1070   * ComputeSelectionUnderlineHeight() computes selection underline height of
   1071   * the specified selection type from the font metrics.
   1072   */
   1073  static gfxFloat ComputeSelectionUnderlineHeight(
   1074      nsPresContext* aPresContext, const gfxFont::Metrics& aFontMetrics,
   1075      SelectionType aSelectionType);
   1076 
   1077  /**
   1078   * @brief Helper struct which contains selection data such as its details,
   1079   * range and priority.
   1080   */
   1081  struct SelectionRange {
   1082    const SelectionDetails* mDetails{nullptr};
   1083    gfxTextRun::Range mRange;
   1084    /// used to determine the order of overlapping selections of the same type.
   1085    uint32_t mPriority{0};
   1086  };
   1087  /**
   1088   * @brief Helper: Extracts a list of `SelectionRange` structs from given
   1089   * `SelectionDetails` and computes a priority for overlapping selection
   1090   * ranges.
   1091   */
   1092  static SelectionTypeMask CreateSelectionRangeList(
   1093      const SelectionDetails* aDetails, SelectionType aSelectionType,
   1094      const PaintTextSelectionParams& aParams,
   1095      nsTArray<SelectionRange>& aSelectionRanges, bool* aAnyBackgrounds);
   1096 
   1097  /**
   1098   * @brief Creates an array of `CombinedSelectionRange`s from given list
   1099   * of `SelectionRange`s.
   1100   * Each instance of `CombinedSelectionRange` represents a piece of text with
   1101   * constant Selections.
   1102   *
   1103   * Example:
   1104   *
   1105   * Consider this text fragment, [] and () marking selection ranges:
   1106   *   ab[cd(e]f)g
   1107   * This results in the following array of combined ranges:
   1108   *  - [0]: range: (2, 4), selections: "[]"
   1109   *  - [1]: range: (4, 5), selections: "[]", "()"
   1110   *  - [2]: range: (5, 6), selections: "()"
   1111   * Depending on the priorities of the ranges, [1] may have a different order
   1112   * of its ranges. The given example indicates that "()" has a higher priority
   1113   * than "[]".
   1114   *
   1115   * @param aSelectionRanges         Array of `SelectionRange` objects. Must be
   1116   *                                 sorted by the start offset.
   1117   * @param aCombinedSelectionRanges Out parameter. Returns the constructed
   1118   *                                 array of combined selection ranges.
   1119   */
   1120  static void CombineSelectionRanges(
   1121      const nsTArray<SelectionRange>& aSelectionRanges,
   1122      nsTArray<PriorityOrderedSelectionsForRange>& aCombinedSelectionRanges);
   1123 
   1124  ContentOffsets GetCharacterOffsetAtFramePointInternal(
   1125      const nsPoint& aPoint, bool aForInsertionPoint);
   1126 
   1127  float GetTextCombineScale() const;
   1128  std::pair<nscoord, float> GetTextCombineOffsetAndScale() const;
   1129 
   1130  void ClearFrameOffsetCache();
   1131 
   1132  void ClearMetrics(ReflowOutput& aMetrics);
   1133 
   1134  // Return pointer to an array of all frames in the continuation chain, or
   1135  // null if we're too short of memory.
   1136  nsTArray<nsTextFrame*>* GetContinuations();
   1137 
   1138  // Clear any cached continuations array; this should be called whenever the
   1139  // chain is modified.
   1140  inline void ClearCachedContinuations();
   1141 
   1142  /**
   1143   * UpdateIteratorFromOffset() updates the iterator from a given offset.
   1144   * Also, aInOffset may be updated to cluster start if aInOffset isn't
   1145   * the offset of cluster start.
   1146   */
   1147  void UpdateIteratorFromOffset(const PropertyProvider& aProperties,
   1148                                int32_t& aInOffset,
   1149                                gfxSkipCharsIterator& aIter);
   1150 
   1151  nsPoint GetPointFromIterator(const gfxSkipCharsIterator& aIter,
   1152                               PropertyProvider& aProperties);
   1153 
   1154  /**
   1155   * Return the content offset of the first preserved newline in this frame,
   1156   * or return -1 if no preserved NL.
   1157   */
   1158  struct NewlineProperty;
   1159  int32_t GetContentNewLineOffset(int32_t aOffset,
   1160                                  NewlineProperty*& aCachedNewlineOffset);
   1161 
   1162  void MaybeSplitFramesForFirstLetter();
   1163  void SetFirstLetterLength(int32_t aLength);
   1164 
   1165  struct AppendRenderedTextState {
   1166    // Inputs, constant across all calls in the loop.
   1167    const uint32_t mStartOffset;
   1168    const uint32_t mEndOffset;
   1169    const TextOffsetType mOffsetType;
   1170    const TrailingWhitespace mTrimTrailingWhitespace;
   1171    const mozilla::dom::CharacterDataBuffer& mCharacterDataBuffer;
   1172    // Mutable state, updated as we loop over the continuations.
   1173    nsBlockFrame* mLineContainer = nullptr;
   1174    uint32_t mOffsetInRenderedString = 0;
   1175    bool mHaveOffsets = false;
   1176  };
   1177  // Helper for GetRenderedText, to process one frame in the continuation
   1178  // chain. Returns true if the caller should continue to loop over the
   1179  // following frames, or false to stop.
   1180  bool AppendRenderedText(AppendRenderedTextState& aState,
   1181                          RenderedText& aResult);
   1182 };
   1183 
   1184 MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(nsTextFrame::TrimmedOffsetFlags)
   1185 MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(nsTextFrame::PropertyFlags)
   1186 
   1187 inline void nsTextFrame::ClearCachedContinuations() {
   1188  MOZ_ASSERT(NS_IsMainThread());
   1189  if (mPropertyFlags & PropertyFlags::Continuations) {
   1190    RemoveProperty(ContinuationsProperty());
   1191    mPropertyFlags &= ~PropertyFlags::Continuations;
   1192  }
   1193 }
   1194 
   1195 #endif