Issue #457 - Remove the constructor from gfxShapedText::CompressedGlyph and make it a trivial class

Also provide a couple of convenience "factory" methods to create simple and complex glyph values.
This commit is contained in:
trav90 2022-05-28 11:45:35 -05:00 • committed by roytam1
commit c782076add
9 changed files with 137 additions and 102 deletions

View file

@ -310,6 +310,8 @@ gfxCoreTextShaper::SetGlyphsFromRun(gfxShapedText *aShapedText,
CTRunRef aCTRun, CTRunRef aCTRun,
int32_t aStringOffset) int32_t aStringOffset)
{ {
typedef gfxShapedText::CompressedGlyph CompressedGlyph;
// The word has been bidi-wrapped; aStringOffset is the number // The word has been bidi-wrapped; aStringOffset is the number
// of chars at the beginning of the CTLine that we should skip. // of chars at the beginning of the CTLine that we should skip.
// aCTRun is a glyph run from the CoreText layout process. // aCTRun is a glyph run from the CoreText layout process.
@ -392,8 +394,7 @@ gfxCoreTextShaper::SetGlyphsFromRun(gfxShapedText *aShapedText,
nullptr, nullptr, nullptr); nullptr, nullptr, nullptr);
AutoTArray<gfxShapedText::DetailedGlyph,1> detailedGlyphs; AutoTArray<gfxShapedText::DetailedGlyph,1> detailedGlyphs;
gfxShapedText::CompressedGlyph *charGlyphs = CompressedGlyph* charGlyphs = aShapedText->GetCharacterGlyphs() + aOffset;
aShapedText->GetCharacterGlyphs() + aOffset;
// CoreText gives us the glyphindex-to-charindex mapping, which relates each glyph // 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 // to a source text character; we also need the charindex-to-glyphindex mapping to
@ -614,10 +615,10 @@ gfxCoreTextShaper::SetGlyphsFromRun(gfxShapedText *aShapedText,
advance = int32_t(toNextGlyph * appUnitsPerDevUnit); advance = int32_t(toNextGlyph * appUnitsPerDevUnit);
} }
gfxTextRun::CompressedGlyph textRunGlyph; bool isClusterStart = charGlyphs[baseCharIndex].IsClusterStart();
textRunGlyph.SetComplex(charGlyphs[baseCharIndex].IsClusterStart(), aShapedText->SetGlyphs(aOffset + baseCharIndex,
true, detailedGlyphs.Length()); CompressedGlyph::MakeComplex(isClusterStart, true,
aShapedText->SetGlyphs(aOffset + baseCharIndex, textRunGlyph, detailedGlyphs.Length()),
detailedGlyphs.Elements()); detailedGlyphs.Elements());
detailedGlyphs.Clear(); detailedGlyphs.Clear();
@ -625,7 +626,7 @@ gfxCoreTextShaper::SetGlyphsFromRun(gfxShapedText *aShapedText,
// the rest of the chars in the group are ligature continuations, no associated glyphs // the rest of the chars in the group are ligature continuations, no associated glyphs
while (++baseCharIndex != endCharIndex && baseCharIndex < wordLength) { while (++baseCharIndex != endCharIndex && baseCharIndex < wordLength) {
gfxShapedText::CompressedGlyph &shapedTextGlyph = charGlyphs[baseCharIndex]; CompressedGlyph &shapedTextGlyph = charGlyphs[baseCharIndex];
NS_ASSERTION(!shapedTextGlyph.IsSimpleGlyph(), "overwriting a simple glyph"); NS_ASSERTION(!shapedTextGlyph.IsSimpleGlyph(), "overwriting a simple glyph");
shapedTextGlyph.SetComplex(inOrder && shapedTextGlyph.IsClusterStart(), false, 0); shapedTextGlyph.SetComplex(inOrder && shapedTextGlyph.IsClusterStart(), false, 0);
} }

View file

@ -62,13 +62,14 @@ void
gfxFT2Font::AddRange(const char16_t *aText, uint32_t aOffset, gfxFT2Font::AddRange(const char16_t *aText, uint32_t aOffset,
uint32_t aLength, gfxShapedText *aShapedText) uint32_t aLength, gfxShapedText *aShapedText)
{ {
typedef gfxShapedText::CompressedGlyph CompressedGlyph;
const uint32_t appUnitsPerDevUnit = aShapedText->GetAppUnitsPerDevUnit(); 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. // we'll pass this in/figure it out dynamically, but at this point there can be only one face.
gfxFT2LockedFace faceLock(this); gfxFT2LockedFace faceLock(this);
FT_Face face = faceLock.get(); FT_Face face = faceLock.get();
gfxShapedText::CompressedGlyph *charGlyphs = CompressedGlyph* charGlyphs = aShapedText->GetCharacterGlyphs();
aShapedText->GetCharacterGlyphs();
const gfxFT2Font::CachedGlyphData *cgd = nullptr, *cgdNext = nullptr; const gfxFT2Font::CachedGlyphData *cgd = nullptr, *cgdNext = nullptr;
@ -135,8 +136,8 @@ gfxFT2Font::AddRange(const char16_t *aText, uint32_t aOffset,
} }
if (advance >= 0 && if (advance >= 0 &&
gfxShapedText::CompressedGlyph::IsSimpleAdvance(advance) && CompressedGlyph::IsSimpleAdvance(advance) &&
gfxShapedText::CompressedGlyph::IsSimpleGlyphID(gid)) { CompressedGlyph::IsSimpleGlyphID(gid)) {
charGlyphs[aOffset].SetSimpleGlyph(advance, gid); charGlyphs[aOffset].SetSimpleGlyph(advance, gid);
} else if (gid == 0) { } else if (gid == 0) {
// gid = 0 only happens when the glyph is missing from the font // gid = 0 only happens when the glyph is missing from the font
@ -149,9 +150,11 @@ gfxFT2Font::AddRange(const char16_t *aText, uint32_t aOffset,
details.mAdvance = advance; details.mAdvance = advance;
details.mXOffset = 0; details.mXOffset = 0;
details.mYOffset = 0; details.mYOffset = 0;
gfxShapedText::CompressedGlyph g; bool isClusterStart = charGlyphs[aOffset].IsClusterStart();
g.SetComplex(charGlyphs[aOffset].IsClusterStart(), true, 1); aShapedText->SetGlyphs(aOffset,
aShapedText->SetGlyphs(aOffset, g, &details); CompressedGlyph::MakeComplex(isClusterStart,
true, 1),
&details);
} }
} }
} }

