When resolving the glyphs needed to measure a text that doesn't fit, we have to ensure that we remain at a word boundary. We may have to back up past the current font, in which case we have to reselect previous fonts to deal with the part of the string being chopped off, bug 241485, r=jshin, sr=tor

This commit is contained in:
rbs%maths.uq.edu.au 2005-08-16 07:44:10 +00:00
Родитель 2ceeb6b6ec
Коммит 8c504de1c7
5 изменённых файлов: 260 добавлений и 108 удалений

Просмотреть файл

@ -4326,7 +4326,7 @@ struct BreakGetTextDimensionsData {
// Remember the fonts that we use so that we can deal with
// line-breaking in-between fonts later. mOffsets[0] is also used
// to initialize the current offset from where to start measuring
nsVoidArray* mFonts; // OUT
nsVoidArray* mFonts; // IN/OUT
nsVoidArray* mOffsets; // IN/OUT
};
@ -4347,10 +4347,10 @@ do_BreakGetTextDimensions(const nsFontSwitchGTK *aFontSwitch,
PRInt32 numCharsFit = data->mNumCharsFit;
nscoord width = data->mWidth;
PRInt32 start = (PRInt32)(aSubstring - pstr);
PRInt32 i = start + aSubstringLength;
PRInt32 end = start + aSubstringLength;
PRBool allDone = PR_FALSE;
while (start < i) {
while (start < end) {
// Estimate how many characters will fit. Do that by dividing the
// available space by the average character width
PRInt32 estimatedNumChars = data->mEstimatedNumChars;
@ -4370,9 +4370,9 @@ do_BreakGetTextDimensions(const nsFontSwitchGTK *aFontSwitch,
// Avoid scanning the break array in the case where we think all
// the text should fit
if (i <= estimatedBreakOffset) {
if (end <= estimatedBreakOffset) {
// Everything should fit
numChars = i - start;
numChars = end - start;
}
else {
// Find the nearest place to break that is less than or equal to
@ -4392,20 +4392,20 @@ do_BreakGetTextDimensions(const nsFontSwitchGTK *aFontSwitch,
if (start < data->mBreaks[breakIndex]) {
// The text crosses at least one segment boundary so measure to the
// break point just before the estimated break offset
numChars = PR_MIN(data->mBreaks[breakIndex] - start, (PRInt32)aSubstringLength);
numChars = PR_MIN(data->mBreaks[breakIndex], end) - start;
}
else {
// See whether there is another segment boundary between this one
// and the end of the text
if ((breakIndex < (data->mNumBreaks - 1)) && (data->mBreaks[breakIndex] < i)) {
if ((breakIndex < (data->mNumBreaks - 1)) && (data->mBreaks[breakIndex] < end)) {
++breakIndex;
numChars = PR_MIN(data->mBreaks[breakIndex] - start, (PRInt32)aSubstringLength);
numChars = PR_MIN(data->mBreaks[breakIndex], end) - start;
}
else {
NS_ASSERTION(i != data->mBreaks[breakIndex], "don't expect to be at segment boundary");
NS_ASSERTION(end != data->mBreaks[breakIndex], "don't expect to be at segment boundary");
// The text is all within the same segment
numChars = i - start;
numChars = end - start;
// Remember we're in the middle of a segment and not between
// two segments
@ -4469,17 +4469,15 @@ do_BreakGetTextDimensions(const nsFontSwitchGTK *aFontSwitch,
// We can't just revert to the previous break state. Find the break
// index just before the end of the text
i = start + numChars;
if (breakIndex == -1) {
breakIndex = 0;
if (data->mBreaks[breakIndex] < i) {
while ((breakIndex + 1 < data->mNumBreaks) && (data->mBreaks[breakIndex + 1] < i)) {
++breakIndex;
}
end = start + numChars;
breakIndex = 0;
if (data->mBreaks[breakIndex] < end) {
while ((breakIndex + 1 < data->mNumBreaks) && (data->mBreaks[breakIndex + 1] < end)) {
++breakIndex;
}
}
if ((0 == breakIndex) && (i <= data->mBreaks[0])) {
if ((0 == breakIndex) && (end <= data->mBreaks[0])) {
// There's no place to back up to, so even though the text doesn't fit
// return it anyway
numCharsFit += numChars;
@ -4508,21 +4506,52 @@ do_BreakGetTextDimensions(const nsFontSwitchGTK *aFontSwitch,
// all the way back to the first word
width += twWidth;
while ((breakIndex >= 0) && (width > data->mAvailWidth)) {
twWidth = 0;
start = data->mBreaks[breakIndex];
numChars = i - start;
numChars = end - start;
numCharsFit = start;
if ((1 == numChars) && (pstr[start] == ' ')) {
twWidth = data->mSpaceWidth;
width -= data->mSpaceWidth;
}
else if (numChars > 0) {
else if (pstr + start >= aSubstring) {
// The entire fragment to chop is within the current font.
pxWidth = fontGTK->GetWidth(&pstr[start], numChars);
twWidth = NSToCoordRound(float(pxWidth) * data->mP2T);
width -= NSToCoordRound(float(pxWidth) * data->mP2T);
}
else {
// The fragment that we want to chop extends back into previous fonts.
// We need to reverse into previous fonts. Fortunately,
// data->mFonts[] and data->mOffsets[] tell us which fonts are used
// and when.
end = data->mNumCharsFit; // same as aSubstring - pstr
data->mNumCharsFit = numCharsFit; // has got shorter...
PRInt32 k = data->mFonts->Count() - 1;
for ( ; k >= 0 && start < end; --k, end -= numChars) {
fontGTK = (nsFontGTK*)data->mFonts->ElementAt(k);
const PRUnichar* ps = (const PRUnichar*)data->mOffsets->ElementAt(k);
if (ps < pstr + start)
ps = pstr + start;
numChars = pstr + end - ps;
NS_ASSERTION(numChars > 0, "empty string");
pxWidth = fontGTK->GetWidth(ps, numChars);
data->mWidth -= NSToCoordRound(float(pxWidth) * data->mP2T);
// By construction, mFonts[k] is the last font, and
// mOffsets[k+1] is the last offset.
data->mFonts->RemoveElementAt(k);
data->mOffsets->RemoveElementAt(k+1);
}
// We are done, update the data now because we won't do it later.
// The |if (data->mNumCharsFit != numCharsFit)| won't apply below
data->mFonts->AppendElement(fontGTK);
data->mOffsets->AppendElement((void*)&pstr[numCharsFit]);
break;
}
width -= twWidth;
numCharsFit = start;
--breakIndex;
i = start;
end = start;
}
}
@ -4530,7 +4559,7 @@ do_BreakGetTextDimensions(const nsFontSwitchGTK *aFontSwitch,
}
#ifdef DEBUG_rbs
NS_ASSERTION(allDone || start == i, "internal error");
NS_ASSERTION(allDone || start == end, "internal error");
NS_ASSERTION(allDone || data->mNumCharsFit != numCharsFit, "internal error");
#endif /* DEBUG_rbs */

Просмотреть файл

@ -1464,7 +1464,7 @@ struct BreakGetTextDimensionsData {
// Remember the fonts that we use so that we can deal with
// line-breaking in-between fonts later. mOffsets[0] is also used
// to initialize the current offset from where to start measuring
nsVoidArray* mFonts; // OUT
nsVoidArray* mFonts; // IN/OUT
nsVoidArray* mOffsets; // IN/OUT
};
@ -1500,10 +1500,10 @@ do_BreakGetTextDimensions(const nsFontSwitch* aFontSwitch,
PRInt32 numCharsFit = data->mNumCharsFit;
nscoord width = data->mWidth;
PRInt32 start = (PRInt32)(aSubstring - pstr);
PRInt32 i = start + aSubstringLength;
PRInt32 end = start + aSubstringLength;
PRBool allDone = PR_FALSE;
while (start < i) {
while (start < end) {
// Estimate how many characters will fit. Do that by dividing the
// available space by the average character width
PRInt32 estimatedNumChars = data->mEstimatedNumChars;
@ -1523,9 +1523,9 @@ do_BreakGetTextDimensions(const nsFontSwitch* aFontSwitch,
// Avoid scanning the break array in the case where we think all
// the text should fit
if (i <= estimatedBreakOffset) {
if (end <= estimatedBreakOffset) {
// Everything should fit
numChars = i - start;
numChars = end - start;
}
else {
// Find the nearest place to break that is less than or equal to
@ -1545,20 +1545,20 @@ do_BreakGetTextDimensions(const nsFontSwitch* aFontSwitch,
if (start < data->mBreaks[breakIndex]) {
// The text crosses at least one segment boundary so measure to the
// break point just before the estimated break offset
numChars = PR_MIN(data->mBreaks[breakIndex] - start, (PRInt32)aSubstringLength);
numChars = PR_MIN(data->mBreaks[breakIndex], end) - start;
}
else {
// See whether there is another segment boundary between this one
// and the end of the text
if ((breakIndex < (data->mNumBreaks - 1)) && (data->mBreaks[breakIndex] < i)) {
if ((breakIndex < (data->mNumBreaks - 1)) && (data->mBreaks[breakIndex] < end)) {
++breakIndex;
numChars = PR_MIN(data->mBreaks[breakIndex] - start, (PRInt32)aSubstringLength);
numChars = PR_MIN(data->mBreaks[breakIndex], end) - start;
}
else {
NS_ASSERTION(i != data->mBreaks[breakIndex], "don't expect to be at segment boundary");
NS_ASSERTION(end != data->mBreaks[breakIndex], "don't expect to be at segment boundary");
// The text is all within the same segment
numChars = i - start;
numChars = end - start;
// Remember we're in the middle of a segment and not between
// two segments
@ -1622,17 +1622,15 @@ do_BreakGetTextDimensions(const nsFontSwitch* aFontSwitch,
// We can't just revert to the previous break state. Find the break
// index just before the end of the text
i = start + numChars;
if (breakIndex == -1) {
breakIndex = 0;
if (data->mBreaks[breakIndex] < i) {
while ((breakIndex + 1 < data->mNumBreaks) && (data->mBreaks[breakIndex + 1] < i)) {
++breakIndex;
}
end = start + numChars;
breakIndex = 0;
if (data->mBreaks[breakIndex] < end) {
while ((breakIndex + 1 < data->mNumBreaks) && (data->mBreaks[breakIndex + 1] < end)) {
++breakIndex;
}
}
if ((0 == breakIndex) && (i <= data->mBreaks[0])) {
if ((0 == breakIndex) && (end <= data->mBreaks[0])) {
// There's no place to back up to, so even though the text doesn't fit
// return it anyway
numCharsFit += numChars;
@ -1661,21 +1659,54 @@ do_BreakGetTextDimensions(const nsFontSwitch* aFontSwitch,
// all the way back to the first word
width += twWidth;
while ((breakIndex >= 0) && (width > data->mAvailWidth)) {
twWidth = 0;
start = data->mBreaks[breakIndex];
numChars = i - start;
numChars = end - start;
numCharsFit = start;
if ((1 == numChars) && (pstr[start] == ' ')) {
twWidth = data->mSpaceWidth;
width -= data->mSpaceWidth;
}
else if (numChars > 0) {
else if (pstr + start >= aSubstring) {
// The entire fragment to chop is within the current font.
pxWidth = font->GetWidth(data->mPS, &pstr[start], numChars);
twWidth = NSToCoordRound(float(pxWidth) * data->mP2T);
width -= NSToCoordRound(float(pxWidth) * data->mP2T);
}
else {
// The fragment that we want to chop extends back into previous fonts.
// We need to reverse into previous fonts. Fortunately,
// data->mFonts[] and data->mOffsets[] tell us which fonts are used
// and when.
end = data->mNumCharsFit; // same as aSubstring - pstr
data->mNumCharsFit = numCharsFit; // has got shorter...
PRInt32 k = data->mFonts->Count() - 1;
for ( ; k >= 0 && start < end; --k, end -= numChars) {
font = (nsFontOS2*)data->mFonts->ElementAt(k);
const PRUnichar* ps = (const PRUnichar*)data->mOffsets->ElementAt(k);
if (ps < pstr + start)
ps = pstr + start;
numChars = pstr + end - ps;
NS_ASSERTION(numChars > 0, "empty string");
data->mFont = font;
data->mSurface->SelectFont(data->mFont);
pxWidth = font->GetWidth(data->mPS, ps, numChars);
data->mWidth -= NSToCoordRound(float(pxWidth) * data->mP2T);
// By construction, mFonts[k] is the last font, and
// mOffsets[k+1] is the last offset.
data->mFonts->RemoveElementAt(k);
data->mOffsets->RemoveElementAt(k+1);
}
// We are done, update the data now because we won't do it later.
// The |if (data->mNumCharsFit != numCharsFit)| won't apply below
data->mFonts->AppendElement(fontWin);
data->mOffsets->AppendElement((void*)&pstr[numCharsFit]);
break;
}
width -= twWidth;
numCharsFit = start;
--breakIndex;
i = start;
end = start;
}
}
@ -1683,7 +1714,7 @@ do_BreakGetTextDimensions(const nsFontSwitch* aFontSwitch,
}
#ifdef DEBUG_rbs
NS_ASSERTION(allDone || start == i, "internal error");
NS_ASSERTION(allDone || start == end, "internal error");
NS_ASSERTION(allDone || data->mNumCharsFit != numCharsFit, "internal error");
#endif /* DEBUG_rbs */

Просмотреть файл

@ -4221,6 +4221,32 @@ nsFontWin::GetBoundingMetrics(HDC aDC,
}
#endif
#ifdef DEBUG
static void
VerifyFontHasGlyph(nsFontWin* aFont, const PRUnichar* aString, PRInt32 aLength)
{
const PRUnichar* curr = aString;
const PRUnichar* last = aString + aLength;
PRUint32 ch;
while (curr < last) {
if (IS_HIGH_SURROGATE(*curr) && (curr+1) < last &&
IS_LOW_SURROGATE(*(curr+1))) {
ch = SURROGATE_TO_UCS4(*curr, *(curr+1));
curr += 2;
}
else {
ch = *curr;
curr += 1;
}
NS_ASSERTION(aFont->HasGlyph(ch), "internal error");
}
}
#define DEBUG_VERIFY_FONT_HASGLYPH(font, string, length) \
VerifyFontHasGlyph(font, string, length)
#else
#define DEBUG_VERIFY_FONT_HASGLYPH(font, string, length)
#endif
nsFontWinUnicode::nsFontWinUnicode(LOGFONT* aLogFont, HFONT aFont,
PRUint16* aCCMap) : nsFontWin(aLogFont, aFont, aCCMap)
{
@ -4238,6 +4264,7 @@ nsFontWinUnicode::~nsFontWinUnicode()
PRInt32
nsFontWinUnicode::GetWidth(HDC aDC, const PRUnichar* aString, PRUint32 aLength)
{
DEBUG_VERIFY_FONT_HASGLYPH(this, aString, aLength);
SIZE size;
::GetTextExtentPoint32W(aDC, aString, aLength, &size);
size.cx -= mOverhangCorrection;
@ -4248,6 +4275,7 @@ void
nsFontWinUnicode::DrawString(HDC aDC, PRInt32 aX, PRInt32 aY,
const PRUnichar* aString, PRUint32 aLength)
{
DEBUG_VERIFY_FONT_HASGLYPH(this, aString, aLength);
// Due to a bug in WIN95 unicode rendering of truetype fonts
// with underline or strikeout, we need to set a clip rect
// to prevent the underline and/or strikethru from being rendered
@ -4288,6 +4316,7 @@ nsFontWinUnicode::GetBoundingMetrics(HDC aDC,
PRUint32 aLength,
nsBoundingMetrics& aBoundingMetrics)
{
DEBUG_VERIFY_FONT_HASGLYPH(this, aString, aLength);
aBoundingMetrics.Clear();
nsAutoChar16Buffer buffer;
@ -4331,6 +4360,7 @@ PRInt32
nsFontWinNonUnicode::GetWidth(HDC aDC, const PRUnichar* aString,
PRUint32 aLength)
{
DEBUG_VERIFY_FONT_HASGLYPH(this, aString, aLength);
nsAutoCharBuffer buffer;
PRInt32 destLength = aLength;
@ -4353,6 +4383,7 @@ void
nsFontWinNonUnicode::DrawString(HDC aDC, PRInt32 aX, PRInt32 aY,
const PRUnichar* aString, PRUint32 aLength)
{
DEBUG_VERIFY_FONT_HASGLYPH(this, aString, aLength);
nsAutoCharBuffer buffer;
PRInt32 destLength = aLength;
@ -4374,6 +4405,7 @@ nsFontWinNonUnicode::GetBoundingMetrics(HDC aDC,
PRUint32 aLength,
nsBoundingMetrics& aBoundingMetrics)
{
DEBUG_VERIFY_FONT_HASGLYPH(this, aString, aLength);
aBoundingMetrics.Clear();
nsAutoCharBuffer buffer;
PRInt32 destLength = aLength;

Просмотреть файл

@ -1697,7 +1697,7 @@ struct BreakGetTextDimensionsData {
// Remember the fonts that we use so that we can deal with
// line-breaking in-between fonts later. mOffsets[0] is also used
// to initialize the current offset from where to start measuring
nsVoidArray* mFonts; // OUT
nsVoidArray* mFonts; // IN/OUT
nsVoidArray* mOffsets; // IN/OUT
};
@ -1723,10 +1723,10 @@ do_BreakGetTextDimensions(const nsFontSwitch* aFontSwitch,
PRInt32 numCharsFit = data->mNumCharsFit;
nscoord width = data->mWidth;
PRInt32 start = (PRInt32)(aSubstring - pstr);
PRInt32 i = start + aSubstringLength;
PRInt32 end = start + aSubstringLength;
PRBool allDone = PR_FALSE;
while (start < i) {
while (start < end) {
// Estimate how many characters will fit. Do that by dividing the
// available space by the average character width
PRInt32 estimatedNumChars = data->mEstimatedNumChars;
@ -1746,9 +1746,9 @@ do_BreakGetTextDimensions(const nsFontSwitch* aFontSwitch,
// Avoid scanning the break array in the case where we think all
// the text should fit
if (i <= estimatedBreakOffset) {
if (end <= estimatedBreakOffset) {
// Everything should fit
numChars = i - start;
numChars = end - start;
}
else {
// Find the nearest place to break that is less than or equal to
@ -1768,20 +1768,20 @@ do_BreakGetTextDimensions(const nsFontSwitch* aFontSwitch,
if (start < data->mBreaks[breakIndex]) {
// The text crosses at least one segment boundary so measure to the
// break point just before the estimated break offset
numChars = PR_MIN(data->mBreaks[breakIndex] - start, (PRInt32)aSubstringLength);
numChars = PR_MIN(data->mBreaks[breakIndex], end) - start;
}
else {
// See whether there is another segment boundary between this one
// and the end of the text
if ((breakIndex < (data->mNumBreaks - 1)) && (data->mBreaks[breakIndex] < i)) {
if ((breakIndex < (data->mNumBreaks - 1)) && (data->mBreaks[breakIndex] < end)) {
++breakIndex;
numChars = PR_MIN(data->mBreaks[breakIndex] - start, (PRInt32)aSubstringLength);
numChars = PR_MIN(data->mBreaks[breakIndex], end) - start;
}
else {
NS_ASSERTION(i != data->mBreaks[breakIndex], "don't expect to be at segment boundary");
NS_ASSERTION(end != data->mBreaks[breakIndex], "don't expect to be at segment boundary");
// The text is all within the same segment
numChars = i - start;
numChars = end - start;
// Remember we're in the middle of a segment and not between
// two segments
@ -1845,17 +1845,15 @@ do_BreakGetTextDimensions(const nsFontSwitch* aFontSwitch,
// We can't just revert to the previous break state. Find the break
// index just before the end of the text
i = start + numChars;
if (breakIndex == -1) {
breakIndex = 0;
if (data->mBreaks[breakIndex] < i) {
while ((breakIndex + 1 < data->mNumBreaks) && (data->mBreaks[breakIndex + 1] < i)) {
++breakIndex;
}
end = start + numChars;
breakIndex = 0;
if (data->mBreaks[breakIndex] < end) {
while ((breakIndex + 1 < data->mNumBreaks) && (data->mBreaks[breakIndex + 1] < end)) {
++breakIndex;
}
}
if ((0 == breakIndex) && (i <= data->mBreaks[0])) {
if ((0 == breakIndex) && (end <= data->mBreaks[0])) {
// There's no place to back up to, so even though the text doesn't fit
// return it anyway
numCharsFit += numChars;
@ -1884,21 +1882,54 @@ do_BreakGetTextDimensions(const nsFontSwitch* aFontSwitch,
// all the way back to the first word
width += twWidth;
while ((breakIndex >= 0) && (width > data->mAvailWidth)) {
twWidth = 0;
start = data->mBreaks[breakIndex];
numChars = i - start;
numChars = end - start;
numCharsFit = start;
if ((1 == numChars) && (pstr[start] == ' ')) {
twWidth = data->mSpaceWidth;
width -= data->mSpaceWidth;
}
else if (numChars > 0) {
else if (pstr + start >= aSubstring) {
// The entire fragment to chop is within the current font.
pxWidth = fontWin->GetWidth(data->mDC, &pstr[start], numChars);
twWidth = NSToCoordRound(float(pxWidth) * data->mP2T);
width -= NSToCoordRound(float(pxWidth) * data->mP2T);
}
else {
// The fragment that we want to chop extends back into previous fonts.
// We need to reverse into previous fonts. Fortunately,
// data->mFonts[] and data->mOffsets[] tell us which fonts are used
// and when.
end = data->mNumCharsFit; // same as aSubstring - pstr
data->mNumCharsFit = numCharsFit; // has got shorter...
PRInt32 k = data->mFonts->Count() - 1;
for ( ; k >= 0 && start < end; --k, end -= numChars) {
fontWin = (nsFontWin*)data->mFonts->ElementAt(k);
const PRUnichar* ps = (const PRUnichar*)data->mOffsets->ElementAt(k);
if (ps < pstr + start)
ps = pstr + start;
numChars = pstr + end - ps;
NS_ASSERTION(numChars > 0, "empty string");
data->mFont = fontWin->mFont;
::SelectObject(data->mDC, data->mFont);
pxWidth = fontWin->GetWidth(data->mDC, ps, numChars);
data->mWidth -= NSToCoordRound(float(pxWidth) * data->mP2T);
// By construction, mFonts[k] is the last font, and
// mOffsets[k+1] is the last offset.
data->mFonts->RemoveElementAt(k);
data->mOffsets->RemoveElementAt(k+1);
}
// We are done, update the data now because we won't do it later.
// The |if (data->mNumCharsFit != numCharsFit)| won't apply below
data->mFonts->AppendElement(fontWin);
data->mOffsets->AppendElement((void*)&pstr[numCharsFit]);
break;
}
width -= twWidth;
numCharsFit = start;
--breakIndex;
i = start;
end = start;
}
}
@ -1906,7 +1937,7 @@ do_BreakGetTextDimensions(const nsFontSwitch* aFontSwitch,
}
#ifdef DEBUG_rbs
NS_ASSERTION(allDone || start == i, "internal error");
NS_ASSERTION(allDone || start == end, "internal error");
NS_ASSERTION(allDone || data->mNumCharsFit != numCharsFit, "internal error");
#endif /* DEBUG_rbs */

Просмотреть файл

@ -1577,7 +1577,7 @@ struct BreakGetTextDimensionsData {
// Remember the fonts that we use so that we can deal with
// line-breaking in-between fonts later. mOffsets[0] is also used
// to initialize the current offset from where to start measuring
nsVoidArray* mFonts; // OUT
nsVoidArray* mFonts; // IN/OUT
nsVoidArray* mOffsets; // IN/OUT
};
@ -1598,10 +1598,10 @@ do_BreakGetTextDimensions(const nsFontSwitchXlib *aFontSwitch,
PRInt32 numCharsFit = data->mNumCharsFit;
nscoord width = data->mWidth;
PRInt32 start = (PRInt32)(aSubstring - pstr);
PRInt32 i = start + aSubstringLength;
PRInt32 end = start + aSubstringLength;
PRBool allDone = PR_FALSE;
while (start < i) {
while (start < end) {
// Estimate how many characters will fit. Do that by dividing the
// available space by the average character width
PRInt32 estimatedNumChars = data->mEstimatedNumChars;
@ -1621,9 +1621,9 @@ do_BreakGetTextDimensions(const nsFontSwitchXlib *aFontSwitch,
// Avoid scanning the break array in the case where we think all
// the text should fit
if (i <= estimatedBreakOffset) {
if (end <= estimatedBreakOffset) {
// Everything should fit
numChars = i - start;
numChars = end - start;
}
else {
// Find the nearest place to break that is less than or equal to
@ -1643,20 +1643,20 @@ do_BreakGetTextDimensions(const nsFontSwitchXlib *aFontSwitch,
if (start < data->mBreaks[breakIndex]) {
// The text crosses at least one segment boundary so measure to the
// break point just before the estimated break offset
numChars = PR_MIN(data->mBreaks[breakIndex] - start, (PRInt32)aSubstringLength);
numChars = PR_MIN(data->mBreaks[breakIndex], end) - start;
}
else {
// See whether there is another segment boundary between this one
// and the end of the text
if ((breakIndex < (data->mNumBreaks - 1)) && (data->mBreaks[breakIndex] < i)) {
if ((breakIndex < (data->mNumBreaks - 1)) && (data->mBreaks[breakIndex] < end)) {
++breakIndex;
numChars = PR_MIN(data->mBreaks[breakIndex] - start, (PRInt32)aSubstringLength);
numChars = PR_MIN(data->mBreaks[breakIndex], end) - start;
}
else {
NS_ASSERTION(i != data->mBreaks[breakIndex], "don't expect to be at segment boundary");
NS_ASSERTION(end != data->mBreaks[breakIndex], "don't expect to be at segment boundary");
// The text is all within the same segment
numChars = i - start;
numChars = end - start;
// Remember we're in the middle of a segment and not between
// two segments
@ -1720,17 +1720,15 @@ do_BreakGetTextDimensions(const nsFontSwitchXlib *aFontSwitch,
// We can't just revert to the previous break state. Find the break
// index just before the end of the text
i = start + numChars;
if (breakIndex == -1) {
breakIndex = 0;
if (data->mBreaks[breakIndex] < i) {
while ((breakIndex + 1 < data->mNumBreaks) && (data->mBreaks[breakIndex + 1] < i)) {
++breakIndex;
}
end = start + numChars;
breakIndex = 0;
if (data->mBreaks[breakIndex] < end) {
while ((breakIndex + 1 < data->mNumBreaks) && (data->mBreaks[breakIndex + 1] < end)) {
++breakIndex;
}
}
if ((0 == breakIndex) && (i <= data->mBreaks[0])) {
if ((0 == breakIndex) && (end <= data->mBreaks[0])) {
// There's no place to back up to, so even though the text doesn't fit
// return it anyway
numCharsFit += numChars;
@ -1759,21 +1757,52 @@ do_BreakGetTextDimensions(const nsFontSwitchXlib *aFontSwitch,
// all the way back to the first word
width += twWidth;
while ((breakIndex >= 0) && (width > data->mAvailWidth)) {
twWidth = 0;
start = data->mBreaks[breakIndex];
numChars = i - start;
numChars = end - start;
numCharsFit = start;
if ((1 == numChars) && (pstr[start] == ' ')) {
twWidth = data->mSpaceWidth;
width -= data->mSpaceWidth;
}
else if (numChars > 0) {
else if (pstr + start >= aSubstring) {
// The entire fragment to chop is within the current font.
pxWidth = fontXlib->GetWidth(&pstr[start], numChars);
twWidth = NSToCoordRound(float(pxWidth) * data->mP2T);
width -= NSToCoordRound(float(pxWidth) * data->mP2T);
}
else {
// The fragment that we want to chop extends back into previous fonts.
// We need to reverse into previous fonts. Fortunately,
// data->mFonts[] and data->mOffsets[] tell us which fonts are used
// and when.
end = data->mNumCharsFit; // same as aSubstring - pstr
data->mNumCharsFit = numCharsFit; // has got shorter...
PRInt32 k = data->mFonts->Count() - 1;
for ( ; k >= 0 && start < end; --k, end -= numChars) {
fontXlib = (nsFontXlib*)data->mFonts->ElementAt(k);
const PRUnichar* ps = (const PRUnichar*)data->mOffsets->ElementAt(k);
if (ps < pstr + start)
ps = pstr + start;
numChars = pstr + end - ps;
NS_ASSERTION(numChars > 0, "empty string");
pxWidth = fontXlib->GetWidth(ps, numChars);
data->mWidth -= NSToCoordRound(float(pxWidth) * data->mP2T);
// By construction, mFonts[k] is the last font, and
// mOffsets[k+1] is the last offset.
data->mFonts->RemoveElementAt(k);
data->mOffsets->RemoveElementAt(k+1);
}
// We are done, update the data now because we won't do it later.
// The |if (data->mNumCharsFit != numCharsFit)| won't apply below
data->mFonts->AppendElement(fontXlib);
data->mOffsets->AppendElement((void*)&pstr[numCharsFit]);
break;
}
width -= twWidth;
numCharsFit = start;
--breakIndex;
i = start;
end = start;
}
}
@ -1781,7 +1810,7 @@ do_BreakGetTextDimensions(const nsFontSwitchXlib *aFontSwitch,
}
#ifdef DEBUG_rbs
NS_ASSERTION(allDone || start == i, "internal error");
NS_ASSERTION(allDone || start == end, "internal error");
NS_ASSERTION(allDone || data->mNumCharsFit != numCharsFit, "internal error");
#endif /* DEBUG_rbs */