зеркало из https://github.com/mozilla/gecko-dev.git
354 строки
16 KiB
C++
354 строки
16 KiB
C++
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* ***** BEGIN LICENSE BLOCK *****
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
*
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
* the License. You may obtain a copy of the License at
|
|
* http://www.mozilla.org/MPL/
|
|
*
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
* for the specific language governing rights and limitations under the
|
|
* License.
|
|
*
|
|
* The Original Code is mozilla.org code.
|
|
*
|
|
* The Initial Developer of the Original Code is
|
|
* Netscape Communications Corporation.
|
|
* Portions created by the Initial Developer are Copyright (C) 1998
|
|
* the Initial Developer. All Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
* Robert O'Callahan <robert@ocallahan.org>
|
|
* Roger B. Sidje <rbs@maths.uq.edu.au>
|
|
* Pierre Phaneuf <pp@ludusdesign.com>
|
|
* Prabhat Hegde <prabhat.hegde@sun.com>
|
|
* Tomi Leppikangas <tomi.leppikangas@oulu.fi>
|
|
* Roland Mainz <roland.mainz@informatik.med.uni-giessen.de>
|
|
* Daniel Glazman <glazman@netscape.com>
|
|
* Neil Deakin <neil@mozdevgroup.com>
|
|
* Masayuki Nakano <masayuki@d-toybox.com>
|
|
* Mats Palmgren <mats.palmgren@bredband.net>
|
|
* Uri Bernstein <uriber@gmail.com>
|
|
* Stephen Blackheath <entangled.mooched.stephen@blacksapphire.com>
|
|
*
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
|
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
* use your version of this file under the terms of the MPL, indicate your
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
* the provisions above, a recipient may use your version of this file under
|
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
|
*
|
|
* ***** END LICENSE BLOCK ***** */
|
|
|
|
#ifndef nsTextFrame_h__
|
|
#define nsTextFrame_h__
|
|
|
|
#include "nsFrame.h"
|
|
#include "nsLineBox.h"
|
|
#include "gfxFont.h"
|
|
#include "gfxSkipChars.h"
|
|
|
|
class nsTextPaintStyle;
|
|
class PropertyProvider;
|
|
|
|
class nsTextFrame : public nsFrame {
|
|
public:
|
|
nsTextFrame(nsStyleContext* aContext) : nsFrame(aContext)
|
|
{
|
|
NS_ASSERTION(mContentOffset == 0, "Bogus content offset");
|
|
}
|
|
|
|
// nsIFrame
|
|
NS_IMETHOD BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
|
const nsRect& aDirtyRect,
|
|
const nsDisplayListSet& aLists);
|
|
|
|
NS_IMETHOD Init(nsIContent* aContent,
|
|
nsIFrame* aParent,
|
|
nsIFrame* aPrevInFlow);
|
|
|
|
virtual void Destroy();
|
|
|
|
NS_IMETHOD GetCursor(const nsPoint& aPoint,
|
|
nsIFrame::Cursor& aCursor);
|
|
|
|
NS_IMETHOD CharacterDataChanged(nsPresContext* aPresContext,
|
|
nsIContent* aChild,
|
|
PRBool aAppend);
|
|
|
|
NS_IMETHOD DidSetStyleContext();
|
|
|
|
virtual nsIFrame* GetNextContinuation() const {
|
|
return mNextContinuation;
|
|
}
|
|
NS_IMETHOD SetNextContinuation(nsIFrame* aNextContinuation) {
|
|
NS_ASSERTION (!aNextContinuation || GetType() == aNextContinuation->GetType(),
|
|
"setting a next continuation with incorrect type!");
|
|
NS_ASSERTION (!nsSplittableFrame::IsInNextContinuationChain(aNextContinuation, this),
|
|
"creating a loop in continuation chain!");
|
|
mNextContinuation = aNextContinuation;
|
|
if (aNextContinuation)
|
|
aNextContinuation->RemoveStateBits(NS_FRAME_IS_FLUID_CONTINUATION);
|
|
return NS_OK;
|
|
}
|
|
virtual nsIFrame* GetNextInFlowVirtual() const { return GetNextInFlow(); }
|
|
nsIFrame* GetNextInFlow() const {
|
|
return mNextContinuation && (mNextContinuation->GetStateBits() & NS_FRAME_IS_FLUID_CONTINUATION) ?
|
|
mNextContinuation : nsnull;
|
|
}
|
|
NS_IMETHOD SetNextInFlow(nsIFrame* aNextInFlow) {
|
|
NS_ASSERTION (!aNextInFlow || GetType() == aNextInFlow->GetType(),
|
|
"setting a next in flow with incorrect type!");
|
|
NS_ASSERTION (!nsSplittableFrame::IsInNextContinuationChain(aNextInFlow, this),
|
|
"creating a loop in continuation chain!");
|
|
mNextContinuation = aNextInFlow;
|
|
if (aNextInFlow)
|
|
aNextInFlow->AddStateBits(NS_FRAME_IS_FLUID_CONTINUATION);
|
|
return NS_OK;
|
|
}
|
|
virtual nsIFrame* GetLastInFlow() const;
|
|
virtual nsIFrame* GetLastContinuation() const;
|
|
|
|
virtual nsSplittableType GetSplittableType() const {
|
|
return NS_FRAME_SPLITTABLE;
|
|
}
|
|
|
|
/**
|
|
* Get the "type" of the frame
|
|
*
|
|
* @see nsGkAtoms::textFrame
|
|
*/
|
|
virtual nsIAtom* GetType() const;
|
|
|
|
virtual PRBool IsFrameOfType(PRUint32 aFlags) const
|
|
{
|
|
// Set the frame state bit for text frames to mark them as replaced.
|
|
// XXX kipp: temporary
|
|
return nsFrame::IsFrameOfType(aFlags & ~(nsIFrame::eReplaced |
|
|
nsIFrame::eLineParticipant));
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
NS_IMETHOD List(FILE* out, PRInt32 aIndent) const;
|
|
NS_IMETHOD GetFrameName(nsAString& aResult) const;
|
|
NS_IMETHOD_(nsFrameState) GetDebugStateBits() const ;
|
|
#endif
|
|
|
|
virtual ContentOffsets CalcContentOffsetsFromFramePoint(nsPoint aPoint);
|
|
|
|
NS_IMETHOD SetSelected(nsPresContext* aPresContext,
|
|
nsIDOMRange *aRange,
|
|
PRBool aSelected,
|
|
nsSpread aSpread);
|
|
|
|
virtual PRBool PeekOffsetNoAmount(PRBool aForward, PRInt32* aOffset);
|
|
virtual PRBool PeekOffsetCharacter(PRBool aForward, PRInt32* aOffset);
|
|
virtual PRBool PeekOffsetWord(PRBool aForward, PRBool aWordSelectEatSpace, PRBool aIsKeyboardSelect,
|
|
PRInt32* aOffset, PeekWordState* aState);
|
|
|
|
NS_IMETHOD CheckVisibility(nsPresContext* aContext, PRInt32 aStartIndex, PRInt32 aEndIndex, PRBool aRecurse, PRBool *aFinished, PRBool *_retval);
|
|
|
|
// Update offsets to account for new length. This may clear mTextRun.
|
|
void SetLength(PRInt32 aLength);
|
|
|
|
NS_IMETHOD GetOffsets(PRInt32 &start, PRInt32 &end)const;
|
|
|
|
virtual void AdjustOffsetsForBidi(PRInt32 start, PRInt32 end);
|
|
|
|
NS_IMETHOD GetPointFromOffset(PRInt32 inOffset,
|
|
nsPoint* outPoint);
|
|
|
|
NS_IMETHOD GetChildFrameContainingOffset(PRInt32 inContentOffset,
|
|
PRBool inHint,
|
|
PRInt32* outFrameContentOffset,
|
|
nsIFrame* *outChildFrame);
|
|
|
|
virtual PRBool IsVisibleInSelection(nsISelection* aSelection);
|
|
|
|
virtual PRBool IsEmpty();
|
|
virtual PRBool IsSelfEmpty() { return IsEmpty(); }
|
|
|
|
/**
|
|
* @return PR_TRUE if this text frame ends with a newline character. It
|
|
* should return PR_FALSE if this is not a text frame.
|
|
*/
|
|
virtual PRBool HasTerminalNewline() const;
|
|
|
|
/**
|
|
* Returns true if this text frame is logically adjacent to the end of the
|
|
* line.
|
|
*/
|
|
PRBool IsAtEndOfLine() const;
|
|
|
|
#ifdef ACCESSIBILITY
|
|
NS_IMETHOD GetAccessible(nsIAccessible** aAccessible);
|
|
#endif
|
|
|
|
virtual void MarkIntrinsicWidthsDirty();
|
|
virtual nscoord GetMinWidth(nsIRenderingContext *aRenderingContext);
|
|
virtual nscoord GetPrefWidth(nsIRenderingContext *aRenderingContext);
|
|
virtual void AddInlineMinWidth(nsIRenderingContext *aRenderingContext,
|
|
InlineMinWidthData *aData);
|
|
virtual void AddInlinePrefWidth(nsIRenderingContext *aRenderingContext,
|
|
InlinePrefWidthData *aData);
|
|
virtual nsSize ComputeSize(nsIRenderingContext *aRenderingContext,
|
|
nsSize aCBSize, nscoord aAvailableWidth,
|
|
nsSize aMargin, nsSize aBorder, nsSize aPadding,
|
|
PRBool aShrinkWrap);
|
|
virtual nsRect ComputeTightBounds(gfxContext* aContext) const;
|
|
NS_IMETHOD Reflow(nsPresContext* aPresContext,
|
|
nsHTMLReflowMetrics& aMetrics,
|
|
const nsHTMLReflowState& aReflowState,
|
|
nsReflowStatus& aStatus);
|
|
virtual PRBool CanContinueTextRun() const;
|
|
NS_IMETHOD TrimTrailingWhiteSpace(nsPresContext* aPresContext,
|
|
nsIRenderingContext& aRC,
|
|
nscoord& aDeltaWidth,
|
|
PRBool& aLastCharIsJustifiable);
|
|
virtual nsresult GetRenderedText(nsAString* aString = nsnull,
|
|
gfxSkipChars* aSkipChars = nsnull,
|
|
gfxSkipCharsIterator* aSkipIter = nsnull,
|
|
PRUint32 aSkippedStartOffset = 0,
|
|
PRUint32 aSkippedMaxLength = PR_UINT32_MAX);
|
|
|
|
nsRect RecomputeOverflowRect();
|
|
|
|
void AddInlineMinWidthForFlow(nsIRenderingContext *aRenderingContext,
|
|
nsIFrame::InlineMinWidthData *aData);
|
|
void AddInlinePrefWidthForFlow(nsIRenderingContext *aRenderingContext,
|
|
InlinePrefWidthData *aData);
|
|
|
|
gfxFloat GetSnappedBaselineY(gfxContext* aContext, gfxFloat aY);
|
|
|
|
// primary frame paint method called from nsDisplayText
|
|
void PaintText(nsIRenderingContext* aRenderingContext, nsPoint aPt,
|
|
const nsRect& aDirtyRect);
|
|
// helper: paint quirks-mode CSS text decorations
|
|
void PaintTextDecorations(gfxContext* aCtx, const gfxRect& aDirtyRect,
|
|
const gfxPoint& aFramePt,
|
|
const gfxPoint& aTextBaselinePt,
|
|
nsTextPaintStyle& aTextStyle,
|
|
PropertyProvider& aProvider);
|
|
// helper: paint text frame when we're impacted by at least one selection.
|
|
// Return PR_FALSE if the text was not painted and we should continue with
|
|
// the fast path.
|
|
PRBool PaintTextWithSelection(gfxContext* aCtx,
|
|
const gfxPoint& aFramePt,
|
|
const gfxPoint& aTextBaselinePt,
|
|
const gfxRect& aDirtyRect,
|
|
PropertyProvider& aProvider,
|
|
nsTextPaintStyle& aTextPaintStyle);
|
|
// helper: paint text with foreground and background colors determined
|
|
// by selection(s). Also computes a mask of all selection types applying to
|
|
// our text, returned in aAllTypes.
|
|
void PaintTextWithSelectionColors(gfxContext* aCtx,
|
|
const gfxPoint& aFramePt,
|
|
const gfxPoint& aTextBaselinePt,
|
|
const gfxRect& aDirtyRect,
|
|
PropertyProvider& aProvider,
|
|
nsTextPaintStyle& aTextPaintStyle,
|
|
SelectionDetails* aDetails,
|
|
SelectionType* aAllTypes);
|
|
// helper: paint text decorations for text selected by aSelectionType
|
|
void PaintTextSelectionDecorations(gfxContext* aCtx,
|
|
const gfxPoint& aFramePt,
|
|
const gfxPoint& aTextBaselinePt,
|
|
const gfxRect& aDirtyRect,
|
|
PropertyProvider& aProvider,
|
|
nsTextPaintStyle& aTextPaintStyle,
|
|
SelectionDetails* aDetails,
|
|
SelectionType aSelectionType);
|
|
|
|
PRInt16 GetSelectionStatus(PRInt16* aSelectionFlags);
|
|
|
|
#ifdef DEBUG
|
|
void ToCString(nsString& aBuf, PRInt32* aTotalContentLength) const;
|
|
#endif
|
|
|
|
PRInt32 GetContentOffset() const { return mContentOffset; }
|
|
PRInt32 GetContentLength() const { return GetContentEnd() - mContentOffset; }
|
|
PRInt32 GetContentEnd() const;
|
|
// This returns the length the frame thinks it *should* have after it was
|
|
// last reflowed (0 if it hasn't been reflowed yet). This should be used only
|
|
// when setting up the text offsets for a new continuation frame.
|
|
PRInt32 GetContentLengthHint() const { return mContentLengthHint; }
|
|
|
|
// Compute the length of the content mapped by this frame
|
|
// and all its in-flow siblings. Basically this means starting at mContentOffset
|
|
// and going to the end of the text node or the next bidi continuation
|
|
// boundary.
|
|
PRInt32 GetInFlowContentLength();
|
|
|
|
// Clears out mTextRun from this frame and all other frames that hold a reference
|
|
// to it, then deletes the textrun.
|
|
void ClearTextRun();
|
|
/**
|
|
* Acquires the text run for this content, if necessary.
|
|
* @param aRC the rendering context to use as a reference for creating
|
|
* the textrun, if available (if not, we'll create one which will just be slower)
|
|
* @param aBlock the block ancestor for this frame, or nsnull if unknown
|
|
* @param aLine the line that this frame is on, if any, or nsnull if unknown
|
|
* @param aFlowEndInTextRun if non-null, this returns the textrun offset of
|
|
* end of the text associated with this frame and its in-flow siblings
|
|
* @return a gfxSkipCharsIterator set up to map DOM offsets for this frame
|
|
* to offsets into the textrun; its initial offset is set to this frame's
|
|
* content offset
|
|
*/
|
|
gfxSkipCharsIterator EnsureTextRun(gfxContext* aReferenceContext = nsnull,
|
|
nsIFrame* aLineContainer = nsnull,
|
|
const nsLineList::iterator* aLine = nsnull,
|
|
PRUint32* aFlowEndInTextRun = nsnull);
|
|
|
|
gfxTextRun* GetTextRun() { return mTextRun; }
|
|
void SetTextRun(gfxTextRun* aTextRun) { mTextRun = aTextRun; }
|
|
|
|
// Get the DOM content range mapped by this frame after excluding
|
|
// whitespace subject to start-of-line and end-of-line trimming.
|
|
// The textrun must have been created before calling this.
|
|
struct TrimmedOffsets {
|
|
PRInt32 mStart;
|
|
PRInt32 mLength;
|
|
PRInt32 GetEnd() { return mStart + mLength; }
|
|
};
|
|
TrimmedOffsets GetTrimmedOffsets(const nsTextFragment* aFrag,
|
|
PRBool aTrimAfter);
|
|
|
|
protected:
|
|
virtual ~nsTextFrame();
|
|
|
|
nsIFrame* mNextContinuation;
|
|
// The key invariant here is that mContentOffset never decreases along
|
|
// a next-continuation chain. And of course mContentOffset is always <= the
|
|
// the text node's content length, and the mContentOffset for the first frame
|
|
// is always 0. Furthermore the text mapped by a frame is determined by
|
|
// GetContentOffset() and GetContentLength()/GetContentEnd(), which get
|
|
// the length from the difference between this frame's offset and the next
|
|
// frame's offset, or the text length if there is no next frame. This means
|
|
// the frames always map the text node without overlapping or leaving any gaps.
|
|
PRInt32 mContentOffset;
|
|
// This does *not* indicate the length of text currently mapped by the frame;
|
|
// instead it's a hint saying that this frame *wants* to map this much text
|
|
// so if we create a new continuation, this is where that continuation should
|
|
// start.
|
|
PRInt32 mContentLengthHint;
|
|
nscoord mAscent;
|
|
gfxTextRun* mTextRun;
|
|
|
|
SelectionDetails* GetSelectionDetails();
|
|
|
|
void AdjustSelectionPointsForBidi(SelectionDetails *sdptr,
|
|
PRInt32 textLength,
|
|
PRBool isRTLChars,
|
|
PRBool isOddLevel,
|
|
PRBool isBidiSystem);
|
|
};
|
|
|
|
#endif
|