Display one hex box with six digits for non-BMP codepoints with no glyph. Bug 376532, r+sr+a=roc

This commit is contained in:
smontagu@smontagu.org 2007-09-20 03:16:15 -07:00
Родитель 372aa77573
Коммит e011fa00ec
8 изменённых файлов: 99 добавлений и 87 удалений

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

@ -1068,7 +1068,7 @@ public:
*/
void SetDetailedGlyphs(PRUint32 aCharIndex, const DetailedGlyph *aGlyphs,
PRUint32 aNumGlyphs);
void SetMissingGlyph(PRUint32 aCharIndex, PRUnichar aChar);
void SetMissingGlyph(PRUint32 aCharIndex, PRUint32 aChar);
void SetSpaceGlyph(gfxFont *aFont, gfxContext *aContext, PRUint32 aCharIndex);
// API for access to the raw glyph data, needed by gfxFont::Draw

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

@ -693,7 +693,8 @@ SetGlyphsForCharacterGroup(ATSLayoutRecord *aGlyphs, PRUint32 aGlyphCount,
Fixed *aBaselineDeltas, PRUint32 aAppUnitsPerDevUnit,
gfxTextRun *aRun, PRUint32 aSegmentStart,
const PRPackedBool *aUnmatched,
const PRUnichar *aString)
const PRUnichar *aString,
const PRUint32 aLength)
{
NS_ASSERTION(aGlyphCount > 0, "Must set at least one glyph");
PRUint32 firstOffset = aGlyphs[0].originalOffset;
@ -727,7 +728,15 @@ SetGlyphsForCharacterGroup(ATSLayoutRecord *aGlyphs, PRUint32 aGlyphCount,
if (!allMatched) {
for (i = firstOffset; i <= lastOffset; ++i) {
PRUint32 index = i/2;
aRun->SetMissingGlyph(aSegmentStart + index, aString[index]);
if (NS_IS_HIGH_SURROGATE(aString[index]) &&
index + 1 < aLength &&
NS_IS_LOW_SURROGATE(aString[index + 1])) {
aRun->SetMissingGlyph(aSegmentStart + index,
SURROGATE_TO_UCS4(aString[index],
aString[index + 1]));
} else {
aRun->SetMissingGlyph(aSegmentStart + index, aString[index]);
}
}
return;
}
@ -888,12 +897,12 @@ PostLayoutCallback(ATSULineRef aLine, gfxTextRun *aRun,
glyphCount,
baselineDeltas ? baselineDeltas + numGlyphs - glyphCount : nsnull,
appUnitsPerDevUnit, aRun, aSegmentStart,
aUnmatched, aString);
aUnmatched, aString, aSegmentLength);
} else {
SetGlyphsForCharacterGroup(glyphRecords,
glyphCount, baselineDeltas,
appUnitsPerDevUnit, aRun, aSegmentStart,
aUnmatched, aString);
aUnmatched, aString, aSegmentLength);
glyphRecords += glyphCount;
if (baselineDeltas) {
baselineDeltas += glyphCount;

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

@ -1559,7 +1559,7 @@ gfxTextRun::SetDetailedGlyphs(PRUint32 aIndex, const DetailedGlyph *aGlyphs,
}
void
gfxTextRun::SetMissingGlyph(PRUint32 aIndex, PRUnichar aChar)
gfxTextRun::SetMissingGlyph(PRUint32 aIndex, PRUint32 aChar)
{
DetailedGlyph *details = AllocateDetailedGlyphs(aIndex, 1);
if (!details)
@ -1569,7 +1569,7 @@ gfxTextRun::SetMissingGlyph(PRUint32 aIndex, PRUnichar aChar)
details->mGlyphID = aChar;
GlyphRun *glyphRun = &mGlyphRuns[FindFirstGlyphRunContaining(aIndex)];
gfxFloat width = PR_MAX(glyphRun->mFont->GetMetrics().aveCharWidth,
gfxFontMissingGlyphs::GetDesiredMinWidth());
gfxFontMissingGlyphs::GetDesiredMinWidth(aChar));
details->mAdvance = PRUint32(width*GetAppUnitsPerDevUnit());
details->mXOffset = 0;
details->mYOffset = 0;

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

@ -126,22 +126,25 @@ static const PRUint16 glyphMicroFont[16] = {
};
/* Parameters that control the rendering of hexboxes. They look like this:
+---------+
| |
| HHH HHH |
| HHH HHH |
| HHH HHH |
| HHH HHH |
| HHH HHH |
| |
| HHH HHH |
| HHH HHH |
| HHH HHH |
| HHH HHH |
| HHH HHH |
| |
+---------+
BMP codepoints non-BMP codepoints
(U+0000 - U+FFFF) (U+10000 - U+10FFFF)
+---------+ +-------------+
| | | |
| HHH HHH | | HHH HHH HHH |
| HHH HHH | | HHH HHH HHH |
| HHH HHH | | HHH HHH HHH |
| HHH HHH | | HHH HHH HHH |
| HHH HHH | | HHH HHH HHH |
| | | |
| HHH HHH | | HHH HHH HHH |
| HHH HHH | | HHH HHH HHH |
| HHH HHH | | HHH HHH HHH |
| HHH HHH | | HHH HHH HHH |
| HHH HHH | | HHH HHH HHH |
| | | |
+---------+ +-------------+
*/
/** Width of a minifont glyph (see above) */
@ -166,15 +169,6 @@ static const int BOX_BORDER_WIDTH = 1;
* opacity being used to draw the text.
*/
static const gfxFloat BOX_BORDER_OPACITY = 0.5;
/**
* The minimum desired width for a missing-glyph glyph box. I've laid it out
* like this so you can see what goes where.
*/
static const int MIN_DESIRED_WIDTH =
BOX_HORIZONTAL_INSET + BOX_BORDER_WIDTH + HEX_CHAR_GAP +
MINIFONT_WIDTH + HEX_CHAR_GAP + MINIFONT_WIDTH +
HEX_CHAR_GAP + BOX_BORDER_WIDTH + BOX_HORIZONTAL_INSET;
/**
* Draw a single hex character using the current color. A nice way to do this
* would be to fill in an A8 image surface and then use it as a mask
@ -201,7 +195,7 @@ DrawHexChar(gfxContext *aContext, const gfxPoint& aPt, PRUint32 aDigit)
void
gfxFontMissingGlyphs::DrawMissingGlyph(gfxContext *aContext, const gfxRect& aRect,
PRUnichar aChar)
PRUint32 aChar)
{
aContext->Save();
@ -233,29 +227,60 @@ gfxFontMissingGlyphs::DrawMissingGlyph(gfxContext *aContext, const gfxRect& aRec
aContext->Stroke();
}
if (aRect.Width() >= 2*MINIFONT_WIDTH + HEX_CHAR_GAP &&
aRect.Height() >= 2*MINIFONT_HEIGHT + HEX_CHAR_GAP) {
aContext->SetColor(currentColor);
gfxPoint center(aRect.X() + aRect.Width()/2,
aRect.Y() + aRect.Height()/2);
gfxFloat halfGap = HEX_CHAR_GAP/2.0;
gfxFloat left = -(MINIFONT_WIDTH + halfGap);
gfxFloat top = -(MINIFONT_HEIGHT + halfGap);
DrawHexChar(aContext,
center + gfxPoint(left, top), (aChar >> 12) & 0xF);
DrawHexChar(aContext,
center + gfxPoint(halfGap, top), (aChar >> 8) & 0xF);
DrawHexChar(aContext,
center + gfxPoint(left, halfGap), (aChar >> 4) & 0xF);
DrawHexChar(aContext,
center + gfxPoint(halfGap, halfGap), aChar & 0xF);
gfxPoint center(aRect.X() + aRect.Width()/2,
aRect.Y() + aRect.Height()/2);
gfxFloat halfGap = HEX_CHAR_GAP/2.0;
gfxFloat top = -(MINIFONT_HEIGHT + halfGap);
if (aChar < 0x10000) {
if (aRect.Width() >= 2*MINIFONT_WIDTH + HEX_CHAR_GAP &&
aRect.Height() >= 2*MINIFONT_HEIGHT + HEX_CHAR_GAP) {
// Draw 4 digits for BMP
aContext->SetColor(currentColor);
gfxFloat left = -(MINIFONT_WIDTH + halfGap);
DrawHexChar(aContext,
center + gfxPoint(left, top), (aChar >> 12) & 0xF);
DrawHexChar(aContext,
center + gfxPoint(halfGap, top), (aChar >> 8) & 0xF);
DrawHexChar(aContext,
center + gfxPoint(left, halfGap), (aChar >> 4) & 0xF);
DrawHexChar(aContext,
center + gfxPoint(halfGap, halfGap), aChar & 0xF);
}
} else {
if (aRect.Width() >= 3*MINIFONT_WIDTH + 2*HEX_CHAR_GAP &&
aRect.Height() >= 2*MINIFONT_HEIGHT + HEX_CHAR_GAP) {
// Draw 6 digits for non-BMP
aContext->SetColor(currentColor);
gfxFloat first = -(MINIFONT_WIDTH * 1.5 + HEX_CHAR_GAP);
gfxFloat second = -(MINIFONT_WIDTH / 2.0);
gfxFloat third = (MINIFONT_WIDTH / 2.0 + HEX_CHAR_GAP);
DrawHexChar(aContext,
center + gfxPoint(first, top), (aChar >> 20) & 0xF);
DrawHexChar(aContext,
center + gfxPoint(second, top), (aChar >> 16) & 0xF);
DrawHexChar(aContext,
center + gfxPoint(third, top), (aChar >> 12) & 0xF);
DrawHexChar(aContext,
center + gfxPoint(first, halfGap), (aChar >> 8) & 0xF);
DrawHexChar(aContext,
center + gfxPoint(second, halfGap), (aChar >> 4) & 0xF);
DrawHexChar(aContext,
center + gfxPoint(third, halfGap), aChar & 0xF);
}
}
aContext->Restore();
}
gfxFloat
gfxFontMissingGlyphs::GetDesiredMinWidth()
gfxFontMissingGlyphs::GetDesiredMinWidth(PRUint32 aChar)
{
return MIN_DESIRED_WIDTH;
/**
* The minimum desired width for a missing-glyph glyph box. I've laid it out
* like this so you can see what goes where.
*/
return BOX_HORIZONTAL_INSET + BOX_BORDER_WIDTH + HEX_CHAR_GAP +
MINIFONT_WIDTH + HEX_CHAR_GAP + MINIFONT_WIDTH +
((aChar < 0x10000) ? 0 : HEX_CHAR_GAP + MINIFONT_WIDTH) +
HEX_CHAR_GAP + BOX_BORDER_WIDTH + BOX_HORIZONTAL_INSET;
}

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

