зеркало из https://github.com/mozilla/pjs.git
Add a mParagraphDepth member to BidiParagraphData and cache it on frames to track nested bidi-isolated paragraphs. Use mParagraphDepth (* 2 + isRTL in order to keep LTR even and RTL odd) as the initial paragraph embedding level instead of pushing a stack of embedding codes. Pass the <bdi> frame instead of its first-child to BidiParagraphData::Reset and save a call to GetParent(). Split inline ancestors before and after bidi-isolated paragraphs, in the same way that we currently do between runs in different directions. This required also adding code to SplitInlineAncestors to handle situations where the parent frame is being split before its first child or after its last child. In JoinInlineAncestors, prevent frames that belong to paragraphs isolated from one another from being rejoined. Bug 712600, r=ehsan, roc
This commit is contained in:
Родитель
438acd9033
Коммит
1ecc6bcb4a
|
@ -86,12 +86,14 @@ struct BidiParagraphData {
|
|||
nsAutoPtr<nsBidi> mBidiEngine;
|
||||
nsIFrame* mPrevFrame;
|
||||
nsAutoPtr<BidiParagraphData> mSubParagraph;
|
||||
PRUint8 mParagraphDepth;
|
||||
|
||||
void Init(nsBlockFrame *aBlockFrame)
|
||||
{
|
||||
mContentToFrameIndex.Init();
|
||||
mBidiEngine = new nsBidi();
|
||||
mPrevContent = nsnull;
|
||||
mParagraphDepth = 0;
|
||||
|
||||
bool styleDirectionIsRTL =
|
||||
(NS_STYLE_DIRECTION_RTL == aBlockFrame->GetStyleVisibility()->mDirection);
|
||||
|
@ -149,19 +151,10 @@ struct BidiParagraphData {
|
|||
mBidiEngine = new nsBidi();
|
||||
mPrevContent = nsnull;
|
||||
mIsVisual = aBpd->mIsVisual;
|
||||
mParaLevel = aBpd->mParaLevel;
|
||||
|
||||
// If the containing paragraph has a level of NSBIDI_DEFAULT_LTR, set
|
||||
// the sub-paragraph to NSBIDI_LTR (we can't use GetParaLevel to find the
|
||||
// resolved paragraph level, because the containing paragraph hasn't yet
|
||||
// been through bidi resolution
|
||||
if (mParaLevel == NSBIDI_DEFAULT_LTR) {
|
||||
mParaLevel = NSBIDI_LTR;
|
||||
}
|
||||
mReset = false;
|
||||
}
|
||||
|
||||
void Reset(nsIFrame* aFrame, BidiParagraphData *aBpd)
|
||||
void Reset(nsIFrame* aBDIFrame, BidiParagraphData *aBpd)
|
||||
{
|
||||
mReset = true;
|
||||
mLogicalFrames.Clear();
|
||||
|
@ -169,37 +162,15 @@ struct BidiParagraphData {
|
|||
mContentToFrameIndex.Clear();
|
||||
mBuffer.SetLength(0);
|
||||
mPrevFrame = aBpd->mPrevFrame;
|
||||
// We need to copy in embeddings (but not overrides!) from the containing
|
||||
// paragraph so that the line(s) including this sub-paragraph will be
|
||||
// correctly reordered.
|
||||
for (PRUint32 i = 0; i < aBpd->mEmbeddingStack.Length(); ++i) {
|
||||
switch(aBpd->mEmbeddingStack[i]) {
|
||||
case kRLE:
|
||||
case kRLO:
|
||||
mParaLevel = NextOddLevel(mParaLevel);
|
||||
break;
|
||||
mParagraphDepth = aBpd->mParagraphDepth + 1;
|
||||
|
||||
case kLRE:
|
||||
case kLRO:
|
||||
mParaLevel = NextEvenLevel(mParaLevel);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
nsIFrame* container = aFrame->GetParent();
|
||||
bool isRTL = (NS_STYLE_DIRECTION_RTL ==
|
||||
container->GetStyleVisibility()->mDirection);
|
||||
if ((isRTL & 1) != (mParaLevel & 1)) {
|
||||
mParaLevel = isRTL ? NextOddLevel(mParaLevel) : NextEvenLevel(mParaLevel);
|
||||
}
|
||||
aBDIFrame->GetStyleVisibility()->mDirection);
|
||||
mParaLevel = mParagraphDepth * 2;
|
||||
if (isRTL) ++mParaLevel;
|
||||
|
||||
if (container->GetStyleTextReset()->mUnicodeBidi & NS_STYLE_UNICODE_BIDI_OVERRIDE) {
|
||||
if (aBDIFrame->GetStyleTextReset()->mUnicodeBidi & NS_STYLE_UNICODE_BIDI_OVERRIDE) {
|
||||
PushBidiControl(isRTL ? kRLO : kLRO);
|
||||
} else {
|
||||
PushBidiControl(isRTL ? kRLE : kLRE);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -333,16 +304,6 @@ struct BidiParagraphData {
|
|||
}
|
||||
}
|
||||
|
||||
nsBidiLevel NextOddLevel(nsBidiLevel aLevel)
|
||||
{
|
||||
return (aLevel + 1) | 1;
|
||||
}
|
||||
|
||||
nsBidiLevel NextEvenLevel(nsBidiLevel aLevel)
|
||||
{
|
||||
return (aLevel + 2) & ~1;
|
||||
}
|
||||
|
||||
static bool
|
||||
IsFrameInCurrentLine(nsBlockInFlowLineIterator* aLineIter,
|
||||
nsIFrame* aPrevFrame, nsIFrame* aFrame)
|
||||
|
@ -453,13 +414,23 @@ IsBidiSplittable(nsIFrame* aFrame) {
|
|||
&& frameType != nsGkAtoms::lineFrame;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create non-fluid continuations for the ancestors of a given frame all the way
|
||||
* up the frame tree until we hit a non-splittable frame (a line or a block).
|
||||
*
|
||||
* @param aParent the first parent frame to be split
|
||||
* @param aFrame the child frames after this frame are reparented to the
|
||||
* newly-created continuation of aParent.
|
||||
* If aFrame is null, all the children of aParent are reparented.
|
||||
*/
|
||||
static nsresult
|
||||
SplitInlineAncestors(nsIFrame* aFrame)
|
||||
SplitInlineAncestors(nsIFrame* aParent,
|
||||
nsIFrame* aFrame)
|
||||
{
|
||||
nsPresContext *presContext = aFrame->PresContext();
|
||||
nsPresContext *presContext = aParent->PresContext();
|
||||
nsIPresShell *presShell = presContext->PresShell();
|
||||
nsIFrame* frame = aFrame;
|
||||
nsIFrame* parent = aFrame->GetParent();
|
||||
nsIFrame* parent = aParent;
|
||||
nsIFrame* newParent;
|
||||
|
||||
while (IsBidiSplittable(parent)) {
|
||||
|
@ -472,21 +443,24 @@ SplitInlineAncestors(nsIFrame* aFrame)
|
|||
return rv;
|
||||
}
|
||||
|
||||
// Split the child list after |frame|.
|
||||
nsContainerFrame* container = do_QueryFrame(parent);
|
||||
nsFrameList tail = container->StealFramesAfter(frame);
|
||||
// Split the child list after |frame|, unless it is the last child.
|
||||
if (!frame || frame->GetNextSibling()) {
|
||||
nsContainerFrame* container = do_QueryFrame(parent);
|
||||
nsFrameList tail = container->StealFramesAfter(frame);
|
||||
|
||||
// Reparent views as necessary
|
||||
rv = nsContainerFrame::ReparentFrameViewList(presContext, tail, parent, newParent);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
// Reparent views as necessary
|
||||
rv = nsContainerFrame::ReparentFrameViewList(presContext, tail, parent, newParent);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
// The parent's continuation adopts the siblings after the split.
|
||||
rv = newParent->InsertFrames(nsIFrame::kNoReflowPrincipalList, nsnull, tail);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
// The parent's continuation adopts the siblings after the split.
|
||||
rv = newParent->InsertFrames(nsIFrame::kNoReflowPrincipalList, nsnull, tail);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
// The list name kNoReflowPrincipalList would indicate we don't want reflow
|
||||
nsFrameList temp(newParent, newParent);
|
||||
rv = grandparent->InsertFrames(nsIFrame::kNoReflowPrincipalList, parent, temp);
|
||||
|
@ -525,7 +499,12 @@ JoinInlineAncestors(nsIFrame* aFrame)
|
|||
while (frame && IsBidiSplittable(frame)) {
|
||||
nsIFrame* next = frame->GetNextContinuation();
|
||||
if (next) {
|
||||
MakeContinuationFluid(frame, next);
|
||||
// Don't join frames if they come from different paragraph depths (i.e.
|
||||
// one is bidi isolated relative to the other
|
||||
if (nsBidiPresUtils::GetParagraphDepth(frame) ==
|
||||
nsBidiPresUtils::GetParagraphDepth(next)) {
|
||||
MakeContinuationFluid(frame, next);
|
||||
}
|
||||
}
|
||||
// Join the parent only as long as we're its last child.
|
||||
if (frame->GetNextSibling())
|
||||
|
@ -580,7 +559,7 @@ CreateContinuation(nsIFrame* aFrame,
|
|||
|
||||
if (!aIsFluid) {
|
||||
// Split inline ancestor frames
|
||||
rv = SplitInlineAncestors(aFrame);
|
||||
rv = SplitInlineAncestors(parent, aFrame);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -705,6 +684,9 @@ nsBidiPresUtils::ResolveParagraph(nsBlockFrame* aBlockFrame,
|
|||
#endif
|
||||
#endif
|
||||
|
||||
nsIFrame* firstFrame = nsnull;
|
||||
nsIFrame* lastFrame = nsnull;
|
||||
|
||||
for (; ;) {
|
||||
if (fragmentLength <= 0) {
|
||||
// Get the next frame from mLogicalFrames
|
||||
|
@ -722,6 +704,10 @@ nsBidiPresUtils::ResolveParagraph(nsBlockFrame* aBlockFrame,
|
|||
fragmentLength = 1;
|
||||
}
|
||||
else {
|
||||
if (!firstFrame) {
|
||||
firstFrame = frame;
|
||||
}
|
||||
lastFrame = frame;
|
||||
currentLine = aBpd->GetLineForFrameAt(frameIndex);
|
||||
content = frame->GetContent();
|
||||
if (!content) {
|
||||
|
@ -737,6 +723,8 @@ nsBidiPresUtils::ResolveParagraph(nsBlockFrame* aBlockFrame,
|
|||
NS_INT32_TO_PTR(embeddingLevel));
|
||||
propTable->Set(frame, nsIFrame::BaseLevelProperty(),
|
||||
NS_INT32_TO_PTR(aBpd->GetParaLevel()));
|
||||
propTable->Set(frame, nsIFrame::ParagraphDepthProperty(),
|
||||
NS_INT32_TO_PTR(aBpd->mParagraphDepth));
|
||||
continue;
|
||||
}
|
||||
PRInt32 start, end;
|
||||
|
@ -771,6 +759,8 @@ nsBidiPresUtils::ResolveParagraph(nsBlockFrame* aBlockFrame,
|
|||
NS_INT32_TO_PTR(embeddingLevel));
|
||||
propTable->Set(frame, nsIFrame::BaseLevelProperty(),
|
||||
NS_INT32_TO_PTR(aBpd->GetParaLevel()));
|
||||
propTable->Set(frame, nsIFrame::ParagraphDepthProperty(),
|
||||
NS_INT32_TO_PTR(aBpd->mParagraphDepth));
|
||||
if (isTextFrame) {
|
||||
if ( (runLength > 0) && (runLength < fragmentLength) ) {
|
||||
/*
|
||||
|
@ -788,7 +778,7 @@ nsBidiPresUtils::ResolveParagraph(nsBlockFrame* aBlockFrame,
|
|||
}
|
||||
nextBidi->AdjustOffsetsForBidi(runEnd,
|
||||
contentOffset + fragmentLength);
|
||||
frame = nextBidi;
|
||||
lastFrame = frame = nextBidi;
|
||||
contentOffset = runEnd;
|
||||
} // if (runLength < fragmentLength)
|
||||
else {
|
||||
|
@ -870,8 +860,9 @@ nsBidiPresUtils::ResolveParagraph(nsBlockFrame* aBlockFrame,
|
|||
child = parent;
|
||||
parent = child->GetParent();
|
||||
}
|
||||
if (parent && IsBidiSplittable(parent))
|
||||
SplitInlineAncestors(child);
|
||||
if (parent && IsBidiSplittable(parent)) {
|
||||
SplitInlineAncestors(parent, child);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -883,6 +874,31 @@ nsBidiPresUtils::ResolveParagraph(nsBlockFrame* aBlockFrame,
|
|||
}
|
||||
} // for
|
||||
|
||||
if (aBpd->mParagraphDepth > 1) {
|
||||
nsIFrame* child;
|
||||
nsIFrame* parent;
|
||||
if (firstFrame) {
|
||||
child = firstFrame->GetParent();
|
||||
if (child) {
|
||||
parent = child->GetParent();
|
||||
if (parent && IsBidiSplittable(parent)) {
|
||||
// no need to null-check the result of GetPrevSibling, because
|
||||
// SplitInlineAncestors accepts a null parameter
|
||||
SplitInlineAncestors(parent, child->GetPrevSibling());
|
||||
}
|
||||
}
|
||||
}
|
||||
if (lastFrame) {
|
||||
child = lastFrame->GetParent();
|
||||
if (child) {
|
||||
parent = child->GetParent();
|
||||
if (parent && IsBidiSplittable(parent)) {
|
||||
SplitInlineAncestors(parent, child);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
#ifdef REALLY_NOISY_BIDI
|
||||
printf("---\nAfter Resolve(), frameTree =:\n");
|
||||
|
@ -1122,7 +1138,7 @@ nsBidiPresUtils::TraverseFrames(nsBlockFrame* aBlockFrame,
|
|||
*/
|
||||
bool isLastContinuation = !frame->GetNextContinuation();
|
||||
if (!frame->GetPrevContinuation() || !subParagraph->mReset) {
|
||||
subParagraph->Reset(kid, aBpd);
|
||||
subParagraph->Reset(frame, aBpd);
|
||||
}
|
||||
TraverseFrames(aBlockFrame, aLineIter, kid, subParagraph);
|
||||
if (isLastContinuation) {
|
||||
|
@ -1177,8 +1193,8 @@ nsBidiPresUtils::ReorderFrames(nsIFrame* aFirstFrameOnLine,
|
|||
RepositionInlineFrames(&bld, aFirstFrameOnLine);
|
||||
}
|
||||
|
||||
nsBidiLevel
|
||||
nsBidiPresUtils::GetFrameEmbeddingLevel(nsIFrame* aFrame)
|
||||
nsIFrame*
|
||||
nsBidiPresUtils::GetFirstLeaf(nsIFrame* aFrame)
|
||||
{
|
||||
nsIFrame* firstLeaf = aFrame;
|
||||
while (!IsBidiLeaf(firstLeaf)) {
|
||||
|
@ -1187,9 +1203,22 @@ nsBidiPresUtils::GetFrameEmbeddingLevel(nsIFrame* aFrame)
|
|||
firstLeaf = (realFrame->GetType() == nsGkAtoms::letterFrame) ?
|
||||
realFrame : firstChild;
|
||||
}
|
||||
return NS_GET_EMBEDDING_LEVEL(firstLeaf);
|
||||
return firstLeaf;
|
||||
}
|
||||
|
||||
nsBidiLevel
|
||||
nsBidiPresUtils::GetFrameEmbeddingLevel(nsIFrame* aFrame)
|
||||
{
|
||||
return NS_GET_EMBEDDING_LEVEL(nsBidiPresUtils::GetFirstLeaf(aFrame));
|
||||
}
|
||||
|
||||
PRUint8
|
||||
nsBidiPresUtils::GetParagraphDepth(nsIFrame* aFrame)
|
||||
{
|
||||
return NS_GET_PARAGRAPH_DEPTH(nsBidiPresUtils::GetFirstLeaf(aFrame));
|
||||
}
|
||||
|
||||
|
||||
nsBidiLevel
|
||||
nsBidiPresUtils::GetFrameBaseLevel(nsIFrame* aFrame)
|
||||
{
|
||||
|
@ -1528,6 +1557,8 @@ nsBidiPresUtils::RemoveBidiContinuation(BidiParagraphData *aBpd,
|
|||
(nsBidiLevel)NS_PTR_TO_INT32(props.Get(nsIFrame::EmbeddingLevelProperty()));
|
||||
nsBidiLevel baseLevel =
|
||||
(nsBidiLevel)NS_PTR_TO_INT32(props.Get(nsIFrame::BaseLevelProperty()));
|
||||
PRUint8 paragraphDepth =
|
||||
NS_PTR_TO_INT32(props.Get(nsIFrame::ParagraphDepthProperty()));
|
||||
|
||||
for (PRInt32 index = aFirstIndex + 1; index <= aLastIndex; index++) {
|
||||
nsIFrame* frame = aBpd->FrameAt(index);
|
||||
|
@ -1542,6 +1573,8 @@ nsBidiPresUtils::RemoveBidiContinuation(BidiParagraphData *aBpd,
|
|||
NS_INT32_TO_PTR(embeddingLevel));
|
||||
frameProps.Set(nsIFrame::BaseLevelProperty(),
|
||||
NS_INT32_TO_PTR(baseLevel));
|
||||
frameProps.Set(nsIFrame::ParagraphDepthProperty(),
|
||||
NS_INT32_TO_PTR(paragraphDepth));
|
||||
frame->AddStateBits(NS_FRAME_IS_BIDI);
|
||||
while (frame) {
|
||||
nsIFrame* prev = frame->GetPrevContinuation();
|
||||
|
|
|
@ -283,11 +283,18 @@ public:
|
|||
static nsIFrame* GetFrameToLeftOf(const nsIFrame* aFrame,
|
||||
nsIFrame* aFirstFrameOnLine,
|
||||
PRInt32 aNumFramesOnLine);
|
||||
|
||||
static nsIFrame* GetFirstLeaf(nsIFrame* aFrame);
|
||||
|
||||
/**
|
||||
* Get the bidi embedding level of the given (inline) frame.
|
||||
*/
|
||||
static nsBidiLevel GetFrameEmbeddingLevel(nsIFrame* aFrame);
|
||||
|
||||
/**
|
||||
* Get the paragraph depth of the given (inline) frame.
|
||||
*/
|
||||
static PRUint8 GetParagraphDepth(nsIFrame* aFrame);
|
||||
|
||||
/**
|
||||
* Get the bidi base level of the given (inline) frame.
|
||||
|
|
|
@ -2529,6 +2529,7 @@ public:
|
|||
|
||||
NS_DECLARE_FRAME_PROPERTY(BaseLevelProperty, nsnull)
|
||||
NS_DECLARE_FRAME_PROPERTY(EmbeddingLevelProperty, nsnull)
|
||||
NS_DECLARE_FRAME_PROPERTY(ParagraphDepthProperty, nsnull)
|
||||
|
||||
#define NS_GET_BASE_LEVEL(frame) \
|
||||
NS_PTR_TO_INT32(frame->Properties().Get(nsIFrame::BaseLevelProperty()))
|
||||
|
@ -2536,6 +2537,9 @@ NS_PTR_TO_INT32(frame->Properties().Get(nsIFrame::BaseLevelProperty()))
|
|||
#define NS_GET_EMBEDDING_LEVEL(frame) \
|
||||
NS_PTR_TO_INT32(frame->Properties().Get(nsIFrame::EmbeddingLevelProperty()))
|
||||
|
||||
#define NS_GET_PARAGRAPH_DEPTH(frame) \
|
||||
NS_PTR_TO_INT32(frame->Properties().Get(nsIFrame::ParagraphDepthProperty()))
|
||||
|
||||
/**
|
||||
* Return true if and only if this frame obeys visibility:hidden.
|
||||
* if it does not, then nsContainerFrame will hide its view even though
|
||||
|
|
|
@ -1492,7 +1492,8 @@ BuildTextRunsScanner::ContinueTextRunAcrossFrames(nsTextFrame* aFrame1, nsTextFr
|
|||
// already guaranteed to be the same as each other (and for the line
|
||||
// container).
|
||||
if (mBidiEnabled &&
|
||||
NS_GET_EMBEDDING_LEVEL(aFrame1) != NS_GET_EMBEDDING_LEVEL(aFrame2))
|
||||
(NS_GET_EMBEDDING_LEVEL(aFrame1) != NS_GET_EMBEDDING_LEVEL(aFrame2) ||
|
||||
NS_GET_PARAGRAPH_DEPTH(aFrame1) != NS_GET_PARAGRAPH_DEPTH(aFrame2)))
|
||||
return false;
|
||||
|
||||
nsStyleContext* sc1 = aFrame1->GetStyleContext();
|
||||
|
@ -3943,8 +3944,10 @@ nsContinuingTextFrame::Init(nsIContent* aContent,
|
|||
// advantage of the propTable's cache and simplify the assertion below
|
||||
void* embeddingLevel = propTable->Get(aPrevInFlow, EmbeddingLevelProperty());
|
||||
void* baseLevel = propTable->Get(aPrevInFlow, BaseLevelProperty());
|
||||
void* paragraphDepth = propTable->Get(aPrevInFlow, ParagraphDepthProperty());
|
||||
propTable->Set(this, EmbeddingLevelProperty(), embeddingLevel);
|
||||
propTable->Set(this, BaseLevelProperty(), baseLevel);
|
||||
propTable->Set(this, ParagraphDepthProperty(), paragraphDepth);
|
||||
|
||||
if (nextContinuation) {
|
||||
SetNextContinuation(nextContinuation);
|
||||
|
@ -3954,7 +3957,8 @@ nsContinuingTextFrame::Init(nsIContent* aContent,
|
|||
nextContinuation->GetContentOffset() < mContentOffset) {
|
||||
NS_ASSERTION(
|
||||
embeddingLevel == propTable->Get(nextContinuation, EmbeddingLevelProperty()) &&
|
||||
baseLevel == propTable->Get(nextContinuation, BaseLevelProperty()),
|
||||
baseLevel == propTable->Get(nextContinuation, BaseLevelProperty()) &&
|
||||
paragraphDepth == propTable->Get(nextContinuation, ParagraphDepthProperty()),
|
||||
"stealing text from different type of BIDI continuation");
|
||||
nextContinuation->mContentOffset = mContentOffset;
|
||||
nextContinuation = static_cast<nsTextFrame*>(nextContinuation->GetNextContinuation());
|
||||
|
|
Загрузка…
Ссылка в новой задаче