Bug 1674340 - Separate out language from gfxFontStyle and pass it separately to shaping processes that need it. r=lsalzman

This allows us to avoid instantiating separate gfxFont objects when content is tagged
with different 'lang' attributes, yet ends up using the same fonts (e.g. Wikipedia may
use a default font such as Arial for language names/links that are tagged with several
dozen different languages).

Differential Revision: https://phabricator.services.mozilla.com/D96978
This commit is contained in:
Jonathan Kew 2020-11-13 13:15:39 +00:00
parent 8e1dfa2a73
commit 16eb1dba68
34 changed files with 252 additions and 214 deletions

View file

@ -3997,6 +3997,9 @@ gfxFontGroup* CanvasRenderingContext2D::GetCurrentFontStyle() {
bool fontUpdated = SetFontInternal(kDefaultFontStyle, err); bool fontUpdated = SetFontInternal(kDefaultFontStyle, err);
if (err.Failed() || !fontUpdated) { if (err.Failed() || !fontUpdated) {
err.SuppressException(); err.SuppressException();
// XXX Should we get a default lang from the prescontext or something?
nsAtom* language = nsGkAtoms::x_western;
bool explicitLanguage = false;
gfxFontStyle style; gfxFontStyle style;
style.size = kDefaultFontSize; style.size = kDefaultFontSize;
gfxTextPerfMetrics* tp = nullptr; gfxTextPerfMetrics* tp = nullptr;
@ -4009,8 +4012,8 @@ gfxFontGroup* CanvasRenderingContext2D::GetCurrentFontStyle() {
GetAppUnitsValues(&perDevPixel, &perCSSPixel); GetAppUnitsValues(&perDevPixel, &perCSSPixel);
gfxFloat devToCssSize = gfxFloat(perDevPixel) / gfxFloat(perCSSPixel); gfxFloat devToCssSize = gfxFloat(perDevPixel) / gfxFloat(perCSSPixel);
CurrentState().fontGroup = gfxPlatform::GetPlatform()->CreateFontGroup( CurrentState().fontGroup = gfxPlatform::GetPlatform()->CreateFontGroup(
FontFamilyList(StyleGenericFontFamily::SansSerif), &style, tp, FontFamilyList(StyleGenericFontFamily::SansSerif), &style, language,
fontStats, nullptr, devToCssSize); explicitLanguage, tp, fontStats, nullptr, devToCssSize);
if (CurrentState().fontGroup) { if (CurrentState().fontGroup) {
CurrentState().font = kDefaultFontStyle; CurrentState().font = kDefaultFontStyle;
} else { } else {

View file

@ -149,7 +149,8 @@ already_AddRefed<nsFontMetrics> nsFontCache::GetMetricsFor(
if (fm->Font().Equals(aFont) && if (fm->Font().Equals(aFont) &&
fm->GetUserFontSet() == aParams.userFontSet && fm->GetUserFontSet() == aParams.userFontSet &&
fm->Language() == language && fm->Language() == language &&
fm->Orientation() == aParams.orientation) { fm->Orientation() == aParams.orientation &&
fm->ExplicitLanguage() == aParams.explicitLanguage) {
if (i != n) { if (i != n) {
// promote it to the end of the cache // promote it to the end of the cache
mFontMetrics.RemoveElementAt(i); mFontMetrics.RemoveElementAt(i);

View file

@ -114,12 +114,12 @@ nsFontMetrics::nsFontMetrics(const nsFont& aFont, const Params& aParams,
mDeviceContext(aContext), mDeviceContext(aContext),
mP2A(aContext->AppUnitsPerDevPixel()), mP2A(aContext->AppUnitsPerDevPixel()),
mOrientation(aParams.orientation), mOrientation(aParams.orientation),
mExplicitLanguage(aParams.explicitLanguage),
mTextRunRTL(false), mTextRunRTL(false),
mVertical(false), mVertical(false),
mTextOrientation(mozilla::StyleTextOrientation::Mixed) { mTextOrientation(mozilla::StyleTextOrientation::Mixed) {
gfxFontStyle style(aFont.style, aFont.weight, aFont.stretch, gfxFontStyle style(aFont.style, aFont.weight, aFont.stretch,
gfxFloat(aFont.size.ToAppUnits()) / mP2A, aParams.language, gfxFloat(aFont.size.ToAppUnits()) / mP2A, aFont.sizeAdjust,
aParams.explicitLanguage, aFont.sizeAdjust,
aFont.systemFont, mDeviceContext->IsPrinterContext(), aFont.systemFont, mDeviceContext->IsPrinterContext(),
aFont.synthesis & NS_FONT_SYNTHESIS_WEIGHT, aFont.synthesis & NS_FONT_SYNTHESIS_WEIGHT,
aFont.synthesis & NS_FONT_SYNTHESIS_STYLE, aFont.synthesis & NS_FONT_SYNTHESIS_STYLE,
@ -132,8 +132,8 @@ nsFontMetrics::nsFontMetrics(const nsFont& aFont, const Params& aParams,
gfxFloat devToCssSize = gfxFloat(mP2A) / gfxFloat(AppUnitsPerCSSPixel()); gfxFloat devToCssSize = gfxFloat(mP2A) / gfxFloat(AppUnitsPerCSSPixel());
mFontGroup = gfxPlatform::GetPlatform()->CreateFontGroup( mFontGroup = gfxPlatform::GetPlatform()->CreateFontGroup(
aFont.fontlist, &style, aParams.textPerf, aParams.fontStats, aFont.fontlist, &style, mLanguage, mExplicitLanguage, aParams.textPerf,
aParams.userFontSet, devToCssSize); aParams.fontStats, aParams.userFontSet, devToCssSize);
} }
nsFontMetrics::~nsFontMetrics() { nsFontMetrics::~nsFontMetrics() {

View file

@ -235,6 +235,8 @@ class nsFontMetrics final {
return mTextOrientation; return mTextOrientation;
} }
bool ExplicitLanguage() const { return mExplicitLanguage; }
gfxFontGroup* GetThebesFontGroup() const { return mFontGroup; } gfxFontGroup* GetThebesFontGroup() const { return mFontGroup; }
gfxUserFontSet* GetUserFontSet() const; gfxUserFontSet* GetUserFontSet() const;
@ -257,6 +259,11 @@ class nsFontMetrics final {
// descent) they will return. // descent) they will return.
FontOrientation mOrientation; FontOrientation mOrientation;
// Whether mLanguage comes from explicit markup (in which case it should be
// used to tailor effects like case-conversion) or is an inferred/default
// value.
bool mExplicitLanguage;
// These fields may be set by clients to control the behavior of methods // These fields may be set by clients to control the behavior of methods
// like GetWidth and DrawString according to the writing mode, direction // like GetWidth and DrawString according to the writing mode, direction
// and text-orientation desired. // and text-orientation desired.

View file

@ -78,7 +78,8 @@ static bool IsBuggyIndicScript(unicode::Script aScript) {
bool gfxCoreTextShaper::ShapeText(DrawTarget* aDrawTarget, bool gfxCoreTextShaper::ShapeText(DrawTarget* aDrawTarget,
const char16_t* aText, uint32_t aOffset, const char16_t* aText, uint32_t aOffset,
uint32_t aLength, Script aScript, uint32_t aLength, Script aScript,
bool aVertical, RoundingFlags aRounding, nsAtom* aLanguage, bool aVertical,
RoundingFlags aRounding,
gfxShapedText* aShapedText) { gfxShapedText* aShapedText) {
// Create a CFAttributedString with text and style info, so we can use // Create a CFAttributedString with text and style info, so we can use
// CoreText to lay it out. // CoreText to lay it out.

View file

@ -19,7 +19,7 @@ class gfxCoreTextShaper : public gfxFontShaper {
virtual ~gfxCoreTextShaper(); virtual ~gfxCoreTextShaper();
bool ShapeText(DrawTarget* aDrawTarget, const char16_t* aText, uint32_t aOffset, uint32_t aLength, bool ShapeText(DrawTarget* aDrawTarget, const char16_t* aText, uint32_t aOffset, uint32_t aLength,
Script aScript, bool aVertical, RoundingFlags aRounding, Script aScript, nsAtom* aLanguage, bool aVertical, RoundingFlags aRounding,
gfxShapedText* aShapedText) override; gfxShapedText* aShapedText) override;
// clean up static objects that may have been cached // clean up static objects that may have been cached

View file

@ -873,7 +873,7 @@ gfxDWriteFontList::gfxDWriteFontList() : mForceGDIClassicMaxFontSize(0.0) {
// Arial to avoid this. // Arial to avoid this.
FontFamily gfxDWriteFontList::GetDefaultFontForPlatform( FontFamily gfxDWriteFontList::GetDefaultFontForPlatform(
const gfxFontStyle* aStyle) { const gfxFontStyle* aStyle, nsAtom* aLanguage) {
// try Arial first // try Arial first
FontFamily ff; FontFamily ff;
ff = FindFamily("Arial"_ns); ff = FindFamily("Arial"_ns);
@ -1870,12 +1870,10 @@ void gfxDWriteFontList::GetDirectWriteSubstitutes() {
} }
} }
bool gfxDWriteFontList::FindAndAddFamilies(StyleGenericFontFamily aGeneric, bool gfxDWriteFontList::FindAndAddFamilies(
const nsACString& aFamily, StyleGenericFontFamily aGeneric, const nsACString& aFamily,
nsTArray<FamilyAndGeneric>* aOutput, nsTArray<FamilyAndGeneric>* aOutput, FindFamiliesFlags aFlags,
FindFamiliesFlags aFlags, gfxFontStyle* aStyle, nsAtom* aLanguage, gfxFloat aDevToCssSize) {
gfxFontStyle* aStyle,
gfxFloat aDevToCssSize) {
nsAutoCString keyName(aFamily); nsAutoCString keyName(aFamily);
BuildKeyNameFromFontName(keyName); BuildKeyNameFromFontName(keyName);
@ -1896,8 +1894,8 @@ bool gfxDWriteFontList::FindAndAddFamilies(StyleGenericFontFamily aGeneric,
return false; return false;
} }
return gfxPlatformFontList::FindAndAddFamilies(aGeneric, keyName, aOutput, return gfxPlatformFontList::FindAndAddFamilies(
aFlags, aStyle, aDevToCssSize); aGeneric, keyName, aOutput, aFlags, aStyle, aLanguage, aDevToCssSize);
} }
void gfxDWriteFontList::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf, void gfxDWriteFontList::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,

View file

@ -413,6 +413,7 @@ class gfxDWriteFontList final : public gfxPlatformFontList {
nsTArray<FamilyAndGeneric>* aOutput, nsTArray<FamilyAndGeneric>* aOutput,
FindFamiliesFlags aFlags, FindFamiliesFlags aFlags,
gfxFontStyle* aStyle = nullptr, gfxFontStyle* aStyle = nullptr,
nsAtom* aLanguage = nullptr,
gfxFloat aDevToCssSize = 1.0) override; gfxFloat aDevToCssSize = 1.0) override;
gfxFloat GetForceGDIClassicMaxFontSize() { gfxFloat GetForceGDIClassicMaxFontSize() {
@ -425,7 +426,8 @@ class gfxDWriteFontList final : public gfxPlatformFontList {
FontListSizes* aSizes) const; FontListSizes* aSizes) const;
protected: protected:
FontFamily GetDefaultFontForPlatform(const gfxFontStyle* aStyle) override; FontFamily GetDefaultFontForPlatform(const gfxFontStyle* aStyle,
nsAtom* aLanguage = nullptr) override;
// attempt to use platform-specific fallback for the given character, // attempt to use platform-specific fallback for the given character,
// return null if no usable result found // return null if no usable result found

View file

@ -1737,8 +1737,8 @@ searchDone:
return fe; return fe;
} }
FontFamily gfxFT2FontList::GetDefaultFontForPlatform( FontFamily gfxFT2FontList::GetDefaultFontForPlatform(const gfxFontStyle* aStyle,
const gfxFontStyle* aStyle) { nsAtom* aLanguage) {
FontFamily ff; FontFamily ff;
#if defined(MOZ_WIDGET_ANDROID) #if defined(MOZ_WIDGET_ANDROID)
ff = FindFamily("Roboto"_ns); ff = FindFamily("Roboto"_ns);

View file

@ -214,7 +214,8 @@ class gfxFT2FontList final : public gfxPlatformFontList {
void FindFontsInDir(const nsCString& aDir, FontNameCache* aFNC); void FindFontsInDir(const nsCString& aDir, FontNameCache* aFNC);
FontFamily GetDefaultFontForPlatform(const gfxFontStyle* aStyle) override; FontFamily GetDefaultFontForPlatform(const gfxFontStyle* aStyle,
nsAtom* aLanguage = nullptr) override;
nsTHashtable<nsCStringHashKey> mSkipSpaceLookupCheckFamilies; nsTHashtable<nsCStringHashKey> mSkipSpaceLookupCheckFamilies;

View file

@ -42,10 +42,11 @@ using namespace mozilla::gfx;
bool gfxFT2Font::ShapeText(DrawTarget* aDrawTarget, const char16_t* aText, bool gfxFT2Font::ShapeText(DrawTarget* aDrawTarget, const char16_t* aText,
uint32_t aOffset, uint32_t aLength, Script aScript, uint32_t aOffset, uint32_t aLength, Script aScript,
bool aVertical, RoundingFlags aRounding, nsAtom* aLanguage, bool aVertical,
RoundingFlags aRounding,
gfxShapedText* aShapedText) { gfxShapedText* aShapedText) {
if (!gfxFont::ShapeText(aDrawTarget, aText, aOffset, aLength, aScript, if (!gfxFont::ShapeText(aDrawTarget, aText, aOffset, aLength, aScript,
aVertical, aRounding, aShapedText)) { aLanguage, aVertical, aRounding, aShapedText)) {
// harfbuzz must have failed(?!), just render raw glyphs // harfbuzz must have failed(?!), just render raw glyphs
AddRange(aText, aOffset, aLength, aShapedText); AddRange(aText, aOffset, aLength, aShapedText);
PostShapingFixup(aDrawTarget, aText, aOffset, aLength, aVertical, PostShapingFixup(aDrawTarget, aText, aOffset, aLength, aVertical,

View file

@ -63,7 +63,7 @@ class gfxFT2Font : public gfxFT2FontBase {
bool ShapeText(DrawTarget* aDrawTarget, const char16_t* aText, bool ShapeText(DrawTarget* aDrawTarget, const char16_t* aText,
uint32_t aOffset, uint32_t aLength, Script aScript, uint32_t aOffset, uint32_t aLength, Script aScript,
bool aVertical, RoundingFlags aRounding, nsAtom* aLanguage, bool aVertical, RoundingFlags aRounding,
gfxShapedText* aShapedText) override; gfxShapedText* aShapedText) override;
void FillGlyphDataForChar(FT_Face face, uint32_t ch, CachedGlyphData* gd); void FillGlyphDataForChar(FT_Face face, uint32_t ch, CachedGlyphData* gd);

View file

@ -1856,11 +1856,11 @@ void gfxFcPlatformFontList::GetFontList(nsAtom* aLangGroup,
} }
FontFamily gfxFcPlatformFontList::GetDefaultFontForPlatform( FontFamily gfxFcPlatformFontList::GetDefaultFontForPlatform(
const gfxFontStyle* aStyle) { const gfxFontStyle* aStyle, nsAtom* aLanguage) {
// Get the default font by using a fake name to retrieve the first // Get the default font by using a fake name to retrieve the first
// scalable font that fontconfig suggests for the given language. // scalable font that fontconfig suggests for the given language.
PrefFontList* prefFonts = PrefFontList* prefFonts = FindGenericFamilies(
FindGenericFamilies("-moz-default"_ns, aStyle->language); "-moz-default"_ns, aLanguage ? aLanguage : nsGkAtoms::x_western);
NS_ASSERTION(prefFonts, "null list of generic fonts"); NS_ASSERTION(prefFonts, "null list of generic fonts");
if (prefFonts && !prefFonts->IsEmpty()) { if (prefFonts && !prefFonts->IsEmpty()) {
return (*prefFonts)[0]; return (*prefFonts)[0];
@ -1906,10 +1906,9 @@ gfxFontEntry* gfxFcPlatformFontList::MakePlatformFont(
bool gfxFcPlatformFontList::FindAndAddFamilies( bool gfxFcPlatformFontList::FindAndAddFamilies(
StyleGenericFontFamily aGeneric, const nsACString& aFamily, StyleGenericFontFamily aGeneric, const nsACString& aFamily,
nsTArray<FamilyAndGeneric>* aOutput, FindFamiliesFlags aFlags, nsTArray<FamilyAndGeneric>* aOutput, FindFamiliesFlags aFlags,
gfxFontStyle* aStyle, gfxFloat aDevToCssSize) { gfxFontStyle* aStyle, nsAtom* aLanguage, gfxFloat aDevToCssSize) {
nsAutoCString familyName(aFamily); nsAutoCString familyName(aFamily);
ToLowerCase(familyName); ToLowerCase(familyName);
nsAtom* language = (aStyle ? aStyle->language.get() : nullptr);
if (!(aFlags & FindFamiliesFlags::eQuotedFamilyName)) { if (!(aFlags & FindFamiliesFlags::eQuotedFamilyName)) {
// deprecated generic names are explicitly converted to standard generics // deprecated generic names are explicitly converted to standard generics
@ -1926,7 +1925,7 @@ bool gfxFcPlatformFontList::FindAndAddFamilies(
// fontconfig generics? use fontconfig to determine the family for lang // fontconfig generics? use fontconfig to determine the family for lang
if (isDeprecatedGeneric || if (isDeprecatedGeneric ||
mozilla::FontFamilyName::Convert(familyName).IsGeneric()) { mozilla::FontFamilyName::Convert(familyName).IsGeneric()) {
PrefFontList* prefFonts = FindGenericFamilies(familyName, language); PrefFontList* prefFonts = FindGenericFamilies(familyName, aLanguage);
if (prefFonts && !prefFonts->IsEmpty()) { if (prefFonts && !prefFonts->IsEmpty()) {
aOutput->AppendElements(*prefFonts); aOutput->AppendElements(*prefFonts);
return true; return true;
@ -1986,7 +1985,7 @@ bool gfxFcPlatformFontList::FindAndAddFamilies(
} }
gfxPlatformFontList::FindAndAddFamilies( gfxPlatformFontList::FindAndAddFamilies(
aGeneric, nsDependentCString(ToCharPtr(substName)), &cachedFamilies, aGeneric, nsDependentCString(ToCharPtr(substName)), &cachedFamilies,
aFlags); aFlags, aStyle, aLanguage);
} }
// Cache the resulting list, so we don't have to do this again. // Cache the resulting list, so we don't have to do this again.

View file

@ -266,6 +266,7 @@ class gfxFcPlatformFontList final : public gfxPlatformFontList {
nsTArray<FamilyAndGeneric>* aOutput, nsTArray<FamilyAndGeneric>* aOutput,
FindFamiliesFlags aFlags, FindFamiliesFlags aFlags,
gfxFontStyle* aStyle = nullptr, gfxFontStyle* aStyle = nullptr,
nsAtom* aLanguage = nullptr,
gfxFloat aDevToCssSize = 1.0) override; gfxFloat aDevToCssSize = 1.0) override;
bool GetStandardFamilyName(const nsCString& aFontName, bool GetStandardFamilyName(const nsCString& aFontName,
@ -320,7 +321,8 @@ class gfxFcPlatformFontList final : public gfxPlatformFontList {
static void CheckFontUpdates(nsITimer* aTimer, void* aThis); static void CheckFontUpdates(nsITimer* aTimer, void* aThis);
FontFamily GetDefaultFontForPlatform(const gfxFontStyle* aStyle) override; FontFamily GetDefaultFontForPlatform(const gfxFontStyle* aStyle,
nsAtom* aLanguage = nullptr) override;
enum class DistroID : int8_t { enum class DistroID : int8_t {
Unknown = 0, Unknown = 0,

View file

@ -2732,9 +2732,9 @@ static char16_t IsBoundarySpace(char16_t aChar, char16_t aNextChar) {
template <typename T> template <typename T>
gfxShapedWord* gfxFont::GetShapedWord( gfxShapedWord* gfxFont::GetShapedWord(
DrawTarget* aDrawTarget, const T* aText, uint32_t aLength, uint32_t aHash, DrawTarget* aDrawTarget, const T* aText, uint32_t aLength, uint32_t aHash,
Script aRunScript, bool aVertical, int32_t aAppUnitsPerDevUnit, Script aRunScript, nsAtom* aLanguage, bool aVertical,
gfx::ShapedTextFlags aFlags, RoundingFlags aRounding, int32_t aAppUnitsPerDevUnit, gfx::ShapedTextFlags aFlags,
gfxTextPerfMetrics* aTextPerf GFX_MAYBE_UNUSED) { RoundingFlags aRounding, gfxTextPerfMetrics* aTextPerf GFX_MAYBE_UNUSED) {
// if the cache is getting too big, flush it and start over // if the cache is getting too big, flush it and start over
uint32_t wordCacheMaxEntries = uint32_t wordCacheMaxEntries =
gfxPlatform::GetPlatform()->WordCacheMaxEntries(); gfxPlatform::GetPlatform()->WordCacheMaxEntries();
@ -2744,8 +2744,8 @@ gfxShapedWord* gfxFont::GetShapedWord(
} }
// if there's a cached entry for this word, just return it // if there's a cached entry for this word, just return it
CacheHashKey key(aText, aLength, aHash, aRunScript, aAppUnitsPerDevUnit, CacheHashKey key(aText, aLength, aHash, aRunScript, aLanguage,
aFlags, aRounding); aAppUnitsPerDevUnit, aFlags, aRounding);
CacheHashEntry* entry = mWordCache->PutEntry(key, fallible); CacheHashEntry* entry = mWordCache->PutEntry(key, fallible);
if (!entry) { if (!entry) {
@ -2770,8 +2770,8 @@ gfxShapedWord* gfxFont::GetShapedWord(
} }
#endif #endif
sw = gfxShapedWord::Create(aText, aLength, aRunScript, aAppUnitsPerDevUnit, sw = gfxShapedWord::Create(aText, aLength, aRunScript, aLanguage,
aFlags, aRounding); aAppUnitsPerDevUnit, aFlags, aRounding);
entry->mShapedWord.reset(sw); entry->mShapedWord.reset(sw);
if (!sw) { if (!sw) {
NS_WARNING("failed to create gfxShapedWord - expect missing text"); NS_WARNING("failed to create gfxShapedWord - expect missing text");
@ -2779,7 +2779,7 @@ gfxShapedWord* gfxFont::GetShapedWord(
} }
DebugOnly<bool> ok = ShapeText(aDrawTarget, aText, 0, aLength, aRunScript, DebugOnly<bool> ok = ShapeText(aDrawTarget, aText, 0, aLength, aRunScript,
aVertical, aRounding, sw); aLanguage, aVertical, aRounding, sw);
NS_WARNING_ASSERTION(ok, "failed to shape word - expect garbled text"); NS_WARNING_ASSERTION(ok, "failed to shape word - expect garbled text");
@ -2788,7 +2788,7 @@ gfxShapedWord* gfxFont::GetShapedWord(
template gfxShapedWord* gfxFont::GetShapedWord( template gfxShapedWord* gfxFont::GetShapedWord(
DrawTarget* aDrawTarget, const uint8_t* aText, uint32_t aLength, DrawTarget* aDrawTarget, const uint8_t* aText, uint32_t aLength,
uint32_t aHash, Script aRunScript, bool aVertical, uint32_t aHash, Script aRunScript, nsAtom* aLanguage, bool aVertical,
int32_t aAppUnitsPerDevUnit, gfx::ShapedTextFlags aFlags, int32_t aAppUnitsPerDevUnit, gfx::ShapedTextFlags aFlags,
RoundingFlags aRounding, gfxTextPerfMetrics* aTextPerf); RoundingFlags aRounding, gfxTextPerfMetrics* aTextPerf);
@ -2800,7 +2800,8 @@ bool gfxFont::CacheHashEntry::KeyEquals(const KeyTypePointer aKey) const {
if (sw->GetLength() != aKey->mLength || sw->GetFlags() != aKey->mFlags || if (sw->GetLength() != aKey->mLength || sw->GetFlags() != aKey->mFlags ||
sw->GetRounding() != aKey->mRounding || sw->GetRounding() != aKey->mRounding ||
sw->GetAppUnitsPerDevUnit() != aKey->mAppUnitsPerDevUnit || sw->GetAppUnitsPerDevUnit() != aKey->mAppUnitsPerDevUnit ||
sw->GetScript() != aKey->mScript) { sw->GetScript() != aKey->mScript ||
sw->GetLanguage() != aKey->mLanguage) {
return false; return false;
} }
if (sw->TextIs8Bit()) { if (sw->TextIs8Bit()) {
@ -2830,8 +2831,8 @@ bool gfxFont::CacheHashEntry::KeyEquals(const KeyTypePointer aKey) const {
bool gfxFont::ShapeText(DrawTarget* aDrawTarget, const uint8_t* aText, bool gfxFont::ShapeText(DrawTarget* aDrawTarget, const uint8_t* aText,
uint32_t aOffset, uint32_t aLength, Script aScript, uint32_t aOffset, uint32_t aLength, Script aScript,
bool aVertical, RoundingFlags aRounding, nsAtom* aLanguage, bool aVertical,
gfxShapedText* aShapedText) { RoundingFlags aRounding, gfxShapedText* aShapedText) {
nsDependentCSubstring ascii((const char*)aText, aLength); nsDependentCSubstring ascii((const char*)aText, aLength);
nsAutoString utf16; nsAutoString utf16;
AppendASCIItoUTF16(ascii, utf16); AppendASCIItoUTF16(ascii, utf16);
@ -2839,13 +2840,13 @@ bool gfxFont::ShapeText(DrawTarget* aDrawTarget, const uint8_t* aText,
return false; return false;
} }
return ShapeText(aDrawTarget, utf16.BeginReading(), aOffset, aLength, aScript, return ShapeText(aDrawTarget, utf16.BeginReading(), aOffset, aLength, aScript,
aVertical, aRounding, aShapedText); aLanguage, aVertical, aRounding, aShapedText);
} }
bool gfxFont::ShapeText(DrawTarget* aDrawTarget, const char16_t* aText, bool gfxFont::ShapeText(DrawTarget* aDrawTarget, const char16_t* aText,
uint32_t aOffset, uint32_t aLength, Script aScript, uint32_t aOffset, uint32_t aLength, Script aScript,
bool aVertical, RoundingFlags aRounding, nsAtom* aLanguage, bool aVertical,
gfxShapedText* aShapedText) { RoundingFlags aRounding, gfxShapedText* aShapedText) {
// XXX Currently, we do all vertical shaping through harfbuzz. // XXX Currently, we do all vertical shaping through harfbuzz.
// Vertical graphite support may be wanted as a future enhancement. // Vertical graphite support may be wanted as a future enhancement.
if (FontCanSupportGraphite() && !aVertical) { if (FontCanSupportGraphite() && !aVertical) {
@ -2855,7 +2856,7 @@ bool gfxFont::ShapeText(DrawTarget* aDrawTarget, const char16_t* aText,
Telemetry::ScalarAdd(Telemetry::ScalarID::BROWSER_USAGE_GRAPHITE, 1); Telemetry::ScalarAdd(Telemetry::ScalarID::BROWSER_USAGE_GRAPHITE, 1);
} }
if (mGraphiteShaper->ShapeText(aDrawTarget, aText, aOffset, aLength, if (mGraphiteShaper->ShapeText(aDrawTarget, aText, aOffset, aLength,
aScript, aVertical, aRounding, aScript, aLanguage, aVertical, aRounding,
aShapedText)) { aShapedText)) {
PostShapingFixup(aDrawTarget, aText, aOffset, aLength, aVertical, PostShapingFixup(aDrawTarget, aText, aOffset, aLength, aVertical,
aShapedText); aShapedText);
@ -2868,7 +2869,8 @@ bool gfxFont::ShapeText(DrawTarget* aDrawTarget, const char16_t* aText,
mHarfBuzzShaper = MakeUnique<gfxHarfBuzzShaper>(this); mHarfBuzzShaper = MakeUnique<gfxHarfBuzzShaper>(this);
} }
if (mHarfBuzzShaper->ShapeText(aDrawTarget, aText, aOffset, aLength, aScript, if (mHarfBuzzShaper->ShapeText(aDrawTarget, aText, aOffset, aLength, aScript,
aVertical, aRounding, aShapedText)) { aLanguage, aVertical, aRounding,
aShapedText)) {
PostShapingFixup(aDrawTarget, aText, aOffset, aLength, aVertical, PostShapingFixup(aDrawTarget, aText, aOffset, aLength, aVertical,
aShapedText); aShapedText);
if (GetFontEntry()->HasTrackingTable()) { if (GetFontEntry()->HasTrackingTable()) {
@ -2917,7 +2919,7 @@ template <typename T>
bool gfxFont::ShapeFragmentWithoutWordCache(DrawTarget* aDrawTarget, bool gfxFont::ShapeFragmentWithoutWordCache(DrawTarget* aDrawTarget,
const T* aText, uint32_t aOffset, const T* aText, uint32_t aOffset,
uint32_t aLength, Script aScript, uint32_t aLength, Script aScript,
bool aVertical, nsAtom* aLanguage, bool aVertical,
RoundingFlags aRounding, RoundingFlags aRounding,
gfxTextRun* aTextRun) { gfxTextRun* aTextRun) {
aTextRun->SetupClusterBoundaries(aOffset, aText, aLength); aTextRun->SetupClusterBoundaries(aOffset, aText, aLength);
@ -2952,8 +2954,8 @@ bool gfxFont::ShapeFragmentWithoutWordCache(DrawTarget* aDrawTarget,
} }
} }
ok = ShapeText(aDrawTarget, aText, aOffset, fragLen, aScript, aVertical, ok = ShapeText(aDrawTarget, aText, aOffset, fragLen, aScript, aLanguage,
aRounding, aTextRun); aVertical, aRounding, aTextRun);
aText += fragLen; aText += fragLen;
aOffset += fragLen; aOffset += fragLen;
@ -2975,8 +2977,8 @@ static bool IsInvalidControlChar(uint32_t aCh) {
template <typename T> template <typename T>
bool gfxFont::ShapeTextWithoutWordCache(DrawTarget* aDrawTarget, const T* aText, bool gfxFont::ShapeTextWithoutWordCache(DrawTarget* aDrawTarget, const T* aText,
uint32_t aOffset, uint32_t aLength, uint32_t aOffset, uint32_t aLength,
Script aScript, bool aVertical, Script aScript, nsAtom* aLanguage,
RoundingFlags aRounding, bool aVertical, RoundingFlags aRounding,
gfxTextRun* aTextRun) { gfxTextRun* aTextRun) {
uint32_t fragStart = 0; uint32_t fragStart = 0;
bool ok = true; bool ok = true;
@ -2992,9 +2994,9 @@ bool gfxFont::ShapeTextWithoutWordCache(DrawTarget* aDrawTarget, const T* aText,
} }
if (length > 0) { if (length > 0) {
ok = ShapeFragmentWithoutWordCache(aDrawTarget, aText + fragStart, ok = ShapeFragmentWithoutWordCache(
aOffset + fragStart, length, aScript, aDrawTarget, aText + fragStart, aOffset + fragStart, length, aScript,
aVertical, aRounding, aTextRun); aLanguage, aVertical, aRounding, aTextRun);
} }
if (i == aLength) { if (i == aLength) {
@ -3015,7 +3017,8 @@ bool gfxFont::ShapeTextWithoutWordCache(DrawTarget* aDrawTarget, const T* aText,
gfx::ShapedTextFlags::TEXT_HIDE_CONTROL_CHARACTERS)) { gfx::ShapedTextFlags::TEXT_HIDE_CONTROL_CHARACTERS)) {
if (GetFontEntry()->IsUserFont() && HasCharacter(ch)) { if (GetFontEntry()->IsUserFont() && HasCharacter(ch)) {
ShapeFragmentWithoutWordCache(aDrawTarget, aText + i, aOffset + i, 1, ShapeFragmentWithoutWordCache(aDrawTarget, aText + i, aOffset + i, 1,
aScript, aVertical, aRounding, aTextRun); aScript, aLanguage, aVertical, aRounding,
aTextRun);
} else { } else {
aTextRun->SetMissingGlyph(aOffset + i, ch, this); aTextRun->SetMissingGlyph(aOffset + i, ch, this);
} }
@ -3054,7 +3057,8 @@ bool gfxFont::SplitAndInitTextRun(
DrawTarget* aDrawTarget, gfxTextRun* aTextRun, DrawTarget* aDrawTarget, gfxTextRun* aTextRun,
const T* aString, // text for this font run const T* aString, // text for this font run
uint32_t aRunStart, // position in the textrun uint32_t aRunStart, // position in the textrun
uint32_t aRunLength, Script aRunScript, ShapedTextFlags aOrientation) { uint32_t aRunLength, Script aRunScript, nsAtom* aLanguage,
ShapedTextFlags aOrientation) {
if (aRunLength == 0) { if (aRunLength == 0) {
return true; return true;
} }
@ -3099,8 +3103,8 @@ bool gfxFont::SplitAndInitTextRun(
if (aRunLength > wordCacheCharLimit || HasSpaces(aString, aRunLength)) { if (aRunLength > wordCacheCharLimit || HasSpaces(aString, aRunLength)) {
TEXT_PERF_INCR(tp, wordCacheSpaceRules); TEXT_PERF_INCR(tp, wordCacheSpaceRules);
return ShapeTextWithoutWordCache(aDrawTarget, aString, aRunStart, return ShapeTextWithoutWordCache(aDrawTarget, aString, aRunStart,
aRunLength, aRunScript, vertical, aRunLength, aRunScript, aLanguage,
rounding, aTextRun); vertical, rounding, aTextRun);
} }
} }
@ -3149,7 +3153,7 @@ bool gfxFont::SplitAndInitTextRun(
TEXT_PERF_INCR(tp, wordCacheLong); TEXT_PERF_INCR(tp, wordCacheLong);
bool ok = ShapeFragmentWithoutWordCache( bool ok = ShapeFragmentWithoutWordCache(
aDrawTarget, aString + wordStart, aRunStart + wordStart, length, aDrawTarget, aString + wordStart, aRunStart + wordStart, length,
aRunScript, vertical, rounding, aTextRun); aRunScript, aLanguage, vertical, rounding, aTextRun);
if (!ok) { if (!ok) {
return false; return false;
} }
@ -3164,8 +3168,8 @@ bool gfxFont::SplitAndInitTextRun(
} }
} }
gfxShapedWord* sw = GetShapedWord( gfxShapedWord* sw = GetShapedWord(
aDrawTarget, aString + wordStart, length, hash, aRunScript, vertical, aDrawTarget, aString + wordStart, length, hash, aRunScript, aLanguage,
appUnitsPerDevUnit, wordFlags, rounding, tp); vertical, appUnitsPerDevUnit, wordFlags, rounding, tp);
if (sw) { if (sw) {
aTextRun->CopyGlyphDataFrom(sw, aRunStart + wordStart); aTextRun->CopyGlyphDataFrom(sw, aRunStart + wordStart);
} else { } else {
@ -3188,7 +3192,7 @@ bool gfxFont::SplitAndInitTextRun(
NS_ASSERTION(boundary16 < 256, "unexpected boundary!"); NS_ASSERTION(boundary16 < 256, "unexpected boundary!");
gfxShapedWord* sw = GetShapedWord( gfxShapedWord* sw = GetShapedWord(
aDrawTarget, &boundary, 1, gfxShapedWord::HashMix(0, boundary), aDrawTarget, &boundary, 1, gfxShapedWord::HashMix(0, boundary),
aRunScript, vertical, appUnitsPerDevUnit, aRunScript, aLanguage, vertical, appUnitsPerDevUnit,
flags | gfx::ShapedTextFlags::TEXT_IS_8BIT, rounding, tp); flags | gfx::ShapedTextFlags::TEXT_IS_8BIT, rounding, tp);
if (sw) { if (sw) {
aTextRun->CopyGlyphDataFrom(sw, aRunStart + i); aTextRun->CopyGlyphDataFrom(sw, aRunStart + i);
@ -3225,8 +3229,8 @@ bool gfxFont::SplitAndInitTextRun(
gfx::ShapedTextFlags::TEXT_HIDE_CONTROL_CHARACTERS)) { gfx::ShapedTextFlags::TEXT_HIDE_CONTROL_CHARACTERS)) {
if (GetFontEntry()->IsUserFont() && HasCharacter(ch)) { if (GetFontEntry()->IsUserFont() && HasCharacter(ch)) {
ShapeFragmentWithoutWordCache(aDrawTarget, aString + i, aRunStart + i, ShapeFragmentWithoutWordCache(aDrawTarget, aString + i, aRunStart + i,
1, aRunScript, vertical, rounding, 1, aRunScript, aLanguage, vertical,
aTextRun); rounding, aTextRun);
} else { } else {
aTextRun->SetMissingGlyph(aRunStart + i, ch, this); aTextRun->SetMissingGlyph(aRunStart + i, ch, this);
} }
@ -3244,11 +3248,11 @@ bool gfxFont::SplitAndInitTextRun(
template bool gfxFont::SplitAndInitTextRun( template bool gfxFont::SplitAndInitTextRun(
DrawTarget* aDrawTarget, gfxTextRun* aTextRun, const uint8_t* aString, DrawTarget* aDrawTarget, gfxTextRun* aTextRun, const uint8_t* aString,
uint32_t aRunStart, uint32_t aRunLength, Script aRunScript, uint32_t aRunStart, uint32_t aRunLength, Script aRunScript,
ShapedTextFlags aOrientation); nsAtom* aLanguage, ShapedTextFlags aOrientation);
template bool gfxFont::SplitAndInitTextRun( template bool gfxFont::SplitAndInitTextRun(
DrawTarget* aDrawTarget, gfxTextRun* aTextRun, const char16_t* aString, DrawTarget* aDrawTarget, gfxTextRun* aTextRun, const char16_t* aString,
uint32_t aRunStart, uint32_t aRunLength, Script aRunScript, uint32_t aRunStart, uint32_t aRunLength, Script aRunScript,
ShapedTextFlags aOrientation); nsAtom* aLanguage, ShapedTextFlags aOrientation);
template <> template <>
bool gfxFont::InitFakeSmallCapsRun(DrawTarget* aDrawTarget, bool gfxFont::InitFakeSmallCapsRun(DrawTarget* aDrawTarget,
@ -3256,8 +3260,8 @@ bool gfxFont::InitFakeSmallCapsRun(DrawTarget* aDrawTarget,
uint32_t aOffset, uint32_t aLength, uint32_t aOffset, uint32_t aLength,
FontMatchType aMatchType, FontMatchType aMatchType,
gfx::ShapedTextFlags aOrientation, gfx::ShapedTextFlags aOrientation,
Script aScript, bool aSyntheticLower, Script aScript, nsAtom* aLanguage,
bool aSyntheticUpper) { bool aSyntheticLower, bool aSyntheticUpper) {
bool ok = true; bool ok = true;
RefPtr<gfxFont> smallCapsFont = GetSmallCapsFont(); RefPtr<gfxFont> smallCapsFont = GetSmallCapsFont();
@ -3297,7 +3301,7 @@ bool gfxFont::InitFakeSmallCapsRun(DrawTarget* aDrawTarget,
} else if (ch != ToLowerCase(ch)) { } else if (ch != ToLowerCase(ch)) {
// ch is upper case // ch is upper case
chAction = (aSyntheticUpper ? kUppercaseReduce : kNoChange); chAction = (aSyntheticUpper ? kUppercaseReduce : kNoChange);
if (mStyle.explicitLanguage && mStyle.language == nsGkAtoms::el) { if (aLanguage == nsGkAtoms::el) {
// In Greek, check for characters that will be modified by // In Greek, check for characters that will be modified by
// the GreekUpperCase mapping - this catches accented // the GreekUpperCase mapping - this catches accented
// capitals where the accent is to be removed (bug 307039). // capitals where the accent is to be removed (bug 307039).
@ -3330,7 +3334,7 @@ bool gfxFont::InitFakeSmallCapsRun(DrawTarget* aDrawTarget,
aOrientation, isCJK); aOrientation, isCJK);
if (!f->SplitAndInitTextRun(aDrawTarget, aTextRun, aText + runStart, if (!f->SplitAndInitTextRun(aDrawTarget, aTextRun, aText + runStart,
aOffset + runStart, runLength, aScript, aOffset + runStart, runLength, aScript,
aOrientation)) { aLanguage, aOrientation)) {
ok = false; ok = false;
} }
break; break;
@ -3349,9 +3353,8 @@ bool gfxFont::InitFakeSmallCapsRun(DrawTarget* aDrawTarget,
bool mergeNeeded = nsCaseTransformTextRunFactory::TransformString( bool mergeNeeded = nsCaseTransformTextRunFactory::TransformString(
origString, convertedString, /* aAllUppercase = */ true, origString, convertedString, /* aAllUppercase = */ true,
/* aCaseTransformsOnly = */ false, /* aCaseTransformsOnly = */ false, aLanguage, charsToMergeArray,
mStyle.explicitLanguage ? mStyle.language.get() : nullptr, deletedCharsArray);
charsToMergeArray, deletedCharsArray);
if (mergeNeeded) { if (mergeNeeded) {
// This is the hard case: the transformation caused chars // This is the hard case: the transformation caused chars
@ -3365,9 +3368,10 @@ bool gfxFont::InitFakeSmallCapsRun(DrawTarget* aDrawTarget,
&params, convertedString.Length(), aTextRun->GetFontGroup(), &params, convertedString.Length(), aTextRun->GetFontGroup(),
gfx::ShapedTextFlags(), nsTextFrameUtils::Flags())); gfx::ShapedTextFlags(), nsTextFrameUtils::Flags()));
tempRun->AddGlyphRun(f, aMatchType, 0, true, aOrientation, isCJK); tempRun->AddGlyphRun(f, aMatchType, 0, true, aOrientation, isCJK);
if (!f->SplitAndInitTextRun( if (!f->SplitAndInitTextRun(aDrawTarget, tempRun.get(),
aDrawTarget, tempRun.get(), convertedString.BeginReading(), convertedString.BeginReading(), 0,
0, convertedString.Length(), aScript, aOrientation)) { convertedString.Length(), aScript,
aLanguage, aOrientation)) {
ok = false; ok = false;
} else { } else {
RefPtr<gfxTextRun> mergedRun(gfxTextRun::Create( RefPtr<gfxTextRun> mergedRun(gfxTextRun::Create(
@ -3383,9 +3387,10 @@ bool gfxFont::InitFakeSmallCapsRun(DrawTarget* aDrawTarget,
} else { } else {
aTextRun->AddGlyphRun(f, aMatchType, aOffset + runStart, true, aTextRun->AddGlyphRun(f, aMatchType, aOffset + runStart, true,
aOrientation, isCJK); aOrientation, isCJK);
if (!f->SplitAndInitTextRun( if (!f->SplitAndInitTextRun(aDrawTarget, aTextRun,
aDrawTarget, aTextRun, convertedString.BeginReading(), convertedString.BeginReading(),
aOffset + runStart, runLength, aScript, aOrientation)) { aOffset + runStart, runLength, aScript,
aLanguage, aOrientation)) {
ok = false; ok = false;
} }
} }
@ -3410,14 +3415,14 @@ bool gfxFont::InitFakeSmallCapsRun(DrawTarget* aDrawTarget,
uint32_t aOffset, uint32_t aLength, uint32_t aOffset, uint32_t aLength,
FontMatchType aMatchType, FontMatchType aMatchType,
gfx::ShapedTextFlags aOrientation, gfx::ShapedTextFlags aOrientation,
Script aScript, bool aSyntheticLower, Script aScript, nsAtom* aLanguage,
bool aSyntheticUpper) { bool aSyntheticLower, bool aSyntheticUpper) {
NS_ConvertASCIItoUTF16 unicodeString(reinterpret_cast<const char*>(aText), NS_ConvertASCIItoUTF16 unicodeString(reinterpret_cast<const char*>(aText),
aLength); aLength);
return InitFakeSmallCapsRun(aDrawTarget, aTextRun, return InitFakeSmallCapsRun(
static_cast<const char16_t*>(unicodeString.get()), aDrawTarget, aTextRun, static_cast<const char16_t*>(unicodeString.get()),
aOffset, aLength, aMatchType, aOrientation, aOffset, aLength, aMatchType, aOrientation, aScript, aLanguage,
aScript, aSyntheticLower, aSyntheticUpper); aSyntheticLower, aSyntheticUpper);
} }
gfxFont* gfxFont::GetSmallCapsFont() { gfxFont* gfxFont::GetSmallCapsFont() {
@ -3968,8 +3973,7 @@ void gfxFont::RemoveGlyphChangeObserver(GlyphChangeObserver* aObserver) {
#define DEFAULT_PIXEL_FONT_SIZE 16.0f #define DEFAULT_PIXEL_FONT_SIZE 16.0f
gfxFontStyle::gfxFontStyle() gfxFontStyle::gfxFontStyle()
: language(nsGkAtoms::x_western), : size(DEFAULT_PIXEL_FONT_SIZE),
size(DEFAULT_PIXEL_FONT_SIZE),
sizeAdjust(-1.0f), sizeAdjust(-1.0f),
baselineOffset(0.0f), baselineOffset(0.0f),
languageOverride(NO_FONT_LANGUAGE_OVERRIDE), languageOverride(NO_FONT_LANGUAGE_OVERRIDE),
@ -3984,18 +3988,15 @@ gfxFontStyle::gfxFontStyle()
useGrayscaleAntialiasing(false), useGrayscaleAntialiasing(false),
allowSyntheticWeight(true), allowSyntheticWeight(true),
allowSyntheticStyle(true), allowSyntheticStyle(true),
noFallbackVariantFeatures(true), noFallbackVariantFeatures(true) {}
explicitLanguage(false) {}
gfxFontStyle::gfxFontStyle(FontSlantStyle aStyle, FontWeight aWeight, gfxFontStyle::gfxFontStyle(FontSlantStyle aStyle, FontWeight aWeight,
FontStretch aStretch, gfxFloat aSize, FontStretch aStretch, gfxFloat aSize,
nsAtom* aLanguage, bool aExplicitLanguage,
float aSizeAdjust, bool aSystemFont, float aSizeAdjust, bool aSystemFont,
bool aPrinterFont, bool aAllowWeightSynthesis, bool aPrinterFont, bool aAllowWeightSynthesis,
bool aAllowStyleSynthesis, bool aAllowStyleSynthesis,
uint32_t aLanguageOverride) uint32_t aLanguageOverride)
: language(aLanguage), : size(aSize),
size(aSize),
sizeAdjust(aSizeAdjust), sizeAdjust(aSizeAdjust),
baselineOffset(0.0f), baselineOffset(0.0f),
languageOverride(aLanguageOverride), languageOverride(aLanguageOverride),
@ -4010,8 +4011,7 @@ gfxFontStyle::gfxFontStyle(FontSlantStyle aStyle, FontWeight aWeight,
useGrayscaleAntialiasing(false), useGrayscaleAntialiasing(false),
allowSyntheticWeight(aAllowWeightSynthesis), allowSyntheticWeight(aAllowWeightSynthesis),
allowSyntheticStyle(aAllowStyleSynthesis), allowSyntheticStyle(aAllowStyleSynthesis),
noFallbackVariantFeatures(true), noFallbackVariantFeatures(true) {
explicitLanguage(aExplicitLanguage) {
MOZ_ASSERT(!mozilla::IsNaN(size)); MOZ_ASSERT(!mozilla::IsNaN(size));
MOZ_ASSERT(!mozilla::IsNaN(sizeAdjust)); MOZ_ASSERT(!mozilla::IsNaN(sizeAdjust));
@ -4029,11 +4029,6 @@ gfxFontStyle::gfxFontStyle(FontSlantStyle aStyle, FontWeight aWeight,
NS_WARNING("negative font size"); NS_WARNING("negative font size");
size = 0.0; size = 0.0;
} }
if (!language) {
NS_WARNING("null language");
language = nsGkAtoms::x_western;
}
} }
PLDHashNumber gfxFontStyle::Hash() const { PLDHashNumber gfxFontStyle::Hash() const {
@ -4044,8 +4039,7 @@ PLDHashNumber gfxFontStyle::Hash() const {
sizeof(gfxFontVariation)); sizeof(gfxFontVariation));
return mozilla::AddToHash(hash, systemFont, style.ForHash(), return mozilla::AddToHash(hash, systemFont, style.ForHash(),
stretch.ForHash(), weight.ForHash(), size, stretch.ForHash(), weight.ForHash(), size,
int32_t(sizeAdjust * 1000.0f), int32_t(sizeAdjust * 1000.0f));
nsRefPtrHashKey<nsAtom>::HashKey(language));
} }
void gfxFontStyle::AdjustForSubSuperscript(int32_t aAppUnitsPerDevPixel) { void gfxFontStyle::AdjustForSubSuperscript(int32_t aAppUnitsPerDevPixel) {

View file

@ -79,16 +79,9 @@ struct gfxFontStyle {
gfxFontStyle(); gfxFontStyle();
gfxFontStyle(FontSlantStyle aStyle, FontWeight aWeight, FontStretch aStretch, gfxFontStyle(FontSlantStyle aStyle, FontWeight aWeight, FontStretch aStretch,
gfxFloat aSize, nsAtom* aLanguage, bool aExplicitLanguage, gfxFloat aSize, float aSizeAdjust, bool aSystemFont,
float aSizeAdjust, bool aSystemFont, bool aPrinterFont, bool aPrinterFont, bool aWeightSynthesis, bool aStyleSynthesis,
bool aWeightSynthesis, bool aStyleSynthesis,
uint32_t aLanguageOverride); uint32_t aLanguageOverride);
// the language (may be an internal langGroup code rather than an actual
// language code) specified in the document or element's lang property,
// or inferred from the charset
RefPtr<nsAtom> language;
// Features are composed of (1) features from style rules (2) features // Features are composed of (1) features from style rules (2) features
// from feature settings rules and (3) family-specific features. (1) and // from feature settings rules and (3) family-specific features. (1) and
// (3) are guaranteed to be mutually exclusive // (3) are guaranteed to be mutually exclusive
@ -182,10 +175,6 @@ struct gfxFontStyle {
// code, so set up a bool to indicate when shaping with fallback is needed // code, so set up a bool to indicate when shaping with fallback is needed
bool noFallbackVariantFeatures : 1; bool noFallbackVariantFeatures : 1;
// whether the |language| field comes from explicit lang tagging in the
// document, or was inferred from charset/system locale
bool explicitLanguage : 1;
// Return the final adjusted font size for the given aspect ratio. // Return the final adjusted font size for the given aspect ratio.
// Not meant to be called when sizeAdjust = -1.0. // Not meant to be called when sizeAdjust = -1.0.
gfxFloat GetAdjustedSize(gfxFloat aspect) const { gfxFloat GetAdjustedSize(gfxFloat aspect) const {
@ -219,8 +208,6 @@ struct gfxFontStyle {
(systemFont == other.systemFont) && (systemFont == other.systemFont) &&
(printerFont == other.printerFont) && (printerFont == other.printerFont) &&
(useGrayscaleAntialiasing == other.useGrayscaleAntialiasing) && (useGrayscaleAntialiasing == other.useGrayscaleAntialiasing) &&
(explicitLanguage == other.explicitLanguage) &&
(language == other.language) &&
(baselineOffset == other.baselineOffset) && (baselineOffset == other.baselineOffset) &&
(*reinterpret_cast<const uint32_t*>(&sizeAdjust) == (*reinterpret_cast<const uint32_t*>(&sizeAdjust) ==
*reinterpret_cast<const uint32_t*>(&other.sizeAdjust)) && *reinterpret_cast<const uint32_t*>(&other.sizeAdjust)) &&
@ -641,6 +628,9 @@ class gfxFontShaper {
// aShapedText to be updated; aLength is also the length of aText. // aShapedText to be updated; aLength is also the length of aText.
virtual bool ShapeText(DrawTarget* aDrawTarget, const char16_t* aText, virtual bool ShapeText(DrawTarget* aDrawTarget, const char16_t* aText,
uint32_t aOffset, uint32_t aLength, Script aScript, uint32_t aOffset, uint32_t aLength, Script aScript,
nsAtom* aLanguage, // may be null, indicating no
// lang-specific shaping to be
// applied
bool aVertical, RoundingFlags aRounding, bool aVertical, RoundingFlags aRounding,
gfxShapedText* aShapedText) = 0; gfxShapedText* aShapedText) = 0;
@ -1224,7 +1214,8 @@ class gfxShapedWord final : public gfxShapedText {
// glyph data; the caller must call gfxFont::ShapeText() with appropriate // glyph data; the caller must call gfxFont::ShapeText() with appropriate
// parameters to set up the glyphs. // parameters to set up the glyphs.
static gfxShapedWord* Create(const uint8_t* aText, uint32_t aLength, static gfxShapedWord* Create(const uint8_t* aText, uint32_t aLength,
Script aRunScript, uint16_t aAppUnitsPerDevUnit, Script aRunScript, nsAtom* aLanguage,
uint16_t aAppUnitsPerDevUnit,
mozilla::gfx::ShapedTextFlags aFlags, mozilla::gfx::ShapedTextFlags aFlags,
gfxFontShaper::RoundingFlags aRounding) { gfxFontShaper::RoundingFlags aRounding) {
NS_ASSERTION(aLength <= gfxPlatform::GetPlatform()->WordCacheCharLimit(), NS_ASSERTION(aLength <= gfxPlatform::GetPlatform()->WordCacheCharLimit(),
@ -1240,12 +1231,13 @@ class gfxShapedWord final : public gfxShapedText {
} }
// Construct in the pre-allocated storage, using placement new // Construct in the pre-allocated storage, using placement new
return new (storage) gfxShapedWord(aText, aLength, aRunScript, return new (storage) gfxShapedWord(aText, aLength, aRunScript, aLanguage,
aAppUnitsPerDevUnit, aFlags, aRounding); aAppUnitsPerDevUnit, aFlags, aRounding);
} }
static gfxShapedWord* Create(const char16_t* aText, uint32_t aLength, static gfxShapedWord* Create(const char16_t* aText, uint32_t aLength,
Script aRunScript, uint16_t aAppUnitsPerDevUnit, Script aRunScript, nsAtom* aLanguage,
uint16_t aAppUnitsPerDevUnit,
mozilla::gfx::ShapedTextFlags aFlags, mozilla::gfx::ShapedTextFlags aFlags,
gfxFontShaper::RoundingFlags aRounding) { gfxFontShaper::RoundingFlags aRounding) {
NS_ASSERTION(aLength <= gfxPlatform::GetPlatform()->WordCacheCharLimit(), NS_ASSERTION(aLength <= gfxPlatform::GetPlatform()->WordCacheCharLimit(),
@ -1258,7 +1250,8 @@ class gfxShapedWord final : public gfxShapedText {
nsAutoCString narrowText; nsAutoCString narrowText;
LossyAppendUTF16toASCII(nsDependentSubstring(aText, aLength), narrowText); LossyAppendUTF16toASCII(nsDependentSubstring(aText, aLength), narrowText);
return Create((const uint8_t*)(narrowText.BeginReading()), aLength, return Create((const uint8_t*)(narrowText.BeginReading()), aLength,
aRunScript, aAppUnitsPerDevUnit, aFlags, aRounding); aRunScript, aLanguage, aAppUnitsPerDevUnit, aFlags,
aRounding);
} }
uint32_t size = offsetof(gfxShapedWord, mCharGlyphsStorage) + uint32_t size = offsetof(gfxShapedWord, mCharGlyphsStorage) +
@ -1268,7 +1261,7 @@ class gfxShapedWord final : public gfxShapedText {
return nullptr; return nullptr;
} }
return new (storage) gfxShapedWord(aText, aLength, aRunScript, return new (storage) gfxShapedWord(aText, aLength, aRunScript, aLanguage,
aAppUnitsPerDevUnit, aFlags, aRounding); aAppUnitsPerDevUnit, aFlags, aRounding);
} }
@ -1300,6 +1293,7 @@ class gfxShapedWord final : public gfxShapedText {
} }
Script GetScript() const { return mScript; } Script GetScript() const { return mScript; }
nsAtom* GetLanguage() const { return mLanguage.get(); }
gfxFontShaper::RoundingFlags GetRounding() const { return mRounding; } gfxFontShaper::RoundingFlags GetRounding() const { return mRounding; }
@ -1317,12 +1311,13 @@ class gfxShapedWord final : public gfxShapedText {
// Construct storage for a ShapedWord, ready to receive glyph data // Construct storage for a ShapedWord, ready to receive glyph data
gfxShapedWord(const uint8_t* aText, uint32_t aLength, Script aRunScript, gfxShapedWord(const uint8_t* aText, uint32_t aLength, Script aRunScript,
uint16_t aAppUnitsPerDevUnit, nsAtom* aLanguage, uint16_t aAppUnitsPerDevUnit,
mozilla::gfx::ShapedTextFlags aFlags, mozilla::gfx::ShapedTextFlags aFlags,
gfxFontShaper::RoundingFlags aRounding) gfxFontShaper::RoundingFlags aRounding)
: gfxShapedText(aLength, : gfxShapedText(aLength,
aFlags | mozilla::gfx::ShapedTextFlags::TEXT_IS_8BIT, aFlags | mozilla::gfx::ShapedTextFlags::TEXT_IS_8BIT,
aAppUnitsPerDevUnit), aAppUnitsPerDevUnit),
mLanguage(aLanguage),
mScript(aRunScript), mScript(aRunScript),
mRounding(aRounding), mRounding(aRounding),
mAgeCounter(0) { mAgeCounter(0) {
@ -1332,10 +1327,11 @@ class gfxShapedWord final : public gfxShapedText {
} }
gfxShapedWord(const char16_t* aText, uint32_t aLength, Script aRunScript, gfxShapedWord(const char16_t* aText, uint32_t aLength, Script aRunScript,
uint16_t aAppUnitsPerDevUnit, nsAtom* aLanguage, uint16_t aAppUnitsPerDevUnit,
mozilla::gfx::ShapedTextFlags aFlags, mozilla::gfx::ShapedTextFlags aFlags,
gfxFontShaper::RoundingFlags aRounding) gfxFontShaper::RoundingFlags aRounding)
: gfxShapedText(aLength, aFlags, aAppUnitsPerDevUnit), : gfxShapedText(aLength, aFlags, aAppUnitsPerDevUnit),
mLanguage(aLanguage),
mScript(aRunScript), mScript(aRunScript),
mRounding(aRounding), mRounding(aRounding),
mAgeCounter(0) { mAgeCounter(0) {
@ -1345,6 +1341,7 @@ class gfxShapedWord final : public gfxShapedText {
SetupClusterBoundaries(0, aText, aLength); SetupClusterBoundaries(0, aText, aLength);
} }
RefPtr<nsAtom> mLanguage;
Script mScript; Script mScript;
gfxFontShaper::RoundingFlags mRounding; gfxFontShaper::RoundingFlags mRounding;
@ -1755,8 +1752,8 @@ class gfxFont {
const T* aText, uint32_t aOffset, uint32_t aLength, const T* aText, uint32_t aOffset, uint32_t aLength,
FontMatchType aMatchType, FontMatchType aMatchType,
mozilla::gfx::ShapedTextFlags aOrientation, mozilla::gfx::ShapedTextFlags aOrientation,
Script aScript, bool aSyntheticLower, Script aScript, nsAtom* aLanguage,
bool aSyntheticUpper); bool aSyntheticLower, bool aSyntheticUpper);
// call the (virtual) InitTextRun method to do glyph generation/shaping, // call the (virtual) InitTextRun method to do glyph generation/shaping,
// limiting the length of text passed by processing the run in multiple // limiting the length of text passed by processing the run in multiple
@ -1765,6 +1762,7 @@ class gfxFont {
bool SplitAndInitTextRun(DrawTarget* aDrawTarget, gfxTextRun* aTextRun, bool SplitAndInitTextRun(DrawTarget* aDrawTarget, gfxTextRun* aTextRun,
const T* aString, uint32_t aRunStart, const T* aString, uint32_t aRunStart,
uint32_t aRunLength, Script aRunScript, uint32_t aRunLength, Script aRunScript,
nsAtom* aLanguage,
mozilla::gfx::ShapedTextFlags aOrientation); mozilla::gfx::ShapedTextFlags aOrientation);
// Get a ShapedWord representing the given text (either 8- or 16-bit) // Get a ShapedWord representing the given text (either 8- or 16-bit)
@ -1772,8 +1770,8 @@ class gfxFont {
template <typename T> template <typename T>
gfxShapedWord* GetShapedWord(DrawTarget* aDrawTarget, const T* aText, gfxShapedWord* GetShapedWord(DrawTarget* aDrawTarget, const T* aText,
uint32_t aLength, uint32_t aHash, uint32_t aLength, uint32_t aHash,
Script aRunScript, bool aVertical, Script aRunScript, nsAtom* aLanguage,
int32_t aAppUnitsPerDevUnit, bool aVertical, int32_t aAppUnitsPerDevUnit,
mozilla::gfx::ShapedTextFlags aFlags, mozilla::gfx::ShapedTextFlags aFlags,
RoundingFlags aRounding, RoundingFlags aRounding,
gfxTextPerfMetrics* aTextPerf); gfxTextPerfMetrics* aTextPerf);
@ -1961,16 +1959,16 @@ class gfxFont {
// For 8-bit text, expand to 16-bit and then call the following method. // For 8-bit text, expand to 16-bit and then call the following method.
bool ShapeText(DrawTarget* aContext, const uint8_t* aText, bool ShapeText(DrawTarget* aContext, const uint8_t* aText,
uint32_t aOffset, // dest offset in gfxShapedText uint32_t aOffset, // dest offset in gfxShapedText
uint32_t aLength, Script aScript, bool aVertical, uint32_t aLength, Script aScript, nsAtom* aLanguage,
RoundingFlags aRounding, bool aVertical, RoundingFlags aRounding,
gfxShapedText* aShapedText); // where to store the result gfxShapedText* aShapedText); // where to store the result
// Call the appropriate shaper to generate glyphs for aText and store // Call the appropriate shaper to generate glyphs for aText and store
// them into aShapedText. // them into aShapedText.
virtual bool ShapeText(DrawTarget* aContext, const char16_t* aText, virtual bool ShapeText(DrawTarget* aContext, const char16_t* aText,
uint32_t aOffset, uint32_t aLength, Script aScript, uint32_t aOffset, uint32_t aLength, Script aScript,
bool aVertical, RoundingFlags aRounding, nsAtom* aLanguage, bool aVertical,
gfxShapedText* aShapedText); RoundingFlags aRounding, gfxShapedText* aShapedText);
// Helper to adjust for synthetic bold and set character-type flags // Helper to adjust for synthetic bold and set character-type flags
// in the shaped text; implementations of ShapeText should call this // in the shaped text; implementations of ShapeText should call this
@ -1990,8 +1988,9 @@ class gfxFont {
template <typename T> template <typename T>
bool ShapeTextWithoutWordCache(DrawTarget* aDrawTarget, const T* aText, bool ShapeTextWithoutWordCache(DrawTarget* aDrawTarget, const T* aText,
uint32_t aOffset, uint32_t aLength, uint32_t aOffset, uint32_t aLength,
Script aScript, bool aVertical, Script aScript, nsAtom* aLanguage,
RoundingFlags aRounding, gfxTextRun* aTextRun); bool aVertical, RoundingFlags aRounding,
gfxTextRun* aTextRun);
// Shape a fragment of text (a run that is known to contain only // Shape a fragment of text (a run that is known to contain only
// "valid" characters, no newlines/tabs/other control chars). // "valid" characters, no newlines/tabs/other control chars).
@ -2001,8 +2000,8 @@ class gfxFont {
template <typename T> template <typename T>
bool ShapeFragmentWithoutWordCache(DrawTarget* aDrawTarget, const T* aText, bool ShapeFragmentWithoutWordCache(DrawTarget* aDrawTarget, const T* aText,
uint32_t aOffset, uint32_t aLength, uint32_t aOffset, uint32_t aLength,
Script aScript, bool aVertical, Script aScript, nsAtom* aLanguage,
RoundingFlags aRounding, bool aVertical, RoundingFlags aRounding,
gfxTextRun* aTextRun); gfxTextRun* aTextRun);
void CheckForFeaturesInvolvingSpace(); void CheckForFeaturesInvolvingSpace();
@ -2025,21 +2024,24 @@ class gfxFont {
uint32_t mLength; uint32_t mLength;
mozilla::gfx::ShapedTextFlags mFlags; mozilla::gfx::ShapedTextFlags mFlags;
Script mScript; Script mScript;
RefPtr<nsAtom> mLanguage;
int32_t mAppUnitsPerDevUnit; int32_t mAppUnitsPerDevUnit;
PLDHashNumber mHashKey; PLDHashNumber mHashKey;
bool mTextIs8Bit; bool mTextIs8Bit;
RoundingFlags mRounding; RoundingFlags mRounding;
CacheHashKey(const uint8_t* aText, uint32_t aLength, uint32_t aStringHash, CacheHashKey(const uint8_t* aText, uint32_t aLength, uint32_t aStringHash,
Script aScriptCode, int32_t aAppUnitsPerDevUnit, Script aScriptCode, nsAtom* aLanguage,
int32_t aAppUnitsPerDevUnit,
mozilla::gfx::ShapedTextFlags aFlags, RoundingFlags aRounding) mozilla::gfx::ShapedTextFlags aFlags, RoundingFlags aRounding)
: mLength(aLength), : mLength(aLength),
mFlags(aFlags), mFlags(aFlags),
mScript(aScriptCode), mScript(aScriptCode),
mLanguage(aLanguage),
mAppUnitsPerDevUnit(aAppUnitsPerDevUnit), mAppUnitsPerDevUnit(aAppUnitsPerDevUnit),
mHashKey(aStringHash + static_cast<int32_t>(aScriptCode) + mHashKey(aStringHash + static_cast<int32_t>(aScriptCode) +
aAppUnitsPerDevUnit * 0x100 + uint16_t(aFlags) * 0x10000 + aAppUnitsPerDevUnit * 0x100 + uint16_t(aFlags) * 0x10000 +
int(aRounding)), int(aRounding) + (aLanguage ? aLanguage->hash() : 0)),
mTextIs8Bit(true), mTextIs8Bit(true),
mRounding(aRounding) { mRounding(aRounding) {
NS_ASSERTION(aFlags & mozilla::gfx::ShapedTextFlags::TEXT_IS_8BIT, NS_ASSERTION(aFlags & mozilla::gfx::ShapedTextFlags::TEXT_IS_8BIT,
@ -2048,11 +2050,13 @@ class gfxFont {
} }
CacheHashKey(const char16_t* aText, uint32_t aLength, uint32_t aStringHash, CacheHashKey(const char16_t* aText, uint32_t aLength, uint32_t aStringHash,
Script aScriptCode, int32_t aAppUnitsPerDevUnit, Script aScriptCode, nsAtom* aLanguage,
int32_t aAppUnitsPerDevUnit,
mozilla::gfx::ShapedTextFlags aFlags, RoundingFlags aRounding) mozilla::gfx::ShapedTextFlags aFlags, RoundingFlags aRounding)
: mLength(aLength), : mLength(aLength),
mFlags(aFlags), mFlags(aFlags),
mScript(aScriptCode), mScript(aScriptCode),
mLanguage(aLanguage),
mAppUnitsPerDevUnit(aAppUnitsPerDevUnit), mAppUnitsPerDevUnit(aAppUnitsPerDevUnit),
mHashKey(aStringHash + static_cast<int32_t>(aScriptCode) + mHashKey(aStringHash + static_cast<int32_t>(aScriptCode) +
aAppUnitsPerDevUnit * 0x100 + uint16_t(aFlags) * 0x10000 + aAppUnitsPerDevUnit * 0x100 + uint16_t(aFlags) * 0x10000 +

View file

@ -59,7 +59,8 @@ UniquePtr<gfxFont> gfxGDIFont::CopyWithAntialiasOption(
bool gfxGDIFont::ShapeText(DrawTarget* aDrawTarget, const char16_t* aText, bool gfxGDIFont::ShapeText(DrawTarget* aDrawTarget, const char16_t* aText,
uint32_t aOffset, uint32_t aLength, Script aScript, uint32_t aOffset, uint32_t aLength, Script aScript,
bool aVertical, RoundingFlags aRounding, nsAtom* aLanguage, bool aVertical,
RoundingFlags aRounding,
gfxShapedText* aShapedText) { gfxShapedText* aShapedText) {
if (!mIsValid) { if (!mIsValid) {
NS_WARNING("invalid font! expect incorrect text rendering"); NS_WARNING("invalid font! expect incorrect text rendering");
@ -67,7 +68,7 @@ bool gfxGDIFont::ShapeText(DrawTarget* aDrawTarget, const char16_t* aText,
} }
return gfxFont::ShapeText(aDrawTarget, aText, aOffset, aLength, aScript, return gfxFont::ShapeText(aDrawTarget, aText, aOffset, aLength, aScript,
aVertical, aRounding, aShapedText); aLanguage, aVertical, aRounding, aShapedText);
} }
const gfxFont::Metrics& gfxGDIFont::GetHorizontalMetrics() { return *mMetrics; } const gfxFont::Metrics& gfxGDIFont::GetHorizontalMetrics() { return *mMetrics; }

View file

@ -61,10 +61,9 @@ class gfxGDIFont : public gfxFont {
protected: protected:
const Metrics& GetHorizontalMetrics() override; const Metrics& GetHorizontalMetrics() override;
/* override to ensure the cairo font is set up properly */
bool ShapeText(DrawTarget* aDrawTarget, const char16_t* aText, bool ShapeText(DrawTarget* aDrawTarget, const char16_t* aText,
uint32_t aOffset, uint32_t aLength, Script aScript, uint32_t aOffset, uint32_t aLength, Script aScript,
bool aVertical, RoundingFlags aRounding, nsAtom* aLanguage, bool aVertical, RoundingFlags aRounding,
gfxShapedText* aShapedText) override; gfxShapedText* aShapedText) override;
void Initialize(); // creates metrics and Cairo fonts void Initialize(); // creates metrics and Cairo fonts

View file

@ -826,7 +826,7 @@ bool gfxGDIFontList::FindAndAddFamilies(StyleGenericFontFamily aGeneric,
const nsACString& aFamily, const nsACString& aFamily,
nsTArray<FamilyAndGeneric>* aOutput, nsTArray<FamilyAndGeneric>* aOutput,
FindFamiliesFlags aFlags, FindFamiliesFlags aFlags,
gfxFontStyle* aStyle, gfxFontStyle* aStyle, nsAtom* aLanguage,
gfxFloat aDevToCssSize) { gfxFloat aDevToCssSize) {
NS_ConvertUTF8toUTF16 key16(aFamily); NS_ConvertUTF8toUTF16 key16(aFamily);
BuildKeyNameFromFontName(key16); BuildKeyNameFromFontName(key16);
@ -842,12 +842,12 @@ bool gfxGDIFontList::FindAndAddFamilies(StyleGenericFontFamily aGeneric,
return false; return false;
} }
return gfxPlatformFontList::FindAndAddFamilies(aGeneric, aFamily, aOutput, return gfxPlatformFontList::FindAndAddFamilies(
aFlags, aStyle, aDevToCssSize); aGeneric, aFamily, aOutput, aFlags, aStyle, aLanguage, aDevToCssSize);
} }
FontFamily gfxGDIFontList::GetDefaultFontForPlatform( FontFamily gfxGDIFontList::GetDefaultFontForPlatform(const gfxFontStyle* aStyle,
const gfxFontStyle* aStyle) { nsAtom* aLanguage) {
FontFamily ff; FontFamily ff;
// this really shouldn't fail to find a font.... // this really shouldn't fail to find a font....

View file

@ -308,6 +308,7 @@ class gfxGDIFontList final : public gfxPlatformFontList {
nsTArray<FamilyAndGeneric>* aOutput, nsTArray<FamilyAndGeneric>* aOutput,
FindFamiliesFlags aFlags, FindFamiliesFlags aFlags,
gfxFontStyle* aStyle = nullptr, gfxFontStyle* aStyle = nullptr,
nsAtom* aLanguage = nullptr,
gfxFloat aDevToCssSize = 1.0) override; gfxFloat aDevToCssSize = 1.0) override;
virtual gfxFontEntry* LookupLocalFont(const nsACString& aFontName, virtual gfxFontEntry* LookupLocalFont(const nsACString& aFontName,
@ -328,7 +329,8 @@ class gfxGDIFontList final : public gfxPlatformFontList {
FontListSizes* aSizes) const; FontListSizes* aSizes) const;
protected: protected:
FontFamily GetDefaultFontForPlatform(const gfxFontStyle* aStyle) override; FontFamily GetDefaultFontForPlatform(const gfxFontStyle* aStyle,
nsAtom* aLanguage = nullptr) override;
private: private:
friend class gfxWindowsPlatform; friend class gfxWindowsPlatform;

View file

@ -131,7 +131,8 @@ static inline size_t CountUnicodes(const char16_t* aText, uint32_t aLength) {
bool gfxGraphiteShaper::ShapeText(DrawTarget* aDrawTarget, bool gfxGraphiteShaper::ShapeText(DrawTarget* aDrawTarget,
const char16_t* aText, uint32_t aOffset, const char16_t* aText, uint32_t aOffset,
uint32_t aLength, Script aScript, uint32_t aLength, Script aScript,
bool aVertical, RoundingFlags aRounding, nsAtom* aLanguage, bool aVertical,
RoundingFlags aRounding,
gfxShapedText* aShapedText) { gfxShapedText* aShapedText) {
const gfxFontStyle* style = mFont->GetStyle(); const gfxFontStyle* style = mFont->GetStyle();
auto t_mGrFace = rlbox::from_opaque(mGrFace); auto t_mGrFace = rlbox::from_opaque(mGrFace);
@ -191,9 +192,9 @@ bool gfxGraphiteShaper::ShapeText(DrawTarget* aDrawTarget,
grLang = MakeGraphiteLangTag(style->languageOverride); grLang = MakeGraphiteLangTag(style->languageOverride);
} else if (entry->mLanguageOverride) { } else if (entry->mLanguageOverride) {
grLang = MakeGraphiteLangTag(entry->mLanguageOverride); grLang = MakeGraphiteLangTag(entry->mLanguageOverride);
} else if (style->explicitLanguage) { } else if (aLanguage) {
nsAutoCString langString; nsAutoCString langString;
style->language->ToUTF8String(langString); aLanguage->ToUTF8String(langString);
grLang = GetGraphiteTagForLang(langString); grLang = GetGraphiteTagForLang(langString);
} }
tainted_gr<gr_feature_val*> grFeatures = tainted_gr<gr_feature_val*> grFeatures =

View file

@ -23,7 +23,7 @@ class gfxGraphiteShaper : public gfxFontShaper {
bool ShapeText(DrawTarget* aDrawTarget, const char16_t* aText, bool ShapeText(DrawTarget* aDrawTarget, const char16_t* aText,
uint32_t aOffset, uint32_t aLength, Script aScript, uint32_t aOffset, uint32_t aLength, Script aScript,
bool aVertical, RoundingFlags aRounding, nsAtom* aLanguage, bool aVertical, RoundingFlags aRounding,
gfxShapedText* aShapedText) override; gfxShapedText* aShapedText) override;
static void Shutdown(); static void Shutdown();

View file

@ -1355,7 +1355,8 @@ void gfxHarfBuzzShaper::InitializeVertical() {
bool gfxHarfBuzzShaper::ShapeText(DrawTarget* aDrawTarget, bool gfxHarfBuzzShaper::ShapeText(DrawTarget* aDrawTarget,
const char16_t* aText, uint32_t aOffset, const char16_t* aText, uint32_t aOffset,
uint32_t aLength, Script aScript, uint32_t aLength, Script aScript,
bool aVertical, RoundingFlags aRounding, nsAtom* aLanguage, bool aVertical,
RoundingFlags aRounding,
gfxShapedText* aShapedText) { gfxShapedText* aShapedText) {
mUseVerticalPresentationForms = false; mUseVerticalPresentationForms = false;
@ -1415,9 +1416,9 @@ bool gfxHarfBuzzShaper::ShapeText(DrawTarget* aDrawTarget,
language = hb_ot_tag_to_language(style->languageOverride); language = hb_ot_tag_to_language(style->languageOverride);
} else if (entry->mLanguageOverride) { } else if (entry->mLanguageOverride) {
language = hb_ot_tag_to_language(entry->mLanguageOverride); language = hb_ot_tag_to_language(entry->mLanguageOverride);
} else if (style->explicitLanguage) { } else if (aLanguage) {
nsCString langString; nsCString langString;
style->language->ToUTF8String(langString); aLanguage->ToUTF8String(langString);
language = hb_language_from_string(langString.get(), langString.Length()); language = hb_language_from_string(langString.get(), langString.Length());
} else { } else {
language = hb_ot_tag_to_language(HB_OT_TAG_DEFAULT_LANGUAGE); language = hb_ot_tag_to_language(HB_OT_TAG_DEFAULT_LANGUAGE);

View file

@ -29,7 +29,7 @@ class gfxHarfBuzzShaper : public gfxFontShaper {
bool ShapeText(DrawTarget* aDrawTarget, const char16_t* aText, bool ShapeText(DrawTarget* aDrawTarget, const char16_t* aText,
uint32_t aOffset, uint32_t aLength, Script aScript, uint32_t aOffset, uint32_t aLength, Script aScript,
bool aVertical, RoundingFlags aRounding, nsAtom* aLanguage, bool aVertical, RoundingFlags aRounding,
gfxShapedText* aShapedText) override; gfxShapedText* aShapedText) override;
// get a given font table in harfbuzz blob form // get a given font table in harfbuzz blob form

View file

@ -142,7 +142,8 @@ gfxMacFont::~gfxMacFont() {
bool gfxMacFont::ShapeText(DrawTarget* aDrawTarget, const char16_t* aText, bool gfxMacFont::ShapeText(DrawTarget* aDrawTarget, const char16_t* aText,
uint32_t aOffset, uint32_t aLength, Script aScript, uint32_t aOffset, uint32_t aLength, Script aScript,
bool aVertical, RoundingFlags aRounding, nsAtom* aLanguage, bool aVertical,
RoundingFlags aRounding,
gfxShapedText* aShapedText) { gfxShapedText* aShapedText) {
if (!mIsValid) { if (!mIsValid) {
NS_WARNING("invalid font! expect incorrect text rendering"); NS_WARNING("invalid font! expect incorrect text rendering");
@ -158,7 +159,7 @@ bool gfxMacFont::ShapeText(DrawTarget* aDrawTarget, const char16_t* aText,
mCoreTextShaper = MakeUnique<gfxCoreTextShaper>(this); mCoreTextShaper = MakeUnique<gfxCoreTextShaper>(this);
} }
if (mCoreTextShaper->ShapeText(aDrawTarget, aText, aOffset, aLength, if (mCoreTextShaper->ShapeText(aDrawTarget, aText, aOffset, aLength,
aScript, aVertical, aRounding, aScript, aLanguage, aVertical, aRounding,
aShapedText)) { aShapedText)) {
PostShapingFixup(aDrawTarget, aText, aOffset, aLength, aVertical, PostShapingFixup(aDrawTarget, aText, aOffset, aLength, aVertical,
aShapedText); aShapedText);
@ -181,7 +182,7 @@ bool gfxMacFont::ShapeText(DrawTarget* aDrawTarget, const char16_t* aText,
} }
return gfxFont::ShapeText(aDrawTarget, aText, aOffset, aLength, aScript, return gfxFont::ShapeText(aDrawTarget, aText, aOffset, aLength, aScript,
aVertical, aRounding, aShapedText); aLanguage, aVertical, aRounding, aShapedText);
} }
gfxFont::RunMetrics gfxMacFont::Measure(const gfxTextRun* aTextRun, gfxFont::RunMetrics gfxMacFont::Measure(const gfxTextRun* aTextRun,

View file

@ -63,7 +63,7 @@ class gfxMacFont : public gfxFont {
// override to prefer CoreText shaping with fonts that depend on AAT // override to prefer CoreText shaping with fonts that depend on AAT
bool ShapeText(DrawTarget* aDrawTarget, const char16_t* aText, uint32_t aOffset, uint32_t aLength, bool ShapeText(DrawTarget* aDrawTarget, const char16_t* aText, uint32_t aOffset, uint32_t aLength,
Script aScript, bool aVertical, RoundingFlags aRounding, Script aScript, nsAtom* aLanguage, bool aVertical, RoundingFlags aRounding,
gfxShapedText* aShapedText) override; gfxShapedText* aShapedText) override;
void InitMetrics(); void InitMetrics();

View file

@ -146,6 +146,7 @@ class gfxMacPlatformFontList final : public gfxPlatformFontList {
nsTArray<FamilyAndGeneric>* aOutput, nsTArray<FamilyAndGeneric>* aOutput,
FindFamiliesFlags aFlags, FindFamiliesFlags aFlags,
gfxFontStyle* aStyle = nullptr, gfxFontStyle* aStyle = nullptr,
nsAtom* aLanguage = nullptr,
gfxFloat aDevToCssSize = 1.0) override; gfxFloat aDevToCssSize = 1.0) override;
// lookup the system font for a particular system font type and set // lookup the system font for a particular system font type and set
@ -163,7 +164,8 @@ class gfxMacPlatformFontList final : public gfxPlatformFontList {
void ReadSystemFontList(nsTArray<FontFamilyListEntry>* aList); void ReadSystemFontList(nsTArray<FontFamilyListEntry>* aList);
protected: protected:
FontFamily GetDefaultFontForPlatform(const gfxFontStyle* aStyle) override; FontFamily GetDefaultFontForPlatform(const gfxFontStyle* aStyle,
nsAtom* aLanguage = nullptr) override;
private: private:
friend class gfxPlatformMac; friend class gfxPlatformMac;

View file

@ -1374,7 +1374,8 @@ gfxFontEntry* gfxMacPlatformFontList::PlatformGlobalFontFallback(const uint32_t
return fontEntry; return fontEntry;
} }
FontFamily gfxMacPlatformFontList::GetDefaultFontForPlatform(const gfxFontStyle* aStyle) { FontFamily gfxMacPlatformFontList::GetDefaultFontForPlatform(const gfxFontStyle* aStyle,
nsAtom* aLanguage) {
nsAutoreleasePool localPool; nsAutoreleasePool localPool;
NSString* defaultFamily = [[NSFont userFontOfSize:aStyle->size] familyName]; NSString* defaultFamily = [[NSFont userFontOfSize:aStyle->size] familyName];
@ -1459,7 +1460,7 @@ bool gfxMacPlatformFontList::FindAndAddFamilies(mozilla::StyleGenericFontFamily
const nsACString& aFamily, const nsACString& aFamily,
nsTArray<FamilyAndGeneric>* aOutput, nsTArray<FamilyAndGeneric>* aOutput,
FindFamiliesFlags aFlags, gfxFontStyle* aStyle, FindFamiliesFlags aFlags, gfxFontStyle* aStyle,
gfxFloat aDevToCssSize) { nsAtom* aLanguage, gfxFloat aDevToCssSize) {
if (aFamily.EqualsLiteral(kSystemFont_system)) { if (aFamily.EqualsLiteral(kSystemFont_system)) {
// Search for special system font name, -apple-system. This is not done via // Search for special system font name, -apple-system. This is not done via
// the shared fontlist on Catalina or later, because the hidden system font // the shared fontlist on Catalina or later, because the hidden system font
@ -1468,11 +1469,12 @@ bool gfxMacPlatformFontList::FindAndAddFamilies(mozilla::StyleGenericFontFamily
const nsCString& systemFontFamilyName = const nsCString& systemFontFamilyName =
mUseSizeSensitiveSystemFont && aStyle && mUseSizeSensitiveSystemFont && aStyle &&
(aStyle->size * aDevToCssSize) >= kTextDisplayCrossover (aStyle->size * aDevToCssSize) >= kTextDisplayCrossover
? mSystemDisplayFontFamilyName : mSystemTextFontFamilyName; ? mSystemDisplayFontFamilyName
: mSystemTextFontFamilyName;
if (SharedFontList() && !nsCocoaFeatures::OnCatalinaOrLater()) { if (SharedFontList() && !nsCocoaFeatures::OnCatalinaOrLater()) {
FindFamiliesFlags flags = aFlags | FindFamiliesFlags::eSearchHiddenFamilies; FindFamiliesFlags flags = aFlags | FindFamiliesFlags::eSearchHiddenFamilies;
return gfxPlatformFontList::FindAndAddFamilies(aGeneric, systemFontFamilyName, aOutput, return gfxPlatformFontList::FindAndAddFamilies(aGeneric, systemFontFamilyName, aOutput, flags,
flags, aStyle, aDevToCssSize); aStyle, aLanguage, aDevToCssSize);
} else { } else {
if (auto* fam = FindSystemFontFamily(systemFontFamilyName)) { if (auto* fam = FindSystemFontFamily(systemFontFamilyName)) {
aOutput->AppendElement(fam); aOutput->AppendElement(fam);
@ -1483,7 +1485,7 @@ bool gfxMacPlatformFontList::FindAndAddFamilies(mozilla::StyleGenericFontFamily
} }
return gfxPlatformFontList::FindAndAddFamilies(aGeneric, aFamily, aOutput, aFlags, aStyle, return gfxPlatformFontList::FindAndAddFamilies(aGeneric, aFamily, aOutput, aFlags, aStyle,
aDevToCssSize); aLanguage, aDevToCssSize);
} }
void gfxMacPlatformFontList::LookupSystemFont(LookAndFeel::FontID aSystemFontID, void gfxMacPlatformFontList::LookupSystemFont(LookAndFeel::FontID aSystemFontID,

View file

@ -1909,10 +1909,12 @@ bool gfxPlatform::IsFontFormatSupported(uint32_t aFormatFlags) {
gfxFontGroup* gfxPlatform::CreateFontGroup( gfxFontGroup* gfxPlatform::CreateFontGroup(
const FontFamilyList& aFontFamilyList, const gfxFontStyle* aStyle, const FontFamilyList& aFontFamilyList, const gfxFontStyle* aStyle,
gfxTextPerfMetrics* aTextPerf, FontMatchingStats* aFontMatchingStats, nsAtom* aLanguage, bool aExplicitLanguage, gfxTextPerfMetrics* aTextPerf,
gfxUserFontSet* aUserFontSet, gfxFloat aDevToCssSize) const { FontMatchingStats* aFontMatchingStats, gfxUserFontSet* aUserFontSet,
return new gfxFontGroup(aFontFamilyList, aStyle, aTextPerf, gfxFloat aDevToCssSize) const {
aFontMatchingStats, aUserFontSet, aDevToCssSize); return new gfxFontGroup(aFontFamilyList, aStyle, aLanguage, aExplicitLanguage,
aTextPerf, aFontMatchingStats, aUserFontSet,
aDevToCssSize);
} }
gfxFontEntry* gfxPlatform::LookupLocalFont(const nsACString& aFontName, gfxFontEntry* gfxPlatform::LookupLocalFont(const nsACString& aFontName,

View file

@ -393,7 +393,8 @@ class gfxPlatform : public mozilla::layers::MemoryPressureListener {
* Create a gfxFontGroup based on the given family list and style. * Create a gfxFontGroup based on the given family list and style.
*/ */
gfxFontGroup* CreateFontGroup(const mozilla::FontFamilyList& aFontFamilyList, gfxFontGroup* CreateFontGroup(const mozilla::FontFamilyList& aFontFamilyList,
const gfxFontStyle* aStyle, const gfxFontStyle* aStyle, nsAtom* aLanguage,
bool aExplicitLanguage,
gfxTextPerfMetrics* aTextPerf, gfxTextPerfMetrics* aTextPerf,
FontMatchingStats* aFontMatchingStats, FontMatchingStats* aFontMatchingStats,
gfxUserFontSet* aUserFontSet, gfxUserFontSet* aUserFontSet,

View file

@ -1138,7 +1138,7 @@ gfxFontFamily* gfxPlatformFontList::CheckFamily(gfxFontFamily* aFamily) {
bool gfxPlatformFontList::FindAndAddFamilies( bool gfxPlatformFontList::FindAndAddFamilies(
StyleGenericFontFamily aGeneric, const nsACString& aFamily, StyleGenericFontFamily aGeneric, const nsACString& aFamily,
nsTArray<FamilyAndGeneric>* aOutput, FindFamiliesFlags aFlags, nsTArray<FamilyAndGeneric>* aOutput, FindFamiliesFlags aFlags,
gfxFontStyle* aStyle, gfxFloat aDevToCssSize) { gfxFontStyle* aStyle, nsAtom* aLanguage, gfxFloat aDevToCssSize) {
nsAutoCString key; nsAutoCString key;
GenerateFontListKey(aFamily, key); GenerateFontListKey(aFamily, key);
@ -1283,13 +1283,13 @@ bool gfxPlatformFontList::FindAndAddFamilies(
fontlist::Family* gfxPlatformFontList::FindSharedFamily( fontlist::Family* gfxPlatformFontList::FindSharedFamily(
const nsACString& aFamily, FindFamiliesFlags aFlags, gfxFontStyle* aStyle, const nsACString& aFamily, FindFamiliesFlags aFlags, gfxFontStyle* aStyle,
gfxFloat aDevToCss) { nsAtom* aLanguage, gfxFloat aDevToCss) {
if (!SharedFontList()) { if (!SharedFontList()) {
return nullptr; return nullptr;
} }
AutoTArray<FamilyAndGeneric, 1> families; AutoTArray<FamilyAndGeneric, 1> families;
if (!FindAndAddFamilies(StyleGenericFontFamily::None, aFamily, &families, if (!FindAndAddFamilies(StyleGenericFontFamily::None, aFamily, &families,
aFlags, aStyle, aDevToCss) || aFlags, aStyle, aLanguage, aDevToCss) ||
!families[0].mFamily.mIsShared) { !families[0].mFamily.mIsShared) {
return nullptr; return nullptr;
} }
@ -1595,12 +1595,9 @@ void gfxPlatformFontList::GetFontFamiliesFromGenericFamilies(
PrefFontList* aGenericFamilies) { PrefFontList* aGenericFamilies) {
// lookup and add platform fonts uniquely // lookup and add platform fonts uniquely
for (const nsCString& genericFamily : aGenericNameFamilies) { for (const nsCString& genericFamily : aGenericNameFamilies) {
gfxFontStyle style;
style.language = aLangGroup;
style.systemFont = false;
AutoTArray<FamilyAndGeneric, 10> families; AutoTArray<FamilyAndGeneric, 10> families;
FindAndAddFamilies(aGenericType, genericFamily, &families, FindAndAddFamilies(aGenericType, genericFamily, &families,
FindFamiliesFlags(0), &style); FindFamiliesFlags(0), nullptr, aLangGroup);
for (const FamilyAndGeneric& f : families) { for (const FamilyAndGeneric& f : families) {
if (!aGenericFamilies->Contains(f.mFamily)) { if (!aGenericFamilies->Contains(f.mFamily)) {
aGenericFamilies->AppendElement(f.mFamily); aGenericFamilies->AppendElement(f.mFamily);

View file

@ -253,6 +253,7 @@ class gfxPlatformFontList : public gfxFontInfoLoader {
nsTArray<FamilyAndGeneric>* aOutput, nsTArray<FamilyAndGeneric>* aOutput,
FindFamiliesFlags aFlags, FindFamiliesFlags aFlags,
gfxFontStyle* aStyle = nullptr, gfxFontStyle* aStyle = nullptr,
nsAtom* aLanguage = nullptr,
gfxFloat aDevToCssSize = 1.0); gfxFloat aDevToCssSize = 1.0);
gfxFontEntry* FindFontForFamily(const nsACString& aFamily, gfxFontEntry* FindFontForFamily(const nsACString& aFamily,
@ -585,18 +586,21 @@ class gfxPlatformFontList : public gfxFontInfoLoader {
mozilla::fontlist::Family* FindSharedFamily( mozilla::fontlist::Family* FindSharedFamily(
const nsACString& aFamily, const nsACString& aFamily,
FindFamiliesFlags aFlags = FindFamiliesFlags(0), FindFamiliesFlags aFlags = FindFamiliesFlags(0),
gfxFontStyle* aStyle = nullptr, gfxFloat aDevToCssSize = 1.0); gfxFontStyle* aStyle = nullptr, nsAtom* aLanguage = nullptr,
gfxFloat aDevToCssSize = 1.0);
gfxFontFamily* FindUnsharedFamily( gfxFontFamily* FindUnsharedFamily(
const nsACString& aFamily, const nsACString& aFamily,
FindFamiliesFlags aFlags = FindFamiliesFlags(0), FindFamiliesFlags aFlags = FindFamiliesFlags(0),
gfxFontStyle* aStyle = nullptr, gfxFloat aDevToCssSize = 1.0) { gfxFontStyle* aStyle = nullptr, nsAtom* aLanguage = nullptr,
gfxFloat aDevToCssSize = 1.0) {
if (SharedFontList()) { if (SharedFontList()) {
return nullptr; return nullptr;
} }
AutoTArray<FamilyAndGeneric, 1> families; AutoTArray<FamilyAndGeneric, 1> families;
if (FindAndAddFamilies(mozilla::StyleGenericFontFamily::None, aFamily, if (FindAndAddFamilies(mozilla::StyleGenericFontFamily::None, aFamily,
&families, aFlags, aStyle, aDevToCssSize)) { &families, aFlags, aStyle, aLanguage,
aDevToCssSize)) {
return families[0].mFamily.mUnshared; return families[0].mFamily.mUnshared;
} }
return nullptr; return nullptr;
@ -605,13 +609,14 @@ class gfxPlatformFontList : public gfxFontInfoLoader {
FontFamily FindFamily(const nsACString& aFamily, FontFamily FindFamily(const nsACString& aFamily,
FindFamiliesFlags aFlags = FindFamiliesFlags(0), FindFamiliesFlags aFlags = FindFamiliesFlags(0),
gfxFontStyle* aStyle = nullptr, gfxFontStyle* aStyle = nullptr,
nsAtom* aLanguage = nullptr,
gfxFloat aDevToCssSize = 1.0) { gfxFloat aDevToCssSize = 1.0) {
if (SharedFontList()) { if (SharedFontList()) {
return FontFamily( return FontFamily(
FindSharedFamily(aFamily, aFlags, aStyle, aDevToCssSize)); FindSharedFamily(aFamily, aFlags, aStyle, aLanguage, aDevToCssSize));
} }
return FontFamily( return FontFamily(
FindUnsharedFamily(aFamily, aFlags, aStyle, aDevToCssSize)); FindUnsharedFamily(aFamily, aFlags, aStyle, aLanguage, aDevToCssSize));
} }
// Lookup family name in global family list without substitutions or // Lookup family name in global family list without substitutions or
@ -766,7 +771,8 @@ class gfxPlatformFontList : public gfxFontInfoLoader {
const FontEntryTable& aTable, mozilla::MallocSizeOf aMallocSizeOf); const FontEntryTable& aTable, mozilla::MallocSizeOf aMallocSizeOf);
// Platform-specific helper for GetDefaultFont(...). // Platform-specific helper for GetDefaultFont(...).
virtual FontFamily GetDefaultFontForPlatform(const gfxFontStyle* aStyle) = 0; virtual FontFamily GetDefaultFontForPlatform(const gfxFontStyle* aStyle,
nsAtom* aLanguage = nullptr) = 0;
// Protects mFontFamilies. // Protects mFontFamilies.
mozilla::Mutex mFontFamiliesMutex; mozilla::Mutex mFontFamiliesMutex;

View file

@ -1546,7 +1546,8 @@ void gfxTextRun::SetSpaceGlyph(gfxFont* aFont, DrawTarget* aDrawTarget,
aFont->GetRoundOffsetsToPixels(aDrawTarget); aFont->GetRoundOffsetsToPixels(aDrawTarget);
gfxShapedWord* sw = aFont->GetShapedWord( gfxShapedWord* sw = aFont->GetShapedWord(
aDrawTarget, &space, 1, gfxShapedWord::HashMix(0, ' '), Script::LATIN, aDrawTarget, &space, 1, gfxShapedWord::HashMix(0, ' '), Script::LATIN,
vertical, mAppUnitsPerDevUnit, flags, roundingFlags, nullptr); /* aLanguage = */ nullptr, vertical, mAppUnitsPerDevUnit, flags,
roundingFlags, nullptr);
if (sw) { if (sw) {
const GlyphRun* prevRun = TrailingGlyphRun(); const GlyphRun* prevRun = TrailingGlyphRun();
bool isCJK = prevRun && prevRun->mFont == aFont && bool isCJK = prevRun && prevRun->mFont == aFont &&
@ -1733,8 +1734,10 @@ void gfxTextRun::Dump(FILE* out) {
# undef APPEND_FLAGS # undef APPEND_FLAGS
# undef APPEND_FLAG # undef APPEND_FLAG
fprintf(out, "gfxTextRun@%p (length %u) [%s] [%s]\n", this, mLength, nsAutoCString lang;
flagsString.get(), flags2String.get()); mFontGroup->Language()->ToUTF8String(lang);
fprintf(out, "gfxTextRun@%p (length %u) [%s] [%s] [%s]\n", this, mLength,
flagsString.get(), flags2String.get(), lang.get());
uint32_t numGlyphRuns; uint32_t numGlyphRuns;
const GlyphRun* glyphRuns = GetGlyphRuns(&numGlyphRuns); const GlyphRun* glyphRuns = GetGlyphRuns(&numGlyphRuns);
@ -1744,12 +1747,9 @@ void gfxTextRun::Dump(FILE* out) {
const gfxFontStyle* style = font->GetStyle(); const gfxFontStyle* style = font->GetStyle();
nsAutoString styleString; nsAutoString styleString;
nsStyleUtil::AppendFontSlantStyle(style->style, styleString); nsStyleUtil::AppendFontSlantStyle(style->style, styleString);
nsAutoCString lang; fprintf(out, " [%d] offset=%d %s %f/%g/%s\n", i,
style->language->ToUTF8String(lang);
fprintf(out, " [%d] offset=%d %s %f/%g/%s/%s\n", i,
glyphRuns[i].mCharacterOffset, font->GetName().get(), style->size, glyphRuns[i].mCharacterOffset, font->GetName().get(), style->size,
style->weight.ToFloat(), NS_ConvertUTF16toUTF8(styleString).get(), style->weight.ToFloat(), NS_ConvertUTF16toUTF8(styleString).get());
lang.get());
} }
fprintf(out, " Glyphs:\n"); fprintf(out, " Glyphs:\n");
@ -1828,12 +1828,14 @@ void gfxTextRun::Dump(FILE* out) {
#endif #endif
gfxFontGroup::gfxFontGroup(const FontFamilyList& aFontFamilyList, gfxFontGroup::gfxFontGroup(const FontFamilyList& aFontFamilyList,
const gfxFontStyle* aStyle, const gfxFontStyle* aStyle, nsAtom* aLanguage,
bool aExplicitLanguage,
gfxTextPerfMetrics* aTextPerf, gfxTextPerfMetrics* aTextPerf,
FontMatchingStats* aFontMatchingStats, FontMatchingStats* aFontMatchingStats,
gfxUserFontSet* aUserFontSet, gfxFloat aDevToCssSize) gfxUserFontSet* aUserFontSet, gfxFloat aDevToCssSize)
: mFamilyList(aFontFamilyList), : mFamilyList(aFontFamilyList),
mStyle(*aStyle), mStyle(*aStyle),
mLanguage(aLanguage),
mUnderlineOffset(UNDERLINE_OFFSET_NOT_SET), mUnderlineOffset(UNDERLINE_OFFSET_NOT_SET),
mHyphenWidth(-1), mHyphenWidth(-1),
mDevToCssSize(aDevToCssSize), mDevToCssSize(aDevToCssSize),
@ -1841,9 +1843,10 @@ gfxFontGroup::gfxFontGroup(const FontFamilyList& aFontFamilyList,
mTextPerf(aTextPerf), mTextPerf(aTextPerf),
mFontMatchingStats(aFontMatchingStats), mFontMatchingStats(aFontMatchingStats),
mLastPrefLang(eFontPrefLang_Western), mLastPrefLang(eFontPrefLang_Western),
mPageLang(gfxPlatformFontList::GetFontPrefLangFor(aStyle->language)), mPageLang(gfxPlatformFontList::GetFontPrefLangFor(aLanguage)),
mLastPrefFirstFont(false), mLastPrefFirstFont(false),
mSkipDrawing(false) { mSkipDrawing(false),
mExplicitLanguage(aExplicitLanguage) {
// We don't use SetUserFontSet() here, as we want to unconditionally call // We don't use SetUserFontSet() here, as we want to unconditionally call
// BuildFontList() rather than only do UpdateUserFonts() if it changed. // BuildFontList() rather than only do UpdateUserFonts() if it changed.
mCurrGeneration = GetGeneration(); mCurrGeneration = GetGeneration();
@ -1869,7 +1872,7 @@ void gfxFontGroup::BuildFontList() {
MOZ_ASSERT_UNREACHABLE("broken FontFamilyName, no atom!"); MOZ_ASSERT_UNREACHABLE("broken FontFamilyName, no atom!");
} }
} else { } else {
pfl->AddGenericFonts(name.mGeneric, mStyle.language, fonts); pfl->AddGenericFonts(name.mGeneric, mLanguage, fonts);
if (mTextPerf) { if (mTextPerf) {
mTextPerf->current.genericLookups++; mTextPerf->current.genericLookups++;
} }
@ -1913,8 +1916,7 @@ void gfxFontGroup::BuildFontList() {
// if necessary, append default generic onto the end // if necessary, append default generic onto the end
if (mFamilyList.GetDefaultFontType() != StyleGenericFontFamily::None && if (mFamilyList.GetDefaultFontType() != StyleGenericFontFamily::None &&
!mFamilyList.HasDefaultGeneric()) { !mFamilyList.HasDefaultGeneric()) {
pfl->AddGenericFonts(mFamilyList.GetDefaultFontType(), mStyle.language, pfl->AddGenericFonts(mFamilyList.GetDefaultFontType(), mLanguage, fonts);
fonts);
if (mTextPerf) { if (mTextPerf) {
mTextPerf->current.genericLookups++; mTextPerf->current.genericLookups++;
} }
@ -1953,7 +1955,7 @@ void gfxFontGroup::AddPlatformFont(const nsACString& aName, bool aQuotedName,
StyleGenericFontFamily::None, aName, &aFamilyList, StyleGenericFontFamily::None, aName, &aFamilyList,
aQuotedName ? gfxPlatformFontList::FindFamiliesFlags::eQuotedFamilyName aQuotedName ? gfxPlatformFontList::FindFamiliesFlags::eQuotedFamilyName
: gfxPlatformFontList::FindFamiliesFlags(0), : gfxPlatformFontList::FindFamiliesFlags(0),
&mStyle, mDevToCssSize); &mStyle, mLanguage.get(), mDevToCssSize);
} }
void gfxFontGroup::AddFamilyToFontList(gfxFontFamily* aFamily, void gfxFontGroup::AddFamilyToFontList(gfxFontFamily* aFamily,
@ -2541,7 +2543,7 @@ void gfxFontGroup::InitTextRun(DrawTarget* aDrawTarget, gfxTextRun* aTextRun,
if (sizeof(T) == sizeof(uint8_t) && !transformedString) { if (sizeof(T) == sizeof(uint8_t) && !transformedString) {
if (MOZ_UNLIKELY(MOZ_LOG_TEST(log, LogLevel::Warning))) { if (MOZ_UNLIKELY(MOZ_LOG_TEST(log, LogLevel::Warning))) {
nsAutoCString lang; nsAutoCString lang;
mStyle.language->ToUTF8String(lang); mLanguage->ToUTF8String(lang);
nsAutoCString families; nsAutoCString families;
mFamilyList.ToString(families); mFamilyList.ToString(families);
nsAutoCString str((const char*)aString, aLength); nsAutoCString str((const char*)aString, aLength);
@ -2588,7 +2590,7 @@ void gfxFontGroup::InitTextRun(DrawTarget* aDrawTarget, gfxTextRun* aTextRun,
while (scriptRuns.Next(runStart, runLimit, runScript)) { while (scriptRuns.Next(runStart, runLimit, runScript)) {
if (MOZ_UNLIKELY(MOZ_LOG_TEST(log, LogLevel::Warning))) { if (MOZ_UNLIKELY(MOZ_LOG_TEST(log, LogLevel::Warning))) {
nsAutoCString lang; nsAutoCString lang;
mStyle.language->ToUTF8String(lang); mLanguage->ToUTF8String(lang);
nsAutoCString families; nsAutoCString families;
mFamilyList.ToString(families); mFamilyList.ToString(families);
nsAutoString styleString; nsAutoString styleString;
@ -2708,7 +2710,7 @@ void gfxFontGroup::InitScriptRun(DrawTarget* aDrawTarget, gfxTextRun* aTextRun,
(matchedLength > 0), range.orientation, isCJK); (matchedLength > 0), range.orientation, isCJK);
if (!matchedFont->SplitAndInitTextRun( if (!matchedFont->SplitAndInitTextRun(
aDrawTarget, aTextRun, aString + runStart, aOffset + runStart, aDrawTarget, aTextRun, aString + runStart, aOffset + runStart,
matchedLength, aRunScript, range.orientation)) { matchedLength, aRunScript, mLanguage, range.orientation)) {
// glyph layout failed! treat as missing glyphs // glyph layout failed! treat as missing glyphs
matchedFont = nullptr; matchedFont = nullptr;
} }
@ -2743,7 +2745,7 @@ void gfxFontGroup::InitScriptRun(DrawTarget* aDrawTarget, gfxTextRun* aTextRun,
(matchedLength > 0), range.orientation, isCJK); (matchedLength > 0), range.orientation, isCJK);
if (!subSuperFont->SplitAndInitTextRun( if (!subSuperFont->SplitAndInitTextRun(
aDrawTarget, aTextRun, aString + runStart, aOffset + runStart, aDrawTarget, aTextRun, aString + runStart, aOffset + runStart,
matchedLength, aRunScript, range.orientation)) { matchedLength, aRunScript, mLanguage, range.orientation)) {
// glyph layout failed! treat as missing glyphs // glyph layout failed! treat as missing glyphs
matchedFont = nullptr; matchedFont = nullptr;
} }
@ -2755,7 +2757,8 @@ void gfxFontGroup::InitScriptRun(DrawTarget* aDrawTarget, gfxTextRun* aTextRun,
if (!matchedFont->InitFakeSmallCapsRun( if (!matchedFont->InitFakeSmallCapsRun(
aDrawTarget, aTextRun, aString + runStart, aOffset + runStart, aDrawTarget, aTextRun, aString + runStart, aOffset + runStart,
matchedLength, range.matchType, range.orientation, aRunScript, matchedLength, range.matchType, range.orientation, aRunScript,
syntheticLower, syntheticUpper)) { mExplicitLanguage ? mLanguage.get() : nullptr, syntheticLower,
syntheticUpper)) {
matchedFont = nullptr; matchedFont = nullptr;
} }
} else { } else {
@ -2777,7 +2780,7 @@ void gfxFontGroup::InitScriptRun(DrawTarget* aDrawTarget, gfxTextRun* aTextRun,
(matchedLength > 0), range.orientation, isCJK); (matchedLength > 0), range.orientation, isCJK);
if (!matchedFont->SplitAndInitTextRun( if (!matchedFont->SplitAndInitTextRun(
aDrawTarget, aTextRun, aString + runStart, aOffset + runStart, aDrawTarget, aTextRun, aString + runStart, aOffset + runStart,
matchedLength, aRunScript, range.orientation)) { matchedLength, aRunScript, mLanguage, range.orientation)) {
// glyph layout failed! treat as missing glyphs // glyph layout failed! treat as missing glyphs
matchedFont = nullptr; matchedFont = nullptr;
} }
@ -3522,7 +3525,7 @@ void gfxFontGroup::ComputeRanges(nsTArray<TextRange>& aRanges, const T* aString,
if (MOZ_UNLIKELY(MOZ_LOG_TEST(log, LogLevel::Debug))) { if (MOZ_UNLIKELY(MOZ_LOG_TEST(log, LogLevel::Debug))) {
nsAutoCString lang; nsAutoCString lang;
mStyle.language->ToUTF8String(lang); mLanguage->ToUTF8String(lang);
nsAutoCString families; nsAutoCString families;
mFamilyList.ToString(families); mFamilyList.ToString(families);

View file

@ -932,7 +932,8 @@ class gfxFontGroup final : public gfxTextRunFactory {
Shutdown(); // platform must call this to release the languageAtomService Shutdown(); // platform must call this to release the languageAtomService
gfxFontGroup(const mozilla::FontFamilyList& aFontFamilyList, gfxFontGroup(const mozilla::FontFamilyList& aFontFamilyList,
const gfxFontStyle* aStyle, gfxTextPerfMetrics* aTextPerf, const gfxFontStyle* aStyle, nsAtom* aLanguage,
bool aExplicitLanguage, gfxTextPerfMetrics* aTextPerf,
FontMatchingStats* aFontMatchingStats, FontMatchingStats* aFontMatchingStats,
gfxUserFontSet* aUserFontSet, gfxFloat aDevToCssSize); gfxUserFontSet* aUserFontSet, gfxFloat aDevToCssSize);
@ -1092,6 +1093,8 @@ class gfxFontGroup final : public gfxTextRunFactory {
} }
} }
nsAtom* Language() const { return mLanguage.get(); }
protected: protected:
friend class mozilla::PostTraversalTask; friend class mozilla::PostTraversalTask;
@ -1377,6 +1380,8 @@ class gfxFontGroup final : public gfxTextRunFactory {
RefPtr<gfxFont> mDefaultFont; RefPtr<gfxFont> mDefaultFont;
gfxFontStyle mStyle; gfxFontStyle mStyle;
RefPtr<nsAtom> mLanguage;
gfxFloat mUnderlineOffset; gfxFloat mUnderlineOffset;
gfxFloat mHyphenWidth; gfxFloat mHyphenWidth;
gfxFloat mDevToCssSize; gfxFloat mDevToCssSize;
@ -1405,6 +1410,8 @@ class gfxFontGroup final : public gfxTextRunFactory {
// download to complete (or fallback // download to complete (or fallback
// timer to fire) // timer to fire)
bool mExplicitLanguage; // Does mLanguage come from an explicit attribute?
uint32_t mFontListGeneration = 0; // platform font list generation for this uint32_t mFontListGeneration = 0; // platform font list generation for this
// fontgroup // fontgroup