зеркало из https://github.com/mozilla/gecko-dev.git
Bug 343445. Change inline reflow strategy to avoid looking ahead through words while measuring text. r+sr=dbaron
This commit is contained in:
Родитель
4e71dcf716
Коммит
899128e82a
|
@ -249,6 +249,16 @@ nsTextFragment::AppendTo(nsAString& aString) const
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsTextFragment::AppendTo(nsAString& aString, PRInt32 aOffset, PRInt32 aLength) const
|
||||
{
|
||||
if (mState.mIs2b) {
|
||||
aString.Append(m2b + aOffset, aLength);
|
||||
} else {
|
||||
AppendASCIItoUTF16(Substring(m1b + aOffset, m1b + aOffset + aLength), aString);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsTextFragment::CopyTo(PRUnichar *aDest, PRInt32 aOffset, PRInt32 aCount)
|
||||
{
|
||||
|
|
|
@ -160,6 +160,13 @@ public:
|
|||
*/
|
||||
void AppendTo(nsAString& aString) const;
|
||||
|
||||
/**
|
||||
* Append a substring of the contents of this string fragment to aString.
|
||||
* @param aOffset where to start the substring in this text fragment
|
||||
* @param aLength the length of the substring
|
||||
*/
|
||||
void AppendTo(nsAString& aString, PRInt32 aOffset, PRInt32 aLength) const;
|
||||
|
||||
/**
|
||||
* Make a copy of the fragments contents starting at offset for
|
||||
* count characters. The offset and count will be adjusted to
|
||||
|
|
|
@ -95,18 +95,11 @@ DestroyRectFunc(void* aFrame,
|
|||
delete NS_STATIC_CAST(nsRect*, aPropertyValue);
|
||||
}
|
||||
|
||||
static nsIFrame* GetParentOrPlaceholderFor(nsFrameManager* aFrameManager,
|
||||
nsIFrame* aFrame) {
|
||||
if (aFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
|
||||
return aFrameManager->GetPlaceholderFrameFor(aFrame);
|
||||
}
|
||||
return aFrame->GetParent();
|
||||
}
|
||||
|
||||
static void MarkFrameForDisplay(nsIFrame* aFrame, nsIFrame* aStopAtFrame) {
|
||||
nsFrameManager* frameManager = aFrame->GetPresContext()->PresShell()->FrameManager();
|
||||
|
||||
for (nsIFrame* f = aFrame; f; f = GetParentOrPlaceholderFor(frameManager, f)) {
|
||||
for (nsIFrame* f = aFrame; f;
|
||||
f = nsLayoutUtils::GetParentOrPlaceholderFor(frameManager, f)) {
|
||||
if (f->GetStateBits() & NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO)
|
||||
return;
|
||||
f->AddStateBits(NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO);
|
||||
|
@ -135,7 +128,8 @@ static void UnmarkFrameForDisplay(nsIFrame* aFrame) {
|
|||
|
||||
nsFrameManager* frameManager = aFrame->GetPresContext()->PresShell()->FrameManager();
|
||||
|
||||
for (nsIFrame* f = aFrame; f; f = GetParentOrPlaceholderFor(frameManager, f)) {
|
||||
for (nsIFrame* f = aFrame; f;
|
||||
f = nsLayoutUtils::GetParentOrPlaceholderFor(frameManager, f)) {
|
||||
if (!(f->GetStateBits() & NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO))
|
||||
return;
|
||||
f->RemoveStateBits(NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO);
|
||||
|
|
|
@ -56,6 +56,7 @@
|
|||
#include "nsGUIEvent.h"
|
||||
#include "nsDisplayList.h"
|
||||
#include "nsRegion.h"
|
||||
#include "nsFrameManager.h"
|
||||
|
||||
#ifdef MOZ_SVG_FOREIGNOBJECT
|
||||
#include "nsSVGForeignObjectFrame.h"
|
||||
|
@ -995,3 +996,69 @@ nsLayoutUtils::GetFontMetricsForFrame(nsIFrame* aFrame,
|
|||
sc->GetStyleVisibility()->mLangGroup,
|
||||
*aFontMetrics);
|
||||
}
|
||||
|
||||
nsIFrame*
|
||||
nsLayoutUtils::GetParentOrPlaceholderFor(nsFrameManager* aFrameManager,
|
||||
nsIFrame* aFrame)
|
||||
{
|
||||
if (aFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW)
|
||||
return aFrameManager->GetPlaceholderFrameFor(aFrame);
|
||||
return aFrame->GetParent();
|
||||
}
|
||||
|
||||
nsIFrame*
|
||||
nsLayoutUtils::GetClosestCommonAncestorViaPlaceholders(nsIFrame* aFrame1,
|
||||
nsIFrame* aFrame2,
|
||||
nsIFrame* aKnownCommonAncestorHint)
|
||||
{
|
||||
NS_PRECONDITION(aFrame1, "aFrame1 must not be null");
|
||||
NS_PRECONDITION(aFrame2, "aFrame2 must not be null");
|
||||
|
||||
nsPresContext* presContext = aFrame1->GetPresContext();
|
||||
if (presContext != aFrame2->GetPresContext()) {
|
||||
// different documents, no common ancestor
|
||||
return nsnull;
|
||||
}
|
||||
nsFrameManager* frameManager = presContext->PresShell()->FrameManager();
|
||||
|
||||
nsAutoVoidArray frame1Ancestors;
|
||||
nsIFrame* f1;
|
||||
for (f1 = aFrame1; f1 && f1 != aKnownCommonAncestorHint;
|
||||
f1 = GetParentOrPlaceholderFor(frameManager, f1)) {
|
||||
frame1Ancestors.AppendElement(f1);
|
||||
}
|
||||
if (!f1 && aKnownCommonAncestorHint) {
|
||||
// So, it turns out aKnownCommonAncestorHint was not an ancestor of f1. Oops.
|
||||
// Never mind. We can continue as if aKnownCommonAncestorHint was null.
|
||||
aKnownCommonAncestorHint = nsnull;
|
||||
}
|
||||
|
||||
nsAutoVoidArray frame2Ancestors;
|
||||
nsIFrame* f2;
|
||||
for (f2 = aFrame2; f2 && f2 != aKnownCommonAncestorHint;
|
||||
f2 = GetParentOrPlaceholderFor(frameManager, f2)) {
|
||||
frame2Ancestors.AppendElement(f2);
|
||||
}
|
||||
if (!f2 && aKnownCommonAncestorHint) {
|
||||
// So, it turns out aKnownCommonAncestorHint was not an ancestor of f2.
|
||||
// We need to retry with no common ancestor hint.
|
||||
return GetClosestCommonAncestorViaPlaceholders(aFrame1, aFrame2, nsnull);
|
||||
}
|
||||
|
||||
// now frame1Ancestors and frame2Ancestors give us the parent frame chain
|
||||
// up to aKnownCommonAncestorHint, or if that is null, up to and including
|
||||
// the root frame. We need to walk from the end (i.e., the top of the
|
||||
// frame (sub)tree) down to aFrame1/aFrame2 looking for the first difference.
|
||||
nsIFrame* lastCommonFrame = aKnownCommonAncestorHint;
|
||||
PRInt32 last1 = frame1Ancestors.Count() - 1;
|
||||
PRInt32 last2 = frame2Ancestors.Count() - 1;
|
||||
while (last1 >= 0 && last2 >= 0) {
|
||||
nsIFrame* frame1 = NS_STATIC_CAST(nsIFrame*, frame1Ancestors.ElementAt(last1));
|
||||
if (frame1 != frame2Ancestors.ElementAt(last2))
|
||||
break;
|
||||
lastCommonFrame = frame1;
|
||||
last1--;
|
||||
last2--;
|
||||
}
|
||||
return lastCommonFrame;
|
||||
}
|
||||
|
|
|
@ -431,6 +431,27 @@ public:
|
|||
*/
|
||||
static nsresult GetFontMetricsForFrame(nsIFrame* aFrame,
|
||||
nsIFontMetrics** aFontMetrics);
|
||||
|
||||
/**
|
||||
* If aFrame is an out of flow frame, return its placeholder, otherwise
|
||||
* return its parent.
|
||||
*/
|
||||
static nsIFrame* GetParentOrPlaceholderFor(nsFrameManager* aFrameManager,
|
||||
nsIFrame* aFrame);
|
||||
|
||||
/**
|
||||
* Find the closest common ancestor of aFrame1 and aFrame2, following
|
||||
* out of flow frames to their placeholders instead of their parents. Returns
|
||||
* nsnull if the frames are in different frame trees.
|
||||
*
|
||||
* @param aKnownCommonAncestorHint a frame that is believed to be on the
|
||||
* ancestor chain of both aFrame1 and aFrame2. If null, or a frame that is
|
||||
* not in fact on both ancestor chains, then this function will still return
|
||||
* the correct result, but it will be slower.
|
||||
*/
|
||||
static nsIFrame*
|
||||
GetClosestCommonAncestorViaPlaceholders(nsIFrame* aFrame1, nsIFrame* aFrame2,
|
||||
nsIFrame* aKnownCommonAncestorHint);
|
||||
};
|
||||
|
||||
#endif // nsLayoutUtils_h__
|
||||
|
|
|
@ -3811,6 +3811,8 @@ nsBlockFrame::ReflowInlineFrames(nsBlockReflowState& aState,
|
|||
PRBool movedPastFloat = PR_FALSE;
|
||||
do {
|
||||
PRBool allowPullUp = aTryPull;
|
||||
nsIContent* forceBreakInContent = nsnull;
|
||||
PRInt32 forceBreakOffset = -1;
|
||||
do {
|
||||
nsSpaceManager::SavedState spaceManagerState;
|
||||
aState.mReflowState.mSpaceManager->PushState(&spaceManagerState);
|
||||
|
@ -3827,17 +3829,30 @@ nsBlockFrame::ReflowInlineFrames(nsBlockReflowState& aState,
|
|||
&aState.mReflowState,
|
||||
aState.GetFlag(BRS_COMPUTEMAXELEMENTWIDTH));
|
||||
lineLayout.Init(&aState, aState.mMinLineHeight, aState.mLineNumber);
|
||||
if (forceBreakInContent) {
|
||||
lineLayout.ForceBreakAtPosition(forceBreakInContent, forceBreakOffset);
|
||||
}
|
||||
rv = DoReflowInlineFrames(aState, lineLayout, aLine,
|
||||
aKeepReflowGoing, &lineReflowStatus,
|
||||
aUpdateMaximumWidth, aDamageDirtyArea,
|
||||
allowPullUp);
|
||||
lineLayout.EndLineReflow();
|
||||
|
||||
|
||||
if (LINE_REFLOW_REDO_NO_PULL == lineReflowStatus ||
|
||||
LINE_REFLOW_REDO_NEXT_BAND == lineReflowStatus) {
|
||||
if (lineLayout.NeedsBackup()) {
|
||||
NS_ASSERTION(!forceBreakInContent, "Backuping up twice; this should never be necessary");
|
||||
// If there is no saved break position, then this will set
|
||||
// set forceBreakInContent to null and we won't back up, which is
|
||||
// correct.
|
||||
forceBreakInContent = lineLayout.GetLastOptionalBreakPosition(&forceBreakOffset);
|
||||
} else {
|
||||
forceBreakInContent = nsnull;
|
||||
}
|
||||
// restore the space manager state
|
||||
aState.mReflowState.mSpaceManager->PopState(&spaceManagerState);
|
||||
// Clear out below-current-line-floats
|
||||
// Clear out float lists
|
||||
aState.mCurrentLineFloats.DeleteAll();
|
||||
aState.mBelowCurrentLineFloats.DeleteAll();
|
||||
}
|
||||
|
||||
|
@ -3887,6 +3902,13 @@ nsBlockFrame::PushTruncatedPlaceholderLine(nsBlockReflowState& aState,
|
|||
aState.mReflowStatus = NS_FRAME_NOT_COMPLETE;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
static const char* LineReflowStatusNames[] = {
|
||||
"LINE_REFLOW_OK", "LINE_REFLOW_STOP", "LINE_REFLOW_REDO_NO_PULL",
|
||||
"LINE_REFLOW_REDO_NEXT_BAND", "LINE_REFLOW_TRUNCATED"
|
||||
};
|
||||
#endif
|
||||
|
||||
nsresult
|
||||
nsBlockFrame::DoReflowInlineFrames(nsBlockReflowState& aState,
|
||||
nsLineLayout& aLineLayout,
|
||||
|
@ -3953,9 +3975,18 @@ nsBlockFrame::DoReflowInlineFrames(nsBlockReflowState& aState,
|
|||
// continuations
|
||||
PRBool isContinuingPlaceholders = PR_FALSE;
|
||||
|
||||
if (impactedByFloats) {
|
||||
// There is a soft break opportunity at the start of the line, because
|
||||
// we can always move this line down below float(s).
|
||||
if (aLineLayout.NotifyOptionalBreakPosition(frame->GetContent(), 0)) {
|
||||
lineReflowStatus = LINE_REFLOW_REDO_NEXT_BAND;
|
||||
}
|
||||
}
|
||||
|
||||
// need to repeatedly call GetChildCount here, because the child
|
||||
// count can change during the loop!
|
||||
for (i = 0; i < aLine->GetChildCount(); i++) {
|
||||
for (i = 0; LINE_REFLOW_OK == lineReflowStatus && i < aLine->GetChildCount();
|
||||
i++, frame = frame->GetNextSibling()) {
|
||||
if (IsContinuationPlaceholder(frame)) {
|
||||
isContinuingPlaceholders = PR_TRUE;
|
||||
}
|
||||
|
@ -3986,9 +4017,7 @@ nsBlockFrame::DoReflowInlineFrames(nsBlockReflowState& aState,
|
|||
PushTruncatedPlaceholderLine(aState, aLine, lastPlaceholder, *aKeepReflowGoing);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
frame = frame->GetNextSibling();
|
||||
}
|
||||
|
||||
// Don't pull up new frames into lines with continuation placeholders
|
||||
|
@ -4024,6 +4053,20 @@ nsBlockFrame::DoReflowInlineFrames(nsBlockReflowState& aState,
|
|||
}
|
||||
}
|
||||
|
||||
if ((lineReflowStatus == LINE_REFLOW_STOP || lineReflowStatus == LINE_REFLOW_OK) &&
|
||||
!aLineLayout.HaveForcedBreakPosition() && aLineLayout.NeedsBackup()) {
|
||||
// We need to try backing up to before a text run
|
||||
PRInt32 offset;
|
||||
nsIContent* breakContent = aLineLayout.GetLastOptionalBreakPosition(&offset);
|
||||
if (breakContent) {
|
||||
// We can back up!
|
||||
lineReflowStatus = LINE_REFLOW_REDO_NO_PULL;
|
||||
}
|
||||
} else {
|
||||
// Don't try to force any breaking if we are going to retry
|
||||
aLineLayout.ClearOptionalBreakPosition();
|
||||
}
|
||||
|
||||
if (LINE_REFLOW_REDO_NEXT_BAND == lineReflowStatus) {
|
||||
// This happens only when we have a line that is impacted by
|
||||
// floats and the first element in the line doesn't fit with
|
||||
|
@ -4084,6 +4127,11 @@ nsBlockFrame::DoReflowInlineFrames(nsBlockReflowState& aState,
|
|||
}
|
||||
}
|
||||
}
|
||||
#ifdef DEBUG
|
||||
if (gNoisyReflow) {
|
||||
printf("Line reflow status = %s\n", LineReflowStatusNames[lineReflowStatus]);
|
||||
}
|
||||
#endif
|
||||
*aLineReflowStatus = lineReflowStatus;
|
||||
|
||||
return rv;
|
||||
|
|
|
@ -218,20 +218,6 @@ nsHTMLCanvasFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
|||
nsISelectionDisplay::DISPLAY_IMAGES);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHTMLCanvasFrame::CanContinueTextRun(PRBool& aContinueTextRun) const
|
||||
{
|
||||
// stolen from nsImageFrame.cpp
|
||||
// images really CAN continue text runs, but the textFrame needs to be
|
||||
// educated before we can indicate that it can. For now, we handle the fixing up
|
||||
// of max element widths in nsLineLayout::VerticalAlignFrames, but hopefully
|
||||
// this can be eliminated and the textFrame can be convinced to handle inlines
|
||||
// that take up space in text runs.
|
||||
|
||||
aContinueTextRun = PR_FALSE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHTMLCanvasFrame::GetContentForEvent(nsPresContext* aPresContext,
|
||||
nsEvent* aEvent,
|
||||
|
|
|
@ -65,9 +65,6 @@ public:
|
|||
const nsHTMLReflowState& aReflowState,
|
||||
nsReflowStatus& aStatus);
|
||||
|
||||
NS_IMETHOD CanContinueTextRun(PRBool& aContinueTextRun) const;
|
||||
|
||||
|
||||
NS_IMETHOD GetContentForEvent(nsPresContext* aPresContext,
|
||||
nsEvent* aEvent,
|
||||
nsIContent** aContent);
|
||||
|
|
|
@ -1628,20 +1628,6 @@ nsImageFrame::GetAnchorHREFTargetAndNode(nsIURI** aHref, nsString& aTarget,
|
|||
return status;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsImageFrame::CanContinueTextRun(PRBool& aContinueTextRun) const
|
||||
{
|
||||
// images really CAN continue text runs, but the textFrame needs to be
|
||||
// educated before we can indicate that it can. For now, we handle the fixing up
|
||||
// of max element widths in nsLineLayout::VerticalAlignFrames, but hopefully
|
||||
// this can be eliminated and the textFrame can be convinced to handle inlines
|
||||
// that take up space in text runs.
|
||||
|
||||
aContinueTextRun = PR_FALSE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsImageFrame::GetContentForEvent(nsPresContext* aPresContext,
|
||||
nsEvent* aEvent,
|
||||
|
|
|
@ -110,9 +110,6 @@ public:
|
|||
const nsHTMLReflowState& aReflowState,
|
||||
nsReflowStatus& aStatus);
|
||||
|
||||
NS_IMETHOD CanContinueTextRun(PRBool& aContinueTextRun) const;
|
||||
|
||||
|
||||
NS_IMETHOD GetContentForEvent(nsPresContext* aPresContext,
|
||||
nsEvent* aEvent,
|
||||
nsIContent** aContent);
|
||||
|
|
|
@ -680,7 +680,9 @@ nsInlineFrame::ReflowInlineFrame(nsPresContext* aPresContext,
|
|||
nsLineLayout* lineLayout = aReflowState.mLineLayout;
|
||||
PRBool reflowingFirstLetter = lineLayout->GetFirstLetterStyleOK();
|
||||
PRBool pushedFrame;
|
||||
nsresult rv = lineLayout->ReflowFrame(aFrame, aStatus, nsnull, pushedFrame);
|
||||
nsresult rv =
|
||||
lineLayout->ReflowFrame(aFrame, aStatus, nsnull, pushedFrame);
|
||||
|
||||
/* This next block is for bug 28811
|
||||
Test the child frame for %-awareness,
|
||||
and mark this frame with a bit if it is %-aware.
|
||||
|
|
|
@ -156,11 +156,15 @@ nsLineLayout::nsLineLayout(nsPresContext* aPresContext,
|
|||
: mPresContext(aPresContext),
|
||||
mSpaceManager(aSpaceManager),
|
||||
mBlockReflowState(aOuterReflowState),
|
||||
mLastOptionalBreakContent(nsnull),
|
||||
mForceBreakContent(nsnull),
|
||||
mLastOptionalBreakContentOffset(-1),
|
||||
mForceBreakContentOffset(-1),
|
||||
mTrailingTextFrame(nsnull),
|
||||
mBlockRS(nsnull),/* XXX temporary */
|
||||
mMinLineHeight(0),
|
||||
mComputeMaxElementWidth(aComputeMaxElementWidth),
|
||||
mTextIndent(0),
|
||||
mWordFrames(0)
|
||||
mTextIndent(0)
|
||||
{
|
||||
MOZ_COUNT_CTOR(nsLineLayout);
|
||||
|
||||
|
@ -195,8 +199,6 @@ nsLineLayout::~nsLineLayout()
|
|||
|
||||
NS_ASSERTION(nsnull == mRootSpan, "bad line-layout user");
|
||||
|
||||
delete mWordFrames; // operator delete for this class just returns
|
||||
|
||||
// PL_FreeArenaPool takes our memory and puts in on a global free list so
|
||||
// that the next time an arena makes an allocation it will not have to go
|
||||
// all the way down to malloc. This is desirable as this class is created
|
||||
|
@ -210,22 +212,6 @@ nsLineLayout::~nsLineLayout()
|
|||
PL_FinishArenaPool(&mArena);
|
||||
}
|
||||
|
||||
void*
|
||||
nsLineLayout::ArenaDeque::operator new(size_t aSize, PLArenaPool &aPool)
|
||||
{
|
||||
void *mem;
|
||||
|
||||
PL_ARENA_ALLOCATE(mem, &aPool, aSize);
|
||||
return mem;
|
||||
}
|
||||
|
||||
PRBool nsLineLayout::AllocateDeque()
|
||||
{
|
||||
mWordFrames = new(mArena) ArenaDeque;
|
||||
|
||||
return mWordFrames != nsnull;
|
||||
}
|
||||
|
||||
// Find out if the frame has a non-null prev-in-flow, i.e., whether it
|
||||
// is a continuation.
|
||||
inline PRBool
|
||||
|
@ -282,8 +268,6 @@ nsLineLayout::BeginLineReflow(nscoord aX, nscoord aY,
|
|||
mSpanDepth = 0;
|
||||
mMaxTopBoxHeight = mMaxBottomBoxHeight = 0;
|
||||
|
||||
ForgetWordFrames();
|
||||
|
||||
PerSpanData* psd;
|
||||
NewPerSpanData(&psd);
|
||||
mCurrentSpan = mRootSpan = psd;
|
||||
|
@ -313,7 +297,7 @@ nsLineLayout::BeginLineReflow(nscoord aX, nscoord aY,
|
|||
|
||||
// If this is the first line of a block then see if the text-indent
|
||||
// property amounts to anything.
|
||||
|
||||
|
||||
if (0 == mLineNumber && !HasPrevInFlow(mBlockReflowState->frame)) {
|
||||
nscoord indent = 0;
|
||||
nsStyleUnit unit = mStyleText->mTextIndent.GetUnit();
|
||||
|
@ -936,17 +920,16 @@ nsLineLayout::ReflowFrame(nsIFrame* aFrame,
|
|||
|
||||
// We want to guarantee that we always make progress when
|
||||
// formatting. Therefore, if the object being placed on the line is
|
||||
// too big for the line, but it is the only thing on the line
|
||||
// (including counting floats) then we go ahead and place it
|
||||
// anyway. Its also true that if the object is a part of a larger
|
||||
// object (a multiple frame word) then we will place it on the line
|
||||
// too.
|
||||
// too big for the line, but it is the only thing on the line and is not
|
||||
// impacted by a float, then we go ahead and place it anyway. (If the line
|
||||
// is impacted by one or more floats, then it is safe to break because
|
||||
// we can move the line down below float(s).)
|
||||
//
|
||||
// Capture this state *before* we reflow the frame in case it clears
|
||||
// the state out. We need to know how to treat the current frame
|
||||
// when breaking.
|
||||
PRBool notSafeToBreak = CanPlaceFloatNow() || InWord();
|
||||
|
||||
PRBool notSafeToBreak = CanPlaceFloatNow() && !GetFlag(LL_IMPACTEDBYFLOATS);
|
||||
|
||||
// Apply start margins (as appropriate) to the frame computing the
|
||||
// new starting x,y coordinates for the frame.
|
||||
ApplyStartMargin(pfd, reflowState);
|
||||
|
@ -991,32 +974,36 @@ nsLineLayout::ReflowFrame(nsIFrame* aFrame,
|
|||
#endif // IBMBIDI
|
||||
|
||||
nsIAtom* frameType = aFrame->GetType();
|
||||
|
||||
PRInt32 savedOptionalBreakOffset;
|
||||
nsIContent* savedOptionalBreakContent =
|
||||
GetLastOptionalBreakPosition(&savedOptionalBreakOffset);
|
||||
|
||||
rv = aFrame->Reflow(mPresContext, metrics, reflowState, aReflowStatus);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING( "Reflow of frame failed in nsLineLayout" );
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
pfd->mJustificationNumSpaces = mTextJustificationNumSpaces;
|
||||
pfd->mJustificationNumLetters = mTextJustificationNumLetters;
|
||||
|
||||
// XXX See if the frame is a placeholderFrame and if it is process
|
||||
// the float.
|
||||
PRBool placedFloat = PR_FALSE;
|
||||
if (frameType) {
|
||||
if (nsLayoutAtoms::placeholderFrame == frameType) {
|
||||
pfd->SetFlag(PFD_SKIPWHENTRIMMINGWHITESPACE, PR_TRUE);
|
||||
nsIFrame* outOfFlowFrame = nsLayoutUtils::GetFloatFromPlaceholder(aFrame);
|
||||
if (outOfFlowFrame) {
|
||||
nsPlaceholderFrame* placeholder = NS_STATIC_CAST(nsPlaceholderFrame*, aFrame);
|
||||
PRBool didPlace;
|
||||
if (eReflowReason_Incremental == reason) {
|
||||
didPlace = InitFloat(placeholder, aReflowStatus);
|
||||
placedFloat = InitFloat(placeholder, aReflowStatus);
|
||||
}
|
||||
else {
|
||||
didPlace = AddFloat(placeholder, aReflowStatus);
|
||||
placedFloat = AddFloat(placeholder, aReflowStatus);
|
||||
}
|
||||
if (!didPlace) {
|
||||
if (!placedFloat) {
|
||||
aReflowStatus = NS_INLINE_LINE_BREAK_BEFORE();
|
||||
}
|
||||
if (outOfFlowFrame->GetType() == nsLayoutAtoms::letterFrame) {
|
||||
|
@ -1164,9 +1151,15 @@ nsLineLayout::ReflowFrame(nsIFrame* aFrame,
|
|||
}
|
||||
}
|
||||
|
||||
// Check whether this frame breaks up text runs. All frames break up text
|
||||
// runs (hence return false here) except for text frames and inline containers.
|
||||
PRBool continuingTextRun;
|
||||
aFrame->CanContinueTextRun(continuingTextRun);
|
||||
|
||||
// See if we can place the frame. If we can't fit it, then we
|
||||
// return now.
|
||||
if (CanPlaceFrame(pfd, reflowState, notSafeToBreak, metrics, aReflowStatus)) {
|
||||
if (CanPlaceFrame(pfd, reflowState, notSafeToBreak, continuingTextRun,
|
||||
metrics, aReflowStatus)) {
|
||||
// Place the frame, updating aBounds with the final size and
|
||||
// location. Then apply the bottom+right margins (as
|
||||
// appropriate) to the frame.
|
||||
|
@ -1178,16 +1171,34 @@ nsLineLayout::ReflowFrame(nsIFrame* aFrame,
|
|||
// so do most of it now.
|
||||
VerticalAlignFrames(span);
|
||||
}
|
||||
|
||||
if (!continuingTextRun) {
|
||||
SetFlag(LL_INWORD, PR_FALSE);
|
||||
mTrailingTextFrame = nsnull;
|
||||
if (!psd->mNoWrap && (!CanPlaceFloatNow() || placedFloat)) {
|
||||
// record soft break opportunity after this content that can't be
|
||||
// part of a text run. This is not a text frame so we know
|
||||
// that offset PR_INT32_MAX means "after the content".
|
||||
if (NotifyOptionalBreakPosition(aFrame->GetContent(), PR_INT32_MAX)) {
|
||||
// If this returns true then we are being told to actually break here.
|
||||
aReflowStatus = NS_INLINE_LINE_BREAK_AFTER(aReflowStatus);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
PushFrame(aFrame);
|
||||
aPushedFrame = PR_TRUE;
|
||||
// Undo any saved break positions that the frame might have told us about,
|
||||
// since we didn't end up placing it
|
||||
RestoreSavedBreakPosition(savedOptionalBreakContent,
|
||||
savedOptionalBreakOffset);
|
||||
}
|
||||
}
|
||||
else {
|
||||
PushFrame(aFrame);
|
||||
}
|
||||
|
||||
|
||||
#ifdef REALLY_NOISY_REFLOW
|
||||
nsFrame::IndentBy(stdout, mSpanDepth);
|
||||
printf("End ReflowFrame ");
|
||||
|
@ -1262,6 +1273,7 @@ PRBool
|
|||
nsLineLayout::CanPlaceFrame(PerFrameData* pfd,
|
||||
const nsHTMLReflowState& aReflowState,
|
||||
PRBool aNotSafeToBreak,
|
||||
PRBool aFrameCanContinueTextRun,
|
||||
nsHTMLReflowMetrics& aMetrics,
|
||||
nsReflowStatus& aStatus)
|
||||
{
|
||||
|
@ -1297,6 +1309,9 @@ nsLineLayout::CanPlaceFrame(PerFrameData* pfd,
|
|||
return PR_TRUE;
|
||||
}
|
||||
|
||||
PRBool ltr = NS_STYLE_DIRECTION_LTR == aReflowState.mStyleVisibility->mDirection;
|
||||
nscoord endMargin = ltr ? pfd->mMargin.right : pfd->mMargin.left;
|
||||
|
||||
#ifdef NOISY_CAN_PLACE_FRAME
|
||||
if (nsnull != psd->mFrame) {
|
||||
nsFrame::ListTag(stdout, psd->mFrame->mFrame);
|
||||
|
@ -1306,13 +1321,12 @@ nsLineLayout::CanPlaceFrame(PerFrameData* pfd,
|
|||
}
|
||||
printf(": aNotSafeToBreak=%s frame=", aNotSafeToBreak ? "true" : "false");
|
||||
nsFrame::ListTag(stdout, pfd->mFrame);
|
||||
printf(" frameWidth=%d\n", pfd->mBounds.XMost() + rightMargin - psd->mX);
|
||||
printf(" frameWidth=%d\n", pfd->mBounds.XMost() + endMargin - psd->mX);
|
||||
#endif
|
||||
|
||||
// Set outside to PR_TRUE if the result of the reflow leads to the
|
||||
// frame sticking outside of our available area.
|
||||
PRBool ltr = (NS_STYLE_DIRECTION_LTR == aReflowState.mStyleVisibility->mDirection);
|
||||
PRBool outside = pfd->mBounds.XMost() + (ltr ? pfd->mMargin.right : pfd->mMargin.left) > psd->mRightEdge;
|
||||
PRBool outside = pfd->mBounds.XMost() + endMargin > psd->mRightEdge;
|
||||
if (!outside) {
|
||||
// If it fits, it fits
|
||||
#ifdef NOISY_CAN_PLACE_FRAME
|
||||
|
@ -1342,75 +1356,20 @@ nsLineLayout::CanPlaceFrame(PerFrameData* pfd,
|
|||
#endif
|
||||
|
||||
if (aNotSafeToBreak) {
|
||||
// There are no frames on the line or we are in the first word on
|
||||
// the line. If the line isn't impacted by a float then the
|
||||
// current frame fits.
|
||||
if (!GetFlag(LL_IMPACTEDBYFLOATS)) {
|
||||
// There are no frames on the line that take up width and the line is
|
||||
// not impacted by floats, so we must allow the current frame to be
|
||||
// placed on the line
|
||||
#ifdef NOISY_CAN_PLACE_FRAME
|
||||
printf(" ==> not-safe and not-impacted fits: ");
|
||||
while (nsnull != psd) {
|
||||
printf("<psd=%p x=%d left=%d> ", psd, psd->mX, psd->mLeftEdge);
|
||||
psd = psd->mParent;
|
||||
}
|
||||
printf("\n");
|
||||
printf(" ==> not-safe and not-impacted fits: ");
|
||||
while (nsnull != psd) {
|
||||
printf("<psd=%p x=%d left=%d> ", psd, psd->mX, psd->mLeftEdge);
|
||||
psd = psd->mParent;
|
||||
}
|
||||
printf("\n");
|
||||
#endif
|
||||
return PR_TRUE;
|
||||
}
|
||||
else if (GetFlag(LL_LASTFLOATWASLETTERFRAME)) {
|
||||
// Another special case: see if the float is a letter
|
||||
// frame. If it is, then allow the frame next to it to fit.
|
||||
if (pfd->GetFlag(PFD_ISNONEMPTYTEXTFRAME)) {
|
||||
// This must be the first piece of non-empty text (because
|
||||
// aNotSafeToBreak is true) or it's a piece of text that is
|
||||
// part of a larger word.
|
||||
pfd->SetFlag(PFD_ISSTICKY, PR_TRUE);
|
||||
}
|
||||
else if (pfd->mSpan) {
|
||||
PerFrameData* pf = pfd->mSpan->mFirstFrame;
|
||||
while (pf) {
|
||||
if (pf->GetFlag(PFD_ISSTICKY)) {
|
||||
// If one of the spans children was sticky then the span
|
||||
// itself is sticky.
|
||||
pfd->SetFlag(PFD_ISSTICKY, PR_TRUE);
|
||||
}
|
||||
pf = pf->mNext;
|
||||
}
|
||||
}
|
||||
|
||||
if (pfd->GetFlag(PFD_ISSTICKY)) {
|
||||
#ifdef NOISY_CAN_PLACE_FRAME
|
||||
printf(" ==> last float was letter frame && frame is sticky\n");
|
||||
#endif
|
||||
return PR_TRUE;
|
||||
}
|
||||
}
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
// If this is a piece of text inside a letter frame...
|
||||
if (pfd->GetFlag(PFD_ISNONEMPTYTEXTFRAME)) {
|
||||
if (psd->mFrame && psd->mFrame->GetFlag(PFD_ISLETTERFRAME)) {
|
||||
nsIFrame* prevInFlow = psd->mFrame->mFrame->GetPrevInFlow();
|
||||
if (prevInFlow) {
|
||||
nsIFrame* prevPrevInFlow = prevInFlow->GetPrevInFlow();
|
||||
if (!prevPrevInFlow) {
|
||||
// And it's the first continuation of the letter frame...
|
||||
// Then make sure that the text fits
|
||||
return PR_TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (pfd->GetFlag(PFD_ISLETTERFRAME)) {
|
||||
// If this is the first continuation of the letter frame...
|
||||
nsIFrame* prevInFlow = pfd->mFrame->GetPrevInFlow();
|
||||
if (prevInFlow) {
|
||||
nsIFrame* prevPrevInFlow = prevInFlow->GetPrevInFlow();
|
||||
if (!prevPrevInFlow) {
|
||||
return PR_TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Special check for span frames
|
||||
if (pfd->mSpan && pfd->mSpan->mContainsFloat) {
|
||||
// If the span either directly or indirectly contains a float then
|
||||
|
@ -1439,6 +1398,24 @@ nsLineLayout::CanPlaceFrame(PerFrameData* pfd,
|
|||
return PR_TRUE;
|
||||
}
|
||||
|
||||
if (aFrameCanContinueTextRun) {
|
||||
// Let it fit, but we reserve the right to roll back
|
||||
// to before the text run! Note that we usually won't get here because
|
||||
// a text frame will break itself to avoid exceeding the available width.
|
||||
// We'll only get here for text frames that couldn't break early enough.
|
||||
#ifdef NOISY_CAN_PLACE_FRAME
|
||||
printf(" ==> placing overflowing textrun, requesting backup\n");
|
||||
#endif
|
||||
if (!mLastOptionalBreakContent) {
|
||||
// Nowhere to roll back to, so make this fit
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
// We have something to roll back to. So, signal that we will to roll back,
|
||||
// and fall through to not place this frame.
|
||||
SetFlag(LL_NEEDBACKUP, PR_TRUE);
|
||||
}
|
||||
|
||||
#ifdef NOISY_CAN_PLACE_FRAME
|
||||
printf(" ==> didn't fit\n");
|
||||
#endif
|
||||
|
@ -3062,107 +3039,6 @@ nsLineLayout::RelativePositionFrames(PerSpanData* psd, nsRect& aCombinedArea)
|
|||
aCombinedArea = combinedAreaResult;
|
||||
}
|
||||
|
||||
void
|
||||
nsLineLayout::ForgetWordFrame(nsIFrame* aFrame)
|
||||
{
|
||||
if (mWordFrames && 0 != mWordFrames->GetSize()) {
|
||||
NS_ASSERTION((void*)aFrame == mWordFrames->PeekFront(), "forget-word-frame");
|
||||
mWordFrames->PopFront();
|
||||
}
|
||||
}
|
||||
|
||||
nsIFrame*
|
||||
nsLineLayout::FindNextText(nsPresContext* aPresContext, nsIFrame* aFrame)
|
||||
{
|
||||
// Grovel through the frame hierarchy to find a text frame that is
|
||||
// "adjacent" to aFrame.
|
||||
|
||||
// So this is kind of funky. During reflow, overflow frames will
|
||||
// have their parent pointers set up lazily. We assume that, on
|
||||
// entry, aFrame has its parent pointer set correctly (as do all of
|
||||
// its ancestors). Starting from that, we need to make sure that as
|
||||
// we traverse through frames trying to find the next text frame, we
|
||||
// leave the frames with their parent pointers set correctly, so the
|
||||
// *next* time we come through here, we're good to go.
|
||||
|
||||
// Build a path from the enclosing block frame down to aFrame. We'll
|
||||
// use this to walk the frame tree. (XXXwaterson if I was clever, I
|
||||
// wouldn't need to build this up before hand, and could incorporate
|
||||
// this logic into the walking code directly.)
|
||||
nsAutoVoidArray stack;
|
||||
for (;;) {
|
||||
stack.InsertElementAt(aFrame, 0);
|
||||
|
||||
aFrame = aFrame->GetParent();
|
||||
|
||||
NS_ASSERTION(aFrame, "wow, no block frame found");
|
||||
if (! aFrame)
|
||||
break;
|
||||
|
||||
if (NS_STYLE_DISPLAY_INLINE != aFrame->GetStyleDisplay()->mDisplay)
|
||||
break;
|
||||
}
|
||||
|
||||
// Using the path we've built up, walk the frame tree looking for
|
||||
// the text frame that follows aFrame.
|
||||
PRInt32 count;
|
||||
while ((count = stack.Count()) != 0) {
|
||||
PRInt32 lastIndex = count - 1;
|
||||
nsIFrame* top = NS_STATIC_CAST(nsIFrame*, stack.ElementAt(lastIndex));
|
||||
|
||||
// If this is a frame that'll break a word, then bail.
|
||||
PRBool canContinue;
|
||||
top->CanContinueTextRun(canContinue);
|
||||
if (! canContinue)
|
||||
return nsnull;
|
||||
|
||||
// Advance to top's next sibling
|
||||
nsIFrame* next = top->GetNextSibling();
|
||||
|
||||
if (! next) {
|
||||
// No more siblings. Pop the top element to walk back up the
|
||||
// frame tree.
|
||||
stack.RemoveElementAt(lastIndex);
|
||||
continue;
|
||||
}
|
||||
|
||||
// We know top's parent is good, but next's might not be. So let's
|
||||
// set it to be sure.
|
||||
next->SetParent(top->GetParent());
|
||||
|
||||
// Save next at the top of the stack...
|
||||
stack.ReplaceElementAt(next, lastIndex);
|
||||
|
||||
// ...and prowl down to next's deepest child. We'll need to check
|
||||
// for potential run-busters "on the way down", too.
|
||||
for (;;) {
|
||||
next->CanContinueTextRun(canContinue);
|
||||
if (! canContinue)
|
||||
return nsnull;
|
||||
|
||||
nsIFrame* child = next->GetFirstChild(nsnull);
|
||||
|
||||
if (! child)
|
||||
break;
|
||||
|
||||
stack.AppendElement(child);
|
||||
next = child;
|
||||
}
|
||||
|
||||
// Ignore continuing frames
|
||||
if (HasPrevInFlow(next))
|
||||
continue;
|
||||
|
||||
// If this is a text frame, return it.
|
||||
if (nsLayoutAtoms::textFrame == next->GetType())
|
||||
return next;
|
||||
}
|
||||
|
||||
// If we get here, then there are no more text frames in this block.
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
|
||||
PRBool
|
||||
nsLineLayout::TreatFrameAsBlock(nsIFrame* aFrame)
|
||||
{
|
||||
|
|
|
@ -56,6 +56,8 @@
|
|||
#include "nsBlockReflowState.h"
|
||||
#include "plarena.h"
|
||||
|
||||
class nsBlockFrame;
|
||||
|
||||
class nsSpaceManager;
|
||||
class nsPlaceholderFrame;
|
||||
struct nsStyleText;
|
||||
|
@ -68,14 +70,6 @@ public:
|
|||
PRBool aComputeMaxElementWidth);
|
||||
~nsLineLayout();
|
||||
|
||||
class ArenaDeque : public nsDeque
|
||||
{
|
||||
public:
|
||||
ArenaDeque() : nsDeque(nsnull) {}
|
||||
void *operator new(size_t, PLArenaPool &pool);
|
||||
void operator delete(void *) {} // Dont do anything. Its Arena memory
|
||||
};
|
||||
|
||||
void Init(nsBlockReflowState* aState, nscoord aMinLineHeight,
|
||||
PRInt32 aLineNumber) {
|
||||
mBlockRS = aState;
|
||||
|
@ -156,6 +150,7 @@ public:
|
|||
protected:
|
||||
#define LL_ENDSINWHITESPACE 0x00000001
|
||||
#define LL_UNDERSTANDSNWHITESPACE 0x00000002
|
||||
#define LL_INWORD 0x00000004
|
||||
#define LL_FIRSTLETTERSTYLEOK 0x00000008
|
||||
#define LL_ISTOPOFPAGE 0x00000010
|
||||
#define LL_UPDATEDBAND 0x00000020
|
||||
|
@ -169,7 +164,9 @@ protected:
|
|||
// large, e.g., if a large word-spacing is set). LL should not be misled into
|
||||
// placing something where the whitespace was trimmed. See bug 329987.
|
||||
#define LL_LINEENDSINSOFTBR 0x00000400
|
||||
#define LL_LASTFLAG LL_LINEENDSINSOFTBR
|
||||
#define LL_NEEDBACKUP 0x00000800
|
||||
#define LL_LASTTEXTFRAME_WRAPPINGENABLED 0x00001000
|
||||
#define LL_LASTFLAG LL_LASTTEXTFRAME_WRAPPINGENABLED
|
||||
|
||||
PRUint16 mFlags;
|
||||
|
||||
|
@ -215,25 +212,6 @@ public:
|
|||
mTextJustificationNumLetters = aNumLetters;
|
||||
}
|
||||
|
||||
void RecordWordFrame(nsIFrame* aWordFrame) {
|
||||
if(mWordFrames || AllocateDeque())
|
||||
mWordFrames->Push(aWordFrame);
|
||||
}
|
||||
|
||||
PRBool InWord() const {
|
||||
return mWordFrames && 0 != mWordFrames->GetSize();
|
||||
}
|
||||
|
||||
void ForgetWordFrame(nsIFrame* aFrame);
|
||||
|
||||
void ForgetWordFrames() {
|
||||
if(mWordFrames) {
|
||||
mWordFrames->Empty();
|
||||
}
|
||||
}
|
||||
|
||||
nsIFrame* FindNextText(nsPresContext* aPresContext, nsIFrame* aFrame);
|
||||
|
||||
PRBool CanPlaceFloatNow() const;
|
||||
|
||||
PRBool LineIsBreakable() const;
|
||||
|
@ -279,6 +257,44 @@ public:
|
|||
return mBlockRS->AddFloat(*this, aFrame, PR_FALSE, aReflowStatus);
|
||||
}
|
||||
|
||||
/**
|
||||
* InWord is true when the last text frame reflowed ended in non-whitespace
|
||||
* (so it has content that might form a word with subsequent text). The word width
|
||||
* is the width of contiguous text up to the end of that last word, possibly
|
||||
* including words from previous frames.
|
||||
*
|
||||
* If GetTrailingTextFrame is null then InWord will be false.
|
||||
*/
|
||||
PRBool InWord(nscoord* aWordWidth) {
|
||||
if (!GetFlag(LL_INWORD))
|
||||
return PR_FALSE;
|
||||
*aWordWidth = mWordWidth;
|
||||
return PR_TRUE;
|
||||
}
|
||||
void SetInWord(PRBool aInWord, nscoord aWordWidth) {
|
||||
SetFlag(LL_INWORD, aInWord);
|
||||
mWordWidth = aWordWidth;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the last content placed on the line (not counting inline containers)
|
||||
* was text, and can form a contiguous text flow with the next content to be
|
||||
* placed, and is not just a frame of all-skipped whitespace, this is the
|
||||
* frame for that last content ... otherwise it's null.
|
||||
*
|
||||
* @param aWrappingEnabled whether that text had word-wrapping enabled
|
||||
* (white-space:normal or -moz-pre-wrap)
|
||||
*/
|
||||
nsIFrame* GetTrailingTextFrame(PRBool* aWrappingEnabled) {
|
||||
*aWrappingEnabled = GetFlag(LL_LASTTEXTFRAME_WRAPPINGENABLED);
|
||||
return mTrailingTextFrame;
|
||||
}
|
||||
void SetTrailingTextFrame(nsIFrame* aFrame, PRBool aWrappingEnabled)
|
||||
{
|
||||
mTrailingTextFrame = aFrame;
|
||||
SetFlag(LL_LASTTEXTFRAME_WRAPPINGENABLED, aWrappingEnabled);
|
||||
}
|
||||
|
||||
//----------------------------------------
|
||||
|
||||
PRBool GetFirstLetterStyleOK() const {
|
||||
|
@ -307,12 +323,99 @@ public:
|
|||
|
||||
nsPresContext* mPresContext;
|
||||
|
||||
/**
|
||||
* Record where an optional break could have been placed. During line reflow,
|
||||
* frames containing optional break points (e.g., whitespace in text frames)
|
||||
* can call SetLastOptionalBreakPosition to record where a break could
|
||||
* have been made, but wasn't because there appeared to be enough room
|
||||
* to place more content on the line. For non-text frames, offset 0 means
|
||||
* before the content, offset PR_INT32_MAX means after the content.
|
||||
*
|
||||
* Currently this is used to handle cases where a single word comprises
|
||||
* multiple frames, and the first frame fits on the line but the whole word
|
||||
* doesn't. We look back to the last optional break position and
|
||||
* reflow the whole line again, forcing a break at that position. The last
|
||||
* optional break position could be in a text frame or else after a frame
|
||||
* that cannot be part of a text run, so those are the positions we record.
|
||||
*
|
||||
* It is imperative that this only gets called for break points that
|
||||
* are within the available width.
|
||||
*
|
||||
* @return PR_TRUE if we are actually reflowing with forced break position and we
|
||||
* should break here
|
||||
*/
|
||||
PRBool NotifyOptionalBreakPosition(nsIContent* aContent, PRInt32 aOffset) {
|
||||
NS_ASSERTION(!GetFlag(LL_NEEDBACKUP),
|
||||
"Shouldn't be updating the break position after we've already flagged an overrun");
|
||||
mLastOptionalBreakContent = aContent;
|
||||
mLastOptionalBreakContentOffset = aOffset;
|
||||
return aContent && mForceBreakContent == aContent &&
|
||||
mForceBreakContentOffset == aOffset;
|
||||
}
|
||||
/**
|
||||
* Like NotifyOptionalBreakPosition, but here it's OK for LL_NEEDBACKUP
|
||||
* to be set, because the caller is merely pruning some saved break position(s)
|
||||
* that are actually not feasible.
|
||||
*/
|
||||
void RestoreSavedBreakPosition(nsIContent* aContent, PRInt32 aOffset) {
|
||||
mLastOptionalBreakContent = aContent;
|
||||
mLastOptionalBreakContentOffset = aOffset;
|
||||
}
|
||||
void ClearOptionalBreakPosition() {
|
||||
mLastOptionalBreakContent = nsnull;
|
||||
mLastOptionalBreakContentOffset = -1;
|
||||
}
|
||||
// Retrieve last set optional break position. When this returns null, no
|
||||
// optional break has been recorded (which means that the line can't break yet).
|
||||
nsIContent* GetLastOptionalBreakPosition(PRInt32* aOffset) {
|
||||
*aOffset = mLastOptionalBreakContentOffset;
|
||||
return mLastOptionalBreakContent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether frames overflowed the available width and CanPlaceFrame
|
||||
* requested backing up to a saved break position.
|
||||
*/
|
||||
PRBool NeedsBackup() { return GetFlag(LL_NEEDBACKUP); }
|
||||
|
||||
// Line layout may place too much content on a line, overflowing its available
|
||||
// width. When that happens, if SetLastOptionalBreakPosition has been
|
||||
// used to record an optional break that wasn't taken, we can reflow the line
|
||||
// again and force the break to happen at that point (i.e., backtracking
|
||||
// to the last choice point).
|
||||
|
||||
// Record that we want to break at the given content+offset (which
|
||||
// should have been previously returned by GetLastOptionalBreakPosition
|
||||
// from another nsLineLayout).
|
||||
void ForceBreakAtPosition(nsIContent* aContent, PRInt32 aOffset) {
|
||||
mForceBreakContent = aContent;
|
||||
mForceBreakContentOffset = aOffset;
|
||||
}
|
||||
PRBool HaveForcedBreakPosition() { return mForceBreakContent != nsnull; }
|
||||
PRInt32 GetForcedBreakPosition(nsIContent* aContent) {
|
||||
return mForceBreakContent == aContent ? mForceBreakContentOffset : -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* This can't be null. It usually returns a block frame but may return
|
||||
* some other kind of frame when inline frames are reflowed in a non-block
|
||||
* context (e.g. MathML).
|
||||
*/
|
||||
nsIFrame* GetLineContainerFrame() { return mBlockReflowState->frame; }
|
||||
|
||||
protected:
|
||||
// This state is constant for a given block frame doing line layout
|
||||
nsSpaceManager* mSpaceManager;
|
||||
const nsStyleText* mStyleText; // for the block
|
||||
const nsHTMLReflowState* mBlockReflowState;
|
||||
|
||||
nsIContent* mLastOptionalBreakContent;
|
||||
nsIContent* mForceBreakContent;
|
||||
PRInt32 mLastOptionalBreakContentOffset;
|
||||
PRInt32 mForceBreakContentOffset;
|
||||
|
||||
nsIFrame* mTrailingTextFrame;
|
||||
|
||||
// XXX remove this when landing bug 154892 (splitting absolute positioned frames)
|
||||
friend class nsInlineFrame;
|
||||
|
||||
|
@ -333,14 +436,13 @@ protected:
|
|||
nsIFrame* mFirstLetterFrame;
|
||||
PRInt32 mLineNumber;
|
||||
PRInt32 mColumn;
|
||||
nscoord mWordWidth;
|
||||
PRInt32 mTextJustificationNumSpaces;
|
||||
PRInt32 mTextJustificationNumLetters;
|
||||
|
||||
nsLineBox* mLineBox;
|
||||
|
||||
PRInt32 mTotalPlacedFrames;
|
||||
ArenaDeque *mWordFrames;
|
||||
PRBool AllocateDeque();
|
||||
|
||||
nscoord mTopEdge;
|
||||
nscoord mMaxTopBoxHeight;
|
||||
|
@ -395,7 +497,6 @@ protected:
|
|||
#define PFD_ISNONEMPTYTEXTFRAME 0x00000004
|
||||
#define PFD_ISNONWHITESPACETEXTFRAME 0x00000008
|
||||
#define PFD_ISLETTERFRAME 0x00000010
|
||||
#define PFD_ISSTICKY 0x00000020
|
||||
#define PFD_ISBULLET 0x00000040
|
||||
#define PFD_SKIPWHENTRIMMINGWHITESPACE 0x00000080
|
||||
#define PFD_LASTFLAG PFD_SKIPWHENTRIMMINGWHITESPACE
|
||||
|
@ -497,6 +598,7 @@ protected:
|
|||
PRBool CanPlaceFrame(PerFrameData* pfd,
|
||||
const nsHTMLReflowState& aReflowState,
|
||||
PRBool aNotSafeToBreak,
|
||||
PRBool aFrameCanContinueTextRun,
|
||||
nsHTMLReflowMetrics& aMetrics,
|
||||
nsReflowStatus& aStatus);
|
||||
|
||||
|
|
|
@ -105,6 +105,18 @@ nsPlaceholderFrame::GetType() const
|
|||
return nsLayoutAtoms::placeholderFrame;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsPlaceholderFrame::CanContinueTextRun(PRBool& aContinueTextRun) const
|
||||
{
|
||||
if (!mOutOfFlowFrame) {
|
||||
aContinueTextRun = PR_FALSE;
|
||||
return NS_OK;
|
||||
}
|
||||
// first-letter frames can continue text runs, and placeholders for floated
|
||||
// first-letter frames can too
|
||||
return mOutOfFlowFrame->CanContinueTextRun(aContinueTextRun);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
static void
|
||||
PaintDebugPlaceholder(nsIFrame* aFrame, nsIRenderingContext* aCtx,
|
||||
|
|
|
@ -99,6 +99,8 @@ public:
|
|||
virtual PRBool IsEmpty() { return PR_TRUE; }
|
||||
virtual PRBool IsSelfEmpty() { return PR_TRUE; }
|
||||
|
||||
NS_IMETHOD CanContinueTextRun(PRBool& aContinueTextRun) const;
|
||||
|
||||
#ifdef ACCESSIBILITY
|
||||
NS_IMETHOD GetAccessible(nsIAccessible** aAccessible)
|
||||
{
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1005,10 +1005,6 @@ nsMathMLContainerFrame::ReflowForeignChild(nsIFrame* aChildFrame,
|
|||
const nsHTMLReflowState& aReflowState,
|
||||
nsReflowStatus& aStatus)
|
||||
{
|
||||
// don't bother trying to span words as if they were non-breaking beyond this point
|
||||
if (aReflowState.mLineLayout)
|
||||
aReflowState.mLineLayout->ForgetWordFrames();
|
||||
|
||||
nsAutoSpaceManager autoSpaceManager(NS_CONST_CAST(nsHTMLReflowState &, aReflowState));
|
||||
nsresult rv = autoSpaceManager.CreateSpaceManagerFor(aPresContext, this);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
|
|
@ -748,6 +748,11 @@ struct nsStyleText : public nsStyleStruct {
|
|||
return mWhiteSpace == NS_STYLE_WHITESPACE_PRE ||
|
||||
mWhiteSpace == NS_STYLE_WHITESPACE_MOZ_PRE_WRAP;
|
||||
}
|
||||
|
||||
PRBool WhiteSpaceCanWrap() const {
|
||||
return mWhiteSpace == NS_STYLE_WHITESPACE_NORMAL ||
|
||||
mWhiteSpace == NS_STYLE_WHITESPACE_MOZ_PRE_WRAP;
|
||||
}
|
||||
};
|
||||
|
||||
struct nsStyleVisibility : public nsStyleStruct {
|
||||
|
|
Загрузка…
Ссылка в новой задаче