@ -56,12 +56,12 @@ public:
* @param aChar the UTF16 codepoint for the character
*/
static void DrawMissingGlyph(gfxContext *aContext, const gfxRect& aRect,
PRUnichar aChar);
PRUint32 aChar);
/**
* @return the desired minimum width for a glyph-box that will allow
* the hexboxes to be drawn reasonably.
*/
static gfxFloat GetDesiredMinWidth();
static gfxFloat GetDesiredMinWidth(PRUint32 aChar);
};
#endif

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

@ -488,21 +488,6 @@ void gfxOS2FontGroup::InitTextRun(gfxTextRun *aTextRun, const PRUint8 *aUTF8Text
aUTF8Length - aUTF8HeaderLength);
}
static void SetMissingGlyphForUCS4(gfxTextRun *aTextRun, PRUint32 aIndex,
PRUint32 aCh)
{
if (aCh < 0x10000) {
aTextRun->SetMissingGlyph(aIndex, PRUnichar(aCh));
return;
}
// Display non-BMP characters as a surrogate pair
aTextRun->SetMissingGlyph(aIndex, H_SURROGATE(aCh));
if (aIndex + 1 < aTextRun->GetLength()) {
aTextRun->SetMissingGlyph(aIndex + 1, L_SURROGATE(aCh));
}
}
// Helper function to return the leading UTF-8 character in a char pointer
// as 32bit number. Also sets the length of the current character (i.e. the
// offset to the next one) in the second argument
@ -587,7 +572,7 @@ void gfxOS2FontGroup::CreateGlyphRunsFT(gfxTextRun *aTextRun, const PRUint8 *aUT
g.SetSimpleGlyph(advance, gid));
} else if (gid == 0) {
// gid = 0 only happens when the glyph is missing from the font
SetMissingGlyphForUCS4(aTextRun, utf16Offset, ch);
aTextRun->SetMissingGlyph(utf16Offset, ch);
} else {
gfxTextRun::DetailedGlyph details;
details.mIsLastGlyph = PR_TRUE;

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

@ -1002,21 +1002,6 @@ ConvertPangoToAppUnits(PRInt32 aCoordinate, PRUint32 aAppUnitsPerDevUnit)
return PRInt32(v);
}
static void
SetMissingGlyphForUCS4(gfxTextRun *aTextRun, PRUint32 aIndex, gunichar aCh)
{
if (aCh < 0x10000) {
aTextRun->SetMissingGlyph(aIndex, PRUnichar(aCh));
return;
}
// Display non-BMP characters as a surrogate pair
aTextRun->SetMissingGlyph(aIndex, H_SURROGATE(aCh));
if (aIndex + 1 < aTextRun->GetLength()) {
aTextRun->SetMissingGlyph(aIndex + 1, L_SURROGATE(aCh));
}
}
/**
* Given a run of Pango glyphs that should be treated as a single
* cluster/ligature, store them in the textrun at the appropriate character
@ -1242,7 +1227,7 @@ gfxPangoFontGroup::SetMissingGlyphs(gfxTextRun *aTextRun,
break;
}
gunichar ch = g_utf8_get_char(aUTF8 + index);
SetMissingGlyphForUCS4(aTextRun, utf16Offset, ch);
aTextRun->SetMissingGlyph(utf16Offset, ch);
++utf16Offset;
NS_ASSERTION(!IS_SURROGATE(ch), "surrogates should not appear in UTF8");
@ -1301,7 +1286,7 @@ gfxPangoFontGroup::CreateGlyphRunsXft(gfxTextRun *aTextRun,
} else if (IS_MISSING_GLYPH(glyph)) {
// Note that missing-glyph IDs are not simple glyph IDs, so we'll
// always get here when a glyph is missing
SetMissingGlyphForUCS4(aTextRun, utf16Offset, ch);
aTextRun->SetMissingGlyph(utf16Offset, ch);
} else {
gfxTextRun::DetailedGlyph details;
details.mIsLastGlyph = PR_TRUE;

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

@ -1103,7 +1103,15 @@ public:
NS_ASSERTION(!gfxFontGroup::IsInvalidChar(mRangeString[offset]),
"invalid character detected");
if (missing) {
aRun->SetMissingGlyph(runOffset, mRangeString[offset]);
if (NS_IS_HIGH_SURROGATE(mRangeString[offset]) &&
offset + 1 < mRangeLength &&
NS_IS_LOW_SURROGATE(mRangeString[offset + 1])) {
aRun->SetMissingGlyph(runOffset,
SURROGATE_TO_UCS4(mRangeString[offset],
mRangeString[offset + 1]));
} else {
aRun->SetMissingGlyph(runOffset, mRangeString[offset]);
}
} else if (glyphCount == 1 && advance >= 0 &&
mOffsets[k].dv == 0 && mOffsets[k].du == 0 &&
gfxTextRun::CompressedGlyph::IsSimpleAdvance(advance) &&