LCOV - code coverage report
Current view: top level - gfx/thebes - gfxFontEntry.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 51 937 5.4 %
Date: 2018-08-07 16:42:27 Functions: 0 0 -
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /* This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       5             : 
       6             : #include "gfxFontEntry.h"
       7             : 
       8             : #include "mozilla/DebugOnly.h"
       9             : #include "mozilla/FontPropertyTypes.h"
      10             : #include "mozilla/MathAlgorithms.h"
      11             : 
      12             : #include "mozilla/Logging.h"
      13             : 
      14             : #include "gfxTextRun.h"
      15             : #include "gfxPlatform.h"
      16             : #include "nsGkAtoms.h"
      17             : 
      18             : #include "gfxTypes.h"
      19             : #include "gfxContext.h"
      20             : #include "gfxFontConstants.h"
      21             : #include "gfxHarfBuzzShaper.h"
      22             : #include "gfxUserFontSet.h"
      23             : #include "gfxPlatformFontList.h"
      24             : #include "nsUnicodeProperties.h"
      25             : #include "nsMathUtils.h"
      26             : #include "nsBidiUtils.h"
      27             : #include "nsUnicodeRange.h"
      28             : #include "nsStyleConsts.h"
      29             : #include "mozilla/AppUnits.h"
      30             : #include "mozilla/FloatingPoint.h"
      31             : #include "mozilla/Likely.h"
      32             : #include "mozilla/MemoryReporting.h"
      33             : #include "mozilla/Preferences.h"
      34             : #include "mozilla/Services.h"
      35             : #include "mozilla/StaticPrefs.h"
      36             : #include "mozilla/Telemetry.h"
      37             : #include "gfxSVGGlyphs.h"
      38             : #include "gfx2DGlue.h"
      39             : 
      40             : #include "harfbuzz/hb.h"
      41             : #include "harfbuzz/hb-ot.h"
      42             : #include "graphite2/Font.h"
      43             : 
      44             : #include <algorithm>
      45             : 
      46             : using namespace mozilla;
      47             : using namespace mozilla::gfx;
      48             : using namespace mozilla::unicode;
      49             : using mozilla::services::GetObserverService;
      50             : 
      51             : void
      52           0 : gfxCharacterMap::NotifyReleased()
      53             : {
      54           0 :     gfxPlatformFontList *fontlist = gfxPlatformFontList::PlatformFontList();
      55           0 :     if (mShared) {
      56           0 :         fontlist->RemoveCmap(this);
      57             :     }
      58           0 :     delete this;
      59           0 : }
      60             : 
      61           0 : gfxFontEntry::gfxFontEntry() :
      62             :     mFixedPitch(false),
      63             :     mIsBadUnderlineFont(false),
      64             :     mIsUserFontContainer(false),
      65             :     mIsDataUserFont(false),
      66             :     mIsLocalUserFont(false),
      67             :     mStandardFace(false),
      68             :     mIgnoreGDEF(false),
      69             :     mIgnoreGSUB(false),
      70             :     mSVGInitialized(false),
      71             :     mHasSpaceFeaturesInitialized(false),
      72             :     mHasSpaceFeatures(false),
      73             :     mHasSpaceFeaturesKerning(false),
      74             :     mHasSpaceFeaturesNonKerning(false),
      75             :     mSkipDefaultFeatureSpaceCheck(false),
      76             :     mGraphiteSpaceContextualsInitialized(false),
      77             :     mHasGraphiteSpaceContextuals(false),
      78             :     mSpaceGlyphIsInvisible(false),
      79             :     mSpaceGlyphIsInvisibleInitialized(false),
      80             :     mCheckedForGraphiteTables(false),
      81             :     mHasCmapTable(false),
      82             :     mGrFaceInitialized(false),
      83             :     mCheckedForColorGlyph(false),
      84           0 :     mCheckedForVariationAxes(false)
      85             : {
      86           0 :     memset(&mDefaultSubSpaceFeatures, 0, sizeof(mDefaultSubSpaceFeatures));
      87           0 :     memset(&mNonDefaultSubSpaceFeatures, 0, sizeof(mNonDefaultSubSpaceFeatures));
      88           0 : }
      89             : 
      90           0 : gfxFontEntry::gfxFontEntry(const nsAString& aName, bool aIsStandardFace) :
      91             :     mName(aName),
      92             :     mFixedPitch(false),
      93             :     mIsBadUnderlineFont(false),
      94             :     mIsUserFontContainer(false),
      95             :     mIsDataUserFont(false),
      96             :     mIsLocalUserFont(false),
      97             :     mStandardFace(aIsStandardFace),
      98             :     mIgnoreGDEF(false),
      99             :     mIgnoreGSUB(false),
     100             :     mSVGInitialized(false),
     101             :     mHasSpaceFeaturesInitialized(false),
     102             :     mHasSpaceFeatures(false),
     103             :     mHasSpaceFeaturesKerning(false),
     104             :     mHasSpaceFeaturesNonKerning(false),
     105             :     mSkipDefaultFeatureSpaceCheck(false),
     106             :     mGraphiteSpaceContextualsInitialized(false),
     107             :     mHasGraphiteSpaceContextuals(false),
     108             :     mSpaceGlyphIsInvisible(false),
     109             :     mSpaceGlyphIsInvisibleInitialized(false),
     110             :     mCheckedForGraphiteTables(false),
     111             :     mHasCmapTable(false),
     112             :     mGrFaceInitialized(false),
     113             :     mCheckedForColorGlyph(false),
     114           0 :     mCheckedForVariationAxes(false)
     115             : {
     116           0 :     memset(&mDefaultSubSpaceFeatures, 0, sizeof(mDefaultSubSpaceFeatures));
     117           0 :     memset(&mNonDefaultSubSpaceFeatures, 0, sizeof(mNonDefaultSubSpaceFeatures));
     118           0 : }
     119             : 
     120           0 : gfxFontEntry::~gfxFontEntry()
     121             : {
     122             :     // Should not be dropped by stylo
     123           0 :     MOZ_ASSERT(NS_IsMainThread());
     124           0 :     if (mCOLR) {
     125           0 :         hb_blob_destroy(mCOLR);
     126             :     }
     127             : 
     128           0 :     if (mCPAL) {
     129           0 :         hb_blob_destroy(mCPAL);
     130             :     }
     131             : 
     132             :     // For downloaded fonts, we need to tell the user font cache that this
     133             :     // entry is being deleted.
     134           0 :     if (mIsDataUserFont) {
     135           0 :         gfxUserFontSet::UserFontCache::ForgetFont(this);
     136             :     }
     137             : 
     138           0 :     if (mFeatureInputs) {
     139           0 :         for (auto iter = mFeatureInputs->Iter(); !iter.Done(); iter.Next()) {
     140           0 :             hb_set_t*& set = iter.Data();
     141           0 :             hb_set_destroy(set);
     142             :         }
     143             :     }
     144             : 
     145             :     // By the time the entry is destroyed, all font instances that were
     146             :     // using it should already have been deleted, and so the HB and/or Gr
     147             :     // face objects should have been released.
     148           0 :     MOZ_ASSERT(!mHBFace);
     149           0 :     MOZ_ASSERT(!mGrFaceInitialized);
     150           0 : }
     151             : 
     152           0 : bool gfxFontEntry::TestCharacterMap(uint32_t aCh)
     153             : {
     154           0 :     if (!mCharacterMap) {
     155           0 :         ReadCMAP();
     156           0 :         NS_ASSERTION(mCharacterMap, "failed to initialize character map");
     157             :     }
     158           0 :     return mCharacterMap->test(aCh);
     159             : }
     160             : 
     161           0 : nsresult gfxFontEntry::InitializeUVSMap()
     162             : {
     163             :     // mUVSOffset will not be initialized
     164             :     // until cmap is initialized.
     165           0 :     if (!mCharacterMap) {
     166           0 :         ReadCMAP();
     167           0 :         NS_ASSERTION(mCharacterMap, "failed to initialize character map");
     168             :     }
     169             : 
     170           0 :     if (!mUVSOffset) {
     171             :         return NS_ERROR_FAILURE;
     172             :     }
     173             : 
     174           0 :     if (!mUVSData) {
     175           0 :         const uint32_t kCmapTag = TRUETYPE_TAG('c','m','a','p');
     176           0 :         AutoTable cmapTable(this, kCmapTag);
     177           0 :         if (!cmapTable) {
     178           0 :             mUVSOffset = 0; // don't bother to read the table again
     179           0 :             return NS_ERROR_FAILURE;
     180             :         }
     181             : 
     182           0 :         UniquePtr<uint8_t[]> uvsData;
     183             :         unsigned int cmapLen;
     184           0 :         const char* cmapData = hb_blob_get_data(cmapTable, &cmapLen);
     185           0 :         nsresult rv = gfxFontUtils::ReadCMAPTableFormat14(
     186           0 :                           (const uint8_t*)cmapData + mUVSOffset,
     187           0 :                           cmapLen - mUVSOffset, uvsData);
     188             : 
     189           0 :         if (NS_FAILED(rv)) {
     190           0 :             mUVSOffset = 0; // don't bother to read the table again
     191           0 :             return rv;
     192             :         }
     193             : 
     194           0 :         mUVSData = std::move(uvsData);
     195             :     }
     196             : 
     197             :     return NS_OK;
     198             : }
     199             : 
     200           0 : uint16_t gfxFontEntry::GetUVSGlyph(uint32_t aCh, uint32_t aVS)
     201             : {
     202           0 :     InitializeUVSMap();
     203             : 
     204           0 :     if (mUVSData) {
     205           0 :         return gfxFontUtils::MapUVSToGlyphFormat14(mUVSData.get(), aCh, aVS);
     206             :     }
     207             : 
     208             :     return 0;
     209             : }
     210             : 
     211           0 : bool gfxFontEntry::SupportsScriptInGSUB(const hb_tag_t* aScriptTags)
     212             : {
     213           0 :     hb_face_t *face = GetHBFace();
     214           0 :     if (!face) {
     215             :         return false;
     216             :     }
     217             : 
     218             :     unsigned int index;
     219             :     hb_tag_t     chosenScript;
     220             :     bool found =
     221           0 :         hb_ot_layout_table_choose_script(face, TRUETYPE_TAG('G','S','U','B'),
     222           0 :                                          aScriptTags, &index, &chosenScript);
     223           0 :     hb_face_destroy(face);
     224             : 
     225           0 :     return found && chosenScript != TRUETYPE_TAG('D','F','L','T');
     226             : }
     227             : 
     228           0 : nsresult gfxFontEntry::ReadCMAP(FontInfoData *aFontInfoData)
     229             : {
     230           0 :     NS_ASSERTION(false, "using default no-op implementation of ReadCMAP");
     231           0 :     mCharacterMap = new gfxCharacterMap();
     232           0 :     return NS_OK;
     233             : }
     234             : 
     235             : nsString
     236           0 : gfxFontEntry::RealFaceName()
     237             : {
     238           0 :     AutoTable nameTable(this, TRUETYPE_TAG('n','a','m','e'));
     239           0 :     if (nameTable) {
     240           0 :         nsAutoString name;
     241           0 :         nsresult rv = gfxFontUtils::GetFullNameFromTable(nameTable, name);
     242           0 :         if (NS_SUCCEEDED(rv)) {
     243           0 :             return name;
     244             :         }
     245             :     }
     246           0 :     return Name();
     247             : }
     248             : 
     249             : gfxFont*
     250           0 : gfxFontEntry::FindOrMakeFont(const gfxFontStyle *aStyle,
     251             :                              gfxCharacterMap* aUnicodeRangeMap)
     252             : {
     253             :     // the font entry name is the psname, not the family name
     254             :     gfxFont* font =
     255           0 :         gfxFontCache::GetCache()->Lookup(this, aStyle, aUnicodeRangeMap);
     256             : 
     257           0 :     if (!font) {
     258           0 :         gfxFont *newFont = CreateFontInstance(aStyle);
     259           0 :         if (!newFont) {
     260             :             return nullptr;
     261             :         }
     262           0 :         if (!newFont->Valid()) {
     263           0 :             delete newFont;
     264           0 :             return nullptr;
     265             :         }
     266           0 :         font = newFont;
     267           0 :         font->SetUnicodeRangeMap(aUnicodeRangeMap);
     268           0 :         gfxFontCache::GetCache()->AddNew(font);
     269             :     }
     270             :     return font;
     271             : }
     272             : 
     273             : uint16_t
     274           0 : gfxFontEntry::UnitsPerEm()
     275             : {
     276           0 :     if (!mUnitsPerEm) {
     277           0 :         AutoTable headTable(this, TRUETYPE_TAG('h','e','a','d'));
     278           0 :         if (headTable) {
     279             :             uint32_t len;
     280             :             const HeadTable* head =
     281           0 :                 reinterpret_cast<const HeadTable*>(hb_blob_get_data(headTable,
     282           0 :                                                                     &len));
     283           0 :             if (len >= sizeof(HeadTable)) {
     284           0 :                 mUnitsPerEm = head->unitsPerEm;
     285             :             }
     286             :         }
     287             : 
     288             :         // if we didn't find a usable 'head' table, or if the value was
     289             :         // outside the valid range, record it as invalid
     290           0 :         if (mUnitsPerEm < kMinUPEM || mUnitsPerEm > kMaxUPEM) {
     291           0 :             mUnitsPerEm = kInvalidUPEM;
     292             :         }
     293             :     }
     294           0 :     return mUnitsPerEm;
     295             : }
     296             : 
     297             : bool
     298           0 : gfxFontEntry::HasSVGGlyph(uint32_t aGlyphId)
     299             : {
     300           0 :     NS_ASSERTION(mSVGInitialized, "SVG data has not yet been loaded. TryGetSVGData() first.");
     301           0 :     return mSVGGlyphs->HasSVGGlyph(aGlyphId);
     302             : }
     303             : 
     304             : bool
     305           0 : gfxFontEntry::GetSVGGlyphExtents(DrawTarget* aDrawTarget, uint32_t aGlyphId,
     306             :                                  gfxFloat aSize, gfxRect* aResult)
     307             : {
     308           0 :     MOZ_ASSERT(mSVGInitialized,
     309             :                "SVG data has not yet been loaded. TryGetSVGData() first.");
     310           0 :     MOZ_ASSERT(mUnitsPerEm >= kMinUPEM && mUnitsPerEm <= kMaxUPEM,
     311             :                "font has invalid unitsPerEm");
     312             : 
     313           0 :     gfxMatrix svgToApp(aSize / mUnitsPerEm, 0, 0, aSize / mUnitsPerEm, 0, 0);
     314           0 :     return mSVGGlyphs->GetGlyphExtents(aGlyphId, svgToApp, aResult);
     315             : }
     316             : 
     317             : void
     318           0 : gfxFontEntry::RenderSVGGlyph(gfxContext *aContext, uint32_t aGlyphId,
     319             :                              SVGContextPaint* aContextPaint)
     320             : {
     321           0 :     NS_ASSERTION(mSVGInitialized, "SVG data has not yet been loaded. TryGetSVGData() first.");
     322           0 :     mSVGGlyphs->RenderGlyph(aContext, aGlyphId, aContextPaint);
     323           0 : }
     324             : 
     325             : bool
     326           0 : gfxFontEntry::TryGetSVGData(gfxFont* aFont)
     327             : {
     328           0 :     if (!gfxPlatform::GetPlatform()->OpenTypeSVGEnabled()) {
     329             :         return false;
     330             :     }
     331             : 
     332           0 :     if (!mSVGInitialized) {
     333           0 :         mSVGInitialized = true;
     334             : 
     335             :         // If UnitsPerEm is not known/valid, we can't use SVG glyphs
     336           0 :         if (UnitsPerEm() == kInvalidUPEM) {
     337             :             return false;
     338             :         }
     339             : 
     340             :         // We don't use AutoTable here because we'll pass ownership of this
     341             :         // blob to the gfxSVGGlyphs, once we've confirmed the table exists
     342           0 :         hb_blob_t *svgTable = GetFontTable(TRUETYPE_TAG('S','V','G',' '));
     343           0 :         if (!svgTable) {
     344             :             return false;
     345             :         }
     346             : 
     347             :         // gfxSVGGlyphs will hb_blob_destroy() the table when it is finished
     348             :         // with it.
     349           0 :         mSVGGlyphs = MakeUnique<gfxSVGGlyphs>(svgTable, this);
     350             :     }
     351             : 
     352           0 :     if (mSVGGlyphs && !mFontsUsingSVGGlyphs.Contains(aFont)) {
     353           0 :         mFontsUsingSVGGlyphs.AppendElement(aFont);
     354             :     }
     355             : 
     356           0 :     return !!mSVGGlyphs;
     357             : }
     358             : 
     359             : void
     360           0 : gfxFontEntry::NotifyFontDestroyed(gfxFont* aFont)
     361             : {
     362           0 :     mFontsUsingSVGGlyphs.RemoveElement(aFont);
     363           0 : }
     364             : 
     365             : void
     366           0 : gfxFontEntry::NotifyGlyphsChanged()
     367             : {
     368           0 :     for (uint32_t i = 0, count = mFontsUsingSVGGlyphs.Length(); i < count; ++i) {
     369           0 :         gfxFont* font = mFontsUsingSVGGlyphs[i];
     370           0 :         font->NotifyGlyphsChanged();
     371             :     }
     372           0 : }
     373             : 
     374             : bool
     375           0 : gfxFontEntry::TryGetColorGlyphs()
     376             : {
     377           0 :     if (mCheckedForColorGlyph) {
     378           0 :         return (mCOLR && mCPAL);
     379             :     }
     380             : 
     381           0 :     mCheckedForColorGlyph = true;
     382             : 
     383           0 :     mCOLR = GetFontTable(TRUETYPE_TAG('C', 'O', 'L', 'R'));
     384           0 :     if (!mCOLR) {
     385             :         return false;
     386             :     }
     387             : 
     388           0 :     mCPAL = GetFontTable(TRUETYPE_TAG('C', 'P', 'A', 'L'));
     389           0 :     if (!mCPAL) {
     390           0 :         hb_blob_destroy(mCOLR);
     391           0 :         mCOLR = nullptr;
     392           0 :         return false;
     393             :     }
     394             : 
     395             :     // validation COLR and CPAL table
     396           0 :     if (gfxFontUtils::ValidateColorGlyphs(mCOLR, mCPAL)) {
     397             :         return true;
     398             :     }
     399             : 
     400           0 :     hb_blob_destroy(mCOLR);
     401           0 :     hb_blob_destroy(mCPAL);
     402           0 :     mCOLR = nullptr;
     403           0 :     mCPAL = nullptr;
     404           0 :     return false;
     405             : }
     406             : 
     407             : /**
     408             :  * FontTableBlobData
     409             :  *
     410             :  * See FontTableHashEntry for the general strategy.
     411             :  */
     412             : 
     413             : class gfxFontEntry::FontTableBlobData {
     414             : public:
     415           0 :     explicit FontTableBlobData(nsTArray<uint8_t>&& aBuffer)
     416           0 :         : mTableData(std::move(aBuffer))
     417             :         , mHashtable(nullptr)
     418           0 :         , mHashKey(0)
     419             :     {
     420           0 :         MOZ_COUNT_CTOR(FontTableBlobData);
     421           0 :     }
     422             : 
     423           0 :     ~FontTableBlobData() {
     424           0 :         MOZ_COUNT_DTOR(FontTableBlobData);
     425           0 :         if (mHashtable && mHashKey) {
     426           0 :             mHashtable->RemoveEntry(mHashKey);
     427             :         }
     428           0 :     }
     429             : 
     430             :     // Useful for creating blobs
     431             :     const char *GetTable() const
     432             :     {
     433           0 :         return reinterpret_cast<const char*>(mTableData.Elements());
     434             :     }
     435           0 :     uint32_t GetTableLength() const { return mTableData.Length(); }
     436             : 
     437             :     // Tell this FontTableBlobData to remove the HashEntry when this is
     438             :     // destroyed.
     439             :     void ManageHashEntry(nsTHashtable<FontTableHashEntry> *aHashtable,
     440             :                          uint32_t aHashKey)
     441             :     {
     442           0 :         mHashtable = aHashtable;
     443           0 :         mHashKey = aHashKey;
     444             :     }
     445             : 
     446             :     // Disconnect from the HashEntry (because the blob has already been
     447             :     // removed from the hashtable).
     448             :     void ForgetHashEntry()
     449             :     {
     450           0 :         mHashtable = nullptr;
     451           0 :         mHashKey = 0;
     452             :     }
     453             : 
     454             :     size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const {
     455           0 :         return mTableData.ShallowSizeOfExcludingThis(aMallocSizeOf);
     456             :     }
     457           0 :     size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const {
     458           0 :         return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
     459             :     }
     460             : 
     461             : private:
     462             :     // The font table data block
     463             :     nsTArray<uint8_t> mTableData;
     464             : 
     465             :     // The blob destroy function needs to know the owning hashtable
     466             :     // and the hashtable key, so that it can remove the entry.
     467             :     nsTHashtable<FontTableHashEntry> *mHashtable;
     468             :     uint32_t                          mHashKey;
     469             : 
     470             :     // not implemented
     471             :     FontTableBlobData(const FontTableBlobData&);
     472             : };
     473             : 
     474             : hb_blob_t *
     475           0 : gfxFontEntry::FontTableHashEntry::
     476             : ShareTableAndGetBlob(nsTArray<uint8_t>&& aTable,
     477             :                      nsTHashtable<FontTableHashEntry> *aHashtable)
     478             : {
     479           0 :     Clear();
     480             :     // adopts elements of aTable
     481           0 :     mSharedBlobData = new FontTableBlobData(std::move(aTable));
     482             : 
     483           0 :     mBlob = hb_blob_create(mSharedBlobData->GetTable(),
     484           0 :                            mSharedBlobData->GetTableLength(),
     485             :                            HB_MEMORY_MODE_READONLY,
     486             :                            mSharedBlobData, DeleteFontTableBlobData);
     487           0 :     if (mBlob == hb_blob_get_empty() ) {
     488             :         // The FontTableBlobData was destroyed during hb_blob_create().
     489             :         // The (empty) blob is still be held in the hashtable with a strong
     490             :         // reference.
     491           0 :         return hb_blob_reference(mBlob);
     492             :     }
     493             : 
     494             :     // Tell the FontTableBlobData to remove this hash entry when destroyed.
     495             :     // The hashtable does not keep a strong reference.
     496           0 :     mSharedBlobData->ManageHashEntry(aHashtable, GetKey());
     497           0 :     return mBlob;
     498             : }
     499             : 
     500             : void
     501           0 : gfxFontEntry::FontTableHashEntry::Clear()
     502             : {
     503             :     // If the FontTableBlobData is managing the hash entry, then the blob is
     504             :     // not owned by this HashEntry; otherwise there is strong reference to the
     505             :     // blob that must be removed.
     506           0 :     if (mSharedBlobData) {
     507           0 :         mSharedBlobData->ForgetHashEntry();
     508           0 :         mSharedBlobData = nullptr;
     509           0 :     } else if (mBlob) {
     510           0 :         hb_blob_destroy(mBlob);
     511             :     }
     512           0 :     mBlob = nullptr;
     513           0 : }
     514             : 
     515             : // a hb_destroy_func for hb_blob_create
     516             : 
     517             : /* static */ void
     518           0 : gfxFontEntry::FontTableHashEntry::DeleteFontTableBlobData(void *aBlobData)
     519             : {
     520           0 :     delete static_cast<FontTableBlobData*>(aBlobData);
     521           0 : }
     522             : 
     523             : hb_blob_t *
     524           0 : gfxFontEntry::FontTableHashEntry::GetBlob() const
     525             : {
     526           0 :     return hb_blob_reference(mBlob);
     527             : }
     528             : 
     529             : bool
     530           0 : gfxFontEntry::GetExistingFontTable(uint32_t aTag, hb_blob_t **aBlob)
     531             : {
     532           0 :     if (!mFontTableCache) {
     533             :         // we do this here rather than on fontEntry construction
     534             :         // because not all shapers will access the table cache at all
     535           0 :         mFontTableCache = MakeUnique<nsTHashtable<FontTableHashEntry>>(8);
     536             :     }
     537             : 
     538           0 :     FontTableHashEntry *entry = mFontTableCache->GetEntry(aTag);
     539           0 :     if (!entry) {
     540             :         return false;
     541             :     }
     542             : 
     543           0 :     *aBlob = entry->GetBlob();
     544           0 :     return true;
     545             : }
     546             : 
     547             : hb_blob_t *
     548           0 : gfxFontEntry::ShareFontTableAndGetBlob(uint32_t aTag,
     549             :                                        nsTArray<uint8_t>* aBuffer)
     550             : {
     551           0 :     if (MOZ_UNLIKELY(!mFontTableCache)) {
     552             :         // we do this here rather than on fontEntry construction
     553             :         // because not all shapers will access the table cache at all
     554           0 :       mFontTableCache = MakeUnique<nsTHashtable<FontTableHashEntry>>(8);
     555             :     }
     556             : 
     557           0 :     FontTableHashEntry *entry = mFontTableCache->PutEntry(aTag);
     558           0 :     if (MOZ_UNLIKELY(!entry)) { // OOM
     559             :         return nullptr;
     560             :     }
     561             : 
     562           0 :     if (!aBuffer) {
     563             :         // ensure the entry is null
     564           0 :         entry->Clear();
     565           0 :         return nullptr;
     566             :     }
     567             : 
     568           0 :     return entry->ShareTableAndGetBlob(std::move(*aBuffer), mFontTableCache.get());
     569             : }
     570             : 
     571             : already_AddRefed<gfxCharacterMap>
     572           0 : gfxFontEntry::GetCMAPFromFontInfo(FontInfoData *aFontInfoData,
     573             :                                   uint32_t& aUVSOffset)
     574             : {
     575           0 :     if (!aFontInfoData || !aFontInfoData->mLoadCmaps) {
     576             :         return nullptr;
     577             :     }
     578             : 
     579           0 :     return aFontInfoData->GetCMAP(mName, aUVSOffset);
     580             : }
     581             : 
     582             : hb_blob_t *
     583           0 : gfxFontEntry::GetFontTable(uint32_t aTag)
     584             : {
     585             :     hb_blob_t *blob;
     586           0 :     if (GetExistingFontTable(aTag, &blob)) {
     587           0 :         return blob;
     588             :     }
     589             : 
     590           0 :     nsTArray<uint8_t> buffer;
     591           0 :     bool haveTable = NS_SUCCEEDED(CopyFontTable(aTag, buffer));
     592             : 
     593           0 :     return ShareFontTableAndGetBlob(aTag, haveTable ? &buffer : nullptr);
     594             : }
     595             : 
     596             : // callback for HarfBuzz to get a font table (in hb_blob_t form)
     597             : // from the font entry (passed as aUserData)
     598             : /*static*/ hb_blob_t *
     599           0 : gfxFontEntry::HBGetTable(hb_face_t *face, uint32_t aTag, void *aUserData)
     600             : {
     601           0 :     gfxFontEntry *fontEntry = static_cast<gfxFontEntry*>(aUserData);
     602             : 
     603             :     // bug 589682 - ignore the GDEF table in buggy fonts (applies to
     604             :     // Italic and BoldItalic faces of Times New Roman)
     605           0 :     if (aTag == TRUETYPE_TAG('G','D','E','F') &&
     606           0 :         fontEntry->IgnoreGDEF()) {
     607             :         return nullptr;
     608             :     }
     609             : 
     610             :     // bug 721719 - ignore the GSUB table in buggy fonts (applies to Roboto,
     611             :     // at least on some Android ICS devices; set in gfxFT2FontList.cpp)
     612           0 :     if (aTag == TRUETYPE_TAG('G','S','U','B') &&
     613           0 :         fontEntry->IgnoreGSUB()) {
     614             :         return nullptr;
     615             :     }
     616             : 
     617           0 :     return fontEntry->GetFontTable(aTag);
     618             : }
     619             : 
     620             : /*static*/ void
     621           0 : gfxFontEntry::HBFaceDeletedCallback(void *aUserData)
     622             : {
     623           0 :     gfxFontEntry *fe = static_cast<gfxFontEntry*>(aUserData);
     624           0 :     fe->ForgetHBFace();
     625           0 : }
     626             : 
     627             : void
     628           0 : gfxFontEntry::ForgetHBFace()
     629             : {
     630           0 :     mHBFace = nullptr;
     631           0 : }
     632             : 
     633             : hb_face_t*
     634           0 : gfxFontEntry::GetHBFace()
     635             : {
     636           0 :     if (!mHBFace) {
     637           0 :         mHBFace = hb_face_create_for_tables(HBGetTable, this,
     638             :                                             HBFaceDeletedCallback);
     639           0 :         return mHBFace;
     640             :     }
     641           0 :     return hb_face_reference(mHBFace);
     642             : }
     643             : 
     644             : /*static*/ const void*
     645           0 : gfxFontEntry::GrGetTable(const void *aAppFaceHandle, unsigned int aName,
     646             :                          size_t *aLen)
     647             : {
     648             :     gfxFontEntry *fontEntry =
     649           0 :         static_cast<gfxFontEntry*>(const_cast<void*>(aAppFaceHandle));
     650           0 :     hb_blob_t *blob = fontEntry->GetFontTable(aName);
     651           0 :     if (blob) {
     652             :         unsigned int blobLength;
     653           0 :         const void *tableData = hb_blob_get_data(blob, &blobLength);
     654           0 :         fontEntry->mGrTableMap->Put(tableData, blob);
     655           0 :         *aLen = blobLength;
     656             :         return tableData;
     657             :     }
     658           0 :     *aLen = 0;
     659           0 :     return nullptr;
     660             : }
     661             : 
     662             : /*static*/ void
     663           0 : gfxFontEntry::GrReleaseTable(const void *aAppFaceHandle,
     664             :                              const void *aTableBuffer)
     665             : {
     666             :     gfxFontEntry *fontEntry =
     667           0 :         static_cast<gfxFontEntry*>(const_cast<void*>(aAppFaceHandle));
     668             :     void* value;
     669           0 :     if (fontEntry->mGrTableMap->Remove(aTableBuffer, &value)) {
     670           0 :         hb_blob_destroy(static_cast<hb_blob_t*>(value));
     671             :     }
     672           0 : }
     673             : 
     674             : gr_face*
     675           0 : gfxFontEntry::GetGrFace()
     676             : {
     677           0 :     if (!mGrFaceInitialized) {
     678             :         gr_face_ops faceOps = {
     679             :             sizeof(gr_face_ops),
     680             :             GrGetTable,
     681             :             GrReleaseTable
     682           0 :         };
     683           0 :         mGrTableMap = new nsDataHashtable<nsPtrHashKey<const void>,void*>;
     684           0 :         mGrFace = gr_make_face_with_ops(this, &faceOps, gr_face_default);
     685           0 :         mGrFaceInitialized = true;
     686             :     }
     687           0 :     ++mGrFaceRefCnt;
     688           0 :     return mGrFace;
     689             : }
     690             : 
     691             : void
     692           0 : gfxFontEntry::ReleaseGrFace(gr_face *aFace)
     693             : {
     694           0 :     MOZ_ASSERT(aFace == mGrFace); // sanity-check
     695           0 :     MOZ_ASSERT(mGrFaceRefCnt > 0);
     696           0 :     if (--mGrFaceRefCnt == 0) {
     697           0 :         gr_face_destroy(mGrFace);
     698           0 :         mGrFace = nullptr;
     699           0 :         mGrFaceInitialized = false;
     700           0 :         delete mGrTableMap;
     701           0 :         mGrTableMap = nullptr;
     702             :     }
     703           0 : }
     704             : 
     705             : void
     706           0 : gfxFontEntry::DisconnectSVG()
     707             : {
     708           0 :     if (mSVGInitialized && mSVGGlyphs) {
     709           0 :         mSVGGlyphs = nullptr;
     710           0 :         mSVGInitialized = false;
     711             :     }
     712           0 : }
     713             : 
     714             : bool
     715           0 : gfxFontEntry::HasFontTable(uint32_t aTableTag)
     716             : {
     717           0 :     AutoTable table(this, aTableTag);
     718           0 :     return table && hb_blob_get_length(table) > 0;
     719             : }
     720             : 
     721             : void
     722           0 : gfxFontEntry::CheckForGraphiteTables()
     723             : {
     724           0 :     mHasGraphiteTables = HasFontTable(TRUETYPE_TAG('S','i','l','f'));
     725           0 : }
     726             : 
     727             : bool
     728           0 : gfxFontEntry::HasGraphiteSpaceContextuals()
     729             : {
     730           0 :     if (!mGraphiteSpaceContextualsInitialized) {
     731           0 :         gr_face* face = GetGrFace();
     732           0 :         if (face) {
     733           0 :             const gr_faceinfo* faceInfo = gr_face_info(face, 0);
     734           0 :             mHasGraphiteSpaceContextuals =
     735           0 :                 faceInfo->space_contextuals != gr_faceinfo::gr_space_none;
     736             :         }
     737           0 :         ReleaseGrFace(face); // always balance GetGrFace, even if face is null
     738           0 :         mGraphiteSpaceContextualsInitialized = true;
     739             :     }
     740           0 :     return mHasGraphiteSpaceContextuals;
     741             : }
     742             : 
     743             : #define FEATURE_SCRIPT_MASK 0x000000ff // script index replaces low byte of tag
     744             : 
     745             : static_assert(int(Script::NUM_SCRIPT_CODES) <= FEATURE_SCRIPT_MASK, "Too many script codes");
     746             : 
     747             : // high-order three bytes of tag with script in low-order byte
     748             : #define SCRIPT_FEATURE(s,tag) (((~FEATURE_SCRIPT_MASK) & (tag)) | \
     749             :                                ((FEATURE_SCRIPT_MASK) & static_cast<uint32_t>(s)))
     750             : 
     751             : bool
     752           0 : gfxFontEntry::SupportsOpenTypeFeature(Script aScript, uint32_t aFeatureTag)
     753             : {
     754           0 :     if (!mSupportedFeatures) {
     755           0 :         mSupportedFeatures = MakeUnique<nsDataHashtable<nsUint32HashKey,bool>>();
     756             :     }
     757             : 
     758             :     // note: high-order three bytes *must* be unique for each feature
     759             :     // listed below (see SCRIPT_FEATURE macro def'n)
     760           0 :     NS_ASSERTION(aFeatureTag == HB_TAG('s','m','c','p') ||
     761             :                  aFeatureTag == HB_TAG('c','2','s','c') ||
     762             :                  aFeatureTag == HB_TAG('p','c','a','p') ||
     763             :                  aFeatureTag == HB_TAG('c','2','p','c') ||
     764             :                  aFeatureTag == HB_TAG('s','u','p','s') ||
     765             :                  aFeatureTag == HB_TAG('s','u','b','s') ||
     766             :                  aFeatureTag == HB_TAG('v','e','r','t'),
     767             :                  "use of unknown feature tag");
     768             : 
     769             :     // note: graphite feature support uses the last script index
     770           0 :     NS_ASSERTION(int(aScript) < FEATURE_SCRIPT_MASK - 1,
     771             :                  "need to bump the size of the feature shift");
     772             : 
     773           0 :     uint32_t scriptFeature = SCRIPT_FEATURE(aScript, aFeatureTag);
     774             :     bool result;
     775           0 :     if (mSupportedFeatures->Get(scriptFeature, &result)) {
     776           0 :         return result;
     777             :     }
     778             : 
     779           0 :     result = false;
     780             : 
     781           0 :     hb_face_t *face = GetHBFace();
     782             : 
     783           0 :     if (hb_ot_layout_has_substitution(face)) {
     784             :         hb_script_t hbScript =
     785           0 :             gfxHarfBuzzShaper::GetHBScriptUsedForShaping(aScript);
     786             : 
     787             :         // Get the OpenType tag(s) that match this script code
     788             :         hb_tag_t scriptTags[4] = {
     789             :             HB_TAG_NONE,
     790             :             HB_TAG_NONE,
     791             :             HB_TAG_NONE,
     792             :             HB_TAG_NONE
     793           0 :         };
     794           0 :         hb_ot_tags_from_script(hbScript, &scriptTags[0], &scriptTags[1]);
     795             : 
     796             :         // Replace the first remaining NONE with DEFAULT
     797           0 :         hb_tag_t* scriptTag = &scriptTags[0];
     798           0 :         while (*scriptTag != HB_TAG_NONE) {
     799           0 :             ++scriptTag;
     800             :         }
     801           0 :         *scriptTag = HB_OT_TAG_DEFAULT_SCRIPT;
     802             : 
     803             :         // Now check for 'smcp' under the first of those scripts that is present
     804           0 :         const hb_tag_t kGSUB = HB_TAG('G','S','U','B');
     805           0 :         scriptTag = &scriptTags[0];
     806           0 :         while (*scriptTag != HB_TAG_NONE) {
     807             :             unsigned int scriptIndex;
     808           0 :             if (hb_ot_layout_table_find_script(face, kGSUB, *scriptTag,
     809             :                                                &scriptIndex)) {
     810           0 :                 if (hb_ot_layout_language_find_feature(face, kGSUB,
     811             :                                                        scriptIndex,
     812             :                                            HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX,
     813             :                                                        aFeatureTag, nullptr)) {
     814           0 :                     result = true;
     815             :                 }
     816           0 :                 break;
     817             :             }
     818           0 :             ++scriptTag;
     819             :         }
     820             :     }
     821             : 
     822           0 :     hb_face_destroy(face);
     823             : 
     824           0 :     mSupportedFeatures->Put(scriptFeature, result);
     825             : 
     826           0 :     return result;
     827             : }
     828             : 
     829             : const hb_set_t*
     830           0 : gfxFontEntry::InputsForOpenTypeFeature(Script aScript, uint32_t aFeatureTag)
     831             : {
     832           0 :     if (!mFeatureInputs) {
     833           0 :         mFeatureInputs = MakeUnique<nsDataHashtable<nsUint32HashKey,hb_set_t*>>();
     834             :     }
     835             : 
     836           0 :     NS_ASSERTION(aFeatureTag == HB_TAG('s','u','p','s') ||
     837             :                  aFeatureTag == HB_TAG('s','u','b','s') ||
     838             :                  aFeatureTag == HB_TAG('v','e','r','t'),
     839             :                  "use of unknown feature tag");
     840             : 
     841           0 :     uint32_t scriptFeature = SCRIPT_FEATURE(aScript, aFeatureTag);
     842             :     hb_set_t *inputGlyphs;
     843           0 :     if (mFeatureInputs->Get(scriptFeature, &inputGlyphs)) {
     844           0 :         return inputGlyphs;
     845             :     }
     846             : 
     847           0 :     inputGlyphs = hb_set_create();
     848             : 
     849           0 :     hb_face_t *face = GetHBFace();
     850             : 
     851           0 :     if (hb_ot_layout_has_substitution(face)) {
     852             :         hb_script_t hbScript =
     853           0 :             gfxHarfBuzzShaper::GetHBScriptUsedForShaping(aScript);
     854             : 
     855             :         // Get the OpenType tag(s) that match this script code
     856             :         hb_tag_t scriptTags[4] = {
     857             :             HB_TAG_NONE,
     858             :             HB_TAG_NONE,
     859             :             HB_TAG_NONE,
     860             :             HB_TAG_NONE
     861           0 :         };
     862           0 :         hb_ot_tags_from_script(hbScript, &scriptTags[0], &scriptTags[1]);
     863             : 
     864             :         // Replace the first remaining NONE with DEFAULT
     865           0 :         hb_tag_t* scriptTag = &scriptTags[0];
     866           0 :         while (*scriptTag != HB_TAG_NONE) {
     867           0 :             ++scriptTag;
     868             :         }
     869           0 :         *scriptTag = HB_OT_TAG_DEFAULT_SCRIPT;
     870             : 
     871           0 :         const hb_tag_t kGSUB = HB_TAG('G','S','U','B');
     872           0 :         hb_tag_t features[2] = { aFeatureTag, HB_TAG_NONE };
     873           0 :         hb_set_t *featurelookups = hb_set_create();
     874             :         hb_ot_layout_collect_lookups(face, kGSUB, scriptTags, nullptr,
     875           0 :                                      features, featurelookups);
     876           0 :         hb_codepoint_t index = -1;
     877           0 :         while (hb_set_next(featurelookups, &index)) {
     878             :             hb_ot_layout_lookup_collect_glyphs(face, kGSUB, index,
     879             :                                                nullptr, inputGlyphs,
     880           0 :                                                nullptr, nullptr);
     881             :         }
     882           0 :         hb_set_destroy(featurelookups);
     883             :     }
     884             : 
     885           0 :     hb_face_destroy(face);
     886             : 
     887           0 :     mFeatureInputs->Put(scriptFeature, inputGlyphs);
     888           0 :     return inputGlyphs;
     889             : }
     890             : 
     891             : bool
     892           0 : gfxFontEntry::SupportsGraphiteFeature(uint32_t aFeatureTag)
     893             : {
     894           0 :     if (!mSupportedFeatures) {
     895           0 :         mSupportedFeatures = MakeUnique<nsDataHashtable<nsUint32HashKey,bool>>();
     896             :     }
     897             : 
     898             :     // note: high-order three bytes *must* be unique for each feature
     899             :     // listed below (see SCRIPT_FEATURE macro def'n)
     900           0 :     NS_ASSERTION(aFeatureTag == HB_TAG('s','m','c','p') ||
     901             :                  aFeatureTag == HB_TAG('c','2','s','c') ||
     902             :                  aFeatureTag == HB_TAG('p','c','a','p') ||
     903             :                  aFeatureTag == HB_TAG('c','2','p','c') ||
     904             :                  aFeatureTag == HB_TAG('s','u','p','s') ||
     905             :                  aFeatureTag == HB_TAG('s','u','b','s'),
     906             :                  "use of unknown feature tag");
     907             : 
     908             :     // graphite feature check uses the last script slot
     909           0 :     uint32_t scriptFeature = SCRIPT_FEATURE(FEATURE_SCRIPT_MASK, aFeatureTag);
     910             :     bool result;
     911           0 :     if (mSupportedFeatures->Get(scriptFeature, &result)) {
     912           0 :         return result;
     913             :     }
     914             : 
     915           0 :     gr_face* face = GetGrFace();
     916           0 :     result = face ? gr_face_find_fref(face, aFeatureTag) != nullptr : false;
     917           0 :     ReleaseGrFace(face);
     918             : 
     919           0 :     mSupportedFeatures->Put(scriptFeature, result);
     920             : 
     921           0 :     return result;
     922             : }
     923             : 
     924             : void
     925           0 : gfxFontEntry::GetFeatureInfo(nsTArray<gfxFontFeatureInfo>& aFeatureInfo)
     926             : {
     927             :     // TODO: implement alternative code path for graphite fonts
     928             : 
     929           0 :     hb_face_t* face = GetHBFace();
     930             : 
     931             :     // Get the list of features for a specific <script,langSys> pair and
     932             :     // append them to aFeatureInfo.
     933             :     auto collectForLang =
     934             :         [=,&aFeatureInfo](hb_tag_t aTableTag,
     935             :                           unsigned int aScript, hb_tag_t aScriptTag,
     936           0 :                           unsigned int aLang, hb_tag_t aLangTag) {
     937             :         unsigned int featCount =
     938           0 :             hb_ot_layout_language_get_feature_tags(face, aTableTag, aScript,
     939           0 :                                                    aLang, 0, nullptr, nullptr);
     940           0 :         AutoTArray<hb_tag_t,32> featTags;
     941           0 :         featTags.SetLength(featCount);
     942           0 :         hb_ot_layout_language_get_feature_tags(face, aTableTag, aScript,
     943             :                                                aLang, 0, &featCount,
     944           0 :                                                featTags.Elements());
     945           0 :         MOZ_ASSERT(featCount <= featTags.Length());
     946             :         // Just in case HB didn't fill featTags (i.e. in case it returned fewer
     947             :         // tags than it promised), we truncate at the length it says it filled:
     948           0 :         featTags.SetLength(featCount);
     949           0 :         for (hb_tag_t t : featTags) {
     950           0 :             aFeatureInfo.AppendElement(
     951           0 :                 gfxFontFeatureInfo{t, aScriptTag, aLangTag});
     952             :         }
     953           0 :     };
     954             : 
     955             :     // Iterate over the language systems supported by a given script,
     956             :     // and call collectForLang for each of them.
     957             :     auto collectForScript = [=](hb_tag_t aTableTag,
     958           0 :                                 unsigned int aScript, hb_tag_t aScriptTag) {
     959           0 :         collectForLang(aTableTag, aScript, aScriptTag,
     960             :                        HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX,
     961           0 :                        HB_TAG('d','f','l','t'));
     962             :         unsigned int langCount =
     963           0 :             hb_ot_layout_script_get_language_tags(face, aTableTag, aScript, 0,
     964           0 :                                                   nullptr, nullptr);
     965           0 :         AutoTArray<hb_tag_t,32> langTags;
     966           0 :         langTags.SetLength(langCount);
     967           0 :         hb_ot_layout_script_get_language_tags(face, aTableTag, aScript, 0,
     968           0 :                                               &langCount, langTags.Elements());
     969           0 :         MOZ_ASSERT(langCount <= langTags.Length());
     970           0 :         langTags.SetLength(langCount);
     971           0 :         for (unsigned int lang = 0; lang < langCount; ++lang) {
     972           0 :             collectForLang(aTableTag, aScript, aScriptTag, lang, langTags[lang]);
     973             :         }
     974           0 :     };
     975             : 
     976             :     // Iterate over the scripts supported by a table (GSUB or GPOS), and call
     977             :     // collectForScript for each of them.
     978           0 :     auto collectForTable = [=](hb_tag_t aTableTag) {
     979             :         unsigned int scriptCount =
     980           0 :             hb_ot_layout_table_get_script_tags(face, aTableTag, 0, nullptr,
     981           0 :                                                nullptr);
     982           0 :         AutoTArray<hb_tag_t,32> scriptTags;
     983           0 :         scriptTags.SetLength(scriptCount);
     984           0 :         hb_ot_layout_table_get_script_tags(face, aTableTag, 0, &scriptCount,
     985           0 :                                            scriptTags.Elements());
     986           0 :         MOZ_ASSERT(scriptCount <= scriptTags.Length());
     987           0 :         scriptTags.SetLength(scriptCount);
     988           0 :         for (unsigned int script = 0; script < scriptCount; ++script) {
     989           0 :             collectForScript(aTableTag, script, scriptTags[script]);
     990             :         }
     991           0 :     };
     992             : 
     993             :     // Collect all OpenType Layout features, both substitution and positioning,
     994             :     // supported by the font resource.
     995           0 :     collectForTable(HB_TAG('G','S','U','B'));
     996           0 :     collectForTable(HB_TAG('G','P','O','S'));
     997             : 
     998           0 :     hb_face_destroy(face);
     999           0 : }
    1000             : 
    1001             : bool
    1002           0 : gfxFontEntry::GetColorLayersInfo(uint32_t aGlyphId,
    1003             :                             const mozilla::gfx::Color& aDefaultColor,
    1004             :                             nsTArray<uint16_t>& aLayerGlyphs,
    1005             :                             nsTArray<mozilla::gfx::Color>& aLayerColors)
    1006             : {
    1007           0 :     return gfxFontUtils::GetColorGlyphLayers(mCOLR,
    1008             :                                              mCPAL,
    1009             :                                              aGlyphId,
    1010             :                                              aDefaultColor,
    1011             :                                              aLayerGlyphs,
    1012           0 :                                              aLayerColors);
    1013             : }
    1014             : 
    1015             : void
    1016           0 : gfxFontEntry::SetupVariationRanges()
    1017             : {
    1018           0 :     if (!gfxPlatform::GetPlatform()->HasVariationFontSupport() ||
    1019           0 :         !StaticPrefs::layout_css_font_variations_enabled() ||
    1020           0 :         !HasVariations() || IsUserFont()) {
    1021           0 :         return;
    1022             :     }
    1023           0 :     AutoTArray<gfxFontVariationAxis,4> axes;
    1024           0 :     GetVariationAxes(axes);
    1025           0 :     for (const auto& axis : axes) {
    1026           0 :         switch (axis.mTag) {
    1027             :         case HB_TAG('w','g','h','t'):
    1028             :             // If the axis range looks like it doesn't fit the CSS font-weight
    1029             :             // scale, we don't hook up the high-level property, and we mark
    1030             :             // the face (in mRangeFlags) as having non-standard weight. This
    1031             :             // means we won't map CSS font-weight to the axis. Setting 'wght'
    1032             :             // with font-variation-settings will still work.
    1033             :             // Strictly speaking, the min value should be checked against 1.0,
    1034             :             // not 0.0, but we'll allow font makers that amount of leeway, as
    1035             :             // in practice a number of fonts seem to use 0..1000.
    1036           0 :             if (axis.mMinValue >= 0.0f && axis.mMaxValue <= 1000.0f &&
    1037             :                 // If axis.mMaxValue is less than the default weight we already
    1038             :                 // set up, assume the axis has a non-standard range (like Skia)
    1039             :                 // and don't try to map it.
    1040           0 :                 Weight().Min() <= FontWeight(axis.mMaxValue)) {
    1041           0 :                 if (FontWeight(axis.mDefaultValue) != Weight().Min()) {
    1042           0 :                     mStandardFace = false;
    1043             :                 }
    1044             :                 mWeightRange =
    1045           0 :                     WeightRange(FontWeight(std::max(1.0f, axis.mMinValue)),
    1046           0 :                                 FontWeight(axis.mMaxValue));
    1047             :             } else {
    1048           0 :                 mRangeFlags |= RangeFlags::eNonCSSWeight;
    1049             :             }
    1050             :             break;
    1051             : 
    1052             :         case HB_TAG('w','d','t','h'):
    1053           0 :             if (axis.mMinValue >= 0.0f && axis.mMaxValue <= 1000.0f &&
    1054           0 :                 Stretch().Min() <= FontStretch(axis.mMaxValue)) {
    1055           0 :                 if (FontStretch(axis.mDefaultValue) != Stretch().Min()) {
    1056           0 :                     mStandardFace = false;
    1057             :                 }
    1058             :                 mStretchRange =
    1059           0 :                     StretchRange(FontStretch(axis.mMinValue),
    1060           0 :                                  FontStretch(axis.mMaxValue));
    1061             :             } else {
    1062           0 :                 mRangeFlags |= RangeFlags::eNonCSSStretch;
    1063             :             }
    1064             :             break;
    1065             : 
    1066             :         case HB_TAG('s','l','n','t'):
    1067           0 :             if (axis.mMinValue >= -90.0f && axis.mMaxValue <= 90.0f) {
    1068           0 :                 if (FontSlantStyle::Oblique(axis.mDefaultValue) != SlantStyle().Min()) {
    1069           0 :                     mStandardFace = false;
    1070             :                 }
    1071             :                 mStyleRange =
    1072           0 :                     SlantStyleRange(FontSlantStyle::Oblique(axis.mMinValue),
    1073           0 :                                     FontSlantStyle::Oblique(axis.mMaxValue));
    1074             :             }
    1075             :             break;
    1076             : 
    1077             :         case HB_TAG('i','t','a','l'):
    1078           0 :             if (axis.mMinValue <= 0.0f && axis.mMaxValue >= 1.0f) {
    1079           0 :                 if (axis.mDefaultValue != 0.0f) {
    1080           0 :                     mStandardFace = false;
    1081             :                 }
    1082             :                 mStyleRange =
    1083           0 :                     SlantStyleRange(FontSlantStyle::Normal(),
    1084           0 :                                     FontSlantStyle::Italic());
    1085             :             }
    1086             :             break;
    1087             : 
    1088             :         default:
    1089             :             continue;
    1090             :         }
    1091             :     }
    1092             : }
    1093             : 
    1094             : void
    1095           0 : gfxFontEntry::CheckForVariationAxes()
    1096             : {
    1097           0 :     if (HasVariations()) {
    1098           0 :         AutoTArray<gfxFontVariationAxis,4> axes;
    1099           0 :         GetVariationAxes(axes);
    1100           0 :         for (const auto& axis : axes) {
    1101           0 :             if (axis.mTag == HB_TAG('w','g','h','t') &&
    1102           0 :                 axis.mMaxValue >= 600.0f) {
    1103           0 :                 mRangeFlags |= RangeFlags::eBoldVariableWeight;
    1104           0 :             } else if (axis.mTag == HB_TAG('i','t','a','l') &&
    1105           0 :                 axis.mMaxValue >= 1.0f) {
    1106           0 :                 mRangeFlags |= RangeFlags::eItalicVariation;
    1107             :             }
    1108             :         }
    1109             :     }
    1110           0 :     mCheckedForVariationAxes = true;
    1111           0 : }
    1112             : 
    1113             : bool
    1114           0 : gfxFontEntry::HasBoldVariableWeight()
    1115             : {
    1116           0 :     MOZ_ASSERT(!mIsUserFontContainer,
    1117             :                "should not be called for user-font containers!");
    1118             : 
    1119           0 :     if (!gfxPlatform::GetPlatform()->HasVariationFontSupport()) {
    1120             :         return false;
    1121             :     }
    1122             : 
    1123           0 :     if (!mCheckedForVariationAxes) {
    1124           0 :         CheckForVariationAxes();
    1125             :     }
    1126             : 
    1127           0 :     return bool(mRangeFlags & RangeFlags::eBoldVariableWeight);
    1128             : }
    1129             : 
    1130             : bool
    1131           0 : gfxFontEntry::HasItalicVariation()
    1132             : {
    1133           0 :     MOZ_ASSERT(!mIsUserFontContainer,
    1134             :                "should not be called for user-font containers!");
    1135             : 
    1136           0 :     if (!gfxPlatform::GetPlatform()->HasVariationFontSupport()) {
    1137             :         return false;
    1138             :     }
    1139             : 
    1140           0 :     if (!mCheckedForVariationAxes) {
    1141           0 :         CheckForVariationAxes();
    1142             :     }
    1143             : 
    1144           0 :     return bool(mRangeFlags & RangeFlags::eItalicVariation);
    1145             : }
    1146             : 
    1147             : void
    1148           0 : gfxFontEntry::GetVariationsForStyle(nsTArray<gfxFontVariation>& aResult,
    1149             :                                     const gfxFontStyle& aStyle)
    1150             : {
    1151           0 :     if (!gfxPlatform::GetPlatform()->HasVariationFontSupport() ||
    1152           0 :         !StaticPrefs::layout_css_font_variations_enabled()) {
    1153           0 :         return;
    1154             :     }
    1155             : 
    1156           0 :     if (!HasVariations()) {
    1157             :         return;
    1158             :     }
    1159             : 
    1160             :     // Resolve high-level CSS properties from the requested style
    1161             :     // (font-{style,weight,stretch}) to the appropriate variations.
    1162             :     // The value used is clamped to the range available in the font face,
    1163             :     // unless the face is a user font where no explicit descriptor was
    1164             :     // given, indicated by the corresponding 'auto' range-flag.
    1165             : 
    1166             :     // We don't do these mappings if the font entry has weight and/or stretch
    1167             :     // ranges that do not appear to use the CSS property scale. Some older
    1168             :     // fonts created for QuickDrawGX/AAT may use "normalized" values where the
    1169             :     // standard variation is 1.0 rather than 400.0 (weight) or 100.0 (stretch).
    1170             : 
    1171           0 :     if (!(mRangeFlags & RangeFlags::eNonCSSWeight)) {
    1172             :         float weight =
    1173           0 :             (IsUserFont() && (mRangeFlags & RangeFlags::eAutoWeight))
    1174           0 :                 ? aStyle.weight.ToFloat()
    1175           0 :                 : Weight().Clamp(aStyle.weight).ToFloat();
    1176           0 :         aResult.AppendElement(gfxFontVariation{HB_TAG('w','g','h','t'),
    1177           0 :                                                weight});
    1178             :     }
    1179             : 
    1180           0 :     if (!(mRangeFlags & RangeFlags::eNonCSSStretch)) {
    1181             :         float stretch =
    1182           0 :             (IsUserFont() && (mRangeFlags & RangeFlags::eAutoStretch))
    1183           0 :                 ? aStyle.stretch.Percentage()
    1184           0 :                 : Stretch().Clamp(aStyle.stretch).Percentage();
    1185           0 :         aResult.AppendElement(gfxFontVariation{HB_TAG('w','d','t','h'),
    1186           0 :                                                stretch});
    1187             :     }
    1188             : 
    1189           0 :     if (aStyle.style.IsItalic() && SupportsItalic()) {
    1190             :         // The 'ital' axis is normally a binary toggle; intermediate values
    1191             :         // can only be set using font-variation-settings.
    1192           0 :         aResult.AppendElement(gfxFontVariation{HB_TAG('i','t','a','l'),
    1193           0 :                                                1.0f});
    1194           0 :     } else if (SlantStyle().Min().IsOblique()) {
    1195             :         // Figure out what slant angle we should try to match from the
    1196             :         // requested style.
    1197             :         float angle =
    1198           0 :             aStyle.style.IsNormal()
    1199           0 :                 ? 0.0f
    1200           0 :                 : aStyle.style.IsItalic()
    1201           0 :                     ? FontSlantStyle::Oblique().ObliqueAngle()
    1202           0 :                     : aStyle.style.ObliqueAngle();
    1203             :         // Clamp to the available range, unless the face is a user font
    1204             :         // with no explicit descriptor.
    1205           0 :         if (!(IsUserFont() && (mRangeFlags & RangeFlags::eAutoSlantStyle))) {
    1206           0 :             angle = SlantStyle().Clamp(
    1207           0 :                 FontSlantStyle::Oblique(angle)).ObliqueAngle();
    1208             :         }
    1209           0 :         aResult.AppendElement(gfxFontVariation{HB_TAG('s','l','n','t'),
    1210           0 :                                                angle});
    1211             :     }
    1212             : 
    1213           0 :     auto replaceOrAppend = [&aResult](const gfxFontVariation& aSetting) {
    1214             :         struct TagEquals {
    1215             :             bool Equals(const gfxFontVariation& aIter, uint32_t aTag) const {
    1216             :                 return aIter.mTag == aTag;
    1217             :             }
    1218             :         };
    1219           0 :         auto index = aResult.IndexOf(aSetting.mTag, 0, TagEquals());
    1220           0 :         if (index == aResult.NoIndex) {
    1221           0 :             aResult.AppendElement(aSetting);
    1222             :         } else {
    1223           0 :             aResult[index].mValue = aSetting.mValue;
    1224             :         }
    1225           0 :     };
    1226             : 
    1227             :     // The low-level font-variation-settings descriptor from @font-face,
    1228             :     // if present, takes precedence over automatic variation settings
    1229             :     // from high-level properties.
    1230           0 :     for (const auto& v : mVariationSettings) {
    1231           0 :         replaceOrAppend(v);
    1232             :     }
    1233             : 
    1234             :     // And the low-level font-variation-settings property takes precedence
    1235             :     // over the descriptor.
    1236           0 :     for (const auto& v : aStyle.variationSettings) {
    1237           0 :         replaceOrAppend(v);
    1238             :     }
    1239             : }
    1240             : 
    1241             : size_t
    1242           0 : gfxFontEntry::FontTableHashEntry::SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
    1243             : {
    1244           0 :     size_t n = 0;
    1245           0 :     if (mBlob) {
    1246           0 :         n += aMallocSizeOf(mBlob);
    1247             :     }
    1248           0 :     if (mSharedBlobData) {
    1249           0 :         n += mSharedBlobData->SizeOfIncludingThis(aMallocSizeOf);
    1250             :     }
    1251           0 :     return n;
    1252             : }
    1253             : 
    1254             : void
    1255           0 : gfxFontEntry::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
    1256             :                                      FontListSizes* aSizes) const
    1257             : {
    1258           0 :     aSizes->mFontListSize += mName.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
    1259             : 
    1260             :     // cmaps are shared so only non-shared cmaps are included here
    1261           0 :     if (mCharacterMap && mCharacterMap->mBuildOnTheFly) {
    1262           0 :         aSizes->mCharMapsSize +=
    1263           0 :             mCharacterMap->SizeOfIncludingThis(aMallocSizeOf);
    1264             :     }
    1265           0 :     if (mFontTableCache) {
    1266           0 :         aSizes->mFontTableCacheSize +=
    1267           0 :             mFontTableCache->SizeOfIncludingThis(aMallocSizeOf);
    1268             :     }
    1269             : 
    1270             :     // If the font has UVS data, we count that as part of the character map.
    1271           0 :     if (mUVSData) {
    1272           0 :         aSizes->mCharMapsSize += aMallocSizeOf(mUVSData.get());
    1273             :     }
    1274             : 
    1275             :     // The following, if present, are essentially cached forms of font table
    1276             :     // data, so we'll accumulate them together with the basic table cache.
    1277           0 :     if (mUserFontData) {
    1278           0 :         aSizes->mFontTableCacheSize +=
    1279           0 :             mUserFontData->SizeOfIncludingThis(aMallocSizeOf);
    1280             :     }
    1281           0 :     if (mSVGGlyphs) {
    1282           0 :         aSizes->mFontTableCacheSize +=
    1283           0 :             mSVGGlyphs->SizeOfIncludingThis(aMallocSizeOf);
    1284             :     }
    1285           0 :     if (mSupportedFeatures) {
    1286           0 :         aSizes->mFontTableCacheSize +=
    1287           0 :             mSupportedFeatures->ShallowSizeOfIncludingThis(aMallocSizeOf);
    1288             :     }
    1289           0 :     if (mFeatureInputs) {
    1290           0 :         aSizes->mFontTableCacheSize +=
    1291           0 :             mFeatureInputs->ShallowSizeOfIncludingThis(aMallocSizeOf);
    1292           0 :         for (auto iter = mFeatureInputs->ConstIter(); !iter.Done();
    1293           0 :              iter.Next()) {
    1294             :             // There's no API to get the real size of an hb_set, so we'll use
    1295             :             // an approximation based on knowledge of the implementation.
    1296           0 :             aSizes->mFontTableCacheSize += 8192; // vector of 64K bits
    1297             :         }
    1298             :     }
    1299             :     // We don't include the size of mCOLR/mCPAL here, because (depending on the
    1300             :     // font backend implementation) they will either wrap blocks of data owned
    1301             :     // by the system (and potentially shared), or tables that are in our font
    1302             :     // table cache and therefore already counted.
    1303           0 : }
    1304             : 
    1305             : void
    1306           0 : gfxFontEntry::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
    1307             :                                      FontListSizes* aSizes) const
    1308             : {
    1309           0 :     aSizes->mFontListSize += aMallocSizeOf(this);
    1310           0 :     AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
    1311           0 : }
    1312             : 
    1313             : // This is used to report the size of an individual downloaded font in the
    1314             : // user font cache. (Fonts that are part of the platform font list accumulate
    1315             : // their sizes to the font list's reporter using the AddSizeOf... methods
    1316             : // above.)
    1317             : size_t
    1318           0 : gfxFontEntry::ComputedSizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
    1319             : {
    1320           0 :     FontListSizes s = { 0 };
    1321           0 :     AddSizeOfExcludingThis(aMallocSizeOf, &s);
    1322             : 
    1323             :     // When reporting memory used for the main platform font list,
    1324             :     // where we're typically summing the totals for a few hundred font faces,
    1325             :     // we report the fields of FontListSizes separately.
    1326             :     // But for downloaded user fonts, the actual resource data (added below)
    1327             :     // will dominate, and the minor overhead of these pieces isn't worth
    1328             :     // splitting out for an individual font.
    1329           0 :     size_t result = s.mFontListSize + s.mFontTableCacheSize + s.mCharMapsSize;
    1330             : 
    1331           0 :     if (mIsDataUserFont) {
    1332           0 :         MOZ_ASSERT(mComputedSizeOfUserFont > 0, "user font with no data?");
    1333           0 :         result += mComputedSizeOfUserFont;
    1334             :     }
    1335             : 
    1336           0 :     return result;
    1337             : }
    1338             : 
    1339             : //////////////////////////////////////////////////////////////////////////////
    1340             : //
    1341             : // class gfxFontFamily
    1342             : //
    1343             : //////////////////////////////////////////////////////////////////////////////
    1344             : 
    1345             : // we consider faces with mStandardFace == true to be "less than" those with false,
    1346             : // because during style matching, earlier entries are tried first
    1347             : class FontEntryStandardFaceComparator {
    1348             :   public:
    1349           0 :     bool Equals(const RefPtr<gfxFontEntry>& a, const RefPtr<gfxFontEntry>& b) const {
    1350           0 :         return a->mStandardFace == b->mStandardFace;
    1351             :     }
    1352           0 :     bool LessThan(const RefPtr<gfxFontEntry>& a, const RefPtr<gfxFontEntry>& b) const {
    1353           0 :         return (a->mStandardFace == true && b->mStandardFace == false);
    1354             :     }
    1355             : };
    1356             : 
    1357             : void
    1358           0 : gfxFontFamily::SortAvailableFonts()
    1359             : {
    1360           0 :     mAvailableFonts.Sort(FontEntryStandardFaceComparator());
    1361           0 : }
    1362             : 
    1363             : bool
    1364           0 : gfxFontFamily::HasOtherFamilyNames()
    1365             : {
    1366             :     // need to read in other family names to determine this
    1367           0 :     if (!mOtherFamilyNamesInitialized) {
    1368           0 :         ReadOtherFamilyNames(gfxPlatformFontList::PlatformFontList());  // sets mHasOtherFamilyNames
    1369             :     }
    1370           0 :     return mHasOtherFamilyNames;
    1371             : }
    1372             : 
    1373             : gfxFontEntry*
    1374           0 : gfxFontFamily::FindFontForStyle(const gfxFontStyle& aFontStyle, 
    1375             :                                 bool aIgnoreSizeTolerance)
    1376             : {
    1377           0 :     AutoTArray<gfxFontEntry*,4> matched;
    1378           0 :     FindAllFontsForStyle(aFontStyle, matched, aIgnoreSizeTolerance);
    1379           0 :     if (!matched.IsEmpty()) {
    1380           0 :         return matched[0];
    1381             :     }
    1382             :     return nullptr;
    1383             : }
    1384             : 
    1385             : // style distance ==> [0,500]
    1386             : static inline double
    1387           0 : StyleDistance(const gfxFontEntry* aFontEntry, FontSlantStyle aTargetStyle)
    1388             : {
    1389           0 :     const FontSlantStyle minStyle = aFontEntry->SlantStyle().Min();
    1390           0 :     if (aTargetStyle == minStyle) {
    1391             :         return 0.0; // styles match exactly ==> 0
    1392             :     }
    1393             : 
    1394             :     // bias added to angle difference when searching in the non-preferred
    1395             :     // direction from a target angle
    1396          30 :     const double kReverse = 100.0;
    1397             : 
    1398             :     // bias added when we've crossed from positive to negative angles or
    1399             :     // vice versa
    1400          30 :     const double kNegate = 200.0;
    1401             : 
    1402           0 :     if (aTargetStyle.IsNormal()) {
    1403          30 :         if (minStyle.IsOblique()) {
    1404             :             // to distinguish oblique 0deg from normal, we add 1.0 to the angle
    1405           0 :             const double minAngle = minStyle.ObliqueAngle();
    1406           6 :             if (minAngle >= 0.0) {
    1407           6 :                 return 1.0 + minAngle;
    1408             :             }
    1409           0 :             const FontSlantStyle maxStyle = aFontEntry->SlantStyle().Max();
    1410           0 :             const double maxAngle = maxStyle.ObliqueAngle();
    1411           0 :             if (maxAngle >= 0.0) {
    1412             :                 // [min,max] range includes 0.0, so just return our minimum
    1413             :                 return 1.0;
    1414             :             }
    1415             :             // negative oblique is even worse than italic
    1416           0 :             return kNegate - maxAngle;
    1417             :         }
    1418             :         // must be italic, which is worse than any non-negative oblique;
    1419             :         // treat as a match in the wrong search direction
    1420          24 :         MOZ_ASSERT(minStyle.IsItalic());
    1421             :         return kReverse;
    1422             :     }
    1423             : 
    1424           0 :     const double kDefaultAngle = FontSlantStyle::Oblique().ObliqueAngle();
    1425             : 
    1426           0 :     if (aTargetStyle.IsItalic()) {
    1427           0 :         if (minStyle.IsOblique()) {
    1428           0 :             const double minAngle = minStyle.ObliqueAngle();
    1429           0 :             if (minAngle >= kDefaultAngle) {
    1430           0 :                 return 1.0 + (minAngle - kDefaultAngle);
    1431             :             }
    1432           0 :             const FontSlantStyle maxStyle = aFontEntry->SlantStyle().Max();
    1433           0 :             const double maxAngle = maxStyle.ObliqueAngle();
    1434           0 :             if (maxAngle >= kDefaultAngle) {
    1435             :                 return 1.0;
    1436             :             }
    1437           0 :             if (maxAngle > 0.0) {
    1438             :                 // wrong direction but still > 0, add bias of 100
    1439           0 :                 return kReverse + (kDefaultAngle - maxAngle);
    1440             :             }
    1441             :             // negative oblique angle, add bias of 300
    1442           0 :             return kReverse + kNegate + (kDefaultAngle - maxAngle);
    1443             :         }
    1444             :         // normal is worse than oblique > 0, but better than oblique <= 0
    1445           0 :         MOZ_ASSERT(minStyle.IsNormal());
    1446             :         return kNegate;
    1447             :     }
    1448             : 
    1449             :     // target is oblique <angle>: four different cases depending on
    1450             :     // the value of the <angle>, which determines the preferred direction
    1451             :     // of search
    1452           0 :     const double targetAngle = aTargetStyle.ObliqueAngle();
    1453           0 :     if (targetAngle >= kDefaultAngle) {
    1454           0 :         if (minStyle.IsOblique()) {
    1455           0 :             const double minAngle = minStyle.ObliqueAngle();
    1456           0 :             if (minAngle >= targetAngle) {
    1457           0 :                 return minAngle - targetAngle;
    1458             :             }
    1459           0 :             const FontSlantStyle maxStyle = aFontEntry->SlantStyle().Max();
    1460           0 :             const double maxAngle = maxStyle.ObliqueAngle();
    1461           0 :             if (maxAngle >= targetAngle) {
    1462             :                 return 0.0;
    1463             :             }
    1464           0 :             if (maxAngle > 0.0) {
    1465           0 :                 return kReverse + (targetAngle - maxAngle);
    1466             :             }
    1467           0 :             return kReverse + kNegate + (targetAngle - maxAngle);
    1468             :         }
    1469           0 :         if (minStyle.IsItalic()) {
    1470             :             return kReverse + kNegate;
    1471             :         }
    1472           0 :         return kReverse + kNegate + 1.0;
    1473             :     }
    1474             : 
    1475           0 :     if (targetAngle <= -kDefaultAngle) {
    1476           0 :         if (minStyle.IsOblique()) {
    1477           0 :             const FontSlantStyle maxStyle = aFontEntry->SlantStyle().Max();
    1478           0 :             const double maxAngle = maxStyle.ObliqueAngle();
    1479           0 :             if (maxAngle <= targetAngle) {
    1480           0 :                 return targetAngle - maxAngle;
    1481             :             }
    1482           0 :             const double minAngle = minStyle.ObliqueAngle();
    1483           0 :             if (minAngle <= targetAngle) {
    1484             :                 return 0.0;
    1485             :             }
    1486           0 :             if (minAngle < 0.0) {
    1487           0 :                 return kReverse + (minAngle - targetAngle);
    1488             :             }
    1489           0 :             return kReverse + kNegate + (minAngle - targetAngle);
    1490             :         }
    1491           0 :         if (minStyle.IsItalic()) {
    1492             :             return kReverse + kNegate;
    1493             :         }
    1494           0 :         return kReverse + kNegate + 1.0;
    1495             :     }
    1496             : 
    1497           0 :     if (targetAngle >= 0.0) {
    1498           0 :         if (minStyle.IsOblique()) {
    1499           0 :             const double minAngle = minStyle.ObliqueAngle();
    1500           0 :             if (minAngle > targetAngle) {
    1501           0 :                 return kReverse + (minAngle - targetAngle);
    1502             :             }
    1503           0 :             const FontSlantStyle maxStyle = aFontEntry->SlantStyle().Max();
    1504           0 :             const double maxAngle = maxStyle.ObliqueAngle();
    1505           0 :             if (maxAngle >= targetAngle) {
    1506             :                 return 0.0;
    1507             :             }
    1508           0 :             if (maxAngle > 0.0) {
    1509           0 :                 return targetAngle - maxAngle;
    1510             :             }
    1511           0 :             return kReverse + kNegate + (targetAngle - maxAngle);
    1512             :         }
    1513           0 :         if (minStyle.IsItalic()) {
    1514             :             return kReverse + kNegate - 2.0;
    1515             :         }
    1516           0 :         return kReverse + kNegate - 1.0;
    1517             :     }
    1518             : 
    1519             :     // last case: (targetAngle < 0.0 && targetAngle > kDefaultAngle)
    1520           0 :     if (minStyle.IsOblique()) {
    1521           0 :         const FontSlantStyle maxStyle = aFontEntry->SlantStyle().Max();
    1522           0 :         const double maxAngle = maxStyle.ObliqueAngle();
    1523           0 :         if (maxAngle < targetAngle) {
    1524           0 :             return kReverse + (targetAngle - maxAngle);
    1525             :         }
    1526           0 :         const double minAngle = minStyle.ObliqueAngle();
    1527           0 :         if (minAngle <= targetAngle) {
    1528             :             return 0.0;
    1529             :         }
    1530           0 :         if (minAngle < 0.0) {
    1531           0 :             return minAngle - targetAngle;
    1532             :         }
    1533           0 :         return kReverse + kNegate + (minAngle - targetAngle);
    1534             :     }
    1535           0 :     if (minStyle.IsItalic()) {
    1536             :         return kReverse + kNegate - 2.0;
    1537             :     }
    1538           0 :     return kReverse + kNegate - 1.0;
    1539             : }
    1540             : 
    1541             : // stretch distance ==> [0,2000]
    1542             : static inline double
    1543          61 : StretchDistance(const gfxFontEntry* aFontEntry, FontStretch aTargetStretch)
    1544             : {
    1545           0 :     const double kReverseDistance = 1000.0;
    1546             : 
    1547          61 :     FontStretch minStretch = aFontEntry->Stretch().Min();
    1548          61 :     FontStretch maxStretch = aFontEntry->Stretch().Max();
    1549             : 
    1550             :     // The stretch value is a (non-negative) percentage; currently we support
    1551             :     // values in the range 0 .. 1000. (If the upper limit is ever increased,
    1552             :     // the kReverseDistance value used here may need to be adjusted.)
    1553             :     // If aTargetStretch is >100, we prefer larger values if available;
    1554             :     // if <=100, we prefer smaller values if available.
    1555          61 :     if (aTargetStretch < minStretch) {
    1556           0 :         if (aTargetStretch > FontStretch::Normal()) {
    1557           0 :             return minStretch - aTargetStretch;
    1558             :         }
    1559           0 :         return (minStretch - aTargetStretch) + kReverseDistance;
    1560             :     }
    1561          61 :     if (aTargetStretch > maxStretch) {
    1562          28 :         if (aTargetStretch <= FontStretch::Normal()) {
    1563          28 :             return aTargetStretch - maxStretch;
    1564             :         }
    1565           0 :         return (aTargetStretch - maxStretch) + kReverseDistance;
    1566             :     }
    1567             :     return 0.0;
    1568             : }
    1569             : 
    1570             : // Calculate weight distance with values in the range (0..1000). In general,
    1571             : // heavier weights match towards even heavier weights while lighter weights
    1572             : // match towards even lighter weights. Target weight values in the range
    1573             : // [400..500] are special, since they will first match up to 500, then down
    1574             : // towards 0, then up again towards 999.
    1575             : //
    1576             : // Example: with target 600 and font weight 800, distance will be 200. With
    1577             : // target 300 and font weight 600, distance will be 900, since heavier
    1578             : // weights are farther away than lighter weights. If the target is 5 and the
    1579             : // font weight 995, the distance would be 1590 for the same reason.
    1580             : 
    1581             : // weight distance ==> [0,1600]
    1582             : static inline double
    1583           0 : WeightDistance(const gfxFontEntry* aFontEntry, FontWeight aTargetWeight)
    1584             : {
    1585           0 :     const double kNotWithinCentralRange = 100.0;
    1586          61 :     const double kReverseDistance = 600.0;
    1587             : 
    1588           0 :     FontWeight minWeight = aFontEntry->Weight().Min();
    1589           0 :     FontWeight maxWeight = aFontEntry->Weight().Max();
    1590             : 
    1591           0 :     if (aTargetWeight >= minWeight && aTargetWeight <= maxWeight) {
    1592             :         // Target is within the face's range, so it's a perfect match
    1593             :         return 0.0;
    1594             :     }
    1595             : 
    1596          62 :     if (aTargetWeight < FontWeight(400)) {
    1597             :         // Requested a lighter-than-400 weight
    1598           0 :         if (maxWeight < aTargetWeight) {
    1599           0 :             return aTargetWeight - maxWeight;
    1600             :         }
    1601             :         // Add reverse-search penalty for bolder faces
    1602           0 :         return (minWeight - aTargetWeight) + kReverseDistance;
    1603             :     }
    1604             : 
    1605           0 :     if (aTargetWeight > FontWeight(500)) {
    1606             :         // Requested a bolder-than-500 weight
    1607           0 :         if (minWeight > aTargetWeight) {
    1608           0 :             return minWeight - aTargetWeight;
    1609             :         }
    1610             :         // Add reverse-search penalty for lighter faces
    1611           0 :         return (aTargetWeight - maxWeight) + kReverseDistance;
    1612             :     }
    1613             : 
    1614             :     // Special case for requested weight in the [400..500] range
    1615          31 :     if (minWeight > aTargetWeight) {
    1616          60 :         if (minWeight <= FontWeight(500)) {
    1617             :             // Bolder weight up to 500 is first choice
    1618           0 :             return minWeight - aTargetWeight;
    1619             :         }
    1620             :         // Other bolder weights get a reverse-search penalty
    1621          30 :         return (minWeight - aTargetWeight) + kReverseDistance;
    1622             :     }
    1623             :     // Lighter weights are not as good as bolder ones within [400..500]
    1624           1 :     return (aTargetWeight - maxWeight) + kNotWithinCentralRange;
    1625             : }
    1626             : 
    1627             : static inline double
    1628           0 : WeightStyleStretchDistance(gfxFontEntry* aFontEntry,
    1629             :                            const gfxFontStyle& aTargetStyle)
    1630             : {
    1631           0 :     double stretchDist = StretchDistance(aFontEntry, aTargetStyle.stretch);
    1632           0 :     double styleDist = StyleDistance(aFontEntry, aTargetStyle.style);
    1633          61 :     double weightDist = WeightDistance(aFontEntry, aTargetStyle.weight);
    1634             : 
    1635             :     // Sanity-check that the distances are within the expected range
    1636             :     // (update if implementation of the distance functions is changed).
    1637           0 :     MOZ_ASSERT(stretchDist >= 0.0 && stretchDist <= 2000.0);
    1638           0 :     MOZ_ASSERT(styleDist >= 0.0 && styleDist <= 500.0);
    1639          61 :     MOZ_ASSERT(weightDist >= 0.0 && weightDist <= 1600.0);
    1640             : 
    1641             :     // weight/style/stretch priority: stretch >> style >> weight
    1642             :     // so we multiply the stretch and style values to make them dominate
    1643             :     // the result
    1644          61 :     return stretchDist * 1.0e8 + styleDist * 1.0e4 + weightDist;
    1645             : }
    1646             : 
    1647             : void
    1648          18 : gfxFontFamily::FindAllFontsForStyle(const gfxFontStyle& aFontStyle,
    1649             :                                     nsTArray<gfxFontEntry*>& aFontEntryList,
    1650             :                                     bool aIgnoreSizeTolerance)
    1651             : {
    1652           0 :     if (!mHasStyles) {
    1653           0 :         FindStyleVariations(); // collect faces for the family, if not already done
    1654             :     }
    1655             : 
    1656          36 :     NS_ASSERTION(mAvailableFonts.Length() > 0, "font family with no faces!");
    1657           0 :     NS_ASSERTION(aFontEntryList.IsEmpty(), "non-empty fontlist passed in");
    1658             : 
    1659          18 :     gfxFontEntry *fe = nullptr;
    1660             : 
    1661             :     // If the family has only one face, we simply return it; no further
    1662             :     // checking needed
    1663          36 :     uint32_t count = mAvailableFonts.Length();
    1664           0 :     if (count == 1) {
    1665           0 :         fe = mAvailableFonts[0];
    1666           0 :         aFontEntryList.AppendElement(fe);
    1667           0 :         return;
    1668             :     }
    1669             : 
    1670             :     // Most families are "simple", having just Regular/Bold/Italic/BoldItalic,
    1671             :     // or some subset of these. In this case, we have exactly 4 entries in mAvailableFonts,
    1672             :     // stored in the above order; note that some of the entries may be nullptr.
    1673             :     // We can then pick the required entry based on whether the request is for
    1674             :     // bold or non-bold, italic or non-italic, without running the more complex
    1675             :     // matching algorithm used for larger families with many weights and/or widths.
    1676             : 
    1677          18 :     if (mIsSimpleFamily) {
    1678             :         // Family has no more than the "standard" 4 faces, at fixed indexes;
    1679             :         // calculate which one we want.
    1680             :         // Note that we cannot simply return it as not all 4 faces are necessarily present.
    1681           0 :         bool wantBold = aFontStyle.weight >= FontWeight(600);
    1682           0 :         bool wantItalic = !aFontStyle.style.IsNormal();
    1683           0 :         uint8_t faceIndex = (wantItalic ? kItalicMask : 0) |
    1684          10 :                             (wantBold ? kBoldMask : 0);
    1685             : 
    1686             :         // if the desired style is available, return it directly
    1687           0 :         fe = mAvailableFonts[faceIndex];
    1688          10 :         if (fe) {
    1689          10 :             aFontEntryList.AppendElement(fe);
    1690           0 :             return;
    1691             :         }
    1692             : 
    1693             :         // order to check fallback faces in a simple family, depending on requested style
    1694             :         static const uint8_t simpleFallbacks[4][3] = {
    1695             :             { kBoldFaceIndex, kItalicFaceIndex, kBoldItalicFaceIndex },   // fallbacks for Regular
    1696             :             { kRegularFaceIndex, kBoldItalicFaceIndex, kItalicFaceIndex },// Bold
    1697             :             { kBoldItalicFaceIndex, kRegularFaceIndex, kBoldFaceIndex },  // Italic
    1698             :             { kItalicFaceIndex, kBoldFaceIndex, kRegularFaceIndex }       // BoldItalic
    1699             :         };
    1700           0 :         const uint8_t *order = simpleFallbacks[faceIndex];
    1701             : 
    1702           0 :         for (uint8_t trial = 0; trial < 3; ++trial) {
    1703             :             // check remaining faces in order of preference to find the first that actually exists
    1704           0 :             fe = mAvailableFonts[order[trial]];
    1705           0 :             if (fe) {
    1706           0 :                 aFontEntryList.AppendElement(fe);
    1707           0 :                 return;
    1708             :             }
    1709             :         }
    1710             : 
    1711             :         // this can't happen unless we have totally broken the font-list manager!
    1712           0 :         NS_NOTREACHED("no face found in simple font family!");
    1713             :     }
    1714             : 
    1715             :     // Pick the font(s) that are closest to the desired weight, style, and
    1716             :     // stretch. Iterate over all fonts, measuring the weight/style distance.
    1717             :     // Because of unicode-range values, there may be more than one font for a
    1718             :     // given but the 99% use case is only a single font entry per
    1719             :     // weight/style/stretch distance value. To optimize this, only add entries
    1720             :     // to the matched font array when another entry already has the same
    1721             :     // weight/style/stretch distance and add the last matched font entry. For
    1722             :     // normal platform fonts with a single font entry for each
    1723             :     // weight/style/stretch combination, only the last matched font entry will
    1724             :     // be added.
    1725             : 
    1726           8 :     double minDistance = INFINITY;
    1727           8 :     gfxFontEntry* matched = nullptr;
    1728             :     // iterate in forward order so that faces like 'Bold' are matched before
    1729             :     // matching style distance faces such as 'Bold Outline' (see bug 1185812)
    1730          69 :     for (uint32_t i = 0; i < count; i++) {
    1731           0 :         fe = mAvailableFonts[i];
    1732             :         // weight/style/stretch priority: stretch >> style >> weight
    1733          61 :         double distance = WeightStyleStretchDistance(fe, aFontStyle);
    1734           0 :         if (distance < minDistance) {
    1735           0 :             matched = fe;
    1736          30 :             if (!aFontEntryList.IsEmpty()) {
    1737           0 :                 aFontEntryList.Clear();
    1738             :             }
    1739             :             minDistance = distance;
    1740           0 :         } else if (distance == minDistance) {
    1741           0 :             if (matched) {
    1742           0 :                 aFontEntryList.AppendElement(matched);
    1743             :             }
    1744           0 :             matched = fe;
    1745             :         }
    1746             :     }
    1747             : 
    1748           0 :     NS_ASSERTION(matched, "didn't match a font within a family");
    1749             : 
    1750           8 :     if (matched) {
    1751           8 :         aFontEntryList.AppendElement(matched);
    1752             :     }
    1753             : }
    1754             : 
    1755             : void
    1756           6 : gfxFontFamily::CheckForSimpleFamily()
    1757             : {
    1758             :     // already checked this family
    1759           0 :     if (mIsSimpleFamily) {
    1760           1 :         return;
    1761             :     }
    1762             : 
    1763          12 :     uint32_t count = mAvailableFonts.Length();
    1764           6 :     if (count > 4 || count == 0) {
    1765             :         return; // can't be "simple" if there are >4 faces;
    1766             :                 // if none then the family is unusable anyway
    1767             :     }
    1768             : 
    1769           3 :     if (count == 1) {
    1770           0 :         mIsSimpleFamily = true;
    1771           0 :         return;
    1772             :     }
    1773             : 
    1774           6 :     StretchRange firstStretch = mAvailableFonts[0]->Stretch();
    1775           0 :     if (!firstStretch.IsSingle()) {
    1776             :         return; // family with variation fonts is not considered "simple"
    1777             :     }
    1778             : 
    1779           0 :     gfxFontEntry *faces[4] = { 0 };
    1780          10 :     for (uint8_t i = 0; i < count; ++i) {
    1781          24 :         gfxFontEntry *fe = mAvailableFonts[i];
    1782           0 :         if (fe->Stretch() != firstStretch || fe->IsOblique()) {
    1783             :             // simple families don't have varying font-stretch or oblique
    1784             :             return;
    1785             :         }
    1786          21 :         if (!fe->Weight().IsSingle() || !fe->SlantStyle().IsSingle()) {
    1787             :             return; // family with variation fonts is not considered "simple"
    1788             :         }
    1789           0 :         uint8_t faceIndex = (fe->IsItalic() ? kItalicMask : 0) |
    1790           0 :                             (fe->SupportsBold() ? kBoldMask : 0);
    1791           0 :         if (faces[faceIndex]) {
    1792             :             return; // two faces resolve to the same slot; family isn't "simple"
    1793             :         }
    1794           7 :         faces[faceIndex] = fe;
    1795             :     }
    1796             : 
    1797             :     // we have successfully slotted the available faces into the standard
    1798             :     // 4-face framework
    1799           2 :     mAvailableFonts.SetLength(4);
    1800           0 :     for (uint8_t i = 0; i < 4; ++i) {
    1801           0 :         if (mAvailableFonts[i].get() != faces[i]) {
    1802           0 :             mAvailableFonts[i].swap(faces[i]);
    1803             :         }
    1804             :     }
    1805             : 
    1806           0 :     mIsSimpleFamily = true;
    1807             : }
    1808             : 
    1809             : #ifdef DEBUG
    1810             : bool
    1811           0 : gfxFontFamily::ContainsFace(gfxFontEntry* aFontEntry) {
    1812          36 :     uint32_t i, numFonts = mAvailableFonts.Length();
    1813          37 :     for (i = 0; i < numFonts; i++) {
    1814         111 :         if (mAvailableFonts[i] == aFontEntry) {
    1815             :             return true;
    1816             :         }
    1817             :         // userfonts contain the actual real font entry
    1818           0 :         if (mAvailableFonts[i] && mAvailableFonts[i]->mIsUserFontContainer) {
    1819             :             gfxUserFontEntry* ufe =
    1820           0 :                 static_cast<gfxUserFontEntry*>(mAvailableFonts[i].get());
    1821           0 :             if (ufe->GetPlatformFontEntry() == aFontEntry) {
    1822             :                 return true;
    1823             :             }
    1824             :         }
    1825             :     }
    1826             :     return false;
    1827             : }
    1828             : #endif
    1829             : 
    1830           0 : void gfxFontFamily::LocalizedName(nsAString& aLocalizedName)
    1831             : {
    1832             :     // just return the primary name; subclasses should override
    1833           0 :     aLocalizedName = mName;
    1834           0 : }
    1835             : 
    1836             : void
    1837           0 : gfxFontFamily::FindFontForChar(GlobalFontMatch* aMatchData)
    1838             : {
    1839           0 :     if (mFamilyCharacterMapInitialized && !TestCharacterMap(aMatchData->mCh)) {
    1840             :         // none of the faces in the family support the required char,
    1841             :         // so bail out immediately
    1842             :         return;
    1843             :     }
    1844             : 
    1845             :     gfxFontEntry* fe =
    1846           0 :         FindFontForStyle(aMatchData->mStyle, /*aIgnoreSizeTolerance*/ true);
    1847           0 :     if (!fe || fe->SkipDuringSystemFallback()) {
    1848             :         return;
    1849             :     }
    1850             : 
    1851           0 :     float distance = INFINITY;
    1852             : 
    1853           0 :     if (fe->HasCharacter(aMatchData->mCh)) {
    1854           0 :         aMatchData->mCount++;
    1855             : 
    1856           0 :         LogModule* log = gfxPlatform::GetLog(eGfxLog_textrun);
    1857             : 
    1858           0 :         if (MOZ_UNLIKELY(MOZ_LOG_TEST(log, LogLevel::Debug))) {
    1859           0 :             uint32_t unicodeRange = FindCharUnicodeRange(aMatchData->mCh);
    1860           0 :             Script script = GetScriptCode(aMatchData->mCh);
    1861           0 :             MOZ_LOG(log, LogLevel::Debug,\
    1862             :                    ("(textrun-systemfallback-fonts) char: u+%6.6x "
    1863             :                     "unicode-range: %d script: %d match: [%s]\n",
    1864             :                     aMatchData->mCh,
    1865             :                     unicodeRange, int(script),
    1866             :                     NS_ConvertUTF16toUTF8(fe->Name()).get()));
    1867             :         }
    1868             : 
    1869           0 :         distance = WeightStyleStretchDistance(fe, aMatchData->mStyle);
    1870           0 :     } else if (!fe->IsNormalStyle()) {
    1871             :         // If style/weight/stretch was not Normal, see if we can
    1872             :         // fall back to a next-best face (e.g. Arial Black -> Bold,
    1873             :         // or Arial Narrow -> Regular).
    1874           0 :         GlobalFontMatch data(aMatchData->mCh, aMatchData->mStyle);
    1875           0 :         SearchAllFontsForChar(&data);
    1876           0 :         if (std::isfinite(data.mMatchDistance)) {
    1877           0 :             fe = data.mBestMatch;
    1878           0 :             distance = data.mMatchDistance;
    1879             :         }
    1880             :     }
    1881           0 :     aMatchData->mCmapsTested++;
    1882             : 
    1883           0 :     if (std::isinf(distance)) {
    1884             :         return;
    1885             :     }
    1886             : 
    1887           0 :     if (distance < aMatchData->mMatchDistance ||
    1888           0 :         (distance == aMatchData->mMatchDistance &&
    1889           0 :          Compare(fe->Name(), aMatchData->mBestMatch->Name()) > 0)) {
    1890           0 :         aMatchData->mBestMatch = fe;
    1891           0 :         aMatchData->mMatchedFamily = this;
    1892           0 :         aMatchData->mMatchDistance = distance;
    1893             :     }
    1894             : }
    1895             : 
    1896             : void
    1897           0 : gfxFontFamily::SearchAllFontsForChar(GlobalFontMatch* aMatchData)
    1898             : {
    1899           0 :     uint32_t i, numFonts = mAvailableFonts.Length();
    1900           0 :     for (i = 0; i < numFonts; i++) {
    1901           0 :         gfxFontEntry *fe = mAvailableFonts[i];
    1902           0 :         if (fe && fe->HasCharacter(aMatchData->mCh)) {
    1903           0 :             float distance = WeightStyleStretchDistance(fe, aMatchData->mStyle);
    1904           0 :             if (distance < aMatchData->mMatchDistance
    1905           0 :                 || (distance == aMatchData->mMatchDistance &&
    1906           0 :                     Compare(fe->Name(), aMatchData->mBestMatch->Name()) > 0))
    1907             :             {
    1908           0 :                 aMatchData->mBestMatch = fe;
    1909           0 :                 aMatchData->mMatchedFamily = this;
    1910           0 :                 aMatchData->mMatchDistance = distance;
    1911             :             }
    1912             :         }
    1913             :     }
    1914           0 : }
    1915             : 
    1916             : /*virtual*/
    1917           0 : gfxFontFamily::~gfxFontFamily()
    1918             : {
    1919             :     // Should not be dropped by stylo
    1920           0 :     MOZ_ASSERT(NS_IsMainThread());
    1921           0 : }
    1922             : 
    1923             : /*static*/ void
    1924           0 : gfxFontFamily::ReadOtherFamilyNamesForFace(const nsAString& aFamilyName,
    1925             :                                            const char *aNameData,
    1926             :                                            uint32_t aDataLength,
    1927             :                                            nsTArray<nsString>& aOtherFamilyNames,
    1928             :                                            bool useFullName)
    1929             : {
    1930             :     const gfxFontUtils::NameHeader *nameHeader =
    1931           0 :         reinterpret_cast<const gfxFontUtils::NameHeader*>(aNameData);
    1932             : 
    1933           0 :     uint32_t nameCount = nameHeader->count;
    1934           0 :     if (nameCount * sizeof(gfxFontUtils::NameRecord) > aDataLength) {
    1935           0 :         NS_WARNING("invalid font (name records)");
    1936           0 :         return;
    1937             :     }
    1938             :     
    1939             :     const gfxFontUtils::NameRecord *nameRecord =
    1940           0 :         reinterpret_cast<const gfxFontUtils::NameRecord*>(aNameData + sizeof(gfxFontUtils::NameHeader));
    1941           0 :     uint32_t stringsBase = uint32_t(nameHeader->stringOffset);
    1942             : 
    1943           0 :     for (uint32_t i = 0; i < nameCount; i++, nameRecord++) {
    1944           0 :         uint32_t nameLen = nameRecord->length;
    1945           0 :         uint32_t nameOff = nameRecord->offset;  // offset from base of string storage
    1946             : 
    1947           0 :         if (stringsBase + nameOff + nameLen > aDataLength) {
    1948           0 :             NS_WARNING("invalid font (name table strings)");
    1949           0 :             return;
    1950             :         }
    1951             : 
    1952           0 :         uint16_t nameID = nameRecord->nameID;
    1953           0 :         if ((useFullName && nameID == gfxFontUtils::NAME_ID_FULL) ||
    1954           0 :             (!useFullName && (nameID == gfxFontUtils::NAME_ID_FAMILY ||
    1955           0 :                               nameID == gfxFontUtils::NAME_ID_PREFERRED_FAMILY))) {
    1956           0 :             nsAutoString otherFamilyName;
    1957           0 :             bool ok = gfxFontUtils::DecodeFontName(aNameData + stringsBase + nameOff,
    1958             :                                                      nameLen,
    1959             :                                                      uint32_t(nameRecord->platformID),
    1960             :                                                      uint32_t(nameRecord->encodingID),
    1961             :                                                      uint32_t(nameRecord->languageID),
    1962           0 :                                                      otherFamilyName);
    1963             :             // add if not same as canonical family name
    1964           0 :             if (ok && otherFamilyName != aFamilyName) {
    1965           0 :                 aOtherFamilyNames.AppendElement(otherFamilyName);
    1966             :             }
    1967             :         }
    1968             :     }
    1969             : }
    1970             : 
    1971             : // returns true if other names were found, false otherwise
    1972             : bool
    1973           0 : gfxFontFamily::ReadOtherFamilyNamesForFace(gfxPlatformFontList *aPlatformFontList,
    1974             :                                            hb_blob_t           *aNameTable,
    1975             :                                            bool                 useFullName)
    1976             : {
    1977             :     uint32_t dataLength;
    1978           0 :     const char *nameData = hb_blob_get_data(aNameTable, &dataLength);
    1979           0 :     AutoTArray<nsString,4> otherFamilyNames;
    1980             : 
    1981           0 :     ReadOtherFamilyNamesForFace(mName, nameData, dataLength,
    1982           0 :                                 otherFamilyNames, useFullName);
    1983             : 
    1984           0 :     uint32_t n = otherFamilyNames.Length();
    1985           0 :     for (uint32_t i = 0; i < n; i++) {
    1986           0 :         aPlatformFontList->AddOtherFamilyName(this, otherFamilyNames[i]);
    1987             :     }
    1988             : 
    1989           0 :     return n != 0;
    1990             : }
    1991             : 
    1992             : void
    1993           0 : gfxFontFamily::ReadOtherFamilyNames(gfxPlatformFontList *aPlatformFontList)
    1994             : {
    1995           0 :     if (mOtherFamilyNamesInitialized) 
    1996             :         return;
    1997           0 :     mOtherFamilyNamesInitialized = true;
    1998             : 
    1999           0 :     FindStyleVariations();
    2000             : 
    2001             :     // read in other family names for the first face in the list
    2002           0 :     uint32_t i, numFonts = mAvailableFonts.Length();
    2003           0 :     const uint32_t kNAME = TRUETYPE_TAG('n','a','m','e');
    2004             : 
    2005           0 :     for (i = 0; i < numFonts; ++i) {
    2006           0 :         gfxFontEntry *fe = mAvailableFonts[i];
    2007           0 :         if (!fe) {
    2008           0 :             continue;
    2009             :         }
    2010           0 :         gfxFontEntry::AutoTable nameTable(fe, kNAME);
    2011           0 :         if (!nameTable) {
    2012           0 :             continue;
    2013             :         }
    2014           0 :         mHasOtherFamilyNames = ReadOtherFamilyNamesForFace(aPlatformFontList,
    2015             :                                                            nameTable);
    2016           0 :         break;
    2017             :     }
    2018             : 
    2019             :     // read in other names for the first face in the list with the assumption
    2020             :     // that if extra names don't exist in that face then they don't exist in
    2021             :     // other faces for the same font
    2022           0 :     if (!mHasOtherFamilyNames) 
    2023             :         return;
    2024             : 
    2025             :     // read in names for all faces, needed to catch cases where fonts have
    2026             :     // family names for individual weights (e.g. Hiragino Kaku Gothic Pro W6)
    2027           0 :     for ( ; i < numFonts; i++) {
    2028           0 :         gfxFontEntry *fe = mAvailableFonts[i];
    2029           0 :         if (!fe) {
    2030           0 :             continue;
    2031             :         }
    2032           0 :         gfxFontEntry::AutoTable nameTable(fe, kNAME);
    2033           0 :         if (!nameTable) {
    2034           0 :             continue;
    2035             :         }
    2036           0 :         ReadOtherFamilyNamesForFace(aPlatformFontList, nameTable);
    2037             :     }
    2038             : }
    2039             : 
    2040             : static bool
    2041           0 : LookForLegacyFamilyName(const nsAString& aCanonicalName,
    2042             :                         const char* aNameData,
    2043             :                         uint32_t aDataLength,
    2044             :                         nsAString& aLegacyName /* outparam */)
    2045             : {
    2046             :     const gfxFontUtils::NameHeader* nameHeader =
    2047           0 :         reinterpret_cast<const gfxFontUtils::NameHeader*>(aNameData);
    2048             : 
    2049           0 :     uint32_t nameCount = nameHeader->count;
    2050           0 :     if (nameCount * sizeof(gfxFontUtils::NameRecord) > aDataLength) {
    2051           0 :         NS_WARNING("invalid font (name records)");
    2052           0 :         return false;
    2053             :     }
    2054             : 
    2055             :     const gfxFontUtils::NameRecord* nameRecord =
    2056             :         reinterpret_cast<const gfxFontUtils::NameRecord*>
    2057           0 :             (aNameData + sizeof(gfxFontUtils::NameHeader));
    2058           0 :     uint32_t stringsBase = uint32_t(nameHeader->stringOffset);
    2059             : 
    2060           0 :     for (uint32_t i = 0; i < nameCount; i++, nameRecord++) {
    2061           0 :         uint32_t nameLen = nameRecord->length;
    2062           0 :         uint32_t nameOff = nameRecord->offset;
    2063             : 
    2064           0 :         if (stringsBase + nameOff + nameLen > aDataLength) {
    2065           0 :             NS_WARNING("invalid font (name table strings)");
    2066           0 :             return false;
    2067             :         }
    2068             : 
    2069           0 :         if (uint16_t(nameRecord->nameID) == gfxFontUtils::NAME_ID_FAMILY) {
    2070             :             bool ok =
    2071           0 :                 gfxFontUtils::DecodeFontName(aNameData + stringsBase + nameOff,
    2072             :                                              nameLen,
    2073             :                                              uint32_t(nameRecord->platformID),
    2074             :                                              uint32_t(nameRecord->encodingID),
    2075             :                                              uint32_t(nameRecord->languageID),
    2076           0 :                                              aLegacyName);
    2077             :             // it's only a legacy name if it differs from the canonical name
    2078           0 :             if (ok && aLegacyName != aCanonicalName) {
    2079             :                 return true;
    2080             :             }
    2081             :         }
    2082             :     }
    2083             :     return false;
    2084             : }
    2085             : 
    2086             : bool
    2087           0 : gfxFontFamily::CheckForLegacyFamilyNames(gfxPlatformFontList* aFontList)
    2088             : {
    2089           0 :     if (mCheckedForLegacyFamilyNames) {
    2090             :         // we already did this, so there's nothing more to add
    2091             :         return false;
    2092             :     }
    2093           0 :     mCheckedForLegacyFamilyNames = true;
    2094           0 :     bool added = false;
    2095           0 :     const uint32_t kNAME = TRUETYPE_TAG('n','a','m','e');
    2096             :     // Make a local copy of the array of font faces, in case of changes
    2097             :     // during the iteration.
    2098           0 :     AutoTArray<RefPtr<gfxFontEntry>,8> faces(mAvailableFonts);
    2099           0 :     for (auto& fe : faces) {
    2100           0 :         if (!fe) {
    2101           0 :             continue;
    2102             :         }
    2103           0 :         gfxFontEntry::AutoTable nameTable(fe, kNAME);
    2104           0 :         if (!nameTable) {
    2105           0 :             continue;
    2106             :         }
    2107           0 :         nsAutoString legacyName;
    2108             :         uint32_t dataLength;
    2109           0 :         const char* nameData = hb_blob_get_data(nameTable, &dataLength);
    2110           0 :         if (LookForLegacyFamilyName(Name(), nameData, dataLength,
    2111             :                                     legacyName)) {
    2112           0 :             if (aFontList->AddWithLegacyFamilyName(legacyName, fe)) {
    2113           0 :                 added = true;
    2114             :             }
    2115             :         }
    2116             :     }
    2117           0 :     return added;
    2118             : }
    2119             : 
    2120             : void
    2121           0 : gfxFontFamily::ReadFaceNames(gfxPlatformFontList *aPlatformFontList, 
    2122             :                              bool aNeedFullnamePostscriptNames,
    2123             :                              FontInfoData *aFontInfoData)
    2124             : {
    2125             :     // if all needed names have already been read, skip
    2126           0 :     if (mOtherFamilyNamesInitialized &&
    2127           0 :         (mFaceNamesInitialized || !aNeedFullnamePostscriptNames))
    2128             :         return;
    2129             : 
    2130           0 :     bool asyncFontLoaderDisabled = false;
    2131             : 
    2132           0 :     if (!mOtherFamilyNamesInitialized &&
    2133           0 :         aFontInfoData &&
    2134           0 :         aFontInfoData->mLoadOtherNames &&
    2135             :         !asyncFontLoaderDisabled)
    2136             :     {
    2137           0 :         AutoTArray<nsString,4> otherFamilyNames;
    2138             :         bool foundOtherNames =
    2139           0 :             aFontInfoData->GetOtherFamilyNames(mName, otherFamilyNames);
    2140           0 :         if (foundOtherNames) {
    2141           0 :             uint32_t i, n = otherFamilyNames.Length();
    2142           0 :             for (i = 0; i < n; i++) {
    2143           0 :                 aPlatformFontList->AddOtherFamilyName(this, otherFamilyNames[i]);
    2144             :             }
    2145             :         }
    2146           0 :         mOtherFamilyNamesInitialized = true;
    2147             :     }
    2148             : 
    2149             :     // if all needed data has been initialized, return
    2150           0 :     if (mOtherFamilyNamesInitialized &&
    2151           0 :         (mFaceNamesInitialized || !aNeedFullnamePostscriptNames)) {
    2152             :         return;
    2153             :     }
    2154             : 
    2155           0 :     FindStyleVariations(aFontInfoData);
    2156             : 
    2157             :     // check again, as style enumeration code may have loaded names
    2158           0 :     if (mOtherFamilyNamesInitialized &&
    2159           0 :         (mFaceNamesInitialized || !aNeedFullnamePostscriptNames)) {
    2160             :         return;
    2161             :     }
    2162             : 
    2163           0 :     uint32_t i, numFonts = mAvailableFonts.Length();
    2164           0 :     const uint32_t kNAME = TRUETYPE_TAG('n','a','m','e');
    2165             : 
    2166           0 :     bool firstTime = true, readAllFaces = false;
    2167           0 :     for (i = 0; i < numFonts; ++i) {
    2168           0 :         gfxFontEntry *fe = mAvailableFonts[i];
    2169           0 :         if (!fe) {
    2170           0 :             continue;
    2171             :         }
    2172             : 
    2173           0 :         nsAutoString fullname, psname;
    2174           0 :         bool foundFaceNames = false;
    2175           0 :         if (!mFaceNamesInitialized &&
    2176           0 :             aNeedFullnamePostscriptNames &&
    2177           0 :             aFontInfoData &&
    2178           0 :             aFontInfoData->mLoadFaceNames) {
    2179           0 :             aFontInfoData->GetFaceNames(fe->Name(), fullname, psname);
    2180           0 :             if (!fullname.IsEmpty()) {
    2181           0 :                 aPlatformFontList->AddFullname(fe, fullname);
    2182             :             }
    2183           0 :             if (!psname.IsEmpty()) {
    2184           0 :                 aPlatformFontList->AddPostscriptName(fe, psname);
    2185             :             }
    2186           0 :             foundFaceNames = true;
    2187             : 
    2188             :             // found everything needed? skip to next font
    2189           0 :             if (mOtherFamilyNamesInitialized) {
    2190           0 :                 continue;
    2191             :             }
    2192             :         }
    2193             : 
    2194             :         // load directly from the name table
    2195           0 :         gfxFontEntry::AutoTable nameTable(fe, kNAME);
    2196           0 :         if (!nameTable) {
    2197             :             continue;
    2198             :         }
    2199             : 
    2200             :         if (aNeedFullnamePostscriptNames && !foundFaceNames) {
    2201             :             if (gfxFontUtils::ReadCanonicalName(
    2202             :                     nameTable, gfxFontUtils::NAME_ID_FULL, fullname) == NS_OK)
    2203             :             {
    2204             :                 aPlatformFontList->AddFullname(fe, fullname);
    2205             :             }
    2206             : 
    2207             :             if (gfxFontUtils::ReadCanonicalName(
    2208             :                     nameTable, gfxFontUtils::NAME_ID_POSTSCRIPT, psname) == NS_OK)
    2209             :             {
    2210             :                 aPlatformFontList->AddPostscriptName(fe, psname);
    2211             :             }
    2212             :         }
    2213             : 
    2214             :         if (!mOtherFamilyNamesInitialized && (firstTime || readAllFaces)) {
    2215             :             bool foundOtherName = ReadOtherFamilyNamesForFace(aPlatformFontList,
    2216             :                                                               nameTable);
    2217             : 
    2218             :             // if the first face has a different name, scan all faces, otherwise
    2219             :             // assume the family doesn't have other names
    2220             :             if (firstTime && foundOtherName) {
    2221             :                 mHasOtherFamilyNames = true;
    2222             :                 readAllFaces = true;
    2223             :             }
    2224             :             firstTime = false;
    2225             :         }
    2226             : 
    2227             :         // if not reading in any more names, skip other faces
    2228             :         if (!readAllFaces && !aNeedFullnamePostscriptNames) {
    2229             :             break;
    2230             :         }
    2231             :     }
    2232             : 
    2233             :     mFaceNamesInitialized = true;
    2234             :     mOtherFamilyNamesInitialized = true;
    2235             : }
    2236             : 
    2237             : 
    2238             : gfxFontEntry*
    2239             : gfxFontFamily::FindFont(const nsAString& aPostscriptName)
    2240             : {
    2241             :     // find the font using a simple linear search
    2242             :     uint32_t numFonts = mAvailableFonts.Length();
    2243             :     for (uint32_t i = 0; i < numFonts; i++) {
    2244             :         gfxFontEntry *fe = mAvailableFonts[i].get();
    2245             :         if (fe && fe->Name() == aPostscriptName)
    2246             :             return fe;
    2247             :     }
    2248             :     return nullptr;
    2249             : }
    2250             : 
    2251             : void
    2252             : gfxFontFamily::ReadAllCMAPs(FontInfoData *aFontInfoData)
    2253             : {
    2254             :     FindStyleVariations(aFontInfoData);
    2255             : 
    2256             :     uint32_t i, numFonts = mAvailableFonts.Length();
    2257             :     for (i = 0; i < numFonts; i++) {
    2258             :         gfxFontEntry *fe = mAvailableFonts[i];
    2259             :         // don't try to load cmaps for downloadable fonts not yet loaded
    2260             :         if (!fe || fe->mIsUserFontContainer) {
    2261             :             continue;
    2262             :         }
    2263             :         fe->ReadCMAP(aFontInfoData);
    2264             :         mFamilyCharacterMap.Union(*(fe->mCharacterMap));
    2265             :     }
    2266             :     mFamilyCharacterMap.Compact();
    2267             :     mFamilyCharacterMapInitialized = true;
    2268             : }
    2269             : 
    2270             : void
    2271             : gfxFontFamily::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
    2272             :                                       FontListSizes* aSizes) const
    2273             : {
    2274             :     aSizes->mFontListSize +=
    2275             :         mName.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
    2276             :     aSizes->mCharMapsSize +=
    2277             :         mFamilyCharacterMap.SizeOfExcludingThis(aMallocSizeOf);
    2278             : 
    2279             :     aSizes->mFontListSize +=
    2280             :         mAvailableFonts.ShallowSizeOfExcludingThis(aMallocSizeOf);
    2281             :     for (uint32_t i = 0; i < mAvailableFonts.Length(); ++i) {
    2282             :         gfxFontEntry *fe = mAvailableFonts[i];
    2283             :         if (fe) {
    2284             :             fe->AddSizeOfIncludingThis(aMallocSizeOf, aSizes);
    2285             :         }
    2286             :     }
    2287             : }
    2288             : 
    2289             : void
    2290             : gfxFontFamily::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
    2291             :                                       FontListSizes* aSizes) const
    2292             : {
    2293             :     aSizes->mFontListSize += aMallocSizeOf(this);
    2294             :     AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
    2295             : }

Generated by: LCOV version 1.13-14-ga5dd952