michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef nsTextFrame_h__ michael@0: #define nsTextFrame_h__ michael@0: michael@0: #include "mozilla/Attributes.h" michael@0: #include "nsFrame.h" michael@0: #include "nsSplittableFrame.h" michael@0: #include "nsLineBox.h" michael@0: #include "gfxFont.h" michael@0: #include "gfxSkipChars.h" michael@0: #include "nsDisplayList.h" michael@0: michael@0: class nsTextPaintStyle; michael@0: class PropertyProvider; michael@0: michael@0: typedef nsFrame nsTextFrameBase; michael@0: michael@0: class nsDisplayTextGeometry; michael@0: class nsDisplayText; michael@0: michael@0: class nsTextFrameTextRunCache { michael@0: public: michael@0: static void Init(); michael@0: static void Shutdown(); michael@0: }; michael@0: michael@0: class nsTextFrame : public nsTextFrameBase { michael@0: public: michael@0: NS_DECL_QUERYFRAME_TARGET(nsTextFrame) michael@0: NS_DECL_FRAMEARENA_HELPERS michael@0: michael@0: friend class nsContinuingTextFrame; michael@0: friend class nsDisplayTextGeometry; michael@0: friend class nsDisplayText; michael@0: michael@0: nsTextFrame(nsStyleContext* aContext) michael@0: : nsTextFrameBase(aContext) michael@0: { michael@0: NS_ASSERTION(mContentOffset == 0, "Bogus content offset"); michael@0: } michael@0: michael@0: // nsQueryFrame michael@0: NS_DECL_QUERYFRAME michael@0: michael@0: // nsIFrame michael@0: virtual void BuildDisplayList(nsDisplayListBuilder* aBuilder, michael@0: const nsRect& aDirtyRect, michael@0: const nsDisplayListSet& aLists) MOZ_OVERRIDE; michael@0: michael@0: virtual void Init(nsIContent* aContent, michael@0: nsIFrame* aParent, michael@0: nsIFrame* aPrevInFlow) MOZ_OVERRIDE; michael@0: michael@0: virtual void DestroyFrom(nsIFrame* aDestructRoot) MOZ_OVERRIDE; michael@0: michael@0: virtual nsresult GetCursor(const nsPoint& aPoint, michael@0: nsIFrame::Cursor& aCursor) MOZ_OVERRIDE; michael@0: michael@0: virtual nsresult CharacterDataChanged(CharacterDataChangeInfo* aInfo) MOZ_OVERRIDE; michael@0: michael@0: virtual void DidSetStyleContext(nsStyleContext* aOldStyleContext) MOZ_OVERRIDE; michael@0: michael@0: virtual nsIFrame* GetNextContinuation() const MOZ_OVERRIDE { michael@0: return mNextContinuation; michael@0: } michael@0: virtual void SetNextContinuation(nsIFrame* aNextContinuation) MOZ_OVERRIDE { michael@0: NS_ASSERTION (!aNextContinuation || GetType() == aNextContinuation->GetType(), michael@0: "setting a next continuation with incorrect type!"); michael@0: NS_ASSERTION (!nsSplittableFrame::IsInNextContinuationChain(aNextContinuation, this), michael@0: "creating a loop in continuation chain!"); michael@0: mNextContinuation = aNextContinuation; michael@0: if (aNextContinuation) michael@0: aNextContinuation->RemoveStateBits(NS_FRAME_IS_FLUID_CONTINUATION); michael@0: } michael@0: virtual nsIFrame* GetNextInFlowVirtual() const MOZ_OVERRIDE { return GetNextInFlow(); } michael@0: nsIFrame* GetNextInFlow() const { michael@0: return mNextContinuation && (mNextContinuation->GetStateBits() & NS_FRAME_IS_FLUID_CONTINUATION) ? michael@0: mNextContinuation : nullptr; michael@0: } michael@0: virtual void SetNextInFlow(nsIFrame* aNextInFlow) MOZ_OVERRIDE { michael@0: NS_ASSERTION (!aNextInFlow || GetType() == aNextInFlow->GetType(), michael@0: "setting a next in flow with incorrect type!"); michael@0: NS_ASSERTION (!nsSplittableFrame::IsInNextContinuationChain(aNextInFlow, this), michael@0: "creating a loop in continuation chain!"); michael@0: mNextContinuation = aNextInFlow; michael@0: if (aNextInFlow) michael@0: aNextInFlow->AddStateBits(NS_FRAME_IS_FLUID_CONTINUATION); michael@0: } michael@0: virtual nsIFrame* LastInFlow() const MOZ_OVERRIDE; michael@0: virtual nsIFrame* LastContinuation() const MOZ_OVERRIDE; michael@0: michael@0: virtual nsSplittableType GetSplittableType() const MOZ_OVERRIDE { michael@0: return NS_FRAME_SPLITTABLE; michael@0: } michael@0: michael@0: /** michael@0: * Get the "type" of the frame michael@0: * michael@0: * @see nsGkAtoms::textFrame michael@0: */ michael@0: virtual nsIAtom* GetType() const MOZ_OVERRIDE; michael@0: michael@0: virtual bool IsFrameOfType(uint32_t aFlags) const MOZ_OVERRIDE michael@0: { michael@0: // Set the frame state bit for text frames to mark them as replaced. michael@0: // XXX kipp: temporary michael@0: return nsFrame::IsFrameOfType(aFlags & ~(nsIFrame::eReplaced | michael@0: nsIFrame::eLineParticipant)); michael@0: } michael@0: michael@0: virtual void InvalidateFrame(uint32_t aDisplayItemKey = 0) MOZ_OVERRIDE; michael@0: virtual void InvalidateFrameWithRect(const nsRect& aRect, uint32_t aDisplayItemKey = 0) MOZ_OVERRIDE; michael@0: michael@0: #ifdef DEBUG_FRAME_DUMP michael@0: void List(FILE* out = stderr, const char* aPrefix = "", uint32_t aFlags = 0) const MOZ_OVERRIDE; michael@0: virtual nsresult GetFrameName(nsAString& aResult) const MOZ_OVERRIDE; michael@0: void ToCString(nsCString& aBuf, int32_t* aTotalContentLength) const; michael@0: #endif michael@0: michael@0: #ifdef DEBUG michael@0: virtual nsFrameState GetDebugStateBits() const MOZ_OVERRIDE; michael@0: #endif michael@0: michael@0: virtual ContentOffsets CalcContentOffsetsFromFramePoint(nsPoint aPoint) MOZ_OVERRIDE; michael@0: ContentOffsets GetCharacterOffsetAtFramePoint(const nsPoint &aPoint); michael@0: michael@0: /** michael@0: * This is called only on the primary text frame. It indicates that michael@0: * the selection state of the given character range has changed. michael@0: * Text in the range is unconditionally invalidated michael@0: * (Selection::Repaint depends on this). michael@0: * @param aSelected true if the selection has been added to the range, michael@0: * false otherwise michael@0: * @param aType the type of selection added or removed michael@0: */ michael@0: void SetSelectedRange(uint32_t aStart, uint32_t aEnd, bool aSelected, michael@0: SelectionType aType); michael@0: michael@0: virtual FrameSearchResult PeekOffsetNoAmount(bool aForward, int32_t* aOffset) MOZ_OVERRIDE; michael@0: virtual FrameSearchResult PeekOffsetCharacter(bool aForward, int32_t* aOffset, michael@0: bool aRespectClusters = true) MOZ_OVERRIDE; michael@0: virtual FrameSearchResult PeekOffsetWord(bool aForward, bool aWordSelectEatSpace, bool aIsKeyboardSelect, michael@0: int32_t* aOffset, PeekWordState* aState) MOZ_OVERRIDE; michael@0: michael@0: virtual nsresult CheckVisibility(nsPresContext* aContext, int32_t aStartIndex, int32_t aEndIndex, bool aRecurse, bool *aFinished, bool *_retval) MOZ_OVERRIDE; michael@0: michael@0: // Flags for aSetLengthFlags michael@0: enum { ALLOW_FRAME_CREATION_AND_DESTRUCTION = 0x01 }; michael@0: michael@0: // Update offsets to account for new length. This may clear mTextRun. michael@0: void SetLength(int32_t aLength, nsLineLayout* aLineLayout, michael@0: uint32_t aSetLengthFlags = 0); michael@0: michael@0: virtual nsresult GetOffsets(int32_t &start, int32_t &end)const MOZ_OVERRIDE; michael@0: michael@0: virtual void AdjustOffsetsForBidi(int32_t start, int32_t end) MOZ_OVERRIDE; michael@0: michael@0: virtual nsresult GetPointFromOffset(int32_t inOffset, michael@0: nsPoint* outPoint) MOZ_OVERRIDE; michael@0: michael@0: virtual nsresult GetChildFrameContainingOffset(int32_t inContentOffset, michael@0: bool inHint, michael@0: int32_t* outFrameContentOffset, michael@0: nsIFrame** outChildFrame) MOZ_OVERRIDE; michael@0: michael@0: virtual bool IsVisibleInSelection(nsISelection* aSelection) MOZ_OVERRIDE; michael@0: michael@0: virtual bool IsEmpty() MOZ_OVERRIDE; michael@0: virtual bool IsSelfEmpty() MOZ_OVERRIDE { return IsEmpty(); } michael@0: virtual nscoord GetBaseline() const MOZ_OVERRIDE; michael@0: michael@0: virtual bool HasSignificantTerminalNewline() const MOZ_OVERRIDE; michael@0: michael@0: /** michael@0: * Returns true if this text frame is logically adjacent to the end of the michael@0: * line. michael@0: */ michael@0: bool IsAtEndOfLine() const; michael@0: michael@0: /** michael@0: * Call this only after reflow the frame. Returns true if non-collapsed michael@0: * characters are present. michael@0: */ michael@0: bool HasNoncollapsedCharacters() const { michael@0: return (GetStateBits() & TEXT_HAS_NONCOLLAPSED_CHARACTERS) != 0; michael@0: } michael@0: michael@0: #ifdef ACCESSIBILITY michael@0: virtual mozilla::a11y::AccType AccessibleType() MOZ_OVERRIDE; michael@0: #endif michael@0: michael@0: float GetFontSizeInflation() const; michael@0: bool IsCurrentFontInflation(float aInflation) const; michael@0: bool HasFontSizeInflation() const { michael@0: return (GetStateBits() & TEXT_HAS_FONT_INFLATION) != 0; michael@0: } michael@0: void SetFontSizeInflation(float aInflation); michael@0: michael@0: virtual void MarkIntrinsicWidthsDirty() MOZ_OVERRIDE; michael@0: virtual nscoord GetMinWidth(nsRenderingContext *aRenderingContext) MOZ_OVERRIDE; michael@0: virtual nscoord GetPrefWidth(nsRenderingContext *aRenderingContext) MOZ_OVERRIDE; michael@0: virtual void AddInlineMinWidth(nsRenderingContext *aRenderingContext, michael@0: InlineMinWidthData *aData) MOZ_OVERRIDE; michael@0: virtual void AddInlinePrefWidth(nsRenderingContext *aRenderingContext, michael@0: InlinePrefWidthData *aData) MOZ_OVERRIDE; michael@0: virtual nsSize ComputeSize(nsRenderingContext *aRenderingContext, michael@0: nsSize aCBSize, nscoord aAvailableWidth, michael@0: nsSize aMargin, nsSize aBorder, nsSize aPadding, michael@0: uint32_t aFlags) MOZ_OVERRIDE; michael@0: virtual nsRect ComputeTightBounds(gfxContext* aContext) const MOZ_OVERRIDE; michael@0: virtual nsresult GetPrefWidthTightBounds(nsRenderingContext* aContext, michael@0: nscoord* aX, michael@0: nscoord* aXMost) MOZ_OVERRIDE; michael@0: virtual nsresult Reflow(nsPresContext* aPresContext, michael@0: nsHTMLReflowMetrics& aMetrics, michael@0: const nsHTMLReflowState& aReflowState, michael@0: nsReflowStatus& aStatus) MOZ_OVERRIDE; michael@0: virtual bool CanContinueTextRun() const MOZ_OVERRIDE; michael@0: // Method that is called for a text frame that is logically michael@0: // adjacent to the end of the line (i.e. followed only by empty text frames, michael@0: // placeholders or inlines containing such). michael@0: struct TrimOutput { michael@0: // true if we trimmed some space or changed metrics in some other way. michael@0: // In this case, we should call RecomputeOverflow on this frame. michael@0: bool mChanged; michael@0: // true if the last character is not justifiable so should be subtracted michael@0: // from the count of justifiable characters in the frame, since the last michael@0: // character in a line is not justifiable. michael@0: bool mLastCharIsJustifiable; michael@0: // an amount to *subtract* from the frame's width (zero if !mChanged) michael@0: nscoord mDeltaWidth; michael@0: }; michael@0: TrimOutput TrimTrailingWhiteSpace(nsRenderingContext* aRC); michael@0: virtual nsresult GetRenderedText(nsAString* aString = nullptr, michael@0: gfxSkipChars* aSkipChars = nullptr, michael@0: gfxSkipCharsIterator* aSkipIter = nullptr, michael@0: uint32_t aSkippedStartOffset = 0, michael@0: uint32_t aSkippedMaxLength = UINT32_MAX) MOZ_OVERRIDE; michael@0: michael@0: nsOverflowAreas michael@0: RecomputeOverflow(const nsHTMLReflowState& aBlockReflowState); michael@0: michael@0: enum TextRunType { michael@0: // Anything in reflow (but not intrinsic width calculation) or michael@0: // painting should use the inflated text run (i.e., with font size michael@0: // inflation applied). michael@0: eInflated, michael@0: // Intrinsic width calculation should use the non-inflated text run. michael@0: // When there is font size inflation, it will be different. michael@0: eNotInflated michael@0: }; michael@0: michael@0: void AddInlineMinWidthForFlow(nsRenderingContext *aRenderingContext, michael@0: nsIFrame::InlineMinWidthData *aData, michael@0: TextRunType aTextRunType); michael@0: void AddInlinePrefWidthForFlow(nsRenderingContext *aRenderingContext, michael@0: InlinePrefWidthData *aData, michael@0: TextRunType aTextRunType); michael@0: michael@0: /** michael@0: * Calculate the horizontal bounds of the grapheme clusters that fit entirely michael@0: * inside the given left/right edges (which are positive lengths from the michael@0: * respective frame edge). If an input value is zero it is ignored and the michael@0: * result for that edge is zero. All out parameter values are undefined when michael@0: * the method returns false. michael@0: * @return true if at least one whole grapheme cluster fit between the edges michael@0: */ michael@0: bool MeasureCharClippedText(nscoord aLeftEdge, nscoord aRightEdge, michael@0: nscoord* aSnappedLeftEdge, michael@0: nscoord* aSnappedRightEdge); michael@0: /** michael@0: * Same as above; this method also the returns the corresponding text run michael@0: * offset and number of characters that fit. All out parameter values are michael@0: * undefined when the method returns false. michael@0: * @return true if at least one whole grapheme cluster fit between the edges michael@0: */ michael@0: bool MeasureCharClippedText(PropertyProvider& aProvider, michael@0: nscoord aLeftEdge, nscoord aRightEdge, michael@0: uint32_t* aStartOffset, uint32_t* aMaxLength, michael@0: nscoord* aSnappedLeftEdge, michael@0: nscoord* aSnappedRightEdge); michael@0: michael@0: /** michael@0: * Object with various callbacks for PaintText() to invoke for different parts michael@0: * of the frame's text rendering, when we're generating paths rather than michael@0: * painting. michael@0: * michael@0: * Callbacks are invoked in the following order: michael@0: * michael@0: * (NotifyBeforeSelectionBackground NotifySelectionBackgroundPathEmitted)? michael@0: * (NotifyBeforeDecorationLine NotifyDecorationLinePathEmitted)* michael@0: * NotifyBeforeText michael@0: * (NotifyGlyphPathEmitted | michael@0: * (NotifyBeforeSVGGlyphPainted NotifyAfterSVGGlyphPainted))* michael@0: * NotifyAfterText michael@0: * (NotifyBeforeDecorationLine NotifyDecorationLinePathEmitted)* michael@0: * (NotifyBeforeSelectionDecorationLine NotifySelectionDecorationLinePathEmitted)* michael@0: * michael@0: * The color of each part of the frame's text rendering is passed as an argument michael@0: * to the NotifyBefore* callback for that part. The nscolor can take on one of michael@0: * the three selection special colors defined in LookAndFeel.h -- michael@0: * NS_TRANSPARENT, NS_SAME_AS_FOREGROUND_COLOR and michael@0: * NS_40PERCENT_FOREGROUND_COLOR. michael@0: */ michael@0: struct DrawPathCallbacks : gfxTextRunDrawCallbacks michael@0: { michael@0: /** michael@0: * @param aShouldPaintSVGGlyphs Whether SVG glyphs should be painted. michael@0: */ michael@0: DrawPathCallbacks(bool aShouldPaintSVGGlyphs = false) michael@0: : gfxTextRunDrawCallbacks(aShouldPaintSVGGlyphs) michael@0: { michael@0: } michael@0: michael@0: /** michael@0: * Called just before any paths have been emitted to the gfxContext michael@0: * for the glyphs of the frame's text. michael@0: */ michael@0: virtual void NotifyBeforeText(nscolor aColor) { } michael@0: michael@0: /** michael@0: * Called just after all the paths have been emitted to the gfxContext michael@0: * for the glyphs of the frame's text. michael@0: */ michael@0: virtual void NotifyAfterText() { } michael@0: michael@0: /** michael@0: * Called just before a path corresponding to the selection background michael@0: * has been emitted to the gfxContext. michael@0: */ michael@0: virtual void NotifyBeforeSelectionBackground(nscolor aColor) { } michael@0: michael@0: /** michael@0: * Called just after a path corresponding to the selection background michael@0: * has been emitted to the gfxContext. michael@0: */ michael@0: virtual void NotifySelectionBackgroundPathEmitted() { } michael@0: michael@0: /** michael@0: * Called just before a path corresponding to a text decoration line michael@0: * has been emitted to the gfxContext. michael@0: */ michael@0: virtual void NotifyBeforeDecorationLine(nscolor aColor) { } michael@0: michael@0: /** michael@0: * Called just after a path corresponding to a text decoration line michael@0: * has been emitted to the gfxContext. michael@0: */ michael@0: virtual void NotifyDecorationLinePathEmitted() { } michael@0: michael@0: /** michael@0: * Called just before a path corresponding to a selection decoration line michael@0: * has been emitted to the gfxContext. michael@0: */ michael@0: virtual void NotifyBeforeSelectionDecorationLine(nscolor aColor) { } michael@0: michael@0: /** michael@0: * Called just after a path corresponding to a selection decoration line michael@0: * has been emitted to the gfxContext. michael@0: */ michael@0: virtual void NotifySelectionDecorationLinePathEmitted() { } michael@0: }; michael@0: michael@0: // Primary frame paint method called from nsDisplayText. Can also be used michael@0: // to generate paths rather than paint the frame's text by passing a callback michael@0: // object. The private DrawText() is what applies the text to a graphics michael@0: // context. michael@0: void PaintText(nsRenderingContext* aRenderingContext, nsPoint aPt, michael@0: const nsRect& aDirtyRect, const nsCharClipDisplayItem& aItem, michael@0: gfxTextContextPaint* aContextPaint = nullptr, michael@0: DrawPathCallbacks* aCallbacks = nullptr); michael@0: // helper: paint text frame when we're impacted by at least one selection. michael@0: // Return false if the text was not painted and we should continue with michael@0: // the fast path. michael@0: bool PaintTextWithSelection(gfxContext* aCtx, michael@0: const gfxPoint& aFramePt, michael@0: const gfxPoint& aTextBaselinePt, michael@0: const gfxRect& aDirtyRect, michael@0: PropertyProvider& aProvider, michael@0: uint32_t aContentOffset, michael@0: uint32_t aContentLength, michael@0: nsTextPaintStyle& aTextPaintStyle, michael@0: const nsCharClipDisplayItem::ClipEdges& aClipEdges, michael@0: gfxTextContextPaint* aContextPaint, michael@0: DrawPathCallbacks* aCallbacks); michael@0: // helper: paint text with foreground and background colors determined michael@0: // by selection(s). Also computes a mask of all selection types applying to michael@0: // our text, returned in aAllTypes. michael@0: // Return false if the text was not painted and we should continue with michael@0: // the fast path. michael@0: bool PaintTextWithSelectionColors(gfxContext* aCtx, michael@0: const gfxPoint& aFramePt, michael@0: const gfxPoint& aTextBaselinePt, michael@0: const gfxRect& aDirtyRect, michael@0: PropertyProvider& aProvider, michael@0: uint32_t aContentOffset, michael@0: uint32_t aContentLength, michael@0: nsTextPaintStyle& aTextPaintStyle, michael@0: SelectionDetails* aDetails, michael@0: SelectionType* aAllTypes, michael@0: const nsCharClipDisplayItem::ClipEdges& aClipEdges, michael@0: DrawPathCallbacks* aCallbacks); michael@0: // helper: paint text decorations for text selected by aSelectionType michael@0: void PaintTextSelectionDecorations(gfxContext* aCtx, michael@0: const gfxPoint& aFramePt, michael@0: const gfxPoint& aTextBaselinePt, michael@0: const gfxRect& aDirtyRect, michael@0: PropertyProvider& aProvider, michael@0: uint32_t aContentOffset, michael@0: uint32_t aContentLength, michael@0: nsTextPaintStyle& aTextPaintStyle, michael@0: SelectionDetails* aDetails, michael@0: SelectionType aSelectionType, michael@0: DrawPathCallbacks* aCallbacks); michael@0: michael@0: virtual nscolor GetCaretColorAt(int32_t aOffset) MOZ_OVERRIDE; michael@0: michael@0: int16_t GetSelectionStatus(int16_t* aSelectionFlags); michael@0: michael@0: int32_t GetContentOffset() const { return mContentOffset; } michael@0: int32_t GetContentLength() const michael@0: { michael@0: NS_ASSERTION(GetContentEnd() - mContentOffset >= 0, "negative length"); michael@0: return GetContentEnd() - mContentOffset; michael@0: } michael@0: int32_t GetContentEnd() const; michael@0: // This returns the length the frame thinks it *should* have after it was michael@0: // last reflowed (0 if it hasn't been reflowed yet). This should be used only michael@0: // when setting up the text offsets for a new continuation frame. michael@0: int32_t GetContentLengthHint() const { return mContentLengthHint; } michael@0: michael@0: // Compute the length of the content mapped by this frame michael@0: // and all its in-flow siblings. Basically this means starting at mContentOffset michael@0: // and going to the end of the text node or the next bidi continuation michael@0: // boundary. michael@0: int32_t GetInFlowContentLength(); michael@0: michael@0: /** michael@0: * Acquires the text run for this content, if necessary. michael@0: * @param aWhichTextRun indicates whether to get an inflated or non-inflated michael@0: * text run michael@0: * @param aReferenceContext the rendering context to use as a reference for michael@0: * creating the textrun, if available (if not, we'll create one which will michael@0: * just be slower) michael@0: * @param aLineContainer the block ancestor for this frame, or nullptr if michael@0: * unknown michael@0: * @param aFlowEndInTextRun if non-null, this returns the textrun offset of michael@0: * end of the text associated with this frame and its in-flow siblings michael@0: * @return a gfxSkipCharsIterator set up to map DOM offsets for this frame michael@0: * to offsets into the textrun; its initial offset is set to this frame's michael@0: * content offset michael@0: */ michael@0: gfxSkipCharsIterator EnsureTextRun(TextRunType aWhichTextRun, michael@0: gfxContext* aReferenceContext = nullptr, michael@0: nsIFrame* aLineContainer = nullptr, michael@0: const nsLineList::iterator* aLine = nullptr, michael@0: uint32_t* aFlowEndInTextRun = nullptr); michael@0: michael@0: gfxTextRun* GetTextRun(TextRunType aWhichTextRun) { michael@0: if (aWhichTextRun == eInflated || !HasFontSizeInflation()) michael@0: return mTextRun; michael@0: return GetUninflatedTextRun(); michael@0: } michael@0: gfxTextRun* GetUninflatedTextRun(); michael@0: void SetTextRun(gfxTextRun* aTextRun, TextRunType aWhichTextRun, michael@0: float aInflation); michael@0: bool IsInTextRunUserData() const { michael@0: return GetStateBits() & michael@0: (TEXT_IN_TEXTRUN_USER_DATA | TEXT_IN_UNINFLATED_TEXTRUN_USER_DATA); michael@0: } michael@0: /** michael@0: * Notify the frame that it should drop its pointer to a text run. michael@0: * Returns whether the text run was removed (i.e., whether it was michael@0: * associated with this frame, either as its inflated or non-inflated michael@0: * text run. michael@0: */ michael@0: bool RemoveTextRun(gfxTextRun* aTextRun); michael@0: /** michael@0: * Clears out |mTextRun| (or the uninflated text run, when aInflated michael@0: * is nsTextFrame::eNotInflated and there is inflation) from all frames that hold a michael@0: * reference to it, starting at |aStartContinuation|, or if it's michael@0: * nullptr, starting at |this|. Deletes the text run if all references michael@0: * were cleared and it's not cached. michael@0: */ michael@0: void ClearTextRun(nsTextFrame* aStartContinuation, michael@0: TextRunType aWhichTextRun); michael@0: michael@0: void ClearTextRuns() { michael@0: ClearTextRun(nullptr, nsTextFrame::eInflated); michael@0: if (HasFontSizeInflation()) { michael@0: ClearTextRun(nullptr, nsTextFrame::eNotInflated); michael@0: } michael@0: } michael@0: michael@0: /** michael@0: * Wipe out references to textrun(s) without deleting the textruns. michael@0: */ michael@0: void DisconnectTextRuns(); michael@0: michael@0: // Get the DOM content range mapped by this frame after excluding michael@0: // whitespace subject to start-of-line and end-of-line trimming. michael@0: // The textrun must have been created before calling this. michael@0: struct TrimmedOffsets { michael@0: int32_t mStart; michael@0: int32_t mLength; michael@0: int32_t GetEnd() const { return mStart + mLength; } michael@0: }; michael@0: TrimmedOffsets GetTrimmedOffsets(const nsTextFragment* aFrag, michael@0: bool aTrimAfter, bool aPostReflow = true); michael@0: michael@0: // Similar to Reflow(), but for use from nsLineLayout michael@0: void ReflowText(nsLineLayout& aLineLayout, nscoord aAvailableWidth, michael@0: nsRenderingContext* aRenderingContext, michael@0: nsHTMLReflowMetrics& aMetrics, nsReflowStatus& aStatus); michael@0: michael@0: bool IsFloatingFirstLetterChild() const; michael@0: michael@0: protected: michael@0: virtual ~nsTextFrame(); michael@0: michael@0: nsIFrame* mNextContinuation; michael@0: // The key invariant here is that mContentOffset never decreases along michael@0: // a next-continuation chain. And of course mContentOffset is always <= the michael@0: // the text node's content length, and the mContentOffset for the first frame michael@0: // is always 0. Furthermore the text mapped by a frame is determined by michael@0: // GetContentOffset() and GetContentLength()/GetContentEnd(), which get michael@0: // the length from the difference between this frame's offset and the next michael@0: // frame's offset, or the text length if there is no next frame. This means michael@0: // the frames always map the text node without overlapping or leaving any gaps. michael@0: int32_t mContentOffset; michael@0: // This does *not* indicate the length of text currently mapped by the frame; michael@0: // instead it's a hint saying that this frame *wants* to map this much text michael@0: // so if we create a new continuation, this is where that continuation should michael@0: // start. michael@0: int32_t mContentLengthHint; michael@0: nscoord mAscent; michael@0: gfxTextRun* mTextRun; michael@0: michael@0: /** michael@0: * Return true if the frame is part of a Selection. michael@0: * Helper method to implement the public IsSelected() API. michael@0: */ michael@0: virtual bool IsFrameSelected() const MOZ_OVERRIDE; michael@0: michael@0: // The caller of this method must call DestroySelectionDetails() on the michael@0: // return value, if that return value is not null. Calling michael@0: // DestroySelectionDetails() on a null value is still OK, just not necessary. michael@0: SelectionDetails* GetSelectionDetails(); michael@0: michael@0: void UnionAdditionalOverflow(nsPresContext* aPresContext, michael@0: const nsHTMLReflowState& aBlockReflowState, michael@0: PropertyProvider& aProvider, michael@0: nsRect* aVisualOverflowRect, michael@0: bool aIncludeTextDecorations); michael@0: michael@0: void PaintOneShadow(uint32_t aOffset, michael@0: uint32_t aLength, michael@0: nsCSSShadowItem* aShadowDetails, michael@0: PropertyProvider* aProvider, michael@0: const nsRect& aDirtyRect, michael@0: const gfxPoint& aFramePt, michael@0: const gfxPoint& aTextBaselinePt, michael@0: gfxContext* aCtx, michael@0: const nscolor& aForegroundColor, michael@0: const nsCharClipDisplayItem::ClipEdges& aClipEdges, michael@0: nscoord aLeftSideOffset, michael@0: gfxRect& aBoundingBox); michael@0: michael@0: struct LineDecoration { michael@0: nsIFrame* mFrame; michael@0: michael@0: // This is represents the offset from our baseline to mFrame's baseline; michael@0: // positive offsets are *above* the baseline and negative offsets below michael@0: nscoord mBaselineOffset; michael@0: michael@0: nscolor mColor; michael@0: uint8_t mStyle; michael@0: michael@0: LineDecoration(nsIFrame *const aFrame, michael@0: const nscoord aOff, michael@0: const nscolor aColor, michael@0: const uint8_t aStyle) michael@0: : mFrame(aFrame), michael@0: mBaselineOffset(aOff), michael@0: mColor(aColor), michael@0: mStyle(aStyle) michael@0: {} michael@0: michael@0: LineDecoration(const LineDecoration& aOther) michael@0: : mFrame(aOther.mFrame), michael@0: mBaselineOffset(aOther.mBaselineOffset), michael@0: mColor(aOther.mColor), michael@0: mStyle(aOther.mStyle) michael@0: {} michael@0: michael@0: bool operator==(const LineDecoration& aOther) const { michael@0: return mFrame == aOther.mFrame && michael@0: mStyle == aOther.mStyle && michael@0: mColor == aOther.mColor && michael@0: mBaselineOffset == aOther.mBaselineOffset; michael@0: } michael@0: michael@0: bool operator!=(const LineDecoration& aOther) const { michael@0: return !(*this == aOther); michael@0: } michael@0: }; michael@0: struct TextDecorations { michael@0: nsAutoTArray mOverlines, mUnderlines, mStrikes; michael@0: michael@0: TextDecorations() { } michael@0: michael@0: bool HasDecorationLines() const { michael@0: return HasUnderline() || HasOverline() || HasStrikeout(); michael@0: } michael@0: bool HasUnderline() const { michael@0: return !mUnderlines.IsEmpty(); michael@0: } michael@0: bool HasOverline() const { michael@0: return !mOverlines.IsEmpty(); michael@0: } michael@0: bool HasStrikeout() const { michael@0: return !mStrikes.IsEmpty(); michael@0: } michael@0: bool operator==(const TextDecorations& aOther) const { michael@0: return mOverlines == aOther.mOverlines && michael@0: mUnderlines == aOther.mUnderlines && michael@0: mStrikes == aOther.mStrikes; michael@0: } michael@0: michael@0: bool operator!=(const TextDecorations& aOther) const { michael@0: return !(*this == aOther); michael@0: } michael@0: michael@0: }; michael@0: enum TextDecorationColorResolution { michael@0: eResolvedColors, michael@0: eUnresolvedColors michael@0: }; michael@0: void GetTextDecorations(nsPresContext* aPresContext, michael@0: TextDecorationColorResolution aColorResolution, michael@0: TextDecorations& aDecorations); michael@0: michael@0: void DrawTextRun(gfxContext* const aCtx, michael@0: const gfxPoint& aTextBaselinePt, michael@0: uint32_t aOffset, michael@0: uint32_t aLength, michael@0: PropertyProvider& aProvider, michael@0: nscolor aTextColor, michael@0: gfxFloat& aAdvanceWidth, michael@0: bool aDrawSoftHyphen, michael@0: gfxTextContextPaint* aContextPaint, michael@0: DrawPathCallbacks* aCallbacks); michael@0: michael@0: void DrawTextRunAndDecorations(gfxContext* const aCtx, michael@0: const gfxRect& aDirtyRect, michael@0: const gfxPoint& aFramePt, michael@0: const gfxPoint& aTextBaselinePt, michael@0: uint32_t aOffset, michael@0: uint32_t aLength, michael@0: PropertyProvider& aProvider, michael@0: const nsTextPaintStyle& aTextStyle, michael@0: nscolor aTextColor, michael@0: const nsCharClipDisplayItem::ClipEdges& aClipEdges, michael@0: gfxFloat& aAdvanceWidth, michael@0: bool aDrawSoftHyphen, michael@0: const TextDecorations& aDecorations, michael@0: const nscolor* const aDecorationOverrideColor, michael@0: gfxTextContextPaint* aContextPaint, michael@0: DrawPathCallbacks* aCallbacks); michael@0: michael@0: void DrawText(gfxContext* const aCtx, michael@0: const gfxRect& aDirtyRect, michael@0: const gfxPoint& aFramePt, michael@0: const gfxPoint& aTextBaselinePt, michael@0: uint32_t aOffset, michael@0: uint32_t aLength, michael@0: PropertyProvider& aProvider, michael@0: const nsTextPaintStyle& aTextStyle, michael@0: nscolor aTextColor, michael@0: const nsCharClipDisplayItem::ClipEdges& aClipEdges, michael@0: gfxFloat& aAdvanceWidth, michael@0: bool aDrawSoftHyphen, michael@0: const nscolor* const aDecorationOverrideColor = nullptr, michael@0: gfxTextContextPaint* aContextPaint = nullptr, michael@0: DrawPathCallbacks* aCallbacks = nullptr); michael@0: michael@0: // Set non empty rect to aRect, it should be overflow rect or frame rect. michael@0: // If the result rect is larger than the given rect, this returns true. michael@0: bool CombineSelectionUnderlineRect(nsPresContext* aPresContext, michael@0: nsRect& aRect); michael@0: michael@0: ContentOffsets GetCharacterOffsetAtFramePointInternal(nsPoint aPoint, michael@0: bool aForInsertionPoint); michael@0: michael@0: void ClearFrameOffsetCache(); michael@0: michael@0: virtual bool HasAnyNoncollapsedCharacters() MOZ_OVERRIDE; michael@0: michael@0: void ClearMetrics(nsHTMLReflowMetrics& aMetrics); michael@0: }; michael@0: michael@0: #endif