From 16eb1dba68b241c41303e67595a46cc45c6f6324 Mon Sep 17 00:00:00 2001 From: Jonathan Kew Date: Fri, 13 Nov 2020 13:15:39 +0000 Subject: [PATCH] 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 --- dom/canvas/CanvasRenderingContext2D.cpp | 7 +- gfx/src/nsDeviceContext.cpp | 3 +- gfx/src/nsFontMetrics.cpp | 8 +- gfx/src/nsFontMetrics.h | 7 ++ gfx/thebes/gfxCoreTextShaper.cpp | 3 +- gfx/thebes/gfxCoreTextShaper.h | 2 +- gfx/thebes/gfxDWriteFontList.cpp | 16 ++- gfx/thebes/gfxDWriteFontList.h | 4 +- gfx/thebes/gfxFT2FontList.cpp | 4 +- gfx/thebes/gfxFT2FontList.h | 3 +- gfx/thebes/gfxFT2Fonts.cpp | 5 +- gfx/thebes/gfxFT2Fonts.h | 2 +- gfx/thebes/gfxFcPlatformFontList.cpp | 13 ++- gfx/thebes/gfxFcPlatformFontList.h | 4 +- gfx/thebes/gfxFont.cpp | 138 ++++++++++++------------ gfx/thebes/gfxFont.h | 78 +++++++------- gfx/thebes/gfxGDIFont.cpp | 5 +- gfx/thebes/gfxGDIFont.h | 3 +- gfx/thebes/gfxGDIFontList.cpp | 10 +- gfx/thebes/gfxGDIFontList.h | 4 +- gfx/thebes/gfxGraphiteShaper.cpp | 7 +- gfx/thebes/gfxGraphiteShaper.h | 2 +- gfx/thebes/gfxHarfBuzzShaper.cpp | 7 +- gfx/thebes/gfxHarfBuzzShaper.h | 2 +- gfx/thebes/gfxMacFont.cpp | 7 +- gfx/thebes/gfxMacFont.h | 2 +- gfx/thebes/gfxMacPlatformFontList.h | 4 +- gfx/thebes/gfxMacPlatformFontList.mm | 18 ++-- gfx/thebes/gfxPlatform.cpp | 10 +- gfx/thebes/gfxPlatform.h | 3 +- gfx/thebes/gfxPlatformFontList.cpp | 11 +- gfx/thebes/gfxPlatformFontList.h | 18 ++-- gfx/thebes/gfxTextRun.cpp | 47 ++++---- gfx/thebes/gfxTextRun.h | 9 +- 34 files changed, 252 insertions(+), 214 deletions(-) diff --git a/dom/canvas/CanvasRenderingContext2D.cpp b/dom/canvas/CanvasRenderingContext2D.cpp index 5ce9a6a9db16..92ca119895b1 100644 --- a/dom/canvas/CanvasRenderingContext2D.cpp +++ b/dom/canvas/CanvasRenderingContext2D.cpp @@ -3997,6 +3997,9 @@ gfxFontGroup* CanvasRenderingContext2D::GetCurrentFontStyle() { bool fontUpdated = SetFontInternal(kDefaultFontStyle, err); if (err.Failed() || !fontUpdated) { err.SuppressException(); + // XXX Should we get a default lang from the prescontext or something? + nsAtom* language = nsGkAtoms::x_western; + bool explicitLanguage = false; gfxFontStyle style; style.size = kDefaultFontSize; gfxTextPerfMetrics* tp = nullptr; @@ -4009,8 +4012,8 @@ gfxFontGroup* CanvasRenderingContext2D::GetCurrentFontStyle() { GetAppUnitsValues(&perDevPixel, &perCSSPixel); gfxFloat devToCssSize = gfxFloat(perDevPixel) / gfxFloat(perCSSPixel); CurrentState().fontGroup = gfxPlatform::GetPlatform()->CreateFontGroup( - FontFamilyList(StyleGenericFontFamily::SansSerif), &style, tp, - fontStats, nullptr, devToCssSize); + FontFamilyList(StyleGenericFontFamily::SansSerif), &style, language, + explicitLanguage, tp, fontStats, nullptr, devToCssSize); if (CurrentState().fontGroup) { CurrentState().font = kDefaultFontStyle; } else { diff --git a/gfx/src/nsDeviceContext.cpp b/gfx/src/nsDeviceContext.cpp index 6516af630571..daa592e1bf08 100644 --- a/gfx/src/nsDeviceContext.cpp +++ b/gfx/src/nsDeviceContext.cpp @@ -149,7 +149,8 @@ already_AddRefed nsFontCache::GetMetricsFor( if (fm->Font().Equals(aFont) && fm->GetUserFontSet() == aParams.userFontSet && fm->Language() == language && - fm->Orientation() == aParams.orientation) { + fm->Orientation() == aParams.orientation && + fm->ExplicitLanguage() == aParams.explicitLanguage) { if (i != n) { // promote it to the end of the cache mFontMetrics.RemoveElementAt(i); diff --git a/gfx/src/nsFontMetrics.cpp b/gfx/src/nsFontMetrics.cpp index 59fb7d3ce542..767b979f3a2d 100644 --- a/gfx/src/nsFontMetrics.cpp +++ b/gfx/src/nsFontMetrics.cpp @@ -114,12 +114,12 @@ nsFontMetrics::nsFontMetrics(const nsFont& aFont, const Params& aParams, mDeviceContext(aContext), mP2A(aContext->AppUnitsPerDevPixel()), mOrientation(aParams.orientation), + mExplicitLanguage(aParams.explicitLanguage), mTextRunRTL(false), mVertical(false), mTextOrientation(mozilla::StyleTextOrientation::Mixed) { gfxFontStyle style(aFont.style, aFont.weight, aFont.stretch, - gfxFloat(aFont.size.ToAppUnits()) / mP2A, aParams.language, - aParams.explicitLanguage, aFont.sizeAdjust, + gfxFloat(aFont.size.ToAppUnits()) / mP2A, aFont.sizeAdjust, aFont.systemFont, mDeviceContext->IsPrinterContext(), aFont.synthesis & NS_FONT_SYNTHESIS_WEIGHT, aFont.synthesis & NS_FONT_SYNTHESIS_STYLE, @@ -132,8 +132,8 @@ nsFontMetrics::nsFontMetrics(const nsFont& aFont, const Params& aParams, gfxFloat devToCssSize = gfxFloat(mP2A) / gfxFloat(AppUnitsPerCSSPixel()); mFontGroup = gfxPlatform::GetPlatform()->CreateFontGroup( - aFont.fontlist, &style, aParams.textPerf, aParams.fontStats, - aParams.userFontSet, devToCssSize); + aFont.fontlist, &style, mLanguage, mExplicitLanguage, aParams.textPerf, + aParams.fontStats, aParams.userFontSet, devToCssSize); } nsFontMetrics::~nsFontMetrics() { diff --git a/gfx/src/nsFontMetrics.h b/gfx/src/nsFontMetrics.h index 022d675865f0..b2f9554a0aef 100644 --- a/gfx/src/nsFontMetrics.h +++ b/gfx/src/nsFontMetrics.h @@ -235,6 +235,8 @@ class nsFontMetrics final { return mTextOrientation; } + bool ExplicitLanguage() const { return mExplicitLanguage; } + gfxFontGroup* GetThebesFontGroup() const { return mFontGroup; } gfxUserFontSet* GetUserFontSet() const; @@ -257,6 +259,11 @@ class nsFontMetrics final { // descent) they will return. 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 // like GetWidth and DrawString according to the writing mode, direction // and text-orientation desired. diff --git a/gfx/thebes/gfxCoreTextShaper.cpp b/gfx/thebes/gfxCoreTextShaper.cpp index ebb7498058f0..0e24337bf47e 100644 --- a/gfx/thebes/gfxCoreTextShaper.cpp +++ b/gfx/thebes/gfxCoreTextShaper.cpp @@ -78,7 +78,8 @@ static bool IsBuggyIndicScript(unicode::Script aScript) { bool gfxCoreTextShaper::ShapeText(DrawTarget* aDrawTarget, const char16_t* aText, uint32_t aOffset, uint32_t aLength, Script aScript, - bool aVertical, RoundingFlags aRounding, + nsAtom* aLanguage, bool aVertical, + RoundingFlags aRounding, gfxShapedText* aShapedText) { // Create a CFAttributedString with text and style info, so we can use // CoreText to lay it out. diff --git a/gfx/thebes/gfxCoreTextShaper.h b/gfx/thebes/gfxCoreTextShaper.h index c06ff73f743a..1385bd00bb12 100644 --- a/gfx/thebes/gfxCoreTextShaper.h +++ b/gfx/thebes/gfxCoreTextShaper.h @@ -19,7 +19,7 @@ class gfxCoreTextShaper : public gfxFontShaper { virtual ~gfxCoreTextShaper(); 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; // clean up static objects that may have been cached diff --git a/gfx/thebes/gfxDWriteFontList.cpp b/gfx/thebes/gfxDWriteFontList.cpp index 93b9beea1d25..549590a22484 100644 --- a/gfx/thebes/gfxDWriteFontList.cpp +++ b/gfx/thebes/gfxDWriteFontList.cpp @@ -873,7 +873,7 @@ gfxDWriteFontList::gfxDWriteFontList() : mForceGDIClassicMaxFontSize(0.0) { // Arial to avoid this. FontFamily gfxDWriteFontList::GetDefaultFontForPlatform( - const gfxFontStyle* aStyle) { + const gfxFontStyle* aStyle, nsAtom* aLanguage) { // try Arial first FontFamily ff; ff = FindFamily("Arial"_ns); @@ -1870,12 +1870,10 @@ void gfxDWriteFontList::GetDirectWriteSubstitutes() { } } -bool gfxDWriteFontList::FindAndAddFamilies(StyleGenericFontFamily aGeneric, - const nsACString& aFamily, - nsTArray* aOutput, - FindFamiliesFlags aFlags, - gfxFontStyle* aStyle, - gfxFloat aDevToCssSize) { +bool gfxDWriteFontList::FindAndAddFamilies( + StyleGenericFontFamily aGeneric, const nsACString& aFamily, + nsTArray* aOutput, FindFamiliesFlags aFlags, + gfxFontStyle* aStyle, nsAtom* aLanguage, gfxFloat aDevToCssSize) { nsAutoCString keyName(aFamily); BuildKeyNameFromFontName(keyName); @@ -1896,8 +1894,8 @@ bool gfxDWriteFontList::FindAndAddFamilies(StyleGenericFontFamily aGeneric, return false; } - return gfxPlatformFontList::FindAndAddFamilies(aGeneric, keyName, aOutput, - aFlags, aStyle, aDevToCssSize); + return gfxPlatformFontList::FindAndAddFamilies( + aGeneric, keyName, aOutput, aFlags, aStyle, aLanguage, aDevToCssSize); } void gfxDWriteFontList::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf, diff --git a/gfx/thebes/gfxDWriteFontList.h b/gfx/thebes/gfxDWriteFontList.h index 1de880af6ae1..e6422aecddae 100644 --- a/gfx/thebes/gfxDWriteFontList.h +++ b/gfx/thebes/gfxDWriteFontList.h @@ -413,6 +413,7 @@ class gfxDWriteFontList final : public gfxPlatformFontList { nsTArray* aOutput, FindFamiliesFlags aFlags, gfxFontStyle* aStyle = nullptr, + nsAtom* aLanguage = nullptr, gfxFloat aDevToCssSize = 1.0) override; gfxFloat GetForceGDIClassicMaxFontSize() { @@ -425,7 +426,8 @@ class gfxDWriteFontList final : public gfxPlatformFontList { FontListSizes* aSizes) const; 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, // return null if no usable result found diff --git a/gfx/thebes/gfxFT2FontList.cpp b/gfx/thebes/gfxFT2FontList.cpp index 690e6cccdd0e..ff312d71c2dc 100644 --- a/gfx/thebes/gfxFT2FontList.cpp +++ b/gfx/thebes/gfxFT2FontList.cpp @@ -1737,8 +1737,8 @@ searchDone: return fe; } -FontFamily gfxFT2FontList::GetDefaultFontForPlatform( - const gfxFontStyle* aStyle) { +FontFamily gfxFT2FontList::GetDefaultFontForPlatform(const gfxFontStyle* aStyle, + nsAtom* aLanguage) { FontFamily ff; #if defined(MOZ_WIDGET_ANDROID) ff = FindFamily("Roboto"_ns); diff --git a/gfx/thebes/gfxFT2FontList.h b/gfx/thebes/gfxFT2FontList.h index eb424c8dd551..fe87d46f9c3a 100644 --- a/gfx/thebes/gfxFT2FontList.h +++ b/gfx/thebes/gfxFT2FontList.h @@ -214,7 +214,8 @@ class gfxFT2FontList final : public gfxPlatformFontList { void FindFontsInDir(const nsCString& aDir, FontNameCache* aFNC); - FontFamily GetDefaultFontForPlatform(const gfxFontStyle* aStyle) override; + FontFamily GetDefaultFontForPlatform(const gfxFontStyle* aStyle, + nsAtom* aLanguage = nullptr) override; nsTHashtable mSkipSpaceLookupCheckFamilies; diff --git a/gfx/thebes/gfxFT2Fonts.cpp b/gfx/thebes/gfxFT2Fonts.cpp index 4cb832c1f406..b4edd2edeeaf 100644 --- a/gfx/thebes/gfxFT2Fonts.cpp +++ b/gfx/thebes/gfxFT2Fonts.cpp @@ -42,10 +42,11 @@ using namespace mozilla::gfx; bool gfxFT2Font::ShapeText(DrawTarget* aDrawTarget, const char16_t* aText, uint32_t aOffset, uint32_t aLength, Script aScript, - bool aVertical, RoundingFlags aRounding, + nsAtom* aLanguage, bool aVertical, + RoundingFlags aRounding, gfxShapedText* aShapedText) { if (!gfxFont::ShapeText(aDrawTarget, aText, aOffset, aLength, aScript, - aVertical, aRounding, aShapedText)) { + aLanguage, aVertical, aRounding, aShapedText)) { // harfbuzz must have failed(?!), just render raw glyphs AddRange(aText, aOffset, aLength, aShapedText); PostShapingFixup(aDrawTarget, aText, aOffset, aLength, aVertical, diff --git a/gfx/thebes/gfxFT2Fonts.h b/gfx/thebes/gfxFT2Fonts.h index 031864a1b94b..65699b27b75a 100644 --- a/gfx/thebes/gfxFT2Fonts.h +++ b/gfx/thebes/gfxFT2Fonts.h @@ -63,7 +63,7 @@ class gfxFT2Font : public gfxFT2FontBase { bool ShapeText(DrawTarget* aDrawTarget, const char16_t* aText, uint32_t aOffset, uint32_t aLength, Script aScript, - bool aVertical, RoundingFlags aRounding, + nsAtom* aLanguage, bool aVertical, RoundingFlags aRounding, gfxShapedText* aShapedText) override; void FillGlyphDataForChar(FT_Face face, uint32_t ch, CachedGlyphData* gd); diff --git a/gfx/thebes/gfxFcPlatformFontList.cpp b/gfx/thebes/gfxFcPlatformFontList.cpp index f4fff2339212..3d9fa8b062f9 100644 --- a/gfx/thebes/gfxFcPlatformFontList.cpp +++ b/gfx/thebes/gfxFcPlatformFontList.cpp @@ -1856,11 +1856,11 @@ void gfxFcPlatformFontList::GetFontList(nsAtom* aLangGroup, } FontFamily gfxFcPlatformFontList::GetDefaultFontForPlatform( - const gfxFontStyle* aStyle) { + const gfxFontStyle* aStyle, nsAtom* aLanguage) { // Get the default font by using a fake name to retrieve the first // scalable font that fontconfig suggests for the given language. - PrefFontList* prefFonts = - FindGenericFamilies("-moz-default"_ns, aStyle->language); + PrefFontList* prefFonts = FindGenericFamilies( + "-moz-default"_ns, aLanguage ? aLanguage : nsGkAtoms::x_western); NS_ASSERTION(prefFonts, "null list of generic fonts"); if (prefFonts && !prefFonts->IsEmpty()) { return (*prefFonts)[0]; @@ -1906,10 +1906,9 @@ gfxFontEntry* gfxFcPlatformFontList::MakePlatformFont( bool gfxFcPlatformFontList::FindAndAddFamilies( StyleGenericFontFamily aGeneric, const nsACString& aFamily, nsTArray* aOutput, FindFamiliesFlags aFlags, - gfxFontStyle* aStyle, gfxFloat aDevToCssSize) { + gfxFontStyle* aStyle, nsAtom* aLanguage, gfxFloat aDevToCssSize) { nsAutoCString familyName(aFamily); ToLowerCase(familyName); - nsAtom* language = (aStyle ? aStyle->language.get() : nullptr); if (!(aFlags & FindFamiliesFlags::eQuotedFamilyName)) { // 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 if (isDeprecatedGeneric || mozilla::FontFamilyName::Convert(familyName).IsGeneric()) { - PrefFontList* prefFonts = FindGenericFamilies(familyName, language); + PrefFontList* prefFonts = FindGenericFamilies(familyName, aLanguage); if (prefFonts && !prefFonts->IsEmpty()) { aOutput->AppendElements(*prefFonts); return true; @@ -1986,7 +1985,7 @@ bool gfxFcPlatformFontList::FindAndAddFamilies( } gfxPlatformFontList::FindAndAddFamilies( aGeneric, nsDependentCString(ToCharPtr(substName)), &cachedFamilies, - aFlags); + aFlags, aStyle, aLanguage); } // Cache the resulting list, so we don't have to do this again. diff --git a/gfx/thebes/gfxFcPlatformFontList.h b/gfx/thebes/gfxFcPlatformFontList.h index cf13b3d9b847..e5803e0b3441 100644 --- a/gfx/thebes/gfxFcPlatformFontList.h +++ b/gfx/thebes/gfxFcPlatformFontList.h @@ -266,6 +266,7 @@ class gfxFcPlatformFontList final : public gfxPlatformFontList { nsTArray* aOutput, FindFamiliesFlags aFlags, gfxFontStyle* aStyle = nullptr, + nsAtom* aLanguage = nullptr, gfxFloat aDevToCssSize = 1.0) override; bool GetStandardFamilyName(const nsCString& aFontName, @@ -320,7 +321,8 @@ class gfxFcPlatformFontList final : public gfxPlatformFontList { 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 { Unknown = 0, diff --git a/gfx/thebes/gfxFont.cpp b/gfx/thebes/gfxFont.cpp index 0eac5a0f0f69..d169297e3cec 100644 --- a/gfx/thebes/gfxFont.cpp +++ b/gfx/thebes/gfxFont.cpp @@ -2732,9 +2732,9 @@ static char16_t IsBoundarySpace(char16_t aChar, char16_t aNextChar) { template gfxShapedWord* gfxFont::GetShapedWord( DrawTarget* aDrawTarget, const T* aText, uint32_t aLength, uint32_t aHash, - Script aRunScript, bool aVertical, int32_t aAppUnitsPerDevUnit, - gfx::ShapedTextFlags aFlags, RoundingFlags aRounding, - gfxTextPerfMetrics* aTextPerf GFX_MAYBE_UNUSED) { + Script aRunScript, nsAtom* aLanguage, bool aVertical, + int32_t aAppUnitsPerDevUnit, gfx::ShapedTextFlags aFlags, + RoundingFlags aRounding, gfxTextPerfMetrics* aTextPerf GFX_MAYBE_UNUSED) { // if the cache is getting too big, flush it and start over uint32_t wordCacheMaxEntries = gfxPlatform::GetPlatform()->WordCacheMaxEntries(); @@ -2744,8 +2744,8 @@ gfxShapedWord* gfxFont::GetShapedWord( } // if there's a cached entry for this word, just return it - CacheHashKey key(aText, aLength, aHash, aRunScript, aAppUnitsPerDevUnit, - aFlags, aRounding); + CacheHashKey key(aText, aLength, aHash, aRunScript, aLanguage, + aAppUnitsPerDevUnit, aFlags, aRounding); CacheHashEntry* entry = mWordCache->PutEntry(key, fallible); if (!entry) { @@ -2770,8 +2770,8 @@ gfxShapedWord* gfxFont::GetShapedWord( } #endif - sw = gfxShapedWord::Create(aText, aLength, aRunScript, aAppUnitsPerDevUnit, - aFlags, aRounding); + sw = gfxShapedWord::Create(aText, aLength, aRunScript, aLanguage, + aAppUnitsPerDevUnit, aFlags, aRounding); entry->mShapedWord.reset(sw); if (!sw) { NS_WARNING("failed to create gfxShapedWord - expect missing text"); @@ -2779,7 +2779,7 @@ gfxShapedWord* gfxFont::GetShapedWord( } DebugOnly 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"); @@ -2788,7 +2788,7 @@ gfxShapedWord* gfxFont::GetShapedWord( template gfxShapedWord* gfxFont::GetShapedWord( 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, 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 || sw->GetRounding() != aKey->mRounding || sw->GetAppUnitsPerDevUnit() != aKey->mAppUnitsPerDevUnit || - sw->GetScript() != aKey->mScript) { + sw->GetScript() != aKey->mScript || + sw->GetLanguage() != aKey->mLanguage) { return false; } if (sw->TextIs8Bit()) { @@ -2830,8 +2831,8 @@ bool gfxFont::CacheHashEntry::KeyEquals(const KeyTypePointer aKey) const { bool gfxFont::ShapeText(DrawTarget* aDrawTarget, const uint8_t* aText, uint32_t aOffset, uint32_t aLength, Script aScript, - bool aVertical, RoundingFlags aRounding, - gfxShapedText* aShapedText) { + nsAtom* aLanguage, bool aVertical, + RoundingFlags aRounding, gfxShapedText* aShapedText) { nsDependentCSubstring ascii((const char*)aText, aLength); nsAutoString utf16; AppendASCIItoUTF16(ascii, utf16); @@ -2839,13 +2840,13 @@ bool gfxFont::ShapeText(DrawTarget* aDrawTarget, const uint8_t* aText, return false; } return ShapeText(aDrawTarget, utf16.BeginReading(), aOffset, aLength, aScript, - aVertical, aRounding, aShapedText); + aLanguage, aVertical, aRounding, aShapedText); } bool gfxFont::ShapeText(DrawTarget* aDrawTarget, const char16_t* aText, uint32_t aOffset, uint32_t aLength, Script aScript, - bool aVertical, RoundingFlags aRounding, - gfxShapedText* aShapedText) { + nsAtom* aLanguage, bool aVertical, + RoundingFlags aRounding, gfxShapedText* aShapedText) { // XXX Currently, we do all vertical shaping through harfbuzz. // Vertical graphite support may be wanted as a future enhancement. if (FontCanSupportGraphite() && !aVertical) { @@ -2855,7 +2856,7 @@ bool gfxFont::ShapeText(DrawTarget* aDrawTarget, const char16_t* aText, Telemetry::ScalarAdd(Telemetry::ScalarID::BROWSER_USAGE_GRAPHITE, 1); } if (mGraphiteShaper->ShapeText(aDrawTarget, aText, aOffset, aLength, - aScript, aVertical, aRounding, + aScript, aLanguage, aVertical, aRounding, aShapedText)) { PostShapingFixup(aDrawTarget, aText, aOffset, aLength, aVertical, aShapedText); @@ -2868,7 +2869,8 @@ bool gfxFont::ShapeText(DrawTarget* aDrawTarget, const char16_t* aText, mHarfBuzzShaper = MakeUnique(this); } if (mHarfBuzzShaper->ShapeText(aDrawTarget, aText, aOffset, aLength, aScript, - aVertical, aRounding, aShapedText)) { + aLanguage, aVertical, aRounding, + aShapedText)) { PostShapingFixup(aDrawTarget, aText, aOffset, aLength, aVertical, aShapedText); if (GetFontEntry()->HasTrackingTable()) { @@ -2917,7 +2919,7 @@ template bool gfxFont::ShapeFragmentWithoutWordCache(DrawTarget* aDrawTarget, const T* aText, uint32_t aOffset, uint32_t aLength, Script aScript, - bool aVertical, + nsAtom* aLanguage, bool aVertical, RoundingFlags aRounding, gfxTextRun* aTextRun) { aTextRun->SetupClusterBoundaries(aOffset, aText, aLength); @@ -2952,8 +2954,8 @@ bool gfxFont::ShapeFragmentWithoutWordCache(DrawTarget* aDrawTarget, } } - ok = ShapeText(aDrawTarget, aText, aOffset, fragLen, aScript, aVertical, - aRounding, aTextRun); + ok = ShapeText(aDrawTarget, aText, aOffset, fragLen, aScript, aLanguage, + aVertical, aRounding, aTextRun); aText += fragLen; aOffset += fragLen; @@ -2975,8 +2977,8 @@ static bool IsInvalidControlChar(uint32_t aCh) { template bool gfxFont::ShapeTextWithoutWordCache(DrawTarget* aDrawTarget, const T* aText, uint32_t aOffset, uint32_t aLength, - Script aScript, bool aVertical, - RoundingFlags aRounding, + Script aScript, nsAtom* aLanguage, + bool aVertical, RoundingFlags aRounding, gfxTextRun* aTextRun) { uint32_t fragStart = 0; bool ok = true; @@ -2992,9 +2994,9 @@ bool gfxFont::ShapeTextWithoutWordCache(DrawTarget* aDrawTarget, const T* aText, } if (length > 0) { - ok = ShapeFragmentWithoutWordCache(aDrawTarget, aText + fragStart, - aOffset + fragStart, length, aScript, - aVertical, aRounding, aTextRun); + ok = ShapeFragmentWithoutWordCache( + aDrawTarget, aText + fragStart, aOffset + fragStart, length, aScript, + aLanguage, aVertical, aRounding, aTextRun); } if (i == aLength) { @@ -3015,7 +3017,8 @@ bool gfxFont::ShapeTextWithoutWordCache(DrawTarget* aDrawTarget, const T* aText, gfx::ShapedTextFlags::TEXT_HIDE_CONTROL_CHARACTERS)) { if (GetFontEntry()->IsUserFont() && HasCharacter(ch)) { ShapeFragmentWithoutWordCache(aDrawTarget, aText + i, aOffset + i, 1, - aScript, aVertical, aRounding, aTextRun); + aScript, aLanguage, aVertical, aRounding, + aTextRun); } else { aTextRun->SetMissingGlyph(aOffset + i, ch, this); } @@ -3054,7 +3057,8 @@ bool gfxFont::SplitAndInitTextRun( DrawTarget* aDrawTarget, gfxTextRun* aTextRun, const T* aString, // text for this font run 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) { return true; } @@ -3099,8 +3103,8 @@ bool gfxFont::SplitAndInitTextRun( if (aRunLength > wordCacheCharLimit || HasSpaces(aString, aRunLength)) { TEXT_PERF_INCR(tp, wordCacheSpaceRules); return ShapeTextWithoutWordCache(aDrawTarget, aString, aRunStart, - aRunLength, aRunScript, vertical, - rounding, aTextRun); + aRunLength, aRunScript, aLanguage, + vertical, rounding, aTextRun); } } @@ -3149,7 +3153,7 @@ bool gfxFont::SplitAndInitTextRun( TEXT_PERF_INCR(tp, wordCacheLong); bool ok = ShapeFragmentWithoutWordCache( aDrawTarget, aString + wordStart, aRunStart + wordStart, length, - aRunScript, vertical, rounding, aTextRun); + aRunScript, aLanguage, vertical, rounding, aTextRun); if (!ok) { return false; } @@ -3164,8 +3168,8 @@ bool gfxFont::SplitAndInitTextRun( } } gfxShapedWord* sw = GetShapedWord( - aDrawTarget, aString + wordStart, length, hash, aRunScript, vertical, - appUnitsPerDevUnit, wordFlags, rounding, tp); + aDrawTarget, aString + wordStart, length, hash, aRunScript, aLanguage, + vertical, appUnitsPerDevUnit, wordFlags, rounding, tp); if (sw) { aTextRun->CopyGlyphDataFrom(sw, aRunStart + wordStart); } else { @@ -3188,7 +3192,7 @@ bool gfxFont::SplitAndInitTextRun( NS_ASSERTION(boundary16 < 256, "unexpected boundary!"); gfxShapedWord* sw = GetShapedWord( aDrawTarget, &boundary, 1, gfxShapedWord::HashMix(0, boundary), - aRunScript, vertical, appUnitsPerDevUnit, + aRunScript, aLanguage, vertical, appUnitsPerDevUnit, flags | gfx::ShapedTextFlags::TEXT_IS_8BIT, rounding, tp); if (sw) { aTextRun->CopyGlyphDataFrom(sw, aRunStart + i); @@ -3225,8 +3229,8 @@ bool gfxFont::SplitAndInitTextRun( gfx::ShapedTextFlags::TEXT_HIDE_CONTROL_CHARACTERS)) { if (GetFontEntry()->IsUserFont() && HasCharacter(ch)) { ShapeFragmentWithoutWordCache(aDrawTarget, aString + i, aRunStart + i, - 1, aRunScript, vertical, rounding, - aTextRun); + 1, aRunScript, aLanguage, vertical, + rounding, aTextRun); } else { aTextRun->SetMissingGlyph(aRunStart + i, ch, this); } @@ -3244,11 +3248,11 @@ bool gfxFont::SplitAndInitTextRun( template bool gfxFont::SplitAndInitTextRun( DrawTarget* aDrawTarget, gfxTextRun* aTextRun, const uint8_t* aString, uint32_t aRunStart, uint32_t aRunLength, Script aRunScript, - ShapedTextFlags aOrientation); + nsAtom* aLanguage, ShapedTextFlags aOrientation); template bool gfxFont::SplitAndInitTextRun( DrawTarget* aDrawTarget, gfxTextRun* aTextRun, const char16_t* aString, uint32_t aRunStart, uint32_t aRunLength, Script aRunScript, - ShapedTextFlags aOrientation); + nsAtom* aLanguage, ShapedTextFlags aOrientation); template <> bool gfxFont::InitFakeSmallCapsRun(DrawTarget* aDrawTarget, @@ -3256,8 +3260,8 @@ bool gfxFont::InitFakeSmallCapsRun(DrawTarget* aDrawTarget, uint32_t aOffset, uint32_t aLength, FontMatchType aMatchType, gfx::ShapedTextFlags aOrientation, - Script aScript, bool aSyntheticLower, - bool aSyntheticUpper) { + Script aScript, nsAtom* aLanguage, + bool aSyntheticLower, bool aSyntheticUpper) { bool ok = true; RefPtr smallCapsFont = GetSmallCapsFont(); @@ -3297,7 +3301,7 @@ bool gfxFont::InitFakeSmallCapsRun(DrawTarget* aDrawTarget, } else if (ch != ToLowerCase(ch)) { // ch is upper case 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 // the GreekUpperCase mapping - this catches accented // capitals where the accent is to be removed (bug 307039). @@ -3330,7 +3334,7 @@ bool gfxFont::InitFakeSmallCapsRun(DrawTarget* aDrawTarget, aOrientation, isCJK); if (!f->SplitAndInitTextRun(aDrawTarget, aTextRun, aText + runStart, aOffset + runStart, runLength, aScript, - aOrientation)) { + aLanguage, aOrientation)) { ok = false; } break; @@ -3349,9 +3353,8 @@ bool gfxFont::InitFakeSmallCapsRun(DrawTarget* aDrawTarget, bool mergeNeeded = nsCaseTransformTextRunFactory::TransformString( origString, convertedString, /* aAllUppercase = */ true, - /* aCaseTransformsOnly = */ false, - mStyle.explicitLanguage ? mStyle.language.get() : nullptr, - charsToMergeArray, deletedCharsArray); + /* aCaseTransformsOnly = */ false, aLanguage, charsToMergeArray, + deletedCharsArray); if (mergeNeeded) { // This is the hard case: the transformation caused chars @@ -3365,9 +3368,10 @@ bool gfxFont::InitFakeSmallCapsRun(DrawTarget* aDrawTarget, ¶ms, convertedString.Length(), aTextRun->GetFontGroup(), gfx::ShapedTextFlags(), nsTextFrameUtils::Flags())); tempRun->AddGlyphRun(f, aMatchType, 0, true, aOrientation, isCJK); - if (!f->SplitAndInitTextRun( - aDrawTarget, tempRun.get(), convertedString.BeginReading(), - 0, convertedString.Length(), aScript, aOrientation)) { + if (!f->SplitAndInitTextRun(aDrawTarget, tempRun.get(), + convertedString.BeginReading(), 0, + convertedString.Length(), aScript, + aLanguage, aOrientation)) { ok = false; } else { RefPtr mergedRun(gfxTextRun::Create( @@ -3383,9 +3387,10 @@ bool gfxFont::InitFakeSmallCapsRun(DrawTarget* aDrawTarget, } else { aTextRun->AddGlyphRun(f, aMatchType, aOffset + runStart, true, aOrientation, isCJK); - if (!f->SplitAndInitTextRun( - aDrawTarget, aTextRun, convertedString.BeginReading(), - aOffset + runStart, runLength, aScript, aOrientation)) { + if (!f->SplitAndInitTextRun(aDrawTarget, aTextRun, + convertedString.BeginReading(), + aOffset + runStart, runLength, aScript, + aLanguage, aOrientation)) { ok = false; } } @@ -3410,14 +3415,14 @@ bool gfxFont::InitFakeSmallCapsRun(DrawTarget* aDrawTarget, uint32_t aOffset, uint32_t aLength, FontMatchType aMatchType, gfx::ShapedTextFlags aOrientation, - Script aScript, bool aSyntheticLower, - bool aSyntheticUpper) { + Script aScript, nsAtom* aLanguage, + bool aSyntheticLower, bool aSyntheticUpper) { NS_ConvertASCIItoUTF16 unicodeString(reinterpret_cast(aText), aLength); - return InitFakeSmallCapsRun(aDrawTarget, aTextRun, - static_cast(unicodeString.get()), - aOffset, aLength, aMatchType, aOrientation, - aScript, aSyntheticLower, aSyntheticUpper); + return InitFakeSmallCapsRun( + aDrawTarget, aTextRun, static_cast(unicodeString.get()), + aOffset, aLength, aMatchType, aOrientation, aScript, aLanguage, + aSyntheticLower, aSyntheticUpper); } gfxFont* gfxFont::GetSmallCapsFont() { @@ -3968,8 +3973,7 @@ void gfxFont::RemoveGlyphChangeObserver(GlyphChangeObserver* aObserver) { #define DEFAULT_PIXEL_FONT_SIZE 16.0f gfxFontStyle::gfxFontStyle() - : language(nsGkAtoms::x_western), - size(DEFAULT_PIXEL_FONT_SIZE), + : size(DEFAULT_PIXEL_FONT_SIZE), sizeAdjust(-1.0f), baselineOffset(0.0f), languageOverride(NO_FONT_LANGUAGE_OVERRIDE), @@ -3984,18 +3988,15 @@ gfxFontStyle::gfxFontStyle() useGrayscaleAntialiasing(false), allowSyntheticWeight(true), allowSyntheticStyle(true), - noFallbackVariantFeatures(true), - explicitLanguage(false) {} + noFallbackVariantFeatures(true) {} gfxFontStyle::gfxFontStyle(FontSlantStyle aStyle, FontWeight aWeight, FontStretch aStretch, gfxFloat aSize, - nsAtom* aLanguage, bool aExplicitLanguage, float aSizeAdjust, bool aSystemFont, bool aPrinterFont, bool aAllowWeightSynthesis, bool aAllowStyleSynthesis, uint32_t aLanguageOverride) - : language(aLanguage), - size(aSize), + : size(aSize), sizeAdjust(aSizeAdjust), baselineOffset(0.0f), languageOverride(aLanguageOverride), @@ -4010,8 +4011,7 @@ gfxFontStyle::gfxFontStyle(FontSlantStyle aStyle, FontWeight aWeight, useGrayscaleAntialiasing(false), allowSyntheticWeight(aAllowWeightSynthesis), allowSyntheticStyle(aAllowStyleSynthesis), - noFallbackVariantFeatures(true), - explicitLanguage(aExplicitLanguage) { + noFallbackVariantFeatures(true) { MOZ_ASSERT(!mozilla::IsNaN(size)); MOZ_ASSERT(!mozilla::IsNaN(sizeAdjust)); @@ -4029,11 +4029,6 @@ gfxFontStyle::gfxFontStyle(FontSlantStyle aStyle, FontWeight aWeight, NS_WARNING("negative font size"); size = 0.0; } - - if (!language) { - NS_WARNING("null language"); - language = nsGkAtoms::x_western; - } } PLDHashNumber gfxFontStyle::Hash() const { @@ -4044,8 +4039,7 @@ PLDHashNumber gfxFontStyle::Hash() const { sizeof(gfxFontVariation)); return mozilla::AddToHash(hash, systemFont, style.ForHash(), stretch.ForHash(), weight.ForHash(), size, - int32_t(sizeAdjust * 1000.0f), - nsRefPtrHashKey::HashKey(language)); + int32_t(sizeAdjust * 1000.0f)); } void gfxFontStyle::AdjustForSubSuperscript(int32_t aAppUnitsPerDevPixel) { diff --git a/gfx/thebes/gfxFont.h b/gfx/thebes/gfxFont.h index 526bd7e700f4..636883e8a4ee 100644 --- a/gfx/thebes/gfxFont.h +++ b/gfx/thebes/gfxFont.h @@ -79,16 +79,9 @@ struct gfxFontStyle { gfxFontStyle(); gfxFontStyle(FontSlantStyle aStyle, FontWeight aWeight, FontStretch aStretch, - gfxFloat aSize, nsAtom* aLanguage, bool aExplicitLanguage, - float aSizeAdjust, bool aSystemFont, bool aPrinterFont, - bool aWeightSynthesis, bool aStyleSynthesis, + gfxFloat aSize, float aSizeAdjust, bool aSystemFont, + bool aPrinterFont, bool aWeightSynthesis, bool aStyleSynthesis, 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 language; - // Features are composed of (1) features from style rules (2) features // from feature settings rules and (3) family-specific features. (1) and // (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 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. // Not meant to be called when sizeAdjust = -1.0. gfxFloat GetAdjustedSize(gfxFloat aspect) const { @@ -219,8 +208,6 @@ struct gfxFontStyle { (systemFont == other.systemFont) && (printerFont == other.printerFont) && (useGrayscaleAntialiasing == other.useGrayscaleAntialiasing) && - (explicitLanguage == other.explicitLanguage) && - (language == other.language) && (baselineOffset == other.baselineOffset) && (*reinterpret_cast(&sizeAdjust) == *reinterpret_cast(&other.sizeAdjust)) && @@ -641,6 +628,9 @@ class gfxFontShaper { // aShapedText to be updated; aLength is also the length of aText. virtual bool ShapeText(DrawTarget* aDrawTarget, const char16_t* aText, 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, gfxShapedText* aShapedText) = 0; @@ -1224,7 +1214,8 @@ class gfxShapedWord final : public gfxShapedText { // glyph data; the caller must call gfxFont::ShapeText() with appropriate // parameters to set up the glyphs. 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, gfxFontShaper::RoundingFlags aRounding) { NS_ASSERTION(aLength <= gfxPlatform::GetPlatform()->WordCacheCharLimit(), @@ -1240,12 +1231,13 @@ class gfxShapedWord final : public gfxShapedText { } // 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); } 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, gfxFontShaper::RoundingFlags aRounding) { NS_ASSERTION(aLength <= gfxPlatform::GetPlatform()->WordCacheCharLimit(), @@ -1258,7 +1250,8 @@ class gfxShapedWord final : public gfxShapedText { nsAutoCString narrowText; LossyAppendUTF16toASCII(nsDependentSubstring(aText, aLength), narrowText); return Create((const uint8_t*)(narrowText.BeginReading()), aLength, - aRunScript, aAppUnitsPerDevUnit, aFlags, aRounding); + aRunScript, aLanguage, aAppUnitsPerDevUnit, aFlags, + aRounding); } uint32_t size = offsetof(gfxShapedWord, mCharGlyphsStorage) + @@ -1268,7 +1261,7 @@ class gfxShapedWord final : public gfxShapedText { return nullptr; } - return new (storage) gfxShapedWord(aText, aLength, aRunScript, + return new (storage) gfxShapedWord(aText, aLength, aRunScript, aLanguage, aAppUnitsPerDevUnit, aFlags, aRounding); } @@ -1300,6 +1293,7 @@ class gfxShapedWord final : public gfxShapedText { } Script GetScript() const { return mScript; } + nsAtom* GetLanguage() const { return mLanguage.get(); } 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 gfxShapedWord(const uint8_t* aText, uint32_t aLength, Script aRunScript, - uint16_t aAppUnitsPerDevUnit, + nsAtom* aLanguage, uint16_t aAppUnitsPerDevUnit, mozilla::gfx::ShapedTextFlags aFlags, gfxFontShaper::RoundingFlags aRounding) : gfxShapedText(aLength, aFlags | mozilla::gfx::ShapedTextFlags::TEXT_IS_8BIT, aAppUnitsPerDevUnit), + mLanguage(aLanguage), mScript(aRunScript), mRounding(aRounding), mAgeCounter(0) { @@ -1332,10 +1327,11 @@ class gfxShapedWord final : public gfxShapedText { } gfxShapedWord(const char16_t* aText, uint32_t aLength, Script aRunScript, - uint16_t aAppUnitsPerDevUnit, + nsAtom* aLanguage, uint16_t aAppUnitsPerDevUnit, mozilla::gfx::ShapedTextFlags aFlags, gfxFontShaper::RoundingFlags aRounding) : gfxShapedText(aLength, aFlags, aAppUnitsPerDevUnit), + mLanguage(aLanguage), mScript(aRunScript), mRounding(aRounding), mAgeCounter(0) { @@ -1345,6 +1341,7 @@ class gfxShapedWord final : public gfxShapedText { SetupClusterBoundaries(0, aText, aLength); } + RefPtr mLanguage; Script mScript; gfxFontShaper::RoundingFlags mRounding; @@ -1755,8 +1752,8 @@ class gfxFont { const T* aText, uint32_t aOffset, uint32_t aLength, FontMatchType aMatchType, mozilla::gfx::ShapedTextFlags aOrientation, - Script aScript, bool aSyntheticLower, - bool aSyntheticUpper); + Script aScript, nsAtom* aLanguage, + bool aSyntheticLower, bool aSyntheticUpper); // call the (virtual) InitTextRun method to do glyph generation/shaping, // limiting the length of text passed by processing the run in multiple @@ -1765,6 +1762,7 @@ class gfxFont { bool SplitAndInitTextRun(DrawTarget* aDrawTarget, gfxTextRun* aTextRun, const T* aString, uint32_t aRunStart, uint32_t aRunLength, Script aRunScript, + nsAtom* aLanguage, mozilla::gfx::ShapedTextFlags aOrientation); // Get a ShapedWord representing the given text (either 8- or 16-bit) @@ -1772,8 +1770,8 @@ class gfxFont { template gfxShapedWord* GetShapedWord(DrawTarget* aDrawTarget, const T* aText, uint32_t aLength, uint32_t aHash, - Script aRunScript, bool aVertical, - int32_t aAppUnitsPerDevUnit, + Script aRunScript, nsAtom* aLanguage, + bool aVertical, int32_t aAppUnitsPerDevUnit, mozilla::gfx::ShapedTextFlags aFlags, RoundingFlags aRounding, gfxTextPerfMetrics* aTextPerf); @@ -1961,16 +1959,16 @@ class gfxFont { // For 8-bit text, expand to 16-bit and then call the following method. bool ShapeText(DrawTarget* aContext, const uint8_t* aText, uint32_t aOffset, // dest offset in gfxShapedText - uint32_t aLength, Script aScript, bool aVertical, - RoundingFlags aRounding, + uint32_t aLength, Script aScript, nsAtom* aLanguage, + bool aVertical, RoundingFlags aRounding, gfxShapedText* aShapedText); // where to store the result // Call the appropriate shaper to generate glyphs for aText and store // them into aShapedText. virtual bool ShapeText(DrawTarget* aContext, const char16_t* aText, uint32_t aOffset, uint32_t aLength, Script aScript, - bool aVertical, RoundingFlags aRounding, - gfxShapedText* aShapedText); + nsAtom* aLanguage, bool aVertical, + RoundingFlags aRounding, gfxShapedText* aShapedText); // Helper to adjust for synthetic bold and set character-type flags // in the shaped text; implementations of ShapeText should call this @@ -1990,8 +1988,9 @@ class gfxFont { template bool ShapeTextWithoutWordCache(DrawTarget* aDrawTarget, const T* aText, uint32_t aOffset, uint32_t aLength, - Script aScript, bool aVertical, - RoundingFlags aRounding, gfxTextRun* aTextRun); + Script aScript, nsAtom* aLanguage, + bool aVertical, RoundingFlags aRounding, + gfxTextRun* aTextRun); // Shape a fragment of text (a run that is known to contain only // "valid" characters, no newlines/tabs/other control chars). @@ -2001,8 +2000,8 @@ class gfxFont { template bool ShapeFragmentWithoutWordCache(DrawTarget* aDrawTarget, const T* aText, uint32_t aOffset, uint32_t aLength, - Script aScript, bool aVertical, - RoundingFlags aRounding, + Script aScript, nsAtom* aLanguage, + bool aVertical, RoundingFlags aRounding, gfxTextRun* aTextRun); void CheckForFeaturesInvolvingSpace(); @@ -2025,21 +2024,24 @@ class gfxFont { uint32_t mLength; mozilla::gfx::ShapedTextFlags mFlags; Script mScript; + RefPtr mLanguage; int32_t mAppUnitsPerDevUnit; PLDHashNumber mHashKey; bool mTextIs8Bit; RoundingFlags mRounding; 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) : mLength(aLength), mFlags(aFlags), mScript(aScriptCode), + mLanguage(aLanguage), mAppUnitsPerDevUnit(aAppUnitsPerDevUnit), mHashKey(aStringHash + static_cast(aScriptCode) + aAppUnitsPerDevUnit * 0x100 + uint16_t(aFlags) * 0x10000 + - int(aRounding)), + int(aRounding) + (aLanguage ? aLanguage->hash() : 0)), mTextIs8Bit(true), mRounding(aRounding) { 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, - Script aScriptCode, int32_t aAppUnitsPerDevUnit, + Script aScriptCode, nsAtom* aLanguage, + int32_t aAppUnitsPerDevUnit, mozilla::gfx::ShapedTextFlags aFlags, RoundingFlags aRounding) : mLength(aLength), mFlags(aFlags), mScript(aScriptCode), + mLanguage(aLanguage), mAppUnitsPerDevUnit(aAppUnitsPerDevUnit), mHashKey(aStringHash + static_cast(aScriptCode) + aAppUnitsPerDevUnit * 0x100 + uint16_t(aFlags) * 0x10000 + diff --git a/gfx/thebes/gfxGDIFont.cpp b/gfx/thebes/gfxGDIFont.cpp index 809b91c6ffc9..4d6574cadbbf 100644 --- a/gfx/thebes/gfxGDIFont.cpp +++ b/gfx/thebes/gfxGDIFont.cpp @@ -59,7 +59,8 @@ UniquePtr gfxGDIFont::CopyWithAntialiasOption( bool gfxGDIFont::ShapeText(DrawTarget* aDrawTarget, const char16_t* aText, uint32_t aOffset, uint32_t aLength, Script aScript, - bool aVertical, RoundingFlags aRounding, + nsAtom* aLanguage, bool aVertical, + RoundingFlags aRounding, gfxShapedText* aShapedText) { if (!mIsValid) { 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, - aVertical, aRounding, aShapedText); + aLanguage, aVertical, aRounding, aShapedText); } const gfxFont::Metrics& gfxGDIFont::GetHorizontalMetrics() { return *mMetrics; } diff --git a/gfx/thebes/gfxGDIFont.h b/gfx/thebes/gfxGDIFont.h index 0bffb091ef4b..b5ccb8940f23 100644 --- a/gfx/thebes/gfxGDIFont.h +++ b/gfx/thebes/gfxGDIFont.h @@ -61,10 +61,9 @@ class gfxGDIFont : public gfxFont { protected: const Metrics& GetHorizontalMetrics() override; - /* override to ensure the cairo font is set up properly */ bool ShapeText(DrawTarget* aDrawTarget, const char16_t* aText, uint32_t aOffset, uint32_t aLength, Script aScript, - bool aVertical, RoundingFlags aRounding, + nsAtom* aLanguage, bool aVertical, RoundingFlags aRounding, gfxShapedText* aShapedText) override; void Initialize(); // creates metrics and Cairo fonts diff --git a/gfx/thebes/gfxGDIFontList.cpp b/gfx/thebes/gfxGDIFontList.cpp index 89b114d19e2d..b5ff31abd665 100644 --- a/gfx/thebes/gfxGDIFontList.cpp +++ b/gfx/thebes/gfxGDIFontList.cpp @@ -826,7 +826,7 @@ bool gfxGDIFontList::FindAndAddFamilies(StyleGenericFontFamily aGeneric, const nsACString& aFamily, nsTArray* aOutput, FindFamiliesFlags aFlags, - gfxFontStyle* aStyle, + gfxFontStyle* aStyle, nsAtom* aLanguage, gfxFloat aDevToCssSize) { NS_ConvertUTF8toUTF16 key16(aFamily); BuildKeyNameFromFontName(key16); @@ -842,12 +842,12 @@ bool gfxGDIFontList::FindAndAddFamilies(StyleGenericFontFamily aGeneric, return false; } - return gfxPlatformFontList::FindAndAddFamilies(aGeneric, aFamily, aOutput, - aFlags, aStyle, aDevToCssSize); + return gfxPlatformFontList::FindAndAddFamilies( + aGeneric, aFamily, aOutput, aFlags, aStyle, aLanguage, aDevToCssSize); } -FontFamily gfxGDIFontList::GetDefaultFontForPlatform( - const gfxFontStyle* aStyle) { +FontFamily gfxGDIFontList::GetDefaultFontForPlatform(const gfxFontStyle* aStyle, + nsAtom* aLanguage) { FontFamily ff; // this really shouldn't fail to find a font.... diff --git a/gfx/thebes/gfxGDIFontList.h b/gfx/thebes/gfxGDIFontList.h index ff015093cf1f..70a2357e173f 100644 --- a/gfx/thebes/gfxGDIFontList.h +++ b/gfx/thebes/gfxGDIFontList.h @@ -308,6 +308,7 @@ class gfxGDIFontList final : public gfxPlatformFontList { nsTArray* aOutput, FindFamiliesFlags aFlags, gfxFontStyle* aStyle = nullptr, + nsAtom* aLanguage = nullptr, gfxFloat aDevToCssSize = 1.0) override; virtual gfxFontEntry* LookupLocalFont(const nsACString& aFontName, @@ -328,7 +329,8 @@ class gfxGDIFontList final : public gfxPlatformFontList { FontListSizes* aSizes) const; protected: - FontFamily GetDefaultFontForPlatform(const gfxFontStyle* aStyle) override; + FontFamily GetDefaultFontForPlatform(const gfxFontStyle* aStyle, + nsAtom* aLanguage = nullptr) override; private: friend class gfxWindowsPlatform; diff --git a/gfx/thebes/gfxGraphiteShaper.cpp b/gfx/thebes/gfxGraphiteShaper.cpp index c5ce613f8f0e..45996fff2dab 100644 --- a/gfx/thebes/gfxGraphiteShaper.cpp +++ b/gfx/thebes/gfxGraphiteShaper.cpp @@ -131,7 +131,8 @@ static inline size_t CountUnicodes(const char16_t* aText, uint32_t aLength) { bool gfxGraphiteShaper::ShapeText(DrawTarget* aDrawTarget, const char16_t* aText, uint32_t aOffset, uint32_t aLength, Script aScript, - bool aVertical, RoundingFlags aRounding, + nsAtom* aLanguage, bool aVertical, + RoundingFlags aRounding, gfxShapedText* aShapedText) { const gfxFontStyle* style = mFont->GetStyle(); auto t_mGrFace = rlbox::from_opaque(mGrFace); @@ -191,9 +192,9 @@ bool gfxGraphiteShaper::ShapeText(DrawTarget* aDrawTarget, grLang = MakeGraphiteLangTag(style->languageOverride); } else if (entry->mLanguageOverride) { grLang = MakeGraphiteLangTag(entry->mLanguageOverride); - } else if (style->explicitLanguage) { + } else if (aLanguage) { nsAutoCString langString; - style->language->ToUTF8String(langString); + aLanguage->ToUTF8String(langString); grLang = GetGraphiteTagForLang(langString); } tainted_gr grFeatures = diff --git a/gfx/thebes/gfxGraphiteShaper.h b/gfx/thebes/gfxGraphiteShaper.h index e2951119dcc7..fc61ac10df38 100644 --- a/gfx/thebes/gfxGraphiteShaper.h +++ b/gfx/thebes/gfxGraphiteShaper.h @@ -23,7 +23,7 @@ class gfxGraphiteShaper : public gfxFontShaper { bool ShapeText(DrawTarget* aDrawTarget, const char16_t* aText, uint32_t aOffset, uint32_t aLength, Script aScript, - bool aVertical, RoundingFlags aRounding, + nsAtom* aLanguage, bool aVertical, RoundingFlags aRounding, gfxShapedText* aShapedText) override; static void Shutdown(); diff --git a/gfx/thebes/gfxHarfBuzzShaper.cpp b/gfx/thebes/gfxHarfBuzzShaper.cpp index ff64c39fd902..8153613896ea 100644 --- a/gfx/thebes/gfxHarfBuzzShaper.cpp +++ b/gfx/thebes/gfxHarfBuzzShaper.cpp @@ -1355,7 +1355,8 @@ void gfxHarfBuzzShaper::InitializeVertical() { bool gfxHarfBuzzShaper::ShapeText(DrawTarget* aDrawTarget, const char16_t* aText, uint32_t aOffset, uint32_t aLength, Script aScript, - bool aVertical, RoundingFlags aRounding, + nsAtom* aLanguage, bool aVertical, + RoundingFlags aRounding, gfxShapedText* aShapedText) { mUseVerticalPresentationForms = false; @@ -1415,9 +1416,9 @@ bool gfxHarfBuzzShaper::ShapeText(DrawTarget* aDrawTarget, language = hb_ot_tag_to_language(style->languageOverride); } else if (entry->mLanguageOverride) { language = hb_ot_tag_to_language(entry->mLanguageOverride); - } else if (style->explicitLanguage) { + } else if (aLanguage) { nsCString langString; - style->language->ToUTF8String(langString); + aLanguage->ToUTF8String(langString); language = hb_language_from_string(langString.get(), langString.Length()); } else { language = hb_ot_tag_to_language(HB_OT_TAG_DEFAULT_LANGUAGE); diff --git a/gfx/thebes/gfxHarfBuzzShaper.h b/gfx/thebes/gfxHarfBuzzShaper.h index a5701c8541d9..31c879b052d8 100644 --- a/gfx/thebes/gfxHarfBuzzShaper.h +++ b/gfx/thebes/gfxHarfBuzzShaper.h @@ -29,7 +29,7 @@ class gfxHarfBuzzShaper : public gfxFontShaper { bool ShapeText(DrawTarget* aDrawTarget, const char16_t* aText, uint32_t aOffset, uint32_t aLength, Script aScript, - bool aVertical, RoundingFlags aRounding, + nsAtom* aLanguage, bool aVertical, RoundingFlags aRounding, gfxShapedText* aShapedText) override; // get a given font table in harfbuzz blob form diff --git a/gfx/thebes/gfxMacFont.cpp b/gfx/thebes/gfxMacFont.cpp index 0e8ff1cf6d5a..8780030a60e1 100644 --- a/gfx/thebes/gfxMacFont.cpp +++ b/gfx/thebes/gfxMacFont.cpp @@ -142,7 +142,8 @@ gfxMacFont::~gfxMacFont() { bool gfxMacFont::ShapeText(DrawTarget* aDrawTarget, const char16_t* aText, uint32_t aOffset, uint32_t aLength, Script aScript, - bool aVertical, RoundingFlags aRounding, + nsAtom* aLanguage, bool aVertical, + RoundingFlags aRounding, gfxShapedText* aShapedText) { if (!mIsValid) { NS_WARNING("invalid font! expect incorrect text rendering"); @@ -158,7 +159,7 @@ bool gfxMacFont::ShapeText(DrawTarget* aDrawTarget, const char16_t* aText, mCoreTextShaper = MakeUnique(this); } if (mCoreTextShaper->ShapeText(aDrawTarget, aText, aOffset, aLength, - aScript, aVertical, aRounding, + aScript, aLanguage, aVertical, aRounding, aShapedText)) { PostShapingFixup(aDrawTarget, aText, aOffset, aLength, aVertical, aShapedText); @@ -181,7 +182,7 @@ bool gfxMacFont::ShapeText(DrawTarget* aDrawTarget, const char16_t* aText, } return gfxFont::ShapeText(aDrawTarget, aText, aOffset, aLength, aScript, - aVertical, aRounding, aShapedText); + aLanguage, aVertical, aRounding, aShapedText); } gfxFont::RunMetrics gfxMacFont::Measure(const gfxTextRun* aTextRun, diff --git a/gfx/thebes/gfxMacFont.h b/gfx/thebes/gfxMacFont.h index 038fd712e665..3d7157b95789 100644 --- a/gfx/thebes/gfxMacFont.h +++ b/gfx/thebes/gfxMacFont.h @@ -63,7 +63,7 @@ class gfxMacFont : public gfxFont { // 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, - Script aScript, bool aVertical, RoundingFlags aRounding, + Script aScript, nsAtom* aLanguage, bool aVertical, RoundingFlags aRounding, gfxShapedText* aShapedText) override; void InitMetrics(); diff --git a/gfx/thebes/gfxMacPlatformFontList.h b/gfx/thebes/gfxMacPlatformFontList.h index e4d9de17edea..302dc937b373 100644 --- a/gfx/thebes/gfxMacPlatformFontList.h +++ b/gfx/thebes/gfxMacPlatformFontList.h @@ -146,6 +146,7 @@ class gfxMacPlatformFontList final : public gfxPlatformFontList { nsTArray* aOutput, FindFamiliesFlags aFlags, gfxFontStyle* aStyle = nullptr, + nsAtom* aLanguage = nullptr, gfxFloat aDevToCssSize = 1.0) override; // lookup the system font for a particular system font type and set @@ -163,7 +164,8 @@ class gfxMacPlatformFontList final : public gfxPlatformFontList { void ReadSystemFontList(nsTArray* aList); protected: - FontFamily GetDefaultFontForPlatform(const gfxFontStyle* aStyle) override; + FontFamily GetDefaultFontForPlatform(const gfxFontStyle* aStyle, + nsAtom* aLanguage = nullptr) override; private: friend class gfxPlatformMac; diff --git a/gfx/thebes/gfxMacPlatformFontList.mm b/gfx/thebes/gfxMacPlatformFontList.mm index 912063458a9d..77806543430b 100644 --- a/gfx/thebes/gfxMacPlatformFontList.mm +++ b/gfx/thebes/gfxMacPlatformFontList.mm @@ -1215,7 +1215,7 @@ void gfxMacPlatformFontList::InitSystemFontNames() { if (mUseSizeSensitiveSystemFont) { NSFont* displaySys = [NSFont systemFontOfSize:128.0]; NSString* displayFamilyName = GetRealFamilyName(displaySys); - if ([displayFamilyName isEqualToString: textFamilyName]) { + if ([displayFamilyName isEqualToString:textFamilyName]) { mUseSizeSensitiveSystemFont = false; } else { nsCocoaUtils::GetStringForNSString(displayFamilyName, familyName); @@ -1374,7 +1374,8 @@ gfxFontEntry* gfxMacPlatformFontList::PlatformGlobalFontFallback(const uint32_t return fontEntry; } -FontFamily gfxMacPlatformFontList::GetDefaultFontForPlatform(const gfxFontStyle* aStyle) { +FontFamily gfxMacPlatformFontList::GetDefaultFontForPlatform(const gfxFontStyle* aStyle, + nsAtom* aLanguage) { nsAutoreleasePool localPool; NSString* defaultFamily = [[NSFont userFontOfSize:aStyle->size] familyName]; @@ -1459,7 +1460,7 @@ bool gfxMacPlatformFontList::FindAndAddFamilies(mozilla::StyleGenericFontFamily const nsACString& aFamily, nsTArray* aOutput, FindFamiliesFlags aFlags, gfxFontStyle* aStyle, - gfxFloat aDevToCssSize) { + nsAtom* aLanguage, gfxFloat aDevToCssSize) { if (aFamily.EqualsLiteral(kSystemFont_system)) { // 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 @@ -1467,12 +1468,13 @@ bool gfxMacPlatformFontList::FindAndAddFamilies(mozilla::StyleGenericFontFamily // this family. const nsCString& systemFontFamilyName = mUseSizeSensitiveSystemFont && aStyle && - (aStyle->size * aDevToCssSize) >= kTextDisplayCrossover - ? mSystemDisplayFontFamilyName : mSystemTextFontFamilyName; + (aStyle->size * aDevToCssSize) >= kTextDisplayCrossover + ? mSystemDisplayFontFamilyName + : mSystemTextFontFamilyName; if (SharedFontList() && !nsCocoaFeatures::OnCatalinaOrLater()) { FindFamiliesFlags flags = aFlags | FindFamiliesFlags::eSearchHiddenFamilies; - return gfxPlatformFontList::FindAndAddFamilies(aGeneric, systemFontFamilyName, aOutput, - flags, aStyle, aDevToCssSize); + return gfxPlatformFontList::FindAndAddFamilies(aGeneric, systemFontFamilyName, aOutput, flags, + aStyle, aLanguage, aDevToCssSize); } else { if (auto* fam = FindSystemFontFamily(systemFontFamilyName)) { aOutput->AppendElement(fam); @@ -1483,7 +1485,7 @@ bool gfxMacPlatformFontList::FindAndAddFamilies(mozilla::StyleGenericFontFamily } return gfxPlatformFontList::FindAndAddFamilies(aGeneric, aFamily, aOutput, aFlags, aStyle, - aDevToCssSize); + aLanguage, aDevToCssSize); } void gfxMacPlatformFontList::LookupSystemFont(LookAndFeel::FontID aSystemFontID, diff --git a/gfx/thebes/gfxPlatform.cpp b/gfx/thebes/gfxPlatform.cpp index f51f578f363c..c650b89ce224 100644 --- a/gfx/thebes/gfxPlatform.cpp +++ b/gfx/thebes/gfxPlatform.cpp @@ -1909,10 +1909,12 @@ bool gfxPlatform::IsFontFormatSupported(uint32_t aFormatFlags) { gfxFontGroup* gfxPlatform::CreateFontGroup( const FontFamilyList& aFontFamilyList, const gfxFontStyle* aStyle, - gfxTextPerfMetrics* aTextPerf, FontMatchingStats* aFontMatchingStats, - gfxUserFontSet* aUserFontSet, gfxFloat aDevToCssSize) const { - return new gfxFontGroup(aFontFamilyList, aStyle, aTextPerf, - aFontMatchingStats, aUserFontSet, aDevToCssSize); + nsAtom* aLanguage, bool aExplicitLanguage, gfxTextPerfMetrics* aTextPerf, + FontMatchingStats* aFontMatchingStats, gfxUserFontSet* aUserFontSet, + gfxFloat aDevToCssSize) const { + return new gfxFontGroup(aFontFamilyList, aStyle, aLanguage, aExplicitLanguage, + aTextPerf, aFontMatchingStats, aUserFontSet, + aDevToCssSize); } gfxFontEntry* gfxPlatform::LookupLocalFont(const nsACString& aFontName, diff --git a/gfx/thebes/gfxPlatform.h b/gfx/thebes/gfxPlatform.h index 5366a6a11f1b..3abf029880df 100644 --- a/gfx/thebes/gfxPlatform.h +++ b/gfx/thebes/gfxPlatform.h @@ -393,7 +393,8 @@ class gfxPlatform : public mozilla::layers::MemoryPressureListener { * Create a gfxFontGroup based on the given family list and style. */ gfxFontGroup* CreateFontGroup(const mozilla::FontFamilyList& aFontFamilyList, - const gfxFontStyle* aStyle, + const gfxFontStyle* aStyle, nsAtom* aLanguage, + bool aExplicitLanguage, gfxTextPerfMetrics* aTextPerf, FontMatchingStats* aFontMatchingStats, gfxUserFontSet* aUserFontSet, diff --git a/gfx/thebes/gfxPlatformFontList.cpp b/gfx/thebes/gfxPlatformFontList.cpp index aa32f9bb30c6..8ece85c44f93 100644 --- a/gfx/thebes/gfxPlatformFontList.cpp +++ b/gfx/thebes/gfxPlatformFontList.cpp @@ -1138,7 +1138,7 @@ gfxFontFamily* gfxPlatformFontList::CheckFamily(gfxFontFamily* aFamily) { bool gfxPlatformFontList::FindAndAddFamilies( StyleGenericFontFamily aGeneric, const nsACString& aFamily, nsTArray* aOutput, FindFamiliesFlags aFlags, - gfxFontStyle* aStyle, gfxFloat aDevToCssSize) { + gfxFontStyle* aStyle, nsAtom* aLanguage, gfxFloat aDevToCssSize) { nsAutoCString key; GenerateFontListKey(aFamily, key); @@ -1283,13 +1283,13 @@ bool gfxPlatformFontList::FindAndAddFamilies( fontlist::Family* gfxPlatformFontList::FindSharedFamily( const nsACString& aFamily, FindFamiliesFlags aFlags, gfxFontStyle* aStyle, - gfxFloat aDevToCss) { + nsAtom* aLanguage, gfxFloat aDevToCss) { if (!SharedFontList()) { return nullptr; } AutoTArray families; if (!FindAndAddFamilies(StyleGenericFontFamily::None, aFamily, &families, - aFlags, aStyle, aDevToCss) || + aFlags, aStyle, aLanguage, aDevToCss) || !families[0].mFamily.mIsShared) { return nullptr; } @@ -1595,12 +1595,9 @@ void gfxPlatformFontList::GetFontFamiliesFromGenericFamilies( PrefFontList* aGenericFamilies) { // lookup and add platform fonts uniquely for (const nsCString& genericFamily : aGenericNameFamilies) { - gfxFontStyle style; - style.language = aLangGroup; - style.systemFont = false; AutoTArray families; FindAndAddFamilies(aGenericType, genericFamily, &families, - FindFamiliesFlags(0), &style); + FindFamiliesFlags(0), nullptr, aLangGroup); for (const FamilyAndGeneric& f : families) { if (!aGenericFamilies->Contains(f.mFamily)) { aGenericFamilies->AppendElement(f.mFamily); diff --git a/gfx/thebes/gfxPlatformFontList.h b/gfx/thebes/gfxPlatformFontList.h index f27378c5f9ac..6e9de61f66b4 100644 --- a/gfx/thebes/gfxPlatformFontList.h +++ b/gfx/thebes/gfxPlatformFontList.h @@ -253,6 +253,7 @@ class gfxPlatformFontList : public gfxFontInfoLoader { nsTArray* aOutput, FindFamiliesFlags aFlags, gfxFontStyle* aStyle = nullptr, + nsAtom* aLanguage = nullptr, gfxFloat aDevToCssSize = 1.0); gfxFontEntry* FindFontForFamily(const nsACString& aFamily, @@ -585,18 +586,21 @@ class gfxPlatformFontList : public gfxFontInfoLoader { mozilla::fontlist::Family* FindSharedFamily( const nsACString& aFamily, FindFamiliesFlags aFlags = FindFamiliesFlags(0), - gfxFontStyle* aStyle = nullptr, gfxFloat aDevToCssSize = 1.0); + gfxFontStyle* aStyle = nullptr, nsAtom* aLanguage = nullptr, + gfxFloat aDevToCssSize = 1.0); gfxFontFamily* FindUnsharedFamily( const nsACString& aFamily, FindFamiliesFlags aFlags = FindFamiliesFlags(0), - gfxFontStyle* aStyle = nullptr, gfxFloat aDevToCssSize = 1.0) { + gfxFontStyle* aStyle = nullptr, nsAtom* aLanguage = nullptr, + gfxFloat aDevToCssSize = 1.0) { if (SharedFontList()) { return nullptr; } AutoTArray families; if (FindAndAddFamilies(mozilla::StyleGenericFontFamily::None, aFamily, - &families, aFlags, aStyle, aDevToCssSize)) { + &families, aFlags, aStyle, aLanguage, + aDevToCssSize)) { return families[0].mFamily.mUnshared; } return nullptr; @@ -605,13 +609,14 @@ class gfxPlatformFontList : public gfxFontInfoLoader { FontFamily FindFamily(const nsACString& aFamily, FindFamiliesFlags aFlags = FindFamiliesFlags(0), gfxFontStyle* aStyle = nullptr, + nsAtom* aLanguage = nullptr, gfxFloat aDevToCssSize = 1.0) { if (SharedFontList()) { return FontFamily( - FindSharedFamily(aFamily, aFlags, aStyle, aDevToCssSize)); + FindSharedFamily(aFamily, aFlags, aStyle, aLanguage, aDevToCssSize)); } return FontFamily( - FindUnsharedFamily(aFamily, aFlags, aStyle, aDevToCssSize)); + FindUnsharedFamily(aFamily, aFlags, aStyle, aLanguage, aDevToCssSize)); } // Lookup family name in global family list without substitutions or @@ -766,7 +771,8 @@ class gfxPlatformFontList : public gfxFontInfoLoader { const FontEntryTable& aTable, mozilla::MallocSizeOf aMallocSizeOf); // Platform-specific helper for GetDefaultFont(...). - virtual FontFamily GetDefaultFontForPlatform(const gfxFontStyle* aStyle) = 0; + virtual FontFamily GetDefaultFontForPlatform(const gfxFontStyle* aStyle, + nsAtom* aLanguage = nullptr) = 0; // Protects mFontFamilies. mozilla::Mutex mFontFamiliesMutex; diff --git a/gfx/thebes/gfxTextRun.cpp b/gfx/thebes/gfxTextRun.cpp index e3301e65d3d4..c78febd602d6 100644 --- a/gfx/thebes/gfxTextRun.cpp +++ b/gfx/thebes/gfxTextRun.cpp @@ -1546,7 +1546,8 @@ void gfxTextRun::SetSpaceGlyph(gfxFont* aFont, DrawTarget* aDrawTarget, aFont->GetRoundOffsetsToPixels(aDrawTarget); gfxShapedWord* sw = aFont->GetShapedWord( aDrawTarget, &space, 1, gfxShapedWord::HashMix(0, ' '), Script::LATIN, - vertical, mAppUnitsPerDevUnit, flags, roundingFlags, nullptr); + /* aLanguage = */ nullptr, vertical, mAppUnitsPerDevUnit, flags, + roundingFlags, nullptr); if (sw) { const GlyphRun* prevRun = TrailingGlyphRun(); bool isCJK = prevRun && prevRun->mFont == aFont && @@ -1733,8 +1734,10 @@ void gfxTextRun::Dump(FILE* out) { # undef APPEND_FLAGS # undef APPEND_FLAG - fprintf(out, "gfxTextRun@%p (length %u) [%s] [%s]\n", this, mLength, - flagsString.get(), flags2String.get()); + nsAutoCString lang; + 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; const GlyphRun* glyphRuns = GetGlyphRuns(&numGlyphRuns); @@ -1744,12 +1747,9 @@ void gfxTextRun::Dump(FILE* out) { const gfxFontStyle* style = font->GetStyle(); nsAutoString styleString; nsStyleUtil::AppendFontSlantStyle(style->style, styleString); - nsAutoCString lang; - style->language->ToUTF8String(lang); - fprintf(out, " [%d] offset=%d %s %f/%g/%s/%s\n", i, + fprintf(out, " [%d] offset=%d %s %f/%g/%s\n", i, glyphRuns[i].mCharacterOffset, font->GetName().get(), style->size, - style->weight.ToFloat(), NS_ConvertUTF16toUTF8(styleString).get(), - lang.get()); + style->weight.ToFloat(), NS_ConvertUTF16toUTF8(styleString).get()); } fprintf(out, " Glyphs:\n"); @@ -1828,12 +1828,14 @@ void gfxTextRun::Dump(FILE* out) { #endif gfxFontGroup::gfxFontGroup(const FontFamilyList& aFontFamilyList, - const gfxFontStyle* aStyle, + const gfxFontStyle* aStyle, nsAtom* aLanguage, + bool aExplicitLanguage, gfxTextPerfMetrics* aTextPerf, FontMatchingStats* aFontMatchingStats, gfxUserFontSet* aUserFontSet, gfxFloat aDevToCssSize) : mFamilyList(aFontFamilyList), mStyle(*aStyle), + mLanguage(aLanguage), mUnderlineOffset(UNDERLINE_OFFSET_NOT_SET), mHyphenWidth(-1), mDevToCssSize(aDevToCssSize), @@ -1841,9 +1843,10 @@ gfxFontGroup::gfxFontGroup(const FontFamilyList& aFontFamilyList, mTextPerf(aTextPerf), mFontMatchingStats(aFontMatchingStats), mLastPrefLang(eFontPrefLang_Western), - mPageLang(gfxPlatformFontList::GetFontPrefLangFor(aStyle->language)), + mPageLang(gfxPlatformFontList::GetFontPrefLangFor(aLanguage)), mLastPrefFirstFont(false), - mSkipDrawing(false) { + mSkipDrawing(false), + mExplicitLanguage(aExplicitLanguage) { // We don't use SetUserFontSet() here, as we want to unconditionally call // BuildFontList() rather than only do UpdateUserFonts() if it changed. mCurrGeneration = GetGeneration(); @@ -1869,7 +1872,7 @@ void gfxFontGroup::BuildFontList() { MOZ_ASSERT_UNREACHABLE("broken FontFamilyName, no atom!"); } } else { - pfl->AddGenericFonts(name.mGeneric, mStyle.language, fonts); + pfl->AddGenericFonts(name.mGeneric, mLanguage, fonts); if (mTextPerf) { mTextPerf->current.genericLookups++; } @@ -1913,8 +1916,7 @@ void gfxFontGroup::BuildFontList() { // if necessary, append default generic onto the end if (mFamilyList.GetDefaultFontType() != StyleGenericFontFamily::None && !mFamilyList.HasDefaultGeneric()) { - pfl->AddGenericFonts(mFamilyList.GetDefaultFontType(), mStyle.language, - fonts); + pfl->AddGenericFonts(mFamilyList.GetDefaultFontType(), mLanguage, fonts); if (mTextPerf) { mTextPerf->current.genericLookups++; } @@ -1953,7 +1955,7 @@ void gfxFontGroup::AddPlatformFont(const nsACString& aName, bool aQuotedName, StyleGenericFontFamily::None, aName, &aFamilyList, aQuotedName ? gfxPlatformFontList::FindFamiliesFlags::eQuotedFamilyName : gfxPlatformFontList::FindFamiliesFlags(0), - &mStyle, mDevToCssSize); + &mStyle, mLanguage.get(), mDevToCssSize); } void gfxFontGroup::AddFamilyToFontList(gfxFontFamily* aFamily, @@ -2541,7 +2543,7 @@ void gfxFontGroup::InitTextRun(DrawTarget* aDrawTarget, gfxTextRun* aTextRun, if (sizeof(T) == sizeof(uint8_t) && !transformedString) { if (MOZ_UNLIKELY(MOZ_LOG_TEST(log, LogLevel::Warning))) { nsAutoCString lang; - mStyle.language->ToUTF8String(lang); + mLanguage->ToUTF8String(lang); nsAutoCString families; mFamilyList.ToString(families); nsAutoCString str((const char*)aString, aLength); @@ -2588,7 +2590,7 @@ void gfxFontGroup::InitTextRun(DrawTarget* aDrawTarget, gfxTextRun* aTextRun, while (scriptRuns.Next(runStart, runLimit, runScript)) { if (MOZ_UNLIKELY(MOZ_LOG_TEST(log, LogLevel::Warning))) { nsAutoCString lang; - mStyle.language->ToUTF8String(lang); + mLanguage->ToUTF8String(lang); nsAutoCString families; mFamilyList.ToString(families); nsAutoString styleString; @@ -2708,7 +2710,7 @@ void gfxFontGroup::InitScriptRun(DrawTarget* aDrawTarget, gfxTextRun* aTextRun, (matchedLength > 0), range.orientation, isCJK); if (!matchedFont->SplitAndInitTextRun( aDrawTarget, aTextRun, aString + runStart, aOffset + runStart, - matchedLength, aRunScript, range.orientation)) { + matchedLength, aRunScript, mLanguage, range.orientation)) { // glyph layout failed! treat as missing glyphs matchedFont = nullptr; } @@ -2743,7 +2745,7 @@ void gfxFontGroup::InitScriptRun(DrawTarget* aDrawTarget, gfxTextRun* aTextRun, (matchedLength > 0), range.orientation, isCJK); if (!subSuperFont->SplitAndInitTextRun( aDrawTarget, aTextRun, aString + runStart, aOffset + runStart, - matchedLength, aRunScript, range.orientation)) { + matchedLength, aRunScript, mLanguage, range.orientation)) { // glyph layout failed! treat as missing glyphs matchedFont = nullptr; } @@ -2755,7 +2757,8 @@ void gfxFontGroup::InitScriptRun(DrawTarget* aDrawTarget, gfxTextRun* aTextRun, if (!matchedFont->InitFakeSmallCapsRun( aDrawTarget, aTextRun, aString + runStart, aOffset + runStart, matchedLength, range.matchType, range.orientation, aRunScript, - syntheticLower, syntheticUpper)) { + mExplicitLanguage ? mLanguage.get() : nullptr, syntheticLower, + syntheticUpper)) { matchedFont = nullptr; } } else { @@ -2777,7 +2780,7 @@ void gfxFontGroup::InitScriptRun(DrawTarget* aDrawTarget, gfxTextRun* aTextRun, (matchedLength > 0), range.orientation, isCJK); if (!matchedFont->SplitAndInitTextRun( aDrawTarget, aTextRun, aString + runStart, aOffset + runStart, - matchedLength, aRunScript, range.orientation)) { + matchedLength, aRunScript, mLanguage, range.orientation)) { // glyph layout failed! treat as missing glyphs matchedFont = nullptr; } @@ -3522,7 +3525,7 @@ void gfxFontGroup::ComputeRanges(nsTArray& aRanges, const T* aString, if (MOZ_UNLIKELY(MOZ_LOG_TEST(log, LogLevel::Debug))) { nsAutoCString lang; - mStyle.language->ToUTF8String(lang); + mLanguage->ToUTF8String(lang); nsAutoCString families; mFamilyList.ToString(families); diff --git a/gfx/thebes/gfxTextRun.h b/gfx/thebes/gfxTextRun.h index c8c702a01c0c..e5720b21e6f1 100644 --- a/gfx/thebes/gfxTextRun.h +++ b/gfx/thebes/gfxTextRun.h @@ -932,7 +932,8 @@ class gfxFontGroup final : public gfxTextRunFactory { Shutdown(); // platform must call this to release the languageAtomService gfxFontGroup(const mozilla::FontFamilyList& aFontFamilyList, - const gfxFontStyle* aStyle, gfxTextPerfMetrics* aTextPerf, + const gfxFontStyle* aStyle, nsAtom* aLanguage, + bool aExplicitLanguage, gfxTextPerfMetrics* aTextPerf, FontMatchingStats* aFontMatchingStats, gfxUserFontSet* aUserFontSet, gfxFloat aDevToCssSize); @@ -1092,6 +1093,8 @@ class gfxFontGroup final : public gfxTextRunFactory { } } + nsAtom* Language() const { return mLanguage.get(); } + protected: friend class mozilla::PostTraversalTask; @@ -1377,6 +1380,8 @@ class gfxFontGroup final : public gfxTextRunFactory { RefPtr mDefaultFont; gfxFontStyle mStyle; + RefPtr mLanguage; + gfxFloat mUnderlineOffset; gfxFloat mHyphenWidth; gfxFloat mDevToCssSize; @@ -1405,6 +1410,8 @@ class gfxFontGroup final : public gfxTextRunFactory { // download to complete (or fallback // timer to fire) + bool mExplicitLanguage; // Does mLanguage come from an explicit attribute? + uint32_t mFontListGeneration = 0; // platform font list generation for this // fontgroup