Bug 1024804 p2 - scan scriptrun for characters lacking variant glyphs. r=jfkthame

This commit is contained in:
John Daggett 2014-07-22 09:02:48 +09:00
Родитель 14c6cc4cc3
Коммит 94caf2851e
5 изменённых файлов: 178 добавлений и 30 удалений

Просмотреть файл

@ -177,6 +177,13 @@ gfxFontEntry::gfxFontEntry(const nsAString& aName, bool aIsStandardFace) :
memset(&mNonDefaultSubSpaceFeatures, 0, sizeof(mNonDefaultSubSpaceFeatures));
}
static PLDHashOperator
DestroyHBSet(const uint32_t& aTag, hb_set_t*& aSet, void *aUserArg)
{
hb_set_destroy(aSet);
return PL_DHASH_NEXT;
}
gfxFontEntry::~gfxFontEntry()
{
if (mCOLR) {
@ -193,6 +200,10 @@ gfxFontEntry::~gfxFontEntry()
gfxUserFontSet::UserFontCache::ForgetFont(this);
}
if (mFeatureInputs) {
mFeatureInputs->Enumerate(DestroyHBSet, nullptr);
}
// By the time the entry is destroyed, all font instances that were
// using it should already have been deleted, and so the HB and/or Gr
// face objects should have been released.
@ -925,15 +936,8 @@ gfxFontEntry::SupportsOpenTypeFeature(int32_t aScript, uint32_t aFeatureTag)
hb_face_t *face = GetHBFace();
if (hb_ot_layout_has_substitution(face)) {
// Decide what harfbuzz script code will be used for shaping
hb_script_t hbScript;
if (aScript <= MOZ_SCRIPT_INHERITED) {
// For unresolved "common" or "inherited" runs, default to Latin
// for now. (Compare gfxHarfBuzzShaper.)
hbScript = HB_SCRIPT_LATIN;
} else {
hbScript = hb_script_t(GetScriptTagForCode(aScript));
}
hb_script_t hbScript =
gfxHarfBuzzShaper::GetHBScriptUsedForShaping(aScript);
// Get the OpenType tag(s) that match this script code
hb_tag_t scriptTags[4] = {
@ -977,6 +981,66 @@ gfxFontEntry::SupportsOpenTypeFeature(int32_t aScript, uint32_t aFeatureTag)
return result;
}
const hb_set_t*
gfxFontEntry::InputsForOpenTypeFeature(int32_t aScript, uint32_t aFeatureTag)
{
if (!mFeatureInputs) {
mFeatureInputs = new nsDataHashtable<nsUint32HashKey,hb_set_t*>();
}
NS_ASSERTION(aFeatureTag == HB_TAG('s','u','p','s') ||
aFeatureTag == HB_TAG('s','u','b','s'),
"use of unknown feature tag");
uint32_t scriptFeature = SCRIPT_FEATURE(aScript, aFeatureTag);
hb_set_t *inputGlyphs;
if (mFeatureInputs->Get(scriptFeature, &inputGlyphs)) {
return inputGlyphs;
}
inputGlyphs = hb_set_create();
hb_face_t *face = GetHBFace();
if (hb_ot_layout_has_substitution(face)) {
hb_script_t hbScript =
gfxHarfBuzzShaper::GetHBScriptUsedForShaping(aScript);
// Get the OpenType tag(s) that match this script code
hb_tag_t scriptTags[4] = {
HB_TAG_NONE,
HB_TAG_NONE,
HB_TAG_NONE,
HB_TAG_NONE
};
hb_ot_tags_from_script(hbScript, &scriptTags[0], &scriptTags[1]);
// Replace the first remaining NONE with DEFAULT
hb_tag_t* scriptTag = &scriptTags[0];
while (*scriptTag != HB_TAG_NONE) {
++scriptTag;
}
*scriptTag = HB_OT_TAG_DEFAULT_SCRIPT;
const hb_tag_t kGSUB = HB_TAG('G','S','U','B');
hb_tag_t features[2] = { aFeatureTag, HB_TAG_NONE };
hb_set_t *featurelookups = hb_set_create();
hb_ot_layout_collect_lookups(face, kGSUB, scriptTags, nullptr,
features, featurelookups);
hb_codepoint_t index = -1;
while (hb_set_next(featurelookups, &index)) {
hb_ot_layout_lookup_collect_glyphs(face, kGSUB, index,
nullptr, inputGlyphs,
nullptr, nullptr);
}
}
hb_face_destroy(face);
mFeatureInputs->Put(scriptFeature, inputGlyphs);
return inputGlyphs;
}
bool
gfxFontEntry::SupportsGraphiteFeature(uint32_t aFeatureTag)
{
@ -2862,20 +2926,77 @@ gfxFont::SupportsVariantCaps(int32_t aScript,
}
bool
gfxFont::SupportsSubSuperscript(int32_t aScript, uint32_t aSubSuperscript)
gfxFont::SupportsSubSuperscript(uint32_t aSubSuperscript,
const uint8_t *aString,
uint32_t aLength, int32_t aRunScript)
{
bool ok = false;
switch (aSubSuperscript) {
case NS_FONT_VARIANT_POSITION_SUPER:
ok = SupportsFeature(aScript, HB_TAG('s','u','p','s'));
break;
case NS_FONT_VARIANT_POSITION_SUB:
ok = SupportsFeature(aScript, HB_TAG('s','u','b','s'));
break;
default:
break;
NS_ConvertASCIItoUTF16 unicodeString(reinterpret_cast<const char*>(aString),
aLength);
return SupportsSubSuperscript(aSubSuperscript, unicodeString.get(),
aLength, aRunScript);
}
bool
gfxFont::SupportsSubSuperscript(uint32_t aSubSuperscript,
const char16_t *aString,
uint32_t aLength, int32_t aRunScript)
{
NS_ASSERTION(aSubSuperscript == NS_FONT_VARIANT_POSITION_SUPER ||
aSubSuperscript == NS_FONT_VARIANT_POSITION_SUB,
"unknown value of font-variant-position");
uint32_t feature = aSubSuperscript == NS_FONT_VARIANT_POSITION_SUPER ?
HB_TAG('s','u','p','s') : HB_TAG('s','u','b','s');
if (!SupportsFeature(aRunScript, feature)) {
return false;
}
return ok;
// xxx - for graphite, don't really know how to sniff lookups so bail
if (mGraphiteShaper && gfxPlatform::GetPlatform()->UseGraphiteShaping()) {
return true;
}
if (!mHarfBuzzShaper) {
mHarfBuzzShaper = new gfxHarfBuzzShaper(this);
}
gfxHarfBuzzShaper* shaper =
static_cast<gfxHarfBuzzShaper*>(mHarfBuzzShaper.get());
if (!shaper->Initialize()) {
return false;
}
// get the hbset containing input glyphs for the feature
const hb_set_t *inputGlyphs = mFontEntry->InputsForOpenTypeFeature(aRunScript, feature);
// create an hbset containing default glyphs for the script run
hb_set_t *defaultGlyphsInRun = hb_set_create();
// for each character, get the glyph id
for (uint32_t i = 0; i < aLength; i++) {
uint32_t ch = aString[i];
if ((i + 1 < aLength) && NS_IS_HIGH_SURROGATE(ch) &&
NS_IS_LOW_SURROGATE(aString[i + 1])) {
i++;
ch = SURROGATE_TO_UCS4(ch, aString[i]);
}
if (ch == 0xa0) {
ch = ' ';
}
hb_codepoint_t gid = shaper->GetGlyph(ch, 0);
hb_set_add(defaultGlyphsInRun, gid);
}
// intersect with input glyphs, if size is not the same ==> fallback
uint32_t origSize = hb_set_get_population(defaultGlyphsInRun);
hb_set_intersect(defaultGlyphsInRun, inputGlyphs);
uint32_t intersectionSize = hb_set_get_population(defaultGlyphsInRun);
hb_set_destroy(defaultGlyphsInRun);
return origSize == intersectionSize;
}
bool
@ -5495,8 +5616,9 @@ gfxFontGroup::InitScriptRun(gfxContext *aContext,
if (mStyle.variantSubSuper != NS_FONT_VARIANT_POSITION_NORMAL &&
(aTextRun->GetShapingState() ==
gfxTextRun::eShapingState_ForceFallbackFeature ||
!matchedFont->SupportsSubSuperscript(aRunScript,
mStyle.variantSubSuper)))
!matchedFont->SupportsSubSuperscript(mStyle.variantSubSuper,
aString, aLength,
aRunScript)))
{
// fallback for subscript/superscript variant glyphs

Просмотреть файл

@ -297,6 +297,10 @@ public:
bool SupportsOpenTypeFeature(int32_t aScript, uint32_t aFeatureTag);
bool SupportsGraphiteFeature(uint32_t aFeatureTag);
// returns a set containing all input glyph ids for a given feature
const hb_set_t*
InputsForOpenTypeFeature(int32_t aScript, uint32_t aFeatureTag);
virtual bool IsSymbolFont();
virtual bool HasFontTable(uint32_t aTableTag);
@ -587,6 +591,7 @@ public:
nsAutoPtr<gfxMathTable> mMathTable;
nsTArray<gfxFontFeature> mFeatureSettings;
nsAutoPtr<nsDataHashtable<nsUint32HashKey,bool>> mSupportedFeatures;
nsAutoPtr<nsDataHashtable<nsUint32HashKey,hb_set_t*>> mFeatureInputs;
uint32_t mLanguageOverride;
// Color Layer font support
@ -1652,7 +1657,15 @@ public:
bool& aSyntheticUpperToSmallCaps);
// whether the font supports subscript/superscript feature
bool SupportsSubSuperscript(int32_t aScript, uint32_t aSubSuperscript);
// for fallback, need to verify that all characters in the run
// have variant substitutions
bool SupportsSubSuperscript(uint32_t aSubSuperscript,
const uint8_t *aString,
uint32_t aLength, int32_t aRunScript);
bool SupportsSubSuperscript(uint32_t aSubSuperscript,
const char16_t *aString,
uint32_t aLength, int32_t aRunScript);
// Subclasses may choose to look up glyph ids for characters.
// If they do not override this, gfxHarfBuzzShaper will fetch the cmap

Просмотреть файл

@ -1003,13 +1003,8 @@ gfxHarfBuzzShaper::ShapeText(gfxContext *aContext,
hb_script_t scriptTag;
if (aShapedText->Flags() & gfxTextRunFactory::TEXT_USE_MATH_SCRIPT) {
scriptTag = sMathScript;
} else if (aScript <= MOZ_SCRIPT_INHERITED) {
// 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?)
scriptTag = HB_SCRIPT_LATIN;
} else {
scriptTag = hb_script_t(GetScriptTagForCode(aScript));
scriptTag = GetHBScriptUsedForShaping(aScript);
}
hb_buffer_set_script(buffer, scriptTag);

Просмотреть файл

@ -9,6 +9,7 @@
#include "gfxFont.h"
#include "harfbuzz/hb.h"
#include "nsUnicodeProperties.h"
class gfxHarfBuzzShaper : public gfxFontShaper {
public:
@ -51,6 +52,21 @@ public:
hb_position_t GetHKerning(uint16_t aFirstGlyph,
uint16_t aSecondGlyph) const;
static hb_script_t
GetHBScriptUsedForShaping(int32_t aScript) {
// Decide what harfbuzz script code will be used for shaping
hb_script_t hbScript;
if (aScript <= MOZ_SCRIPT_INHERITED) {
// For unresolved "common" or "inherited" runs,
// default to Latin for now.
hbScript = HB_SCRIPT_LATIN;
} else {
hbScript =
hb_script_t(mozilla::unicode::GetScriptTagForCode(aScript));
}
return hbScript;
}
protected:
nsresult SetGlyphsFromRun(gfxContext *aContext,
gfxShapedText *aShapedText,

Просмотреть файл

@ -588,7 +588,9 @@ hb_set_add
hb_set_clear
hb_set_create
hb_set_destroy
hb_set_get_population
hb_set_has
hb_set_intersect
hb_set_is_empty
hb_set_next
hb_shape