mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
bug 825871 - refactor gfxTextRun and gfxShapedWord to share a common abstract base class (gfxShapedText) and shaping interface. r=roc
This commit is contained in:
parent
f7a2bb0534
commit
266183f3c3
@ -63,23 +63,25 @@ gfxCoreTextShaper::~gfxCoreTextShaper()
|
||||
}
|
||||
|
||||
bool
|
||||
gfxCoreTextShaper::ShapeWord(gfxContext *aContext,
|
||||
gfxShapedWord *aShapedWord,
|
||||
const PRUnichar *aText)
|
||||
gfxCoreTextShaper::ShapeText(gfxContext *aContext,
|
||||
const PRUnichar *aText,
|
||||
uint32_t aOffset,
|
||||
uint32_t aLength,
|
||||
int32_t aScript,
|
||||
gfxShapedText *aShapedText)
|
||||
{
|
||||
// Create a CFAttributedString with text and style info, so we can use CoreText to lay it out.
|
||||
|
||||
bool isRightToLeft = aShapedWord->IsRightToLeft();
|
||||
uint32_t length = aShapedWord->Length();
|
||||
bool isRightToLeft = aShapedText->IsRightToLeft();
|
||||
uint32_t length = aLength;
|
||||
|
||||
// we need to bidi-wrap the text if the run is RTL,
|
||||
// or if it is an LTR run but may contain (overridden) RTL chars
|
||||
bool bidiWrap = isRightToLeft;
|
||||
if (!bidiWrap && !aShapedWord->TextIs8Bit()) {
|
||||
const PRUnichar *text = aShapedWord->TextUnicode();
|
||||
if (!bidiWrap && !aShapedText->TextIs8Bit()) {
|
||||
uint32_t i;
|
||||
for (i = 0; i < length; ++i) {
|
||||
if (gfxFontUtils::PotentialRTLChar(text[i])) {
|
||||
if (gfxFontUtils::PotentialRTLChar(aText[i])) {
|
||||
bidiWrap = true;
|
||||
break;
|
||||
}
|
||||
@ -115,7 +117,7 @@ gfxCoreTextShaper::ShapeWord(gfxContext *aContext,
|
||||
}
|
||||
|
||||
CFDictionaryRef attrObj;
|
||||
if (aShapedWord->DisableLigatures()) {
|
||||
if (aShapedText->DisableLigatures()) {
|
||||
// For letterspacing (or maybe other situations) we need to make a copy of the CTFont
|
||||
// with the ligature feature disabled
|
||||
CTFontRef ctFont =
|
||||
@ -156,7 +158,7 @@ gfxCoreTextShaper::ShapeWord(gfxContext *aContext,
|
||||
for (uint32_t runIndex = 0; runIndex < numRuns; runIndex++) {
|
||||
CTRunRef aCTRun =
|
||||
(CTRunRef)::CFArrayGetValueAtIndex(glyphRuns, runIndex);
|
||||
if (SetGlyphsFromRun(aShapedWord, aCTRun, startOffset) != NS_OK) {
|
||||
if (SetGlyphsFromRun(aShapedText, aOffset, aLength, aCTRun, startOffset) != NS_OK) {
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
@ -172,22 +174,24 @@ gfxCoreTextShaper::ShapeWord(gfxContext *aContext,
|
||||
// without requiring a separate allocation
|
||||
|
||||
nsresult
|
||||
gfxCoreTextShaper::SetGlyphsFromRun(gfxShapedWord *aShapedWord,
|
||||
CTRunRef aCTRun,
|
||||
int32_t aStringOffset)
|
||||
gfxCoreTextShaper::SetGlyphsFromRun(gfxShapedText *aShapedText,
|
||||
uint32_t aOffset,
|
||||
uint32_t aLength,
|
||||
CTRunRef aCTRun,
|
||||
int32_t aStringOffset)
|
||||
{
|
||||
// The word has been bidi-wrapped; aStringOffset is the number
|
||||
// of chars at the beginning of the CTLine that we should skip.
|
||||
// aCTRun is a glyph run from the CoreText layout process.
|
||||
|
||||
int32_t direction = aShapedWord->IsRightToLeft() ? -1 : 1;
|
||||
int32_t direction = aShapedText->IsRightToLeft() ? -1 : 1;
|
||||
|
||||
int32_t numGlyphs = ::CTRunGetGlyphCount(aCTRun);
|
||||
if (numGlyphs == 0) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
int32_t wordLength = aShapedWord->Length();
|
||||
int32_t wordLength = aLength;
|
||||
|
||||
// character offsets get really confusing here, as we have to keep track of
|
||||
// (a) the text in the actual textRun we're constructing
|
||||
@ -257,8 +261,10 @@ gfxCoreTextShaper::SetGlyphsFromRun(gfxShapedWord *aShapedWord,
|
||||
double runWidth = ::CTRunGetTypographicBounds(aCTRun, ::CFRangeMake(0, 0),
|
||||
NULL, NULL, NULL);
|
||||
|
||||
nsAutoTArray<gfxTextRun::DetailedGlyph,1> detailedGlyphs;
|
||||
gfxTextRun::CompressedGlyph g;
|
||||
nsAutoTArray<gfxShapedText::DetailedGlyph,1> detailedGlyphs;
|
||||
gfxShapedText::CompressedGlyph g;
|
||||
gfxShapedText::CompressedGlyph *charGlyphs =
|
||||
aShapedText->GetCharacterGlyphs() + aOffset;
|
||||
|
||||
// CoreText gives us the glyphindex-to-charindex mapping, which relates each glyph
|
||||
// to a source text character; we also need the charindex-to-glyphindex mapping to
|
||||
@ -302,7 +308,7 @@ gfxCoreTextShaper::SetGlyphsFromRun(gfxShapedWord *aShapedWord,
|
||||
// This may find characters that fall outside the range 0:wordLength,
|
||||
// so we won't necessarily use everything we find here.
|
||||
|
||||
bool isRightToLeft = aShapedWord->IsRightToLeft();
|
||||
bool isRightToLeft = aShapedText->IsRightToLeft();
|
||||
int32_t glyphStart = 0; // looking for a clump that starts at this glyph index
|
||||
int32_t charStart = isRightToLeft ?
|
||||
stringRange.length - 1 : 0; // and this char index (in the stringRange of the glyph run)
|
||||
@ -438,7 +444,7 @@ gfxCoreTextShaper::SetGlyphsFromRun(gfxShapedWord *aShapedWord,
|
||||
|
||||
// Now we're ready to set the glyph info in the textRun; measure the glyph width
|
||||
// of the first (perhaps only) glyph, to see if it is "Simple"
|
||||
int32_t appUnitsPerDevUnit = aShapedWord->AppUnitsPerDevUnit();
|
||||
int32_t appUnitsPerDevUnit = aShapedText->GetAppUnitsPerDevUnit();
|
||||
double toNextGlyph;
|
||||
if (glyphStart < numGlyphs-1) {
|
||||
toNextGlyph = positions[glyphStart+1].x - positions[glyphStart].x;
|
||||
@ -452,12 +458,11 @@ gfxCoreTextShaper::SetGlyphsFromRun(gfxShapedWord *aShapedWord,
|
||||
if (glyphsInClump == 1 &&
|
||||
gfxTextRun::CompressedGlyph::IsSimpleGlyphID(glyphs[glyphStart]) &&
|
||||
gfxTextRun::CompressedGlyph::IsSimpleAdvance(advance) &&
|
||||
aShapedWord->IsClusterStart(baseCharIndex) &&
|
||||
charGlyphs[baseCharIndex].IsClusterStart() &&
|
||||
positions[glyphStart].y == 0.0)
|
||||
{
|
||||
aShapedWord->SetSimpleGlyph(baseCharIndex,
|
||||
g.SetSimpleGlyph(advance,
|
||||
glyphs[glyphStart]));
|
||||
charGlyphs[baseCharIndex].SetSimpleGlyph(advance,
|
||||
glyphs[glyphStart]);
|
||||
} else {
|
||||
// collect all glyphs in a list to be assigned to the first char;
|
||||
// there must be at least one in the clump, and we already measured its advance,
|
||||
@ -480,18 +485,18 @@ gfxCoreTextShaper::SetGlyphsFromRun(gfxShapedWord *aShapedWord,
|
||||
}
|
||||
|
||||
gfxTextRun::CompressedGlyph g;
|
||||
g.SetComplex(aShapedWord->IsClusterStart(baseCharIndex),
|
||||
g.SetComplex(charGlyphs[baseCharIndex].IsClusterStart(),
|
||||
true, detailedGlyphs.Length());
|
||||
aShapedWord->SetGlyphs(baseCharIndex, g, detailedGlyphs.Elements());
|
||||
aShapedText->SetGlyphs(aOffset + baseCharIndex, g, detailedGlyphs.Elements());
|
||||
|
||||
detailedGlyphs.Clear();
|
||||
}
|
||||
|
||||
// the rest of the chars in the group are ligature continuations, no associated glyphs
|
||||
while (++baseCharIndex != endCharIndex && baseCharIndex < wordLength) {
|
||||
g.SetComplex(inOrder && aShapedWord->IsClusterStart(baseCharIndex),
|
||||
false, 0);
|
||||
aShapedWord->SetGlyphs(baseCharIndex, g, nullptr);
|
||||
gfxShapedText::CompressedGlyph &g = charGlyphs[baseCharIndex];
|
||||
NS_ASSERTION(!g.IsSimpleGlyph(), "overwriting a simple glyph");
|
||||
g.SetComplex(inOrder && g.IsClusterStart(), false, 0);
|
||||
}
|
||||
|
||||
glyphStart = glyphEnd;
|
||||
|
@ -22,9 +22,12 @@ public:
|
||||
|
||||
virtual ~gfxCoreTextShaper();
|
||||
|
||||
virtual bool ShapeWord(gfxContext *aContext,
|
||||
gfxShapedWord *aShapedWord,
|
||||
const PRUnichar *aText);
|
||||
virtual bool ShapeText(gfxContext *aContext,
|
||||
const PRUnichar *aText,
|
||||
uint32_t aOffset,
|
||||
uint32_t aLength,
|
||||
int32_t aScript,
|
||||
gfxShapedText *aShapedText);
|
||||
|
||||
// clean up static objects that may have been cached
|
||||
static void Shutdown();
|
||||
@ -33,9 +36,11 @@ protected:
|
||||
CTFontRef mCTFont;
|
||||
CFDictionaryRef mAttributesDict;
|
||||
|
||||
nsresult SetGlyphsFromRun(gfxShapedWord *aShapedWord,
|
||||
CTRunRef aCTRun,
|
||||
int32_t aStringOffset);
|
||||
nsresult SetGlyphsFromRun(gfxShapedText *aShapedText,
|
||||
uint32_t aOffset,
|
||||
uint32_t aLength,
|
||||
CTRunRef aCTRun,
|
||||
int32_t aStringOffset);
|
||||
|
||||
CTFontRef CreateCTFontWithDisabledLigatures(CGFloat aSize);
|
||||
|
||||
|
@ -13,21 +13,24 @@
|
||||
#include "nsCRT.h"
|
||||
|
||||
bool
|
||||
gfxDWriteShaper::ShapeWord(gfxContext *aContext,
|
||||
gfxShapedWord *aShapedWord,
|
||||
const PRUnichar *aString)
|
||||
gfxDWriteShaper::ShapeText(gfxContext *aContext,
|
||||
const PRUnichar *aText,
|
||||
uint32_t aOffset,
|
||||
uint32_t aLength,
|
||||
int32_t aScript,
|
||||
gfxShapedText *aShapedText)
|
||||
{
|
||||
HRESULT hr;
|
||||
// TODO: Handle TEST_DISABLE_OPTIONAL_LIGATURES
|
||||
// TODO: Handle TEXT_DISABLE_OPTIONAL_LIGATURES
|
||||
|
||||
DWRITE_READING_DIRECTION readingDirection =
|
||||
aShapedWord->IsRightToLeft()
|
||||
aShapedText->IsRightToLeft()
|
||||
? DWRITE_READING_DIRECTION_RIGHT_TO_LEFT
|
||||
: DWRITE_READING_DIRECTION_LEFT_TO_RIGHT;
|
||||
|
||||
gfxDWriteFont *font = static_cast<gfxDWriteFont*>(mFont);
|
||||
|
||||
gfxShapedWord::CompressedGlyph g;
|
||||
gfxShapedText::CompressedGlyph g;
|
||||
|
||||
IDWriteTextAnalyzer *analyzer =
|
||||
gfxWindowsPlatform::GetPlatform()->GetDWriteAnalyzer();
|
||||
@ -37,12 +40,12 @@ gfxDWriteShaper::ShapeWord(gfxContext *aContext,
|
||||
|
||||
/**
|
||||
* There's an internal 16-bit limit on some things inside the analyzer,
|
||||
* but we never attempt to shape a word longer than 64K characters
|
||||
* in a single gfxShapedWord, so we cannot exceed that limit.
|
||||
* but we never attempt to shape a word longer than 32K characters
|
||||
* in a single call, so we cannot exceed that limit.
|
||||
*/
|
||||
UINT32 length = aShapedWord->Length();
|
||||
UINT32 length = aLength;
|
||||
|
||||
TextAnalysis analysis(aString, length, NULL, readingDirection);
|
||||
TextAnalysis analysis(aText, length, NULL, readingDirection);
|
||||
TextAnalysis::Run *runHead;
|
||||
hr = analysis.GenerateResults(analyzer, &runHead);
|
||||
|
||||
@ -51,7 +54,7 @@ gfxDWriteShaper::ShapeWord(gfxContext *aContext,
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t appUnitsPerDevPixel = aShapedWord->AppUnitsPerDevUnit();
|
||||
uint32_t appUnitsPerDevPixel = aShapedText->GetAppUnitsPerDevUnit();
|
||||
|
||||
UINT32 maxGlyphs = 0;
|
||||
trymoreglyphs:
|
||||
@ -77,7 +80,7 @@ trymoreglyphs:
|
||||
|
||||
UINT32 actualGlyphs;
|
||||
|
||||
hr = analyzer->GetGlyphs(aString, length,
|
||||
hr = analyzer->GetGlyphs(aText, length,
|
||||
font->GetFontFace(), FALSE,
|
||||
readingDirection == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT,
|
||||
&runHead->mScript, NULL, NULL, NULL, NULL, 0,
|
||||
@ -104,7 +107,7 @@ trymoreglyphs:
|
||||
|
||||
if (!static_cast<gfxDWriteFont*>(mFont)->mUseSubpixelPositions) {
|
||||
hr = analyzer->GetGdiCompatibleGlyphPlacements(
|
||||
aString,
|
||||
aText,
|
||||
clusters.Elements(),
|
||||
textProperties.Elements(),
|
||||
length,
|
||||
@ -126,7 +129,7 @@ trymoreglyphs:
|
||||
advances.Elements(),
|
||||
glyphOffsets.Elements());
|
||||
} else {
|
||||
hr = analyzer->GetGlyphPlacements(aString,
|
||||
hr = analyzer->GetGlyphPlacements(aText,
|
||||
clusters.Elements(),
|
||||
textProperties.Elements(),
|
||||
length,
|
||||
@ -150,16 +153,19 @@ trymoreglyphs:
|
||||
return false;
|
||||
}
|
||||
|
||||
nsAutoTArray<gfxTextRun::DetailedGlyph,1> detailedGlyphs;
|
||||
nsAutoTArray<gfxShapedText::DetailedGlyph,1> detailedGlyphs;
|
||||
gfxShapedText::CompressedGlyph *charGlyphs =
|
||||
aShapedText->GetCharacterGlyphs();
|
||||
|
||||
for (unsigned int c = 0; c < length; c++) {
|
||||
uint32_t k = clusters[c];
|
||||
uint32_t absC = c;
|
||||
uint32_t absC = aOffset + c;
|
||||
|
||||
if (c > 0 && k == clusters[c - 1]) {
|
||||
g.SetComplex(aShapedWord->IsClusterStart(absC), false, 0);
|
||||
aShapedWord->SetGlyphs(absC, g, nullptr);
|
||||
// This is a cluster continuation. No glyph here.
|
||||
gfxShapedText::CompressedGlyph &g = charGlyphs[absC];
|
||||
NS_ASSERTION(!g.IsSimpleGlyph(), "overwriting a simple glyph");
|
||||
g.SetComplex(g.IsClusterStart(), false, 0);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -177,12 +183,10 @@ trymoreglyphs:
|
||||
if (glyphCount == 1 && advance >= 0 &&
|
||||
glyphOffsets[k].advanceOffset == 0 &&
|
||||
glyphOffsets[k].ascenderOffset == 0 &&
|
||||
aShapedWord->IsClusterStart(absC) &&
|
||||
gfxShapedWord::CompressedGlyph::IsSimpleAdvance(advance) &&
|
||||
gfxShapedWord::CompressedGlyph::IsSimpleGlyphID(indices[k])) {
|
||||
aShapedWord->SetSimpleGlyph(absC,
|
||||
g.SetSimpleGlyph(advance,
|
||||
indices[k]));
|
||||
charGlyphs[absC].IsClusterStart() &&
|
||||
gfxShapedText::CompressedGlyph::IsSimpleAdvance(advance) &&
|
||||
gfxShapedText::CompressedGlyph::IsSimpleGlyphID(indices[k])) {
|
||||
charGlyphs[absC].SetSimpleGlyph(advance, indices[k]);
|
||||
} else {
|
||||
if (detailedGlyphs.Length() < glyphCount) {
|
||||
if (!detailedGlyphs.AppendElements(
|
||||
@ -212,9 +216,9 @@ trymoreglyphs:
|
||||
appUnitsPerDevPixel;
|
||||
totalAdvance += advances[k + z];
|
||||
}
|
||||
aShapedWord->SetGlyphs(
|
||||
aShapedText->SetGlyphs(
|
||||
absC,
|
||||
g.SetComplex(aShapedWord->IsClusterStart(absC),
|
||||
g.SetComplex(charGlyphs[absC].IsClusterStart(),
|
||||
true,
|
||||
glyphCount),
|
||||
detailedGlyphs.Elements());
|
||||
|
@ -25,9 +25,12 @@ public:
|
||||
MOZ_COUNT_DTOR(gfxDWriteShaper);
|
||||
}
|
||||
|
||||
virtual bool ShapeWord(gfxContext *aContext,
|
||||
gfxShapedWord *aShapedWord,
|
||||
const PRUnichar *aString);
|
||||
virtual bool ShapeText(gfxContext *aContext,
|
||||
const PRUnichar *aText,
|
||||
uint32_t aOffset,
|
||||
uint32_t aLength,
|
||||
int32_t aScript,
|
||||
gfxShapedText *aShapedText);
|
||||
};
|
||||
|
||||
#endif /* GFX_DWRITESHAPER_H */
|
||||
|
@ -403,10 +403,13 @@ gfxFT2FontGroup::WhichSystemFontSupportsChar(uint32_t aCh, int32_t aRunScript)
|
||||
*/
|
||||
|
||||
bool
|
||||
gfxFT2Font::ShapeWord(gfxContext *aContext,
|
||||
gfxShapedWord *aShapedWord,
|
||||
const PRUnichar *aString,
|
||||
bool aPreferPlatformShaping)
|
||||
gfxFT2Font::ShapeText(gfxContext *aContext,
|
||||
const PRUnichar *aText,
|
||||
uint32_t aOffset,
|
||||
uint32_t aLength,
|
||||
int32_t aScript,
|
||||
gfxShapedText *aShapedText,
|
||||
bool aPreferPlatformShaping)
|
||||
{
|
||||
bool ok = false;
|
||||
|
||||
@ -416,55 +419,56 @@ gfxFT2Font::ShapeWord(gfxContext *aContext,
|
||||
if (!mGraphiteShaper) {
|
||||
mGraphiteShaper = new gfxGraphiteShaper(this);
|
||||
}
|
||||
ok = mGraphiteShaper->ShapeWord(aContext, aShapedWord, aString);
|
||||
ok = mGraphiteShaper->ShapeText(aContext, aText,
|
||||
aOffset, aLength,
|
||||
aScript, aShapedText);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!ok && gfxPlatform::GetPlatform()->UseHarfBuzzForScript(aShapedWord->Script())) {
|
||||
if (!ok && gfxPlatform::GetPlatform()->UseHarfBuzzForScript(aScript)) {
|
||||
if (!mHarfBuzzShaper) {
|
||||
gfxFT2LockedFace face(this);
|
||||
mFUnitsConvFactor = face.XScale();
|
||||
|
||||
mHarfBuzzShaper = new gfxHarfBuzzShaper(this);
|
||||
}
|
||||
ok = mHarfBuzzShaper->ShapeWord(aContext, aShapedWord, aString);
|
||||
ok = mHarfBuzzShaper->ShapeText(aContext, aText,
|
||||
aOffset, aLength,
|
||||
aScript, aShapedText);
|
||||
}
|
||||
|
||||
if (!ok) {
|
||||
AddRange(aShapedWord, aString);
|
||||
AddRange(aText, aOffset, aLength, aShapedText);
|
||||
}
|
||||
|
||||
if (IsSyntheticBold()) {
|
||||
float synBoldOffset =
|
||||
GetSyntheticBoldOffset() * CalcXScale(aContext);
|
||||
aShapedWord->AdjustAdvancesForSyntheticBold(synBoldOffset);
|
||||
}
|
||||
PostShapingFixup(aContext, aText, aOffset, aLength, aShapedText);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
gfxFT2Font::AddRange(gfxShapedWord *aShapedWord, const PRUnichar *str)
|
||||
gfxFT2Font::AddRange(const PRUnichar *aText, uint32_t aOffset,
|
||||
uint32_t aLength, gfxShapedText *aShapedText)
|
||||
{
|
||||
const uint32_t appUnitsPerDevUnit = aShapedWord->AppUnitsPerDevUnit();
|
||||
const uint32_t appUnitsPerDevUnit = aShapedText->GetAppUnitsPerDevUnit();
|
||||
// we'll pass this in/figure it out dynamically, but at this point there can be only one face.
|
||||
gfxFT2LockedFace faceLock(this);
|
||||
FT_Face face = faceLock.get();
|
||||
|
||||
gfxShapedWord::CompressedGlyph g;
|
||||
gfxShapedText::CompressedGlyph *charGlyphs =
|
||||
aShapedText->GetCharacterGlyphs();
|
||||
|
||||
const gfxFT2Font::CachedGlyphData *cgd = nullptr, *cgdNext = nullptr;
|
||||
|
||||
FT_UInt spaceGlyph = GetSpaceGlyph();
|
||||
|
||||
uint32_t len = aShapedWord->Length();
|
||||
for (uint32_t i = 0; i < len; i++) {
|
||||
PRUnichar ch = str[i];
|
||||
for (uint32_t i = 0; i < aLength; i++, aOffset++) {
|
||||
PRUnichar ch = aText[i];
|
||||
|
||||
if (ch == 0) {
|
||||
// treat this null byte as a missing glyph, don't create a glyph for it
|
||||
aShapedWord->SetMissingGlyph(i, 0, this);
|
||||
aShapedText->SetMissingGlyph(aOffset, 0, this);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -489,8 +493,8 @@ gfxFT2Font::AddRange(gfxShapedWord *aShapedWord, const PRUnichar *str)
|
||||
FT_UInt gidNext = 0;
|
||||
FT_Pos lsbDeltaNext = 0;
|
||||
|
||||
if (FT_HAS_KERNING(face) && i + 1 < len) {
|
||||
chNext = str[i + 1];
|
||||
if (FT_HAS_KERNING(face) && i + 1 < aLength) {
|
||||
chNext = aText[i + 1];
|
||||
if (chNext != 0) {
|
||||
cgdNext = GetGlyphDataForChar(chNext);
|
||||
gidNext = cgdNext->glyphIndex;
|
||||
@ -520,21 +524,23 @@ gfxFT2Font::AddRange(gfxShapedWord *aShapedWord, const PRUnichar *str)
|
||||
}
|
||||
|
||||
if (advance >= 0 &&
|
||||
gfxShapedWord::CompressedGlyph::IsSimpleAdvance(advance) &&
|
||||
gfxShapedWord::CompressedGlyph::IsSimpleGlyphID(gid)) {
|
||||
aShapedWord->SetSimpleGlyph(i, g.SetSimpleGlyph(advance, gid));
|
||||
gfxShapedText::CompressedGlyph::IsSimpleAdvance(advance) &&
|
||||
gfxShapedText::CompressedGlyph::IsSimpleGlyphID(gid)) {
|
||||
charGlyphs[aOffset].SetSimpleGlyph(advance, gid);
|
||||
} else if (gid == 0) {
|
||||
// gid = 0 only happens when the glyph is missing from the font
|
||||
aShapedWord->SetMissingGlyph(i, ch, this);
|
||||
aShapedText->SetMissingGlyph(aOffset, ch, this);
|
||||
} else {
|
||||
gfxTextRun::DetailedGlyph details;
|
||||
details.mGlyphID = gid;
|
||||
NS_ASSERTION(details.mGlyphID == gid, "Seriously weird glyph ID detected!");
|
||||
NS_ASSERTION(details.mGlyphID == gid,
|
||||
"Seriously weird glyph ID detected!");
|
||||
details.mAdvance = advance;
|
||||
details.mXOffset = 0;
|
||||
details.mYOffset = 0;
|
||||
g.SetComplex(aShapedWord->IsClusterStart(i), true, 1);
|
||||
aShapedWord->SetGlyphs(i, g, &details);
|
||||
gfxShapedText::CompressedGlyph g;
|
||||
g.SetComplex(charGlyphs[aOffset].IsClusterStart(), true, 1);
|
||||
aShapedText->SetGlyphs(aOffset, g, &details);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -69,14 +69,20 @@ public: // new functions
|
||||
FontCacheSizes* aSizes) const;
|
||||
|
||||
protected:
|
||||
virtual bool ShapeWord(gfxContext *aContext,
|
||||
gfxShapedWord *aShapedWord,
|
||||
const PRUnichar *aString,
|
||||
bool aPreferPlatformShaping = false);
|
||||
virtual bool ShapeText(gfxContext *aContext,
|
||||
const PRUnichar *aText,
|
||||
uint32_t aOffset,
|
||||
uint32_t aLength,
|
||||
int32_t aScript,
|
||||
gfxShapedText *aShapedText,
|
||||
bool aPreferPlatformShaping);
|
||||
|
||||
void FillGlyphDataForChar(uint32_t ch, CachedGlyphData *gd);
|
||||
|
||||
void AddRange(gfxShapedWord *aShapedWord, const PRUnichar *str);
|
||||
void AddRange(const PRUnichar *aText,
|
||||
uint32_t aOffset,
|
||||
uint32_t aLength,
|
||||
gfxShapedText *aShapedText);
|
||||
|
||||
typedef nsBaseHashtableET<nsUint32HashKey, CachedGlyphData> CharGlyphMapEntryType;
|
||||
typedef nsTHashtable<CharGlyphMapEntryType> CharGlyphMap;
|
||||
|
@ -2335,14 +2335,6 @@ gfxFont::Measure(gfxTextRun *aTextRun,
|
||||
return metrics;
|
||||
}
|
||||
|
||||
#define MAX_SHAPING_LENGTH 32760 // slightly less than 32K, trying to avoid
|
||||
// over-stressing platform shapers
|
||||
|
||||
#define BACKTRACK_LIMIT 1024 // If we can't find a space or a cluster start
|
||||
// within 1K chars, just chop arbitrarily.
|
||||
// Limiting backtrack here avoids pathological
|
||||
// behavior on long runs with no whitespace.
|
||||
|
||||
static bool
|
||||
IsBoundarySpace(PRUnichar aChar, PRUnichar aNextChar)
|
||||
{
|
||||
@ -2358,12 +2350,12 @@ HashMix(uint32_t aHash, PRUnichar aCh)
|
||||
template<typename T>
|
||||
gfxShapedWord*
|
||||
gfxFont::GetShapedWord(gfxContext *aContext,
|
||||
const T *aText,
|
||||
uint32_t aLength,
|
||||
uint32_t aHash,
|
||||
int32_t aRunScript,
|
||||
int32_t aAppUnitsPerDevUnit,
|
||||
uint32_t aFlags)
|
||||
const T *aText,
|
||||
uint32_t aLength,
|
||||
uint32_t aHash,
|
||||
int32_t aRunScript,
|
||||
int32_t aAppUnitsPerDevUnit,
|
||||
uint32_t aFlags)
|
||||
{
|
||||
// if the cache is getting too big, flush it and start over
|
||||
if (mWordCache.Count() > 10000) {
|
||||
@ -2400,28 +2392,10 @@ gfxFont::GetShapedWord(gfxContext *aContext,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
DebugOnly<bool> ok = false;
|
||||
if (sizeof(T) == sizeof(PRUnichar)) {
|
||||
ok = ShapeWord(aContext, sw, (const PRUnichar*)aText);
|
||||
} else {
|
||||
nsAutoString utf16;
|
||||
AppendASCIItoUTF16(nsDependentCSubstring((const char*)aText, aLength),
|
||||
utf16);
|
||||
if (utf16.Length() == aLength) {
|
||||
ok = ShapeWord(aContext, sw, utf16.BeginReading());
|
||||
}
|
||||
}
|
||||
NS_WARN_IF_FALSE(ok, "failed to shape word - expect garbled text");
|
||||
DebugOnly<bool> ok =
|
||||
ShapeText(aContext, aText, 0, aLength, aRunScript, sw);
|
||||
|
||||
for (uint32_t i = 0; i < aLength; ++i) {
|
||||
if (aText[i] == ' ') {
|
||||
sw->SetIsSpace(i);
|
||||
} else if (i > 0 &&
|
||||
NS_IS_HIGH_SURROGATE(aText[i - 1]) &&
|
||||
NS_IS_LOW_SURROGATE(aText[i])) {
|
||||
sw->SetIsLowSurrogate(i);
|
||||
}
|
||||
}
|
||||
NS_WARN_IF_FALSE(ok, "failed to shape word - expect garbled text");
|
||||
|
||||
return sw;
|
||||
}
|
||||
@ -2433,9 +2407,9 @@ gfxFont::CacheHashEntry::KeyEquals(const KeyTypePointer aKey) const
|
||||
if (!sw) {
|
||||
return false;
|
||||
}
|
||||
if (sw->Length() != aKey->mLength ||
|
||||
if (sw->GetLength() != aKey->mLength ||
|
||||
sw->Flags() != aKey->mFlags ||
|
||||
sw->AppUnitsPerDevUnit() != aKey->mAppUnitsPerDevUnit ||
|
||||
sw->GetAppUnitsPerDevUnit() != aKey->mAppUnitsPerDevUnit ||
|
||||
sw->Script() != aKey->mScript) {
|
||||
return false;
|
||||
}
|
||||
@ -2464,22 +2438,46 @@ gfxFont::CacheHashEntry::KeyEquals(const KeyTypePointer aKey) const
|
||||
}
|
||||
|
||||
bool
|
||||
gfxFont::ShapeWord(gfxContext *aContext,
|
||||
gfxShapedWord *aShapedWord,
|
||||
gfxFont::ShapeText(gfxContext *aContext,
|
||||
const uint8_t *aText,
|
||||
uint32_t aOffset,
|
||||
uint32_t aLength,
|
||||
int32_t aScript,
|
||||
gfxShapedText *aShapedText,
|
||||
bool aPreferPlatformShaping)
|
||||
{
|
||||
nsDependentCSubstring ascii((const char*)aText, aLength);
|
||||
nsAutoString utf16;
|
||||
AppendASCIItoUTF16(ascii, utf16);
|
||||
if (utf16.Length() != aLength) {
|
||||
return false;
|
||||
}
|
||||
return ShapeText(aContext, utf16.BeginReading(), aOffset, aLength,
|
||||
aScript, aShapedText, aPreferPlatformShaping);
|
||||
}
|
||||
|
||||
bool
|
||||
gfxFont::ShapeText(gfxContext *aContext,
|
||||
const PRUnichar *aText,
|
||||
bool aPreferPlatformShaping)
|
||||
uint32_t aOffset,
|
||||
uint32_t aLength,
|
||||
int32_t aScript,
|
||||
gfxShapedText *aShapedText,
|
||||
bool aPreferPlatformShaping)
|
||||
{
|
||||
bool ok = false;
|
||||
|
||||
#ifdef MOZ_GRAPHITE
|
||||
if (mGraphiteShaper && gfxPlatform::GetPlatform()->UseGraphiteShaping()) {
|
||||
ok = mGraphiteShaper->ShapeWord(aContext, aShapedWord, aText);
|
||||
ok = mGraphiteShaper->ShapeText(aContext, aText, aOffset, aLength,
|
||||
aScript, aShapedText);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!ok && mHarfBuzzShaper && !aPreferPlatformShaping) {
|
||||
if (gfxPlatform::GetPlatform()->UseHarfBuzzForScript(aShapedWord->Script())) {
|
||||
ok = mHarfBuzzShaper->ShapeWord(aContext, aShapedWord, aText);
|
||||
if (gfxPlatform::GetPlatform()->UseHarfBuzzForScript(aScript)) {
|
||||
ok = mHarfBuzzShaper->ShapeText(aContext, aText, aOffset, aLength,
|
||||
aScript, aShapedText);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2489,19 +2487,134 @@ gfxFont::ShapeWord(gfxContext *aContext,
|
||||
NS_ASSERTION(mPlatformShaper, "no platform shaper available!");
|
||||
}
|
||||
if (mPlatformShaper) {
|
||||
ok = mPlatformShaper->ShapeWord(aContext, aShapedWord, aText);
|
||||
ok = mPlatformShaper->ShapeText(aContext, aText, aOffset, aLength,
|
||||
aScript, aShapedText);
|
||||
}
|
||||
}
|
||||
|
||||
if (ok && IsSyntheticBold()) {
|
||||
PostShapingFixup(aContext, aText, aOffset, aLength, aShapedText);
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
void
|
||||
gfxFont::PostShapingFixup(gfxContext *aContext,
|
||||
const PRUnichar *aText,
|
||||
uint32_t aOffset,
|
||||
uint32_t aLength,
|
||||
gfxShapedText *aShapedText)
|
||||
{
|
||||
if (IsSyntheticBold()) {
|
||||
float synBoldOffset =
|
||||
GetSyntheticBoldOffset() * CalcXScale(aContext);
|
||||
aShapedWord->AdjustAdvancesForSyntheticBold(synBoldOffset);
|
||||
aShapedText->AdjustAdvancesForSyntheticBold(synBoldOffset,
|
||||
aOffset, aLength);
|
||||
}
|
||||
}
|
||||
|
||||
#define MAX_SHAPING_LENGTH 32760 // slightly less than 32K, trying to avoid
|
||||
// over-stressing platform shapers
|
||||
#define BACKTRACK_LIMIT 16 // backtrack this far looking for a good place
|
||||
// to split into fragments for separate shaping
|
||||
|
||||
template<typename T>
|
||||
bool
|
||||
gfxFont::ShapeFragmentWithoutWordCache(gfxContext *aContext,
|
||||
const T *aText,
|
||||
uint32_t aOffset,
|
||||
uint32_t aLength,
|
||||
int32_t aScript,
|
||||
gfxTextRun *aTextRun)
|
||||
{
|
||||
aTextRun->SetupClusterBoundaries(aOffset, aText, aLength);
|
||||
|
||||
bool ok = true;
|
||||
|
||||
while (ok && aLength > 0) {
|
||||
uint32_t fragLen = aLength;
|
||||
|
||||
// limit the length of text we pass to shapers in a single call
|
||||
if (fragLen > MAX_SHAPING_LENGTH) {
|
||||
fragLen = MAX_SHAPING_LENGTH;
|
||||
|
||||
// in the 8-bit case, there are no multi-char clusters,
|
||||
// so we don't need to do this check
|
||||
if (sizeof(T) == sizeof(PRUnichar)) {
|
||||
uint32_t i;
|
||||
for (i = 0; i < BACKTRACK_LIMIT; ++i) {
|
||||
if (aTextRun->IsClusterStart(aOffset + fragLen - i)) {
|
||||
fragLen -= i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == BACKTRACK_LIMIT) {
|
||||
// if we didn't find any cluster start while backtracking,
|
||||
// just check that we're not in the middle of a surrogate
|
||||
// pair; back up by one code unit if we are.
|
||||
if (NS_IS_LOW_SURROGATE(aText[fragLen]) &&
|
||||
NS_IS_HIGH_SURROGATE(aText[fragLen - 1])) {
|
||||
--fragLen;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ok = ShapeText(aContext, aText, aOffset, fragLen, aScript, aTextRun);
|
||||
|
||||
aText += fragLen;
|
||||
aOffset += fragLen;
|
||||
aLength -= fragLen;
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool
|
||||
gfxFont::ShapeTextWithoutWordCache(gfxContext *aContext,
|
||||
const T *aText,
|
||||
uint32_t aOffset,
|
||||
uint32_t aLength,
|
||||
int32_t aScript,
|
||||
gfxTextRun *aTextRun)
|
||||
{
|
||||
uint32_t fragStart = 0;
|
||||
bool ok = true;
|
||||
|
||||
for (uint32_t i = 0; i <= aLength && ok; ++i) {
|
||||
T ch = (i < aLength) ? aText[i] : '\n';
|
||||
bool invalid = gfxFontGroup::IsInvalidChar(ch);
|
||||
uint32_t length = i - fragStart;
|
||||
|
||||
// break into separate fragments when we hit an invalid char
|
||||
if (!invalid) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (length > 0) {
|
||||
ok = ShapeFragmentWithoutWordCache(aContext, aText + fragStart,
|
||||
aOffset + fragStart, length,
|
||||
aScript, aTextRun);
|
||||
}
|
||||
|
||||
if (i == aLength) {
|
||||
break;
|
||||
}
|
||||
|
||||
// fragment was terminated by an invalid char: skip it,
|
||||
// but record where TAB or NEWLINE occur
|
||||
if (ch == '\t') {
|
||||
aTextRun->SetIsTab(aOffset + i);
|
||||
} else if (ch == '\n') {
|
||||
aTextRun->SetIsNewline(aOffset + i);
|
||||
}
|
||||
fragStart = i + 1;
|
||||
}
|
||||
|
||||
NS_WARN_IF_FALSE(ok, "failed to shape text - expect garbled text");
|
||||
return ok;
|
||||
}
|
||||
|
||||
inline static bool IsChar8Bit(uint8_t /*aCh*/) { return true; }
|
||||
inline static bool IsChar8Bit(PRUnichar aCh) { return aCh < 0x100; }
|
||||
|
||||
@ -2548,7 +2661,7 @@ gfxFont::SplitAndInitTextRun(gfxContext *aContext,
|
||||
bool breakHere = boundary || invalid;
|
||||
|
||||
if (!breakHere) {
|
||||
// if we're approaching the max ShapedWord length, break anyway...
|
||||
// if we're approaching the max length for shaping, break anyway...
|
||||
if (sizeof(T) == sizeof(uint8_t)) {
|
||||
// in 8-bit text, no clusters or surrogates to worry about
|
||||
if (length >= gfxShapedWord::kMaxLength) {
|
||||
@ -3768,7 +3881,7 @@ gfxFontGroup::InitScriptRun(gfxContext *aContext,
|
||||
for (uint32_t r = 0; r < numRanges; r++) {
|
||||
const gfxTextRange& range = fontRanges[r];
|
||||
uint32_t matchedLength = range.Length();
|
||||
gfxFont *matchedFont = (range.font ? range.font.get() : nullptr);
|
||||
gfxFont *matchedFont = range.font;
|
||||
|
||||
// create the glyph run for this range
|
||||
if (matchedFont) {
|
||||
@ -3787,14 +3900,11 @@ gfxFontGroup::InitScriptRun(gfxContext *aContext,
|
||||
}
|
||||
|
||||
if (!matchedFont) {
|
||||
// for PRUnichar text, we need to set cluster boundaries so that
|
||||
// We need to set cluster boundaries (and mark spaces) so that
|
||||
// surrogate pairs, combining characters, etc behave properly,
|
||||
// even if we don't have glyphs for them
|
||||
if (sizeof(T) == sizeof(PRUnichar)) {
|
||||
gfxShapedWord::SetupClusterBoundaries(aTextRun->GetCharacterGlyphs() + runStart,
|
||||
reinterpret_cast<const PRUnichar*>(aString) + runStart,
|
||||
matchedLength);
|
||||
}
|
||||
aTextRun->SetupClusterBoundaries(runStart, aString + runStart,
|
||||
matchedLength);
|
||||
|
||||
// various "missing" characters may need special handling,
|
||||
// so we check for them here
|
||||
@ -3822,9 +3932,9 @@ gfxFontGroup::InitScriptRun(gfxContext *aContext,
|
||||
{
|
||||
aTextRun->SetMissingGlyph(index,
|
||||
SURROGATE_TO_UCS4(ch,
|
||||
aString[index + 1]));
|
||||
aString[index + 1]),
|
||||
mainFont);
|
||||
index++;
|
||||
aTextRun->SetIsLowSurrogate(index);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -3834,16 +3944,16 @@ gfxFontGroup::InitScriptRun(gfxContext *aContext,
|
||||
if (wid >= 0.0) {
|
||||
nscoord advance =
|
||||
aTextRun->GetAppUnitsPerDevUnit() * floor(wid + 0.5);
|
||||
gfxTextRun::CompressedGlyph g;
|
||||
if (gfxTextRun::CompressedGlyph::IsSimpleAdvance(advance)) {
|
||||
aTextRun->SetSimpleGlyph(index,
|
||||
g.SetSimpleGlyph(advance,
|
||||
mainFont->GetSpaceGlyph()));
|
||||
if (gfxShapedText::CompressedGlyph::IsSimpleAdvance(advance)) {
|
||||
aTextRun->GetCharacterGlyphs()[index].
|
||||
SetSimpleGlyph(advance,
|
||||
mainFont->GetSpaceGlyph());
|
||||
} else {
|
||||
gfxTextRun::DetailedGlyph detailedGlyph;
|
||||
detailedGlyph.mGlyphID = mainFont->GetSpaceGlyph();
|
||||
detailedGlyph.mAdvance = advance;
|
||||
detailedGlyph.mXOffset = detailedGlyph.mYOffset = 0;
|
||||
gfxShapedText::CompressedGlyph g;
|
||||
g.SetComplex(true, true, 1);
|
||||
aTextRun->SetGlyphs(index,
|
||||
g, &detailedGlyph);
|
||||
@ -3858,7 +3968,7 @@ gfxFontGroup::InitScriptRun(gfxContext *aContext,
|
||||
}
|
||||
|
||||
// record char code so we can draw a box with the Unicode value
|
||||
aTextRun->SetMissingGlyph(index, ch);
|
||||
aTextRun->SetMissingGlyph(index, ch, mainFont);
|
||||
}
|
||||
}
|
||||
|
||||
@ -4329,13 +4439,13 @@ gfxFontStyle::ComputeWeight() const
|
||||
return baseWeight;
|
||||
}
|
||||
|
||||
// This is not a member function of gfxShapedWord because it is also used
|
||||
// by gfxFontGroup on missing-glyph runs, where we don't actually "shape"
|
||||
// anything but still need to set cluster info.
|
||||
/*static*/ void
|
||||
gfxShapedWord::SetupClusterBoundaries(CompressedGlyph *aGlyphs,
|
||||
const PRUnichar *aString, uint32_t aLength)
|
||||
void
|
||||
gfxShapedText::SetupClusterBoundaries(uint32_t aOffset,
|
||||
const PRUnichar *aString,
|
||||
uint32_t aLength)
|
||||
{
|
||||
CompressedGlyph *glyphs = GetCharacterGlyphs() + aOffset;
|
||||
|
||||
gfxTextRun::CompressedGlyph extendCluster;
|
||||
extendCluster.SetComplex(false, true, 0);
|
||||
|
||||
@ -4344,27 +4454,51 @@ gfxShapedWord::SetupClusterBoundaries(CompressedGlyph *aGlyphs,
|
||||
// the ClusterIterator won't be able to tell us if the string
|
||||
// _begins_ with a cluster-extender, so we handle that here
|
||||
if (aLength && IsClusterExtender(*aString)) {
|
||||
*aGlyphs = extendCluster;
|
||||
*glyphs = extendCluster;
|
||||
}
|
||||
|
||||
while (!iter.AtEnd()) {
|
||||
if (*iter == PRUnichar(' ')) {
|
||||
glyphs->SetIsSpace();
|
||||
}
|
||||
// advance iter to the next cluster-start (or end of text)
|
||||
iter.Next();
|
||||
// step past the first char of the cluster
|
||||
aString++;
|
||||
aGlyphs++;
|
||||
glyphs++;
|
||||
// mark all the rest as cluster-continuations
|
||||
while (aString < iter) {
|
||||
*aGlyphs++ = extendCluster;
|
||||
*glyphs = extendCluster;
|
||||
if (NS_IS_LOW_SURROGATE(*aString)) {
|
||||
glyphs->SetIsLowSurrogate();
|
||||
}
|
||||
glyphs++;
|
||||
aString++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gfxShapedWord::DetailedGlyph *
|
||||
gfxShapedWord::AllocateDetailedGlyphs(uint32_t aIndex, uint32_t aCount)
|
||||
void
|
||||
gfxShapedText::SetupClusterBoundaries(uint32_t aOffset,
|
||||
const uint8_t *aString,
|
||||
uint32_t aLength)
|
||||
{
|
||||
NS_ASSERTION(aIndex < Length(), "Index out of range");
|
||||
CompressedGlyph *glyphs = GetCharacterGlyphs() + aOffset;
|
||||
const uint8_t *limit = aString + aLength;
|
||||
|
||||
while (aString < limit) {
|
||||
if (*aString == uint8_t(' ')) {
|
||||
glyphs->SetIsSpace();
|
||||
}
|
||||
aString++;
|
||||
glyphs++;
|
||||
}
|
||||
}
|
||||
|
||||
gfxShapedText::DetailedGlyph *
|
||||
gfxShapedText::AllocateDetailedGlyphs(uint32_t aIndex, uint32_t aCount)
|
||||
{
|
||||
NS_ASSERTION(aIndex < GetLength(), "Index out of range");
|
||||
|
||||
if (!mDetailedGlyphs) {
|
||||
mDetailedGlyphs = new DetailedGlyphStore();
|
||||
@ -4372,7 +4506,7 @@ gfxShapedWord::AllocateDetailedGlyphs(uint32_t aIndex, uint32_t aCount)
|
||||
|
||||
DetailedGlyph *details = mDetailedGlyphs->Allocate(aIndex, aCount);
|
||||
if (!details) {
|
||||
mCharacterGlyphs[aIndex].SetMissing(0);
|
||||
GetCharacterGlyphs()[aIndex].SetMissing(0);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -4380,7 +4514,7 @@ gfxShapedWord::AllocateDetailedGlyphs(uint32_t aIndex, uint32_t aCount)
|
||||
}
|
||||
|
||||
void
|
||||
gfxShapedWord::SetGlyphs(uint32_t aIndex, CompressedGlyph aGlyph,
|
||||
gfxShapedText::SetGlyphs(uint32_t aIndex, CompressedGlyph aGlyph,
|
||||
const DetailedGlyph *aGlyphs)
|
||||
{
|
||||
NS_ASSERTION(!aGlyph.IsSimpleGlyph(), "Simple glyphs not handled here");
|
||||
@ -4395,7 +4529,7 @@ gfxShapedWord::SetGlyphs(uint32_t aIndex, CompressedGlyph aGlyph,
|
||||
}
|
||||
memcpy(details, aGlyphs, sizeof(DetailedGlyph)*glyphCount);
|
||||
}
|
||||
mCharacterGlyphs[aIndex] = aGlyph;
|
||||
GetCharacterGlyphs()[aIndex] = aGlyph;
|
||||
}
|
||||
|
||||
#define ZWNJ 0x200C
|
||||
@ -4408,8 +4542,15 @@ IsDefaultIgnorable(uint32_t aChar)
|
||||
}
|
||||
|
||||
void
|
||||
gfxShapedWord::SetMissingGlyph(uint32_t aIndex, uint32_t aChar, gfxFont *aFont)
|
||||
gfxShapedText::SetMissingGlyph(uint32_t aIndex, uint32_t aChar, gfxFont *aFont)
|
||||
{
|
||||
uint8_t category = GetGeneralCategory(aChar);
|
||||
if (category >= HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK &&
|
||||
category <= HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
|
||||
{
|
||||
GetCharacterGlyphs()[aIndex].SetComplex(false, true, 0);
|
||||
}
|
||||
|
||||
DetailedGlyph *details = AllocateDetailedGlyphs(aIndex, 1);
|
||||
if (!details) {
|
||||
return;
|
||||
@ -4426,21 +4567,20 @@ gfxShapedWord::SetMissingGlyph(uint32_t aIndex, uint32_t aChar, gfxFont *aFont)
|
||||
}
|
||||
details->mXOffset = 0;
|
||||
details->mYOffset = 0;
|
||||
mCharacterGlyphs[aIndex].SetMissing(1);
|
||||
GetCharacterGlyphs()[aIndex].SetMissing(1);
|
||||
}
|
||||
|
||||
bool
|
||||
gfxShapedWord::FilterIfIgnorable(uint32_t aIndex)
|
||||
gfxShapedText::FilterIfIgnorable(uint32_t aIndex, uint32_t aCh)
|
||||
{
|
||||
uint32_t ch = GetCharAt(aIndex);
|
||||
if (IsDefaultIgnorable(ch)) {
|
||||
if (IsDefaultIgnorable(aCh)) {
|
||||
DetailedGlyph *details = AllocateDetailedGlyphs(aIndex, 1);
|
||||
if (details) {
|
||||
details->mGlyphID = ch;
|
||||
details->mGlyphID = aCh;
|
||||
details->mAdvance = 0;
|
||||
details->mXOffset = 0;
|
||||
details->mYOffset = 0;
|
||||
mCharacterGlyphs[aIndex].SetMissing(1);
|
||||
GetCharacterGlyphs()[aIndex].SetMissing(1);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -4448,11 +4588,14 @@ gfxShapedWord::FilterIfIgnorable(uint32_t aIndex)
|
||||
}
|
||||
|
||||
void
|
||||
gfxShapedWord::AdjustAdvancesForSyntheticBold(float aSynBoldOffset)
|
||||
gfxShapedText::AdjustAdvancesForSyntheticBold(float aSynBoldOffset,
|
||||
uint32_t aOffset,
|
||||
uint32_t aLength)
|
||||
{
|
||||
uint32_t synAppUnitOffset = aSynBoldOffset * mAppUnitsPerDevUnit;
|
||||
for (uint32_t i = 0; i < Length(); ++i) {
|
||||
CompressedGlyph *glyphData = &mCharacterGlyphs[i];
|
||||
CompressedGlyph *charGlyphs = GetCharacterGlyphs();
|
||||
for (uint32_t i = aOffset; i < aOffset + aLength; ++i) {
|
||||
CompressedGlyph *glyphData = charGlyphs + i;
|
||||
if (glyphData->IsSimpleGlyph()) {
|
||||
// simple glyphs ==> just add the advance
|
||||
int32_t advance = glyphData->GetSimpleAdvance() + synAppUnitOffset;
|
||||
@ -4493,7 +4636,7 @@ gfxTextRun::GlyphRunIterator::NextRun() {
|
||||
|
||||
mStringStart = NS_MAX(mStartOffset, mGlyphRun->mCharacterOffset);
|
||||
uint32_t last = mNextIndex + 1 < mTextRun->mGlyphRuns.Length()
|
||||
? mTextRun->mGlyphRuns[mNextIndex + 1].mCharacterOffset : mTextRun->mCharacterCount;
|
||||
? mTextRun->mGlyphRuns[mNextIndex + 1].mCharacterOffset : mTextRun->GetLength();
|
||||
mStringEnd = NS_MIN(mEndOffset, last);
|
||||
|
||||
++mNextIndex;
|
||||
@ -4553,10 +4696,9 @@ gfxTextRun::Create(const gfxTextRunFactory::Parameters *aParams,
|
||||
|
||||
gfxTextRun::gfxTextRun(const gfxTextRunFactory::Parameters *aParams,
|
||||
uint32_t aLength, gfxFontGroup *aFontGroup, uint32_t aFlags)
|
||||
: mUserData(aParams->mUserData),
|
||||
mFontGroup(aFontGroup),
|
||||
mAppUnitsPerDevUnit(aParams->mAppUnitsPerDevUnit),
|
||||
mFlags(aFlags), mCharacterCount(aLength)
|
||||
: gfxShapedText(aLength, aFlags, aParams->mAppUnitsPerDevUnit)
|
||||
, mUserData(aParams->mUserData)
|
||||
, mFontGroup(aFontGroup)
|
||||
{
|
||||
NS_ASSERTION(mAppUnitsPerDevUnit != 0, "Invalid app unit scale");
|
||||
MOZ_COUNT_CTOR(gfxTextRun);
|
||||
@ -4594,7 +4736,7 @@ gfxTextRun::SetPotentialLineBreaks(uint32_t aStart, uint32_t aLength,
|
||||
uint8_t *aBreakBefore,
|
||||
gfxContext *aRefContext)
|
||||
{
|
||||
NS_ASSERTION(aStart + aLength <= mCharacterCount, "Overflow");
|
||||
NS_ASSERTION(aStart + aLength <= GetLength(), "Overflow");
|
||||
|
||||
uint32_t changed = 0;
|
||||
uint32_t i;
|
||||
@ -4617,7 +4759,7 @@ gfxTextRun::ComputeLigatureData(uint32_t aPartStart, uint32_t aPartEnd,
|
||||
PropertyProvider *aProvider)
|
||||
{
|
||||
NS_ASSERTION(aPartStart < aPartEnd, "Computing ligature data for empty range");
|
||||
NS_ASSERTION(aPartEnd <= mCharacterCount, "Character length overflow");
|
||||
NS_ASSERTION(aPartEnd <= GetLength(), "Character length overflow");
|
||||
|
||||
LigatureData result;
|
||||
CompressedGlyph *charGlyphs = mCharacterGlyphs;
|
||||
@ -4627,7 +4769,7 @@ gfxTextRun::ComputeLigatureData(uint32_t aPartStart, uint32_t aPartEnd,
|
||||
NS_ASSERTION(i > 0, "Ligature at the start of the run??");
|
||||
}
|
||||
result.mLigatureStart = i;
|
||||
for (i = aPartStart + 1; i < mCharacterCount && !charGlyphs[i].IsLigatureGroupStart(); ++i) {
|
||||
for (i = aPartStart + 1; i < GetLength() && !charGlyphs[i].IsLigatureGroupStart(); ++i) {
|
||||
}
|
||||
result.mLigatureEnd = i;
|
||||
|
||||
@ -4782,7 +4924,7 @@ gfxTextRun::ShrinkToLigatureBoundaries(uint32_t *aStart, uint32_t *aEnd)
|
||||
while (*aStart < *aEnd && !charGlyphs[*aStart].IsLigatureGroupStart()) {
|
||||
++(*aStart);
|
||||
}
|
||||
if (*aEnd < mCharacterCount) {
|
||||
if (*aEnd < GetLength()) {
|
||||
while (*aEnd > *aStart && !charGlyphs[*aEnd].IsLigatureGroupStart()) {
|
||||
--(*aEnd);
|
||||
}
|
||||
@ -4947,7 +5089,7 @@ gfxTextRun::Draw(gfxContext *aContext, gfxPoint aPt, gfxFont::DrawMode aDrawMode
|
||||
gfxTextObjectPaint *aObjectPaint,
|
||||
gfxTextRun::DrawCallbacks *aCallbacks)
|
||||
{
|
||||
NS_ASSERTION(aStart + aLength <= mCharacterCount, "Substring out of range");
|
||||
NS_ASSERTION(aStart + aLength <= GetLength(), "Substring out of range");
|
||||
NS_ASSERTION(aDrawMode <= gfxFont::GLYPH_PATH, "GLYPH_PATH cannot be used with GLYPH_FILL or GLYPH_STROKE");
|
||||
NS_ASSERTION(aDrawMode == gfxFont::GLYPH_PATH || !aCallbacks, "callback must not be specified unless using GLYPH_PATH");
|
||||
|
||||
@ -5085,7 +5227,7 @@ gfxTextRun::MeasureText(uint32_t aStart, uint32_t aLength,
|
||||
gfxContext *aRefContext,
|
||||
PropertyProvider *aProvider)
|
||||
{
|
||||
NS_ASSERTION(aStart + aLength <= mCharacterCount, "Substring out of range");
|
||||
NS_ASSERTION(aStart + aLength <= GetLength(), "Substring out of range");
|
||||
|
||||
Metrics accumulatedMetrics;
|
||||
GlyphRunIterator iter(this, aStart, aLength);
|
||||
@ -5133,9 +5275,9 @@ gfxTextRun::BreakAndMeasureText(uint32_t aStart, uint32_t aMaxLength,
|
||||
bool aCanWordWrap,
|
||||
gfxBreakPriority *aBreakPriority)
|
||||
{
|
||||
aMaxLength = NS_MIN(aMaxLength, mCharacterCount - aStart);
|
||||
aMaxLength = NS_MIN(aMaxLength, GetLength() - aStart);
|
||||
|
||||
NS_ASSERTION(aStart + aMaxLength <= mCharacterCount, "Substring out of range");
|
||||
NS_ASSERTION(aStart + aMaxLength <= GetLength(), "Substring out of range");
|
||||
|
||||
uint32_t bufferStart = aStart;
|
||||
uint32_t bufferLength = NS_MIN<uint32_t>(aMaxLength, MEASUREMENT_BUFFER_SIZE);
|
||||
@ -5294,7 +5436,7 @@ gfxFloat
|
||||
gfxTextRun::GetAdvanceWidth(uint32_t aStart, uint32_t aLength,
|
||||
PropertyProvider *aProvider)
|
||||
{
|
||||
NS_ASSERTION(aStart + aLength <= mCharacterCount, "Substring out of range");
|
||||
NS_ASSERTION(aStart + aLength <= GetLength(), "Substring out of range");
|
||||
|
||||
uint32_t ligatureRunStart = aStart;
|
||||
uint32_t ligatureRunEnd = aStart + aLength;
|
||||
@ -5338,10 +5480,10 @@ gfxTextRun::SetLineBreaks(uint32_t aStart, uint32_t aLength,
|
||||
uint32_t
|
||||
gfxTextRun::FindFirstGlyphRunContaining(uint32_t aOffset)
|
||||
{
|
||||
NS_ASSERTION(aOffset <= mCharacterCount, "Bad offset looking for glyphrun");
|
||||
NS_ASSERTION(mCharacterCount == 0 || mGlyphRuns.Length() > 0,
|
||||
NS_ASSERTION(aOffset <= GetLength(), "Bad offset looking for glyphrun");
|
||||
NS_ASSERTION(GetLength() == 0 || mGlyphRuns.Length() > 0,
|
||||
"non-empty text but no glyph runs present!");
|
||||
if (aOffset == mCharacterCount)
|
||||
if (aOffset == GetLength())
|
||||
return mGlyphRuns.Length();
|
||||
uint32_t start = 0;
|
||||
uint32_t end = mGlyphRuns.Length();
|
||||
@ -5459,13 +5601,13 @@ gfxTextRun::SanitizeGlyphRuns()
|
||||
for (i = lastRunIndex; i >= 0; --i) {
|
||||
GlyphRun& run = mGlyphRuns[i];
|
||||
while (charGlyphs[run.mCharacterOffset].IsLigatureContinuation() &&
|
||||
run.mCharacterOffset < mCharacterCount) {
|
||||
run.mCharacterOffset < GetLength()) {
|
||||
run.mCharacterOffset++;
|
||||
}
|
||||
// if the run has become empty, eliminate it
|
||||
if ((i < lastRunIndex &&
|
||||
run.mCharacterOffset >= mGlyphRuns[i+1].mCharacterOffset) ||
|
||||
(i == lastRunIndex && run.mCharacterOffset == mCharacterCount)) {
|
||||
(i == lastRunIndex && run.mCharacterOffset == GetLength())) {
|
||||
mGlyphRuns.RemoveElementAt(i);
|
||||
--lastRunIndex;
|
||||
}
|
||||
@ -5477,7 +5619,7 @@ gfxTextRun::CountMissingGlyphs()
|
||||
{
|
||||
uint32_t i;
|
||||
uint32_t count = 0;
|
||||
for (i = 0; i < mCharacterCount; ++i) {
|
||||
for (i = 0; i < GetLength(); ++i) {
|
||||
if (mCharacterGlyphs[i].IsMissing()) {
|
||||
++count;
|
||||
}
|
||||
@ -5488,7 +5630,7 @@ gfxTextRun::CountMissingGlyphs()
|
||||
gfxTextRun::DetailedGlyph *
|
||||
gfxTextRun::AllocateDetailedGlyphs(uint32_t aIndex, uint32_t aCount)
|
||||
{
|
||||
NS_ASSERTION(aIndex < mCharacterCount, "Index out of range");
|
||||
NS_ASSERTION(aIndex < GetLength(), "Index out of range");
|
||||
|
||||
if (!mDetailedGlyphs) {
|
||||
mDetailedGlyphs = new DetailedGlyphStore();
|
||||
@ -5504,65 +5646,19 @@ gfxTextRun::AllocateDetailedGlyphs(uint32_t aIndex, uint32_t aCount)
|
||||
}
|
||||
|
||||
void
|
||||
gfxTextRun::SetGlyphs(uint32_t aIndex, CompressedGlyph aGlyph,
|
||||
const DetailedGlyph *aGlyphs)
|
||||
gfxTextRun::CopyGlyphDataFrom(gfxShapedWord *aShapedWord, uint32_t aOffset)
|
||||
{
|
||||
NS_ASSERTION(!aGlyph.IsSimpleGlyph(), "Simple glyphs not handled here");
|
||||
NS_ASSERTION(aIndex > 0 || aGlyph.IsLigatureGroupStart(),
|
||||
"First character can't be a ligature continuation!");
|
||||
|
||||
uint32_t glyphCount = aGlyph.GetGlyphCount();
|
||||
if (glyphCount > 0) {
|
||||
DetailedGlyph *details = AllocateDetailedGlyphs(aIndex, glyphCount);
|
||||
if (!details)
|
||||
return;
|
||||
memcpy(details, aGlyphs, sizeof(DetailedGlyph)*glyphCount);
|
||||
}
|
||||
mCharacterGlyphs[aIndex] = aGlyph;
|
||||
}
|
||||
|
||||
void
|
||||
gfxTextRun::SetMissingGlyph(uint32_t aIndex, uint32_t aChar)
|
||||
{
|
||||
uint8_t category = GetGeneralCategory(aChar);
|
||||
if (category >= HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK &&
|
||||
category <= HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
|
||||
{
|
||||
mCharacterGlyphs[aIndex].SetComplex(false, true, 0);
|
||||
}
|
||||
|
||||
DetailedGlyph *details = AllocateDetailedGlyphs(aIndex, 1);
|
||||
if (!details)
|
||||
return;
|
||||
|
||||
details->mGlyphID = aChar;
|
||||
GlyphRun *glyphRun = &mGlyphRuns[FindFirstGlyphRunContaining(aIndex)];
|
||||
if (IsDefaultIgnorable(aChar)) {
|
||||
// Setting advance width to zero will prevent drawing the hexbox
|
||||
details->mAdvance = 0;
|
||||
} else {
|
||||
gfxFloat width = NS_MAX(glyphRun->mFont->GetMetrics().aveCharWidth,
|
||||
gfxFontMissingGlyphs::GetDesiredMinWidth(aChar));
|
||||
details->mAdvance = uint32_t(width*GetAppUnitsPerDevUnit());
|
||||
}
|
||||
details->mXOffset = 0;
|
||||
details->mYOffset = 0;
|
||||
mCharacterGlyphs[aIndex].SetMissing(1);
|
||||
}
|
||||
|
||||
void
|
||||
gfxTextRun::CopyGlyphDataFrom(const gfxShapedWord *aShapedWord, uint32_t aOffset)
|
||||
{
|
||||
uint32_t wordLen = aShapedWord->Length();
|
||||
uint32_t wordLen = aShapedWord->GetLength();
|
||||
NS_ASSERTION(aOffset + wordLen <= GetLength(),
|
||||
"word overruns end of textrun!");
|
||||
|
||||
CompressedGlyph *charGlyphs = GetCharacterGlyphs();
|
||||
const CompressedGlyph *wordGlyphs = aShapedWord->GetCharacterGlyphs();
|
||||
if (aShapedWord->HasDetailedGlyphs()) {
|
||||
for (uint32_t i = 0; i < wordLen; ++i, ++aOffset) {
|
||||
const CompressedGlyph& g = wordGlyphs[i];
|
||||
if (g.IsSimpleGlyph()) {
|
||||
SetSimpleGlyph(aOffset, g);
|
||||
charGlyphs[aOffset] = g;
|
||||
} else {
|
||||
const DetailedGlyph *details =
|
||||
g.GetGlyphCount() > 0 ?
|
||||
@ -5571,7 +5667,7 @@ gfxTextRun::CopyGlyphDataFrom(const gfxShapedWord *aShapedWord, uint32_t aOffset
|
||||
}
|
||||
}
|
||||
} else {
|
||||
memcpy(GetCharacterGlyphs() + aOffset, wordGlyphs,
|
||||
memcpy(charGlyphs + aOffset, wordGlyphs,
|
||||
wordLen * sizeof(CompressedGlyph));
|
||||
}
|
||||
}
|
||||
@ -5696,7 +5792,7 @@ gfxTextRun::SetSpaceGlyphIfSimple(gfxFont *aFont, gfxContext *aContext,
|
||||
if (aSpaceChar == ' ') {
|
||||
g.SetIsSpace();
|
||||
}
|
||||
SetSimpleGlyph(aCharIndex, g);
|
||||
GetCharacterGlyphs()[aCharIndex] = g;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -41,6 +41,7 @@ class gfxFontFamily;
|
||||
class gfxFontGroup;
|
||||
class gfxUserFontSet;
|
||||
class gfxUserFontData;
|
||||
class gfxShapedText;
|
||||
class gfxShapedWord;
|
||||
class gfxSVGGlyphs;
|
||||
class gfxTextObjectPaint;
|
||||
@ -1126,9 +1127,15 @@ public:
|
||||
|
||||
virtual ~gfxFontShaper() { }
|
||||
|
||||
virtual bool ShapeWord(gfxContext *aContext,
|
||||
gfxShapedWord *aShapedWord,
|
||||
const PRUnichar *aText) = 0;
|
||||
// Shape a piece of text and store the resulting glyph data into
|
||||
// aShapedText. Parameters aOffset/aLength indicate the range of
|
||||
// aShapedText to be updated; aLength is also the length of aText.
|
||||
virtual bool ShapeText(gfxContext *aContext,
|
||||
const PRUnichar *aText,
|
||||
uint32_t aOffset,
|
||||
uint32_t aLength,
|
||||
int32_t aScript,
|
||||
gfxShapedText *aShapedText) = 0;
|
||||
|
||||
gfxFont *GetFont() const { return mFont; }
|
||||
|
||||
@ -1561,13 +1568,61 @@ public:
|
||||
{ return gfxPlatform::GetPlatform()->GetScaledFontForFont(aTarget, this); }
|
||||
|
||||
protected:
|
||||
// For 8-bit text, expand to 16-bit and then call the following method.
|
||||
bool ShapeText(gfxContext *aContext,
|
||||
const uint8_t *aText,
|
||||
uint32_t aOffset, // dest offset in gfxShapedText
|
||||
uint32_t aLength,
|
||||
int32_t aScript,
|
||||
gfxShapedText *aShapedText, // where to store the result
|
||||
bool aPreferPlatformShaping = false);
|
||||
|
||||
// Call the appropriate shaper to generate glyphs for aText and store
|
||||
// them into aShapedWord.
|
||||
// The length of the text is aShapedWord->Length().
|
||||
virtual bool ShapeWord(gfxContext *aContext,
|
||||
gfxShapedWord *aShapedWord,
|
||||
// them into aShapedText.
|
||||
virtual bool ShapeText(gfxContext *aContext,
|
||||
const PRUnichar *aText,
|
||||
bool aPreferPlatformShaping = false);
|
||||
uint32_t aOffset,
|
||||
uint32_t aLength,
|
||||
int32_t aScript,
|
||||
gfxShapedText *aShapedText,
|
||||
bool aPreferPlatformShaping = false);
|
||||
|
||||
// Helper to adjust for synthetic bold and set character-type flags
|
||||
// in the shaped text; implementations of ShapeText should call this
|
||||
// after glyph shaping has been completed.
|
||||
void PostShapingFixup(gfxContext *aContext,
|
||||
const PRUnichar *aText,
|
||||
uint32_t aOffset, // position within aShapedText
|
||||
uint32_t aLength,
|
||||
gfxShapedText *aShapedText);
|
||||
|
||||
// Shape text directly into a range within a textrun, without using the
|
||||
// font's word cache. Intended for use when the font has layout features
|
||||
// that involve space, and therefore require shaping complete runs rather
|
||||
// than isolated words, or for long strings that are inefficient to cache.
|
||||
// This will split the text on "invalid" characters (tab/newline) that are
|
||||
// not handled via normal shaping, but does not otherwise divide up the
|
||||
// text.
|
||||
template<typename T>
|
||||
bool ShapeTextWithoutWordCache(gfxContext *aContext,
|
||||
const T *aText,
|
||||
uint32_t aOffset,
|
||||
uint32_t aLength,
|
||||
int32_t aScript,
|
||||
gfxTextRun *aTextRun);
|
||||
|
||||
// Shape a fragment of text (a run that is known to contain only
|
||||
// "valid" characters, no newlines/tabs/other control chars).
|
||||
// All non-wordcache shaping goes through here; this is the function
|
||||
// that will ensure we don't pass excessively long runs to the various
|
||||
// platform shapers.
|
||||
template<typename T>
|
||||
bool ShapeFragmentWithoutWordCache(gfxContext *aContext,
|
||||
const T *aText,
|
||||
uint32_t aOffset,
|
||||
uint32_t aLength,
|
||||
int32_t aScript,
|
||||
gfxTextRun *aTextRun);
|
||||
|
||||
nsRefPtr<gfxFontEntry> mFontEntry;
|
||||
|
||||
@ -1724,8 +1779,9 @@ protected:
|
||||
#define DEFAULT_XHEIGHT_FACTOR 0.56f
|
||||
|
||||
/*
|
||||
* gfxShapedWord stores a list of zero or more glyphs for each character. For each
|
||||
* glyph we store the glyph ID, the advance, and possibly an xoffset and yoffset.
|
||||
* gfxShapedText is an abstract superclass for gfxShapedWord and gfxTextRun.
|
||||
* These are objects that store a list of zero or more glyphs for each character.
|
||||
* For each glyph we store the glyph ID, the advance, and possibly x/y-offsets.
|
||||
* The idea is that a string is rendered by a loop that draws each glyph
|
||||
* at its designated offset from the current point, then advances the current
|
||||
* point by the glyph's advance in the direction of the textrun (LTR or RTL).
|
||||
@ -1736,83 +1792,22 @@ protected:
|
||||
* and the glyph ID and advance are in a reasonable range so we can pack all
|
||||
* necessary data into 32 bits.
|
||||
*
|
||||
* This glyph data is copied into gfxTextRuns as needed from the cache of
|
||||
* ShapedWords associated with each gfxFont instance.
|
||||
*
|
||||
* gfxTextRun methods that measure or draw substrings will associate all the
|
||||
* glyphs in a cluster with the first character of the cluster; if that character
|
||||
* is in the substring, the glyphs will be measured or drawn, otherwise they
|
||||
* won't.
|
||||
* gfxFontShaper can shape text into either a gfxShapedWord (cached by a gfxFont)
|
||||
* or directly into a gfxTextRun (for cases where we want to shape textruns in
|
||||
* their entirety rather than using cached words, because there may be layout
|
||||
* features that depend on the inter-word spaces).
|
||||
*/
|
||||
class gfxShapedWord
|
||||
class gfxShapedText
|
||||
{
|
||||
public:
|
||||
static const uint32_t kMaxLength = 0x7fff;
|
||||
gfxShapedText(uint32_t aLength, uint32_t aFlags,
|
||||
uint32_t aAppUnitsPerDevUnit)
|
||||
: mLength(aLength)
|
||||
, mFlags(aFlags)
|
||||
, mAppUnitsPerDevUnit(aAppUnitsPerDevUnit)
|
||||
{ }
|
||||
|
||||
// Create a ShapedWord that can hold glyphs for aLength characters,
|
||||
// with mCharacterGlyphs sized appropriately.
|
||||
//
|
||||
// Returns null on allocation failure (does NOT use infallible alloc)
|
||||
// so caller must check for success.
|
||||
//
|
||||
// This does NOT perform shaping, so the returned word contains no
|
||||
// glyph data; the caller must call gfxFont::Shape() with appropriate
|
||||
// parameters to set up the glyphs.
|
||||
static gfxShapedWord* Create(const uint8_t *aText, uint32_t aLength,
|
||||
int32_t aRunScript,
|
||||
int32_t aAppUnitsPerDevUnit,
|
||||
uint32_t aFlags) {
|
||||
NS_ASSERTION(aLength <= kMaxLength, "excessive length for gfxShapedWord!");
|
||||
|
||||
// Compute size needed including the mCharacterGlyphs array
|
||||
// and a copy of the original text
|
||||
uint32_t size =
|
||||
offsetof(gfxShapedWord, mCharacterGlyphs) +
|
||||
aLength * (sizeof(CompressedGlyph) + sizeof(uint8_t));
|
||||
void *storage = moz_malloc(size);
|
||||
if (!storage) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Construct in the pre-allocated storage, using placement new
|
||||
return new (storage) gfxShapedWord(aText, aLength, aRunScript,
|
||||
aAppUnitsPerDevUnit, aFlags);
|
||||
}
|
||||
|
||||
static gfxShapedWord* Create(const PRUnichar *aText, uint32_t aLength,
|
||||
int32_t aRunScript,
|
||||
int32_t aAppUnitsPerDevUnit,
|
||||
uint32_t aFlags) {
|
||||
NS_ASSERTION(aLength <= kMaxLength, "excessive length for gfxShapedWord!");
|
||||
|
||||
// In the 16-bit version of Create, if the TEXT_IS_8BIT flag is set,
|
||||
// then we convert the text to an 8-bit version and call the 8-bit
|
||||
// Create function instead.
|
||||
if (aFlags & gfxTextRunFactory::TEXT_IS_8BIT) {
|
||||
nsAutoCString narrowText;
|
||||
LossyAppendUTF16toASCII(nsDependentSubstring(aText, aLength),
|
||||
narrowText);
|
||||
return Create((const uint8_t*)(narrowText.BeginReading()),
|
||||
aLength, aRunScript, aAppUnitsPerDevUnit, aFlags);
|
||||
}
|
||||
|
||||
uint32_t size =
|
||||
offsetof(gfxShapedWord, mCharacterGlyphs) +
|
||||
aLength * (sizeof(CompressedGlyph) + sizeof(PRUnichar));
|
||||
void *storage = moz_malloc(size);
|
||||
if (!storage) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return new (storage) gfxShapedWord(aText, aLength, aRunScript,
|
||||
aAppUnitsPerDevUnit, aFlags);
|
||||
}
|
||||
|
||||
// Override operator delete to properly free the object that was
|
||||
// allocated via moz_malloc.
|
||||
void operator delete(void* p) {
|
||||
moz_free(p);
|
||||
}
|
||||
virtual ~gfxShapedText() { }
|
||||
|
||||
/**
|
||||
* This class records the information associated with a character in the
|
||||
@ -2012,6 +2007,10 @@ public:
|
||||
uint32_t mValue;
|
||||
};
|
||||
|
||||
// Accessor for the array of CompressedGlyph records, which will be in
|
||||
// a different place in gfxShapedWord vs gfxTextRun
|
||||
virtual CompressedGlyph *GetCharacterGlyphs() = 0;
|
||||
|
||||
/**
|
||||
* When the glyphs for a character don't fit into a CompressedGlyph record
|
||||
* in SimpleGlyph format, we use an array of DetailedGlyphs instead.
|
||||
@ -2028,35 +2027,59 @@ public:
|
||||
float mXOffset, mYOffset;
|
||||
};
|
||||
|
||||
void SetGlyphs(uint32_t aCharIndex, CompressedGlyph aGlyph,
|
||||
const DetailedGlyph *aGlyphs);
|
||||
|
||||
void SetMissingGlyph(uint32_t aIndex, uint32_t aChar, gfxFont *aFont);
|
||||
|
||||
void SetIsSpace(uint32_t aIndex) {
|
||||
GetCharacterGlyphs()[aIndex].SetIsSpace();
|
||||
}
|
||||
|
||||
void SetIsLowSurrogate(uint32_t aIndex) {
|
||||
SetGlyphs(aIndex, CompressedGlyph().SetComplex(false, false, 0), nullptr);
|
||||
GetCharacterGlyphs()[aIndex].SetIsLowSurrogate();
|
||||
}
|
||||
|
||||
bool HasDetailedGlyphs() const {
|
||||
return mDetailedGlyphs != nullptr;
|
||||
}
|
||||
|
||||
bool IsClusterStart(uint32_t aPos) {
|
||||
NS_ASSERTION(aPos < Length(), "aPos out of range");
|
||||
return mCharacterGlyphs[aPos].IsClusterStart();
|
||||
NS_ASSERTION(aPos < GetLength(), "aPos out of range");
|
||||
return GetCharacterGlyphs()[aPos].IsClusterStart();
|
||||
}
|
||||
|
||||
bool IsLigatureGroupStart(uint32_t aPos) {
|
||||
NS_ASSERTION(aPos < Length(), "aPos out of range");
|
||||
return mCharacterGlyphs[aPos].IsLigatureGroupStart();
|
||||
NS_ASSERTION(aPos < GetLength(), "aPos out of range");
|
||||
return GetCharacterGlyphs()[aPos].IsLigatureGroupStart();
|
||||
}
|
||||
|
||||
uint32_t Length() const {
|
||||
return mLength;
|
||||
// NOTE that this must not be called for a character offset that does
|
||||
// not have any DetailedGlyph records; callers must have verified that
|
||||
// GetCharacterGlyphs()[aCharIndex].GetGlyphCount() is greater than zero.
|
||||
DetailedGlyph *GetDetailedGlyphs(uint32_t aCharIndex) {
|
||||
NS_ASSERTION(GetCharacterGlyphs() && HasDetailedGlyphs() &&
|
||||
!GetCharacterGlyphs()[aCharIndex].IsSimpleGlyph() &&
|
||||
GetCharacterGlyphs()[aCharIndex].GetGlyphCount() > 0,
|
||||
"invalid use of GetDetailedGlyphs; check the caller!");
|
||||
return mDetailedGlyphs->Get(aCharIndex);
|
||||
}
|
||||
|
||||
const uint8_t* Text8Bit() const {
|
||||
NS_ASSERTION(TextIs8Bit(), "invalid use of Text8Bit()");
|
||||
return reinterpret_cast<const uint8_t*>(&mCharacterGlyphs[Length()]);
|
||||
}
|
||||
void AdjustAdvancesForSyntheticBold(float aSynBoldOffset,
|
||||
uint32_t aOffset, uint32_t aLength);
|
||||
|
||||
const PRUnichar* TextUnicode() const {
|
||||
NS_ASSERTION(!TextIs8Bit(), "invalid use of TextUnicode()");
|
||||
return reinterpret_cast<const PRUnichar*>(&mCharacterGlyphs[Length()]);
|
||||
}
|
||||
|
||||
PRUnichar GetCharAt(uint32_t aOffset) const {
|
||||
NS_ASSERTION(aOffset < Length(), "aOffset out of range");
|
||||
return TextIs8Bit() ?
|
||||
PRUnichar(Text8Bit()[aOffset]) : TextUnicode()[aOffset];
|
||||
}
|
||||
// Mark clusters in the CompressedGlyph records, starting at aOffset,
|
||||
// based on the Unicode properties of the text in aString.
|
||||
// This is also responsible to set the IsSpace flag for space characters.
|
||||
void SetupClusterBoundaries(uint32_t aOffset,
|
||||
const PRUnichar *aString,
|
||||
uint32_t aLength);
|
||||
// In 8-bit text, there won't actually be any clusters, but we still need
|
||||
// the space-marking functionality.
|
||||
void SetupClusterBoundaries(uint32_t aOffset,
|
||||
const uint8_t *aString,
|
||||
uint32_t aLength);
|
||||
|
||||
uint32_t Flags() const {
|
||||
return mFlags;
|
||||
@ -2078,105 +2101,17 @@ public:
|
||||
return (Flags() & gfxTextRunFactory::TEXT_IS_8BIT) != 0;
|
||||
}
|
||||
|
||||
int32_t Script() const {
|
||||
return mScript;
|
||||
}
|
||||
|
||||
int32_t AppUnitsPerDevUnit() const {
|
||||
uint32_t GetAppUnitsPerDevUnit() const {
|
||||
return mAppUnitsPerDevUnit;
|
||||
}
|
||||
|
||||
void ResetAge() {
|
||||
mAgeCounter = 0;
|
||||
}
|
||||
uint32_t IncrementAge() {
|
||||
return ++mAgeCounter;
|
||||
uint32_t GetLength() const {
|
||||
return mLength;
|
||||
}
|
||||
|
||||
void SetSimpleGlyph(uint32_t aCharIndex, CompressedGlyph aGlyph) {
|
||||
NS_ASSERTION(aGlyph.IsSimpleGlyph(), "Should be a simple glyph here");
|
||||
NS_ASSERTION(mCharacterGlyphs, "mCharacterGlyphs pointer is null!");
|
||||
mCharacterGlyphs[aCharIndex] = aGlyph;
|
||||
}
|
||||
|
||||
void SetGlyphs(uint32_t aCharIndex, CompressedGlyph aGlyph,
|
||||
const DetailedGlyph *aGlyphs);
|
||||
|
||||
void SetMissingGlyph(uint32_t aIndex, uint32_t aChar, gfxFont *aFont);
|
||||
|
||||
void SetIsSpace(uint32_t aIndex) {
|
||||
mCharacterGlyphs[aIndex].SetIsSpace();
|
||||
}
|
||||
|
||||
void SetIsLowSurrogate(uint32_t aIndex) {
|
||||
SetGlyphs(aIndex, CompressedGlyph().SetComplex(false, false, 0), nullptr);
|
||||
mCharacterGlyphs[aIndex].SetIsLowSurrogate();
|
||||
}
|
||||
|
||||
bool FilterIfIgnorable(uint32_t aIndex);
|
||||
|
||||
const CompressedGlyph *GetCharacterGlyphs() const {
|
||||
return &mCharacterGlyphs[0];
|
||||
}
|
||||
|
||||
bool HasDetailedGlyphs() const {
|
||||
return mDetailedGlyphs != nullptr;
|
||||
}
|
||||
|
||||
// NOTE that this must not be called for a character offset that does
|
||||
// not have any DetailedGlyph records; callers must have verified that
|
||||
// mCharacterGlyphs[aCharIndex].GetGlyphCount() is greater than zero.
|
||||
DetailedGlyph *GetDetailedGlyphs(uint32_t aCharIndex) const {
|
||||
NS_ASSERTION(HasDetailedGlyphs() &&
|
||||
!mCharacterGlyphs[aCharIndex].IsSimpleGlyph() &&
|
||||
mCharacterGlyphs[aCharIndex].GetGlyphCount() > 0,
|
||||
"invalid use of GetDetailedGlyphs; check the caller!");
|
||||
return mDetailedGlyphs->Get(aCharIndex);
|
||||
}
|
||||
|
||||
void AdjustAdvancesForSyntheticBold(float aSynBoldOffset);
|
||||
|
||||
// this is a public static method in order to make it available
|
||||
// for gfxTextRun to use directly on its own CompressedGlyph array,
|
||||
// in addition to the use within ShapedWord
|
||||
static void
|
||||
SetupClusterBoundaries(CompressedGlyph *aGlyphs,
|
||||
const PRUnichar *aString, uint32_t aLength);
|
||||
|
||||
private:
|
||||
// so that gfxTextRun can share our DetailedGlyphStore class
|
||||
friend class gfxTextRun;
|
||||
|
||||
// Construct storage for a ShapedWord, ready to receive glyph data
|
||||
gfxShapedWord(const uint8_t *aText, uint32_t aLength,
|
||||
int32_t aRunScript, int32_t aAppUnitsPerDevUnit,
|
||||
uint32_t aFlags)
|
||||
: mLength(aLength)
|
||||
, mFlags(aFlags | gfxTextRunFactory::TEXT_IS_8BIT)
|
||||
, mAppUnitsPerDevUnit(aAppUnitsPerDevUnit)
|
||||
, mScript(aRunScript)
|
||||
, mAgeCounter(0)
|
||||
{
|
||||
memset(mCharacterGlyphs, 0, aLength * sizeof(CompressedGlyph));
|
||||
uint8_t *text = reinterpret_cast<uint8_t*>(&mCharacterGlyphs[aLength]);
|
||||
memcpy(text, aText, aLength * sizeof(uint8_t));
|
||||
}
|
||||
|
||||
gfxShapedWord(const PRUnichar *aText, uint32_t aLength,
|
||||
int32_t aRunScript, int32_t aAppUnitsPerDevUnit,
|
||||
uint32_t aFlags)
|
||||
: mLength(aLength)
|
||||
, mFlags(aFlags)
|
||||
, mAppUnitsPerDevUnit(aAppUnitsPerDevUnit)
|
||||
, mScript(aRunScript)
|
||||
, mAgeCounter(0)
|
||||
{
|
||||
memset(mCharacterGlyphs, 0, aLength * sizeof(CompressedGlyph));
|
||||
PRUnichar *text = reinterpret_cast<PRUnichar*>(&mCharacterGlyphs[aLength]);
|
||||
memcpy(text, aText, aLength * sizeof(PRUnichar));
|
||||
SetupClusterBoundaries(&mCharacterGlyphs[0], aText, aLength);
|
||||
}
|
||||
bool FilterIfIgnorable(uint32_t aIndex, uint32_t aCh);
|
||||
|
||||
protected:
|
||||
// Allocate aCount DetailedGlyphs for the given index
|
||||
DetailedGlyph *AllocateDetailedGlyphs(uint32_t aCharIndex,
|
||||
uint32_t aCount);
|
||||
@ -2303,25 +2238,164 @@ private:
|
||||
|
||||
nsAutoPtr<DetailedGlyphStore> mDetailedGlyphs;
|
||||
|
||||
// Number of PRUnichar characters and CompressedGlyph glyph records;
|
||||
// note that gfx font code will never attempt to create a ShapedWord
|
||||
// with a huge number of characters, so we could limit this to 16 bits
|
||||
// to minimize memory usage for large numbers of cached words.
|
||||
// Number of PRUnichar characters and CompressedGlyph glyph records
|
||||
uint32_t mLength;
|
||||
|
||||
// Shaping flags (direction, ligature-suppression)
|
||||
uint32_t mFlags;
|
||||
|
||||
int32_t mAppUnitsPerDevUnit;
|
||||
int32_t mScript;
|
||||
uint32_t mAppUnitsPerDevUnit;
|
||||
};
|
||||
|
||||
uint32_t mAgeCounter;
|
||||
/*
|
||||
* gfxShapedWord: an individual (space-delimited) run of text shaped with a
|
||||
* particular font, without regard to external context.
|
||||
*
|
||||
* The glyph data is copied into gfxTextRuns as needed from the cache of
|
||||
* ShapedWords associated with each gfxFont instance.
|
||||
*/
|
||||
class gfxShapedWord : public gfxShapedText
|
||||
{
|
||||
public:
|
||||
static const uint32_t kMaxLength = 0x7fff;
|
||||
|
||||
// The mCharacterGlyphs array is actually a variable-size member;
|
||||
// Create a ShapedWord that can hold glyphs for aLength characters,
|
||||
// with mCharacterGlyphs sized appropriately.
|
||||
//
|
||||
// Returns null on allocation failure (does NOT use infallible alloc)
|
||||
// so caller must check for success.
|
||||
//
|
||||
// This does NOT perform shaping, so the returned word contains no
|
||||
// glyph data; the caller must call gfxFont::ShapeText() with appropriate
|
||||
// parameters to set up the glyphs.
|
||||
static gfxShapedWord* Create(const uint8_t *aText, uint32_t aLength,
|
||||
int32_t aRunScript,
|
||||
int32_t aAppUnitsPerDevUnit,
|
||||
uint32_t aFlags) {
|
||||
NS_ASSERTION(aLength <= kMaxLength, "excessive length for gfxShapedWord!");
|
||||
|
||||
// Compute size needed including the mCharacterGlyphs array
|
||||
// and a copy of the original text
|
||||
uint32_t size =
|
||||
offsetof(gfxShapedWord, mCharGlyphsStorage) +
|
||||
aLength * (sizeof(CompressedGlyph) + sizeof(uint8_t));
|
||||
void *storage = moz_malloc(size);
|
||||
if (!storage) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Construct in the pre-allocated storage, using placement new
|
||||
return new (storage) gfxShapedWord(aText, aLength, aRunScript,
|
||||
aAppUnitsPerDevUnit, aFlags);
|
||||
}
|
||||
|
||||
static gfxShapedWord* Create(const PRUnichar *aText, uint32_t aLength,
|
||||
int32_t aRunScript,
|
||||
int32_t aAppUnitsPerDevUnit,
|
||||
uint32_t aFlags) {
|
||||
NS_ASSERTION(aLength <= kMaxLength, "excessive length for gfxShapedWord!");
|
||||
|
||||
// In the 16-bit version of Create, if the TEXT_IS_8BIT flag is set,
|
||||
// then we convert the text to an 8-bit version and call the 8-bit
|
||||
// Create function instead.
|
||||
if (aFlags & gfxTextRunFactory::TEXT_IS_8BIT) {
|
||||
nsAutoCString narrowText;
|
||||
LossyAppendUTF16toASCII(nsDependentSubstring(aText, aLength),
|
||||
narrowText);
|
||||
return Create((const uint8_t*)(narrowText.BeginReading()),
|
||||
aLength, aRunScript, aAppUnitsPerDevUnit, aFlags);
|
||||
}
|
||||
|
||||
uint32_t size =
|
||||
offsetof(gfxShapedWord, mCharGlyphsStorage) +
|
||||
aLength * (sizeof(CompressedGlyph) + sizeof(PRUnichar));
|
||||
void *storage = moz_malloc(size);
|
||||
if (!storage) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return new (storage) gfxShapedWord(aText, aLength, aRunScript,
|
||||
aAppUnitsPerDevUnit, aFlags);
|
||||
}
|
||||
|
||||
// Override operator delete to properly free the object that was
|
||||
// allocated via moz_malloc.
|
||||
void operator delete(void* p) {
|
||||
moz_free(p);
|
||||
}
|
||||
|
||||
CompressedGlyph *GetCharacterGlyphs() {
|
||||
return &mCharGlyphsStorage[0];
|
||||
}
|
||||
|
||||
const uint8_t* Text8Bit() const {
|
||||
NS_ASSERTION(TextIs8Bit(), "invalid use of Text8Bit()");
|
||||
return reinterpret_cast<const uint8_t*>(mCharGlyphsStorage + GetLength());
|
||||
}
|
||||
|
||||
const PRUnichar* TextUnicode() const {
|
||||
NS_ASSERTION(!TextIs8Bit(), "invalid use of TextUnicode()");
|
||||
return reinterpret_cast<const PRUnichar*>(mCharGlyphsStorage + GetLength());
|
||||
}
|
||||
|
||||
PRUnichar GetCharAt(uint32_t aOffset) const {
|
||||
NS_ASSERTION(aOffset < GetLength(), "aOffset out of range");
|
||||
return TextIs8Bit() ?
|
||||
PRUnichar(Text8Bit()[aOffset]) : TextUnicode()[aOffset];
|
||||
}
|
||||
|
||||
int32_t Script() const {
|
||||
return mScript;
|
||||
}
|
||||
|
||||
void ResetAge() {
|
||||
mAgeCounter = 0;
|
||||
}
|
||||
uint32_t IncrementAge() {
|
||||
return ++mAgeCounter;
|
||||
}
|
||||
|
||||
private:
|
||||
// so that gfxTextRun can share our DetailedGlyphStore class
|
||||
friend class gfxTextRun;
|
||||
|
||||
// Construct storage for a ShapedWord, ready to receive glyph data
|
||||
gfxShapedWord(const uint8_t *aText, uint32_t aLength,
|
||||
int32_t aRunScript, int32_t aAppUnitsPerDevUnit,
|
||||
uint32_t aFlags)
|
||||
: gfxShapedText(aLength, aFlags | gfxTextRunFactory::TEXT_IS_8BIT,
|
||||
aAppUnitsPerDevUnit)
|
||||
, mScript(aRunScript)
|
||||
, mAgeCounter(0)
|
||||
{
|
||||
memset(mCharGlyphsStorage, 0, aLength * sizeof(CompressedGlyph));
|
||||
uint8_t *text = reinterpret_cast<uint8_t*>(&mCharGlyphsStorage[aLength]);
|
||||
memcpy(text, aText, aLength * sizeof(uint8_t));
|
||||
}
|
||||
|
||||
gfxShapedWord(const PRUnichar *aText, uint32_t aLength,
|
||||
int32_t aRunScript, int32_t aAppUnitsPerDevUnit,
|
||||
uint32_t aFlags)
|
||||
: gfxShapedText(aLength, aFlags, aAppUnitsPerDevUnit)
|
||||
, mScript(aRunScript)
|
||||
, mAgeCounter(0)
|
||||
{
|
||||
memset(mCharGlyphsStorage, 0, aLength * sizeof(CompressedGlyph));
|
||||
PRUnichar *text = reinterpret_cast<PRUnichar*>(&mCharGlyphsStorage[aLength]);
|
||||
memcpy(text, aText, aLength * sizeof(PRUnichar));
|
||||
SetupClusterBoundaries(0, aText, aLength);
|
||||
}
|
||||
|
||||
int32_t mScript;
|
||||
|
||||
uint32_t mAgeCounter;
|
||||
|
||||
// The mCharGlyphsStorage array is actually a variable-size member;
|
||||
// when the ShapedWord is created, its size will be increased as necessary
|
||||
// to allow the proper number of glyphs to be stored.
|
||||
// The original text, in either 8-bit or 16-bit form, will be stored
|
||||
// immediately following the CompressedGlyphs.
|
||||
CompressedGlyph mCharacterGlyphs[1];
|
||||
CompressedGlyph mCharGlyphsStorage[1];
|
||||
};
|
||||
|
||||
/**
|
||||
@ -2343,13 +2417,8 @@ private:
|
||||
* It is important that zero-length substrings are handled correctly. This will
|
||||
* be on the test!
|
||||
*/
|
||||
class THEBES_API gfxTextRun {
|
||||
class THEBES_API gfxTextRun : public gfxShapedText {
|
||||
public:
|
||||
// we use the same glyph storage as gfxShapedWord, to facilitate copying
|
||||
// glyph data from shaped words into text runs as needed
|
||||
typedef gfxShapedWord::CompressedGlyph CompressedGlyph;
|
||||
typedef gfxShapedWord::DetailedGlyph DetailedGlyph;
|
||||
typedef gfxShapedWord::DetailedGlyphStore DetailedGlyphStore;
|
||||
|
||||
// Override operator delete to properly free the object that was
|
||||
// allocated via moz_malloc.
|
||||
@ -2364,42 +2433,42 @@ public:
|
||||
// Public textrun API for general use
|
||||
|
||||
bool IsClusterStart(uint32_t aPos) {
|
||||
NS_ASSERTION(aPos < mCharacterCount, "aPos out of range");
|
||||
NS_ASSERTION(aPos < GetLength(), "aPos out of range");
|
||||
return mCharacterGlyphs[aPos].IsClusterStart();
|
||||
}
|
||||
bool IsLigatureGroupStart(uint32_t aPos) {
|
||||
NS_ASSERTION(aPos < mCharacterCount, "aPos out of range");
|
||||
NS_ASSERTION(aPos < GetLength(), "aPos out of range");
|
||||
return mCharacterGlyphs[aPos].IsLigatureGroupStart();
|
||||
}
|
||||
bool CanBreakLineBefore(uint32_t aPos) {
|
||||
NS_ASSERTION(aPos < mCharacterCount, "aPos out of range");
|
||||
NS_ASSERTION(aPos < GetLength(), "aPos out of range");
|
||||
return mCharacterGlyphs[aPos].CanBreakBefore() ==
|
||||
CompressedGlyph::FLAG_BREAK_TYPE_NORMAL;
|
||||
}
|
||||
bool CanHyphenateBefore(uint32_t aPos) {
|
||||
NS_ASSERTION(aPos < mCharacterCount, "aPos out of range");
|
||||
NS_ASSERTION(aPos < GetLength(), "aPos out of range");
|
||||
return mCharacterGlyphs[aPos].CanBreakBefore() ==
|
||||
CompressedGlyph::FLAG_BREAK_TYPE_HYPHEN;
|
||||
}
|
||||
|
||||
bool CharIsSpace(uint32_t aPos) {
|
||||
NS_ASSERTION(aPos < mCharacterCount, "aPos out of range");
|
||||
NS_ASSERTION(aPos < GetLength(), "aPos out of range");
|
||||
return mCharacterGlyphs[aPos].CharIsSpace();
|
||||
}
|
||||
bool CharIsTab(uint32_t aPos) {
|
||||
NS_ASSERTION(aPos < mCharacterCount, "aPos out of range");
|
||||
NS_ASSERTION(aPos < GetLength(), "aPos out of range");
|
||||
return mCharacterGlyphs[aPos].CharIsTab();
|
||||
}
|
||||
bool CharIsNewline(uint32_t aPos) {
|
||||
NS_ASSERTION(aPos < mCharacterCount, "aPos out of range");
|
||||
NS_ASSERTION(aPos < GetLength(), "aPos out of range");
|
||||
return mCharacterGlyphs[aPos].CharIsNewline();
|
||||
}
|
||||
bool CharIsLowSurrogate(uint32_t aPos) {
|
||||
NS_ASSERTION(aPos < mCharacterCount, "aPos out of range");
|
||||
NS_ASSERTION(aPos < GetLength(), "aPos out of range");
|
||||
return mCharacterGlyphs[aPos].CharIsLowSurrogate();
|
||||
}
|
||||
|
||||
uint32_t GetLength() { return mCharacterCount; }
|
||||
uint32_t GetLength() { return mLength; }
|
||||
|
||||
// All uint32_t aStart, uint32_t aLength ranges below are restricted to
|
||||
// grapheme cluster boundaries! All offsets are in terms of the string
|
||||
@ -2655,7 +2724,6 @@ public:
|
||||
|
||||
// Utility getters
|
||||
|
||||
bool IsRightToLeft() const { return (mFlags & gfxTextRunFactory::TEXT_IS_RTL) != 0; }
|
||||
gfxFloat GetDirection() const { return (mFlags & gfxTextRunFactory::TEXT_IS_RTL) ? -1.0 : 1.0; }
|
||||
void *GetUserData() const { return mUserData; }
|
||||
void SetUserData(void *aUserData) { mUserData = aUserData; }
|
||||
@ -2671,7 +2739,6 @@ public:
|
||||
mFlags &= ~aFlags;
|
||||
}
|
||||
const gfxSkipChars& GetSkipChars() const { return mSkipChars; }
|
||||
uint32_t GetAppUnitsPerDevUnit() const { return mAppUnitsPerDevUnit; }
|
||||
gfxFontGroup *GetFontGroup() const { return mFontGroup; }
|
||||
|
||||
|
||||
@ -2747,20 +2814,11 @@ public:
|
||||
void SortGlyphRuns();
|
||||
void SanitizeGlyphRuns();
|
||||
|
||||
// Call the following glyph-setters during initialization or during reshaping
|
||||
// only. It is OK to overwrite existing data for a character.
|
||||
void SetSimpleGlyph(uint32_t aCharIndex, CompressedGlyph aGlyph) {
|
||||
NS_ASSERTION(aGlyph.IsSimpleGlyph(), "Should be a simple glyph here");
|
||||
mCharacterGlyphs[aCharIndex] = aGlyph;
|
||||
CompressedGlyph* GetCharacterGlyphs() {
|
||||
NS_ASSERTION(mCharacterGlyphs, "failed to initialize mCharacterGlyphs");
|
||||
return mCharacterGlyphs;
|
||||
}
|
||||
/**
|
||||
* Set the glyph data for a character. aGlyphs may be null if aGlyph is a
|
||||
* simple glyph or has no associated glyphs. If non-null the data is copied,
|
||||
* the caller retains ownership.
|
||||
*/
|
||||
void SetGlyphs(uint32_t aCharIndex, CompressedGlyph aGlyph,
|
||||
const DetailedGlyph *aGlyphs);
|
||||
void SetMissingGlyph(uint32_t aCharIndex, uint32_t aUnicodeChar);
|
||||
|
||||
void SetSpaceGlyph(gfxFont *aFont, gfxContext *aContext, uint32_t aCharIndex);
|
||||
|
||||
// Set the glyph data for the given character index to the font's
|
||||
@ -2820,22 +2878,6 @@ public:
|
||||
*/
|
||||
void FetchGlyphExtents(gfxContext *aRefContext);
|
||||
|
||||
// API for access to the raw glyph data, needed by gfxFont::Draw
|
||||
// and gfxFont::GetBoundingBox
|
||||
CompressedGlyph *GetCharacterGlyphs() { return mCharacterGlyphs; }
|
||||
|
||||
// NOTE that this must not be called for a character offset that does
|
||||
// not have any DetailedGlyph records; callers must have verified that
|
||||
// mCharacterGlyphs[aCharIndex].GetGlyphCount() is greater than zero.
|
||||
DetailedGlyph *GetDetailedGlyphs(uint32_t aCharIndex) {
|
||||
NS_ASSERTION(mDetailedGlyphs != nullptr &&
|
||||
!mCharacterGlyphs[aCharIndex].IsSimpleGlyph() &&
|
||||
mCharacterGlyphs[aCharIndex].GetGlyphCount() > 0,
|
||||
"invalid use of GetDetailedGlyphs; check the caller!");
|
||||
return mDetailedGlyphs->Get(aCharIndex);
|
||||
}
|
||||
|
||||
bool HasDetailedGlyphs() { return mDetailedGlyphs != nullptr; }
|
||||
uint32_t CountMissingGlyphs();
|
||||
const GlyphRun *GetGlyphRuns(uint32_t *aNumGlyphRuns) {
|
||||
*aNumGlyphRuns = mGlyphRuns.Length();
|
||||
@ -2846,7 +2888,7 @@ public:
|
||||
uint32_t FindFirstGlyphRunContaining(uint32_t aOffset);
|
||||
|
||||
// Copy glyph data from a ShapedWord into this textrun.
|
||||
void CopyGlyphDataFrom(const gfxShapedWord *aSource, uint32_t aStart);
|
||||
void CopyGlyphDataFrom(gfxShapedWord *aSource, uint32_t aStart);
|
||||
|
||||
// Copy glyph data for a range of characters from aSource to this
|
||||
// textrun.
|
||||
@ -2911,11 +2953,9 @@ protected:
|
||||
*/
|
||||
static void* AllocateStorageForTextRun(size_t aSize, uint32_t aLength);
|
||||
|
||||
// All our glyph data is in logical order, not visual.
|
||||
// Space for mCharacterGlyphs is allocated fused with the textrun object,
|
||||
// and then the constructor sets the pointer to the beginning of this
|
||||
// storage area. Thus, this pointer must NOT be freed!
|
||||
CompressedGlyph *mCharacterGlyphs;
|
||||
// Pointer to the array of CompressedGlyph records; must be initialized
|
||||
// when the object is constructed.
|
||||
CompressedGlyph *mCharacterGlyphs;
|
||||
|
||||
private:
|
||||
// **** general helpers ****
|
||||
@ -2975,8 +3015,6 @@ private:
|
||||
uint32_t aEnd, PropertyProvider *aProvider,
|
||||
uint32_t aSpacingStart, uint32_t aSpacingEnd);
|
||||
|
||||
nsAutoPtr<DetailedGlyphStore> mDetailedGlyphs;
|
||||
|
||||
// XXX this should be changed to a GlyphRun plus a maybe-null GlyphRun*,
|
||||
// for smaller size especially in the super-common one-glyphrun case
|
||||
nsAutoTArray<GlyphRun,1> mGlyphRuns;
|
||||
@ -2985,9 +3023,6 @@ private:
|
||||
gfxFontGroup *mFontGroup; // addrefed
|
||||
gfxSkipChars mSkipChars;
|
||||
nsExpirationState mExpirationState;
|
||||
uint32_t mAppUnitsPerDevUnit;
|
||||
uint32_t mFlags;
|
||||
uint32_t mCharacterCount;
|
||||
|
||||
bool mSkipDrawing; // true if the font group we used had a user font
|
||||
// download that's in progress, so we should hide text
|
||||
|
@ -82,10 +82,11 @@ gfxGDIFont::CopyWithAntialiasOption(AntialiasOption anAAOption)
|
||||
}
|
||||
|
||||
static bool
|
||||
UseUniscribe(gfxShapedWord *aShapedWord,
|
||||
const PRUnichar *aString)
|
||||
UseUniscribe(gfxShapedText *aShapedText,
|
||||
const PRUnichar *aText,
|
||||
uint32_t aLength)
|
||||
{
|
||||
uint32_t flags = aShapedWord->Flags();
|
||||
uint32_t flags = aShapedText->Flags();
|
||||
bool useGDI;
|
||||
|
||||
bool isXP = (gfxWindowsPlatform::WindowsOSVersion()
|
||||
@ -101,14 +102,17 @@ UseUniscribe(gfxShapedWord *aShapedWord,
|
||||
) == gfxTextRunFactory::TEXT_OPTIMIZE_SPEED;
|
||||
|
||||
return !useGDI ||
|
||||
ScriptIsComplex(aString, aShapedWord->Length(), SIC_COMPLEX) == S_OK;
|
||||
ScriptIsComplex(aText, aLength, SIC_COMPLEX) == S_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
gfxGDIFont::ShapeWord(gfxContext *aContext,
|
||||
gfxShapedWord *aShapedWord,
|
||||
const PRUnichar *aString,
|
||||
bool aPreferPlatformShaping)
|
||||
gfxGDIFont::ShapeText(gfxContext *aContext,
|
||||
const PRUnichar *aText,
|
||||
uint32_t aOffset,
|
||||
uint32_t aLength,
|
||||
int32_t aScript,
|
||||
gfxShapedText *aShapedText,
|
||||
bool aPreferPlatformShaping)
|
||||
{
|
||||
if (!mMetrics) {
|
||||
Initialize();
|
||||
@ -130,13 +134,16 @@ gfxGDIFont::ShapeWord(gfxContext *aContext,
|
||||
|
||||
#ifdef MOZ_GRAPHITE
|
||||
if (mGraphiteShaper && gfxPlatform::GetPlatform()->UseGraphiteShaping()) {
|
||||
ok = mGraphiteShaper->ShapeWord(aContext, aShapedWord, aString);
|
||||
ok = mGraphiteShaper->ShapeText(aContext, aText,
|
||||
aOffset, aLength,
|
||||
aScript, aShapedText);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!ok && mHarfBuzzShaper) {
|
||||
if (gfxPlatform::GetPlatform()->UseHarfBuzzForScript(aShapedWord->Script())) {
|
||||
ok = mHarfBuzzShaper->ShapeWord(aContext, aShapedWord, aString);
|
||||
if (gfxPlatform::GetPlatform()->UseHarfBuzzForScript(aScript)) {
|
||||
ok = mHarfBuzzShaper->ShapeText(aContext, aText, aOffset, aLength,
|
||||
aScript, aShapedText);
|
||||
}
|
||||
}
|
||||
|
||||
@ -145,41 +152,42 @@ gfxGDIFont::ShapeWord(gfxContext *aContext,
|
||||
bool preferUniscribe =
|
||||
(!fe->IsTrueType() || fe->IsSymbolFont()) && !fe->mForceGDI;
|
||||
|
||||
if (preferUniscribe || UseUniscribe(aShapedWord, aString)) {
|
||||
if (preferUniscribe || UseUniscribe(aShapedText, aText, aLength)) {
|
||||
// first try Uniscribe
|
||||
if (!mUniscribeShaper) {
|
||||
mUniscribeShaper = new gfxUniscribeShaper(this);
|
||||
}
|
||||
|
||||
ok = mUniscribeShaper->ShapeWord(aContext, aShapedWord, aString);
|
||||
if (ok) {
|
||||
return true;
|
||||
}
|
||||
ok = mUniscribeShaper->ShapeText(aContext, aText, aOffset, aLength,
|
||||
aScript, aShapedText);
|
||||
if (!ok) {
|
||||
// fallback to GDI shaping
|
||||
if (!mPlatformShaper) {
|
||||
CreatePlatformShaper();
|
||||
}
|
||||
|
||||
// fallback to GDI shaping
|
||||
if (!mPlatformShaper) {
|
||||
CreatePlatformShaper();
|
||||
ok = mPlatformShaper->ShapeText(aContext, aText, aOffset,
|
||||
aLength, aScript, aShapedText);
|
||||
}
|
||||
|
||||
ok = mPlatformShaper->ShapeWord(aContext, aShapedWord, aString);
|
||||
} else {
|
||||
// first use GDI
|
||||
if (!mPlatformShaper) {
|
||||
CreatePlatformShaper();
|
||||
}
|
||||
|
||||
ok = mPlatformShaper->ShapeWord(aContext, aShapedWord, aString);
|
||||
if (ok) {
|
||||
return true;
|
||||
}
|
||||
ok = mPlatformShaper->ShapeText(aContext, aText, aOffset, aLength,
|
||||
aScript, aShapedText);
|
||||
if (!ok) {
|
||||
// try Uniscribe if GDI failed
|
||||
if (!mUniscribeShaper) {
|
||||
mUniscribeShaper = new gfxUniscribeShaper(this);
|
||||
}
|
||||
|
||||
// try Uniscribe if GDI failed
|
||||
if (!mUniscribeShaper) {
|
||||
mUniscribeShaper = new gfxUniscribeShaper(this);
|
||||
// use Uniscribe shaping
|
||||
ok = mUniscribeShaper->ShapeText(aContext, aText,
|
||||
aOffset, aLength,
|
||||
aScript, aShapedText);
|
||||
}
|
||||
|
||||
// use Uniscribe shaping
|
||||
ok = mUniscribeShaper->ShapeWord(aContext, aShapedWord, aString);
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
@ -196,11 +204,7 @@ gfxGDIFont::ShapeWord(gfxContext *aContext,
|
||||
#endif
|
||||
}
|
||||
|
||||
if (ok && IsSyntheticBold()) {
|
||||
float synBoldOffset =
|
||||
GetSyntheticBoldOffset() * CalcXScale(aContext);
|
||||
aShapedWord->AdjustAdvancesForSyntheticBold(synBoldOffset);
|
||||
}
|
||||
PostShapingFixup(aContext, aText, aOffset, aLength, aShapedText);
|
||||
|
||||
return ok;
|
||||
}
|
||||
@ -421,14 +425,11 @@ gfxGDIFont::Initialize()
|
||||
mMetrics->zeroOrAveCharWidth = mMetrics->aveCharWidth;
|
||||
}
|
||||
|
||||
mSpaceGlyph = 0;
|
||||
if (metrics.tmPitchAndFamily & TMPF_TRUETYPE) {
|
||||
WORD glyph;
|
||||
DWORD ret = GetGlyphIndicesW(dc.GetDC(), L" ", 1, &glyph,
|
||||
GGI_MARK_NONEXISTING_GLYPHS);
|
||||
if (ret != GDI_ERROR && glyph != 0xFFFF) {
|
||||
mSpaceGlyph = glyph;
|
||||
}
|
||||
WORD glyph;
|
||||
DWORD ret = GetGlyphIndicesW(dc.GetDC(), L" ", 1, &glyph,
|
||||
GGI_MARK_NONEXISTING_GLYPHS);
|
||||
if (ret != GDI_ERROR && glyph != 0xFFFF) {
|
||||
mSpaceGlyph = glyph;
|
||||
}
|
||||
|
||||
SanitizeMetrics(mMetrics, GetFontEntry()->mIsBadUnderlineFont);
|
||||
|
@ -64,10 +64,13 @@ protected:
|
||||
virtual void CreatePlatformShaper();
|
||||
|
||||
/* override to check for uniscribe failure and fall back to GDI */
|
||||
virtual bool ShapeWord(gfxContext *aContext,
|
||||
gfxShapedWord *aShapedWord,
|
||||
const PRUnichar *aString,
|
||||
bool aPreferPlatformShaping = false);
|
||||
virtual bool ShapeText(gfxContext *aContext,
|
||||
const PRUnichar *aText,
|
||||
uint32_t aOffset,
|
||||
uint32_t aLength,
|
||||
int32_t aScript,
|
||||
gfxShapedText *aShapedText,
|
||||
bool aPreferPlatformShaping);
|
||||
|
||||
void Initialize(); // creates metrics and Cairo fonts
|
||||
|
||||
|
@ -14,21 +14,24 @@
|
||||
**********************************************************************/
|
||||
|
||||
bool
|
||||
gfxGDIShaper::ShapeWord(gfxContext *aContext,
|
||||
gfxShapedWord *aShapedWord,
|
||||
const PRUnichar *aString)
|
||||
gfxGDIShaper::ShapeText(gfxContext *aContext,
|
||||
const PRUnichar *aText,
|
||||
uint32_t aOffset,
|
||||
uint32_t aLength,
|
||||
int32_t aScript,
|
||||
gfxShapedText *aShapedText)
|
||||
{
|
||||
DCFromContext dc(aContext);
|
||||
AutoSelectFont selectFont(dc, static_cast<gfxGDIFont*>(mFont)->GetHFONT());
|
||||
|
||||
uint32_t length = aShapedWord->Length();
|
||||
uint32_t length = aLength;
|
||||
nsAutoTArray<WORD,500> glyphArray;
|
||||
if (!glyphArray.SetLength(length)) {
|
||||
return false;
|
||||
}
|
||||
WORD *glyphs = glyphArray.Elements();
|
||||
|
||||
DWORD ret = ::GetGlyphIndicesW(dc, aString, length,
|
||||
DWORD ret = ::GetGlyphIndicesW(dc, aText, length,
|
||||
glyphs, GGI_MARK_NONEXISTING_GLYPHS);
|
||||
if (ret == GDI_ERROR) {
|
||||
return false;
|
||||
@ -57,32 +60,33 @@ gfxGDIShaper::ShapeWord(gfxContext *aContext,
|
||||
}
|
||||
|
||||
gfxTextRun::CompressedGlyph g;
|
||||
gfxTextRun::CompressedGlyph *charGlyphs =
|
||||
aShapedText->GetCharacterGlyphs();
|
||||
uint32_t i;
|
||||
int32_t lastWidth = 0;
|
||||
uint32_t appUnitsPerDevPixel = aShapedWord->AppUnitsPerDevUnit();
|
||||
uint32_t appUnitsPerDevPixel = aShapedText->GetAppUnitsPerDevUnit();
|
||||
for (i = 0; i < length; ++i) {
|
||||
uint32_t offset = i;
|
||||
uint32_t offset = aOffset + i;
|
||||
int32_t advancePixels = partialWidthArray[i] - lastWidth;
|
||||
lastWidth = partialWidthArray[i];
|
||||
int32_t advanceAppUnits = advancePixels * appUnitsPerDevPixel;
|
||||
WCHAR glyph = glyphs[i];
|
||||
NS_ASSERTION(!gfxFontGroup::IsInvalidChar(aShapedWord->GetCharAt(offset)),
|
||||
NS_ASSERTION(!gfxFontGroup::IsInvalidChar(aText[i]),
|
||||
"Invalid character detected!");
|
||||
bool atClusterStart = aShapedWord->IsClusterStart(offset);
|
||||
bool atClusterStart = charGlyphs[offset].IsClusterStart();
|
||||
if (advanceAppUnits >= 0 &&
|
||||
gfxShapedWord::CompressedGlyph::IsSimpleAdvance(advanceAppUnits) &&
|
||||
gfxShapedWord::CompressedGlyph::IsSimpleGlyphID(glyph) &&
|
||||
atClusterStart)
|
||||
{
|
||||
aShapedWord->SetSimpleGlyph(offset,
|
||||
g.SetSimpleGlyph(advanceAppUnits, glyph));
|
||||
charGlyphs[offset].SetSimpleGlyph(advanceAppUnits, glyph);
|
||||
} else {
|
||||
gfxShapedWord::DetailedGlyph details;
|
||||
gfxShapedText::DetailedGlyph details;
|
||||
details.mGlyphID = glyph;
|
||||
details.mAdvance = advanceAppUnits;
|
||||
details.mXOffset = 0;
|
||||
details.mYOffset = 0;
|
||||
aShapedWord->SetGlyphs(offset,
|
||||
aShapedText->SetGlyphs(offset,
|
||||
g.SetComplex(atClusterStart, true, 1),
|
||||
&details);
|
||||
}
|
||||
|
@ -22,9 +22,12 @@ public:
|
||||
MOZ_COUNT_DTOR(gfxGDIShaper);
|
||||
}
|
||||
|
||||
virtual bool ShapeWord(gfxContext *aContext,
|
||||
gfxShapedWord *aShapedWord,
|
||||
const PRUnichar *aString);
|
||||
virtual bool ShapeText(gfxContext *aContext,
|
||||
const PRUnichar *aText,
|
||||
uint32_t aOffset,
|
||||
uint32_t aLength,
|
||||
int32_t aScript,
|
||||
gfxShapedText *aShapedText);
|
||||
};
|
||||
|
||||
#endif /* GFX_GDISHAPER_H */
|
||||
|
@ -138,9 +138,12 @@ AddFeature(const uint32_t& aTag, uint32_t& aValue, void *aUserArg)
|
||||
}
|
||||
|
||||
bool
|
||||
gfxGraphiteShaper::ShapeWord(gfxContext *aContext,
|
||||
gfxShapedWord *aShapedWord,
|
||||
const PRUnichar *aText)
|
||||
gfxGraphiteShaper::ShapeText(gfxContext *aContext,
|
||||
const PRUnichar *aText,
|
||||
uint32_t aOffset,
|
||||
uint32_t aLength,
|
||||
int32_t aScript,
|
||||
gfxShapedText *aShapedText)
|
||||
{
|
||||
// some font back-ends require this in order to get proper hinted metrics
|
||||
if (!mFont->SetupCairoFont(aContext)) {
|
||||
@ -183,15 +186,15 @@ gfxGraphiteShaper::ShapeWord(gfxContext *aContext,
|
||||
nsDataHashtable<nsUint32HashKey,uint32_t> mergedFeatures;
|
||||
|
||||
if (MergeFontFeatures(style->featureSettings, entry->mFeatureSettings,
|
||||
aShapedWord->DisableLigatures(), mergedFeatures)) {
|
||||
aShapedText->DisableLigatures(), mergedFeatures)) {
|
||||
// enumerate result and insert into Graphite feature list
|
||||
GrFontFeatures f = {mGrFace, grFeatures};
|
||||
mergedFeatures.Enumerate(AddFeature, &f);
|
||||
}
|
||||
|
||||
gr_segment *seg = gr_make_seg(mGrFont, mGrFace, 0, grFeatures,
|
||||
gr_utf16, aText, aShapedWord->Length(),
|
||||
aShapedWord->IsRightToLeft());
|
||||
gr_utf16, aText, aLength,
|
||||
aShapedText->IsRightToLeft());
|
||||
|
||||
gr_featureval_destroy(grFeatures);
|
||||
|
||||
@ -199,7 +202,8 @@ gfxGraphiteShaper::ShapeWord(gfxContext *aContext,
|
||||
return false;
|
||||
}
|
||||
|
||||
nsresult rv = SetGlyphsFromSegment(aShapedWord, seg);
|
||||
nsresult rv = SetGlyphsFromSegment(aShapedText, aOffset, aLength,
|
||||
aText, seg);
|
||||
|
||||
gr_seg_destroy(seg);
|
||||
|
||||
@ -218,11 +222,14 @@ struct Cluster {
|
||||
};
|
||||
|
||||
nsresult
|
||||
gfxGraphiteShaper::SetGlyphsFromSegment(gfxShapedWord *aShapedWord,
|
||||
gr_segment *aSegment)
|
||||
gfxGraphiteShaper::SetGlyphsFromSegment(gfxShapedText *aShapedText,
|
||||
uint32_t aOffset,
|
||||
uint32_t aLength,
|
||||
const PRUnichar *aText,
|
||||
gr_segment *aSegment)
|
||||
{
|
||||
int32_t dev2appUnits = aShapedWord->AppUnitsPerDevUnit();
|
||||
bool rtl = aShapedWord->IsRightToLeft();
|
||||
int32_t dev2appUnits = aShapedText->GetAppUnitsPerDevUnit();
|
||||
bool rtl = aShapedText->IsRightToLeft();
|
||||
|
||||
uint32_t glyphCount = gr_seg_n_slots(aSegment);
|
||||
|
||||
@ -232,7 +239,7 @@ gfxGraphiteShaper::SetGlyphsFromSegment(gfxShapedWord *aShapedWord,
|
||||
nsAutoTArray<float,SMALL_GLYPH_RUN> xLocs;
|
||||
nsAutoTArray<float,SMALL_GLYPH_RUN> yLocs;
|
||||
|
||||
if (!clusters.SetLength(aShapedWord->Length()) ||
|
||||
if (!clusters.SetLength(aLength) ||
|
||||
!gids.SetLength(glyphCount) ||
|
||||
!xLocs.SetLength(glyphCount) ||
|
||||
!yLocs.SetLength(glyphCount))
|
||||
@ -268,7 +275,7 @@ gfxGraphiteShaper::SetGlyphsFromSegment(gfxShapedWord *aShapedWord,
|
||||
if (gr_slot_can_insert_before(slot) && clusters[cIndex].nChars &&
|
||||
before >= clusters[cIndex].baseChar + clusters[cIndex].nChars)
|
||||
{
|
||||
NS_ASSERTION(cIndex < aShapedWord->Length() - 1, "cIndex at end of word");
|
||||
NS_ASSERTION(cIndex < aLength - 1, "cIndex at end of word");
|
||||
Cluster& c = clusters[cIndex + 1];
|
||||
c.baseChar = clusters[cIndex].baseChar + clusters[cIndex].nChars;
|
||||
c.nChars = before - c.baseChar;
|
||||
@ -278,7 +285,7 @@ gfxGraphiteShaper::SetGlyphsFromSegment(gfxShapedWord *aShapedWord,
|
||||
}
|
||||
|
||||
// increment cluster's glyph count to include current slot
|
||||
NS_ASSERTION(cIndex < aShapedWord->Length(), "cIndex beyond word length");
|
||||
NS_ASSERTION(cIndex < aLength, "cIndex beyond word length");
|
||||
++clusters[cIndex].nGlyphs;
|
||||
|
||||
// extend cluster if necessary to reach the glyph's "after" index
|
||||
@ -287,6 +294,9 @@ gfxGraphiteShaper::SetGlyphsFromSegment(gfxShapedWord *aShapedWord,
|
||||
}
|
||||
}
|
||||
|
||||
gfxShapedText::CompressedGlyph *charGlyphs =
|
||||
aShapedText->GetCharacterGlyphs() + aOffset;
|
||||
|
||||
// now put glyphs into the textrun, one cluster at a time
|
||||
for (uint32_t i = 0; i <= cIndex; ++i) {
|
||||
const Cluster& c = clusters[i];
|
||||
@ -309,30 +319,26 @@ gfxGraphiteShaper::SetGlyphsFromSegment(gfxShapedWord *aShapedWord,
|
||||
// Check for default-ignorable char that didn't get filtered, combined,
|
||||
// etc by the shaping process, and skip it.
|
||||
uint32_t offs = gr_cinfo_base(gr_seg_cinfo(aSegment, c.baseChar));
|
||||
NS_ASSERTION(offs >= c.baseChar && offs < aShapedWord->Length(),
|
||||
NS_ASSERTION(offs >= c.baseChar && offs < aLength,
|
||||
"unexpected offset");
|
||||
if (c.nGlyphs == 1 && c.nChars == 1 &&
|
||||
aShapedWord->FilterIfIgnorable(offs))
|
||||
{
|
||||
aShapedText->FilterIfIgnorable(aOffset + offs, aText[offs])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
uint32_t appAdvance = adv * dev2appUnits;
|
||||
if (c.nGlyphs == 1 &&
|
||||
gfxShapedWord::CompressedGlyph::IsSimpleGlyphID(gids[c.baseGlyph]) &&
|
||||
gfxShapedWord::CompressedGlyph::IsSimpleAdvance(appAdvance) &&
|
||||
gfxShapedText::CompressedGlyph::IsSimpleGlyphID(gids[c.baseGlyph]) &&
|
||||
gfxShapedText::CompressedGlyph::IsSimpleAdvance(appAdvance) &&
|
||||
yLocs[c.baseGlyph] == 0)
|
||||
{
|
||||
gfxShapedWord::CompressedGlyph g;
|
||||
aShapedWord->SetSimpleGlyph(offs,
|
||||
g.SetSimpleGlyph(appAdvance,
|
||||
gids[c.baseGlyph]));
|
||||
charGlyphs[offs].SetSimpleGlyph(appAdvance, gids[c.baseGlyph]);
|
||||
} else {
|
||||
// not a one-to-one mapping with simple metrics: use DetailedGlyph
|
||||
nsAutoTArray<gfxShapedWord::DetailedGlyph,8> details;
|
||||
nsAutoTArray<gfxShapedText::DetailedGlyph,8> details;
|
||||
float clusterLoc;
|
||||
for (uint32_t j = c.baseGlyph; j < c.baseGlyph + c.nGlyphs; ++j) {
|
||||
gfxShapedWord::DetailedGlyph* d = details.AppendElement();
|
||||
gfxShapedText::DetailedGlyph* d = details.AppendElement();
|
||||
d->mGlyphID = gids[j];
|
||||
d->mYOffset = -yLocs[j] * dev2appUnits;
|
||||
if (j == c.baseGlyph) {
|
||||
@ -346,19 +352,19 @@ gfxGraphiteShaper::SetGlyphsFromSegment(gfxShapedWord *aShapedWord,
|
||||
d->mAdvance = 0;
|
||||
}
|
||||
}
|
||||
gfxShapedWord::CompressedGlyph g;
|
||||
g.SetComplex(aShapedWord->IsClusterStart(offs),
|
||||
gfxShapedText::CompressedGlyph g;
|
||||
g.SetComplex(charGlyphs[offs].IsClusterStart(),
|
||||
true, details.Length());
|
||||
aShapedWord->SetGlyphs(offs, g, details.Elements());
|
||||
aShapedText->SetGlyphs(aOffset + offs, g, details.Elements());
|
||||
}
|
||||
|
||||
for (uint32_t j = c.baseChar + 1; j < c.baseChar + c.nChars; ++j) {
|
||||
offs = gr_cinfo_base(gr_seg_cinfo(aSegment, j));
|
||||
NS_ASSERTION(offs >= j && offs < aShapedWord->Length(),
|
||||
NS_ASSERTION(offs >= j && offs < aLength,
|
||||
"unexpected offset");
|
||||
gfxShapedWord::CompressedGlyph g;
|
||||
g.SetComplex(aShapedWord->IsClusterStart(offs), false, 0);
|
||||
aShapedWord->SetGlyphs(offs, g, nullptr);
|
||||
gfxShapedText::CompressedGlyph &g = charGlyphs[offs];
|
||||
NS_ASSERTION(!g.IsSimpleGlyph(), "overwriting a simple glyph");
|
||||
g.SetComplex(g.IsClusterStart(), false, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -20,9 +20,12 @@ public:
|
||||
gfxGraphiteShaper(gfxFont *aFont);
|
||||
virtual ~gfxGraphiteShaper();
|
||||
|
||||
virtual bool ShapeWord(gfxContext *aContext,
|
||||
gfxShapedWord *aShapedWord,
|
||||
const PRUnichar *aText);
|
||||
virtual bool ShapeText(gfxContext *aContext,
|
||||
const PRUnichar *aText,
|
||||
uint32_t aOffset,
|
||||
uint32_t aLength,
|
||||
int32_t aScript,
|
||||
gfxShapedText *aShapedText);
|
||||
|
||||
const void* GetTable(uint32_t aTag, size_t *aLength);
|
||||
|
||||
@ -41,8 +44,11 @@ public:
|
||||
};
|
||||
|
||||
protected:
|
||||
nsresult SetGlyphsFromSegment(gfxShapedWord *aShapedWord,
|
||||
gr_segment *aSegment);
|
||||
nsresult SetGlyphsFromSegment(gfxShapedText *aShapedText,
|
||||
uint32_t aOffset,
|
||||
uint32_t aLength,
|
||||
const PRUnichar *aText,
|
||||
gr_segment *aSegment);
|
||||
|
||||
gr_face *mGrFace;
|
||||
gr_font *mGrFont;
|
||||
|
@ -116,43 +116,55 @@ hb_codepoint_t
|
||||
gfxHarfBuzzShaper::GetGlyph(hb_codepoint_t unicode,
|
||||
hb_codepoint_t variation_selector) const
|
||||
{
|
||||
if (mUseFontGetGlyph) {
|
||||
return mFont->GetGlyph(unicode, variation_selector);
|
||||
}
|
||||
|
||||
// we only instantiate a harfbuzz shaper if there's a cmap available
|
||||
NS_ASSERTION(mFont->GetFontEntry()->HasCmapTable(),
|
||||
"we cannot be using this font!");
|
||||
|
||||
NS_ASSERTION(mCmapTable && (mCmapFormat > 0) && (mSubtableOffset > 0),
|
||||
"cmap data not correctly set up, expect disaster");
|
||||
|
||||
const uint8_t* data = (const uint8_t*)hb_blob_get_data(mCmapTable, nullptr);
|
||||
|
||||
hb_codepoint_t gid;
|
||||
switch (mCmapFormat) {
|
||||
case 4:
|
||||
gid = unicode < UNICODE_BMP_LIMIT ?
|
||||
gfxFontUtils::MapCharToGlyphFormat4(data + mSubtableOffset, unicode) : 0;
|
||||
break;
|
||||
case 12:
|
||||
gid = gfxFontUtils::MapCharToGlyphFormat12(data + mSubtableOffset, unicode);
|
||||
break;
|
||||
default:
|
||||
NS_WARNING("unsupported cmap format, glyphs will be missing");
|
||||
gid = 0;
|
||||
break;
|
||||
|
||||
if (mUseFontGetGlyph) {
|
||||
gid = mFont->GetGlyph(unicode, variation_selector);
|
||||
} else {
|
||||
// we only instantiate a harfbuzz shaper if there's a cmap available
|
||||
NS_ASSERTION(mFont->GetFontEntry()->HasCmapTable(),
|
||||
"we cannot be using this font!");
|
||||
|
||||
NS_ASSERTION(mCmapTable && (mCmapFormat > 0) && (mSubtableOffset > 0),
|
||||
"cmap data not correctly set up, expect disaster");
|
||||
|
||||
const uint8_t* data =
|
||||
(const uint8_t*)hb_blob_get_data(mCmapTable, nullptr);
|
||||
|
||||
switch (mCmapFormat) {
|
||||
case 4:
|
||||
gid = unicode < UNICODE_BMP_LIMIT ?
|
||||
gfxFontUtils::MapCharToGlyphFormat4(data + mSubtableOffset,
|
||||
unicode) : 0;
|
||||
break;
|
||||
case 12:
|
||||
gid = gfxFontUtils::MapCharToGlyphFormat12(data + mSubtableOffset,
|
||||
unicode);
|
||||
break;
|
||||
default:
|
||||
NS_WARNING("unsupported cmap format, glyphs will be missing");
|
||||
gid = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (gid && variation_selector && mUVSTableOffset) {
|
||||
hb_codepoint_t varGID =
|
||||
gfxFontUtils::MapUVSToGlyphFormat14(data + mUVSTableOffset,
|
||||
unicode,
|
||||
variation_selector);
|
||||
if (varGID) {
|
||||
gid = varGID;
|
||||
}
|
||||
// else the variation sequence was not supported, use default
|
||||
// mapping of the character code alone
|
||||
}
|
||||
}
|
||||
|
||||
if (gid && variation_selector && mUVSTableOffset) {
|
||||
hb_codepoint_t varGID =
|
||||
gfxFontUtils::MapUVSToGlyphFormat14(data + mUVSTableOffset,
|
||||
unicode, variation_selector);
|
||||
if (varGID) {
|
||||
gid = varGID;
|
||||
if (!gid) {
|
||||
// if there's no glyph for , just use the space glyph instead
|
||||
if (unicode == 0xA0) {
|
||||
gid = mFont->GetSpaceGlyph();
|
||||
}
|
||||
// else the variation sequence was not supported, use default mapping
|
||||
// of the character code alone
|
||||
}
|
||||
|
||||
return gid;
|
||||
@ -830,9 +842,12 @@ static hb_font_funcs_t * sHBFontFuncs = nullptr;
|
||||
static hb_unicode_funcs_t * sHBUnicodeFuncs = nullptr;
|
||||
|
||||
bool
|
||||
gfxHarfBuzzShaper::ShapeWord(gfxContext *aContext,
|
||||
gfxShapedWord *aShapedWord,
|
||||
const PRUnichar *aText)
|
||||
gfxHarfBuzzShaper::ShapeText(gfxContext *aContext,
|
||||
const PRUnichar *aText,
|
||||
uint32_t aOffset,
|
||||
uint32_t aLength,
|
||||
int32_t aScript,
|
||||
gfxShapedText *aShapedText)
|
||||
{
|
||||
// some font back-ends require this in order to get proper hinted metrics
|
||||
if (!mFont->SetupCairoFont(aContext)) {
|
||||
@ -960,12 +975,12 @@ gfxHarfBuzzShaper::ShapeWord(gfxContext *aContext,
|
||||
|
||||
if (MergeFontFeatures(style->featureSettings,
|
||||
mFont->GetFontEntry()->mFeatureSettings,
|
||||
aShapedWord->DisableLigatures(), mergedFeatures)) {
|
||||
aShapedText->DisableLigatures(), mergedFeatures)) {
|
||||
// enumerate result and insert into hb_feature array
|
||||
mergedFeatures.Enumerate(AddFeature, &features);
|
||||
}
|
||||
|
||||
bool isRightToLeft = aShapedWord->IsRightToLeft();
|
||||
bool isRightToLeft = aShapedText->IsRightToLeft();
|
||||
hb_buffer_t *buffer = hb_buffer_create();
|
||||
hb_buffer_set_unicode_funcs(buffer, sHBUnicodeFuncs);
|
||||
hb_buffer_set_direction(buffer, isRightToLeft ? HB_DIRECTION_RTL :
|
||||
@ -973,10 +988,9 @@ gfxHarfBuzzShaper::ShapeWord(gfxContext *aContext,
|
||||
// For unresolved "common" or "inherited" runs, default to Latin for now.
|
||||
// (Should we somehow use the language or locale to try and infer
|
||||
// a better default?)
|
||||
int32_t scriptCode = aShapedWord->Script();
|
||||
hb_script_t scriptTag = (scriptCode <= MOZ_SCRIPT_INHERITED) ?
|
||||
hb_script_t scriptTag = (aScript <= MOZ_SCRIPT_INHERITED) ?
|
||||
HB_SCRIPT_LATIN :
|
||||
hb_script_t(GetScriptTagForCode(scriptCode));
|
||||
hb_script_t(GetScriptTagForCode(aScript));
|
||||
hb_buffer_set_script(buffer, scriptTag);
|
||||
|
||||
hb_language_t language;
|
||||
@ -992,7 +1006,7 @@ gfxHarfBuzzShaper::ShapeWord(gfxContext *aContext,
|
||||
}
|
||||
hb_buffer_set_language(buffer, language);
|
||||
|
||||
uint32_t length = aShapedWord->Length();
|
||||
uint32_t length = aLength;
|
||||
hb_buffer_add_utf16(buffer,
|
||||
reinterpret_cast<const uint16_t*>(aText),
|
||||
length, 0, length);
|
||||
@ -1003,7 +1017,8 @@ gfxHarfBuzzShaper::ShapeWord(gfxContext *aContext,
|
||||
hb_buffer_reverse(buffer);
|
||||
}
|
||||
|
||||
nsresult rv = SetGlyphsFromRun(aContext, aShapedWord, buffer);
|
||||
nsresult rv = SetGlyphsFromRun(aContext, aShapedText, aOffset, aLength,
|
||||
aText, buffer);
|
||||
|
||||
NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "failed to store glyphs into gfxShapedWord");
|
||||
hb_buffer_destroy(buffer);
|
||||
@ -1091,9 +1106,12 @@ GetRoundOffsetsToPixels(gfxContext *aContext,
|
||||
// for charToGlyphArray
|
||||
|
||||
nsresult
|
||||
gfxHarfBuzzShaper::SetGlyphsFromRun(gfxContext *aContext,
|
||||
gfxShapedWord *aShapedWord,
|
||||
hb_buffer_t *aBuffer)
|
||||
gfxHarfBuzzShaper::SetGlyphsFromRun(gfxContext *aContext,
|
||||
gfxShapedText *aShapedText,
|
||||
uint32_t aOffset,
|
||||
uint32_t aLength,
|
||||
const PRUnichar *aText,
|
||||
hb_buffer_t *aBuffer)
|
||||
{
|
||||
uint32_t numGlyphs;
|
||||
const hb_glyph_info_t *ginfo = hb_buffer_get_glyph_infos(aBuffer, &numGlyphs);
|
||||
@ -1103,7 +1121,7 @@ gfxHarfBuzzShaper::SetGlyphsFromRun(gfxContext *aContext,
|
||||
|
||||
nsAutoTArray<gfxTextRun::DetailedGlyph,1> detailedGlyphs;
|
||||
|
||||
uint32_t wordLength = aShapedWord->Length();
|
||||
uint32_t wordLength = aLength;
|
||||
static const int32_t NO_GLYPH = -1;
|
||||
nsAutoTArray<int32_t,SMALL_GLYPH_RUN> charToGlyphArray;
|
||||
if (!charToGlyphArray.SetLength(wordLength)) {
|
||||
@ -1129,11 +1147,13 @@ gfxHarfBuzzShaper::SetGlyphsFromRun(gfxContext *aContext,
|
||||
bool roundY;
|
||||
GetRoundOffsetsToPixels(aContext, &roundX, &roundY);
|
||||
|
||||
int32_t appUnitsPerDevUnit = aShapedWord->AppUnitsPerDevUnit();
|
||||
int32_t appUnitsPerDevUnit = aShapedText->GetAppUnitsPerDevUnit();
|
||||
gfxShapedText::CompressedGlyph *charGlyphs =
|
||||
aShapedText->GetCharacterGlyphs() + aOffset;
|
||||
|
||||
// factor to convert 16.16 fixed-point pixels to app units
|
||||
// (only used if not rounding)
|
||||
double hb2appUnits = FixedToFloat(aShapedWord->AppUnitsPerDevUnit());
|
||||
double hb2appUnits = FixedToFloat(aShapedText->GetAppUnitsPerDevUnit());
|
||||
|
||||
// Residual from rounding of previous advance, for use in rounding the
|
||||
// subsequent offset or advance appropriately. 16.16 fixed-point
|
||||
@ -1236,7 +1256,8 @@ gfxHarfBuzzShaper::SetGlyphsFromRun(gfxContext *aContext,
|
||||
// etc by the shaping process, and remove from the run.
|
||||
// (This may be done within harfbuzz eventually.)
|
||||
if (glyphsInClump == 1 && baseCharIndex + 1 == endCharIndex &&
|
||||
aShapedWord->FilterIfIgnorable(baseCharIndex)) {
|
||||
aShapedText->FilterIfIgnorable(aOffset + baseCharIndex,
|
||||
aText[baseCharIndex])) {
|
||||
glyphStart = glyphEnd;
|
||||
charStart = charEnd;
|
||||
continue;
|
||||
@ -1261,14 +1282,12 @@ gfxHarfBuzzShaper::SetGlyphsFromRun(gfxContext *aContext,
|
||||
if (glyphsInClump == 1 &&
|
||||
gfxTextRun::CompressedGlyph::IsSimpleGlyphID(ginfo[glyphStart].codepoint) &&
|
||||
gfxTextRun::CompressedGlyph::IsSimpleAdvance(advance) &&
|
||||
aShapedWord->IsClusterStart(baseCharIndex) &&
|
||||
charGlyphs[baseCharIndex].IsClusterStart() &&
|
||||
xOffset == 0 &&
|
||||
posInfo[glyphStart].y_offset == 0 && yPos == 0)
|
||||
{
|
||||
gfxTextRun::CompressedGlyph g;
|
||||
aShapedWord->SetSimpleGlyph(baseCharIndex,
|
||||
g.SetSimpleGlyph(advance,
|
||||
ginfo[glyphStart].codepoint));
|
||||
charGlyphs[baseCharIndex].SetSimpleGlyph(advance,
|
||||
ginfo[glyphStart].codepoint);
|
||||
} else {
|
||||
// collect all glyphs in a list to be assigned to the first char;
|
||||
// there must be at least one in the clump, and we already measured
|
||||
@ -1317,11 +1336,11 @@ gfxHarfBuzzShaper::SetGlyphsFromRun(gfxContext *aContext,
|
||||
}
|
||||
}
|
||||
|
||||
gfxTextRun::CompressedGlyph g;
|
||||
g.SetComplex(aShapedWord->IsClusterStart(baseCharIndex),
|
||||
gfxShapedText::CompressedGlyph g;
|
||||
g.SetComplex(charGlyphs[baseCharIndex].IsClusterStart(),
|
||||
true, detailedGlyphs.Length());
|
||||
aShapedWord->SetGlyphs(baseCharIndex,
|
||||
g, detailedGlyphs.Elements());
|
||||
aShapedText->SetGlyphs(aOffset + baseCharIndex,
|
||||
g, detailedGlyphs.Elements());
|
||||
|
||||
detailedGlyphs.Clear();
|
||||
}
|
||||
@ -1330,10 +1349,9 @@ gfxHarfBuzzShaper::SetGlyphsFromRun(gfxContext *aContext,
|
||||
// no associated glyphs
|
||||
while (++baseCharIndex != endCharIndex &&
|
||||
baseCharIndex < int32_t(wordLength)) {
|
||||
gfxTextRun::CompressedGlyph g;
|
||||
g.SetComplex(aShapedWord->IsClusterStart(baseCharIndex),
|
||||
false, 0);
|
||||
aShapedWord->SetGlyphs(baseCharIndex, g, nullptr);
|
||||
gfxShapedText::CompressedGlyph &g = charGlyphs[baseCharIndex];
|
||||
NS_ASSERTION(!g.IsSimpleGlyph(), "overwriting a simple glyph");
|
||||
g.SetComplex(g.IsClusterStart(), false, 0);
|
||||
}
|
||||
|
||||
glyphStart = glyphEnd;
|
||||
|
@ -18,9 +18,12 @@ public:
|
||||
gfxHarfBuzzShaper(gfxFont *aFont);
|
||||
virtual ~gfxHarfBuzzShaper();
|
||||
|
||||
virtual bool ShapeWord(gfxContext *aContext,
|
||||
gfxShapedWord *aShapedWord,
|
||||
const PRUnichar *aText);
|
||||
virtual bool ShapeText(gfxContext *aContext,
|
||||
const PRUnichar *aText,
|
||||
uint32_t aOffset,
|
||||
uint32_t aLength,
|
||||
int32_t aScript,
|
||||
gfxShapedText *aShapedText);
|
||||
|
||||
// get a given font table in harfbuzz blob form
|
||||
hb_blob_t * GetFontTable(hb_tag_t aTag) const;
|
||||
@ -37,9 +40,12 @@ public:
|
||||
uint16_t aSecondGlyph) const;
|
||||
|
||||
protected:
|
||||
nsresult SetGlyphsFromRun(gfxContext *aContext,
|
||||
gfxShapedWord *aShapedWord,
|
||||
hb_buffer_t *aBuffer);
|
||||
nsresult SetGlyphsFromRun(gfxContext *aContext,
|
||||
gfxShapedText *aShapedText,
|
||||
uint32_t aOffset,
|
||||
uint32_t aLength,
|
||||
const PRUnichar *aText,
|
||||
hb_buffer_t *aBuffer);
|
||||
|
||||
// retrieve glyph positions, applying advance adjustments and attachments
|
||||
// returns results in appUnits
|
||||
|
@ -120,10 +120,13 @@ gfxMacFont::~gfxMacFont()
|
||||
}
|
||||
|
||||
bool
|
||||
gfxMacFont::ShapeWord(gfxContext *aContext,
|
||||
gfxShapedWord *aShapedWord,
|
||||
gfxMacFont::ShapeText(gfxContext *aContext,
|
||||
const PRUnichar *aText,
|
||||
bool aPreferPlatformShaping)
|
||||
uint32_t aOffset,
|
||||
uint32_t aLength,
|
||||
int32_t aScript,
|
||||
gfxShapedText *aShapedText,
|
||||
bool aPreferPlatformShaping)
|
||||
{
|
||||
if (!mIsValid) {
|
||||
NS_WARNING("invalid font! expect incorrect text rendering");
|
||||
@ -132,7 +135,8 @@ gfxMacFont::ShapeWord(gfxContext *aContext,
|
||||
|
||||
bool requiresAAT =
|
||||
static_cast<MacOSFontEntry*>(GetFontEntry())->RequiresAATLayout();
|
||||
return gfxFont::ShapeWord(aContext, aShapedWord, aText, requiresAAT);
|
||||
return gfxFont::ShapeText(aContext, aText, aOffset, aLength,
|
||||
aScript, aShapedText, requiresAAT);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -57,10 +57,13 @@ protected:
|
||||
virtual void CreatePlatformShaper();
|
||||
|
||||
// override to prefer CoreText shaping with fonts that depend on AAT
|
||||
virtual bool ShapeWord(gfxContext *aContext,
|
||||
gfxShapedWord *aShapedWord,
|
||||
virtual bool ShapeText(gfxContext *aContext,
|
||||
const PRUnichar *aText,
|
||||
bool aPreferPlatformShaping = false);
|
||||
uint32_t aOffset,
|
||||
uint32_t aLength,
|
||||
int32_t aScript,
|
||||
gfxShapedText *aShapedText,
|
||||
bool aPreferPlatformShaping = false);
|
||||
|
||||
void InitMetrics();
|
||||
void InitMetricsFromPlatform();
|
||||
|
@ -83,7 +83,7 @@ static PangoLanguage *GuessPangoLanguage(nsIAtom *aLanguage);
|
||||
|
||||
static cairo_scaled_font_t *
|
||||
CreateScaledFont(FcPattern *aPattern, cairo_font_face_t *aFace);
|
||||
static void SetMissingGlyphs(gfxShapedWord *aShapedWord, const gchar *aUTF8,
|
||||
static void SetMissingGlyphs(gfxShapedText *aShapedText, const gchar *aUTF8,
|
||||
uint32_t aUTF8Length, uint32_t *aUTF16Offset,
|
||||
gfxFont *aFont);
|
||||
|
||||
@ -286,7 +286,7 @@ gfxFcFontEntry::ShouldUseHarfBuzz(int32_t aRunScript) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Mimicing gfxHarfBuzzShaper::ShapeWord
|
||||
// Mimicing gfxHarfBuzzShaper::ShapeText
|
||||
hb_script_t script = (aRunScript <= MOZ_SCRIPT_INHERITED) ?
|
||||
HB_SCRIPT_LATIN :
|
||||
hb_script_t(GetScriptTagForCode(aRunScript));
|
||||
@ -804,13 +804,19 @@ public:
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual bool ShapeWord(gfxContext *aContext,
|
||||
gfxShapedWord *aShapedWord,
|
||||
const PRUnichar *aString,
|
||||
bool aPreferPlatformShaping);
|
||||
virtual bool ShapeText(gfxContext *aContext,
|
||||
const PRUnichar *aText,
|
||||
uint32_t aOffset,
|
||||
uint32_t aLength,
|
||||
int32_t aScript,
|
||||
gfxShapedText *aShapedText,
|
||||
bool aPreferPlatformShaping);
|
||||
|
||||
bool InitGlyphRunWithPango(gfxShapedWord *aTextRun,
|
||||
const PRUnichar *aString);
|
||||
bool InitGlyphRunWithPango(const PRUnichar *aString,
|
||||
uint32_t aOffset,
|
||||
uint32_t aLength,
|
||||
int32_t aScript,
|
||||
gfxShapedText *aShapedText);
|
||||
|
||||
private:
|
||||
gfxFcFont(cairo_scaled_font_t *aCairoFont, gfxFcFontEntry *aFontEntry,
|
||||
@ -2247,45 +2253,55 @@ gfxFcFont::~gfxFcFont()
|
||||
}
|
||||
|
||||
bool
|
||||
gfxFcFont::ShapeWord(gfxContext *aContext,
|
||||
gfxShapedWord *aShapedWord,
|
||||
const PRUnichar *aString,
|
||||
bool aPreferPlatformShaping)
|
||||
gfxFcFont::ShapeText(gfxContext *aContext,
|
||||
const PRUnichar *aText,
|
||||
uint32_t aOffset,
|
||||
uint32_t aLength,
|
||||
int32_t aScript,
|
||||
gfxShapedText *aShapedText,
|
||||
bool aPreferPlatformShaping)
|
||||
{
|
||||
gfxFcFontEntry *fontEntry = static_cast<gfxFcFontEntry*>(GetFontEntry());
|
||||
|
||||
bool ok = false;
|
||||
|
||||
#ifdef MOZ_GRAPHITE
|
||||
if (FontCanSupportGraphite()) {
|
||||
if (gfxPlatform::GetPlatform()->UseGraphiteShaping()) {
|
||||
if (!mGraphiteShaper) {
|
||||
mGraphiteShaper = new gfxGraphiteShaper(this);
|
||||
}
|
||||
if (mGraphiteShaper->ShapeWord(aContext, aShapedWord, aString)) {
|
||||
return true;
|
||||
}
|
||||
ok = mGraphiteShaper->ShapeText(aContext, aText, aOffset, aLength,
|
||||
aScript, aShapedText);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (fontEntry->ShouldUseHarfBuzz(aShapedWord->Script())) {
|
||||
if (!ok && fontEntry->ShouldUseHarfBuzz(aScript)) {
|
||||
if (!mHarfBuzzShaper) {
|
||||
gfxFT2LockedFace face(this);
|
||||
mHarfBuzzShaper = new gfxHarfBuzzShaper(this);
|
||||
// Used by gfxHarfBuzzShaper, currently only for kerning
|
||||
mFUnitsConvFactor = face.XScale();
|
||||
}
|
||||
if (mHarfBuzzShaper->ShapeWord(aContext, aShapedWord, aString)) {
|
||||
return true;
|
||||
ok = mHarfBuzzShaper->ShapeText(aContext, aText, aOffset, aLength,
|
||||
aScript, aShapedText);
|
||||
if (!ok) {
|
||||
// Wrong font type for HarfBuzz
|
||||
fontEntry->SkipHarfBuzz();
|
||||
mHarfBuzzShaper = nullptr;
|
||||
}
|
||||
|
||||
// Wrong font type for HarfBuzz
|
||||
fontEntry->SkipHarfBuzz();
|
||||
mHarfBuzzShaper = nullptr;
|
||||
}
|
||||
|
||||
bool ok = InitGlyphRunWithPango(aShapedWord, aString);
|
||||
if (!ok) {
|
||||
ok = InitGlyphRunWithPango(aText, aOffset, aLength, aScript,
|
||||
aShapedText);
|
||||
}
|
||||
|
||||
NS_WARN_IF_FALSE(ok, "shaper failed, expect scrambled or missing text");
|
||||
|
||||
PostShapingFixup(aContext, aText, aOffset, aLength, aShapedText);
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
@ -2786,42 +2802,42 @@ ConvertPangoToAppUnits(int32_t aCoordinate, uint32_t aAppUnitsPerDevUnit)
|
||||
*/
|
||||
static nsresult
|
||||
SetGlyphsForCharacterGroup(const PangoGlyphInfo *aGlyphs, uint32_t aGlyphCount,
|
||||
gfxShapedWord *aShapedWord,
|
||||
gfxShapedText *aShapedText,
|
||||
const gchar *aUTF8, uint32_t aUTF8Length,
|
||||
uint32_t *aUTF16Offset,
|
||||
PangoGlyphUnit aOverrideSpaceWidth)
|
||||
{
|
||||
uint32_t utf16Offset = *aUTF16Offset;
|
||||
uint32_t wordLength = aShapedWord->Length();
|
||||
const uint32_t appUnitsPerDevUnit = aShapedWord->AppUnitsPerDevUnit();
|
||||
uint32_t limit = aShapedText->GetLength();
|
||||
const uint32_t appUnitsPerDevUnit = aShapedText->GetAppUnitsPerDevUnit();
|
||||
gfxShapedText::CompressedGlyph *charGlyphs =
|
||||
aShapedText->GetCharacterGlyphs();
|
||||
bool atClusterStart = charGlyphs[utf16Offset].IsClusterStart();
|
||||
|
||||
// Override the width of a space, but only for spaces that aren't
|
||||
// clustered with something else (like a freestanding diacritical mark)
|
||||
PangoGlyphUnit width = aGlyphs[0].geometry.width;
|
||||
if (aOverrideSpaceWidth && aUTF8[0] == ' ' &&
|
||||
(utf16Offset + 1 == wordLength ||
|
||||
aShapedWord->IsClusterStart(utf16Offset))) {
|
||||
(utf16Offset + 1 == limit || atClusterStart)) {
|
||||
width = aOverrideSpaceWidth;
|
||||
}
|
||||
int32_t advance = ConvertPangoToAppUnits(width, appUnitsPerDevUnit);
|
||||
|
||||
gfxShapedWord::CompressedGlyph g;
|
||||
bool atClusterStart = aShapedWord->IsClusterStart(utf16Offset);
|
||||
gfxShapedText::CompressedGlyph g;
|
||||
// See if we fit in the compressed area.
|
||||
if (aGlyphCount == 1 && advance >= 0 && atClusterStart &&
|
||||
aGlyphs[0].geometry.x_offset == 0 &&
|
||||
aGlyphs[0].geometry.y_offset == 0 &&
|
||||
!IS_EMPTY_GLYPH(aGlyphs[0].glyph) &&
|
||||
gfxShapedWord::CompressedGlyph::IsSimpleAdvance(advance) &&
|
||||
gfxShapedWord::CompressedGlyph::IsSimpleGlyphID(aGlyphs[0].glyph)) {
|
||||
aShapedWord->SetSimpleGlyph(utf16Offset,
|
||||
g.SetSimpleGlyph(advance, aGlyphs[0].glyph));
|
||||
gfxShapedText::CompressedGlyph::IsSimpleAdvance(advance) &&
|
||||
gfxShapedText::CompressedGlyph::IsSimpleGlyphID(aGlyphs[0].glyph)) {
|
||||
charGlyphs[utf16Offset].SetSimpleGlyph(advance, aGlyphs[0].glyph);
|
||||
} else {
|
||||
nsAutoTArray<gfxShapedWord::DetailedGlyph,10> detailedGlyphs;
|
||||
nsAutoTArray<gfxShapedText::DetailedGlyph,10> detailedGlyphs;
|
||||
if (!detailedGlyphs.AppendElements(aGlyphCount))
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
int32_t direction = aShapedWord->IsRightToLeft() ? -1 : 1;
|
||||
int32_t direction = aShapedText->IsRightToLeft() ? -1 : 1;
|
||||
uint32_t pangoIndex = direction > 0 ? 0 : aGlyphCount - 1;
|
||||
uint32_t detailedIndex = 0;
|
||||
for (uint32_t i = 0; i < aGlyphCount; ++i) {
|
||||
@ -2832,7 +2848,7 @@ SetGlyphsForCharacterGroup(const PangoGlyphInfo *aGlyphs, uint32_t aGlyphCount,
|
||||
if (IS_EMPTY_GLYPH(glyph.glyph))
|
||||
continue;
|
||||
|
||||
gfxShapedWord::DetailedGlyph *details = &detailedGlyphs[detailedIndex];
|
||||
gfxShapedText::DetailedGlyph *details = &detailedGlyphs[detailedIndex];
|
||||
++detailedIndex;
|
||||
|
||||
details->mGlyphID = glyph.glyph;
|
||||
@ -2847,7 +2863,7 @@ SetGlyphsForCharacterGroup(const PangoGlyphInfo *aGlyphs, uint32_t aGlyphCount,
|
||||
float(glyph.geometry.y_offset)*appUnitsPerDevUnit/PANGO_SCALE;
|
||||
}
|
||||
g.SetComplex(atClusterStart, true, detailedIndex);
|
||||
aShapedWord->SetGlyphs(utf16Offset, g, detailedGlyphs.Elements());
|
||||
aShapedText->SetGlyphs(utf16Offset, g, detailedGlyphs.Elements());
|
||||
}
|
||||
|
||||
// Check for ligatures and set *aUTF16Offset.
|
||||
@ -2872,20 +2888,21 @@ SetGlyphsForCharacterGroup(const PangoGlyphInfo *aGlyphs, uint32_t aGlyphCount,
|
||||
if (p >= end)
|
||||
break;
|
||||
|
||||
if (utf16Offset >= wordLength) {
|
||||
if (utf16Offset >= limit) {
|
||||
NS_ERROR("Someone has added too many glyphs!");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
g.SetComplex(aShapedWord->IsClusterStart(utf16Offset), false, 0);
|
||||
aShapedWord->SetGlyphs(utf16Offset, g, nullptr);
|
||||
gfxShapedText::CompressedGlyph &g = charGlyphs[utf16Offset];
|
||||
NS_ASSERTION(!g.IsSimpleGlyph(), "overwriting a simple glyph");
|
||||
g.SetComplex(g.IsClusterStart(), false, 0);
|
||||
}
|
||||
*aUTF16Offset = utf16Offset;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static nsresult
|
||||
SetGlyphs(gfxShapedWord *aShapedWord, const gchar *aUTF8, uint32_t aUTF8Length,
|
||||
SetGlyphs(gfxShapedText *aShapedText, const gchar *aUTF8, uint32_t aUTF8Length,
|
||||
uint32_t *aUTF16Offset, PangoGlyphString *aGlyphs,
|
||||
PangoGlyphUnit aOverrideSpaceWidth,
|
||||
gfxFont *aFont)
|
||||
@ -2921,13 +2938,13 @@ SetGlyphs(gfxShapedWord *aShapedWord, const gchar *aUTF8, uint32_t aUTF8Length,
|
||||
}
|
||||
|
||||
uint32_t utf16Offset = *aUTF16Offset;
|
||||
uint32_t wordLength = aShapedWord->Length();
|
||||
uint32_t limit = aShapedText->GetLength();
|
||||
utf8Index = 0;
|
||||
// The next glyph cluster in logical order.
|
||||
gint nextGlyphClusterStart = logGlyphs[utf8Index];
|
||||
NS_ASSERTION(nextGlyphClusterStart >= 0, "No glyphs! - NUL in string?");
|
||||
while (utf8Index < aUTF8Length) {
|
||||
if (utf16Offset >= wordLength) {
|
||||
if (utf16Offset >= limit) {
|
||||
NS_ERROR("Someone has added too many glyphs!");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
@ -2935,7 +2952,7 @@ SetGlyphs(gfxShapedWord *aShapedWord, const gchar *aUTF8, uint32_t aUTF8Length,
|
||||
// Find the utf8 text associated with this glyph cluster.
|
||||
uint32_t clusterUTF8Start = utf8Index;
|
||||
// Check whether we are consistent with pango_break data.
|
||||
NS_WARN_IF_FALSE(aShapedWord->IsClusterStart(utf16Offset),
|
||||
NS_WARN_IF_FALSE(aShapedText->IsClusterStart(utf16Offset),
|
||||
"Glyph cluster not aligned on character cluster.");
|
||||
do {
|
||||
++utf8Index;
|
||||
@ -2961,12 +2978,12 @@ SetGlyphs(gfxShapedWord *aShapedWord, const gchar *aUTF8, uint32_t aUTF8Length,
|
||||
|
||||
nsresult rv;
|
||||
if (haveMissingGlyph) {
|
||||
SetMissingGlyphs(aShapedWord, clusterUTF8, clusterUTF8Length,
|
||||
SetMissingGlyphs(aShapedText, clusterUTF8, clusterUTF8Length,
|
||||
&utf16Offset, aFont);
|
||||
} else {
|
||||
rv = SetGlyphsForCharacterGroup(&glyphs[glyphClusterStart],
|
||||
glyphIndex - glyphClusterStart,
|
||||
aShapedWord,
|
||||
aShapedText,
|
||||
clusterUTF8, clusterUTF8Length,
|
||||
&utf16Offset, aOverrideSpaceWidth);
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
@ -2977,19 +2994,19 @@ SetGlyphs(gfxShapedWord *aShapedWord, const gchar *aUTF8, uint32_t aUTF8Length,
|
||||
}
|
||||
|
||||
static void
|
||||
SetMissingGlyphs(gfxShapedWord *aShapedWord, const gchar *aUTF8,
|
||||
SetMissingGlyphs(gfxShapedText *aShapedText, const gchar *aUTF8,
|
||||
uint32_t aUTF8Length, uint32_t *aUTF16Offset,
|
||||
gfxFont *aFont)
|
||||
{
|
||||
uint32_t utf16Offset = *aUTF16Offset;
|
||||
uint32_t wordLength = aShapedWord->Length();
|
||||
uint32_t limit = aShapedText->GetLength();
|
||||
for (uint32_t index = 0; index < aUTF8Length;) {
|
||||
if (utf16Offset >= wordLength) {
|
||||
if (utf16Offset >= limit) {
|
||||
NS_ERROR("Someone has added too many glyphs!");
|
||||
break;
|
||||
}
|
||||
gunichar ch = g_utf8_get_char(aUTF8 + index);
|
||||
aShapedWord->SetMissingGlyph(utf16Offset, ch, aFont);
|
||||
aShapedText->SetMissingGlyph(utf16Offset, ch, aFont);
|
||||
|
||||
++utf16Offset;
|
||||
NS_ASSERTION(!IS_SURROGATE(ch), "surrogates should not appear in UTF8");
|
||||
@ -3003,20 +3020,23 @@ SetMissingGlyphs(gfxShapedWord *aShapedWord, const gchar *aUTF8,
|
||||
}
|
||||
|
||||
static void
|
||||
InitGlyphRunWithPangoAnalysis(gfxShapedWord *aShapedWord,
|
||||
InitGlyphRunWithPangoAnalysis(gfxShapedText *aShapedText,
|
||||
uint32_t aOffset, uint32_t aLength,
|
||||
const gchar *aUTF8, uint32_t aUTF8Length,
|
||||
PangoAnalysis *aAnalysis,
|
||||
PangoGlyphUnit aOverrideSpaceWidth,
|
||||
gfxFont *aFont)
|
||||
{
|
||||
uint32_t utf16Offset = 0;
|
||||
uint32_t utf16Offset = aOffset;
|
||||
PangoGlyphString *glyphString = pango_glyph_string_new();
|
||||
|
||||
const gchar *p = aUTF8;
|
||||
const gchar *end = p + aUTF8Length;
|
||||
while (p < end) {
|
||||
NS_ASSERTION(utf16Offset < aOffset + aLength,
|
||||
"overrun expected range of aShapedText");
|
||||
if (*p == 0) {
|
||||
aShapedWord->SetMissingGlyph(utf16Offset, 0, aFont);
|
||||
aShapedText->SetMissingGlyph(utf16Offset, 0, aFont);
|
||||
++p;
|
||||
++utf16Offset;
|
||||
continue;
|
||||
@ -3031,7 +3051,7 @@ InitGlyphRunWithPangoAnalysis(gfxShapedWord *aShapedWord,
|
||||
gint len = p - text;
|
||||
|
||||
pango_shape(text, len, aAnalysis, glyphString);
|
||||
SetGlyphs(aShapedWord, text, len, &utf16Offset, glyphString,
|
||||
SetGlyphs(aShapedText, text, len, &utf16Offset, glyphString,
|
||||
aOverrideSpaceWidth, aFont);
|
||||
}
|
||||
|
||||
@ -3059,11 +3079,14 @@ typedef union {
|
||||
} PangoAnalysisUnion;
|
||||
|
||||
bool
|
||||
gfxFcFont::InitGlyphRunWithPango(gfxShapedWord *aShapedWord,
|
||||
const PRUnichar *aString)
|
||||
gfxFcFont::InitGlyphRunWithPango(const PRUnichar *aString,
|
||||
uint32_t aOffset,
|
||||
uint32_t aLength,
|
||||
int32_t aScript,
|
||||
gfxShapedText *aShapedText)
|
||||
{
|
||||
const PangoScript script = static_cast<PangoScript>(aShapedWord->Script());
|
||||
NS_ConvertUTF16toUTF8 utf8(aString, aShapedWord->Length());
|
||||
const PangoScript script = static_cast<PangoScript>(aScript);
|
||||
NS_ConvertUTF16toUTF8 utf8(aString, aLength);
|
||||
|
||||
PangoFont *font = GetPangoFont();
|
||||
|
||||
@ -3169,7 +3192,7 @@ gfxFcFont::InitGlyphRunWithPango(gfxShapedWord *aShapedWord,
|
||||
PANGO_ENGINE_LANG(pango_map_get_engine(langMap, script));
|
||||
|
||||
analysis.local.font = font;
|
||||
analysis.local.level = aShapedWord->IsRightToLeft() ? 1 : 0;
|
||||
analysis.local.level = aShapedText->IsRightToLeft() ? 1 : 0;
|
||||
// gravity and flags are used in Pango 1.14.10 and newer.
|
||||
//
|
||||
// PANGO_GRAVITY_SOUTH is what we want for upright horizontal text. The
|
||||
@ -3192,7 +3215,8 @@ gfxFcFont::InitGlyphRunWithPango(gfxShapedWord *aShapedWord,
|
||||
PangoGlyphUnit spaceWidth =
|
||||
moz_pango_units_from_double(GetMetrics().spaceWidth);
|
||||
|
||||
InitGlyphRunWithPangoAnalysis(aShapedWord, utf8.get(), utf8.Length(),
|
||||
InitGlyphRunWithPangoAnalysis(aShapedText, aOffset, aLength,
|
||||
utf8.get(), utf8.Length(),
|
||||
&analysis.pango, spaceWidth, this);
|
||||
return true;
|
||||
}
|
||||
|
@ -1601,8 +1601,7 @@ gfxPlatform::SetupClusterBoundaries(gfxTextRun *aTextRun, const PRUnichar *aStri
|
||||
return;
|
||||
}
|
||||
|
||||
gfxShapedWord::SetupClusterBoundaries(aTextRun->GetCharacterGlyphs(),
|
||||
aString, aTextRun->GetLength());
|
||||
aTextRun->SetupClusterBoundaries(0, aString, aTextRun->GetLength());
|
||||
}
|
||||
|
||||
int32_t
|
||||
|
@ -217,7 +217,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void SaveGlyphs(gfxShapedWord *aShapedWord) {
|
||||
void SaveGlyphs(gfxShapedText *aShapedText, uint32_t aOffset) {
|
||||
uint32_t offsetInRun = mScriptItem->iCharPos;
|
||||
|
||||
// XXX We should store this in the item and only fetch it once
|
||||
@ -225,15 +225,18 @@ public:
|
||||
ScriptFontProperties(&sfp);
|
||||
|
||||
uint32_t offset = 0;
|
||||
nsAutoTArray<gfxShapedWord::DetailedGlyph,1> detailedGlyphs;
|
||||
gfxShapedWord::CompressedGlyph g;
|
||||
const uint32_t appUnitsPerDevUnit = aShapedWord->AppUnitsPerDevUnit();
|
||||
nsAutoTArray<gfxShapedText::DetailedGlyph,1> detailedGlyphs;
|
||||
gfxShapedText::CompressedGlyph g;
|
||||
gfxShapedText::CompressedGlyph *charGlyphs =
|
||||
aShapedText->GetCharacterGlyphs();
|
||||
const uint32_t appUnitsPerDevUnit = aShapedText->GetAppUnitsPerDevUnit();
|
||||
while (offset < mItemLength) {
|
||||
uint32_t runOffset = offsetInRun + offset;
|
||||
bool atClusterStart = aShapedWord->IsClusterStart(runOffset);
|
||||
uint32_t runOffset = aOffset + offsetInRun + offset;
|
||||
bool atClusterStart = charGlyphs[runOffset].IsClusterStart();
|
||||
if (offset > 0 && mClusters[offset] == mClusters[offset - 1]) {
|
||||
gfxShapedText::CompressedGlyph &g = charGlyphs[runOffset];
|
||||
NS_ASSERTION(!g.IsSimpleGlyph(), "overwriting a simple glyph");
|
||||
g.SetComplex(atClusterStart, false, 0);
|
||||
aShapedWord->SetGlyphs(runOffset, g, nullptr);
|
||||
} else {
|
||||
// Count glyphs for this character
|
||||
uint32_t k = mClusters[offset];
|
||||
@ -260,21 +263,21 @@ public:
|
||||
if (NS_IS_HIGH_SURROGATE(mItemString[offset]) &&
|
||||
offset + 1 < mItemLength &&
|
||||
NS_IS_LOW_SURROGATE(mItemString[offset + 1])) {
|
||||
aShapedWord->SetMissingGlyph(runOffset,
|
||||
aShapedText->SetMissingGlyph(runOffset,
|
||||
SURROGATE_TO_UCS4(mItemString[offset],
|
||||
mItemString[offset + 1]),
|
||||
mShaper->GetFont());
|
||||
} else {
|
||||
aShapedWord->SetMissingGlyph(runOffset, mItemString[offset],
|
||||
aShapedText->SetMissingGlyph(runOffset, mItemString[offset],
|
||||
mShaper->GetFont());
|
||||
}
|
||||
} else if (glyphCount == 1 && advance >= 0 &&
|
||||
mOffsets[k].dv == 0 && mOffsets[k].du == 0 &&
|
||||
gfxShapedWord::CompressedGlyph::IsSimpleAdvance(advance) &&
|
||||
gfxShapedWord::CompressedGlyph::IsSimpleGlyphID(glyph) &&
|
||||
gfxShapedText::CompressedGlyph::IsSimpleAdvance(advance) &&
|
||||
gfxShapedText::CompressedGlyph::IsSimpleGlyphID(glyph) &&
|
||||
atClusterStart)
|
||||
{
|
||||
aShapedWord->SetSimpleGlyph(runOffset, g.SetSimpleGlyph(advance, glyph));
|
||||
charGlyphs[runOffset].SetSimpleGlyph(advance, glyph);
|
||||
} else {
|
||||
if (detailedGlyphs.Length() < glyphCount) {
|
||||
if (!detailedGlyphs.AppendElements(glyphCount - detailedGlyphs.Length()))
|
||||
@ -286,10 +289,10 @@ public:
|
||||
details->mGlyphID = mGlyphs[k + i];
|
||||
details->mAdvance = mAdvances[k + i] * appUnitsPerDevUnit;
|
||||
details->mXOffset = float(mOffsets[k + i].du) * appUnitsPerDevUnit *
|
||||
aShapedWord->GetDirection();
|
||||
aShapedText->GetDirection();
|
||||
details->mYOffset = - float(mOffsets[k + i].dv) * appUnitsPerDevUnit;
|
||||
}
|
||||
aShapedWord->SetGlyphs(runOffset,
|
||||
aShapedText->SetGlyphs(runOffset,
|
||||
g.SetComplex(atClusterStart, true,
|
||||
glyphCount),
|
||||
detailedGlyphs.Elements());
|
||||
@ -367,8 +370,10 @@ class Uniscribe
|
||||
{
|
||||
public:
|
||||
Uniscribe(const PRUnichar *aString,
|
||||
gfxShapedWord *aShapedWord):
|
||||
mString(aString), mShapedWord(aShapedWord)
|
||||
gfxShapedText *aShapedText,
|
||||
uint32_t aOffset, uint32_t aLength):
|
||||
mString(aString), mShapedText(aShapedText),
|
||||
mOffset(aOffset), mLength(aLength)
|
||||
{
|
||||
}
|
||||
|
||||
@ -377,7 +382,7 @@ public:
|
||||
memset(&mState, 0, sizeof(SCRIPT_STATE));
|
||||
// Lock the direction. Don't allow the itemizer to change directions
|
||||
// based on character type.
|
||||
mState.uBidiLevel = mShapedWord->IsRightToLeft() ? 1 : 0;
|
||||
mState.uBidiLevel = mShapedText->IsRightToLeft() ? 1 : 0;
|
||||
mState.fOverrideDirection = true;
|
||||
}
|
||||
|
||||
@ -394,7 +399,7 @@ public:
|
||||
if (!mItems.SetLength(maxItems + 1)) {
|
||||
return 0;
|
||||
}
|
||||
while ((rv = ScriptItemize(mString, mShapedWord->Length(),
|
||||
while ((rv = ScriptItemize(mString, mLength,
|
||||
maxItems, &mControl, &mState,
|
||||
mItems.Elements(), &mNumItems)) == E_OUTOFMEMORY) {
|
||||
maxItems *= 2;
|
||||
@ -414,7 +419,9 @@ public:
|
||||
|
||||
private:
|
||||
const PRUnichar *mString;
|
||||
gfxShapedWord *mShapedWord;
|
||||
gfxShapedText *mShapedText;
|
||||
uint32_t mOffset;
|
||||
uint32_t mLength;
|
||||
|
||||
SCRIPT_CONTROL mControl;
|
||||
SCRIPT_STATE mState;
|
||||
@ -424,21 +431,24 @@ private:
|
||||
|
||||
|
||||
bool
|
||||
gfxUniscribeShaper::ShapeWord(gfxContext *aContext,
|
||||
gfxShapedWord *aShapedWord,
|
||||
const PRUnichar *aString)
|
||||
gfxUniscribeShaper::ShapeText(gfxContext *aContext,
|
||||
const PRUnichar *aText,
|
||||
uint32_t aOffset,
|
||||
uint32_t aLength,
|
||||
int32_t aScript,
|
||||
gfxShapedText *aShapedText)
|
||||
{
|
||||
DCFromContext aDC(aContext);
|
||||
|
||||
bool result = true;
|
||||
HRESULT rv;
|
||||
|
||||
Uniscribe us(aString, aShapedWord);
|
||||
Uniscribe us(aText, aShapedText, aOffset, aLength);
|
||||
|
||||
/* itemize the string */
|
||||
int numItems = us.Itemize();
|
||||
|
||||
uint32_t length = aShapedWord->Length();
|
||||
uint32_t length = aLength;
|
||||
SaveDC(aDC);
|
||||
uint32_t ivs = 0;
|
||||
for (int i = 0; i < numItems; ++i) {
|
||||
@ -454,18 +464,18 @@ gfxUniscribeShaper::ShapeWord(gfxContext *aContext,
|
||||
}
|
||||
|
||||
if (i+1 < numItems && iCharPosNext <= length - 2
|
||||
&& aString[iCharPosNext] == H_SURROGATE(kUnicodeVS17)
|
||||
&& uint32_t(aString[iCharPosNext + 1]) - L_SURROGATE(kUnicodeVS17)
|
||||
&& aText[iCharPosNext] == H_SURROGATE(kUnicodeVS17)
|
||||
&& uint32_t(aText[iCharPosNext + 1]) - L_SURROGATE(kUnicodeVS17)
|
||||
<= L_SURROGATE(kUnicodeVS256) - L_SURROGATE(kUnicodeVS17)) {
|
||||
|
||||
ivs = SURROGATE_TO_UCS4(aString[iCharPosNext],
|
||||
aString[iCharPosNext + 1]);
|
||||
ivs = SURROGATE_TO_UCS4(aText[iCharPosNext],
|
||||
aText[iCharPosNext + 1]);
|
||||
} else {
|
||||
ivs = 0;
|
||||
}
|
||||
|
||||
UniscribeItem item(aContext, aDC, this,
|
||||
aString + iCharPos,
|
||||
aText + iCharPos,
|
||||
iCharPosNext - iCharPos,
|
||||
us.ScriptItem(i), ivs);
|
||||
if (!item.AllocateBuffers()) {
|
||||
@ -509,7 +519,7 @@ gfxUniscribeShaper::ShapeWord(gfxContext *aContext,
|
||||
break;
|
||||
}
|
||||
|
||||
item.SaveGlyphs(aShapedWord);
|
||||
item.SaveGlyphs(aShapedText, aOffset);
|
||||
}
|
||||
|
||||
RestoreDC(aDC, -1);
|
||||
|
@ -29,9 +29,12 @@ public:
|
||||
MOZ_COUNT_DTOR(gfxUniscribeShaper);
|
||||
}
|
||||
|
||||
virtual bool ShapeWord(gfxContext *aContext,
|
||||
gfxShapedWord *aShapedWord,
|
||||
const PRUnichar *aString);
|
||||
virtual bool ShapeText(gfxContext *aContext,
|
||||
const PRUnichar *aText,
|
||||
uint32_t aOffset,
|
||||
uint32_t aLength,
|
||||
int32_t aScript,
|
||||
gfxShapedText *aShapedText);
|
||||
|
||||
SCRIPT_CACHE *ScriptCache() { return &mScriptCache; }
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user