Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/layout/generic/nsTextFrame.h
Line
Count
Source (jump to first uncovered line)
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 "mozilla/Attributes.h"
11
#include "mozilla/EventForwards.h"
12
#include "mozilla/gfx/2D.h"
13
#include "mozilla/UniquePtr.h"
14
#include "mozilla/dom/CharacterData.h"
15
#include "nsFrame.h"
16
#include "nsFrameSelection.h"
17
#include "nsSplittableFrame.h"
18
#include "nsLineBox.h"
19
#include "gfxSkipChars.h"
20
#include "gfxTextRun.h"
21
#include "nsDisplayList.h"
22
#include "JustificationUtils.h"
23
#include "RubyUtils.h"
24
25
// Undo the windows.h damage
26
#if defined(XP_WIN) && defined(DrawText)
27
#undef DrawText
28
#endif
29
30
class nsTextPaintStyle;
31
class PropertyProvider;
32
struct SelectionDetails;
33
class nsTextFragment;
34
35
class nsDisplayTextGeometry;
36
class nsDisplayText;
37
38
namespace mozilla {
39
class SVGContextPaint;
40
};
41
42
class nsTextFrame : public nsFrame
43
{
44
  typedef mozilla::LayoutDeviceRect LayoutDeviceRect;
45
  typedef mozilla::SelectionTypeMask SelectionTypeMask;
46
  typedef mozilla::SelectionType SelectionType;
47
  typedef mozilla::TextRangeStyle TextRangeStyle;
48
  typedef mozilla::gfx::DrawTarget DrawTarget;
49
  typedef mozilla::gfx::Point Point;
50
  typedef mozilla::gfx::Rect Rect;
51
  typedef mozilla::gfx::Size Size;
52
  typedef gfxTextRun::Range Range;
53
54
public:
55
  explicit nsTextFrame(ComputedStyle* aStyle, ClassID aID = kClassID)
56
    : nsFrame(aStyle, aID)
57
    , mNextContinuation(nullptr)
58
    , mContentOffset(0)
59
    , mContentLengthHint(0)
60
    , mAscent(0)
61
0
  {}
62
63
  NS_DECL_FRAMEARENA_HELPERS(nsTextFrame)
64
65
  friend class nsContinuingTextFrame;
66
  friend class nsDisplayTextGeometry;
67
  friend class nsDisplayText;
68
69
  // nsQueryFrame
70
  NS_DECL_QUERYFRAME
71
72
  // nsIFrame
73
  void BuildDisplayList(nsDisplayListBuilder* aBuilder,
74
                        const nsDisplayListSet& aLists) override;
75
76
  void Init(nsIContent* aContent,
77
            nsContainerFrame* aParent,
78
            nsIFrame* aPrevInFlow) override;
79
80
  void DestroyFrom(nsIFrame* aDestructRoot, PostDestroyData& aPostDestroyData) override;
81
82
  nsresult GetCursor(const nsPoint& aPoint, nsIFrame::Cursor& aCursor) override;
83
84
  nsresult CharacterDataChanged(const CharacterDataChangeInfo&) final;
85
86
0
  nsTextFrame* GetPrevContinuation() const override { return nullptr; }
87
0
  nsTextFrame* GetNextContinuation() const final { return mNextContinuation; }
88
  void SetNextContinuation(nsIFrame* aNextContinuation) final
89
0
  {
90
0
    NS_ASSERTION(!aNextContinuation || Type() == aNextContinuation->Type(),
91
0
                 "setting a next continuation with incorrect type!");
92
0
    NS_ASSERTION(
93
0
      !nsSplittableFrame::IsInNextContinuationChain(aNextContinuation, this),
94
0
      "creating a loop in continuation chain!");
95
0
    mNextContinuation = static_cast<nsTextFrame*>(aNextContinuation);
96
0
    if (aNextContinuation)
97
0
      aNextContinuation->RemoveStateBits(NS_FRAME_IS_FLUID_CONTINUATION);
98
0
    // Setting a non-fluid continuation might affect our flow length (they're
99
0
    // quite rare so we assume it always does) so we delete our cached value:
100
0
    if (GetContent()->HasFlag(NS_HAS_FLOWLENGTH_PROPERTY)) {
101
0
      GetContent()->DeleteProperty(nsGkAtoms::flowlength);
102
0
      GetContent()->UnsetFlags(NS_HAS_FLOWLENGTH_PROPERTY);
103
0
    }
104
0
  }
105
0
  nsIFrame* GetNextInFlowVirtual() const override { return GetNextInFlow(); }
106
  nsTextFrame* GetNextInFlow() const
107
0
  {
108
0
    return mNextContinuation &&
109
0
               (mNextContinuation->GetStateBits() &
110
0
                NS_FRAME_IS_FLUID_CONTINUATION)
111
0
             ? mNextContinuation
112
0
             : nullptr;
113
0
  }
114
  void SetNextInFlow(nsIFrame* aNextInFlow) final
115
0
  {
116
0
    NS_ASSERTION(!aNextInFlow || Type() == aNextInFlow->Type(),
117
0
                 "setting a next in flow with incorrect type!");
118
0
    NS_ASSERTION(
119
0
      !nsSplittableFrame::IsInNextContinuationChain(aNextInFlow, this),
120
0
      "creating a loop in continuation chain!");
121
0
    mNextContinuation = static_cast<nsTextFrame*>(aNextInFlow);
122
0
    if (mNextContinuation &&
123
0
        !mNextContinuation->HasAnyStateBits(NS_FRAME_IS_FLUID_CONTINUATION)) {
124
0
      // Changing from non-fluid to fluid continuation might affect our flow
125
0
      // length, so we delete our cached value:
126
0
      if (GetContent()->HasFlag(NS_HAS_FLOWLENGTH_PROPERTY)) {
127
0
        GetContent()->DeleteProperty(nsGkAtoms::flowlength);
128
0
        GetContent()->UnsetFlags(NS_HAS_FLOWLENGTH_PROPERTY);
129
0
      }
130
0
    }
131
0
    if (aNextInFlow) {
132
0
      aNextInFlow->AddStateBits(NS_FRAME_IS_FLUID_CONTINUATION);
133
0
    }
134
0
  }
135
  nsTextFrame* LastInFlow() const final;
136
  nsTextFrame* LastContinuation() const final;
137
138
  nsSplittableType GetSplittableType() const final
139
0
  {
140
0
    return NS_FRAME_SPLITTABLE;
141
0
  }
142
143
  bool IsFrameOfType(uint32_t aFlags) const final
144
0
  {
145
0
    // Set the frame state bit for text frames to mark them as replaced.
146
0
    // XXX kipp: temporary
147
0
    return nsFrame::IsFrameOfType(
148
0
      aFlags & ~(nsIFrame::eReplaced | nsIFrame::eLineParticipant));
149
0
  }
150
151
  bool ShouldSuppressLineBreak() const
152
0
  {
153
0
    // If the parent frame of the text frame is ruby content box, it must
154
0
    // suppress line break inside. This check is necessary, because when
155
0
    // a whitespace is only contained by pseudo ruby frames, its style
156
0
    // context won't have SuppressLineBreak bit set.
157
0
    if (mozilla::RubyUtils::IsRubyContentBox(GetParent()->Type())) {
158
0
      return true;
159
0
    }
160
0
    return Style()->ShouldSuppressLineBreak();
161
0
  }
162
163
  void InvalidateFrame(uint32_t aDisplayItemKey = 0, bool aRebuildDisplayItems = true) override;
164
  void InvalidateFrameWithRect(const nsRect& aRect,
165
                               uint32_t aDisplayItemKey = 0,
166
                               bool aRebuildDisplayItems = true) override;
167
168
#ifdef DEBUG_FRAME_DUMP
169
  void List(FILE* out = stderr,
170
            const char* aPrefix = "",
171
            uint32_t aFlags = 0) const override;
172
  nsresult GetFrameName(nsAString& aResult) const override;
173
  void ToCString(nsCString& aBuf, int32_t* aTotalContentLength) const;
174
#endif
175
176
  ContentOffsets CalcContentOffsetsFromFramePoint(const nsPoint& aPoint) override;
177
  ContentOffsets GetCharacterOffsetAtFramePoint(const nsPoint& aPoint);
178
179
  /**
180
   * This is called only on the primary text frame. It indicates that
181
   * the selection state of the given character range has changed.
182
   * Text in the range is unconditionally invalidated
183
   * (Selection::Repaint depends on this).
184
   * @param aSelected true if the selection has been added to the range,
185
   * false otherwise
186
   * @param aType the type of selection added or removed
187
   */
188
  void SetSelectedRange(uint32_t aStart,
189
                        uint32_t aEnd,
190
                        bool aSelected,
191
                        SelectionType aSelectionType);
192
193
  FrameSearchResult PeekOffsetNoAmount(bool aForward,
194
                                       int32_t* aOffset) override;
195
  FrameSearchResult
196
  PeekOffsetCharacter(bool aForward,
197
                      int32_t* aOffset,
198
                      PeekOffsetCharacterOptions aOptions =
199
                        PeekOffsetCharacterOptions()) override;
200
  FrameSearchResult PeekOffsetWord(bool aForward,
201
                                   bool aWordSelectEatSpace,
202
                                   bool aIsKeyboardSelect,
203
                                   int32_t* aOffset,
204
                                   PeekWordState* aState) override;
205
206
  nsresult CheckVisibility(nsPresContext* aContext,
207
                           int32_t aStartIndex,
208
                           int32_t aEndIndex,
209
                           bool aRecurse,
210
                           bool* aFinished,
211
                           bool* _retval) override;
212
213
  // Flags for aSetLengthFlags
214
  enum
215
  {
216
    ALLOW_FRAME_CREATION_AND_DESTRUCTION = 0x01
217
  };
218
219
  // Update offsets to account for new length. This may clear mTextRun.
220
  void SetLength(int32_t aLength,
221
                 nsLineLayout* aLineLayout,
222
                 uint32_t aSetLengthFlags = 0);
223
224
  nsresult GetOffsets(int32_t& start, int32_t& end) const override;
225
226
  void AdjustOffsetsForBidi(int32_t start, int32_t end) override;
227
228
  nsresult GetPointFromOffset(int32_t inOffset, nsPoint* outPoint) override;
229
  nsresult GetCharacterRectsInRange(int32_t aInOffset,
230
                                    int32_t aLength,
231
                                    nsTArray<nsRect>& aRects) override;
232
233
  nsresult GetChildFrameContainingOffset(int32_t inContentOffset,
234
                                         bool inHint,
235
                                         int32_t* outFrameContentOffset,
236
                                         nsIFrame** outChildFrame) override;
237
238
  bool IsVisibleInSelection(mozilla::dom::Selection* aSelection) override;
239
240
  bool IsEmpty() override;
241
0
  bool IsSelfEmpty() override { return IsEmpty(); }
242
  nscoord GetLogicalBaseline(mozilla::WritingMode aWritingMode) const final;
243
244
  bool HasSignificantTerminalNewline() const override;
245
246
  /**
247
   * Returns true if this text frame is logically adjacent to the end of the
248
   * line.
249
   */
250
  bool IsAtEndOfLine() const;
251
252
  /**
253
   * Call this only after reflow the frame. Returns true if non-collapsed
254
   * characters are present.
255
   */
256
  bool HasNoncollapsedCharacters() const
257
0
  {
258
0
    return (GetStateBits() & TEXT_HAS_NONCOLLAPSED_CHARACTERS) != 0;
259
0
  }
260
261
#ifdef ACCESSIBILITY
262
  mozilla::a11y::AccType AccessibleType() override;
263
#endif
264
265
  float GetFontSizeInflation() const;
266
  bool IsCurrentFontInflation(float aInflation) const;
267
  bool HasFontSizeInflation() const
268
0
  {
269
0
    return (GetStateBits() & TEXT_HAS_FONT_INFLATION) != 0;
270
0
  }
271
  void SetFontSizeInflation(float aInflation);
272
273
  void MarkIntrinsicISizesDirty() override;
274
  nscoord GetMinISize(gfxContext* aRenderingContext) override;
275
  nscoord GetPrefISize(gfxContext* aRenderingContext) override;
276
  void AddInlineMinISize(gfxContext* aRenderingContext,
277
                         InlineMinISizeData* aData) override;
278
  void AddInlinePrefISize(gfxContext* aRenderingContext,
279
                          InlinePrefISizeData* aData) override;
280
  mozilla::LogicalSize ComputeSize(gfxContext* aRenderingContext,
281
                                   mozilla::WritingMode aWritingMode,
282
                                   const mozilla::LogicalSize& aCBSize,
283
                                   nscoord aAvailableISize,
284
                                   const mozilla::LogicalSize& aMargin,
285
                                   const mozilla::LogicalSize& aBorder,
286
                                   const mozilla::LogicalSize& aPadding,
287
                                   ComputeSizeFlags aFlags) override;
288
  nsRect ComputeTightBounds(DrawTarget* aDrawTarget) const override;
289
  nsresult GetPrefWidthTightBounds(gfxContext* aContext,
290
                                   nscoord* aX,
291
                                   nscoord* aXMost) override;
292
  void Reflow(nsPresContext* aPresContext,
293
              ReflowOutput& aMetrics,
294
              const ReflowInput& aReflowInput,
295
              nsReflowStatus& aStatus) override;
296
  bool CanContinueTextRun() const override;
297
  // Method that is called for a text frame that is logically
298
  // adjacent to the end of the line (i.e. followed only by empty text frames,
299
  // placeholders or inlines containing such).
300
  struct TrimOutput
301
  {
302
    // true if we trimmed some space or changed metrics in some other way.
303
    // In this case, we should call RecomputeOverflow on this frame.
304
    bool mChanged;
305
    // an amount to *subtract* from the frame's width (zero if !mChanged)
306
    nscoord mDeltaWidth;
307
  };
308
  TrimOutput TrimTrailingWhiteSpace(DrawTarget* aDrawTarget);
309
  RenderedText GetRenderedText(
310
    uint32_t aStartOffset = 0,
311
    uint32_t aEndOffset = UINT32_MAX,
312
    TextOffsetType aOffsetType = TextOffsetType::OFFSETS_IN_CONTENT_TEXT,
313
    TrailingWhitespace aTrimTrailingWhitespace =
314
      TrailingWhitespace::TRIM_TRAILING_WHITESPACE) override;
315
316
  nsOverflowAreas RecomputeOverflow(nsIFrame* aBlockFrame);
317
318
  enum TextRunType
319
  {
320
    // Anything in reflow (but not intrinsic width calculation) or
321
    // painting should use the inflated text run (i.e., with font size
322
    // inflation applied).
323
    eInflated,
324
    // Intrinsic width calculation should use the non-inflated text run.
325
    // When there is font size inflation, it will be different.
326
    eNotInflated
327
  };
328
329
  void AddInlineMinISizeForFlow(gfxContext* aRenderingContext,
330
                                nsIFrame::InlineMinISizeData* aData,
331
                                TextRunType aTextRunType);
332
  void AddInlinePrefISizeForFlow(gfxContext* aRenderingContext,
333
                                 InlinePrefISizeData* aData,
334
                                 TextRunType aTextRunType);
335
336
  /**
337
   * Calculate the horizontal bounds of the grapheme clusters that fit entirely
338
   * inside the given left[top]/right[bottom] edges (which are positive lengths
339
   * from the respective frame edge).  If an input value is zero it is ignored
340
   * and the result for that edge is zero.  All out parameter values are
341
   * undefined when the method returns false.
342
   * @return true if at least one whole grapheme cluster fit between the edges
343
   */
344
  bool MeasureCharClippedText(nscoord aVisIStartEdge,
345
                              nscoord aVisIEndEdge,
346
                              nscoord* aSnappedStartEdge,
347
                              nscoord* aSnappedEndEdge);
348
  /**
349
   * Same as above; this method also the returns the corresponding text run
350
   * offset and number of characters that fit.  All out parameter values are
351
   * undefined when the method returns false.
352
   * @return true if at least one whole grapheme cluster fit between the edges
353
   */
354
  bool MeasureCharClippedText(PropertyProvider& aProvider,
355
                              nscoord aVisIStartEdge,
356
                              nscoord aVisIEndEdge,
357
                              uint32_t* aStartOffset,
358
                              uint32_t* aMaxLength,
359
                              nscoord* aSnappedStartEdge,
360
                              nscoord* aSnappedEndEdge);
361
362
  /**
363
   * Return true if this box has some text to display.
364
   * It returns false if at least one of these conditions are met:
365
   * a. the frame hasn't been reflowed yet
366
   * b. GetContentLength() == 0
367
   * c. it contains only non-significant white-space
368
   */
369
  bool HasNonSuppressedText();
370
371
  /**
372
   * Object with various callbacks for PaintText() to invoke for different parts
373
   * of the frame's text rendering, when we're generating paths rather than
374
   * painting.
375
   *
376
   * Callbacks are invoked in the following order:
377
   *
378
   *   NotifySelectionBackgroundNeedsFill?
379
   *   PaintDecorationLine*
380
   *   NotifyBeforeText
381
   *   NotifyGlyphPathEmitted*
382
   *   NotifyAfterText
383
   *   PaintDecorationLine*
384
   *   PaintSelectionDecorationLine*
385
   *
386
   * The color of each part of the frame's text rendering is passed as an argument
387
   * to the NotifyBefore* callback for that part.  The nscolor can take on one of
388
   * the three selection special colors defined in LookAndFeel.h --
389
   * NS_TRANSPARENT, NS_SAME_AS_FOREGROUND_COLOR and
390
   * NS_40PERCENT_FOREGROUND_COLOR.
391
   */
392
  struct DrawPathCallbacks : gfxTextRunDrawCallbacks
393
  {
394
    /**
395
     * @param aShouldPaintSVGGlyphs Whether SVG glyphs should be painted.
396
     */
397
    explicit DrawPathCallbacks(bool aShouldPaintSVGGlyphs = false)
398
      : gfxTextRunDrawCallbacks(aShouldPaintSVGGlyphs)
399
0
    {}
400
401
    /**
402
     * Called to have the selection highlight drawn before the text is drawn
403
     * over the top.
404
     */
405
    virtual void NotifySelectionBackgroundNeedsFill(const Rect& aBackgroundRect,
406
                                                    nscolor aColor,
407
                                                    DrawTarget& aDrawTarget)
408
0
    {}
409
410
    /**
411
     * Called before (for under/over-line) or after (for line-through) the text
412
     * is drawn to have a text decoration line drawn.
413
     */
414
0
    virtual void PaintDecorationLine(Rect aPath, nscolor aColor) {}
415
416
    /**
417
     * Called after selected text is drawn to have a decoration line drawn over
418
     * the text. (All types of text decoration are drawn after the text when
419
     * text is selected.)
420
     */
421
0
    virtual void PaintSelectionDecorationLine(Rect aPath, nscolor aColor) {}
422
423
    /**
424
     * Called just before any paths have been emitted to the gfxContext
425
     * for the glyphs of the frame's text.
426
     */
427
0
    virtual void NotifyBeforeText(nscolor aColor) {}
428
429
    /**
430
     * Called just after all the paths have been emitted to the gfxContext
431
     * for the glyphs of the frame's text.
432
     */
433
0
    virtual void NotifyAfterText() {}
434
435
    /**
436
     * Called just before a path corresponding to a selection decoration line
437
     * has been emitted to the gfxContext.
438
     */
439
0
    virtual void NotifyBeforeSelectionDecorationLine(nscolor aColor) {}
440
441
    /**
442
     * Called just after a path corresponding to a selection decoration line
443
     * has been emitted to the gfxContext.
444
     */
445
0
    virtual void NotifySelectionDecorationLinePathEmitted() {}
446
  };
447
448
  struct PaintTextParams
449
  {
450
    gfxContext* context;
451
    mozilla::gfx::Point framePt;
452
    LayoutDeviceRect dirtyRect;
453
    mozilla::SVGContextPaint* contextPaint = nullptr;
454
    DrawPathCallbacks* callbacks = nullptr;
455
    enum
456
    {
457
      PaintText,        // Normal text painting.
458
      PaintTextBGColor, // Only paint background color of the selected text
459
                        // range in this state.
460
      GenerateTextMask  // To generate a mask from a text frame. Should
461
                        // only paint text itself with opaque color.
462
                        // Text shadow, text selection color and text
463
                        // decoration are all discarded in this state.
464
    };
465
    uint8_t state = PaintText;
466
    explicit PaintTextParams(gfxContext* aContext)
467
      : context(aContext)
468
0
    {
469
0
    }
470
471
0
    bool IsPaintText() const { return state == PaintText; }
472
0
    bool IsGenerateTextMask() const { return state == GenerateTextMask; }
473
0
    bool IsPaintBGColor() const { return state == PaintTextBGColor; }
474
  };
475
476
  struct PaintTextSelectionParams : PaintTextParams
477
  {
478
    mozilla::gfx::Point textBaselinePt;
479
    PropertyProvider* provider = nullptr;
480
    Range contentRange;
481
    nsTextPaintStyle* textPaintStyle = nullptr;
482
    explicit PaintTextSelectionParams(const PaintTextParams& aParams)
483
      : PaintTextParams(aParams)
484
0
    {}
485
  };
486
487
  struct DrawTextRunParams
488
  {
489
    gfxContext* context;
490
    PropertyProvider* provider = nullptr;
491
    gfxFloat* advanceWidth = nullptr;
492
    mozilla::SVGContextPaint* contextPaint = nullptr;
493
    DrawPathCallbacks* callbacks = nullptr;
494
    nscolor textColor = NS_RGBA(0, 0, 0, 0);
495
    nscolor textStrokeColor = NS_RGBA(0, 0, 0, 0);
496
    float textStrokeWidth = 0.0f;
497
    bool drawSoftHyphen = false;
498
    explicit DrawTextRunParams(gfxContext* aContext)
499
      : context(aContext)
500
0
    {}
501
  };
502
503
  struct DrawTextParams : DrawTextRunParams
504
  {
505
    mozilla::gfx::Point framePt;
506
    LayoutDeviceRect dirtyRect;
507
    const nsTextPaintStyle* textStyle = nullptr;
508
    const nsCharClipDisplayItem::ClipEdges* clipEdges = nullptr;
509
    const nscolor* decorationOverrideColor = nullptr;
510
    explicit DrawTextParams(gfxContext* aContext)
511
      : DrawTextRunParams(aContext)
512
0
    {}
513
  };
514
515
  // Primary frame paint method called from nsDisplayText.  Can also be used
516
  // to generate paths rather than paint the frame's text by passing a callback
517
  // object.  The private DrawText() is what applies the text to a graphics
518
  // context.
519
  void PaintText(const PaintTextParams& aParams,
520
                 const nsCharClipDisplayItem& aItem,
521
                 float aOpacity = 1.0f);
522
  // helper: paint text frame when we're impacted by at least one selection.
523
  // Return false if the text was not painted and we should continue with
524
  // the fast path.
525
  bool PaintTextWithSelection(
526
    const PaintTextSelectionParams& aParams,
527
    const nsCharClipDisplayItem::ClipEdges& aClipEdges);
528
  // helper: paint text with foreground and background colors determined
529
  // by selection(s). Also computes a mask of all selection types applying to
530
  // our text, returned in aAllSelectionTypeMask.
531
  // Return false if the text was not painted and we should continue with
532
  // the fast path.
533
  bool PaintTextWithSelectionColors(
534
    const PaintTextSelectionParams& aParams,
535
    const mozilla::UniquePtr<SelectionDetails>& aDetails,
536
    SelectionTypeMask* aAllSelectionTypeMask,
537
    const nsCharClipDisplayItem::ClipEdges& aClipEdges);
538
  // helper: paint text decorations for text selected by aSelectionType
539
  void PaintTextSelectionDecorations(const PaintTextSelectionParams& aParams,
540
                                     const mozilla::UniquePtr<SelectionDetails>& aDetails,
541
                                     SelectionType aSelectionType);
542
543
  void DrawEmphasisMarks(gfxContext* aContext,
544
                         mozilla::WritingMode aWM,
545
                         const mozilla::gfx::Point& aTextBaselinePt,
546
                         const mozilla::gfx::Point& aFramePt,
547
                         Range aRange,
548
                         const nscolor* aDecorationOverrideColor,
549
                         PropertyProvider* aProvider);
550
551
  nscolor GetCaretColorAt(int32_t aOffset) override;
552
553
  int16_t GetSelectionStatus(int16_t* aSelectionFlags);
554
555
0
  int32_t GetContentOffset() const { return mContentOffset; }
556
  int32_t GetContentLength() const
557
0
  {
558
0
    NS_ASSERTION(GetContentEnd() - mContentOffset >= 0, "negative length");
559
0
    return GetContentEnd() - mContentOffset;
560
0
  }
561
  int32_t GetContentEnd() const;
562
  // This returns the length the frame thinks it *should* have after it was
563
  // last reflowed (0 if it hasn't been reflowed yet). This should be used only
564
  // when setting up the text offsets for a new continuation frame.
565
0
  int32_t GetContentLengthHint() const { return mContentLengthHint; }
566
567
  // Compute the length of the content mapped by this frame
568
  // and all its in-flow siblings. Basically this means starting at mContentOffset
569
  // and going to the end of the text node or the next bidi continuation
570
  // boundary.
571
  int32_t GetInFlowContentLength();
572
573
  /**
574
   * Acquires the text run for this content, if necessary.
575
   * @param aWhichTextRun indicates whether to get an inflated or non-inflated
576
   * text run
577
   * @param aRefDrawTarget the DrawTarget to use as a reference for creating the
578
   * textrun, if available (if not, we'll create one which will just be slower)
579
   * @param aLineContainer the block ancestor for this frame, or nullptr if
580
   * unknown
581
   * @param aFlowEndInTextRun if non-null, this returns the textrun offset of
582
   * end of the text associated with this frame and its in-flow siblings
583
   * @return a gfxSkipCharsIterator set up to map DOM offsets for this frame
584
   * to offsets into the textrun; its initial offset is set to this frame's
585
   * content offset
586
   */
587
  gfxSkipCharsIterator EnsureTextRun(
588
    TextRunType aWhichTextRun,
589
    DrawTarget* aRefDrawTarget = nullptr,
590
    nsIFrame* aLineContainer = nullptr,
591
    const nsLineList::iterator* aLine = nullptr,
592
    uint32_t* aFlowEndInTextRun = nullptr);
593
594
  gfxTextRun* GetTextRun(TextRunType aWhichTextRun)
595
0
  {
596
0
    if (aWhichTextRun == eInflated || !HasFontSizeInflation())
597
0
      return mTextRun;
598
0
    return GetUninflatedTextRun();
599
0
  }
600
  gfxTextRun* GetUninflatedTextRun();
601
  void SetTextRun(gfxTextRun* aTextRun,
602
                  TextRunType aWhichTextRun,
603
                  float aInflation);
604
  bool IsInTextRunUserData() const
605
0
  {
606
0
    return GetStateBits() &
607
0
           (TEXT_IN_TEXTRUN_USER_DATA | TEXT_IN_UNINFLATED_TEXTRUN_USER_DATA);
608
0
  }
609
  /**
610
   * Notify the frame that it should drop its pointer to a text run.
611
   * Returns whether the text run was removed (i.e., whether it was
612
   * associated with this frame, either as its inflated or non-inflated
613
   * text run.
614
   */
615
  bool RemoveTextRun(gfxTextRun* aTextRun);
616
  /**
617
   * Clears out |mTextRun| (or the uninflated text run, when aInflated
618
   * is nsTextFrame::eNotInflated and there is inflation) from all frames that hold a
619
   * reference to it, starting at |aStartContinuation|, or if it's
620
   * nullptr, starting at |this|.  Deletes the text run if all references
621
   * were cleared and it's not cached.
622
   */
623
  void ClearTextRun(nsTextFrame* aStartContinuation, TextRunType aWhichTextRun);
624
625
  void ClearTextRuns()
626
0
  {
627
0
    ClearTextRun(nullptr, nsTextFrame::eInflated);
628
0
    if (HasFontSizeInflation()) {
629
0
      ClearTextRun(nullptr, nsTextFrame::eNotInflated);
630
0
    }
631
0
  }
632
633
  /**
634
   * Wipe out references to textrun(s) without deleting the textruns.
635
   */
636
  void DisconnectTextRuns();
637
638
  // Get the DOM content range mapped by this frame after excluding
639
  // whitespace subject to start-of-line and end-of-line trimming.
640
  // The textrun must have been created before calling this.
641
  struct TrimmedOffsets
642
  {
643
    int32_t mStart;
644
    int32_t mLength;
645
0
    int32_t GetEnd() const { return mStart + mLength; }
646
  };
647
  TrimmedOffsets GetTrimmedOffsets(const nsTextFragment* aFrag,
648
                                   bool aTrimAfter,
649
                                   bool aPostReflow = true) const;
650
651
  // Similar to Reflow(), but for use from nsLineLayout
652
  void ReflowText(nsLineLayout& aLineLayout,
653
                  nscoord aAvailableWidth,
654
                  DrawTarget* aDrawTarget,
655
                  ReflowOutput& aMetrics,
656
                  nsReflowStatus& aStatus);
657
658
  bool IsFloatingFirstLetterChild() const;
659
660
  bool IsInitialLetterChild() const;
661
662
  bool ComputeCustomOverflow(nsOverflowAreas& aOverflowAreas) override;
663
664
  void AssignJustificationGaps(const mozilla::JustificationAssignment& aAssign);
665
  mozilla::JustificationAssignment GetJustificationAssignment() const;
666
667
  uint32_t CountGraphemeClusters() const;
668
669
  bool HasAnyNoncollapsedCharacters() override;
670
671
protected:
672
  virtual ~nsTextFrame();
673
674
  RefPtr<gfxTextRun> mTextRun;
675
  nsTextFrame* mNextContinuation;
676
  // The key invariant here is that mContentOffset never decreases along
677
  // a next-continuation chain. And of course mContentOffset is always <= the
678
  // the text node's content length, and the mContentOffset for the first frame
679
  // is always 0. Furthermore the text mapped by a frame is determined by
680
  // GetContentOffset() and GetContentLength()/GetContentEnd(), which get
681
  // the length from the difference between this frame's offset and the next
682
  // frame's offset, or the text length if there is no next frame. This means
683
  // the frames always map the text node without overlapping or leaving any gaps.
684
  int32_t mContentOffset;
685
  // This does *not* indicate the length of text currently mapped by the frame;
686
  // instead it's a hint saying that this frame *wants* to map this much text
687
  // so if we create a new continuation, this is where that continuation should
688
  // start.
689
  int32_t mContentLengthHint;
690
  nscoord mAscent;
691
692
  /**
693
   * Return true if the frame is part of a Selection.
694
   * Helper method to implement the public IsSelected() API.
695
   */
696
  bool IsFrameSelected() const override;
697
698
  mozilla::UniquePtr<SelectionDetails> GetSelectionDetails();
699
700
  void UnionAdditionalOverflow(nsPresContext* aPresContext,
701
                               nsIFrame* aBlock,
702
                               PropertyProvider& aProvider,
703
                               nsRect* aVisualOverflowRect,
704
                               bool aIncludeTextDecorations);
705
706
  // Update information of emphasis marks, and return the visial
707
  // overflow rect of the emphasis marks.
708
  nsRect UpdateTextEmphasis(mozilla::WritingMode aWM,
709
                            PropertyProvider& aProvider);
710
711
  struct PaintShadowParams
712
  {
713
    gfxTextRun::Range range;
714
    LayoutDeviceRect dirtyRect;
715
    mozilla::gfx::Point framePt;
716
    mozilla::gfx::Point textBaselinePt;
717
    gfxContext* context;
718
    nscolor foregroundColor = NS_RGBA(0, 0, 0, 0);
719
    const nsCharClipDisplayItem::ClipEdges* clipEdges = nullptr;
720
    PropertyProvider* provider = nullptr;
721
    nscoord leftSideOffset = 0;
722
    explicit PaintShadowParams(const PaintTextParams& aParams)
723
      : dirtyRect(aParams.dirtyRect)
724
      , framePt(aParams.framePt)
725
      , context(aParams.context)
726
0
    {
727
0
    }
728
  };
729
730
  void PaintOneShadow(const PaintShadowParams& aParams,
731
                      nsCSSShadowItem* aShadowDetails,
732
                      gfxRect& aBoundingBox,
733
                      uint32_t aBlurFlags);
734
735
  void PaintShadows(nsCSSShadowArray* aShadow,
736
                    const PaintShadowParams& aParams);
737
738
  struct LineDecoration
739
  {
740
    nsIFrame* mFrame;
741
742
    // This is represents the offset from our baseline to mFrame's baseline;
743
    // positive offsets are *above* the baseline and negative offsets below
744
    nscoord mBaselineOffset;
745
746
    nscolor mColor;
747
    uint8_t mStyle;
748
749
    LineDecoration(nsIFrame* const aFrame,
750
                   const nscoord aOff,
751
                   const nscolor aColor,
752
                   const uint8_t aStyle)
753
      : mFrame(aFrame)
754
      , mBaselineOffset(aOff)
755
      , mColor(aColor)
756
      , mStyle(aStyle)
757
0
    {
758
0
    }
759
760
    LineDecoration(const LineDecoration& aOther)
761
      : mFrame(aOther.mFrame)
762
      , mBaselineOffset(aOther.mBaselineOffset)
763
      , mColor(aOther.mColor)
764
      , mStyle(aOther.mStyle)
765
0
    {
766
0
    }
767
768
    bool operator==(const LineDecoration& aOther) const
769
0
    {
770
0
      return mFrame == aOther.mFrame && mStyle == aOther.mStyle &&
771
0
             mColor == aOther.mColor &&
772
0
             mBaselineOffset == aOther.mBaselineOffset;
773
0
    }
774
775
    bool operator!=(const LineDecoration& aOther) const
776
0
    {
777
0
      return !(*this == aOther);
778
0
    }
779
  };
780
  struct TextDecorations
781
  {
782
    AutoTArray<LineDecoration, 1> mOverlines, mUnderlines, mStrikes;
783
784
0
    TextDecorations() {}
785
786
    bool HasDecorationLines() const
787
0
    {
788
0
      return HasUnderline() || HasOverline() || HasStrikeout();
789
0
    }
790
0
    bool HasUnderline() const { return !mUnderlines.IsEmpty(); }
791
0
    bool HasOverline() const { return !mOverlines.IsEmpty(); }
792
0
    bool HasStrikeout() const { return !mStrikes.IsEmpty(); }
793
    bool operator==(const TextDecorations& aOther) const
794
0
    {
795
0
      return mOverlines == aOther.mOverlines &&
796
0
             mUnderlines == aOther.mUnderlines && mStrikes == aOther.mStrikes;
797
0
    }
798
    bool operator!=(const TextDecorations& aOther) const
799
0
    {
800
0
      return !(*this == aOther);
801
0
    }
802
  };
803
  enum TextDecorationColorResolution
804
  {
805
    eResolvedColors,
806
    eUnresolvedColors
807
  };
808
  void GetTextDecorations(nsPresContext* aPresContext,
809
                          TextDecorationColorResolution aColorResolution,
810
                          TextDecorations& aDecorations);
811
812
  void DrawTextRun(Range aRange,
813
                   const mozilla::gfx::Point& aTextBaselinePt,
814
                   const DrawTextRunParams& aParams);
815
816
  void DrawTextRunAndDecorations(Range aRange,
817
                                 const mozilla::gfx::Point& aTextBaselinePt,
818
                                 const DrawTextParams& aParams,
819
                                 const TextDecorations& aDecorations);
820
821
  void DrawText(Range aRange,
822
                const mozilla::gfx::Point& aTextBaselinePt,
823
                const DrawTextParams& aParams);
824
825
  // Set non empty rect to aRect, it should be overflow rect or frame rect.
826
  // If the result rect is larger than the given rect, this returns true.
827
  bool CombineSelectionUnderlineRect(nsPresContext* aPresContext,
828
                                     nsRect& aRect);
829
830
  /**
831
   * Utility methods to paint selection.
832
   */
833
  void DrawSelectionDecorations(gfxContext* aContext,
834
                                const LayoutDeviceRect& aDirtyRect,
835
                                mozilla::SelectionType aSelectionType,
836
                                nsTextPaintStyle& aTextPaintStyle,
837
                                const TextRangeStyle& aRangeStyle,
838
                                const Point& aPt,
839
                                gfxFloat aICoordInFrame,
840
                                gfxFloat aWidth,
841
                                gfxFloat aAscent,
842
                                const gfxFont::Metrics& aFontMetrics,
843
                                DrawPathCallbacks* aCallbacks,
844
                                bool aVertical,
845
                                uint8_t aDecoration);
846
847
  struct PaintDecorationLineParams;
848
  void PaintDecorationLine(const PaintDecorationLineParams& aParams);
849
  /**
850
   * ComputeDescentLimitForSelectionUnderline() computes the most far position
851
   * where we can put selection underline.
852
   *
853
   * @return The maximum underline offset from the baseline (positive value
854
   *         means that the underline can put below the baseline).
855
   */
856
  gfxFloat ComputeDescentLimitForSelectionUnderline(
857
    nsPresContext* aPresContext,
858
    const gfxFont::Metrics& aFontMetrics);
859
  /**
860
   * This function encapsulates all knowledge of how selections affect
861
   * foreground and background colors.
862
   * @param aForeground the foreground color to use
863
   * @param aBackground the background color to use, or RGBA(0,0,0,0) if no
864
   *                    background should be painted
865
   * @return            true if the selection affects colors, false otherwise
866
   */
867
  static bool GetSelectionTextColors(SelectionType aSelectionType,
868
                                     nsTextPaintStyle& aTextPaintStyle,
869
                                     const TextRangeStyle& aRangeStyle,
870
                                     nscolor* aForeground,
871
                                     nscolor* aBackground);
872
  /**
873
   * ComputeSelectionUnderlineHeight() computes selection underline height of
874
   * the specified selection type from the font metrics.
875
   */
876
  static gfxFloat ComputeSelectionUnderlineHeight(
877
    nsPresContext* aPresContext,
878
    const gfxFont::Metrics& aFontMetrics,
879
    SelectionType aSelectionType);
880
881
  ContentOffsets GetCharacterOffsetAtFramePointInternal(
882
    const nsPoint& aPoint,
883
    bool aForInsertionPoint);
884
885
  void ClearFrameOffsetCache();
886
887
  void ClearMetrics(ReflowOutput& aMetrics);
888
889
  /**
890
   * UpdateIteratorFromOffset() updates the iterator from a given offset.
891
   * Also, aInOffset may be updated to cluster start if aInOffset isn't
892
   * the offset of cluster start.
893
   */
894
  void UpdateIteratorFromOffset(const PropertyProvider& aProperties,
895
                                int32_t& aInOffset,
896
                                gfxSkipCharsIterator& aIter);
897
898
  nsPoint GetPointFromIterator(const gfxSkipCharsIterator& aIter,
899
                               PropertyProvider& aProperties);
900
};
901
902
#endif