From eb9c9884606212ea89f9af35c6a6913eec45452c Mon Sep 17 00:00:00 2001 From: Jonathan Kew Date: Thu, 15 Jan 2015 11:07:26 +0000 Subject: [PATCH] Bug 1120101 - Calculate vertical glyph origin based on 'vmtx' table in TrueType fonts. r=jdaggett --- gfx/thebes/gfxHarfBuzzShaper.cpp | 97 +++++++++++++++++++++++++++++++- gfx/thebes/gfxHarfBuzzShaper.h | 5 ++ 2 files changed, 101 insertions(+), 1 deletion(-) diff --git a/gfx/thebes/gfxHarfBuzzShaper.cpp b/gfx/thebes/gfxHarfBuzzShaper.cpp index c7fd9990864..7df10a42b30 100644 --- a/gfx/thebes/gfxHarfBuzzShaper.cpp +++ b/gfx/thebes/gfxHarfBuzzShaper.cpp @@ -41,6 +41,8 @@ gfxHarfBuzzShaper::gfxHarfBuzzShaper(gfxFont *aFont) mHmtxTable(nullptr), mVmtxTable(nullptr), mVORGTable(nullptr), + mLocaTable(nullptr), + mGlyfTable(nullptr), mCmapTable(nullptr), mCmapFormat(-1), mSubtableOffset(0), @@ -50,7 +52,8 @@ gfxHarfBuzzShaper::gfxHarfBuzzShaper(gfxFont *aFont) mUseFontGetGlyph(aFont->ProvidesGetGlyph()), mUseFontGlyphWidths(false), mInitialized(false), - mVerticalInitialized(false) + mVerticalInitialized(false), + mLocaLongOffsets(false) { } @@ -65,6 +68,18 @@ gfxHarfBuzzShaper::~gfxHarfBuzzShaper() if (mKernTable) { hb_blob_destroy(mKernTable); } + if (mVmtxTable) { + hb_blob_destroy(mVmtxTable); + } + if (mVORGTable) { + hb_blob_destroy(mVORGTable); + } + if (mLocaTable) { + hb_blob_destroy(mLocaTable); + } + if (mGlyfTable) { + hb_blob_destroy(mGlyfTable); + } if (mHBFont) { hb_font_destroy(mHBFont); } @@ -330,6 +345,72 @@ gfxHarfBuzzShaper::GetGlyphVOrigin(hb_codepoint_t aGlyph, return; } + if (mVmtxTable) { + if (mLocaTable && mGlyfTable) { + // TrueType outlines: use glyph bbox + top sidebearing + uint32_t offset; // offset of glyph record in the 'glyf' table + uint32_t len; + const char* data = hb_blob_get_data(mLocaTable, &len); + if (mLocaLongOffsets) { + if ((aGlyph + 1) * sizeof(AutoSwap_PRUint32) > len) { + *aY = 0; + return; + } + const AutoSwap_PRUint32* offsets = + reinterpret_cast(data); + offset = offsets[aGlyph]; + if (offset == offsets[aGlyph + 1]) { + // empty glyph + *aY = 0; + return; + } + } else { + if ((aGlyph + 1) * sizeof(AutoSwap_PRUint16) > len) { + *aY = 0; + return; + } + const AutoSwap_PRUint16* offsets = + reinterpret_cast(data); + offset = uint16_t(offsets[aGlyph]); + if (offset == uint16_t(offsets[aGlyph + 1])) { + // empty glyph + *aY = 0; + return; + } + offset *= 2; + } + + struct Glyf { // we only need the bounding-box at the beginning + // of the glyph record, not the actual outline data + AutoSwap_PRInt16 numberOfContours; + AutoSwap_PRInt16 xMin; + AutoSwap_PRInt16 yMin; + AutoSwap_PRInt16 xMax; + AutoSwap_PRInt16 yMax; + }; + data = hb_blob_get_data(mGlyfTable, &len); + if (offset + sizeof(Glyf) > len) { + *aY = 0; + return; + } + const Glyf* glyf = reinterpret_cast(data + offset); + + if (aGlyph >= uint32_t(mNumLongVMetrics)) { + aGlyph = mNumLongVMetrics - 1; + } + const GlyphMetrics* metrics = + reinterpret_cast + (hb_blob_get_data(mVmtxTable, nullptr)); + *aY = -FloatToFixed(mFont->FUnitsToDevUnitsFactor() * + (int16_t(metrics->metrics[aGlyph].lsb) + + int16_t(glyf->yMax))); + return; + } else { + // XXX TODO: CFF outlines - need to get glyph extents. + // For now, fall through to default code below. + } + } + // XXX should we consider using OS/2 sTypo* metrics if available? gfxFontEntry::AutoTable hheaTable(GetFont()->GetFontEntry(), @@ -1144,6 +1225,20 @@ gfxHarfBuzzShaper::InitializeVertical() mVORGTable = nullptr; } } + } else if (mVmtxTable) { + // Otherwise, try to load loca and glyf tables so that we can read + // bounding boxes (needed to support vertical glyph origin). + uint32_t len; + gfxFontEntry::AutoTable headTable(entry, + TRUETYPE_TAG('h','e','a','d')); + const HeadTable* head = + reinterpret_cast(hb_blob_get_data(headTable, + &len)); + if (len >= sizeof(HeadTable)) { + mLocaLongOffsets = int16_t(head->indexToLocFormat) > 0; + mLocaTable = entry->GetFontTable(TRUETYPE_TAG('l','o','c','a')); + mGlyfTable = entry->GetFontTable(TRUETYPE_TAG('g','l','y','f')); + } } return true; diff --git a/gfx/thebes/gfxHarfBuzzShaper.h b/gfx/thebes/gfxHarfBuzzShaper.h index 54ed5bdd73b..10ca6459ab3 100644 --- a/gfx/thebes/gfxHarfBuzzShaper.h +++ b/gfx/thebes/gfxHarfBuzzShaper.h @@ -130,6 +130,10 @@ protected: // For vertical fonts, cached vmtx and VORG table, if present. mutable hb_blob_t *mVmtxTable; mutable hb_blob_t *mVORGTable; + // And for vertical TrueType (not CFF) fonts that have vmtx, + // we also use loca and glyf to get glyph bounding boxes. + mutable hb_blob_t *mLocaTable; + mutable hb_blob_t *mGlyfTable; // Cached pointer to cmap subtable to be used for char-to-glyph mapping. // This comes from GetFontTablePtr; if it is non-null, our destructor @@ -157,6 +161,7 @@ protected: bool mInitialized; bool mVerticalInitialized; + bool mLocaLongOffsets; }; #endif /* GFX_HARFBUZZSHAPER_H */