From 64b1171f3c52be96daadfbd83065cff3fe44464a Mon Sep 17 00:00:00 2001 From: Jonathan Kew Date: Tue, 8 Jan 2013 14:38:48 +0000 Subject: [PATCH] Bug 761442 - don't use per-word shaping with fonts that use in opentype lookups. r=jdaggett --- gfx/thebes/gfxFont.cpp | 61 +++++++++++++++++++++++++++++++++++-- gfx/thebes/gfxFont.h | 27 ++++++++++++++++ layout/media/symbols.def.in | 8 +++++ 3 files changed, 93 insertions(+), 3 deletions(-) diff --git a/gfx/thebes/gfxFont.cpp b/gfx/thebes/gfxFont.cpp index 2985cd58dfe..ec60d05dee9 100644 --- a/gfx/thebes/gfxFont.cpp +++ b/gfx/thebes/gfxFont.cpp @@ -44,6 +44,7 @@ #include "gfxFontTest.h" #include "harfbuzz/hb.h" +#include "harfbuzz/hb-ot.h" #include "nsCRT.h" #include "GeckoProfiler.h" @@ -1492,6 +1493,54 @@ gfxFont::GetFontTable(uint32_t aTag) { haveTable ? &buffer : nullptr); } +static hb_blob_t * +HBGetTable(hb_face_t *face, hb_tag_t aTag, void *aUserData) +{ + gfxFont* font = static_cast(aUserData); + return font->GetFontTable(aTag); +} + +static bool +HasLayoutFeatureInvolving(hb_face_t *aFace, hb_tag_t aTag, uint16_t aGlyph) +{ + hb_set_t *lookups = hb_set_create(); + hb_set_t *glyphs = hb_set_create(); + + hb_ot_layout_collect_lookups(aFace, aTag, nullptr, nullptr, nullptr, + lookups); + + hb_codepoint_t index = -1; + while (hb_set_next(lookups, &index)) { + hb_ot_layout_lookup_collect_glyphs(aFace, aTag, index, + glyphs, glyphs, glyphs, + glyphs); + } + + bool result = hb_set_has(glyphs, aGlyph); + + hb_set_destroy(glyphs); + hb_set_destroy(lookups); + + return result; +} + +bool +gfxFont::CheckForFeaturesInvolvingSpace() +{ + hb_face_t *face = hb_face_create_for_tables(HBGetTable, this, nullptr); + + bool result = (hb_ot_layout_has_substitution(face) && + HasLayoutFeatureInvolving(face, HB_OT_TAG_GSUB, + GetSpaceGlyph())) || + (hb_ot_layout_has_positioning(face) && + HasLayoutFeatureInvolving(face, HB_OT_TAG_GPOS, + GetSpaceGlyph())); + + hb_face_destroy(face); + + return result; +} + /** * A helper function in case we need to do any rounding or other * processing here. @@ -2710,12 +2759,18 @@ gfxFont::SplitAndInitTextRun(gfxContext *aContext, return true; } + uint32_t flags = aTextRun->GetFlags(); + if (BypassShapedWordCache(flags)) { + return ShapeTextWithoutWordCache(aContext, aString + aRunStart, + aRunStart, aRunLength, aRunScript, + aTextRun); + } + InitWordCache(); // the only flags we care about for ShapedWord construction/caching - uint32_t flags = aTextRun->GetFlags() & - (gfxTextRunFactory::TEXT_IS_RTL | - gfxTextRunFactory::TEXT_DISABLE_OPTIONAL_LIGATURES); + flags &= (gfxTextRunFactory::TEXT_IS_RTL | + gfxTextRunFactory::TEXT_DISABLE_OPTIONAL_LIGATURES); if (sizeof(T) == sizeof(uint8_t)) { flags |= gfxTextRunFactory::TEXT_IS_8BIT; } diff --git a/gfx/thebes/gfxFont.h b/gfx/thebes/gfxFont.h index 5685b919e72..bc944b93c33 100644 --- a/gfx/thebes/gfxFont.h +++ b/gfx/thebes/gfxFont.h @@ -216,6 +216,7 @@ public: mIgnoreGSUB(false), mSVGInitialized(false), mWeight(500), mStretch(NS_FONT_STRETCH_NORMAL), + mHasSpaceFeaturesInitialized(false), mCheckedForGraphiteTables(false), mHasCmapTable(false), mUVSOffset(0), mUVSData(nullptr), @@ -348,6 +349,9 @@ public: uint16_t mWeight; int16_t mStretch; + bool mHasSpaceFeatures; + bool mHasSpaceFeaturesInitialized; + bool mHasGraphiteTables; bool mCheckedForGraphiteTables; bool mHasCmapTable; @@ -379,6 +383,7 @@ protected: mIgnoreGSUB(false), mSVGInitialized(false), mWeight(500), mStretch(NS_FONT_STRETCH_NORMAL), + mHasSpaceFeaturesInitialized(false), mCheckedForGraphiteTables(false), mHasCmapTable(false), mUVSOffset(0), mUVSData(nullptr), @@ -1561,6 +1566,26 @@ public: { return gfxPlatform::GetPlatform()->GetScaledFontForFont(aTarget, this); } protected: + bool BypassShapedWordCache(uint32_t aRunFlags) { + // When creating a textrun in optimizeSpeed mode, we always use the + // word cache (which means we do not support features that span + // inter-word spaces) + if (aRunFlags & gfxTextRunFactory::TEXT_OPTIMIZE_SPEED) { + return false; + } + // We record the presence of space-dependent features in the font entry + // so that subsequent instantiations for the same font face won't + // require us to re-check the tables; however, the actual check is done + // by gfxFont because not all font entry subclasses know how to create + // a harfbuzz face for introspection. + gfxFontEntry *fe = GetFontEntry(); + if (!fe->mHasSpaceFeaturesInitialized) { + fe->mHasSpaceFeaturesInitialized = true; + fe->mHasSpaceFeatures = CheckForFeaturesInvolvingSpace(); + } + return fe->mHasSpaceFeatures; + } + // For 8-bit text, expand to 16-bit and then call the following method. bool ShapeText(gfxContext *aContext, const uint8_t *aText, @@ -1617,6 +1642,8 @@ protected: int32_t aScript, gfxTextRun *aTextRun); + bool CheckForFeaturesInvolvingSpace(); + nsRefPtr mFontEntry; struct CacheHashKey { diff --git a/layout/media/symbols.def.in b/layout/media/symbols.def.in index 7dfe2651cae..29ffdb28d4b 100644 --- a/layout/media/symbols.def.in +++ b/layout/media/symbols.def.in @@ -544,7 +544,15 @@ hb_font_set_funcs hb_font_set_ppem hb_font_set_scale hb_language_from_string +hb_ot_layout_collect_lookups +hb_ot_layout_has_positioning +hb_ot_layout_has_substitution +hb_ot_layout_lookup_collect_glyphs hb_ot_tag_to_language +hb_set_create +hb_set_destroy +hb_set_has +hb_set_next hb_shape hb_unicode_funcs_create hb_unicode_funcs_get_empty