LCOV - code coverage report
Current view: top level - gfx/thebes - gfxFontEntry.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 233 791 29.5 %
Date: 2017-07-14 16:53:18 Functions: 32 83 38.6 %
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 "mozilla/DebugOnly.h"
       7             : #include "mozilla/MathAlgorithms.h"
       8             : 
       9             : #include "mozilla/Logging.h"
      10             : 
      11             : #include "gfxFontEntry.h"
      12             : #include "gfxTextRun.h"
      13             : #include "gfxPlatform.h"
      14             : #include "nsGkAtoms.h"
      15             : 
      16             : #include "gfxTypes.h"
      17             : #include "gfxContext.h"
      18             : #include "gfxFontConstants.h"
      19             : #include "gfxHarfBuzzShaper.h"
      20             : #include "gfxUserFontSet.h"
      21             : #include "gfxPlatformFontList.h"
      22             : #include "nsUnicodeProperties.h"
      23             : #include "nsMathUtils.h"
      24             : #include "nsBidiUtils.h"
      25             : #include "nsUnicodeRange.h"
      26             : #include "nsStyleConsts.h"
      27             : #include "mozilla/AppUnits.h"
      28             : #include "mozilla/FloatingPoint.h"
      29             : #include "mozilla/Likely.h"
      30             : #include "mozilla/MemoryReporting.h"
      31             : #include "mozilla/Preferences.h"
      32             : #include "mozilla/Services.h"
      33             : #include "mozilla/Telemetry.h"
      34             : #include "gfxSVGGlyphs.h"
      35             : #include "gfx2DGlue.h"
      36             : 
      37             : #include "cairo.h"
      38             : 
      39             : #include "harfbuzz/hb.h"
      40             : #include "harfbuzz/hb-ot.h"
      41             : #include "graphite2/Font.h"
      42             : 
      43             : #include <algorithm>
      44             : 
      45             : using namespace mozilla;
      46             : using namespace mozilla::gfx;
      47             : using namespace mozilla::unicode;
      48             : using mozilla::services::GetObserverService;
      49             : 
      50             : void
      51           0 : gfxCharacterMap::NotifyReleased()
      52             : {
      53           0 :     gfxPlatformFontList *fontlist = gfxPlatformFontList::PlatformFontList();
      54           0 :     if (mShared) {
      55           0 :         fontlist->RemoveCmap(this);
      56             :     }
      57           0 :     delete this;
      58           0 : }
      59             : 
      60           0 : gfxFontEntry::gfxFontEntry() :
      61             :     mStyle(NS_FONT_STYLE_NORMAL), mFixedPitch(false),
      62             :     mIsValid(true),
      63             :     mIsBadUnderlineFont(false),
      64             :     mIsUserFontContainer(false),
      65             :     mIsDataUserFont(false),
      66             :     mIsLocalUserFont(false),
      67             :     mStandardFace(false),
      68             :     mSymbolFont(false),
      69             :     mIgnoreGDEF(false),
      70             :     mIgnoreGSUB(false),
      71             :     mSVGInitialized(false),
      72             :     mHasSpaceFeaturesInitialized(false),
      73             :     mHasSpaceFeatures(false),
      74             :     mHasSpaceFeaturesKerning(false),
      75             :     mHasSpaceFeaturesNonKerning(false),
      76             :     mSkipDefaultFeatureSpaceCheck(false),
      77             :     mGraphiteSpaceContextualsInitialized(false),
      78             :     mHasGraphiteSpaceContextuals(false),
      79             :     mSpaceGlyphIsInvisible(false),
      80             :     mSpaceGlyphIsInvisibleInitialized(false),
      81             :     mCheckedForGraphiteTables(false),
      82             :     mHasCmapTable(false),
      83             :     mGrFaceInitialized(false),
      84             :     mCheckedForColorGlyph(false),
      85             :     mWeight(500), mStretch(NS_FONT_STRETCH_NORMAL),
      86             :     mUVSOffset(0), mUVSData(nullptr),
      87             :     mLanguageOverride(NO_FONT_LANGUAGE_OVERRIDE),
      88             :     mCOLR(nullptr),
      89             :     mCPAL(nullptr),
      90             :     mUnitsPerEm(0),
      91             :     mHBFace(nullptr),
      92             :     mGrFace(nullptr),
      93             :     mGrFaceRefCnt(0),
      94           0 :     mComputedSizeOfUserFont(0)
      95             : {
      96           0 :     memset(&mDefaultSubSpaceFeatures, 0, sizeof(mDefaultSubSpaceFeatures));
      97           0 :     memset(&mNonDefaultSubSpaceFeatures, 0, sizeof(mNonDefaultSubSpaceFeatures));
      98           0 : }
      99             : 
     100         107 : gfxFontEntry::gfxFontEntry(const nsAString& aName, bool aIsStandardFace) :
     101             :     mName(aName), mStyle(NS_FONT_STYLE_NORMAL), mFixedPitch(false),
     102             :     mIsValid(true),
     103             :     mIsBadUnderlineFont(false),
     104             :     mIsUserFontContainer(false),
     105             :     mIsDataUserFont(false),
     106             :     mIsLocalUserFont(false), mStandardFace(aIsStandardFace),
     107             :     mSymbolFont(false),
     108             :     mIgnoreGDEF(false),
     109             :     mIgnoreGSUB(false),
     110             :     mSVGInitialized(false),
     111             :     mHasSpaceFeaturesInitialized(false),
     112             :     mHasSpaceFeatures(false),
     113             :     mHasSpaceFeaturesKerning(false),
     114             :     mHasSpaceFeaturesNonKerning(false),
     115             :     mSkipDefaultFeatureSpaceCheck(false),
     116             :     mGraphiteSpaceContextualsInitialized(false),
     117             :     mHasGraphiteSpaceContextuals(false),
     118             :     mSpaceGlyphIsInvisible(false),
     119             :     mSpaceGlyphIsInvisibleInitialized(false),
     120             :     mCheckedForGraphiteTables(false),
     121             :     mHasCmapTable(false),
     122             :     mGrFaceInitialized(false),
     123             :     mCheckedForColorGlyph(false),
     124             :     mWeight(500), mStretch(NS_FONT_STRETCH_NORMAL),
     125             :     mUVSOffset(0), mUVSData(nullptr),
     126             :     mLanguageOverride(NO_FONT_LANGUAGE_OVERRIDE),
     127             :     mCOLR(nullptr),
     128             :     mCPAL(nullptr),
     129             :     mUnitsPerEm(0),
     130             :     mHBFace(nullptr),
     131             :     mGrFace(nullptr),
     132             :     mGrFaceRefCnt(0),
     133         107 :     mComputedSizeOfUserFont(0)
     134             : {
     135         107 :     memset(&mDefaultSubSpaceFeatures, 0, sizeof(mDefaultSubSpaceFeatures));
     136         107 :     memset(&mNonDefaultSubSpaceFeatures, 0, sizeof(mNonDefaultSubSpaceFeatures));
     137         107 : }
     138             : 
     139           0 : gfxFontEntry::~gfxFontEntry()
     140             : {
     141             :     // Should not be dropped by stylo
     142           0 :     MOZ_ASSERT(NS_IsMainThread());
     143           0 :     if (mCOLR) {
     144           0 :         hb_blob_destroy(mCOLR);
     145             :     }
     146             : 
     147           0 :     if (mCPAL) {
     148           0 :         hb_blob_destroy(mCPAL);
     149             :     }
     150             : 
     151             :     // For downloaded fonts, we need to tell the user font cache that this
     152             :     // entry is being deleted.
     153           0 :     if (mIsDataUserFont) {
     154           0 :         gfxUserFontSet::UserFontCache::ForgetFont(this);
     155             :     }
     156             : 
     157           0 :     if (mFeatureInputs) {
     158           0 :         for (auto iter = mFeatureInputs->Iter(); !iter.Done(); iter.Next()) {
     159           0 :             hb_set_t*& set = iter.Data();
     160           0 :             hb_set_destroy(set);
     161             :         }
     162             :     }
     163             : 
     164             :     // By the time the entry is destroyed, all font instances that were
     165             :     // using it should already have been deleted, and so the HB and/or Gr
     166             :     // face objects should have been released.
     167           0 :     MOZ_ASSERT(!mHBFace);
     168           0 :     MOZ_ASSERT(!mGrFaceInitialized);
     169           0 : }
     170             : 
     171           0 : bool gfxFontEntry::IsSymbolFont() 
     172             : {
     173           0 :     return mSymbolFont;
     174             : }
     175             : 
     176           0 : bool gfxFontEntry::TestCharacterMap(uint32_t aCh)
     177             : {
     178           0 :     if (!mCharacterMap) {
     179           0 :         ReadCMAP();
     180           0 :         NS_ASSERTION(mCharacterMap, "failed to initialize character map");
     181             :     }
     182           0 :     return mCharacterMap->test(aCh);
     183             : }
     184             : 
     185           0 : nsresult gfxFontEntry::InitializeUVSMap()
     186             : {
     187             :     // mUVSOffset will not be initialized
     188             :     // until cmap is initialized.
     189           0 :     if (!mCharacterMap) {
     190           0 :         ReadCMAP();
     191           0 :         NS_ASSERTION(mCharacterMap, "failed to initialize character map");
     192             :     }
     193             : 
     194           0 :     if (!mUVSOffset) {
     195           0 :         return NS_ERROR_FAILURE;
     196             :     }
     197             : 
     198           0 :     if (!mUVSData) {
     199           0 :         const uint32_t kCmapTag = TRUETYPE_TAG('c','m','a','p');
     200           0 :         AutoTable cmapTable(this, kCmapTag);
     201           0 :         if (!cmapTable) {
     202           0 :             mUVSOffset = 0; // don't bother to read the table again
     203           0 :             return NS_ERROR_FAILURE;
     204             :         }
     205             : 
     206           0 :         UniquePtr<uint8_t[]> uvsData;
     207             :         unsigned int cmapLen;
     208           0 :         const char* cmapData = hb_blob_get_data(cmapTable, &cmapLen);
     209           0 :         nsresult rv = gfxFontUtils::ReadCMAPTableFormat14(
     210           0 :                           (const uint8_t*)cmapData + mUVSOffset,
     211           0 :                           cmapLen - mUVSOffset, uvsData);
     212             : 
     213           0 :         if (NS_FAILED(rv)) {
     214           0 :             mUVSOffset = 0; // don't bother to read the table again
     215           0 :             return rv;
     216             :         }
     217             : 
     218           0 :         mUVSData = Move(uvsData);
     219             :     }
     220             : 
     221           0 :     return NS_OK;
     222             : }
     223             : 
     224           0 : uint16_t gfxFontEntry::GetUVSGlyph(uint32_t aCh, uint32_t aVS)
     225             : {
     226           0 :     InitializeUVSMap();
     227             : 
     228           0 :     if (mUVSData) {
     229           0 :         return gfxFontUtils::MapUVSToGlyphFormat14(mUVSData.get(), aCh, aVS);
     230             :     }
     231             : 
     232           0 :     return 0;
     233             : }
     234             : 
     235           0 : bool gfxFontEntry::SupportsScriptInGSUB(const hb_tag_t* aScriptTags)
     236             : {
     237           0 :     hb_face_t *face = GetHBFace();
     238           0 :     if (!face) {
     239           0 :         return false;
     240             :     }
     241             : 
     242             :     unsigned int index;
     243             :     hb_tag_t     chosenScript;
     244             :     bool found =
     245           0 :         hb_ot_layout_table_choose_script(face, TRUETYPE_TAG('G','S','U','B'),
     246           0 :                                          aScriptTags, &index, &chosenScript);
     247           0 :     hb_face_destroy(face);
     248             : 
     249           0 :     return found && chosenScript != TRUETYPE_TAG('D','F','L','T');
     250             : }
     251             : 
     252           0 : nsresult gfxFontEntry::ReadCMAP(FontInfoData *aFontInfoData)
     253             : {
     254           0 :     NS_ASSERTION(false, "using default no-op implementation of ReadCMAP");
     255           0 :     mCharacterMap = new gfxCharacterMap();
     256           0 :     return NS_OK;
     257             : }
     258             : 
     259             : nsString
     260           0 : gfxFontEntry::RealFaceName()
     261             : {
     262           0 :     AutoTable nameTable(this, TRUETYPE_TAG('n','a','m','e'));
     263           0 :     if (nameTable) {
     264           0 :         nsAutoString name;
     265           0 :         nsresult rv = gfxFontUtils::GetFullNameFromTable(nameTable, name);
     266           0 :         if (NS_SUCCEEDED(rv)) {
     267           0 :             return name;
     268             :         }
     269             :     }
     270           0 :     return Name();
     271             : }
     272             : 
     273             : gfxFont*
     274           9 : gfxFontEntry::FindOrMakeFont(const gfxFontStyle *aStyle,
     275             :                              bool aNeedsBold,
     276             :                              gfxCharacterMap* aUnicodeRangeMap)
     277             : {
     278             :     // the font entry name is the psname, not the family name
     279             :     gfxFont* font =
     280           9 :         gfxFontCache::GetCache()->Lookup(this, aStyle, aUnicodeRangeMap);
     281             : 
     282           9 :     if (!font) {
     283           8 :         gfxFont *newFont = CreateFontInstance(aStyle, aNeedsBold);
     284           8 :         if (!newFont) {
     285           0 :             return nullptr;
     286             :         }
     287           8 :         if (!newFont->Valid()) {
     288           0 :             delete newFont;
     289           0 :             return nullptr;
     290             :         }
     291           8 :         font = newFont;
     292           8 :         font->SetUnicodeRangeMap(aUnicodeRangeMap);
     293           8 :         gfxFontCache::GetCache()->AddNew(font);
     294             :     }
     295           9 :     return font;
     296             : }
     297             : 
     298             : uint16_t
     299           2 : gfxFontEntry::UnitsPerEm()
     300             : {
     301           2 :     if (!mUnitsPerEm) {
     302           4 :         AutoTable headTable(this, TRUETYPE_TAG('h','e','a','d'));
     303           2 :         if (headTable) {
     304             :             uint32_t len;
     305             :             const HeadTable* head =
     306           2 :                 reinterpret_cast<const HeadTable*>(hb_blob_get_data(headTable,
     307           2 :                                                                     &len));
     308           2 :             if (len >= sizeof(HeadTable)) {
     309           2 :                 mUnitsPerEm = head->unitsPerEm;
     310             :             }
     311             :         }
     312             : 
     313             :         // if we didn't find a usable 'head' table, or if the value was
     314             :         // outside the valid range, record it as invalid
     315           2 :         if (mUnitsPerEm < kMinUPEM || mUnitsPerEm > kMaxUPEM) {
     316           0 :             mUnitsPerEm = kInvalidUPEM;
     317             :         }
     318             :     }
     319           2 :     return mUnitsPerEm;
     320             : }
     321             : 
     322             : bool
     323           0 : gfxFontEntry::HasSVGGlyph(uint32_t aGlyphId)
     324             : {
     325           0 :     NS_ASSERTION(mSVGInitialized, "SVG data has not yet been loaded. TryGetSVGData() first.");
     326           0 :     return mSVGGlyphs->HasSVGGlyph(aGlyphId);
     327             : }
     328             : 
     329             : bool
     330           0 : gfxFontEntry::GetSVGGlyphExtents(DrawTarget* aDrawTarget, uint32_t aGlyphId,
     331             :                                  gfxRect *aResult)
     332             : {
     333           0 :     MOZ_ASSERT(mSVGInitialized,
     334             :                "SVG data has not yet been loaded. TryGetSVGData() first.");
     335           0 :     MOZ_ASSERT(mUnitsPerEm >= kMinUPEM && mUnitsPerEm <= kMaxUPEM,
     336             :                "font has invalid unitsPerEm");
     337             : 
     338             :     cairo_matrix_t fontMatrix;
     339           0 :     cairo_get_font_matrix(gfxFont::RefCairo(aDrawTarget), &fontMatrix);
     340             : 
     341             :     gfxMatrix svgToAppSpace(fontMatrix.xx, fontMatrix.yx,
     342             :                             fontMatrix.xy, fontMatrix.yy,
     343           0 :                             fontMatrix.x0, fontMatrix.y0);
     344           0 :     svgToAppSpace.PreScale(1.0f / mUnitsPerEm, 1.0f / mUnitsPerEm);
     345             : 
     346           0 :     return mSVGGlyphs->GetGlyphExtents(aGlyphId, svgToAppSpace, aResult);
     347             : }
     348             : 
     349             : void
     350           0 : gfxFontEntry::RenderSVGGlyph(gfxContext *aContext, uint32_t aGlyphId,
     351             :                              SVGContextPaint* aContextPaint)
     352             : {
     353           0 :     NS_ASSERTION(mSVGInitialized, "SVG data has not yet been loaded. TryGetSVGData() first.");
     354           0 :     mSVGGlyphs->RenderGlyph(aContext, aGlyphId, aContextPaint);
     355           0 : }
     356             : 
     357             : bool
     358          92 : gfxFontEntry::TryGetSVGData(gfxFont* aFont)
     359             : {
     360          92 :     if (!gfxPlatform::GetPlatform()->OpenTypeSVGEnabled()) {
     361           0 :         return false;
     362             :     }
     363             : 
     364          92 :     if (!mSVGInitialized) {
     365           2 :         mSVGInitialized = true;
     366             : 
     367             :         // If UnitsPerEm is not known/valid, we can't use SVG glyphs
     368           2 :         if (UnitsPerEm() == kInvalidUPEM) {
     369           2 :             return false;
     370             :         }
     371             : 
     372             :         // We don't use AutoTable here because we'll pass ownership of this
     373             :         // blob to the gfxSVGGlyphs, once we've confirmed the table exists
     374           2 :         hb_blob_t *svgTable = GetFontTable(TRUETYPE_TAG('S','V','G',' '));
     375           2 :         if (!svgTable) {
     376           2 :             return false;
     377             :         }
     378             : 
     379             :         // gfxSVGGlyphs will hb_blob_destroy() the table when it is finished
     380             :         // with it.
     381           0 :         mSVGGlyphs = MakeUnique<gfxSVGGlyphs>(svgTable, this);
     382             :     }
     383             : 
     384          90 :     if (mSVGGlyphs && !mFontsUsingSVGGlyphs.Contains(aFont)) {
     385           0 :         mFontsUsingSVGGlyphs.AppendElement(aFont);
     386             :     }
     387             : 
     388          90 :     return !!mSVGGlyphs;
     389             : }
     390             : 
     391             : void
     392           0 : gfxFontEntry::NotifyFontDestroyed(gfxFont* aFont)
     393             : {
     394           0 :     mFontsUsingSVGGlyphs.RemoveElement(aFont);
     395           0 : }
     396             : 
     397             : void
     398           0 : gfxFontEntry::NotifyGlyphsChanged()
     399             : {
     400           0 :     for (uint32_t i = 0, count = mFontsUsingSVGGlyphs.Length(); i < count; ++i) {
     401           0 :         gfxFont* font = mFontsUsingSVGGlyphs[i];
     402           0 :         font->NotifyGlyphsChanged();
     403             :     }
     404           0 : }
     405             : 
     406             : bool
     407          29 : gfxFontEntry::TryGetColorGlyphs()
     408             : {
     409          29 :     if (mCheckedForColorGlyph) {
     410          27 :         return (mCOLR && mCPAL);
     411             :     }
     412             : 
     413           2 :     mCheckedForColorGlyph = true;
     414             : 
     415           2 :     mCOLR = GetFontTable(TRUETYPE_TAG('C', 'O', 'L', 'R'));
     416           2 :     if (!mCOLR) {
     417           2 :         return false;
     418             :     }
     419             : 
     420           0 :     mCPAL = GetFontTable(TRUETYPE_TAG('C', 'P', 'A', 'L'));
     421           0 :     if (!mCPAL) {
     422           0 :         hb_blob_destroy(mCOLR);
     423           0 :         mCOLR = nullptr;
     424           0 :         return false;
     425             :     }
     426             : 
     427             :     // validation COLR and CPAL table
     428           0 :     if (gfxFontUtils::ValidateColorGlyphs(mCOLR, mCPAL)) {
     429           0 :         return true;
     430             :     }
     431             : 
     432           0 :     hb_blob_destroy(mCOLR);
     433           0 :     hb_blob_destroy(mCPAL);
     434           0 :     mCOLR = nullptr;
     435           0 :     mCPAL = nullptr;
     436           0 :     return false;
     437             : }
     438             : 
     439             : /**
     440             :  * FontTableBlobData
     441             :  *
     442             :  * See FontTableHashEntry for the general strategy.
     443             :  */
     444             : 
     445             : class gfxFontEntry::FontTableBlobData {
     446             : public:
     447          14 :     explicit FontTableBlobData(nsTArray<uint8_t>&& aBuffer)
     448          14 :         : mTableData(Move(aBuffer))
     449             :         , mHashtable(nullptr)
     450          14 :         , mHashKey(0)
     451             :     {
     452          14 :         MOZ_COUNT_CTOR(FontTableBlobData);
     453          14 :     }
     454             : 
     455          18 :     ~FontTableBlobData() {
     456           9 :         MOZ_COUNT_DTOR(FontTableBlobData);
     457           9 :         if (mHashtable && mHashKey) {
     458           9 :             mHashtable->RemoveEntry(mHashKey);
     459             :         }
     460           9 :     }
     461             : 
     462             :     // Useful for creating blobs
     463          14 :     const char *GetTable() const
     464             :     {
     465          14 :         return reinterpret_cast<const char*>(mTableData.Elements());
     466             :     }
     467          14 :     uint32_t GetTableLength() const { return mTableData.Length(); }
     468             : 
     469             :     // Tell this FontTableBlobData to remove the HashEntry when this is
     470             :     // destroyed.
     471          14 :     void ManageHashEntry(nsTHashtable<FontTableHashEntry> *aHashtable,
     472             :                          uint32_t aHashKey)
     473             :     {
     474          14 :         mHashtable = aHashtable;
     475          14 :         mHashKey = aHashKey;
     476          14 :     }
     477             : 
     478             :     // Disconnect from the HashEntry (because the blob has already been
     479             :     // removed from the hashtable).
     480           9 :     void ForgetHashEntry()
     481             :     {
     482           9 :         mHashtable = nullptr;
     483           9 :         mHashKey = 0;
     484           9 :     }
     485             : 
     486           0 :     size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const {
     487           0 :         return mTableData.ShallowSizeOfExcludingThis(aMallocSizeOf);
     488             :     }
     489           0 :     size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const {
     490           0 :         return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
     491             :     }
     492             : 
     493             : private:
     494             :     // The font table data block
     495             :     nsTArray<uint8_t> mTableData;
     496             : 
     497             :     // The blob destroy function needs to know the owning hashtable
     498             :     // and the hashtable key, so that it can remove the entry.
     499             :     nsTHashtable<FontTableHashEntry> *mHashtable;
     500             :     uint32_t                          mHashKey;
     501             : 
     502             :     // not implemented
     503             :     FontTableBlobData(const FontTableBlobData&);
     504             : };
     505             : 
     506             : hb_blob_t *
     507          14 : gfxFontEntry::FontTableHashEntry::
     508             : ShareTableAndGetBlob(nsTArray<uint8_t>&& aTable,
     509             :                      nsTHashtable<FontTableHashEntry> *aHashtable)
     510             : {
     511          14 :     Clear();
     512             :     // adopts elements of aTable
     513          28 :     mSharedBlobData = new FontTableBlobData(Move(aTable));
     514             : 
     515          14 :     mBlob = hb_blob_create(mSharedBlobData->GetTable(),
     516          14 :                            mSharedBlobData->GetTableLength(),
     517             :                            HB_MEMORY_MODE_READONLY,
     518          14 :                            mSharedBlobData, DeleteFontTableBlobData);
     519          14 :     if (mBlob == hb_blob_get_empty() ) {
     520             :         // The FontTableBlobData was destroyed during hb_blob_create().
     521             :         // The (empty) blob is still be held in the hashtable with a strong
     522             :         // reference.
     523           0 :         return hb_blob_reference(mBlob);
     524             :     }
     525             : 
     526             :     // Tell the FontTableBlobData to remove this hash entry when destroyed.
     527             :     // The hashtable does not keep a strong reference.
     528          14 :     mSharedBlobData->ManageHashEntry(aHashtable, GetKey());
     529          14 :     return mBlob;
     530             : }
     531             : 
     532             : void
     533          30 : gfxFontEntry::FontTableHashEntry::Clear()
     534             : {
     535             :     // If the FontTableBlobData is managing the hash entry, then the blob is
     536             :     // not owned by this HashEntry; otherwise there is strong reference to the
     537             :     // blob that must be removed.
     538          30 :     if (mSharedBlobData) {
     539           9 :         mSharedBlobData->ForgetHashEntry();
     540           9 :         mSharedBlobData = nullptr;
     541          21 :     } else if (mBlob) {
     542           0 :         hb_blob_destroy(mBlob);
     543             :     }
     544          30 :     mBlob = nullptr;
     545          30 : }
     546             : 
     547             : // a hb_destroy_func for hb_blob_create
     548             : 
     549             : /* static */ void
     550           9 : gfxFontEntry::FontTableHashEntry::DeleteFontTableBlobData(void *aBlobData)
     551             : {
     552           9 :     delete static_cast<FontTableBlobData*>(aBlobData);
     553           9 : }
     554             : 
     555             : hb_blob_t *
     556           1 : gfxFontEntry::FontTableHashEntry::GetBlob() const
     557             : {
     558           1 :     return hb_blob_reference(mBlob);
     559             : }
     560             : 
     561             : bool
     562          22 : gfxFontEntry::GetExistingFontTable(uint32_t aTag, hb_blob_t **aBlob)
     563             : {
     564          22 :     if (!mFontTableCache) {
     565             :         // we do this here rather than on fontEntry construction
     566             :         // because not all shapers will access the table cache at all
     567           2 :         mFontTableCache = MakeUnique<nsTHashtable<FontTableHashEntry>>(8);
     568             :     }
     569             : 
     570          22 :     FontTableHashEntry *entry = mFontTableCache->GetEntry(aTag);
     571          22 :     if (!entry) {
     572          21 :         return false;
     573             :     }
     574             : 
     575           1 :     *aBlob = entry->GetBlob();
     576           1 :     return true;
     577             : }
     578             : 
     579             : hb_blob_t *
     580          21 : gfxFontEntry::ShareFontTableAndGetBlob(uint32_t aTag,
     581             :                                        nsTArray<uint8_t>* aBuffer)
     582             : {
     583          21 :     if (MOZ_UNLIKELY(!mFontTableCache)) {
     584             :         // we do this here rather than on fontEntry construction
     585             :         // because not all shapers will access the table cache at all
     586           0 :       mFontTableCache = MakeUnique<nsTHashtable<FontTableHashEntry>>(8);
     587             :     }
     588             : 
     589          21 :     FontTableHashEntry *entry = mFontTableCache->PutEntry(aTag);
     590          21 :     if (MOZ_UNLIKELY(!entry)) { // OOM
     591           0 :         return nullptr;
     592             :     }
     593             : 
     594          21 :     if (!aBuffer) {
     595             :         // ensure the entry is null
     596           7 :         entry->Clear();
     597           7 :         return nullptr;
     598             :     }
     599             : 
     600          14 :     return entry->ShareTableAndGetBlob(Move(*aBuffer), mFontTableCache.get());
     601             : }
     602             : 
     603             : already_AddRefed<gfxCharacterMap>
     604           0 : gfxFontEntry::GetCMAPFromFontInfo(FontInfoData *aFontInfoData,
     605             :                                   uint32_t& aUVSOffset,
     606             :                                   bool& aSymbolFont)
     607             : {
     608           0 :     if (!aFontInfoData || !aFontInfoData->mLoadCmaps) {
     609           0 :         return nullptr;
     610             :     }
     611             : 
     612           0 :     return aFontInfoData->GetCMAP(mName, aUVSOffset, aSymbolFont);
     613             : }
     614             : 
     615             : hb_blob_t *
     616          22 : gfxFontEntry::GetFontTable(uint32_t aTag)
     617             : {
     618             :     hb_blob_t *blob;
     619          22 :     if (GetExistingFontTable(aTag, &blob)) {
     620           1 :         return blob;
     621             :     }
     622             : 
     623          42 :     nsTArray<uint8_t> buffer;
     624          21 :     bool haveTable = NS_SUCCEEDED(CopyFontTable(aTag, buffer));
     625             : 
     626          21 :     return ShareFontTableAndGetBlob(aTag, haveTable ? &buffer : nullptr);
     627             : }
     628             : 
     629             : // callback for HarfBuzz to get a font table (in hb_blob_t form)
     630             : // from the font entry (passed as aUserData)
     631             : /*static*/ hb_blob_t *
     632          14 : gfxFontEntry::HBGetTable(hb_face_t *face, uint32_t aTag, void *aUserData)
     633             : {
     634          14 :     gfxFontEntry *fontEntry = static_cast<gfxFontEntry*>(aUserData);
     635             : 
     636             :     // bug 589682 - ignore the GDEF table in buggy fonts (applies to
     637             :     // Italic and BoldItalic faces of Times New Roman)
     638          18 :     if (aTag == TRUETYPE_TAG('G','D','E','F') &&
     639           4 :         fontEntry->IgnoreGDEF()) {
     640           0 :         return nullptr;
     641             :     }
     642             : 
     643             :     // bug 721719 - ignore the GSUB table in buggy fonts (applies to Roboto,
     644             :     // at least on some Android ICS devices; set in gfxFT2FontList.cpp)
     645          18 :     if (aTag == TRUETYPE_TAG('G','S','U','B') &&
     646           4 :         fontEntry->IgnoreGSUB()) {
     647           0 :         return nullptr;
     648             :     }
     649             : 
     650          14 :     return fontEntry->GetFontTable(aTag);
     651             : }
     652             : 
     653             : /*static*/ void
     654           2 : gfxFontEntry::HBFaceDeletedCallback(void *aUserData)
     655             : {
     656           2 :     gfxFontEntry *fe = static_cast<gfxFontEntry*>(aUserData);
     657           2 :     fe->ForgetHBFace();
     658           2 : }
     659             : 
     660             : void
     661           2 : gfxFontEntry::ForgetHBFace()
     662             : {
     663           2 :     mHBFace = nullptr;
     664           2 : }
     665             : 
     666             : hb_face_t*
     667           4 : gfxFontEntry::GetHBFace()
     668             : {
     669           4 :     if (!mHBFace) {
     670           4 :         mHBFace = hb_face_create_for_tables(HBGetTable, this,
     671             :                                             HBFaceDeletedCallback);
     672           4 :         return mHBFace;
     673             :     }
     674           0 :     return hb_face_reference(mHBFace);
     675             : }
     676             : 
     677             : /*static*/ const void*
     678           0 : gfxFontEntry::GrGetTable(const void *aAppFaceHandle, unsigned int aName,
     679             :                          size_t *aLen)
     680             : {
     681             :     gfxFontEntry *fontEntry =
     682           0 :         static_cast<gfxFontEntry*>(const_cast<void*>(aAppFaceHandle));
     683           0 :     hb_blob_t *blob = fontEntry->GetFontTable(aName);
     684           0 :     if (blob) {
     685             :         unsigned int blobLength;
     686           0 :         const void *tableData = hb_blob_get_data(blob, &blobLength);
     687           0 :         fontEntry->mGrTableMap->Put(tableData, blob);
     688           0 :         *aLen = blobLength;
     689           0 :         return tableData;
     690             :     }
     691           0 :     *aLen = 0;
     692           0 :     return nullptr;
     693             : }
     694             : 
     695             : /*static*/ void
     696           0 : gfxFontEntry::GrReleaseTable(const void *aAppFaceHandle,
     697             :                              const void *aTableBuffer)
     698             : {
     699             :     gfxFontEntry *fontEntry =
     700           0 :         static_cast<gfxFontEntry*>(const_cast<void*>(aAppFaceHandle));
     701             :     void* value;
     702           0 :     if (fontEntry->mGrTableMap->Remove(aTableBuffer, &value)) {
     703           0 :         hb_blob_destroy(static_cast<hb_blob_t*>(value));
     704             :     }
     705           0 : }
     706             : 
     707             : gr_face*
     708           0 : gfxFontEntry::GetGrFace()
     709             : {
     710           0 :     if (!mGrFaceInitialized) {
     711             :         gr_face_ops faceOps = {
     712             :             sizeof(gr_face_ops),
     713             :             GrGetTable,
     714             :             GrReleaseTable
     715           0 :         };
     716           0 :         mGrTableMap = new nsDataHashtable<nsPtrHashKey<const void>,void*>;
     717           0 :         mGrFace = gr_make_face_with_ops(this, &faceOps, gr_face_default);
     718           0 :         mGrFaceInitialized = true;
     719             :     }
     720           0 :     ++mGrFaceRefCnt;
     721           0 :     return mGrFace;
     722             : }
     723             : 
     724             : void
     725           0 : gfxFontEntry::ReleaseGrFace(gr_face *aFace)
     726             : {
     727           0 :     MOZ_ASSERT(aFace == mGrFace); // sanity-check
     728           0 :     MOZ_ASSERT(mGrFaceRefCnt > 0);
     729           0 :     if (--mGrFaceRefCnt == 0) {
     730           0 :         gr_face_destroy(mGrFace);
     731           0 :         mGrFace = nullptr;
     732           0 :         mGrFaceInitialized = false;
     733           0 :         delete mGrTableMap;
     734           0 :         mGrTableMap = nullptr;
     735             :     }
     736           0 : }
     737             : 
     738             : void
     739           0 : gfxFontEntry::DisconnectSVG()
     740             : {
     741           0 :     if (mSVGInitialized && mSVGGlyphs) {
     742           0 :         mSVGGlyphs = nullptr;
     743           0 :         mSVGInitialized = false;
     744             :     }
     745           0 : }
     746             : 
     747             : bool
     748           2 : gfxFontEntry::HasFontTable(uint32_t aTableTag)
     749             : {
     750           4 :     AutoTable table(this, aTableTag);
     751           4 :     return table && hb_blob_get_length(table) > 0;
     752             : }
     753             : 
     754             : void
     755           2 : gfxFontEntry::CheckForGraphiteTables()
     756             : {
     757           2 :     mHasGraphiteTables = HasFontTable(TRUETYPE_TAG('S','i','l','f'));
     758           2 : }
     759             : 
     760             : bool
     761           0 : gfxFontEntry::HasGraphiteSpaceContextuals()
     762             : {
     763           0 :     if (!mGraphiteSpaceContextualsInitialized) {
     764           0 :         gr_face* face = GetGrFace();
     765           0 :         if (face) {
     766           0 :             const gr_faceinfo* faceInfo = gr_face_info(face, 0);
     767           0 :             mHasGraphiteSpaceContextuals =
     768           0 :                 faceInfo->space_contextuals != gr_faceinfo::gr_space_none;
     769             :         }
     770           0 :         ReleaseGrFace(face); // always balance GetGrFace, even if face is null
     771           0 :         mGraphiteSpaceContextualsInitialized = true;
     772             :     }
     773           0 :     return mHasGraphiteSpaceContextuals;
     774             : }
     775             : 
     776             : #define FEATURE_SCRIPT_MASK 0x000000ff // script index replaces low byte of tag
     777             : 
     778             : static_assert(int(Script::NUM_SCRIPT_CODES) <= FEATURE_SCRIPT_MASK, "Too many script codes");
     779             : 
     780             : // high-order three bytes of tag with script in low-order byte
     781             : #define SCRIPT_FEATURE(s,tag) (((~FEATURE_SCRIPT_MASK) & (tag)) | \
     782             :                                ((FEATURE_SCRIPT_MASK) & static_cast<uint32_t>(s)))
     783             : 
     784             : bool
     785           0 : gfxFontEntry::SupportsOpenTypeFeature(Script aScript, uint32_t aFeatureTag)
     786             : {
     787           0 :     if (!mSupportedFeatures) {
     788           0 :         mSupportedFeatures = MakeUnique<nsDataHashtable<nsUint32HashKey,bool>>();
     789             :     }
     790             : 
     791             :     // note: high-order three bytes *must* be unique for each feature
     792             :     // listed below (see SCRIPT_FEATURE macro def'n)
     793           0 :     NS_ASSERTION(aFeatureTag == HB_TAG('s','m','c','p') ||
     794             :                  aFeatureTag == HB_TAG('c','2','s','c') ||
     795             :                  aFeatureTag == HB_TAG('p','c','a','p') ||
     796             :                  aFeatureTag == HB_TAG('c','2','p','c') ||
     797             :                  aFeatureTag == HB_TAG('s','u','p','s') ||
     798             :                  aFeatureTag == HB_TAG('s','u','b','s') ||
     799             :                  aFeatureTag == HB_TAG('v','e','r','t'),
     800             :                  "use of unknown feature tag");
     801             : 
     802             :     // note: graphite feature support uses the last script index
     803           0 :     NS_ASSERTION(int(aScript) < FEATURE_SCRIPT_MASK - 1,
     804             :                  "need to bump the size of the feature shift");
     805             : 
     806           0 :     uint32_t scriptFeature = SCRIPT_FEATURE(aScript, aFeatureTag);
     807             :     bool result;
     808           0 :     if (mSupportedFeatures->Get(scriptFeature, &result)) {
     809           0 :         return result;
     810             :     }
     811             : 
     812           0 :     result = false;
     813             : 
     814           0 :     hb_face_t *face = GetHBFace();
     815             : 
     816           0 :     if (hb_ot_layout_has_substitution(face)) {
     817             :         hb_script_t hbScript =
     818           0 :             gfxHarfBuzzShaper::GetHBScriptUsedForShaping(aScript);
     819             : 
     820             :         // Get the OpenType tag(s) that match this script code
     821             :         hb_tag_t scriptTags[4] = {
     822             :             HB_TAG_NONE,
     823             :             HB_TAG_NONE,
     824             :             HB_TAG_NONE,
     825             :             HB_TAG_NONE
     826           0 :         };
     827           0 :         hb_ot_tags_from_script(hbScript, &scriptTags[0], &scriptTags[1]);
     828             : 
     829             :         // Replace the first remaining NONE with DEFAULT
     830           0 :         hb_tag_t* scriptTag = &scriptTags[0];
     831           0 :         while (*scriptTag != HB_TAG_NONE) {
     832           0 :             ++scriptTag;
     833             :         }
     834           0 :         *scriptTag = HB_OT_TAG_DEFAULT_SCRIPT;
     835             : 
     836             :         // Now check for 'smcp' under the first of those scripts that is present
     837           0 :         const hb_tag_t kGSUB = HB_TAG('G','S','U','B');
     838           0 :         scriptTag = &scriptTags[0];
     839           0 :         while (*scriptTag != HB_TAG_NONE) {
     840             :             unsigned int scriptIndex;
     841           0 :             if (hb_ot_layout_table_find_script(face, kGSUB, *scriptTag,
     842             :                                                &scriptIndex)) {
     843           0 :                 if (hb_ot_layout_language_find_feature(face, kGSUB,
     844             :                                                        scriptIndex,
     845             :                                            HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX,
     846             :                                                        aFeatureTag, nullptr)) {
     847           0 :                     result = true;
     848             :                 }
     849           0 :                 break;
     850             :             }
     851           0 :             ++scriptTag;
     852             :         }
     853             :     }
     854             : 
     855           0 :     hb_face_destroy(face);
     856             : 
     857           0 :     mSupportedFeatures->Put(scriptFeature, result);
     858             : 
     859           0 :     return result;
     860             : }
     861             : 
     862             : const hb_set_t*
     863           0 : gfxFontEntry::InputsForOpenTypeFeature(Script aScript, uint32_t aFeatureTag)
     864             : {
     865           0 :     if (!mFeatureInputs) {
     866           0 :         mFeatureInputs = MakeUnique<nsDataHashtable<nsUint32HashKey,hb_set_t*>>();
     867             :     }
     868             : 
     869           0 :     NS_ASSERTION(aFeatureTag == HB_TAG('s','u','p','s') ||
     870             :                  aFeatureTag == HB_TAG('s','u','b','s'),
     871             :                  "use of unknown feature tag");
     872             : 
     873           0 :     uint32_t scriptFeature = SCRIPT_FEATURE(aScript, aFeatureTag);
     874             :     hb_set_t *inputGlyphs;
     875           0 :     if (mFeatureInputs->Get(scriptFeature, &inputGlyphs)) {
     876           0 :         return inputGlyphs;
     877             :     }
     878             : 
     879           0 :     inputGlyphs = hb_set_create();
     880             : 
     881           0 :     hb_face_t *face = GetHBFace();
     882             : 
     883           0 :     if (hb_ot_layout_has_substitution(face)) {
     884             :         hb_script_t hbScript =
     885           0 :             gfxHarfBuzzShaper::GetHBScriptUsedForShaping(aScript);
     886             : 
     887             :         // Get the OpenType tag(s) that match this script code
     888             :         hb_tag_t scriptTags[4] = {
     889             :             HB_TAG_NONE,
     890             :             HB_TAG_NONE,
     891             :             HB_TAG_NONE,
     892             :             HB_TAG_NONE
     893           0 :         };
     894           0 :         hb_ot_tags_from_script(hbScript, &scriptTags[0], &scriptTags[1]);
     895             : 
     896             :         // Replace the first remaining NONE with DEFAULT
     897           0 :         hb_tag_t* scriptTag = &scriptTags[0];
     898           0 :         while (*scriptTag != HB_TAG_NONE) {
     899           0 :             ++scriptTag;
     900             :         }
     901           0 :         *scriptTag = HB_OT_TAG_DEFAULT_SCRIPT;
     902             : 
     903           0 :         const hb_tag_t kGSUB = HB_TAG('G','S','U','B');
     904           0 :         hb_tag_t features[2] = { aFeatureTag, HB_TAG_NONE };
     905           0 :         hb_set_t *featurelookups = hb_set_create();
     906             :         hb_ot_layout_collect_lookups(face, kGSUB, scriptTags, nullptr,
     907           0 :                                      features, featurelookups);
     908           0 :         hb_codepoint_t index = -1;
     909           0 :         while (hb_set_next(featurelookups, &index)) {
     910             :             hb_ot_layout_lookup_collect_glyphs(face, kGSUB, index,
     911             :                                                nullptr, inputGlyphs,
     912           0 :                                                nullptr, nullptr);
     913             :         }
     914           0 :         hb_set_destroy(featurelookups);
     915             :     }
     916             : 
     917           0 :     hb_face_destroy(face);
     918             : 
     919           0 :     mFeatureInputs->Put(scriptFeature, inputGlyphs);
     920           0 :     return inputGlyphs;
     921             : }
     922             : 
     923             : bool
     924           0 : gfxFontEntry::SupportsGraphiteFeature(uint32_t aFeatureTag)
     925             : {
     926           0 :     if (!mSupportedFeatures) {
     927           0 :         mSupportedFeatures = MakeUnique<nsDataHashtable<nsUint32HashKey,bool>>();
     928             :     }
     929             : 
     930             :     // note: high-order three bytes *must* be unique for each feature
     931             :     // listed below (see SCRIPT_FEATURE macro def'n)
     932           0 :     NS_ASSERTION(aFeatureTag == HB_TAG('s','m','c','p') ||
     933             :                  aFeatureTag == HB_TAG('c','2','s','c') ||
     934             :                  aFeatureTag == HB_TAG('p','c','a','p') ||
     935             :                  aFeatureTag == HB_TAG('c','2','p','c') ||
     936             :                  aFeatureTag == HB_TAG('s','u','p','s') ||
     937             :                  aFeatureTag == HB_TAG('s','u','b','s'),
     938             :                  "use of unknown feature tag");
     939             : 
     940             :     // graphite feature check uses the last script slot
     941           0 :     uint32_t scriptFeature = SCRIPT_FEATURE(FEATURE_SCRIPT_MASK, aFeatureTag);
     942             :     bool result;
     943           0 :     if (mSupportedFeatures->Get(scriptFeature, &result)) {
     944           0 :         return result;
     945             :     }
     946             : 
     947           0 :     gr_face* face = GetGrFace();
     948           0 :     result = face ? gr_face_find_fref(face, aFeatureTag) != nullptr : false;
     949           0 :     ReleaseGrFace(face);
     950             : 
     951           0 :     mSupportedFeatures->Put(scriptFeature, result);
     952             : 
     953           0 :     return result;
     954             : }
     955             : 
     956             : bool
     957           0 : gfxFontEntry::GetColorLayersInfo(uint32_t aGlyphId,
     958             :                             const mozilla::gfx::Color& aDefaultColor,
     959             :                             nsTArray<uint16_t>& aLayerGlyphs,
     960             :                             nsTArray<mozilla::gfx::Color>& aLayerColors)
     961             : {
     962           0 :     return gfxFontUtils::GetColorGlyphLayers(mCOLR,
     963             :                                              mCPAL,
     964             :                                              aGlyphId,
     965             :                                              aDefaultColor,
     966             :                                              aLayerGlyphs,
     967           0 :                                              aLayerColors);
     968             : }
     969             : 
     970             : size_t
     971           0 : gfxFontEntry::FontTableHashEntry::SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
     972             : {
     973           0 :     size_t n = 0;
     974           0 :     if (mBlob) {
     975           0 :         n += aMallocSizeOf(mBlob);
     976             :     }
     977           0 :     if (mSharedBlobData) {
     978           0 :         n += mSharedBlobData->SizeOfIncludingThis(aMallocSizeOf);
     979             :     }
     980           0 :     return n;
     981             : }
     982             : 
     983             : void
     984           0 : gfxFontEntry::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
     985             :                                      FontListSizes* aSizes) const
     986             : {
     987           0 :     aSizes->mFontListSize += mName.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
     988             : 
     989             :     // cmaps are shared so only non-shared cmaps are included here
     990           0 :     if (mCharacterMap && mCharacterMap->mBuildOnTheFly) {
     991           0 :         aSizes->mCharMapsSize +=
     992           0 :             mCharacterMap->SizeOfIncludingThis(aMallocSizeOf);
     993             :     }
     994           0 :     if (mFontTableCache) {
     995           0 :         aSizes->mFontTableCacheSize +=
     996           0 :             mFontTableCache->SizeOfIncludingThis(aMallocSizeOf);
     997             :     }
     998             : 
     999             :     // If the font has UVS data, we count that as part of the character map.
    1000           0 :     if (mUVSData) {
    1001           0 :         aSizes->mCharMapsSize += aMallocSizeOf(mUVSData.get());
    1002             :     }
    1003             : 
    1004             :     // The following, if present, are essentially cached forms of font table
    1005             :     // data, so we'll accumulate them together with the basic table cache.
    1006           0 :     if (mUserFontData) {
    1007           0 :         aSizes->mFontTableCacheSize +=
    1008           0 :             mUserFontData->SizeOfIncludingThis(aMallocSizeOf);
    1009             :     }
    1010           0 :     if (mSVGGlyphs) {
    1011           0 :         aSizes->mFontTableCacheSize +=
    1012           0 :             mSVGGlyphs->SizeOfIncludingThis(aMallocSizeOf);
    1013             :     }
    1014           0 :     if (mSupportedFeatures) {
    1015           0 :         aSizes->mFontTableCacheSize +=
    1016           0 :             mSupportedFeatures->ShallowSizeOfIncludingThis(aMallocSizeOf);
    1017             :     }
    1018           0 :     if (mFeatureInputs) {
    1019           0 :         aSizes->mFontTableCacheSize +=
    1020           0 :             mFeatureInputs->ShallowSizeOfIncludingThis(aMallocSizeOf);
    1021           0 :         for (auto iter = mFeatureInputs->ConstIter(); !iter.Done();
    1022           0 :              iter.Next()) {
    1023             :             // There's no API to get the real size of an hb_set, so we'll use
    1024             :             // an approximation based on knowledge of the implementation.
    1025           0 :             aSizes->mFontTableCacheSize += 8192; // vector of 64K bits
    1026             :         }
    1027             :     }
    1028             :     // We don't include the size of mCOLR/mCPAL here, because (depending on the
    1029             :     // font backend implementation) they will either wrap blocks of data owned
    1030             :     // by the system (and potentially shared), or tables that are in our font
    1031             :     // table cache and therefore already counted.
    1032           0 : }
    1033             : 
    1034             : void
    1035           0 : gfxFontEntry::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
    1036             :                                      FontListSizes* aSizes) const
    1037             : {
    1038           0 :     aSizes->mFontListSize += aMallocSizeOf(this);
    1039           0 :     AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
    1040           0 : }
    1041             : 
    1042             : // This is used to report the size of an individual downloaded font in the
    1043             : // user font cache. (Fonts that are part of the platform font list accumulate
    1044             : // their sizes to the font list's reporter using the AddSizeOf... methods
    1045             : // above.)
    1046             : size_t
    1047           0 : gfxFontEntry::ComputedSizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
    1048             : {
    1049           0 :     FontListSizes s = { 0 };
    1050           0 :     AddSizeOfExcludingThis(aMallocSizeOf, &s);
    1051             : 
    1052             :     // When reporting memory used for the main platform font list,
    1053             :     // where we're typically summing the totals for a few hundred font faces,
    1054             :     // we report the fields of FontListSizes separately.
    1055             :     // But for downloaded user fonts, the actual resource data (added below)
    1056             :     // will dominate, and the minor overhead of these pieces isn't worth
    1057             :     // splitting out for an individual font.
    1058           0 :     size_t result = s.mFontListSize + s.mFontTableCacheSize + s.mCharMapsSize;
    1059             : 
    1060           0 :     if (mIsDataUserFont) {
    1061           0 :         MOZ_ASSERT(mComputedSizeOfUserFont > 0, "user font with no data?");
    1062           0 :         result += mComputedSizeOfUserFont;
    1063             :     }
    1064             : 
    1065           0 :     return result;
    1066             : }
    1067             : 
    1068             : //////////////////////////////////////////////////////////////////////////////
    1069             : //
    1070             : // class gfxFontFamily
    1071             : //
    1072             : //////////////////////////////////////////////////////////////////////////////
    1073             : 
    1074             : // we consider faces with mStandardFace == true to be "less than" those with false,
    1075             : // because during style matching, earlier entries are tried first
    1076             : class FontEntryStandardFaceComparator {
    1077             :   public:
    1078           0 :     bool Equals(const RefPtr<gfxFontEntry>& a, const RefPtr<gfxFontEntry>& b) const {
    1079           0 :         return a->mStandardFace == b->mStandardFace;
    1080             :     }
    1081           0 :     bool LessThan(const RefPtr<gfxFontEntry>& a, const RefPtr<gfxFontEntry>& b) const {
    1082           0 :         return (a->mStandardFace == true && b->mStandardFace == false);
    1083             :     }
    1084             : };
    1085             : 
    1086             : void
    1087           0 : gfxFontFamily::SortAvailableFonts()
    1088             : {
    1089           0 :     mAvailableFonts.Sort(FontEntryStandardFaceComparator());
    1090           0 : }
    1091             : 
    1092             : bool
    1093           0 : gfxFontFamily::HasOtherFamilyNames()
    1094             : {
    1095             :     // need to read in other family names to determine this
    1096           0 :     if (!mOtherFamilyNamesInitialized) {
    1097           0 :         ReadOtherFamilyNames(gfxPlatformFontList::PlatformFontList());  // sets mHasOtherFamilyNames
    1098             :     }
    1099           0 :     return mHasOtherFamilyNames;
    1100             : }
    1101             : 
    1102             : gfxFontEntry*
    1103           3 : gfxFontFamily::FindFontForStyle(const gfxFontStyle& aFontStyle, 
    1104             :                                 bool& aNeedsSyntheticBold)
    1105             : {
    1106           6 :     AutoTArray<gfxFontEntry*,4> matched;
    1107           3 :     FindAllFontsForStyle(aFontStyle, matched, aNeedsSyntheticBold);
    1108           3 :     if (!matched.IsEmpty()) {
    1109           3 :         return matched[0];
    1110             :     }
    1111           0 :     return nullptr;
    1112             : }
    1113             : 
    1114             : #define STYLE_SHIFT 2 // number of bits to contain style distance
    1115             : 
    1116             : // style distance ==> [0,2]
    1117             : static inline uint32_t
    1118         115 : StyleDistance(uint32_t aFontStyle, uint32_t aTargetStyle)
    1119             : {
    1120         115 :     if (aFontStyle == aTargetStyle) {
    1121          59 :         return 0; // styles match exactly ==> 0
    1122             :     }
    1123          56 :     if (aFontStyle == NS_FONT_STYLE_NORMAL ||
    1124             :         aTargetStyle == NS_FONT_STYLE_NORMAL) {
    1125          56 :         return 2; // one is normal (but not the other) ==> 2
    1126             :     }
    1127           0 :     return 1; // neither is normal; must be italic vs oblique ==> 1
    1128             : }
    1129             : 
    1130             : #define REVERSE_STRETCH_DISTANCE 5
    1131             : 
    1132             : // stretch distance ==> [0,13]
    1133             : static inline uint32_t
    1134         115 : StretchDistance(int16_t aFontStretch, int16_t aTargetStretch)
    1135             : {
    1136         115 :     int32_t distance = 0;
    1137         115 :     if (aTargetStretch != aFontStretch) {
    1138             :         // stretch values are in the range -4 .. +4
    1139             :         // if aTargetStretch is positive, we prefer more-positive values;
    1140             :         // if zero or negative, prefer more-negative
    1141          32 :         if (aTargetStretch > 0) {
    1142           0 :             distance = (aFontStretch - aTargetStretch);
    1143             :         } else {
    1144          32 :             distance = (aTargetStretch - aFontStretch);
    1145             :         }
    1146             :         // if the computed "distance" here is negative, it means that
    1147             :         // aFontEntry lies in the "non-preferred" direction from aTargetStretch,
    1148             :         // so we treat that as larger than any preferred-direction distance
    1149             :         // (max possible is 4) by adding an extra 5 to the absolute value
    1150          32 :         if (distance < 0) {
    1151           0 :             distance = -distance + REVERSE_STRETCH_DISTANCE;
    1152             :         }
    1153             :     }
    1154         115 :     return uint32_t(distance);
    1155             : }
    1156             : 
    1157             : // CSS currently limits font weights to multiples of 100 but the weight
    1158             : // matching code below does not assume this.
    1159             : //
    1160             : // Calculate weight distance with values in the range (0..1000). In general,
    1161             : // heavier weights match towards even heavier weights while lighter weights
    1162             : // match towards even lighter weights. Target weight values in the range
    1163             : // [400..500] are special, since they will first match up to 500, then down
    1164             : // towards 0, then up again towards 999.
    1165             : //
    1166             : // Example: with target 600 and font weight 800, distance will be 200. With
    1167             : // target 300 and font weight 600, distance will be 900, since heavier
    1168             : // weights are farther away than lighter weights. If the target is 5 and the
    1169             : // font weight 995, the distance would be 1590 for the same reason.
    1170             : 
    1171             : #define REVERSE_WEIGHT_DISTANCE 600
    1172             : #define WEIGHT_SHIFT             11 // number of bits to contain weight distance
    1173             : 
    1174             : // weight distance ==> [0,1598]
    1175             : static inline uint32_t
    1176         115 : WeightDistance(uint32_t aFontWeight, uint32_t aTargetWeight)
    1177             : {
    1178             :     // Compute a measure of the "distance" between the requested
    1179             :     // weight and the given fontEntry
    1180             : 
    1181         115 :     int32_t distance = 0, addedDistance = 0;
    1182         115 :     if (aTargetWeight != aFontWeight) {
    1183          61 :         if (aTargetWeight > 500) {
    1184           0 :             distance = aFontWeight - aTargetWeight;
    1185          61 :         } else if (aTargetWeight < 400) {
    1186           0 :             distance = aTargetWeight - aFontWeight;
    1187             :         } else {
    1188             :             // special case - target is between 400 and 500
    1189             : 
    1190             :             // font weights between 400 and 500 are close
    1191          61 :             if (aFontWeight >= 400 && aFontWeight <= 500) {
    1192           4 :                 if (aFontWeight < aTargetWeight) {
    1193           0 :                     distance = 500 - aFontWeight;
    1194             :                 } else {
    1195           2 :                     distance = aFontWeight - aTargetWeight;
    1196             :                 }
    1197             :             } else {
    1198             :                 // font weights outside use rule for target weights < 400 with
    1199             :                 // added distance to separate from font weights in
    1200             :                 // the [400..500] range
    1201          59 :                 distance = aTargetWeight - aFontWeight;
    1202          59 :                 addedDistance = 100;
    1203             :             }
    1204             :         }
    1205          61 :         if (distance < 0) {
    1206          54 :             distance = -distance + REVERSE_WEIGHT_DISTANCE;
    1207             :         }
    1208          61 :         distance += addedDistance;
    1209             :     }
    1210         115 :     return uint32_t(distance);
    1211             : }
    1212             : 
    1213             : #define MAX_DISTANCE 0xffffffff
    1214             : 
    1215             : static inline uint32_t
    1216         115 : WeightStyleStretchDistance(gfxFontEntry* aFontEntry,
    1217             :                            const gfxFontStyle& aTargetStyle)
    1218             : {
    1219             :     // weight/style/stretch priority: stretch >> style >> weight
    1220             :     uint32_t stretchDist =
    1221         115 :         StretchDistance(aFontEntry->mStretch, aTargetStyle.stretch);
    1222         115 :     uint32_t styleDist = StyleDistance(aFontEntry->mStyle, aTargetStyle.style);
    1223             :     uint32_t weightDist =
    1224         115 :         WeightDistance(aFontEntry->Weight(), aTargetStyle.weight);
    1225             : 
    1226         115 :     NS_ASSERTION(weightDist < (1 << WEIGHT_SHIFT), "weight value out of bounds");
    1227         115 :     NS_ASSERTION(styleDist < (1 << STYLE_SHIFT), "slope value out of bounds");
    1228             : 
    1229         230 :     return (stretchDist << (STYLE_SHIFT + WEIGHT_SHIFT)) |
    1230         115 :            (styleDist << WEIGHT_SHIFT) |
    1231         115 :            weightDist;
    1232             : }
    1233             : 
    1234             : void
    1235          19 : gfxFontFamily::FindAllFontsForStyle(const gfxFontStyle& aFontStyle,
    1236             :                                     nsTArray<gfxFontEntry*>& aFontEntryList,
    1237             :                                     bool& aNeedsSyntheticBold)
    1238             : {
    1239          19 :     if (!mHasStyles) {
    1240           0 :         FindStyleVariations(); // collect faces for the family, if not already done
    1241             :     }
    1242             : 
    1243          19 :     NS_ASSERTION(mAvailableFonts.Length() > 0, "font family with no faces!");
    1244          19 :     NS_ASSERTION(aFontEntryList.IsEmpty(), "non-empty fontlist passed in");
    1245             : 
    1246          19 :     aNeedsSyntheticBold = false;
    1247             : 
    1248          19 :     int8_t baseWeight = aFontStyle.ComputeWeight();
    1249          19 :     bool wantBold = baseWeight >= 6;
    1250          19 :     gfxFontEntry *fe = nullptr;
    1251             : 
    1252             :     // If the family has only one face, we simply return it; no further
    1253             :     // checking needed
    1254          19 :     uint32_t count = mAvailableFonts.Length();
    1255          19 :     if (count == 1) {
    1256           0 :         fe = mAvailableFonts[0];
    1257           0 :         aNeedsSyntheticBold =
    1258           0 :             wantBold && !fe->IsBold() && aFontStyle.allowSyntheticWeight;
    1259           0 :         aFontEntryList.AppendElement(fe);
    1260           0 :         return;
    1261             :     }
    1262             : 
    1263             :     // Most families are "simple", having just Regular/Bold/Italic/BoldItalic,
    1264             :     // or some subset of these. In this case, we have exactly 4 entries in mAvailableFonts,
    1265             :     // stored in the above order; note that some of the entries may be nullptr.
    1266             :     // We can then pick the required entry based on whether the request is for
    1267             :     // bold or non-bold, italic or non-italic, without running the more complex
    1268             :     // matching algorithm used for larger families with many weights and/or widths.
    1269             : 
    1270          19 :     if (mIsSimpleFamily) {
    1271             :         // Family has no more than the "standard" 4 faces, at fixed indexes;
    1272             :         // calculate which one we want.
    1273             :         // Note that we cannot simply return it as not all 4 faces are necessarily present.
    1274           5 :         bool wantItalic = (aFontStyle.style != NS_FONT_STYLE_NORMAL);
    1275           5 :         uint8_t faceIndex = (wantItalic ? kItalicMask : 0) |
    1276           5 :                             (wantBold ? kBoldMask : 0);
    1277             : 
    1278             :         // if the desired style is available, return it directly
    1279           5 :         fe = mAvailableFonts[faceIndex];
    1280           5 :         if (fe) {
    1281             :             // no need to set aNeedsSyntheticBold here as we matched the boldness request
    1282           5 :             aFontEntryList.AppendElement(fe);
    1283           5 :             return;
    1284             :         }
    1285             : 
    1286             :         // order to check fallback faces in a simple family, depending on requested style
    1287             :         static const uint8_t simpleFallbacks[4][3] = {
    1288             :             { kBoldFaceIndex, kItalicFaceIndex, kBoldItalicFaceIndex },   // fallbacks for Regular
    1289             :             { kRegularFaceIndex, kBoldItalicFaceIndex, kItalicFaceIndex },// Bold
    1290             :             { kBoldItalicFaceIndex, kRegularFaceIndex, kBoldFaceIndex },  // Italic
    1291             :             { kItalicFaceIndex, kBoldFaceIndex, kRegularFaceIndex }       // BoldItalic
    1292             :         };
    1293           0 :         const uint8_t *order = simpleFallbacks[faceIndex];
    1294             : 
    1295           0 :         for (uint8_t trial = 0; trial < 3; ++trial) {
    1296             :             // check remaining faces in order of preference to find the first that actually exists
    1297           0 :             fe = mAvailableFonts[order[trial]];
    1298           0 :             if (fe) {
    1299           0 :                 aNeedsSyntheticBold =
    1300           0 :                     wantBold && !fe->IsBold() &&
    1301           0 :                     aFontStyle.allowSyntheticWeight;
    1302           0 :                 aFontEntryList.AppendElement(fe);
    1303           0 :                 return;
    1304             :             }
    1305             :         }
    1306             : 
    1307             :         // this can't happen unless we have totally broken the font-list manager!
    1308           0 :         NS_NOTREACHED("no face found in simple font family!");
    1309             :     }
    1310             : 
    1311             :     // Pick the font(s) that are closest to the desired weight, style, and
    1312             :     // stretch. Iterate over all fonts, measuring the weight/style distance.
    1313             :     // Because of unicode-range values, there may be more than one font for a
    1314             :     // given but the 99% use case is only a single font entry per
    1315             :     // weight/style/stretch distance value. To optimize this, only add entries
    1316             :     // to the matched font array when another entry already has the same
    1317             :     // weight/style/stretch distance and add the last matched font entry. For
    1318             :     // normal platform fonts with a single font entry for each
    1319             :     // weight/style/stretch combination, only the last matched font entry will
    1320             :     // be added.
    1321             : 
    1322          14 :     uint32_t minDistance = MAX_DISTANCE;
    1323          14 :     gfxFontEntry* matched = nullptr;
    1324             :     // iterate in forward order so that faces like 'Bold' are matched before
    1325             :     // matching style distance faces such as 'Bold Outline' (see bug 1185812)
    1326         129 :     for (uint32_t i = 0; i < count; i++) {
    1327         115 :         fe = mAvailableFonts[i];
    1328             :         // weight/style/stretch priority: stretch >> style >> weight
    1329         115 :         uint32_t distance = WeightStyleStretchDistance(fe, aFontStyle);
    1330         115 :         if (distance < minDistance) {
    1331          28 :             matched = fe;
    1332          28 :             if (!aFontEntryList.IsEmpty()) {
    1333           0 :                 aFontEntryList.Clear();
    1334             :             }
    1335          28 :             minDistance = distance;
    1336          87 :         } else if (distance == minDistance) {
    1337           5 :             if (matched) {
    1338           5 :                 aFontEntryList.AppendElement(matched);
    1339             :             }
    1340           5 :             matched = fe;
    1341             :         }
    1342             :     }
    1343             : 
    1344          14 :     NS_ASSERTION(matched, "didn't match a font within a family");
    1345             : 
    1346          14 :     if (matched) {
    1347          14 :         aFontEntryList.AppendElement(matched);
    1348          14 :         if (!matched->IsBold() && aFontStyle.weight >= 600 &&
    1349           0 :             aFontStyle.allowSyntheticWeight) {
    1350           0 :             aNeedsSyntheticBold = true;
    1351             :         }
    1352             :     }
    1353             : }
    1354             : 
    1355             : void
    1356          16 : gfxFontFamily::CheckForSimpleFamily()
    1357             : {
    1358             :     // already checked this family
    1359          16 :     if (mIsSimpleFamily) {
    1360          14 :         return;
    1361             :     }
    1362             : 
    1363          16 :     uint32_t count = mAvailableFonts.Length();
    1364          16 :     if (count > 4 || count == 0) {
    1365          11 :         return; // can't be "simple" if there are >4 faces;
    1366             :                 // if none then the family is unusable anyway
    1367             :     }
    1368             : 
    1369           5 :     if (count == 1) {
    1370           0 :         mIsSimpleFamily = true;
    1371           0 :         return;
    1372             :     }
    1373             : 
    1374           5 :     int16_t firstStretch = mAvailableFonts[0]->Stretch();
    1375             : 
    1376           5 :     gfxFontEntry *faces[4] = { 0 };
    1377          12 :     for (uint8_t i = 0; i < count; ++i) {
    1378          10 :         gfxFontEntry *fe = mAvailableFonts[i];
    1379          10 :         if (fe->Stretch() != firstStretch || fe->IsOblique()) {
    1380             :             // simple families don't have varying font-stretch or oblique
    1381           3 :             return;
    1382             :         }
    1383          14 :         uint8_t faceIndex = (fe->IsItalic() ? kItalicMask : 0) |
    1384          14 :                             (fe->Weight() >= 600 ? kBoldMask : 0);
    1385           7 :         if (faces[faceIndex]) {
    1386           0 :             return; // two faces resolve to the same slot; family isn't "simple"
    1387             :         }
    1388           7 :         faces[faceIndex] = fe;
    1389             :     }
    1390             : 
    1391             :     // we have successfully slotted the available faces into the standard
    1392             :     // 4-face framework
    1393           2 :     mAvailableFonts.SetLength(4);
    1394          10 :     for (uint8_t i = 0; i < 4; ++i) {
    1395           8 :         if (mAvailableFonts[i].get() != faces[i]) {
    1396           0 :             mAvailableFonts[i].swap(faces[i]);
    1397             :         }
    1398             :     }
    1399             : 
    1400           2 :     mIsSimpleFamily = true;
    1401             : }
    1402             : 
    1403             : #ifdef DEBUG
    1404             : bool
    1405          21 : gfxFontFamily::ContainsFace(gfxFontEntry* aFontEntry) {
    1406          21 :     uint32_t i, numFonts = mAvailableFonts.Length();
    1407          62 :     for (i = 0; i < numFonts; i++) {
    1408          62 :         if (mAvailableFonts[i] == aFontEntry) {
    1409          21 :             return true;
    1410             :         }
    1411             :         // userfonts contain the actual real font entry
    1412          41 :         if (mAvailableFonts[i] && mAvailableFonts[i]->mIsUserFontContainer) {
    1413             :             gfxUserFontEntry* ufe =
    1414           0 :                 static_cast<gfxUserFontEntry*>(mAvailableFonts[i].get());
    1415           0 :             if (ufe->GetPlatformFontEntry() == aFontEntry) {
    1416           0 :                 return true;
    1417             :             }
    1418             :         }
    1419             :     }
    1420           0 :     return false;
    1421             : }
    1422             : #endif
    1423             : 
    1424           0 : void gfxFontFamily::LocalizedName(nsAString& aLocalizedName)
    1425             : {
    1426             :     // just return the primary name; subclasses should override
    1427           0 :     aLocalizedName = mName;
    1428           0 : }
    1429             : 
    1430             : // metric for how close a given font matches a style
    1431             : static int32_t
    1432           0 : CalcStyleMatch(gfxFontEntry *aFontEntry, const gfxFontStyle *aStyle)
    1433             : {
    1434           0 :     int32_t rank = 0;
    1435           0 :     if (aStyle) {
    1436             :          // italics
    1437           0 :          bool wantUpright = (aStyle->style == NS_FONT_STYLE_NORMAL);
    1438           0 :          if (aFontEntry->IsUpright() == wantUpright) {
    1439           0 :              rank += 10;
    1440             :          }
    1441             : 
    1442             :         // measure of closeness of weight to the desired value
    1443           0 :         rank += 9 - DeprecatedAbs(aFontEntry->Weight() / 100 - aStyle->ComputeWeight());
    1444             :     } else {
    1445             :         // if no font to match, prefer non-bold, non-italic fonts
    1446           0 :         if (aFontEntry->IsUpright()) {
    1447           0 :             rank += 3;
    1448             :         }
    1449           0 :         if (!aFontEntry->IsBold()) {
    1450           0 :             rank += 2;
    1451             :         }
    1452             :     }
    1453             : 
    1454           0 :     return rank;
    1455             : }
    1456             : 
    1457             : #define RANK_MATCHED_CMAP   20
    1458             : 
    1459             : void
    1460           0 : gfxFontFamily::FindFontForChar(GlobalFontMatch *aMatchData)
    1461             : {
    1462           0 :     if (mFamilyCharacterMapInitialized && !TestCharacterMap(aMatchData->mCh)) {
    1463             :         // none of the faces in the family support the required char,
    1464             :         // so bail out immediately
    1465           0 :         return;
    1466             :     }
    1467             : 
    1468             :     bool needsBold;
    1469             :     gfxFontEntry *fe =
    1470           0 :         FindFontForStyle(aMatchData->mStyle ? *aMatchData->mStyle
    1471             :                                             : gfxFontStyle(),
    1472           0 :                          needsBold);
    1473             : 
    1474           0 :     if (fe && !fe->SkipDuringSystemFallback()) {
    1475           0 :         int32_t rank = 0;
    1476             : 
    1477           0 :         if (fe->HasCharacter(aMatchData->mCh)) {
    1478           0 :             rank += RANK_MATCHED_CMAP;
    1479           0 :             aMatchData->mCount++;
    1480             : 
    1481           0 :             LogModule* log = gfxPlatform::GetLog(eGfxLog_textrun);
    1482             : 
    1483           0 :             if (MOZ_UNLIKELY(MOZ_LOG_TEST(log, LogLevel::Debug))) {
    1484           0 :                 uint32_t unicodeRange = FindCharUnicodeRange(aMatchData->mCh);
    1485           0 :                 Script script = GetScriptCode(aMatchData->mCh);
    1486           0 :                 MOZ_LOG(log, LogLevel::Debug,\
    1487             :                        ("(textrun-systemfallback-fonts) char: u+%6.6x "
    1488             :                         "unicode-range: %d script: %d match: [%s]\n",
    1489             :                         aMatchData->mCh,
    1490             :                         unicodeRange, int(script),
    1491             :                         NS_ConvertUTF16toUTF8(fe->Name()).get()));
    1492             :             }
    1493             :         }
    1494             : 
    1495           0 :         aMatchData->mCmapsTested++;
    1496           0 :         if (rank == 0) {
    1497           0 :             return;
    1498             :         }
    1499             : 
    1500             :          // omitting from original windows code -- family name, lang group, pitch
    1501             :          // not available in current FontEntry implementation
    1502           0 :         rank += CalcStyleMatch(fe, aMatchData->mStyle);
    1503             : 
    1504             :         // xxx - add whether AAT font with morphing info for specific lang groups
    1505             : 
    1506           0 :         if (rank > aMatchData->mMatchRank
    1507           0 :             || (rank == aMatchData->mMatchRank &&
    1508           0 :                 Compare(fe->Name(), aMatchData->mBestMatch->Name()) > 0))
    1509             :         {
    1510           0 :             aMatchData->mBestMatch = fe;
    1511           0 :             aMatchData->mMatchedFamily = this;
    1512           0 :             aMatchData->mMatchRank = rank;
    1513             :         }
    1514             :     }
    1515             : }
    1516             : 
    1517             : void
    1518           0 : gfxFontFamily::SearchAllFontsForChar(GlobalFontMatch *aMatchData)
    1519             : {
    1520           0 :     uint32_t i, numFonts = mAvailableFonts.Length();
    1521           0 :     for (i = 0; i < numFonts; i++) {
    1522           0 :         gfxFontEntry *fe = mAvailableFonts[i];
    1523           0 :         if (fe && fe->HasCharacter(aMatchData->mCh)) {
    1524           0 :             int32_t rank = RANK_MATCHED_CMAP;
    1525           0 :             rank += CalcStyleMatch(fe, aMatchData->mStyle);
    1526           0 :             if (rank > aMatchData->mMatchRank
    1527           0 :                 || (rank == aMatchData->mMatchRank &&
    1528           0 :                     Compare(fe->Name(), aMatchData->mBestMatch->Name()) > 0))
    1529             :             {
    1530           0 :                 aMatchData->mBestMatch = fe;
    1531           0 :                 aMatchData->mMatchedFamily = this;
    1532           0 :                 aMatchData->mMatchRank = rank;
    1533             :             }
    1534             :         }
    1535             :     }
    1536           0 : }
    1537             : 
    1538             : /*virtual*/
    1539           0 : gfxFontFamily::~gfxFontFamily()
    1540             : {
    1541             :     // Should not be dropped by stylo
    1542           0 :     MOZ_ASSERT(NS_IsMainThread());
    1543           0 : }
    1544             : 
    1545             : /*static*/ void
    1546           0 : gfxFontFamily::ReadOtherFamilyNamesForFace(const nsAString& aFamilyName,
    1547             :                                            const char *aNameData,
    1548             :                                            uint32_t aDataLength,
    1549             :                                            nsTArray<nsString>& aOtherFamilyNames,
    1550             :                                            bool useFullName)
    1551             : {
    1552             :     const gfxFontUtils::NameHeader *nameHeader =
    1553           0 :         reinterpret_cast<const gfxFontUtils::NameHeader*>(aNameData);
    1554             : 
    1555           0 :     uint32_t nameCount = nameHeader->count;
    1556           0 :     if (nameCount * sizeof(gfxFontUtils::NameRecord) > aDataLength) {
    1557           0 :         NS_WARNING("invalid font (name records)");
    1558           0 :         return;
    1559             :     }
    1560             :     
    1561             :     const gfxFontUtils::NameRecord *nameRecord =
    1562           0 :         reinterpret_cast<const gfxFontUtils::NameRecord*>(aNameData + sizeof(gfxFontUtils::NameHeader));
    1563           0 :     uint32_t stringsBase = uint32_t(nameHeader->stringOffset);
    1564             : 
    1565           0 :     for (uint32_t i = 0; i < nameCount; i++, nameRecord++) {
    1566           0 :         uint32_t nameLen = nameRecord->length;
    1567           0 :         uint32_t nameOff = nameRecord->offset;  // offset from base of string storage
    1568             : 
    1569           0 :         if (stringsBase + nameOff + nameLen > aDataLength) {
    1570           0 :             NS_WARNING("invalid font (name table strings)");
    1571           0 :             return;
    1572             :         }
    1573             : 
    1574           0 :         uint16_t nameID = nameRecord->nameID;
    1575           0 :         if ((useFullName && nameID == gfxFontUtils::NAME_ID_FULL) ||
    1576           0 :             (!useFullName && (nameID == gfxFontUtils::NAME_ID_FAMILY ||
    1577             :                               nameID == gfxFontUtils::NAME_ID_PREFERRED_FAMILY))) {
    1578           0 :             nsAutoString otherFamilyName;
    1579           0 :             bool ok = gfxFontUtils::DecodeFontName(aNameData + stringsBase + nameOff,
    1580             :                                                      nameLen,
    1581             :                                                      uint32_t(nameRecord->platformID),
    1582             :                                                      uint32_t(nameRecord->encodingID),
    1583             :                                                      uint32_t(nameRecord->languageID),
    1584           0 :                                                      otherFamilyName);
    1585             :             // add if not same as canonical family name
    1586           0 :             if (ok && otherFamilyName != aFamilyName) {
    1587           0 :                 aOtherFamilyNames.AppendElement(otherFamilyName);
    1588             :             }
    1589             :         }
    1590             :     }
    1591             : }
    1592             : 
    1593             : // returns true if other names were found, false otherwise
    1594             : bool
    1595           0 : gfxFontFamily::ReadOtherFamilyNamesForFace(gfxPlatformFontList *aPlatformFontList,
    1596             :                                            hb_blob_t           *aNameTable,
    1597             :                                            bool                 useFullName)
    1598             : {
    1599             :     uint32_t dataLength;
    1600           0 :     const char *nameData = hb_blob_get_data(aNameTable, &dataLength);
    1601           0 :     AutoTArray<nsString,4> otherFamilyNames;
    1602             : 
    1603           0 :     ReadOtherFamilyNamesForFace(mName, nameData, dataLength,
    1604           0 :                                 otherFamilyNames, useFullName);
    1605             : 
    1606           0 :     uint32_t n = otherFamilyNames.Length();
    1607           0 :     for (uint32_t i = 0; i < n; i++) {
    1608           0 :         aPlatformFontList->AddOtherFamilyName(this, otherFamilyNames[i]);
    1609             :     }
    1610             : 
    1611           0 :     return n != 0;
    1612             : }
    1613             : 
    1614             : void
    1615           0 : gfxFontFamily::ReadOtherFamilyNames(gfxPlatformFontList *aPlatformFontList)
    1616             : {
    1617           0 :     if (mOtherFamilyNamesInitialized) 
    1618           0 :         return;
    1619           0 :     mOtherFamilyNamesInitialized = true;
    1620             : 
    1621           0 :     FindStyleVariations();
    1622             : 
    1623             :     // read in other family names for the first face in the list
    1624           0 :     uint32_t i, numFonts = mAvailableFonts.Length();
    1625           0 :     const uint32_t kNAME = TRUETYPE_TAG('n','a','m','e');
    1626             : 
    1627           0 :     for (i = 0; i < numFonts; ++i) {
    1628           0 :         gfxFontEntry *fe = mAvailableFonts[i];
    1629           0 :         if (!fe) {
    1630           0 :             continue;
    1631             :         }
    1632           0 :         gfxFontEntry::AutoTable nameTable(fe, kNAME);
    1633           0 :         if (!nameTable) {
    1634           0 :             continue;
    1635             :         }
    1636           0 :         mHasOtherFamilyNames = ReadOtherFamilyNamesForFace(aPlatformFontList,
    1637             :                                                            nameTable);
    1638           0 :         break;
    1639             :     }
    1640             : 
    1641             :     // read in other names for the first face in the list with the assumption
    1642             :     // that if extra names don't exist in that face then they don't exist in
    1643             :     // other faces for the same font
    1644           0 :     if (!mHasOtherFamilyNames) 
    1645           0 :         return;
    1646             : 
    1647             :     // read in names for all faces, needed to catch cases where fonts have
    1648             :     // family names for individual weights (e.g. Hiragino Kaku Gothic Pro W6)
    1649           0 :     for ( ; i < numFonts; i++) {
    1650           0 :         gfxFontEntry *fe = mAvailableFonts[i];
    1651           0 :         if (!fe) {
    1652           0 :             continue;
    1653             :         }
    1654           0 :         gfxFontEntry::AutoTable nameTable(fe, kNAME);
    1655           0 :         if (!nameTable) {
    1656           0 :             continue;
    1657             :         }
    1658           0 :         ReadOtherFamilyNamesForFace(aPlatformFontList, nameTable);
    1659             :     }
    1660             : }
    1661             : 
    1662             : void
    1663           0 : gfxFontFamily::ReadFaceNames(gfxPlatformFontList *aPlatformFontList, 
    1664             :                              bool aNeedFullnamePostscriptNames,
    1665             :                              FontInfoData *aFontInfoData)
    1666             : {
    1667             :     // if all needed names have already been read, skip
    1668           0 :     if (mOtherFamilyNamesInitialized &&
    1669           0 :         (mFaceNamesInitialized || !aNeedFullnamePostscriptNames))
    1670           0 :         return;
    1671             : 
    1672           0 :     bool asyncFontLoaderDisabled = false;
    1673             : 
    1674           0 :     if (!mOtherFamilyNamesInitialized &&
    1675           0 :         aFontInfoData &&
    1676           0 :         aFontInfoData->mLoadOtherNames &&
    1677           0 :         !asyncFontLoaderDisabled)
    1678             :     {
    1679           0 :         AutoTArray<nsString,4> otherFamilyNames;
    1680             :         bool foundOtherNames =
    1681           0 :             aFontInfoData->GetOtherFamilyNames(mName, otherFamilyNames);
    1682           0 :         if (foundOtherNames) {
    1683           0 :             uint32_t i, n = otherFamilyNames.Length();
    1684           0 :             for (i = 0; i < n; i++) {
    1685           0 :                 aPlatformFontList->AddOtherFamilyName(this, otherFamilyNames[i]);
    1686             :             }
    1687             :         }
    1688           0 :         mOtherFamilyNamesInitialized = true;
    1689             :     }
    1690             : 
    1691             :     // if all needed data has been initialized, return
    1692           0 :     if (mOtherFamilyNamesInitialized &&
    1693           0 :         (mFaceNamesInitialized || !aNeedFullnamePostscriptNames)) {
    1694           0 :         return;
    1695             :     }
    1696             : 
    1697           0 :     FindStyleVariations(aFontInfoData);
    1698             : 
    1699             :     // check again, as style enumeration code may have loaded names
    1700           0 :     if (mOtherFamilyNamesInitialized &&
    1701           0 :         (mFaceNamesInitialized || !aNeedFullnamePostscriptNames)) {
    1702           0 :         return;
    1703             :     }
    1704             : 
    1705           0 :     uint32_t i, numFonts = mAvailableFonts.Length();
    1706           0 :     const uint32_t kNAME = TRUETYPE_TAG('n','a','m','e');
    1707             : 
    1708           0 :     bool firstTime = true, readAllFaces = false;
    1709           0 :     for (i = 0; i < numFonts; ++i) {
    1710           0 :         gfxFontEntry *fe = mAvailableFonts[i];
    1711           0 :         if (!fe) {
    1712           0 :             continue;
    1713             :         }
    1714             : 
    1715           0 :         nsAutoString fullname, psname;
    1716           0 :         bool foundFaceNames = false;
    1717           0 :         if (!mFaceNamesInitialized &&
    1718           0 :             aNeedFullnamePostscriptNames &&
    1719           0 :             aFontInfoData &&
    1720           0 :             aFontInfoData->mLoadFaceNames) {
    1721           0 :             aFontInfoData->GetFaceNames(fe->Name(), fullname, psname);
    1722           0 :             if (!fullname.IsEmpty()) {
    1723           0 :                 aPlatformFontList->AddFullname(fe, fullname);
    1724             :             }
    1725           0 :             if (!psname.IsEmpty()) {
    1726           0 :                 aPlatformFontList->AddPostscriptName(fe, psname);
    1727             :             }
    1728           0 :             foundFaceNames = true;
    1729             : 
    1730             :             // found everything needed? skip to next font
    1731           0 :             if (mOtherFamilyNamesInitialized) {
    1732           0 :                 continue;
    1733             :             }
    1734             :         }
    1735             : 
    1736             :         // load directly from the name table
    1737           0 :         gfxFontEntry::AutoTable nameTable(fe, kNAME);
    1738           0 :         if (!nameTable) {
    1739           0 :             continue;
    1740             :         }
    1741             : 
    1742           0 :         if (aNeedFullnamePostscriptNames && !foundFaceNames) {
    1743           0 :             if (gfxFontUtils::ReadCanonicalName(
    1744             :                     nameTable, gfxFontUtils::NAME_ID_FULL, fullname) == NS_OK)
    1745             :             {
    1746           0 :                 aPlatformFontList->AddFullname(fe, fullname);
    1747             :             }
    1748             : 
    1749           0 :             if (gfxFontUtils::ReadCanonicalName(
    1750             :                     nameTable, gfxFontUtils::NAME_ID_POSTSCRIPT, psname) == NS_OK)
    1751             :             {
    1752           0 :                 aPlatformFontList->AddPostscriptName(fe, psname);
    1753             :             }
    1754             :         }
    1755             : 
    1756           0 :         if (!mOtherFamilyNamesInitialized && (firstTime || readAllFaces)) {
    1757           0 :             bool foundOtherName = ReadOtherFamilyNamesForFace(aPlatformFontList,
    1758           0 :                                                               nameTable);
    1759             : 
    1760             :             // if the first face has a different name, scan all faces, otherwise
    1761             :             // assume the family doesn't have other names
    1762           0 :             if (firstTime && foundOtherName) {
    1763           0 :                 mHasOtherFamilyNames = true;
    1764           0 :                 readAllFaces = true;
    1765             :             }
    1766           0 :             firstTime = false;
    1767             :         }
    1768             : 
    1769             :         // if not reading in any more names, skip other faces
    1770           0 :         if (!readAllFaces && !aNeedFullnamePostscriptNames) {
    1771           0 :             break;
    1772             :         }
    1773             :     }
    1774             : 
    1775           0 :     mFaceNamesInitialized = true;
    1776           0 :     mOtherFamilyNamesInitialized = true;
    1777             : }
    1778             : 
    1779             : 
    1780             : gfxFontEntry*
    1781           0 : gfxFontFamily::FindFont(const nsAString& aPostscriptName)
    1782             : {
    1783             :     // find the font using a simple linear search
    1784           0 :     uint32_t numFonts = mAvailableFonts.Length();
    1785           0 :     for (uint32_t i = 0; i < numFonts; i++) {
    1786           0 :         gfxFontEntry *fe = mAvailableFonts[i].get();
    1787           0 :         if (fe && fe->Name() == aPostscriptName)
    1788           0 :             return fe;
    1789             :     }
    1790           0 :     return nullptr;
    1791             : }
    1792             : 
    1793             : void
    1794           0 : gfxFontFamily::ReadAllCMAPs(FontInfoData *aFontInfoData)
    1795             : {
    1796           0 :     FindStyleVariations(aFontInfoData);
    1797             : 
    1798           0 :     uint32_t i, numFonts = mAvailableFonts.Length();
    1799           0 :     for (i = 0; i < numFonts; i++) {
    1800           0 :         gfxFontEntry *fe = mAvailableFonts[i];
    1801             :         // don't try to load cmaps for downloadable fonts not yet loaded
    1802           0 :         if (!fe || fe->mIsUserFontContainer) {
    1803           0 :             continue;
    1804             :         }
    1805           0 :         fe->ReadCMAP(aFontInfoData);
    1806           0 :         mFamilyCharacterMap.Union(*(fe->mCharacterMap));
    1807             :     }
    1808           0 :     mFamilyCharacterMap.Compact();
    1809           0 :     mFamilyCharacterMapInitialized = true;
    1810           0 : }
    1811             : 
    1812             : void
    1813           0 : gfxFontFamily::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
    1814             :                                       FontListSizes* aSizes) const
    1815             : {
    1816           0 :     aSizes->mFontListSize +=
    1817           0 :         mName.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
    1818           0 :     aSizes->mCharMapsSize +=
    1819           0 :         mFamilyCharacterMap.SizeOfExcludingThis(aMallocSizeOf);
    1820             : 
    1821           0 :     aSizes->mFontListSize +=
    1822           0 :         mAvailableFonts.ShallowSizeOfExcludingThis(aMallocSizeOf);
    1823           0 :     for (uint32_t i = 0; i < mAvailableFonts.Length(); ++i) {
    1824           0 :         gfxFontEntry *fe = mAvailableFonts[i];
    1825           0 :         if (fe) {
    1826           0 :             fe->AddSizeOfIncludingThis(aMallocSizeOf, aSizes);
    1827             :         }
    1828             :     }
    1829           0 : }
    1830             : 
    1831             : void
    1832           0 : gfxFontFamily::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
    1833             :                                       FontListSizes* aSizes) const
    1834             : {
    1835           0 :     aSizes->mFontListSize += aMallocSizeOf(this);
    1836           0 :     AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
    1837           0 : }

Generated by: LCOV version 1.13