View file

@ -639,10 +639,10 @@ gfxShapedText::SetupClusterBoundaries(uint32_t aOffset,
const char16_t *aString, const char16_t *aString,
uint32_t aLength) uint32_t aLength)
{ {
CompressedGlyph *glyphs = GetCharacterGlyphs() + aOffset; CompressedGlyph* glyphs = GetCharacterGlyphs() + aOffset;
gfxTextRun::CompressedGlyph extendCluster; CompressedGlyph extendCluster =
extendCluster.SetComplex(false, true, 0); CompressedGlyph::MakeComplex(false, true, 0);
ClusterIterator iter(aString, aLength); ClusterIterator iter(aString, aLength);

View file

@ -245,7 +245,7 @@ struct gfxTextRange {
/** /**
* Font cache design: * Font cache design:
* *
* The mFonts hashtable contains most fonts, indexed by (gfxFontEntry*, style). * The mFonts hashtable contains most fonts, indexed by (gfxFontEntry*, style).
* It does not add a reference to the fonts it contains. * It does not add a reference to the fonts it contains.
* When a font's refcount decreases to zero, instead of deleting it we * When a font's refcount decreases to zero, instead of deleting it we
@ -699,21 +699,19 @@ public:
* This class records the information associated with a character in the * This class records the information associated with a character in the
* input string. It's optimized for the case where there is one glyph * input string. It's optimized for the case where there is one glyph
* representing that character alone. * representing that character alone.
* *
* A character can have zero or more associated glyphs. Each glyph * A character can have zero or more associated glyphs. Each glyph
* has an advance width and an x and y offset. * has an advance width and an x and y offset.
* A character may be the start of a cluster. * A character may be the start of a cluster.
* A character may be the start of a ligature group. * A character may be the start of a ligature group.
* A character can be "missing", indicating that the system is unable * A character can be "missing", indicating that the system is unable
* to render the character. * to render the character.
* *
* All characters in a ligature group conceptually share all the glyphs * All characters in a ligature group conceptually share all the glyphs
* associated with the characters in a group. * associated with the characters in a group.
*/ */
class CompressedGlyph { class CompressedGlyph {
public: public:
CompressedGlyph() { mValue = 0; }
enum { enum {
// Indicates that a cluster and ligature group starts at this // Indicates that a cluster and ligature group starts at this
// character; this character has a single glyph with a reasonable // character; this character has a single glyph with a reasonable
@ -843,25 +841,52 @@ public:
return toggle; return toggle;
} }
CompressedGlyph& SetSimpleGlyph(uint32_t aAdvanceAppUnits, uint32_t aGlyph) { // Create a CompressedGlyph value representing a simple glyph with
// no extra flags (line-break or is_space) set.
static CompressedGlyph
MakeSimpleGlyph(uint32_t aAdvanceAppUnits, uint32_t aGlyph) {
NS_ASSERTION(IsSimpleAdvance(aAdvanceAppUnits), "Advance overflow"); NS_ASSERTION(IsSimpleAdvance(aAdvanceAppUnits), "Advance overflow");
NS_ASSERTION(IsSimpleGlyphID(aGlyph), "Glyph overflow"); NS_ASSERTION(IsSimpleGlyphID(aGlyph), "Glyph overflow");
CompressedGlyph g;
g.mValue = FLAG_IS_SIMPLE_GLYPH |
(aAdvanceAppUnits << ADVANCE_SHIFT) |
aGlyph;
return g;
}
// Assign a simple glyph value to an existing CompressedGlyph record,
// preserving line-break/is-space flags if present.
CompressedGlyph& SetSimpleGlyph(uint32_t aAdvanceAppUnits,
uint32_t aGlyph) {
NS_ASSERTION(!CharTypeFlags(), "Char type flags lost"); NS_ASSERTION(!CharTypeFlags(), "Char type flags lost");
mValue = (mValue & (FLAGS_CAN_BREAK_BEFORE | FLAG_CHAR_IS_SPACE)) | mValue = (mValue & (FLAGS_CAN_BREAK_BEFORE | FLAG_CHAR_IS_SPACE)) |
FLAG_IS_SIMPLE_GLYPH | MakeSimpleGlyph(aAdvanceAppUnits, aGlyph).mValue;
(aAdvanceAppUnits << ADVANCE_SHIFT) | aGlyph;
return *this; return *this;
} }
// Create a CompressedGlyph value representing a complex glyph record,
// without any line-break or char-type flags.
static CompressedGlyph
MakeComplex(bool aClusterStart, bool aLigatureStart,
uint32_t aGlyphCount) {
CompressedGlyph g;
g.mValue = FLAG_NOT_MISSING |
(aClusterStart ? 0 : FLAG_NOT_CLUSTER_START) |
(aLigatureStart ? 0 : FLAG_NOT_LIGATURE_GROUP_START) |
(aGlyphCount << GLYPH_COUNT_SHIFT);
return g;
}
// Assign a complex glyph value to an existing CompressedGlyph record,
// preserving line-break/char-type flags if present.
CompressedGlyph& SetComplex(bool aClusterStart, bool aLigatureStart, CompressedGlyph& SetComplex(bool aClusterStart, bool aLigatureStart,
uint32_t aGlyphCount) { uint32_t aGlyphCount) {
mValue = (mValue & (FLAGS_CAN_BREAK_BEFORE | FLAG_CHAR_IS_SPACE)) | mValue = (mValue & (FLAGS_CAN_BREAK_BEFORE | FLAG_CHAR_IS_SPACE)) |
FLAG_NOT_MISSING |
CharTypeFlags() | CharTypeFlags() |
(aClusterStart ? 0 : FLAG_NOT_CLUSTER_START) | MakeComplex(aClusterStart, aLigatureStart, aGlyphCount).mValue;
(aLigatureStart ? 0 : FLAG_NOT_LIGATURE_GROUP_START) |
(aGlyphCount << GLYPH_COUNT_SHIFT);
return *this; return *this;
} }
/** /**
* Missing glyphs are treated as ligature group starts; don't mess with * Missing glyphs are treated as ligature group starts; don't mess with
* the cluster-start flag (see bugs 618870 and 619286). * the cluster-start flag (see bugs 618870 and 619286).
@ -914,7 +939,7 @@ public:
/** The advance, x-offset and y-offset of the glyph, in appunits /** The advance, x-offset and y-offset of the glyph, in appunits
* mAdvance is in the text direction (RTL or LTR) * mAdvance is in the text direction (RTL or LTR)
* mXOffset is always from left to right * mXOffset is always from left to right
* mYOffset is always from top to bottom */ * mYOffset is always from top to bottom */
int32_t mAdvance; int32_t mAdvance;
float mXOffset, mYOffset; float mXOffset, mYOffset;
}; };
@ -1039,7 +1064,7 @@ protected:
// For characters whose glyph data does not fit the "simple" glyph criteria // For characters whose glyph data does not fit the "simple" glyph criteria
// in CompressedGlyph, we use a sorted array to store the association // in CompressedGlyph, we use a sorted array to store the association
// between the source character offset and an index into an array // between the source character offset and an index into an array
// DetailedGlyphs. The CompressedGlyph record includes a count of // DetailedGlyphs. The CompressedGlyph record includes a count of
// the number of DetailedGlyph records that belong to the character, // the number of DetailedGlyph records that belong to the character,
// starting at the given index. // starting at the given index.
@ -1581,11 +1606,11 @@ public:
// (offset1, length1) plus the advance width of (offset1 + length1, // (offset1, length1) plus the advance width of (offset1 + length1,
// length2) should be the advance width of (offset1, length1 + length2) // length2) should be the advance width of (offset1, length1 + length2)
gfxFloat mAdvanceWidth; gfxFloat mAdvanceWidth;
// For zero-width substrings, these must be zero! // For zero-width substrings, these must be zero!
gfxFloat mAscent; // always non-negative gfxFloat mAscent; // always non-negative
gfxFloat mDescent; // always non-negative gfxFloat mDescent; // always non-negative
// Bounding box that is guaranteed to include everything drawn. // Bounding box that is guaranteed to include everything drawn.
// If a tight boundingBox was requested when these metrics were // If a tight boundingBox was requested when these metrics were
// generated, this will tightly wrap the glyphs, otherwise it is // generated, this will tightly wrap the glyphs, otherwise it is
@ -1648,11 +1673,11 @@ public:
* @param aSpacing spacing to insert before and after glyphs. The bounding box * @param aSpacing spacing to insert before and after glyphs. The bounding box
* need not include the spacing itself, but the spacing affects the glyph * need not include the spacing itself, but the spacing affects the glyph
* positions. null if there is no spacing. * positions. null if there is no spacing.
* *
* Callers guarantee: * Callers guarantee:
* -- aStart and aEnd are aligned to cluster and ligature boundaries * -- aStart and aEnd are aligned to cluster and ligature boundaries
* -- all glyphs use this font * -- all glyphs use this font
* *
* The default implementation just uses font metrics and aTextRun's * The default implementation just uses font metrics and aTextRun's
* advances, and assumes no characters fall outside the font box. In * advances, and assumes no characters fall outside the font box. In
* general this is insufficient, because that assumption is not always true. * general this is insufficient, because that assumption is not always true.
@ -1707,7 +1732,7 @@ public:
(mUnicodeRangeMap && !mUnicodeRangeMap->test(ch))) { (mUnicodeRangeMap && !mUnicodeRangeMap->test(ch))) {
return false; return false;
} }
return mFontEntry->HasCharacter(ch); return mFontEntry->HasCharacter(ch);
} }
const gfxCharacterMap* GetUnicodeRangeMap() const { const gfxCharacterMap* GetUnicodeRangeMap() const {
@ -1722,7 +1747,7 @@ public:
if (!mIsValid) { if (!mIsValid) {
return 0; return 0;
} }
return mFontEntry->GetUVSGlyph(aCh, aVS); return mFontEntry->GetUVSGlyph(aCh, aVS);
} }
template<typename T> template<typename T>

