1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
15 * The Original Code is mozilla.org code.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998
20 * the Initial Developer. All Rights Reserved.
23 * Robert O'Callahan <robert@ocallahan.org>
24 * Roger B. Sidje <rbs@maths.uq.edu.au>
25 * Pierre Phaneuf <pp@ludusdesign.com>
26 * Prabhat Hegde <prabhat.hegde@sun.com>
27 * Tomi Leppikangas <tomi.leppikangas@oulu.fi>
28 * Roland Mainz <roland.mainz@informatik.med.uni-giessen.de>
29 * Daniel Glazman <glazman@netscape.com>
30 * Neil Deakin <neil@mozdevgroup.com>
31 * Masayuki Nakano <masayuki@d-toybox.com>
32 * Mats Palmgren <mats.palmgren@bredband.net>
33 * Uri Bernstein <uriber@gmail.com>
34 * Stephen Blackheath <entangled.mooched.stephen@blacksapphire.com>
36 * Alternatively, the contents of this file may be used under the terms of
37 * either of the GNU General Public License Version 2 or later (the "GPL"),
38 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
39 * in which case the provisions of the GPL or the LGPL are applicable instead
40 * of those above. If you wish to allow use of your version of this file only
41 * under the terms of either the GPL or the LGPL, and not to allow others to
42 * use your version of this file under the terms of the MPL, indicate your
43 * decision by deleting the provisions above and replace them with the notice
44 * and other provisions required by the GPL or the LGPL. If you do not delete
45 * the provisions above, a recipient may use your version of this file under
46 * the terms of any one of the MPL, the GPL or the LGPL.
48 * ***** END LICENSE BLOCK ***** */
50 #ifndef nsTextFrame_h__
51 #define nsTextFrame_h__
54 #include "nsLineBox.h"
56 #include "gfxSkipChars.h"
57 #include "gfxContext.h"
59 class nsTextPaintStyle
;
60 class PropertyProvider
;
62 // This state bit is set on frames that have some non-collapsed characters after
64 #define TEXT_HAS_NONCOLLAPSED_CHARACTERS 0x80000000
66 class nsTextFrame
: public nsFrame
{
68 friend class nsContinuingTextFrame
;
70 nsTextFrame(nsStyleContext
* aContext
) : nsFrame(aContext
)
72 NS_ASSERTION(mContentOffset
== 0, "Bogus content offset");
76 NS_IMETHOD
BuildDisplayList(nsDisplayListBuilder
* aBuilder
,
77 const nsRect
& aDirtyRect
,
78 const nsDisplayListSet
& aLists
);
80 NS_IMETHOD
Init(nsIContent
* aContent
,
82 nsIFrame
* aPrevInFlow
);
84 virtual void Destroy();
86 NS_IMETHOD
GetCursor(const nsPoint
& aPoint
,
87 nsIFrame::Cursor
& aCursor
);
89 NS_IMETHOD
CharacterDataChanged(nsPresContext
* aPresContext
,
93 NS_IMETHOD
DidSetStyleContext();
95 virtual nsIFrame
* GetNextContinuation() const {
96 return mNextContinuation
;
98 NS_IMETHOD
SetNextContinuation(nsIFrame
* aNextContinuation
) {
99 NS_ASSERTION (!aNextContinuation
|| GetType() == aNextContinuation
->GetType(),
100 "setting a next continuation with incorrect type!");
101 NS_ASSERTION (!nsSplittableFrame::IsInNextContinuationChain(aNextContinuation
, this),
102 "creating a loop in continuation chain!");
103 mNextContinuation
= aNextContinuation
;
104 if (aNextContinuation
)
105 aNextContinuation
->RemoveStateBits(NS_FRAME_IS_FLUID_CONTINUATION
);
108 virtual nsIFrame
* GetNextInFlowVirtual() const { return GetNextInFlow(); }
109 nsIFrame
* GetNextInFlow() const {
110 return mNextContinuation
&& (mNextContinuation
->GetStateBits() & NS_FRAME_IS_FLUID_CONTINUATION
) ?
111 mNextContinuation
: nsnull
;
113 NS_IMETHOD
SetNextInFlow(nsIFrame
* aNextInFlow
) {
114 NS_ASSERTION (!aNextInFlow
|| GetType() == aNextInFlow
->GetType(),
115 "setting a next in flow with incorrect type!");
116 NS_ASSERTION (!nsSplittableFrame::IsInNextContinuationChain(aNextInFlow
, this),
117 "creating a loop in continuation chain!");
118 mNextContinuation
= aNextInFlow
;
120 aNextInFlow
->AddStateBits(NS_FRAME_IS_FLUID_CONTINUATION
);
123 virtual nsIFrame
* GetLastInFlow() const;
124 virtual nsIFrame
* GetLastContinuation() const;
126 virtual nsSplittableType
GetSplittableType() const {
127 return NS_FRAME_SPLITTABLE
;
131 * Get the "type" of the frame
133 * @see nsGkAtoms::textFrame
135 virtual nsIAtom
* GetType() const;
137 virtual PRBool
IsFrameOfType(PRUint32 aFlags
) const
139 // Set the frame state bit for text frames to mark them as replaced.
140 // XXX kipp: temporary
141 return nsFrame::IsFrameOfType(aFlags
& ~(nsIFrame::eReplaced
|
142 nsIFrame::eLineParticipant
));
146 NS_IMETHOD
List(FILE* out
, PRInt32 aIndent
) const;
147 NS_IMETHOD
GetFrameName(nsAString
& aResult
) const;
148 NS_IMETHOD_(nsFrameState
) GetDebugStateBits() const ;
151 virtual ContentOffsets
CalcContentOffsetsFromFramePoint(nsPoint aPoint
);
153 NS_IMETHOD
SetSelected(nsPresContext
* aPresContext
,
158 virtual PRBool
PeekOffsetNoAmount(PRBool aForward
, PRInt32
* aOffset
);
159 virtual PRBool
PeekOffsetCharacter(PRBool aForward
, PRInt32
* aOffset
);
160 virtual PRBool
PeekOffsetWord(PRBool aForward
, PRBool aWordSelectEatSpace
, PRBool aIsKeyboardSelect
,
161 PRInt32
* aOffset
, PeekWordState
* aState
);
163 NS_IMETHOD
CheckVisibility(nsPresContext
* aContext
, PRInt32 aStartIndex
, PRInt32 aEndIndex
, PRBool aRecurse
, PRBool
*aFinished
, PRBool
*_retval
);
165 // Update offsets to account for new length. This may clear mTextRun.
166 void SetLength(PRInt32 aLength
);
168 NS_IMETHOD
GetOffsets(PRInt32
&start
, PRInt32
&end
)const;
170 virtual void AdjustOffsetsForBidi(PRInt32 start
, PRInt32 end
);
172 NS_IMETHOD
GetPointFromOffset(PRInt32 inOffset
,
175 NS_IMETHOD
GetChildFrameContainingOffset(PRInt32 inContentOffset
,
177 PRInt32
* outFrameContentOffset
,
178 nsIFrame
* *outChildFrame
);
180 virtual PRBool
IsVisibleInSelection(nsISelection
* aSelection
);
182 virtual PRBool
IsEmpty();
183 virtual PRBool
IsSelfEmpty() { return IsEmpty(); }
186 * @return PR_TRUE if this text frame ends with a newline character. It
187 * should return PR_FALSE if this is not a text frame.
189 virtual PRBool
HasTerminalNewline() const;
192 * Returns true if this text frame is logically adjacent to the end of the
195 PRBool
IsAtEndOfLine() const;
198 * Call this only after reflow the frame. Returns true if non-collapsed
199 * characters are present.
201 PRBool
HasNoncollapsedCharacters() const {
202 return (GetStateBits() & TEXT_HAS_NONCOLLAPSED_CHARACTERS
) != 0;
206 NS_IMETHOD
GetAccessible(nsIAccessible
** aAccessible
);
209 virtual void MarkIntrinsicWidthsDirty();
210 virtual nscoord
GetMinWidth(nsIRenderingContext
*aRenderingContext
);
211 virtual nscoord
GetPrefWidth(nsIRenderingContext
*aRenderingContext
);
212 virtual void AddInlineMinWidth(nsIRenderingContext
*aRenderingContext
,
213 InlineMinWidthData
*aData
);
214 virtual void AddInlinePrefWidth(nsIRenderingContext
*aRenderingContext
,
215 InlinePrefWidthData
*aData
);
216 virtual nsSize
ComputeSize(nsIRenderingContext
*aRenderingContext
,
217 nsSize aCBSize
, nscoord aAvailableWidth
,
218 nsSize aMargin
, nsSize aBorder
, nsSize aPadding
,
220 virtual nsRect
ComputeTightBounds(gfxContext
* aContext
) const;
221 NS_IMETHOD
Reflow(nsPresContext
* aPresContext
,
222 nsHTMLReflowMetrics
& aMetrics
,
223 const nsHTMLReflowState
& aReflowState
,
224 nsReflowStatus
& aStatus
);
225 virtual PRBool
CanContinueTextRun() const;
226 // Method that is called for a text frame that is logically
227 // adjacent to the end of the line (i.e. followed only by empty text frames,
228 // placeholders or inlines containing such).
230 // true if we trimmed some space or changed metrics in some other way.
231 // In this case, we should call RecomputeOverflowRect on this frame.
232 PRPackedBool mChanged
;
233 // true if the last character is not justifiable so should be subtracted
234 // from the count of justifiable characters in the frame, since the last
235 // character in a line is not justifiable.
236 PRPackedBool mLastCharIsJustifiable
;
237 // an amount to *subtract* from the frame's width (zero if !mChanged)
240 TrimOutput
TrimTrailingWhiteSpace(nsIRenderingContext
* aRC
);
241 virtual nsresult
GetRenderedText(nsAString
* aString
= nsnull
,
242 gfxSkipChars
* aSkipChars
= nsnull
,
243 gfxSkipCharsIterator
* aSkipIter
= nsnull
,
244 PRUint32 aSkippedStartOffset
= 0,
245 PRUint32 aSkippedMaxLength
= PR_UINT32_MAX
);
247 nsRect
RecomputeOverflowRect();
249 void AddInlineMinWidthForFlow(nsIRenderingContext
*aRenderingContext
,
250 nsIFrame::InlineMinWidthData
*aData
);
251 void AddInlinePrefWidthForFlow(nsIRenderingContext
*aRenderingContext
,
252 InlinePrefWidthData
*aData
);
254 gfxFloat
GetSnappedBaselineY(gfxContext
* aContext
, gfxFloat aY
);
256 // primary frame paint method called from nsDisplayText
257 // The private DrawText() is what applies the text to a graphics context
258 void PaintText(nsIRenderingContext
* aRenderingContext
, nsPoint aPt
,
259 const nsRect
& aDirtyRect
);
260 // helper: paint quirks-mode CSS text decorations
261 void PaintTextDecorations(gfxContext
* aCtx
, const gfxRect
& aDirtyRect
,
262 const gfxPoint
& aFramePt
,
263 const gfxPoint
& aTextBaselinePt
,
264 nsTextPaintStyle
& aTextStyle
,
265 PropertyProvider
& aProvider
,
266 const nscolor
& aOverrideColor
= 0);
267 // helper: paint text frame when we're impacted by at least one selection.
268 // Return PR_FALSE if the text was not painted and we should continue with
270 PRBool
PaintTextWithSelection(gfxContext
* aCtx
,
271 const gfxPoint
& aFramePt
,
272 const gfxPoint
& aTextBaselinePt
,
273 const gfxRect
& aDirtyRect
,
274 PropertyProvider
& aProvider
,
275 nsTextPaintStyle
& aTextPaintStyle
);
276 // helper: paint text with foreground and background colors determined
277 // by selection(s). Also computes a mask of all selection types applying to
278 // our text, returned in aAllTypes.
279 void PaintTextWithSelectionColors(gfxContext
* aCtx
,
280 const gfxPoint
& aFramePt
,
281 const gfxPoint
& aTextBaselinePt
,
282 const gfxRect
& aDirtyRect
,
283 PropertyProvider
& aProvider
,
284 nsTextPaintStyle
& aTextPaintStyle
,
285 SelectionDetails
* aDetails
,
286 SelectionType
* aAllTypes
);
287 // helper: paint text decorations for text selected by aSelectionType
288 void PaintTextSelectionDecorations(gfxContext
* aCtx
,
289 const gfxPoint
& aFramePt
,
290 const gfxPoint
& aTextBaselinePt
,
291 const gfxRect
& aDirtyRect
,
292 PropertyProvider
& aProvider
,
293 nsTextPaintStyle
& aTextPaintStyle
,
294 SelectionDetails
* aDetails
,
295 SelectionType aSelectionType
);
297 PRInt16
GetSelectionStatus(PRInt16
* aSelectionFlags
);
300 void ToCString(nsCString
& aBuf
, PRInt32
* aTotalContentLength
) const;
303 PRInt32
GetContentOffset() const { return mContentOffset
; }
304 PRInt32
GetContentLength() const
306 NS_ASSERTION(GetContentEnd() - mContentOffset
>= 0, "negative length");
307 return GetContentEnd() - mContentOffset
;
309 PRInt32
GetContentEnd() const;
310 // This returns the length the frame thinks it *should* have after it was
311 // last reflowed (0 if it hasn't been reflowed yet). This should be used only
312 // when setting up the text offsets for a new continuation frame.
313 PRInt32
GetContentLengthHint() const { return mContentLengthHint
; }
315 // Compute the length of the content mapped by this frame
316 // and all its in-flow siblings. Basically this means starting at mContentOffset
317 // and going to the end of the text node or the next bidi continuation
319 PRInt32
GetInFlowContentLength();
321 // Clears out mTextRun from this frame and all other frames that hold a reference
322 // to it, then deletes the textrun.
325 * Acquires the text run for this content, if necessary.
326 * @param aRC the rendering context to use as a reference for creating
327 * the textrun, if available (if not, we'll create one which will just be slower)
328 * @param aBlock the block ancestor for this frame, or nsnull if unknown
329 * @param aLine the line that this frame is on, if any, or nsnull if unknown
330 * @param aFlowEndInTextRun if non-null, this returns the textrun offset of
331 * end of the text associated with this frame and its in-flow siblings
332 * @return a gfxSkipCharsIterator set up to map DOM offsets for this frame
333 * to offsets into the textrun; its initial offset is set to this frame's
336 gfxSkipCharsIterator
EnsureTextRun(gfxContext
* aReferenceContext
= nsnull
,
337 nsIFrame
* aLineContainer
= nsnull
,
338 const nsLineList::iterator
* aLine
= nsnull
,
339 PRUint32
* aFlowEndInTextRun
= nsnull
);
341 gfxTextRun
* GetTextRun() { return mTextRun
; }
342 void SetTextRun(gfxTextRun
* aTextRun
) { mTextRun
= aTextRun
; }
344 // Get the DOM content range mapped by this frame after excluding
345 // whitespace subject to start-of-line and end-of-line trimming.
346 // The textrun must have been created before calling this.
347 struct TrimmedOffsets
{
350 PRInt32
GetEnd() { return mStart
+ mLength
; }
352 TrimmedOffsets
GetTrimmedOffsets(const nsTextFragment
* aFrag
,
356 virtual ~nsTextFrame();
358 nsIFrame
* mNextContinuation
;
359 // The key invariant here is that mContentOffset never decreases along
360 // a next-continuation chain. And of course mContentOffset is always <= the
361 // the text node's content length, and the mContentOffset for the first frame
362 // is always 0. Furthermore the text mapped by a frame is determined by
363 // GetContentOffset() and GetContentLength()/GetContentEnd(), which get
364 // the length from the difference between this frame's offset and the next
365 // frame's offset, or the text length if there is no next frame. This means
366 // the frames always map the text node without overlapping or leaving any gaps.
367 PRInt32 mContentOffset
;
368 // This does *not* indicate the length of text currently mapped by the frame;
369 // instead it's a hint saying that this frame *wants* to map this much text
370 // so if we create a new continuation, this is where that continuation should
372 PRInt32 mContentLengthHint
;
374 gfxTextRun
* mTextRun
;
376 // The caller of this method must call DestroySelectionDetails() on the
377 // return value, if that return value is not null. Calling
378 // DestroySelectionDetails() on a null value is still OK, just not necessary.
379 SelectionDetails
* GetSelectionDetails();
381 void UnionTextDecorationOverflow(nsPresContext
* aPresContext
,
382 PropertyProvider
& aProvider
,
383 nsRect
* aOverflowRect
);
385 void DrawText(gfxContext
* aCtx
,
386 const gfxPoint
& aTextBaselinePt
,
389 const gfxRect
* aDirtyRect
,
390 PropertyProvider
* aProvider
,
391 gfxFloat
& aAdvanceWidth
,
392 PRBool aDrawSoftHyphen
);
394 void PaintOneShadow(PRUint32 aOffset
,
396 nsCSSShadowItem
* aShadowDetails
,
397 PropertyProvider
* aProvider
,
398 const gfxRect
& aDirtyRect
,
399 const gfxPoint
& aFramePt
,
400 const gfxPoint
& aTextBaselinePt
,
402 const nscolor
& aForegroundColor
);
404 struct TextDecorations
{
405 PRUint8 mDecorations
;
408 nscolor mStrikeColor
;
411 mDecorations(0), mOverColor(NS_RGB(0, 0, 0)),
412 mUnderColor(NS_RGB(0, 0, 0)), mStrikeColor(NS_RGB(0, 0, 0))
415 PRBool
HasDecorationlines() {
416 return !!(mDecorations
& (NS_STYLE_TEXT_DECORATION_UNDERLINE
|
417 NS_STYLE_TEXT_DECORATION_OVERLINE
|
418 NS_STYLE_TEXT_DECORATION_LINE_THROUGH
));
420 PRBool
HasUnderline() {
421 return !!(mDecorations
& NS_STYLE_TEXT_DECORATION_UNDERLINE
);
423 PRBool
HasOverline() {
424 return !!(mDecorations
& NS_STYLE_TEXT_DECORATION_OVERLINE
);
426 PRBool
HasStrikeout() {
427 return !!(mDecorations
& NS_STYLE_TEXT_DECORATION_LINE_THROUGH
);
430 TextDecorations
GetTextDecorations(nsPresContext
* aPresContext
);
432 PRBool
HasSelectionOverflowingDecorations(nsPresContext
* aPresContext
,
433 float* aRatio
= nsnull
);
435 PRBool
IsFloatingFirstLetterChild();