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