View file

@ -215,6 +215,8 @@ gfxGraphiteShaper::SetGlyphsFromSegment(DrawTarget *aDrawTarget,
const char16_t *aText, const char16_t *aText,
gr_segment *aSegment) gr_segment *aSegment)
{ {
typedef gfxShapedText::CompressedGlyph CompressedGlyph;
int32_t dev2appUnits = aShapedText->GetAppUnitsPerDevUnit(); int32_t dev2appUnits = aShapedText->GetAppUnitsPerDevUnit();
bool rtl = aShapedText->IsRightToLeft(); bool rtl = aShapedText->IsRightToLeft();
@ -291,8 +293,7 @@ gfxGraphiteShaper::SetGlyphsFromSegment(DrawTarget *aDrawTarget,
bool roundX, roundY; bool roundX, roundY;
GetRoundOffsetsToPixels(aDrawTarget, &roundX, &roundY); GetRoundOffsetsToPixels(aDrawTarget, &roundX, &roundY);
gfxShapedText::CompressedGlyph *charGlyphs = CompressedGlyph* charGlyphs = aShapedText->GetCharacterGlyphs() + aOffset;
aShapedText->GetCharacterGlyphs() + aOffset;
// now put glyphs into the textrun, one cluster at a time // now put glyphs into the textrun, one cluster at a time
for (uint32_t i = 0; i <= cIndex; ++i) { for (uint32_t i = 0; i <= cIndex; ++i) {
@ -325,8 +326,8 @@ gfxGraphiteShaper::SetGlyphsFromSegment(DrawTarget *aDrawTarget,
uint32_t appAdvance = roundX ? NSToIntRound(adv) * dev2appUnits : uint32_t appAdvance = roundX ? NSToIntRound(adv) * dev2appUnits :
NSToIntRound(adv * dev2appUnits); NSToIntRound(adv * dev2appUnits);
if (c.nGlyphs == 1 && if (c.nGlyphs == 1 &&
gfxShapedText::CompressedGlyph::IsSimpleGlyphID(gids[c.baseGlyph]) && CompressedGlyph::IsSimpleGlyphID(gids[c.baseGlyph]) &&
gfxShapedText::CompressedGlyph::IsSimpleAdvance(appAdvance) && CompressedGlyph::IsSimpleAdvance(appAdvance) &&
charGlyphs[offs].IsClusterStart() && charGlyphs[offs].IsClusterStart() &&
yLocs[c.baseGlyph] == 0) yLocs[c.baseGlyph] == 0)
{ {
@ -352,15 +353,17 @@ gfxGraphiteShaper::SetGlyphsFromSegment(DrawTarget *aDrawTarget,
d->mAdvance = 0; d->mAdvance = 0;
} }
} }
gfxShapedText::CompressedGlyph g; bool isClusterStart = charGlyphs[offs].IsClusterStart();
g.SetComplex(charGlyphs[offs].IsClusterStart(), aShapedText->SetGlyphs(aOffset + offs,
true, details.Length()); CompressedGlyph::MakeComplex(isClusterStart,
aShapedText->SetGlyphs(aOffset + offs, g, details.Elements()); true,
details.Length()),
details.Elements());
} }
for (uint32_t j = c.baseChar + 1; j < c.baseChar + c.nChars; ++j) { for (uint32_t j = c.baseChar + 1; j < c.baseChar + c.nChars; ++j) {
NS_ASSERTION(j < aLength, "unexpected offset"); NS_ASSERTION(j < aLength, "unexpected offset");
gfxShapedText::CompressedGlyph &g = charGlyphs[j]; CompressedGlyph &g = charGlyphs[j];
NS_ASSERTION(!g.IsSimpleGlyph(), "overwriting a simple glyph"); NS_ASSERTION(!g.IsSimpleGlyph(), "overwriting a simple glyph");
g.SetComplex(g.IsClusterStart(), false, 0); g.SetComplex(g.IsClusterStart(), false, 0);
} }

View file

@ -817,7 +817,7 @@ GetKernValueVersion1Fmt3(const void* aSubtable,
hdr->leftClassCount * hdr->rightClassCount > aSubtableLen) { hdr->leftClassCount * hdr->rightClassCount > aSubtableLen) {
return 0; return 0;
} }
if (aFirstGlyph >= glyphCount || aSecondGlyph >= glyphCount) { if (aFirstGlyph >= glyphCount || aSecondGlyph >= glyphCount) {
// glyphs are out of range for the class tables // glyphs are out of range for the class tables
return 0; return 0;
@ -1503,6 +1503,8 @@ gfxHarfBuzzShaper::SetGlyphsFromRun(DrawTarget *aDrawTarget,
hb_buffer_t *aBuffer, hb_buffer_t *aBuffer,
bool aVertical) bool aVertical)
{ {
typedef gfxShapedText::CompressedGlyph CompressedGlyph;
uint32_t numGlyphs; uint32_t numGlyphs;
const hb_glyph_info_t *ginfo = hb_buffer_get_glyph_infos(aBuffer, &numGlyphs); const hb_glyph_info_t *ginfo = hb_buffer_get_glyph_infos(aBuffer, &numGlyphs);
if (numGlyphs == 0) { if (numGlyphs == 0) {
@ -1541,8 +1543,7 @@ gfxHarfBuzzShaper::SetGlyphsFromRun(DrawTarget *aDrawTarget,
} }
int32_t appUnitsPerDevUnit = aShapedText->GetAppUnitsPerDevUnit(); int32_t appUnitsPerDevUnit = aShapedText->GetAppUnitsPerDevUnit();
gfxShapedText::CompressedGlyph *charGlyphs = CompressedGlyph* charGlyphs = aShapedText->GetCharacterGlyphs() + aOffset;
aShapedText->GetCharacterGlyphs() + aOffset;
// factor to convert 16.16 fixed-point pixels to app units // factor to convert 16.16 fixed-point pixels to app units
// (only used if not rounding) // (only used if not rounding)
@ -1688,8 +1689,8 @@ gfxHarfBuzzShaper::SetGlyphsFromRun(DrawTarget *aDrawTarget,
} }
// Check if it's a simple one-to-one mapping // Check if it's a simple one-to-one mapping
if (glyphsInClump == 1 && if (glyphsInClump == 1 &&
gfxTextRun::CompressedGlyph::IsSimpleGlyphID(ginfo[glyphStart].codepoint) && CompressedGlyph::IsSimpleGlyphID(ginfo[glyphStart].codepoint) &&
gfxTextRun::CompressedGlyph::IsSimpleAdvance(advance) && CompressedGlyph::IsSimpleAdvance(advance) &&
charGlyphs[baseCharIndex].IsClusterStart() && charGlyphs[baseCharIndex].IsClusterStart() &&
iOffset == 0 && b_offset == 0 && iOffset == 0 && b_offset == 0 &&
b_advance == 0 && bPos == 0) b_advance == 0 && bPos == 0)
@ -1760,11 +1761,12 @@ gfxHarfBuzzShaper::SetGlyphsFromRun(DrawTarget *aDrawTarget,
} }
} }
gfxShapedText::CompressedGlyph g; bool isClusterStart = charGlyphs[baseCharIndex].IsClusterStart();
g.SetComplex(charGlyphs[baseCharIndex].IsClusterStart(),
true, detailedGlyphs.Length());
aShapedText->SetGlyphs(aOffset + baseCharIndex, aShapedText->SetGlyphs(aOffset + baseCharIndex,
g, detailedGlyphs.Elements()); CompressedGlyph::MakeComplex(isClusterStart,
true,
detailedGlyphs.Length()),
detailedGlyphs.Elements());
detailedGlyphs.Clear(); detailedGlyphs.Clear();
} }
@ -1773,7 +1775,7 @@ gfxHarfBuzzShaper::SetGlyphsFromRun(DrawTarget *aDrawTarget,
// no associated glyphs // no associated glyphs
while (++baseCharIndex != endCharIndex && while (++baseCharIndex != endCharIndex &&
baseCharIndex < int32_t(wordLength)) { baseCharIndex < int32_t(wordLength)) {
gfxShapedText::CompressedGlyph &g = charGlyphs[baseCharIndex]; CompressedGlyph &g = charGlyphs[baseCharIndex];
NS_ASSERTION(!g.IsSimpleGlyph(), "overwriting a simple glyph"); NS_ASSERTION(!g.IsSimpleGlyph(), "overwriting a simple glyph");
g.SetComplex(g.IsClusterStart(), false, 0); g.SetComplex(g.IsClusterStart(), false, 0);
} }

View file

@ -244,7 +244,7 @@ gfxTextRun::ComputeLigatureData(Range aPartRange,
NS_ASSERTION(aPartRange.start < aPartRange.end, NS_ASSERTION(aPartRange.start < aPartRange.end,
"Computing ligature data for empty range"); "Computing ligature data for empty range");
NS_ASSERTION(aPartRange.end <= GetLength(), "Character length overflow"); NS_ASSERTION(aPartRange.end <= GetLength(), "Character length overflow");
LigatureData result; LigatureData result;
const CompressedGlyph *charGlyphs = mCharacterGlyphs; const CompressedGlyph *charGlyphs = mCharacterGlyphs;
@ -392,7 +392,7 @@ gfxTextRun::ShrinkToLigatureBoundaries(Range* aRange) const
{ {
if (aRange->start >= aRange->end) if (aRange->start >= aRange->end)
return; return;
const CompressedGlyph *charGlyphs = mCharacterGlyphs; const CompressedGlyph *charGlyphs = mCharacterGlyphs;
while (aRange->start < aRange->end && while (aRange->start < aRange->end &&
@ -440,7 +440,7 @@ ClipPartialLigature(const gfxTextRun* aTextRun,
} else { } else {
*aEnd = std::min(*aEnd, endEdge); *aEnd = std::min(*aEnd, endEdge);
} }
} }
} }
void void
@ -789,7 +789,7 @@ gfxTextRun::AccumulatePartialLigatureMetrics(gfxFont *aFont, Range aRange,
// ligature. Shift it left. // ligature. Shift it left.
metrics.mBoundingBox.x -= metrics.mBoundingBox.x -=
IsRightToLeft() ? metrics.mAdvanceWidth - (data.mPartAdvance + data.mPartWidth) IsRightToLeft() ? metrics.mAdvanceWidth - (data.mPartAdvance + data.mPartWidth)
: data.mPartAdvance; : data.mPartAdvance;
metrics.mAdvanceWidth = data.mPartWidth; metrics.mAdvanceWidth = data.mPartWidth;
aMetrics->CombineWith(metrics, IsRightToLeft()); aMetrics->CombineWith(metrics, IsRightToLeft());
@ -905,7 +905,7 @@ gfxTextRun::BreakAndMeasureText(uint32_t aStart, uint32_t aMaxLength,
} }
// There can't be a word-wrap break opportunity at the beginning of the // There can't be a word-wrap break opportunity at the beginning of the
// line: if the width is too small for even one character to fit, it // line: if the width is too small for even one character to fit, it
// could be the first and last break opportunity on the line, and that // could be the first and last break opportunity on the line, and that
// would trigger an infinite loop. // would trigger an infinite loop.
if (aSuppressBreak != eSuppressAllBreaks && if (aSuppressBreak != eSuppressAllBreaks &&
@ -923,7 +923,7 @@ gfxTextRun::BreakAndMeasureText(uint32_t aStart, uint32_t aMaxLength,
if (atHyphenationBreak) { if (atHyphenationBreak) {
hyphenatedAdvance += aProvider->GetHyphenWidth(); hyphenatedAdvance += aProvider->GetHyphenWidth();
} }
if (lastBreak < 0 || width + hyphenatedAdvance - trimmableAdvance <= aWidth) { if (lastBreak < 0 || width + hyphenatedAdvance - trimmableAdvance <= aWidth) {
// We can break here. // We can break here.
lastBreak = i; lastBreak = i;
@ -943,7 +943,7 @@ gfxTextRun::BreakAndMeasureText(uint32_t aStart, uint32_t aMaxLength,
} }
} }
} }
gfxFloat charAdvance; gfxFloat charAdvance;
if (i >= ligatureRange.start && i < ligatureRange.end) { if (i >= ligatureRange.start && i < ligatureRange.end) {
charAdvance = GetAdvanceForGlyphs(Range(i, i + 1)); charAdvance = GetAdvanceForGlyphs(Range(i, i + 1));
@ -956,7 +956,7 @@ gfxTextRun::BreakAndMeasureText(uint32_t aStart, uint32_t aMaxLength,
charAdvance = charAdvance =
ComputePartialLigatureWidth(Range(i, i + 1), aProvider); ComputePartialLigatureWidth(Range(i, i + 1), aProvider);
} }
advance += charAdvance; advance += charAdvance;
if (aTrimWhitespace || aWhitespaceCanHang) { if (aTrimWhitespace || aWhitespaceCanHang) {
if (mCharacterGlyphs[i].CharIsSpace()) { if (mCharacterGlyphs[i].CharIsSpace()) {
@ -1145,7 +1145,7 @@ gfxTextRun::AddGlyphRun(gfxFont *aFont, uint8_t aMatchType,
"mixed orientation should have been resolved"); "mixed orientation should have been resolved");
if (!aFont) { if (!aFont) {
return NS_OK; return NS_OK;
} }
uint32_t numGlyphRuns = mGlyphRuns.Length(); uint32_t numGlyphRuns = mGlyphRuns.Length();
if (!aForceNewRun && numGlyphRuns > 0) { if (!aForceNewRun && numGlyphRuns > 0) {
GlyphRun *lastGlyphRun = &mGlyphRuns[numGlyphRuns - 1]; GlyphRun *lastGlyphRun = &mGlyphRuns[numGlyphRuns - 1];
@ -1405,7 +1405,7 @@ gfxTextRun::SetSpaceGlyph(gfxFont* aFont, DrawTarget* aDrawTarget,
(GetFlags() & gfxTextRunFactory::TEXT_ORIENT_VERTICAL_UPRIGHT) != 0; (GetFlags() & gfxTextRunFactory::TEXT_ORIENT_VERTICAL_UPRIGHT) != 0;
gfxShapedWord* sw = aFont->GetShapedWord(aDrawTarget, gfxShapedWord* sw = aFont->GetShapedWord(aDrawTarget,
&space, 1, &space, 1,
gfxShapedWord::HashMix(0, ' '), gfxShapedWord::HashMix(0, ' '),
Script::LATIN, Script::LATIN,
vertical, vertical,
mAppUnitsPerDevUnit, mAppUnitsPerDevUnit,
@ -1439,8 +1439,8 @@ gfxTextRun::SetSpaceGlyphIfSimple(gfxFont* aFont, uint32_t aCharIndex,
AddGlyphRun(aFont, gfxTextRange::kFontGroup, aCharIndex, false, AddGlyphRun(aFont, gfxTextRange::kFontGroup, aCharIndex, false,
aOrientation); aOrientation);
CompressedGlyph g; CompressedGlyph g =
g.SetSimpleGlyph(spaceWidthAppUnits, spaceGlyph); CompressedGlyph::MakeSimpleGlyph(spaceWidthAppUnits, spaceGlyph);
if (aSpaceChar == ' ') { if (aSpaceChar == ' ') {
g.SetIsSpace(); g.SetIsSpace();
} }
@ -1471,7 +1471,7 @@ gfxTextRun::FetchGlyphExtents(DrawTarget* aRefDrawTarget)
bool fontIsSetup = false; bool fontIsSetup = false;
uint32_t j; uint32_t j;
gfxGlyphExtents *extents = font->GetOrCreateGlyphExtents(mAppUnitsPerDevUnit); gfxGlyphExtents *extents = font->GetOrCreateGlyphExtents(mAppUnitsPerDevUnit);
for (j = start; j < end; ++j) { for (j = start; j < end; ++j) {
const gfxTextRun::CompressedGlyph *glyphData = &charGlyphs[j]; const gfxTextRun::CompressedGlyph *glyphData = &charGlyphs[j];
if (glyphData->IsSimpleGlyph()) { if (glyphData->IsSimpleGlyph()) {
@ -1943,13 +1943,13 @@ gfxFontGroup::Copy(const gfxFontStyle *aStyle)
return fg; return fg;
} }
bool bool
gfxFontGroup::IsInvalidChar(uint8_t ch) gfxFontGroup::IsInvalidChar(uint8_t ch)
{ {
return ((ch & 0x7f) < 0x20 || ch == 0x7f); return ((ch & 0x7f) < 0x20 || ch == 0x7f);
} }
bool bool
gfxFontGroup::IsInvalidChar(char16_t ch) gfxFontGroup::IsInvalidChar(char16_t ch)
{ {
// All printable 7-bit ASCII values are OK // All printable 7-bit ASCII values are OK
@ -2514,8 +2514,8 @@ gfxFontGroup::InitScriptRun(DrawTarget* aDrawTarget,
detailedGlyph.mGlyphID = mainFont->GetSpaceGlyph(); detailedGlyph.mGlyphID = mainFont->GetSpaceGlyph();
detailedGlyph.mAdvance = advance; detailedGlyph.mAdvance = advance;
detailedGlyph.mXOffset = detailedGlyph.mYOffset = 0; detailedGlyph.mXOffset = detailedGlyph.mYOffset = 0;
gfxShapedText::CompressedGlyph g; CompressedGlyph g =
g.SetComplex(true, true, 1); CompressedGlyph::MakeComplex(true, true, 1);
aTextRun->SetGlyphs(aOffset + index, aTextRun->SetGlyphs(aOffset + index,
g, &detailedGlyph); g, &detailedGlyph);
} }
@ -3128,7 +3128,7 @@ gfxFontGroup::WhichPrefFontSupportsChar(uint32_t aCh, uint32_t aNextCh)
uint32_t unicodeRange = FindCharUnicodeRange(aCh); uint32_t unicodeRange = FindCharUnicodeRange(aCh);
charLang = pfl->GetFontPrefLangFor(unicodeRange); charLang = pfl->GetFontPrefLangFor(unicodeRange);
} }
// if the last pref font was the first family in the pref list, no need to recheck through a list of families // if the last pref font was the first family in the pref list, no need to recheck through a list of families
if (mLastPrefFont && charLang == mLastPrefLang && if (mLastPrefFont && charLang == mLastPrefLang &&
mLastPrefFirstFont && mLastPrefFont->HasCharacter(aCh)) { mLastPrefFirstFont && mLastPrefFont->HasCharacter(aCh)) {
@ -3190,7 +3190,7 @@ already_AddRefed<gfxFont>
gfxFontGroup::WhichSystemFontSupportsChar(uint32_t aCh, uint32_t aNextCh, gfxFontGroup::WhichSystemFontSupportsChar(uint32_t aCh, uint32_t aNextCh,
Script aRunScript) Script aRunScript)
{ {
gfxFontEntry *fe = gfxFontEntry *fe =
gfxPlatformFontList::PlatformFontList()-> gfxPlatformFontList::PlatformFontList()->
SystemFindFontForChar(aCh, aNextCh, aRunScript, &mStyle); SystemFindFontForChar(aCh, aNextCh, aRunScript, &mStyle);
if (fe) { if (fe) {

View file

@ -70,7 +70,7 @@ struct gfxTextRunDrawCallbacks {
* of text. It stores runs of positioned glyph data, each run having a single * of text. It stores runs of positioned glyph data, each run having a single
* gfxFont. The glyphs are associated with a string of source text, and the * gfxFont. The glyphs are associated with a string of source text, and the
* gfxTextRun APIs take parameters that are offsets into that source text. * gfxTextRun APIs take parameters that are offsets into that source text.
* *
* gfxTextRuns are mostly immutable. The only things that can change are * gfxTextRuns are mostly immutable. The only things that can change are
* inter-cluster spacing and line break placement. Spacing is always obtained * inter-cluster spacing and line break placement. Spacing is always obtained
* lazily by methods that need it, it is not cached. Line breaks are stored * lazily by methods that need it, it is not cached. Line breaks are stored
@ -78,7 +78,7 @@ struct gfxTextRunDrawCallbacks {
* not actually do anything to explicitly account for line breaks). Initially * not actually do anything to explicitly account for line breaks). Initially
* there are no line breaks. The textrun can record line breaks before or after * there are no line breaks. The textrun can record line breaks before or after
* any given cluster. (Line breaks specified inside clusters are ignored.) * any given cluster. (Line breaks specified inside clusters are ignored.)
* *
* It is important that zero-length substrings are handled correctly. This will * It is important that zero-length substrings are handled correctly. This will
* be on the test! * be on the test!
*/ */
@ -163,11 +163,11 @@ public:
* Set the potential linebreaks for a substring of the textrun. These are * Set the potential linebreaks for a substring of the textrun. These are
* the "allow break before" points. Initially, there are no potential * the "allow break before" points. Initially, there are no potential
* linebreaks. * linebreaks.
* *
* This can change glyphs and/or geometry! Some textruns' shapes * This can change glyphs and/or geometry! Some textruns' shapes
* depend on potential line breaks (e.g., title-case-converting textruns). * depend on potential line breaks (e.g., title-case-converting textruns).
* This function is virtual so that those textruns can reshape themselves. * This function is virtual so that those textruns can reshape themselves.
* *
* @return true if this changed the linebreaks, false if the new line * @return true if this changed the linebreaks, false if the new line
* breaks are the same as the old * breaks are the same as the old
*/ */
@ -179,7 +179,7 @@ public:
* potential line break points and computation of spacing. We pass the data * potential line break points and computation of spacing. We pass the data
* this way to allow lazy data acquisition; for example BreakAndMeasureText * this way to allow lazy data acquisition; for example BreakAndMeasureText
* will want to only ask for properties of text it's actually looking at. * will want to only ask for properties of text it's actually looking at.
* *
* NOTE that requested spacing may not actually be applied, if the textrun * NOTE that requested spacing may not actually be applied, if the textrun
* is unable to apply it in some context. Exception: spacing around a * is unable to apply it in some context. Exception: spacing around a
* whitespace character MUST always be applied. * whitespace character MUST always be applied.
@ -238,7 +238,7 @@ public:
* Draws a substring. Uses only GetSpacing from aBreakProvider. * Draws a substring. Uses only GetSpacing from aBreakProvider.
* The provided point is the baseline origin on the left of the string * The provided point is the baseline origin on the left of the string
* for LTR, on the right of the string for RTL. * for LTR, on the right of the string for RTL.
* *
* Drawing should respect advance widths in the sense that for LTR runs, * Drawing should respect advance widths in the sense that for LTR runs,
* Draw(Range(start, middle), pt, ...) followed by * Draw(Range(start, middle), pt, ...) followed by
* Draw(Range(middle, end), gfxPoint(pt.x + advance, pt.y), ...) * Draw(Range(middle, end), gfxPoint(pt.x + advance, pt.y), ...)
@ -250,7 +250,7 @@ public:
* Draw(Range(start, middle), gfxPoint(pt.x + advance, pt.y), ...) * Draw(Range(start, middle), gfxPoint(pt.x + advance, pt.y), ...)
* should have the same effect as * should have the same effect as
* Draw(Range(start, end), pt, ...) * Draw(Range(start, end), pt, ...)
* *
* Glyphs should be drawn in logical content order, which can be significant * Glyphs should be drawn in logical content order, which can be significant
* if they overlap (perhaps due to negative spacing). * if they overlap (perhaps due to negative spacing).
*/ */
@ -307,14 +307,14 @@ public:
* Clear all stored line breaks for the given range (both before and after), * Clear all stored line breaks for the given range (both before and after),
* and then set the line-break state before aRange.start to aBreakBefore and * and then set the line-break state before aRange.start to aBreakBefore and
* after the last cluster to aBreakAfter. * after the last cluster to aBreakAfter.
* *
* We require that before and after line breaks be consistent. For clusters * We require that before and after line breaks be consistent. For clusters
* i and i+1, we require that if there is a break after cluster i, a break * i and i+1, we require that if there is a break after cluster i, a break
* will be specified before cluster i+1. This may be temporarily violated * will be specified before cluster i+1. This may be temporarily violated
* (e.g. after reflowing line L and before reflowing line L+1); to handle * (e.g. after reflowing line L and before reflowing line L+1); to handle
* these temporary violations, we say that there is a break betwen i and i+1 * these temporary violations, we say that there is a break betwen i and i+1
* if a break is specified after i OR a break is specified before i+1. * if a break is specified after i OR a break is specified before i+1.
* *
* This can change textrun geometry! The existence of a linebreak can affect * This can change textrun geometry! The existence of a linebreak can affect
* the advance width of the cluster before the break (when kerning) or the * the advance width of the cluster before the break (when kerning) or the
* geometry of one cluster before the break or any number of clusters * geometry of one cluster before the break or any number of clusters
@ -322,11 +322,11 @@ public:
* arbitrary; if some scripts require breaking it, then we need to * arbitrary; if some scripts require breaking it, then we need to
* alter nsTextFrame::TrimTrailingWhitespace, perhaps drastically becase * alter nsTextFrame::TrimTrailingWhitespace, perhaps drastically becase
* it could affect the layout of frames before it...) * it could affect the layout of frames before it...)
* *
* We return true if glyphs or geometry changed, false otherwise. This * We return true if glyphs or geometry changed, false otherwise. This
* function is virtual so that gfxTextRun subclasses can reshape * function is virtual so that gfxTextRun subclasses can reshape
* properly. * properly.
* *
* @param aAdvanceWidthDelta if non-null, returns the change in advance * @param aAdvanceWidthDelta if non-null, returns the change in advance
* width of the given range. * width of the given range.
*/ */
@ -393,7 +393,7 @@ public:
* @param aBreakPriority in/out the priority of the break opportunity * @param aBreakPriority in/out the priority of the break opportunity
* saved in the line. If we are prioritizing break opportunities, we will * saved in the line. If we are prioritizing break opportunities, we will
* not set a break with a lower priority. @see gfxBreakPriority. * not set a break with a lower priority. @see gfxBreakPriority.
* *
* Note that negative advance widths are possible especially if negative * Note that negative advance widths are possible especially if negative
* spacing is provided. * spacing is provided.
*/ */
@ -596,11 +596,11 @@ public:
// when the part is at the start of the ligature, and after-spacing // when the part is at the start of the ligature, and after-spacing
// when the part is as the end of the ligature // when the part is as the end of the ligature
gfxFloat mPartWidth; gfxFloat mPartWidth;
bool mClipBeforePart; bool mClipBeforePart;
bool mClipAfterPart; bool mClipAfterPart;
}; };
// return storage used by this run, for memory reporter; // return storage used by this run, for memory reporter;
// nsTransformedTextRun needs to override this as it holds additional data // nsTransformedTextRun needs to override this as it holds additional data
virtual size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) virtual size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf)
@ -681,7 +681,7 @@ protected:
CompressedGlyph *mCharacterGlyphs; CompressedGlyph *mCharacterGlyphs;
private: private:
// **** general helpers **** // **** general helpers ****
// Get the total advance for a range of glyphs. // Get the total advance for a range of glyphs.
int32_t GetAdvanceForGlyphs(Range aRange) const; int32_t GetAdvanceForGlyphs(Range aRange) const;
@ -765,6 +765,7 @@ private:
class gfxFontGroup : public gfxTextRunFactory { class gfxFontGroup : public gfxTextRunFactory {
public: public:
typedef mozilla::unicode::Script Script; typedef mozilla::unicode::Script Script;
typedef gfxShapedText::CompressedGlyph CompressedGlyph;
static void Shutdown(); // platform must call this to release the languageAtomService static void Shutdown(); // platform must call this to release the languageAtomService

View file

@ -581,9 +581,9 @@ nsOpenTypeTable::MakeTextRun(DrawTarget* aDrawTarget,
aFontGroup->GetFirstValidFont()-> aFontGroup->GetFirstValidFont()->
GetGlyphHAdvance(aDrawTarget, aGlyph.glyphID)); GetGlyphHAdvance(aDrawTarget, aGlyph.glyphID));
detailedGlyph.mXOffset = detailedGlyph.mYOffset = 0; detailedGlyph.mXOffset = detailedGlyph.mYOffset = 0;
gfxShapedText::CompressedGlyph g; textRun->SetGlyphs(0,
g.SetComplex(true, true, 1); gfxShapedText::CompressedGlyph::MakeComplex(true, true, 1),
textRun->SetGlyphs(0, g, &detailedGlyph); &detailedGlyph);
return textRun.forget(); return textRun.forget();
} }
@ -1459,7 +1459,7 @@ nsMathMLChar::StretchEnumContext::EnumCallback(const FontFamilyName& aFamily,
if (!openTypeTable) { if (!openTypeTable) {
if (context->mTablesTried.Contains(glyphTable)) if (context->mTablesTried.Contains(glyphTable))
return true; // already tried this one return true; // already tried this one
// Only try this table once. // Only try this table once.
context->mTablesTried.AppendElement(glyphTable); context->mTablesTried.AppendElement(glyphTable);
} }
@ -1626,7 +1626,7 @@ nsMathMLChar::StretchInternal(nsPresContext* aPresContext,
if (!maxWidth && !largeop) { if (!maxWidth && !largeop) {
// Doing Stretch() not GetMaxWidth(), // Doing Stretch() not GetMaxWidth(),
// and not a largeop in display mode; we're done if size fits // and not a largeop in display mode; we're done if size fits
if ((targetSize <= 0) || if ((targetSize <= 0) ||
((isVertical && charSize >= targetSize) || ((isVertical && charSize >= targetSize) ||
IsSizeOK(charSize, targetSize, aStretchHint))) IsSizeOK(charSize, targetSize, aStretchHint)))
done = true; done = true;
@ -1678,7 +1678,7 @@ nsMathMLChar::StretchInternal(nsPresContext* aPresContext,
// variables accordingly. // variables accordingly.
mUnscaledAscent = aDesiredStretchSize.ascent; mUnscaledAscent = aDesiredStretchSize.ascent;
} }
if (glyphFound) { if (glyphFound) {
return NS_OK; return NS_OK;
} }
@ -1695,7 +1695,7 @@ nsMathMLChar::StretchInternal(nsPresContext* aPresContext,
if (!Preferences::GetBool("mathml.scale_stretchy_operators.enabled", true)) { if (!Preferences::GetBool("mathml.scale_stretchy_operators.enabled", true)) {
return NS_OK; return NS_OK;
} }
// stretchy character // stretchy character
if (stretchy) { if (stretchy) {
if (isVertical) { if (isVertical) {
@ -1863,7 +1863,7 @@ public:
nsDisplayMathMLCharForeground(nsDisplayListBuilder* aBuilder, nsDisplayMathMLCharForeground(nsDisplayListBuilder* aBuilder,
nsIFrame* aFrame, nsMathMLChar* aChar, nsIFrame* aFrame, nsMathMLChar* aChar,
uint32_t aIndex, bool aIsSelected) uint32_t aIndex, bool aIsSelected)
: nsDisplayItem(aBuilder, aFrame), mChar(aChar), : nsDisplayItem(aBuilder, aFrame), mChar(aChar),
mIndex(aIndex), mIsSelected(aIsSelected) { mIndex(aIndex), mIsSelected(aIsSelected) {
MOZ_COUNT_CTOR(nsDisplayMathMLCharForeground); MOZ_COUNT_CTOR(nsDisplayMathMLCharForeground);
} }
@ -1886,7 +1886,7 @@ public:
temp.Inflate(mFrame->PresContext()->AppUnitsPerDevPixel()); temp.Inflate(mFrame->PresContext()->AppUnitsPerDevPixel());
return temp; return temp;
} }
virtual void Paint(nsDisplayListBuilder* aBuilder, virtual void Paint(nsDisplayListBuilder* aBuilder,
nsRenderingContext* aCtx) override nsRenderingContext* aCtx) override
{ {
@ -1901,7 +1901,7 @@ public:
bool snap; bool snap;
return GetBounds(aBuilder, &snap); return GetBounds(aBuilder, &snap);
} }
virtual uint32_t GetPerFrameKey() override { virtual uint32_t GetPerFrameKey() override {
return (mIndex << nsDisplayItem::TYPE_BITS) return (mIndex << nsDisplayItem::TYPE_BITS)
| nsDisplayItem::GetPerFrameKey(); | nsDisplayItem::GetPerFrameKey();
@ -2355,7 +2355,7 @@ nsMathMLChar::PaintHorizontally(nsPresContext* aPresContext,
// _cairo_scaled_font_glyph_device_extents rounds outwards to the nearest // _cairo_scaled_font_glyph_device_extents rounds outwards to the nearest
// pixel, so the bm values can include 1 row of faint pixels on each edge. // pixel, so the bm values can include 1 row of faint pixels on each edge.
// Don't rely on this pixel as it can look like a gap. // Don't rely on this pixel as it can look like a gap.
if (bm.rightBearing - bm.leftBearing >= 2 * oneDevPixel) { if (bm.rightBearing - bm.leftBearing >= 2 * oneDevPixel) {
start[i] = dx + bm.leftBearing + oneDevPixel; // left join start[i] = dx + bm.leftBearing + oneDevPixel; // left join
end[i] = dx + bm.rightBearing - oneDevPixel; // right join end[i] = dx + bm.rightBearing - oneDevPixel; // right join
} else { } else {