зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1772189 - Avoid potential infinite recursion when initializing vertical metrics, if the font has a broken 'vmtx' table. r=lsalzman
Differential Revision: https://phabricator.services.mozilla.com/D148928
This commit is contained in:
Родитель
a413b63464
Коммит
d58446c275
|
@ -82,7 +82,6 @@ gfxDWriteFont::gfxDWriteFont(const RefPtr<UnscaledFontDWrite>& aUnscaledFont,
|
|||
AntialiasOption anAAOption)
|
||||
: gfxFont(aUnscaledFont, aFontEntry, aFontStyle, anAAOption),
|
||||
mFontFace(aFontFace ? aFontFace : aUnscaledFont->GetFontFace()),
|
||||
mMetrics(nullptr),
|
||||
mUseSubpixelPositions(false),
|
||||
mAllowManualShowGlyphs(true),
|
||||
mAzureScaledFontUsedClearType(false) {
|
||||
|
@ -112,7 +111,6 @@ gfxDWriteFont::~gfxDWriteFont() {
|
|||
if (auto* scaledFont = mAzureScaledFontGDI.exchange(nullptr)) {
|
||||
scaledFont->Release();
|
||||
}
|
||||
delete mMetrics;
|
||||
}
|
||||
|
||||
/* static */
|
||||
|
@ -305,6 +303,8 @@ bool gfxDWriteFont::GetFakeMetricsForArialBlack(
|
|||
}
|
||||
|
||||
void gfxDWriteFont::ComputeMetrics(AntialiasOption anAAOption) {
|
||||
::memset(&mMetrics, 0, sizeof(mMetrics));
|
||||
|
||||
DWRITE_FONT_METRICS fontMetrics;
|
||||
if (!(mFontEntry->Weight().Min() == FontWeight::FromInt(900) &&
|
||||
mFontEntry->Weight().Max() == FontWeight::FromInt(900) &&
|
||||
|
@ -381,22 +381,19 @@ void gfxDWriteFont::ComputeMetrics(AntialiasOption anAAOption) {
|
|||
mAllowManualShowGlyphs = false;
|
||||
}
|
||||
|
||||
mMetrics = new gfxFont::Metrics;
|
||||
::memset(mMetrics, 0, sizeof(*mMetrics));
|
||||
mMetrics.xHeight = fontMetrics.xHeight * mFUnitsConvFactor;
|
||||
mMetrics.capHeight = fontMetrics.capHeight * mFUnitsConvFactor;
|
||||
|
||||
mMetrics->xHeight = fontMetrics.xHeight * mFUnitsConvFactor;
|
||||
mMetrics->capHeight = fontMetrics.capHeight * mFUnitsConvFactor;
|
||||
mMetrics.maxAscent = round(fontMetrics.ascent * mFUnitsConvFactor);
|
||||
mMetrics.maxDescent = round(fontMetrics.descent * mFUnitsConvFactor);
|
||||
mMetrics.maxHeight = mMetrics.maxAscent + mMetrics.maxDescent;
|
||||
|
||||
mMetrics->maxAscent = round(fontMetrics.ascent * mFUnitsConvFactor);
|
||||
mMetrics->maxDescent = round(fontMetrics.descent * mFUnitsConvFactor);
|
||||
mMetrics->maxHeight = mMetrics->maxAscent + mMetrics->maxDescent;
|
||||
mMetrics.emHeight = mAdjustedSize;
|
||||
mMetrics.emAscent =
|
||||
mMetrics.emHeight * mMetrics.maxAscent / mMetrics.maxHeight;
|
||||
mMetrics.emDescent = mMetrics.emHeight - mMetrics.emAscent;
|
||||
|
||||
mMetrics->emHeight = mAdjustedSize;
|
||||
mMetrics->emAscent =
|
||||
mMetrics->emHeight * mMetrics->maxAscent / mMetrics->maxHeight;
|
||||
mMetrics->emDescent = mMetrics->emHeight - mMetrics->emAscent;
|
||||
|
||||
mMetrics->maxAdvance = mAdjustedSize;
|
||||
mMetrics.maxAdvance = mAdjustedSize;
|
||||
|
||||
// try to get the true maxAdvance value from 'hhea'
|
||||
gfxFontEntry::AutoTable hheaTable(GetFontEntry(),
|
||||
|
@ -406,28 +403,27 @@ void gfxDWriteFont::ComputeMetrics(AntialiasOption anAAOption) {
|
|||
const MetricsHeader* hhea = reinterpret_cast<const MetricsHeader*>(
|
||||
hb_blob_get_data(hheaTable, &len));
|
||||
if (len >= sizeof(MetricsHeader)) {
|
||||
mMetrics->maxAdvance =
|
||||
uint16_t(hhea->advanceWidthMax) * mFUnitsConvFactor;
|
||||
mMetrics.maxAdvance = uint16_t(hhea->advanceWidthMax) * mFUnitsConvFactor;
|
||||
}
|
||||
}
|
||||
|
||||
mMetrics->internalLeading =
|
||||
std::max(mMetrics->maxHeight - mMetrics->emHeight, 0.0);
|
||||
mMetrics->externalLeading = ceil(fontMetrics.lineGap * mFUnitsConvFactor);
|
||||
mMetrics.internalLeading =
|
||||
std::max(mMetrics.maxHeight - mMetrics.emHeight, 0.0);
|
||||
mMetrics.externalLeading = ceil(fontMetrics.lineGap * mFUnitsConvFactor);
|
||||
|
||||
UINT32 ucs = L' ';
|
||||
UINT16 glyph;
|
||||
if (SUCCEEDED(mFontFace->GetGlyphIndices(&ucs, 1, &glyph)) && glyph != 0) {
|
||||
mSpaceGlyph = glyph;
|
||||
mMetrics->spaceWidth = MeasureGlyphWidth(glyph);
|
||||
mMetrics.spaceWidth = MeasureGlyphWidth(glyph);
|
||||
} else {
|
||||
mMetrics->spaceWidth = 0;
|
||||
mMetrics.spaceWidth = 0;
|
||||
}
|
||||
|
||||
// try to get aveCharWidth from the OS/2 table, fall back to measuring 'x'
|
||||
// if the table is not available or if using hinted/pixel-snapped widths
|
||||
if (mUseSubpixelPositions) {
|
||||
mMetrics->aveCharWidth = 0;
|
||||
mMetrics.aveCharWidth = 0;
|
||||
gfxFontEntry::AutoTable os2Table(GetFontEntry(),
|
||||
TRUETYPE_TAG('O', 'S', '/', '2'));
|
||||
if (os2Table) {
|
||||
|
@ -438,57 +434,56 @@ void gfxDWriteFont::ComputeMetrics(AntialiasOption anAAOption) {
|
|||
// Not checking against sizeof(mozilla::OS2Table) here because older
|
||||
// versions of the table have different sizes; we only need the first
|
||||
// two 16-bit fields here.
|
||||
mMetrics->aveCharWidth =
|
||||
int16_t(os2->xAvgCharWidth) * mFUnitsConvFactor;
|
||||
mMetrics.aveCharWidth = int16_t(os2->xAvgCharWidth) * mFUnitsConvFactor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mMetrics->aveCharWidth < 1) {
|
||||
mMetrics->aveCharWidth = GetCharAdvance('x');
|
||||
if (mMetrics->aveCharWidth < 1) {
|
||||
if (mMetrics.aveCharWidth < 1) {
|
||||
mMetrics.aveCharWidth = GetCharAdvance('x');
|
||||
if (mMetrics.aveCharWidth < 1) {
|
||||
// Let's just assume the X is square.
|
||||
mMetrics->aveCharWidth = fontMetrics.xHeight * mFUnitsConvFactor;
|
||||
mMetrics.aveCharWidth = fontMetrics.xHeight * mFUnitsConvFactor;
|
||||
}
|
||||
}
|
||||
|
||||
mMetrics->zeroWidth = GetCharAdvance('0');
|
||||
mMetrics.zeroWidth = GetCharAdvance('0');
|
||||
|
||||
mMetrics->ideographicWidth = GetCharAdvance(kWaterIdeograph);
|
||||
mMetrics.ideographicWidth = GetCharAdvance(kWaterIdeograph);
|
||||
|
||||
mMetrics->underlineOffset = fontMetrics.underlinePosition * mFUnitsConvFactor;
|
||||
mMetrics->underlineSize = fontMetrics.underlineThickness * mFUnitsConvFactor;
|
||||
mMetrics->strikeoutOffset =
|
||||
mMetrics.underlineOffset = fontMetrics.underlinePosition * mFUnitsConvFactor;
|
||||
mMetrics.underlineSize = fontMetrics.underlineThickness * mFUnitsConvFactor;
|
||||
mMetrics.strikeoutOffset =
|
||||
fontMetrics.strikethroughPosition * mFUnitsConvFactor;
|
||||
mMetrics->strikeoutSize =
|
||||
mMetrics.strikeoutSize =
|
||||
fontMetrics.strikethroughThickness * mFUnitsConvFactor;
|
||||
|
||||
SanitizeMetrics(mMetrics, GetFontEntry()->mIsBadUnderlineFont);
|
||||
SanitizeMetrics(&mMetrics, GetFontEntry()->mIsBadUnderlineFont);
|
||||
|
||||
if (ApplySyntheticBold()) {
|
||||
auto delta = GetSyntheticBoldOffset();
|
||||
mMetrics->spaceWidth += delta;
|
||||
mMetrics->aveCharWidth += delta;
|
||||
mMetrics->maxAdvance += delta;
|
||||
if (mMetrics->zeroWidth > 0) {
|
||||
mMetrics->zeroWidth += delta;
|
||||
mMetrics.spaceWidth += delta;
|
||||
mMetrics.aveCharWidth += delta;
|
||||
mMetrics.maxAdvance += delta;
|
||||
if (mMetrics.zeroWidth > 0) {
|
||||
mMetrics.zeroWidth += delta;
|
||||
}
|
||||
if (mMetrics->ideographicWidth > 0) {
|
||||
mMetrics->ideographicWidth += delta;
|
||||
if (mMetrics.ideographicWidth > 0) {
|
||||
mMetrics.ideographicWidth += delta;
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
printf("Font: %p (%s) size: %f\n", this,
|
||||
NS_ConvertUTF16toUTF8(GetName()).get(), mStyle.size);
|
||||
printf(" emHeight: %f emAscent: %f emDescent: %f\n", mMetrics->emHeight, mMetrics->emAscent, mMetrics->emDescent);
|
||||
printf(" maxAscent: %f maxDescent: %f maxAdvance: %f\n", mMetrics->maxAscent, mMetrics->maxDescent, mMetrics->maxAdvance);
|
||||
printf(" internalLeading: %f externalLeading: %f\n", mMetrics->internalLeading, mMetrics->externalLeading);
|
||||
printf(" emHeight: %f emAscent: %f emDescent: %f\n", mMetrics.emHeight, mMetrics.emAscent, mMetrics.emDescent);
|
||||
printf(" maxAscent: %f maxDescent: %f maxAdvance: %f\n", mMetrics.maxAscent, mMetrics.maxDescent, mMetrics.maxAdvance);
|
||||
printf(" internalLeading: %f externalLeading: %f\n", mMetrics.internalLeading, mMetrics.externalLeading);
|
||||
printf(" spaceWidth: %f aveCharWidth: %f zeroWidth: %f\n",
|
||||
mMetrics->spaceWidth, mMetrics->aveCharWidth, mMetrics->zeroWidth);
|
||||
printf(" xHeight: %f capHeight: %f\n", mMetrics->xHeight, mMetrics->capHeight);
|
||||
mMetrics.spaceWidth, mMetrics.aveCharWidth, mMetrics.zeroWidth);
|
||||
printf(" xHeight: %f capHeight: %f\n", mMetrics.xHeight, mMetrics.capHeight);
|
||||
printf(" uOff: %f uSize: %f stOff: %f stSize: %f\n",
|
||||
mMetrics->underlineOffset, mMetrics->underlineSize, mMetrics->strikeoutOffset, mMetrics->strikeoutSize);
|
||||
mMetrics.underlineOffset, mMetrics.underlineSize, mMetrics.strikeoutOffset, mMetrics.strikeoutSize);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -766,7 +761,6 @@ bool gfxDWriteFont::GetGlyphBounds(uint16_t aGID, gfxRect* aBounds,
|
|||
void gfxDWriteFont::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
|
||||
FontCacheSizes* aSizes) const {
|
||||
gfxFont::AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
|
||||
aSizes->mFontInstances += aMallocSizeOf(mMetrics);
|
||||
if (mGlyphWidths) {
|
||||
aSizes->mFontInstances +=
|
||||
mGlyphWidths->ShallowSizeOfIncludingThis(aMallocSizeOf);
|
||||
|
|
|
@ -74,7 +74,7 @@ class gfxDWriteFont final : public gfxFont {
|
|||
bool ShouldRoundXOffset(cairo_t* aCairo) const override;
|
||||
|
||||
protected:
|
||||
const Metrics& GetHorizontalMetrics() const override { return *mMetrics; }
|
||||
const Metrics& GetHorizontalMetrics() const override { return mMetrics; }
|
||||
|
||||
bool GetFakeMetricsForArialBlack(DWRITE_FONT_METRICS* aFontMetrics);
|
||||
|
||||
|
@ -92,7 +92,7 @@ class gfxDWriteFont final : public gfxFont {
|
|||
RefPtr<IDWriteFontFace> mFontFace;
|
||||
RefPtr<IDWriteFontFace1> mFontFace1; // may be unavailable on older DWrite
|
||||
|
||||
Metrics* mMetrics;
|
||||
Metrics mMetrics;
|
||||
|
||||
// cache of glyph widths in 16.16 fixed-point pixels
|
||||
mozilla::UniquePtr<nsTHashMap<nsUint32HashKey, int32_t>> mGlyphWidths;
|
||||
|
|
|
@ -984,9 +984,17 @@ gfxFloat gfxFont::GetGlyphAdvance(uint16_t aGID, bool aVertical) {
|
|||
NS_ASSERTION(mFUnitsConvFactor >= 0.0f,
|
||||
"missing font unit conversion factor");
|
||||
if (gfxHarfBuzzShaper* shaper = GetHarfBuzzShaper()) {
|
||||
return (aVertical ? shaper->GetGlyphVAdvance(aGID)
|
||||
: shaper->GetGlyphHAdvance(aGID)) /
|
||||
65536.0;
|
||||
if (aVertical) {
|
||||
// Note that GetGlyphVAdvance may return -1 to indicate it was unable
|
||||
// to retrieve vertical metrics; in that case we fall back to the
|
||||
// aveCharWidth value as a default advance.
|
||||
int32_t advance = shaper->GetGlyphVAdvance(aGID);
|
||||
if (advance < 0) {
|
||||
return GetMetrics(nsFontMetrics::eVertical).aveCharWidth;
|
||||
}
|
||||
return advance / 65536.0;
|
||||
}
|
||||
return shaper->GetGlyphHAdvance(aGID) / 65536.0;
|
||||
}
|
||||
return 0.0;
|
||||
}
|
||||
|
@ -3948,6 +3956,7 @@ void gfxFont::CreateVerticalMetrics() {
|
|||
if (mFUnitsConvFactor < 0.0) {
|
||||
uint16_t upem = GetFontEntry()->UnitsPerEm();
|
||||
if (upem != gfxFontEntry::kInvalidUPEM) {
|
||||
AutoWriteLock lock(mLock);
|
||||
mFUnitsConvFactor = GetAdjustedSize() / upem;
|
||||
}
|
||||
}
|
||||
|
@ -4016,7 +4025,17 @@ void gfxFont::CreateVerticalMetrics() {
|
|||
metrics->maxDescent = halfExtent;
|
||||
SET_SIGNED(externalLeading, vhea->lineGap);
|
||||
}
|
||||
metrics->ideographicWidth = GetCharAdvance(kWaterIdeograph, true);
|
||||
// Call gfxHarfBuzzShaper::GetGlyphVAdvance directly, as GetCharAdvance
|
||||
// would potentially recurse if no v-advance is available and it attempts
|
||||
// to fall back to a value from mVerticalMetrics.
|
||||
if (gfxHarfBuzzShaper* shaper = GetHarfBuzzShaper()) {
|
||||
uint32_t gid = ProvidesGetGlyph()
|
||||
? GetGlyph(kWaterIdeograph, 0)
|
||||
: shaper->GetNominalGlyph(kWaterIdeograph);
|
||||
int32_t advance = shaper->GetGlyphVAdvance(gid);
|
||||
metrics->ideographicWidth =
|
||||
advance < 0 ? metrics->aveCharWidth : mFUnitsConvFactor * advance;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -320,10 +320,10 @@ hb_position_t gfxHarfBuzzShaper::GetGlyphVAdvance(hb_codepoint_t glyph) {
|
|||
InitializeVertical();
|
||||
|
||||
if (!mVmtxTable) {
|
||||
// Must be a "vertical" font that doesn't actually have vertical metrics;
|
||||
// use a fixed advance.
|
||||
return FloatToFixed(
|
||||
mFont->GetMetrics(nsFontMetrics::eVertical).aveCharWidth);
|
||||
// Must be a "vertical" font that doesn't actually have vertical metrics.
|
||||
// Return an invalid (negative) value to tell the caller to fall back to
|
||||
// something else.
|
||||
return -1;
|
||||
}
|
||||
|
||||
NS_ASSERTION(mNumLongVMetrics > 0,
|
||||
|
@ -367,11 +367,17 @@ hb_position_t gfxHarfBuzzShaper::HBGetGlyphVAdvance(hb_font_t* font,
|
|||
// and provide hinted platform-specific vertical advances (analogous to the
|
||||
// GetGlyphWidth method for horizontal advances). If that proves necessary,
|
||||
// we'll add a new gfxFont method and call it from here.
|
||||
//
|
||||
hb_position_t advance = fcd->mShaper->GetGlyphVAdvance(glyph);
|
||||
if (advance < 0) {
|
||||
// Not available (e.g. broken metrics in the font); use a fallback value.
|
||||
advance = FloatToFixed(fcd->mShaper->GetFont()
|
||||
->GetMetrics(nsFontMetrics::eVertical)
|
||||
.aveCharWidth);
|
||||
}
|
||||
// We negate the value from GetGlyphVAdvance here because harfbuzz shapes
|
||||
// with a coordinate system where positive is upwards, whereas the inline
|
||||
// direction in which glyphs advance is downwards.
|
||||
return -fcd->mShaper->GetGlyphVAdvance(glyph);
|
||||
return -advance;
|
||||
}
|
||||
|
||||
struct VORG {
|
||||
|
|
|
@ -47,6 +47,8 @@ class gfxHarfBuzzShaper : public gfxFontShaper {
|
|||
// get harfbuzz glyph advance, in font design units
|
||||
hb_position_t GetGlyphHAdvance(hb_codepoint_t glyph) const;
|
||||
|
||||
// Get vertical glyph advance, or -1 if not available; caller should check
|
||||
// for a negative result and provide a fallback or fail, as appropriate.
|
||||
hb_position_t GetGlyphVAdvance(hb_codepoint_t glyph);
|
||||
|
||||
void GetGlyphVOrigin(hb_codepoint_t aGlyph, hb_position_t* aX,
|
||||
|
|
Загрузка…
Ссылка в новой задаче