зеркало из https://github.com/mozilla/pjs.git
bug 38387; add optimized GetWidth method to Japanese Windows 95-specific
subclass nsRenderingContextWinA to allow proper layout on Win95-J; a,r=kmcclusk
This commit is contained in:
Родитель
cbfbd753fe
Коммит
d8caf32f9e
|
@ -3305,6 +3305,296 @@ FoundFont:
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsRenderingContextWinA::GetWidth(const PRUnichar *aString,
|
||||
PRInt32 aLength,
|
||||
PRInt32 aAvailWidth,
|
||||
PRInt32* aBreaks,
|
||||
PRInt32 aNumBreaks,
|
||||
nscoord& aWidth,
|
||||
PRInt32& aNumCharsFit,
|
||||
PRInt32* aFontID)
|
||||
{
|
||||
NS_PRECONDITION(aBreaks[aNumBreaks - 1] == aLength, "invalid break array");
|
||||
|
||||
if (nsnull != mFontMetrics) {
|
||||
// If we need to back up this state represents the last place we could
|
||||
// break. We can use this to avoid remeasuring text
|
||||
struct PrevBreakState {
|
||||
PRInt32 mBreakIndex;
|
||||
nscoord mWidth;
|
||||
|
||||
PrevBreakState() {
|
||||
mBreakIndex = -1; // not known (hasn't been computed)
|
||||
mWidth = 0;
|
||||
}
|
||||
};
|
||||
|
||||
PRUnichar* pstr = (PRUnichar *)(const PRUnichar *)aString;
|
||||
nsFontMetricsWinA* metrics = (nsFontMetricsWinA*) mFontMetrics;
|
||||
nsFontSubset* prevFont = nsnull;
|
||||
PrevBreakState prevBreakState;
|
||||
|
||||
// Initialize OUT parameter
|
||||
aNumCharsFit = 0;
|
||||
|
||||
// Setup the font and foreground color
|
||||
SetupFontAndColor();
|
||||
|
||||
// Iterate each character in the string and determine which font to use
|
||||
HFONT selectedFont = mCurrFont;
|
||||
nscoord width = 0;
|
||||
PRInt32 start = 0;
|
||||
PRInt32 i = 0;
|
||||
PRBool allDone = PR_FALSE;
|
||||
while (!allDone) {
|
||||
nsFontSubset* currFont = nsnull;
|
||||
nsFontMetricsWinA* fontMetricsWin;
|
||||
nscoord aveCharWidth;
|
||||
|
||||
// First search the fonts we already have loaded
|
||||
nsFontWinA** font = (nsFontWinA**) metrics->mLoadedFonts;
|
||||
nsFontWinA** end = (nsFontWinA**) &metrics->mLoadedFonts[metrics->mLoadedFontsCount];
|
||||
while (font < end) {
|
||||
if (FONT_HAS_GLYPH((*font)->mMap, pstr[i])) {
|
||||
nsFontSubset** subset = (*font)->mSubsets;
|
||||
nsFontSubset** endSubsets = &((*font)->mSubsets[(*font)->mSubsetsCount]);
|
||||
while (subset < endSubsets) {
|
||||
if (!(*subset)->mMap) {
|
||||
if (!(*subset)->Load(*font)) {
|
||||
subset++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (FONT_HAS_GLYPH((*subset)->mMap, pstr[i])) {
|
||||
currFont = *subset;
|
||||
goto FoundFont;
|
||||
}
|
||||
subset++;
|
||||
}
|
||||
}
|
||||
font++; // try the next font
|
||||
}
|
||||
|
||||
// No match in the already loaded fonts. Find a new font
|
||||
currFont = (nsFontSubset*) metrics->FindFont(mDC, pstr[i]);
|
||||
|
||||
FoundFont:
|
||||
// See if this is the same font we found for the previous character.
|
||||
// If so, then keep accumulating characters
|
||||
if (prevFont) {
|
||||
if (currFont != prevFont) {
|
||||
// The font has changed. We need to measure the existing text using
|
||||
// the previous font
|
||||
goto MeasureText;
|
||||
}
|
||||
}
|
||||
else {
|
||||
prevFont = currFont; // remember this font
|
||||
}
|
||||
|
||||
// Advance to the next character
|
||||
if (++i >= aLength) {
|
||||
allDone = PR_TRUE;
|
||||
goto MeasureText; // measure any remaining text
|
||||
}
|
||||
continue;
|
||||
|
||||
MeasureText:
|
||||
// Make sure the font is selected
|
||||
if (prevFont->mFont != selectedFont) {
|
||||
::SelectObject(mDC, prevFont->mFont);
|
||||
selectedFont = prevFont->mFont;
|
||||
}
|
||||
|
||||
// Get the average character width
|
||||
fontMetricsWin = (nsFontMetricsWinA*)mFontMetrics;
|
||||
fontMetricsWin->GetAveCharWidth(aveCharWidth);
|
||||
while (start < i) {
|
||||
// Estimate how many characters will fit. Do that by diving the available
|
||||
// space by the average character width
|
||||
PRInt32 estimatedNumChars = (aAvailWidth - width) / aveCharWidth;
|
||||
|
||||
// Make sure the estimated number of characters is at least 1
|
||||
if (estimatedNumChars < 1) {
|
||||
estimatedNumChars = 1;
|
||||
}
|
||||
|
||||
// Find the nearest break offset
|
||||
PRInt32 estimatedBreakOffset = start + estimatedNumChars;
|
||||
PRInt32 breakIndex = -1; // not computed
|
||||
PRBool inMiddleOfSegment = PR_FALSE;
|
||||
nscoord numChars;
|
||||
|
||||
// Avoid scanning the break array in the case where we think all
|
||||
// the text should fit
|
||||
if (i <= estimatedBreakOffset) {
|
||||
// Everything should fit
|
||||
numChars = i - start;
|
||||
|
||||
} else {
|
||||
// Find the nearest place to break that is less than or equal to
|
||||
// the estimated break offset
|
||||
breakIndex = prevBreakState.mBreakIndex;
|
||||
while (aBreaks[breakIndex + 1] <= estimatedBreakOffset) {
|
||||
breakIndex++;
|
||||
}
|
||||
NS_ASSERTION(aBreaks[breakIndex] <= estimatedBreakOffset, "bad break index");
|
||||
|
||||
// We found a place to break that is before the estimated break
|
||||
// offset. Where we break depends on whether the text crosses a
|
||||
// segment boundary
|
||||
if (start < aBreaks[breakIndex]) {
|
||||
// The text crosses at least one segment boundary so measure to the
|
||||
// break point just before the estimated break offset
|
||||
numChars = aBreaks[breakIndex] - start;
|
||||
|
||||
} else {
|
||||
// See whether there is another segment boundary between this one
|
||||
// and the end of the text
|
||||
if ((breakIndex < (aNumBreaks - 1)) && (aBreaks[breakIndex] < i)) {
|
||||
breakIndex++;
|
||||
numChars = aBreaks[breakIndex] - start;
|
||||
|
||||
} else {
|
||||
NS_ASSERTION(i != aBreaks[breakIndex], "don't expect to be at segment boundary");
|
||||
|
||||
// The text is all within the same segment
|
||||
numChars = i - start;
|
||||
|
||||
// Remember we're in the middle of a segment and not in between
|
||||
// two segments
|
||||
inMiddleOfSegment = PR_TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Measure the text
|
||||
PRInt32 pxWidth;
|
||||
nscoord twWidth;
|
||||
if ((1 == numChars) && (pstr[start] == ' ')) {
|
||||
fontMetricsWin->GetSpaceWidth(twWidth);
|
||||
|
||||
} else {
|
||||
pxWidth = prevFont->GetWidth(mDC, &pstr[start], numChars);
|
||||
twWidth = NSToCoordRound(float(pxWidth) * mP2T);
|
||||
}
|
||||
|
||||
// See if the text fits
|
||||
PRBool textFits = (twWidth + width) <= aAvailWidth;
|
||||
|
||||
// If the text fits then update the width and the number of
|
||||
// characters that fit
|
||||
if (textFits) {
|
||||
aNumCharsFit += numChars;
|
||||
width += twWidth;
|
||||
|
||||
// If we computed the break index and we're not in the middle
|
||||
// of a segment then this is a spot that we can back up to if
|
||||
// we need to so remember this state
|
||||
if ((breakIndex != -1) && !inMiddleOfSegment) {
|
||||
prevBreakState.mBreakIndex = breakIndex;
|
||||
prevBreakState.mWidth = width;
|
||||
}
|
||||
|
||||
} else {
|
||||
// The text didn't fit. If we're out of room then we're all done
|
||||
allDone = PR_TRUE;
|
||||
|
||||
// See if we can just back up to the previous saved state and not
|
||||
// have to measure any text
|
||||
if (prevBreakState.mBreakIndex != -1) {
|
||||
PRBool canBackup;
|
||||
|
||||
// If we're in the middle of a word then the break index
|
||||
// must be the same if we can use it. If we're at a segment
|
||||
// boundary, then if the saved state is for the previous
|
||||
// break index then we can use it
|
||||
if (inMiddleOfSegment) {
|
||||
canBackup = prevBreakState.mBreakIndex == breakIndex;
|
||||
} else {
|
||||
canBackup = prevBreakState.mBreakIndex == (breakIndex - 1);
|
||||
}
|
||||
|
||||
if (canBackup) {
|
||||
aNumCharsFit = aBreaks[prevBreakState.mBreakIndex];
|
||||
width = prevBreakState.mWidth;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
while (aBreaks[breakIndex + 1] < i) {
|
||||
breakIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
if ((0 == breakIndex) && (i <= aBreaks[0])) {
|
||||
// There's no place to back up to so even though the text doesn't fit
|
||||
// return it anyway
|
||||
aNumCharsFit += numChars;
|
||||
width += twWidth;
|
||||
break;
|
||||
}
|
||||
|
||||
// Repeatedly back up until we get to where the text fits or we're
|
||||
// all the way back to the first word
|
||||
width += twWidth;
|
||||
while ((breakIndex >= 0) && (width > aAvailWidth)) {
|
||||
start = aBreaks[breakIndex];
|
||||
numChars = i - start;
|
||||
if ((1 == numChars) && (pstr[start] == ' ')) {
|
||||
fontMetricsWin->GetSpaceWidth(twWidth);
|
||||
|
||||
} else {
|
||||
pxWidth = prevFont->GetWidth(mDC, &pstr[start], numChars);
|
||||
twWidth = NSToCoordRound(float(pxWidth) * mP2T);
|
||||
}
|
||||
|
||||
width -= twWidth;
|
||||
aNumCharsFit = start;
|
||||
breakIndex--;
|
||||
i = start;
|
||||
}
|
||||
}
|
||||
|
||||
start += numChars;
|
||||
}
|
||||
|
||||
// We're done measuring that run
|
||||
if (!allDone) {
|
||||
prevFont = currFont;
|
||||
NS_ASSERTION(start == i, "internal error");
|
||||
|
||||
// Advance to the next character
|
||||
if (++i >= aLength) {
|
||||
allDone = PR_TRUE;
|
||||
goto MeasureText;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
aWidth = width;
|
||||
|
||||
if (selectedFont != mCurrFont) {
|
||||
// Restore the font
|
||||
::SelectObject(mDC, mCurrFont);
|
||||
}
|
||||
|
||||
if (nsnull != aFontID) {
|
||||
*aFontID = 0;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsRenderingContextWinA :: DrawString(const PRUnichar *aString, PRUint32 aLength,
|
||||
nscoord aX, nscoord aY,
|
||||
PRInt32 aFontID,
|
||||
|
|
|
@ -270,6 +270,14 @@ class nsRenderingContextWinA : public nsRenderingContextWin
|
|||
public:
|
||||
NS_IMETHOD GetWidth(const PRUnichar* aString, PRUint32 aLength,
|
||||
nscoord& aWidth, PRInt32 *aFontID);
|
||||
NS_IMETHOD GetWidth(const PRUnichar *aString,
|
||||
PRInt32 aLength,
|
||||
PRInt32 aAvailWidth,
|
||||
PRInt32* aBreaks,
|
||||
PRInt32 aNumBreaks,
|
||||
nscoord& aWidth,
|
||||
PRInt32& aNumCharsFit,
|
||||
PRInt32* aFontID);
|
||||
NS_IMETHOD DrawString(const PRUnichar *aString, PRUint32 aLength,
|
||||
nscoord aX, nscoord aY,
|
||||
PRInt32 aFontID,
|
||||
|
|
Загрузка…
Ссылка в новой задаче