mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-26 14:22:01 +00:00
#161328 CJK string is not breakable before joined frames
This patch include 3 changes: 1) check the breaking possibility in between for 2 connection pieces. 2) Make word breakable after the second word, priviously it only applies to western. 3) always call RevertSpacesToNBSP before call line breaker. This is necessary because the change in 1. r=boris zbarsky, sr=rbs
This commit is contained in:
parent
cb652e487a
commit
6245c03e54
@ -651,7 +651,7 @@ public:
|
||||
PRPackedBool mMeasureText; // IN
|
||||
PRPackedBool mInWord; // IN
|
||||
PRPackedBool mFirstLetterOK; // IN
|
||||
PRPackedBool mIsBreakable; // IN
|
||||
PRPackedBool mCanBreakBefore; // IN
|
||||
PRPackedBool mComputeMaxWordWidth; // IN
|
||||
PRPackedBool mTrailingSpaceTrimmed; // IN/OUT
|
||||
|
||||
@ -661,7 +661,7 @@ public:
|
||||
PRBool aMeasureText,
|
||||
PRBool aInWord,
|
||||
PRBool aFirstLetterOK,
|
||||
PRBool aIsBreakable,
|
||||
PRBool aCanBreakBefore,
|
||||
PRBool aComputeMaxWordWidth,
|
||||
PRBool aTrailingSpaceTrimmed)
|
||||
: mX(0),
|
||||
@ -674,7 +674,7 @@ public:
|
||||
mMeasureText(aMeasureText),
|
||||
mInWord(aInWord),
|
||||
mFirstLetterOK(aFirstLetterOK),
|
||||
mIsBreakable(aIsBreakable),
|
||||
mCanBreakBefore(aCanBreakBefore),
|
||||
mComputeMaxWordWidth(aComputeMaxWordWidth),
|
||||
mTrailingSpaceTrimmed(aTrailingSpaceTrimmed)
|
||||
{}
|
||||
@ -774,7 +774,7 @@ public:
|
||||
PRUnichar* aWordBuf,
|
||||
PRUint32 aWordBufLen,
|
||||
PRUint32 aWordBufSize,
|
||||
PRBool aIsBreakable);
|
||||
PRBool aCanBreakBefore);
|
||||
|
||||
nsTextDimensions ComputeWordFragmentDimensions(nsIPresContext* aPresContext,
|
||||
nsILineBreaker* aLineBreaker,
|
||||
@ -787,7 +787,7 @@ public:
|
||||
const PRUnichar* aWordBuf,
|
||||
PRUint32 &aWordBufLen,
|
||||
PRUint32 aWordBufSize,
|
||||
PRBool aIsBreakable);
|
||||
PRBool aCanBreakBefore);
|
||||
|
||||
void ToCString(nsString& aBuf, PRInt32* aTotalContentLength) const;
|
||||
|
||||
@ -4626,6 +4626,7 @@ nsTextFrame::MeasureText(nsIPresContext* aPresContext,
|
||||
aTs.mNormalFont->GetMaxAscent(aTextData.mAscent);
|
||||
aTs.mNormalFont->GetMaxDescent(aTextData.mDescent);
|
||||
}
|
||||
PRBool firstWordDone = PR_FALSE;
|
||||
for (;;firstThing = PR_FALSE) {
|
||||
#ifdef IBMBIDI
|
||||
if (nextBidi && (mContentLength <= 0) ) {
|
||||
@ -4648,6 +4649,15 @@ nsTextFrame::MeasureText(nsIPresContext* aPresContext,
|
||||
#ifdef IBMBIDI
|
||||
wordLen = start;
|
||||
#endif // IBMBIDI
|
||||
|
||||
// We need to set aTextData.mCanBreakBefore to true after 1st word. But we can't set
|
||||
// aTextData.mCanBreakBefore without seeing the 2nd word. That's because this frame
|
||||
// may only contain part of one word, the other part is in next frame.
|
||||
// we don't care if first word is whitespace, that will be addressed later.
|
||||
if (!aTextData.mCanBreakBefore && !firstThing && !isWhitespace) {
|
||||
firstWordDone = PR_TRUE;
|
||||
}
|
||||
|
||||
bp2 = aTx.GetNextWord(aTextData.mInWord, &wordLen, &contentLen, &isWhitespace,
|
||||
&wasTransformed, textRun.mNumSegments == 0);
|
||||
#ifdef IBMBIDI
|
||||
@ -4664,7 +4674,14 @@ nsTextFrame::MeasureText(nsIPresContext* aPresContext,
|
||||
if (wasTransformed) {
|
||||
mState |= TEXT_WAS_TRANSFORMED;
|
||||
}
|
||||
if (nsnull == bp2) {
|
||||
|
||||
if (bp2) {
|
||||
if (firstWordDone) {
|
||||
// The first word has been processed, and 2nd word is seen
|
||||
// we can set it be breakable here after.
|
||||
aTextData.mCanBreakBefore = PR_TRUE;
|
||||
}
|
||||
} else {
|
||||
if (textRun.IsBuffering()) {
|
||||
// Measure the remaining text
|
||||
goto MeasureTextRun;
|
||||
@ -4677,6 +4694,7 @@ nsTextFrame::MeasureText(nsIPresContext* aPresContext,
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
lastWordLen = wordLen;
|
||||
lastWordPtr = bp2;
|
||||
aTextData.mInWord = PR_FALSE;
|
||||
@ -4717,7 +4735,7 @@ nsTextFrame::MeasureText(nsIPresContext* aPresContext,
|
||||
|
||||
// NOTE: Even if the textRun absorbs the whitespace below, we still
|
||||
// want to remember that we're breakable.
|
||||
aTextData.mIsBreakable = PR_TRUE;
|
||||
aTextData.mCanBreakBefore = PR_TRUE;
|
||||
aTextData.mFirstLetterOK = PR_FALSE;
|
||||
|
||||
if ('\t' == firstChar) {
|
||||
@ -5024,13 +5042,13 @@ nsTextFrame::MeasureText(nsIPresContext* aPresContext,
|
||||
// Force breakable to false when we aren't wrapping (this
|
||||
// guarantees that the combined word will stay together)
|
||||
if (!aTextData.mWrapping) {
|
||||
aTextData.mIsBreakable = PR_FALSE;
|
||||
aTextData.mCanBreakBefore = PR_FALSE;
|
||||
}
|
||||
|
||||
// This frame does start a word. However, there is no point
|
||||
// messing around with it if we are already out of room. We
|
||||
// always have room if we are not breakable.
|
||||
if (!aTextData.mIsBreakable || (aTextData.mX <= maxWidth)) {
|
||||
if (!aTextData.mCanBreakBefore || (aTextData.mX <= maxWidth)) {
|
||||
// There is room for this word fragment. It's possible that
|
||||
// this word fragment is the end of the text-run. If it's not
|
||||
// then we continue with the look-ahead processing.
|
||||
@ -5086,8 +5104,8 @@ nsTextFrame::MeasureText(nsIPresContext* aPresContext,
|
||||
pWordBuf,
|
||||
lastWordLen,
|
||||
wordBufLen,
|
||||
aTextData.mIsBreakable);
|
||||
if (!aTextData.mIsBreakable || (aTextData.mX - lastWordDimensions.width + wordDimensions.width <= maxWidth)) {
|
||||
aTextData.mCanBreakBefore);
|
||||
if (!aTextData.mCanBreakBefore || (aTextData.mX - lastWordDimensions.width + wordDimensions.width <= maxWidth)) {
|
||||
// The fully joined word has fit. Account for the joined
|
||||
// word's affect on the max-element-size here (since the
|
||||
// joined word is large than it's pieces, the right effect
|
||||
@ -5606,13 +5624,11 @@ nsTextFrame::ComputeTotalWordDimensions(nsIPresContext* aPresContext,
|
||||
PRUnichar* aWordBuf,
|
||||
PRUint32 aWordLen,
|
||||
PRUint32 aWordBufSize,
|
||||
PRBool aIsBreakable)
|
||||
PRBool aCanBreakBefore)
|
||||
{
|
||||
if (aIsBreakable) {
|
||||
// Before we get going, convert any spaces in the current word back
|
||||
// to nbsp's. This keeps the breaking logic happy.
|
||||
RevertSpacesToNBSP(aWordBuf, (PRInt32) aWordLen);
|
||||
}
|
||||
// Before we get going, convert any spaces in the current word back
|
||||
// to nbsp's. This keeps the breaking logic happy.
|
||||
RevertSpacesToNBSP(aWordBuf, (PRInt32) aWordLen);
|
||||
|
||||
nsTextDimensions addedDimensions;
|
||||
PRUnichar *newWordBuf = aWordBuf;
|
||||
@ -5640,7 +5656,7 @@ nsTextFrame::ComputeTotalWordDimensions(nsIPresContext* aPresContext,
|
||||
newWordBuf,
|
||||
aWordLen,
|
||||
newWordBufSize,
|
||||
aIsBreakable);
|
||||
aCanBreakBefore);
|
||||
if (moreDimensions.width < 0) {
|
||||
PRUint32 moreSize = -moreDimensions.width;
|
||||
//Oh, wordBuf is too small, we have to grow it
|
||||
@ -5662,7 +5678,7 @@ nsTextFrame::ComputeTotalWordDimensions(nsIPresContext* aPresContext,
|
||||
aLineLayout, aReflowState,
|
||||
aNextFrame, content, tc, &stop,
|
||||
newWordBuf, aWordLen, newWordBufSize,
|
||||
aIsBreakable);
|
||||
aCanBreakBefore);
|
||||
NS_ASSERTION((moreDimensions.width >= 0),
|
||||
"ComputeWordFragmentWidth is returning negative");
|
||||
} else {
|
||||
@ -5714,7 +5730,7 @@ nsTextFrame::ComputeWordFragmentDimensions(nsIPresContext* aPresContext,
|
||||
const PRUnichar* aWordBuf,
|
||||
PRUint32& aRunningWordLen,
|
||||
PRUint32 aWordBufSize,
|
||||
PRBool aIsBreakable)
|
||||
PRBool aCanBreakBefore)
|
||||
{
|
||||
nsTextTransformer tx(aLineBreaker, nsnull, aPresContext);
|
||||
tx.Init(aTextFrame, aContent, 0);
|
||||
@ -5747,11 +5763,11 @@ nsTextFrame::ComputeWordFragmentDimensions(nsIPresContext* aPresContext,
|
||||
}
|
||||
*aStop = contentLen < tx.GetContentLength();
|
||||
|
||||
if (aIsBreakable) {
|
||||
// Convert any spaces in the current word back to nbsp's. This keeps
|
||||
// the breaking logic happy.
|
||||
RevertSpacesToNBSP(bp, wordLen);
|
||||
// Convert any spaces in the current word back to nbsp's. This keeps
|
||||
// the breaking logic happy.
|
||||
RevertSpacesToNBSP(bp, wordLen);
|
||||
|
||||
if (aCanBreakBefore) {
|
||||
if(wordLen > 0)
|
||||
{
|
||||
memcpy((void*)&(aWordBuf[aRunningWordLen]), bp, sizeof(PRUnichar)*wordLen);
|
||||
@ -5780,6 +5796,17 @@ nsTextFrame::ComputeWordFragmentDimensions(nsIPresContext* aPresContext,
|
||||
aRunningWordLen += wordLen;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Even if the previous text fragment is not breakable, the connected pieces
|
||||
// can be breakable in between. This especially true for CJK.
|
||||
PRBool canBreak;
|
||||
nsresult lres = aLineBreaker->BreakInBetween(aWordBuf, aRunningWordLen, bp, wordLen, &canBreak);
|
||||
if (NS_SUCCEEDED(lres) && canBreak) {
|
||||
wordLen = 0;
|
||||
*aStop = PR_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if((*aStop) && (wordLen == 0))
|
||||
return dimensions; // 0;
|
||||
|
||||
|
@ -651,7 +651,7 @@ public:
|
||||
PRPackedBool mMeasureText; // IN
|
||||
PRPackedBool mInWord; // IN
|
||||
PRPackedBool mFirstLetterOK; // IN
|
||||
PRPackedBool mIsBreakable; // IN
|
||||
PRPackedBool mCanBreakBefore; // IN
|
||||
PRPackedBool mComputeMaxWordWidth; // IN
|
||||
PRPackedBool mTrailingSpaceTrimmed; // IN/OUT
|
||||
|
||||
@ -661,7 +661,7 @@ public:
|
||||
PRBool aMeasureText,
|
||||
PRBool aInWord,
|
||||
PRBool aFirstLetterOK,
|
||||
PRBool aIsBreakable,
|
||||
PRBool aCanBreakBefore,
|
||||
PRBool aComputeMaxWordWidth,
|
||||
PRBool aTrailingSpaceTrimmed)
|
||||
: mX(0),
|
||||
@ -674,7 +674,7 @@ public:
|
||||
mMeasureText(aMeasureText),
|
||||
mInWord(aInWord),
|
||||
mFirstLetterOK(aFirstLetterOK),
|
||||
mIsBreakable(aIsBreakable),
|
||||
mCanBreakBefore(aCanBreakBefore),
|
||||
mComputeMaxWordWidth(aComputeMaxWordWidth),
|
||||
mTrailingSpaceTrimmed(aTrailingSpaceTrimmed)
|
||||
{}
|
||||
@ -774,7 +774,7 @@ public:
|
||||
PRUnichar* aWordBuf,
|
||||
PRUint32 aWordBufLen,
|
||||
PRUint32 aWordBufSize,
|
||||
PRBool aIsBreakable);
|
||||
PRBool aCanBreakBefore);
|
||||
|
||||
nsTextDimensions ComputeWordFragmentDimensions(nsIPresContext* aPresContext,
|
||||
nsILineBreaker* aLineBreaker,
|
||||
@ -787,7 +787,7 @@ public:
|
||||
const PRUnichar* aWordBuf,
|
||||
PRUint32 &aWordBufLen,
|
||||
PRUint32 aWordBufSize,
|
||||
PRBool aIsBreakable);
|
||||
PRBool aCanBreakBefore);
|
||||
|
||||
void ToCString(nsString& aBuf, PRInt32* aTotalContentLength) const;
|
||||
|
||||
@ -4626,6 +4626,7 @@ nsTextFrame::MeasureText(nsIPresContext* aPresContext,
|
||||
aTs.mNormalFont->GetMaxAscent(aTextData.mAscent);
|
||||
aTs.mNormalFont->GetMaxDescent(aTextData.mDescent);
|
||||
}
|
||||
PRBool firstWordDone = PR_FALSE;
|
||||
for (;;firstThing = PR_FALSE) {
|
||||
#ifdef IBMBIDI
|
||||
if (nextBidi && (mContentLength <= 0) ) {
|
||||
@ -4648,6 +4649,15 @@ nsTextFrame::MeasureText(nsIPresContext* aPresContext,
|
||||
#ifdef IBMBIDI
|
||||
wordLen = start;
|
||||
#endif // IBMBIDI
|
||||
|
||||
// We need to set aTextData.mCanBreakBefore to true after 1st word. But we can't set
|
||||
// aTextData.mCanBreakBefore without seeing the 2nd word. That's because this frame
|
||||
// may only contain part of one word, the other part is in next frame.
|
||||
// we don't care if first word is whitespace, that will be addressed later.
|
||||
if (!aTextData.mCanBreakBefore && !firstThing && !isWhitespace) {
|
||||
firstWordDone = PR_TRUE;
|
||||
}
|
||||
|
||||
bp2 = aTx.GetNextWord(aTextData.mInWord, &wordLen, &contentLen, &isWhitespace,
|
||||
&wasTransformed, textRun.mNumSegments == 0);
|
||||
#ifdef IBMBIDI
|
||||
@ -4664,7 +4674,14 @@ nsTextFrame::MeasureText(nsIPresContext* aPresContext,
|
||||
if (wasTransformed) {
|
||||
mState |= TEXT_WAS_TRANSFORMED;
|
||||
}
|
||||
if (nsnull == bp2) {
|
||||
|
||||
if (bp2) {
|
||||
if (firstWordDone) {
|
||||
// The first word has been processed, and 2nd word is seen
|
||||
// we can set it be breakable here after.
|
||||
aTextData.mCanBreakBefore = PR_TRUE;
|
||||
}
|
||||
} else {
|
||||
if (textRun.IsBuffering()) {
|
||||
// Measure the remaining text
|
||||
goto MeasureTextRun;
|
||||
@ -4677,6 +4694,7 @@ nsTextFrame::MeasureText(nsIPresContext* aPresContext,
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
lastWordLen = wordLen;
|
||||
lastWordPtr = bp2;
|
||||
aTextData.mInWord = PR_FALSE;
|
||||
@ -4717,7 +4735,7 @@ nsTextFrame::MeasureText(nsIPresContext* aPresContext,
|
||||
|
||||
// NOTE: Even if the textRun absorbs the whitespace below, we still
|
||||
// want to remember that we're breakable.
|
||||
aTextData.mIsBreakable = PR_TRUE;
|
||||
aTextData.mCanBreakBefore = PR_TRUE;
|
||||
aTextData.mFirstLetterOK = PR_FALSE;
|
||||
|
||||
if ('\t' == firstChar) {
|
||||
@ -5024,13 +5042,13 @@ nsTextFrame::MeasureText(nsIPresContext* aPresContext,
|
||||
// Force breakable to false when we aren't wrapping (this
|
||||
// guarantees that the combined word will stay together)
|
||||
if (!aTextData.mWrapping) {
|
||||
aTextData.mIsBreakable = PR_FALSE;
|
||||
aTextData.mCanBreakBefore = PR_FALSE;
|
||||
}
|
||||
|
||||
// This frame does start a word. However, there is no point
|
||||
// messing around with it if we are already out of room. We
|
||||
// always have room if we are not breakable.
|
||||
if (!aTextData.mIsBreakable || (aTextData.mX <= maxWidth)) {
|
||||
if (!aTextData.mCanBreakBefore || (aTextData.mX <= maxWidth)) {
|
||||
// There is room for this word fragment. It's possible that
|
||||
// this word fragment is the end of the text-run. If it's not
|
||||
// then we continue with the look-ahead processing.
|
||||
@ -5086,8 +5104,8 @@ nsTextFrame::MeasureText(nsIPresContext* aPresContext,
|
||||
pWordBuf,
|
||||
lastWordLen,
|
||||
wordBufLen,
|
||||
aTextData.mIsBreakable);
|
||||
if (!aTextData.mIsBreakable || (aTextData.mX - lastWordDimensions.width + wordDimensions.width <= maxWidth)) {
|
||||
aTextData.mCanBreakBefore);
|
||||
if (!aTextData.mCanBreakBefore || (aTextData.mX - lastWordDimensions.width + wordDimensions.width <= maxWidth)) {
|
||||
// The fully joined word has fit. Account for the joined
|
||||
// word's affect on the max-element-size here (since the
|
||||
// joined word is large than it's pieces, the right effect
|
||||
@ -5606,13 +5624,11 @@ nsTextFrame::ComputeTotalWordDimensions(nsIPresContext* aPresContext,
|
||||
PRUnichar* aWordBuf,
|
||||
PRUint32 aWordLen,
|
||||
PRUint32 aWordBufSize,
|
||||
PRBool aIsBreakable)
|
||||
PRBool aCanBreakBefore)
|
||||
{
|
||||
if (aIsBreakable) {
|
||||
// Before we get going, convert any spaces in the current word back
|
||||
// to nbsp's. This keeps the breaking logic happy.
|
||||
RevertSpacesToNBSP(aWordBuf, (PRInt32) aWordLen);
|
||||
}
|
||||
// Before we get going, convert any spaces in the current word back
|
||||
// to nbsp's. This keeps the breaking logic happy.
|
||||
RevertSpacesToNBSP(aWordBuf, (PRInt32) aWordLen);
|
||||
|
||||
nsTextDimensions addedDimensions;
|
||||
PRUnichar *newWordBuf = aWordBuf;
|
||||
@ -5640,7 +5656,7 @@ nsTextFrame::ComputeTotalWordDimensions(nsIPresContext* aPresContext,
|
||||
newWordBuf,
|
||||
aWordLen,
|
||||
newWordBufSize,
|
||||
aIsBreakable);
|
||||
aCanBreakBefore);
|
||||
if (moreDimensions.width < 0) {
|
||||
PRUint32 moreSize = -moreDimensions.width;
|
||||
//Oh, wordBuf is too small, we have to grow it
|
||||
@ -5662,7 +5678,7 @@ nsTextFrame::ComputeTotalWordDimensions(nsIPresContext* aPresContext,
|
||||
aLineLayout, aReflowState,
|
||||
aNextFrame, content, tc, &stop,
|
||||
newWordBuf, aWordLen, newWordBufSize,
|
||||
aIsBreakable);
|
||||
aCanBreakBefore);
|
||||
NS_ASSERTION((moreDimensions.width >= 0),
|
||||
"ComputeWordFragmentWidth is returning negative");
|
||||
} else {
|
||||
@ -5714,7 +5730,7 @@ nsTextFrame::ComputeWordFragmentDimensions(nsIPresContext* aPresContext,
|
||||
const PRUnichar* aWordBuf,
|
||||
PRUint32& aRunningWordLen,
|
||||
PRUint32 aWordBufSize,
|
||||
PRBool aIsBreakable)
|
||||
PRBool aCanBreakBefore)
|
||||
{
|
||||
nsTextTransformer tx(aLineBreaker, nsnull, aPresContext);
|
||||
tx.Init(aTextFrame, aContent, 0);
|
||||
@ -5747,11 +5763,11 @@ nsTextFrame::ComputeWordFragmentDimensions(nsIPresContext* aPresContext,
|
||||
}
|
||||
*aStop = contentLen < tx.GetContentLength();
|
||||
|
||||
if (aIsBreakable) {
|
||||
// Convert any spaces in the current word back to nbsp's. This keeps
|
||||
// the breaking logic happy.
|
||||
RevertSpacesToNBSP(bp, wordLen);
|
||||
// Convert any spaces in the current word back to nbsp's. This keeps
|
||||
// the breaking logic happy.
|
||||
RevertSpacesToNBSP(bp, wordLen);
|
||||
|
||||
if (aCanBreakBefore) {
|
||||
if(wordLen > 0)
|
||||
{
|
||||
memcpy((void*)&(aWordBuf[aRunningWordLen]), bp, sizeof(PRUnichar)*wordLen);
|
||||
@ -5780,6 +5796,17 @@ nsTextFrame::ComputeWordFragmentDimensions(nsIPresContext* aPresContext,
|
||||
aRunningWordLen += wordLen;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Even if the previous text fragment is not breakable, the connected pieces
|
||||
// can be breakable in between. This especially true for CJK.
|
||||
PRBool canBreak;
|
||||
nsresult lres = aLineBreaker->BreakInBetween(aWordBuf, aRunningWordLen, bp, wordLen, &canBreak);
|
||||
if (NS_SUCCEEDED(lres) && canBreak) {
|
||||
wordLen = 0;
|
||||
*aStop = PR_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if((*aStop) && (wordLen == 0))
|
||||
return dimensions; // 0;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user