2018-11-30 22:52:05 +03:00
|
|
|
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
2014-09-16 13:58:12 +04:00
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
|
2018-04-13 22:34:37 +03:00
|
|
|
#include "gfxFontEntry.h"
|
|
|
|
|
2014-09-16 13:58:12 +04:00
|
|
|
#include "mozilla/DebugOnly.h"
|
2018-04-13 22:34:37 +03:00
|
|
|
#include "mozilla/FontPropertyTypes.h"
|
2014-09-16 13:58:12 +04:00
|
|
|
#include "mozilla/MathAlgorithms.h"
|
|
|
|
|
2015-05-19 21:15:34 +03:00
|
|
|
#include "mozilla/Logging.h"
|
2014-09-16 13:58:12 +04:00
|
|
|
|
|
|
|
#include "gfxTextRun.h"
|
|
|
|
#include "gfxPlatform.h"
|
|
|
|
#include "nsGkAtoms.h"
|
|
|
|
|
|
|
|
#include "gfxTypes.h"
|
|
|
|
#include "gfxContext.h"
|
|
|
|
#include "gfxFontConstants.h"
|
|
|
|
#include "gfxHarfBuzzShaper.h"
|
|
|
|
#include "gfxUserFontSet.h"
|
|
|
|
#include "gfxPlatformFontList.h"
|
|
|
|
#include "nsUnicodeProperties.h"
|
|
|
|
#include "nsMathUtils.h"
|
|
|
|
#include "nsBidiUtils.h"
|
|
|
|
#include "nsStyleConsts.h"
|
|
|
|
#include "mozilla/AppUnits.h"
|
|
|
|
#include "mozilla/FloatingPoint.h"
|
|
|
|
#include "mozilla/Likely.h"
|
|
|
|
#include "mozilla/MemoryReporting.h"
|
|
|
|
#include "mozilla/Preferences.h"
|
|
|
|
#include "mozilla/Services.h"
|
2018-05-04 19:35:38 +03:00
|
|
|
#include "mozilla/StaticPrefs.h"
|
2014-09-16 13:58:12 +04:00
|
|
|
#include "mozilla/Telemetry.h"
|
|
|
|
#include "gfxSVGGlyphs.h"
|
|
|
|
#include "gfx2DGlue.h"
|
|
|
|
|
|
|
|
#include "harfbuzz/hb.h"
|
|
|
|
#include "harfbuzz/hb-ot.h"
|
|
|
|
#include "graphite2/Font.h"
|
|
|
|
|
|
|
|
#include <algorithm>
|
|
|
|
|
|
|
|
using namespace mozilla;
|
|
|
|
using namespace mozilla::gfx;
|
|
|
|
using namespace mozilla::unicode;
|
|
|
|
using mozilla::services::GetObserverService;
|
|
|
|
|
|
|
|
void gfxCharacterMap::NotifyReleased() {
|
|
|
|
gfxPlatformFontList* fontlist = gfxPlatformFontList::PlatformFontList();
|
|
|
|
if (mShared) {
|
|
|
|
fontlist->RemoveCmap(this);
|
|
|
|
}
|
|
|
|
delete this;
|
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2018-04-13 16:01:28 +03:00
|
|
|
gfxFontEntry::gfxFontEntry()
|
2018-04-23 17:52:20 +03:00
|
|
|
: mFixedPitch(false),
|
2018-04-13 16:01:28 +03:00
|
|
|
mIsBadUnderlineFont(false),
|
|
|
|
mIsUserFontContainer(false),
|
|
|
|
mIsDataUserFont(false),
|
|
|
|
mIsLocalUserFont(false),
|
|
|
|
mStandardFace(false),
|
|
|
|
mIgnoreGDEF(false),
|
|
|
|
mIgnoreGSUB(false),
|
|
|
|
mSVGInitialized(false),
|
|
|
|
mHasSpaceFeaturesInitialized(false),
|
|
|
|
mHasSpaceFeatures(false),
|
|
|
|
mHasSpaceFeaturesKerning(false),
|
|
|
|
mHasSpaceFeaturesNonKerning(false),
|
|
|
|
mSkipDefaultFeatureSpaceCheck(false),
|
|
|
|
mGraphiteSpaceContextualsInitialized(false),
|
|
|
|
mHasGraphiteSpaceContextuals(false),
|
|
|
|
mSpaceGlyphIsInvisible(false),
|
|
|
|
mSpaceGlyphIsInvisibleInitialized(false),
|
2018-06-16 17:42:33 +03:00
|
|
|
mHasGraphiteTables(false),
|
2018-04-13 16:01:28 +03:00
|
|
|
mCheckedForGraphiteTables(false),
|
|
|
|
mHasCmapTable(false),
|
|
|
|
mGrFaceInitialized(false),
|
2018-05-04 12:19:55 +03:00
|
|
|
mCheckedForColorGlyph(false),
|
2018-05-09 15:49:24 +03:00
|
|
|
mCheckedForVariationAxes(false) {
|
2014-09-16 13:58:12 +04:00
|
|
|
memset(&mDefaultSubSpaceFeatures, 0, sizeof(mDefaultSubSpaceFeatures));
|
|
|
|
memset(&mNonDefaultSubSpaceFeatures, 0, sizeof(mNonDefaultSubSpaceFeatures));
|
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2018-09-12 22:34:57 +03:00
|
|
|
gfxFontEntry::gfxFontEntry(const nsACString& aName, bool aIsStandardFace)
|
2018-04-25 20:54:03 +03:00
|
|
|
: mName(aName),
|
|
|
|
mFixedPitch(false),
|
2018-04-13 16:01:28 +03:00
|
|
|
mIsBadUnderlineFont(false),
|
|
|
|
mIsUserFontContainer(false),
|
|
|
|
mIsDataUserFont(false),
|
2018-04-25 20:54:03 +03:00
|
|
|
mIsLocalUserFont(false),
|
|
|
|
mStandardFace(aIsStandardFace),
|
2018-04-13 16:01:28 +03:00
|
|
|
mIgnoreGDEF(false),
|
|
|
|
mIgnoreGSUB(false),
|
|
|
|
mSVGInitialized(false),
|
|
|
|
mHasSpaceFeaturesInitialized(false),
|
|
|
|
mHasSpaceFeatures(false),
|
|
|
|
mHasSpaceFeaturesKerning(false),
|
|
|
|
mHasSpaceFeaturesNonKerning(false),
|
|
|
|
mSkipDefaultFeatureSpaceCheck(false),
|
|
|
|
mGraphiteSpaceContextualsInitialized(false),
|
|
|
|
mHasGraphiteSpaceContextuals(false),
|
|
|
|
mSpaceGlyphIsInvisible(false),
|
|
|
|
mSpaceGlyphIsInvisibleInitialized(false),
|
2018-06-16 17:42:33 +03:00
|
|
|
mHasGraphiteTables(false),
|
2018-04-13 16:01:28 +03:00
|
|
|
mCheckedForGraphiteTables(false),
|
|
|
|
mHasCmapTable(false),
|
|
|
|
mGrFaceInitialized(false),
|
2018-05-04 12:19:55 +03:00
|
|
|
mCheckedForColorGlyph(false),
|
2018-05-09 15:49:24 +03:00
|
|
|
mCheckedForVariationAxes(false) {
|
2014-09-16 13:58:12 +04:00
|
|
|
memset(&mDefaultSubSpaceFeatures, 0, sizeof(mDefaultSubSpaceFeatures));
|
|
|
|
memset(&mNonDefaultSubSpaceFeatures, 0, sizeof(mNonDefaultSubSpaceFeatures));
|
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2014-09-16 13:58:12 +04:00
|
|
|
gfxFontEntry::~gfxFontEntry() {
|
2017-04-08 01:49:44 +03:00
|
|
|
// Should not be dropped by stylo
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2019-02-18 20:16:22 +03:00
|
|
|
hb_blob_destroy(mCOLR);
|
|
|
|
hb_blob_destroy(mCPAL);
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2014-09-16 13:58:12 +04:00
|
|
|
// For downloaded fonts, we need to tell the user font cache that this
|
|
|
|
// entry is being deleted.
|
|
|
|
if (mIsDataUserFont) {
|
|
|
|
gfxUserFontSet::UserFontCache::ForgetFont(this);
|
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2014-09-16 13:58:12 +04:00
|
|
|
if (mFeatureInputs) {
|
2015-09-24 18:31:30 +03:00
|
|
|
for (auto iter = mFeatureInputs->Iter(); !iter.Done(); iter.Next()) {
|
|
|
|
hb_set_t*& set = iter.Data();
|
|
|
|
hb_set_destroy(set);
|
2014-09-16 13:58:12 +04:00
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
2014-09-16 13:58:12 +04:00
|
|
|
|
|
|
|
// By the time the entry is destroyed, all font instances that were
|
|
|
|
// using it should already have been deleted, and so the HB and/or Gr
|
|
|
|
// face objects should have been released.
|
|
|
|
MOZ_ASSERT(!mHBFace);
|
|
|
|
MOZ_ASSERT(!mGrFaceInitialized);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool gfxFontEntry::TestCharacterMap(uint32_t aCh) {
|
2019-04-27 18:37:58 +03:00
|
|
|
if (!mCharacterMap && !mShmemCharacterMap) {
|
2014-09-16 13:58:12 +04:00
|
|
|
ReadCMAP();
|
2019-04-27 18:37:58 +03:00
|
|
|
MOZ_ASSERT(mCharacterMap || mShmemCharacterMap,
|
|
|
|
"failed to initialize character map");
|
2014-09-16 13:58:12 +04:00
|
|
|
}
|
2019-04-27 18:37:58 +03:00
|
|
|
return mShmemCharacterMap ? mShmemCharacterMap->test(aCh)
|
|
|
|
: mCharacterMap->test(aCh);
|
2014-09-16 13:58:12 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
nsresult gfxFontEntry::InitializeUVSMap() {
|
|
|
|
// mUVSOffset will not be initialized
|
|
|
|
// until cmap is initialized.
|
|
|
|
if (!mCharacterMap) {
|
|
|
|
ReadCMAP();
|
|
|
|
NS_ASSERTION(mCharacterMap, "failed to initialize character map");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!mUVSOffset) {
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!mUVSData) {
|
|
|
|
const uint32_t kCmapTag = TRUETYPE_TAG('c', 'm', 'a', 'p');
|
|
|
|
AutoTable cmapTable(this, kCmapTag);
|
|
|
|
if (!cmapTable) {
|
|
|
|
mUVSOffset = 0; // don't bother to read the table again
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
2015-10-20 19:12:41 +03:00
|
|
|
UniquePtr<uint8_t[]> uvsData;
|
2014-09-16 13:58:12 +04:00
|
|
|
unsigned int cmapLen;
|
|
|
|
const char* cmapData = hb_blob_get_data(cmapTable, &cmapLen);
|
|
|
|
nsresult rv = gfxFontUtils::ReadCMAPTableFormat14(
|
|
|
|
(const uint8_t*)cmapData + mUVSOffset, cmapLen - mUVSOffset, uvsData);
|
|
|
|
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
mUVSOffset = 0; // don't bother to read the table again
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2018-05-30 22:15:35 +03:00
|
|
|
mUVSData = std::move(uvsData);
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
|
2014-09-16 13:58:12 +04:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint16_t gfxFontEntry::GetUVSGlyph(uint32_t aCh, uint32_t aVS) {
|
|
|
|
InitializeUVSMap();
|
|
|
|
|
|
|
|
if (mUVSData) {
|
2015-10-20 19:12:41 +03:00
|
|
|
return gfxFontUtils::MapUVSToGlyphFormat14(mUVSData.get(), aCh, aVS);
|
2014-09-16 13:58:12 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-12-08 16:44:55 +03:00
|
|
|
bool gfxFontEntry::SupportsScriptInGSUB(const hb_tag_t* aScriptTags,
|
|
|
|
uint32_t aNumTags) {
|
2014-09-16 13:58:12 +04:00
|
|
|
hb_face_t* face = GetHBFace();
|
|
|
|
if (!face) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned int index;
|
|
|
|
hb_tag_t chosenScript;
|
2018-12-08 16:44:55 +03:00
|
|
|
bool found = hb_ot_layout_table_select_script(
|
|
|
|
face, TRUETYPE_TAG('G', 'S', 'U', 'B'), aNumTags, aScriptTags, &index,
|
|
|
|
&chosenScript);
|
2014-09-16 13:58:12 +04:00
|
|
|
hb_face_destroy(face);
|
|
|
|
|
|
|
|
return found && chosenScript != TRUETYPE_TAG('D', 'F', 'L', 'T');
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult gfxFontEntry::ReadCMAP(FontInfoData* aFontInfoData) {
|
|
|
|
NS_ASSERTION(false, "using default no-op implementation of ReadCMAP");
|
|
|
|
mCharacterMap = new gfxCharacterMap();
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsCString gfxFontEntry::RealFaceName() {
|
|
|
|
AutoTable nameTable(this, TRUETYPE_TAG('n', 'a', 'm', 'e'));
|
|
|
|
if (nameTable) {
|
2018-09-12 22:34:57 +03:00
|
|
|
nsAutoCString name;
|
2014-09-16 13:58:12 +04:00
|
|
|
nsresult rv = gfxFontUtils::GetFullNameFromTable(nameTable, name);
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
Bug 1489944 - Fixed some std::move warnings - r=froydnj
> dom/media/gmp/CDMStorageIdProvider.cpp(63,10): warning:
> local variable 'storageId' will be copied despite being returned by name [-Wreturn-std-move]
nsAutoCString -> nsCString, will add std::move().
> layout/painting/DisplayItemClip.cpp(581,10): warning:
> local variable 'str' will be copied despite being returned by name [-Wreturn-std-move]
nsAutoCString -> nsCString, will add std::move().
> layout/painting/DisplayItemClipChain.cpp(88,10): warning:
> local variable 'str' will be copied despite being returned by name [-Wreturn-std-move]
nsAutoCString -> nsCString, will add std::move().
> layout/painting/nsDisplayList.cpp(179,10): warning:
> local variable 'str' will be copied despite being returned by name [-Wreturn-std-move]
nsAutoCString -> nsCString, will add std::move().
> gfx/thebes/gfxWindowsPlatform.cpp(454,10): warning:
> moving a local object in a return statement prevents copy elision [-Wpessimizing-move]
Will remove std::move().
> gfx/thebes/gfxFontEntry.cpp(245,20): warning:
> local variable 'name' will be copied despite being returned by name [-Wreturn-std-move]
nsAutoCString -> nsCString, will add std::move().
> netwerk/cookie/nsCookieService.cpp(4460,10): warning:
> local variable 'path' will be copied despite being returned by name [-Wreturn-std-move]
GetPathFromURI() result is stored in an nsAutoCString, so it might as well return that type.
> toolkit/components/extensions/WebExtensionPolicy.cpp(462,12): warning:
> local variable 'result' will be copied despite being returned by name [-Wreturn-std-move]
> toolkit/components/extensions/WebExtensionPolicy.cpp(475,10): warning:
> local variable 'result' will be copied despite being returned by name [-Wreturn-std-move]
`result` may be empty or may be arbitrarily long, so I'll use nsCString inside the function.
> toolkit/xre/CmdLineAndEnvUtils.h(349,10): warning:
> moving a local object in a return statement prevents copy elision [-Wpessimizing-move]
Returning an UniquePtr, will remove std::move().
Also will `return s` instead of `return nullptr` when `(!s)`, to avoid extra construction which could also prevent elision (not entirely sure, but it's at least not worse!); and it's clearer that the two `return`s return the same already-constructed on-stack object.
> tools/profiler/core/shared-libraries-win32.cc(111,10): warning:
> local variable 'version' will be copied despite being returned by name [-Wreturn-std-move]
nsPrintfCString -> nsCString, will add std::move().
> xpcom/glue/FileUtils.cpp(179,10): warning:
> local variable 'fullName' will be copied despite being returned by name [-Wreturn-std-move]
> xpcom/glue/FileUtils.cpp(209,10): warning:
> local variable 'path' will be copied despite being returned by name [-Wreturn-std-move]
nsAuto{,C}String -> ns{,C}String, will add std::move().
This allowed removals of 'AllowCompilerWarnings' from layout/painting,
netwerk/cookie, and toolkit/components/extensions.
Differential Revision: https://phabricator.services.mozilla.com/D5425
--HG--
extra : moz-landing-system : lando
2018-09-10 18:51:48 +03:00
|
|
|
return std::move(name);
|
2014-09-16 13:58:12 +04:00
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
2014-09-16 13:58:12 +04:00
|
|
|
return Name();
|
|
|
|
}
|
|
|
|
|
2014-11-06 07:42:50 +03:00
|
|
|
gfxFont* gfxFontEntry::FindOrMakeFont(const gfxFontStyle* aStyle,
|
|
|
|
gfxCharacterMap* aUnicodeRangeMap) {
|
2014-09-16 13:58:12 +04:00
|
|
|
// the font entry name is the psname, not the family name
|
2017-06-30 01:37:52 +03:00
|
|
|
gfxFont* font =
|
2016-09-27 03:48:56 +03:00
|
|
|
gfxFontCache::GetCache()->Lookup(this, aStyle, aUnicodeRangeMap);
|
2014-09-16 13:58:12 +04:00
|
|
|
|
|
|
|
if (!font) {
|
|
|
|
gfxFont* newFont = CreateFontInstance(aStyle);
|
|
|
|
if (!newFont) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
if (!newFont->Valid()) {
|
|
|
|
delete newFont;
|
|
|
|
return nullptr;
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
2014-09-16 13:58:12 +04:00
|
|
|
font = newFont;
|
|
|
|
font->SetUnicodeRangeMap(aUnicodeRangeMap);
|
|
|
|
gfxFontCache::GetCache()->AddNew(font);
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
2014-09-16 13:58:12 +04:00
|
|
|
return font;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint16_t gfxFontEntry::UnitsPerEm() {
|
|
|
|
if (!mUnitsPerEm) {
|
|
|
|
AutoTable headTable(this, TRUETYPE_TAG('h', 'e', 'a', 'd'));
|
|
|
|
if (headTable) {
|
|
|
|
uint32_t len;
|
|
|
|
const HeadTable* head =
|
|
|
|
reinterpret_cast<const HeadTable*>(hb_blob_get_data(headTable, &len));
|
|
|
|
if (len >= sizeof(HeadTable)) {
|
|
|
|
mUnitsPerEm = head->unitsPerEm;
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-16 13:58:12 +04:00
|
|
|
// if we didn't find a usable 'head' table, or if the value was
|
|
|
|
// outside the valid range, record it as invalid
|
|
|
|
if (mUnitsPerEm < kMinUPEM || mUnitsPerEm > kMaxUPEM) {
|
|
|
|
mUnitsPerEm = kInvalidUPEM;
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
}
|
2014-09-16 13:58:12 +04:00
|
|
|
return mUnitsPerEm;
|
|
|
|
}
|
|
|
|
|
2015-12-16 00:56:40 +03:00
|
|
|
bool gfxFontEntry::HasSVGGlyph(uint32_t aGlyphId) {
|
2015-02-10 01:34:50 +03:00
|
|
|
NS_ASSERTION(mSVGInitialized,
|
|
|
|
"SVG data has not yet been loaded. TryGetSVGData() first.");
|
2017-11-23 22:40:33 +03:00
|
|
|
return mSVGGlyphs->HasSVGGlyph(aGlyphId);
|
2014-09-16 13:58:12 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
bool gfxFontEntry::GetSVGGlyphExtents(DrawTarget* aDrawTarget,
|
|
|
|
uint32_t aGlyphId, gfxFloat aSize,
|
2016-07-22 16:56:09 +03:00
|
|
|
gfxRect* aResult) {
|
2014-09-16 13:58:12 +04:00
|
|
|
MOZ_ASSERT(mSVGInitialized,
|
|
|
|
"SVG data has not yet been loaded. TryGetSVGData() first.");
|
2015-02-10 01:34:50 +03:00
|
|
|
MOZ_ASSERT(mUnitsPerEm >= kMinUPEM && mUnitsPerEm <= kMaxUPEM,
|
2017-05-18 23:03:41 +03:00
|
|
|
"font has invalid unitsPerEm");
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2017-05-18 23:03:41 +03:00
|
|
|
gfxMatrix svgToApp(aSize / mUnitsPerEm, 0, 0, aSize / mUnitsPerEm, 0, 0);
|
|
|
|
return mSVGGlyphs->GetGlyphExtents(aGlyphId, svgToApp, aResult);
|
2014-09-16 13:58:12 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void gfxFontEntry::RenderSVGGlyph(gfxContext* aContext, uint32_t aGlyphId,
|
|
|
|
SVGContextPaint* aContextPaint) {
|
2014-11-06 07:42:50 +03:00
|
|
|
NS_ASSERTION(mSVGInitialized,
|
2014-09-16 13:58:12 +04:00
|
|
|
"SVG data has not yet been loaded. TryGetSVGData() first.");
|
|
|
|
mSVGGlyphs->RenderGlyph(aContext, aGlyphId, aContextPaint);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool gfxFontEntry::TryGetSVGData(gfxFont* aFont) {
|
|
|
|
if (!gfxPlatform::GetPlatform()->OpenTypeSVGEnabled()) {
|
|
|
|
return false;
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
2014-09-16 13:58:12 +04:00
|
|
|
|
|
|
|
if (!mSVGInitialized) {
|
|
|
|
mSVGInitialized = true;
|
|
|
|
|
|
|
|
// If UnitsPerEm is not known/valid, we can't use SVG glyphs
|
|
|
|
if (UnitsPerEm() == kInvalidUPEM) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-07-22 08:54:12 +03:00
|
|
|
// We don't use AutoTable here because we'll pass ownership of this
|
|
|
|
// blob to the gfxSVGGlyphs, once we've confirmed the table exists
|
|
|
|
hb_blob_t* svgTable = GetFontTable(TRUETYPE_TAG('S', 'V', 'G', ' '));
|
|
|
|
if (!svgTable) {
|
2014-09-16 13:58:12 +04:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// gfxSVGGlyphs will hb_blob_destroy() the table when it is finished
|
|
|
|
// with it.
|
|
|
|
mSVGGlyphs = MakeUnique<gfxSVGGlyphs>(svgTable, this);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mSVGGlyphs && !mFontsUsingSVGGlyphs.Contains(aFont)) {
|
|
|
|
mFontsUsingSVGGlyphs.AppendElement(aFont);
|
|
|
|
}
|
|
|
|
|
|
|
|
return !!mSVGGlyphs;
|
|
|
|
}
|
|
|
|
|
|
|
|
void gfxFontEntry::NotifyFontDestroyed(gfxFont* aFont) {
|
|
|
|
mFontsUsingSVGGlyphs.RemoveElement(aFont);
|
|
|
|
}
|
|
|
|
|
|
|
|
void gfxFontEntry::NotifyGlyphsChanged() {
|
|
|
|
for (uint32_t i = 0, count = mFontsUsingSVGGlyphs.Length(); i < count; ++i) {
|
|
|
|
gfxFont* font = mFontsUsingSVGGlyphs[i];
|
|
|
|
font->NotifyGlyphsChanged();
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
}
|
2014-09-16 13:58:12 +04:00
|
|
|
|
|
|
|
bool gfxFontEntry::TryGetColorGlyphs() {
|
|
|
|
if (mCheckedForColorGlyph) {
|
|
|
|
return (mCOLR && mCPAL);
|
|
|
|
}
|
|
|
|
|
|
|
|
mCheckedForColorGlyph = true;
|
|
|
|
|
|
|
|
mCOLR = GetFontTable(TRUETYPE_TAG('C', 'O', 'L', 'R'));
|
|
|
|
if (!mCOLR) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
mCPAL = GetFontTable(TRUETYPE_TAG('C', 'P', 'A', 'L'));
|
|
|
|
if (!mCPAL) {
|
|
|
|
hb_blob_destroy(mCOLR);
|
|
|
|
mCOLR = nullptr;
|
|
|
|
return false;
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
|
2014-09-16 13:58:12 +04:00
|
|
|
// validation COLR and CPAL table
|
|
|
|
if (gfxFontUtils::ValidateColorGlyphs(mCOLR, mCPAL)) {
|
|
|
|
return true;
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
|
2014-09-16 13:58:12 +04:00
|
|
|
hb_blob_destroy(mCOLR);
|
|
|
|
hb_blob_destroy(mCPAL);
|
|
|
|
mCOLR = nullptr;
|
|
|
|
mCPAL = nullptr;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* FontTableBlobData
|
|
|
|
*
|
|
|
|
* See FontTableHashEntry for the general strategy.
|
|
|
|
*/
|
|
|
|
|
|
|
|
class gfxFontEntry::FontTableBlobData {
|
|
|
|
public:
|
2016-02-02 18:36:30 +03:00
|
|
|
explicit FontTableBlobData(nsTArray<uint8_t>&& aBuffer)
|
2018-05-30 22:15:35 +03:00
|
|
|
: mTableData(std::move(aBuffer)), mHashtable(nullptr), mHashKey(0) {
|
2014-09-16 13:58:12 +04:00
|
|
|
MOZ_COUNT_CTOR(FontTableBlobData);
|
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2014-09-16 13:58:12 +04:00
|
|
|
~FontTableBlobData() {
|
|
|
|
MOZ_COUNT_DTOR(FontTableBlobData);
|
|
|
|
if (mHashtable && mHashKey) {
|
|
|
|
mHashtable->RemoveEntry(mHashKey);
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
2014-09-16 13:58:12 +04:00
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2014-09-16 13:58:12 +04:00
|
|
|
// Useful for creating blobs
|
|
|
|
const char* GetTable() const {
|
|
|
|
return reinterpret_cast<const char*>(mTableData.Elements());
|
|
|
|
}
|
|
|
|
uint32_t GetTableLength() const { return mTableData.Length(); }
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2014-09-16 13:58:12 +04:00
|
|
|
// Tell this FontTableBlobData to remove the HashEntry when this is
|
|
|
|
// destroyed.
|
|
|
|
void ManageHashEntry(nsTHashtable<FontTableHashEntry>* aHashtable,
|
|
|
|
uint32_t aHashKey) {
|
|
|
|
mHashtable = aHashtable;
|
|
|
|
mHashKey = aHashKey;
|
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2014-09-16 13:58:12 +04:00
|
|
|
// Disconnect from the HashEntry (because the blob has already been
|
|
|
|
// removed from the hashtable).
|
|
|
|
void ForgetHashEntry() {
|
|
|
|
mHashtable = nullptr;
|
|
|
|
mHashKey = 0;
|
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2014-09-16 13:58:12 +04:00
|
|
|
size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const {
|
2015-07-29 09:24:24 +03:00
|
|
|
return mTableData.ShallowSizeOfExcludingThis(aMallocSizeOf);
|
2014-09-16 13:58:12 +04:00
|
|
|
}
|
|
|
|
size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const {
|
|
|
|
return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
|
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2014-09-16 13:58:12 +04:00
|
|
|
private:
|
2016-02-02 18:36:30 +03:00
|
|
|
// The font table data block
|
|
|
|
nsTArray<uint8_t> mTableData;
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2014-09-16 13:58:12 +04:00
|
|
|
// The blob destroy function needs to know the owning hashtable
|
|
|
|
// and the hashtable key, so that it can remove the entry.
|
|
|
|
nsTHashtable<FontTableHashEntry>* mHashtable;
|
|
|
|
uint32_t mHashKey;
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2014-09-16 13:58:12 +04:00
|
|
|
// not implemented
|
|
|
|
FontTableBlobData(const FontTableBlobData&);
|
2018-11-30 13:46:48 +03:00
|
|
|
};
|
2014-09-16 13:58:12 +04:00
|
|
|
|
|
|
|
hb_blob_t* gfxFontEntry::FontTableHashEntry::ShareTableAndGetBlob(
|
|
|
|
nsTArray<uint8_t>&& aTable, nsTHashtable<FontTableHashEntry>* aHashtable) {
|
2018-11-30 13:46:48 +03:00
|
|
|
Clear();
|
2014-09-16 13:58:12 +04:00
|
|
|
// adopts elements of aTable
|
|
|
|
mSharedBlobData = new FontTableBlobData(std::move(aTable));
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2014-09-16 13:58:12 +04:00
|
|
|
mBlob = hb_blob_create(
|
|
|
|
mSharedBlobData->GetTable(), mSharedBlobData->GetTableLength(),
|
|
|
|
HB_MEMORY_MODE_READONLY, mSharedBlobData, DeleteFontTableBlobData);
|
2016-02-10 17:47:02 +03:00
|
|
|
if (mBlob == hb_blob_get_empty()) {
|
2014-09-16 13:58:12 +04:00
|
|
|
// The FontTableBlobData was destroyed during hb_blob_create().
|
|
|
|
// The (empty) blob is still be held in the hashtable with a strong
|
|
|
|
// reference.
|
|
|
|
return hb_blob_reference(mBlob);
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
2014-09-16 13:58:12 +04:00
|
|
|
|
|
|
|
// Tell the FontTableBlobData to remove this hash entry when destroyed.
|
|
|
|
// The hashtable does not keep a strong reference.
|
|
|
|
mSharedBlobData->ManageHashEntry(aHashtable, GetKey());
|
|
|
|
return mBlob;
|
|
|
|
}
|
|
|
|
|
|
|
|
void gfxFontEntry::FontTableHashEntry::Clear() {
|
|
|
|
// If the FontTableBlobData is managing the hash entry, then the blob is
|
|
|
|
// not owned by this HashEntry; otherwise there is strong reference to the
|
|
|
|
// blob that must be removed.
|
|
|
|
if (mSharedBlobData) {
|
|
|
|
mSharedBlobData->ForgetHashEntry();
|
|
|
|
mSharedBlobData = nullptr;
|
2019-02-18 20:16:22 +03:00
|
|
|
} else {
|
2014-09-16 13:58:12 +04:00
|
|
|
hb_blob_destroy(mBlob);
|
|
|
|
}
|
|
|
|
mBlob = nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
// a hb_destroy_func for hb_blob_create
|
|
|
|
|
2019-02-26 01:07:19 +03:00
|
|
|
/* static */
|
|
|
|
void gfxFontEntry::FontTableHashEntry::DeleteFontTableBlobData(
|
2014-09-16 13:58:12 +04:00
|
|
|
void* aBlobData) {
|
|
|
|
delete static_cast<FontTableBlobData*>(aBlobData);
|
|
|
|
}
|
|
|
|
|
|
|
|
hb_blob_t* gfxFontEntry::FontTableHashEntry::GetBlob() const {
|
|
|
|
return hb_blob_reference(mBlob);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool gfxFontEntry::GetExistingFontTable(uint32_t aTag, hb_blob_t** aBlob) {
|
|
|
|
if (!mFontTableCache) {
|
|
|
|
// we do this here rather than on fontEntry construction
|
|
|
|
// because not all shapers will access the table cache at all
|
2016-04-15 22:45:37 +03:00
|
|
|
mFontTableCache = MakeUnique<nsTHashtable<FontTableHashEntry>>(8);
|
2014-09-16 13:58:12 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
FontTableHashEntry* entry = mFontTableCache->GetEntry(aTag);
|
|
|
|
if (!entry) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
*aBlob = entry->GetBlob();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
hb_blob_t* gfxFontEntry::ShareFontTableAndGetBlob(uint32_t aTag,
|
2016-02-02 18:36:30 +03:00
|
|
|
nsTArray<uint8_t>* aBuffer) {
|
2014-09-16 13:58:12 +04:00
|
|
|
if (MOZ_UNLIKELY(!mFontTableCache)) {
|
|
|
|
// we do this here rather than on fontEntry construction
|
|
|
|
// because not all shapers will access the table cache at all
|
2016-04-15 22:45:37 +03:00
|
|
|
mFontTableCache = MakeUnique<nsTHashtable<FontTableHashEntry>>(8);
|
2014-09-16 13:58:12 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
FontTableHashEntry* entry = mFontTableCache->PutEntry(aTag);
|
|
|
|
if (MOZ_UNLIKELY(!entry)) { // OOM
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!aBuffer) {
|
|
|
|
// ensure the entry is null
|
|
|
|
entry->Clear();
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2018-05-30 22:15:35 +03:00
|
|
|
return entry->ShareTableAndGetBlob(std::move(*aBuffer),
|
|
|
|
mFontTableCache.get());
|
2014-09-16 13:58:12 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
already_AddRefed<gfxCharacterMap> gfxFontEntry::GetCMAPFromFontInfo(
|
|
|
|
FontInfoData* aFontInfoData, uint32_t& aUVSOffset) {
|
|
|
|
if (!aFontInfoData || !aFontInfoData->mLoadCmaps) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2017-09-11 21:23:30 +03:00
|
|
|
return aFontInfoData->GetCMAP(mName, aUVSOffset);
|
2014-09-16 13:58:12 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
hb_blob_t* gfxFontEntry::GetFontTable(uint32_t aTag) {
|
|
|
|
hb_blob_t* blob;
|
|
|
|
if (GetExistingFontTable(aTag, &blob)) {
|
|
|
|
return blob;
|
|
|
|
}
|
|
|
|
|
2016-02-02 18:36:30 +03:00
|
|
|
nsTArray<uint8_t> buffer;
|
2014-09-16 13:58:12 +04:00
|
|
|
bool haveTable = NS_SUCCEEDED(CopyFontTable(aTag, buffer));
|
|
|
|
|
|
|
|
return ShareFontTableAndGetBlob(aTag, haveTable ? &buffer : nullptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
// callback for HarfBuzz to get a font table (in hb_blob_t form)
|
|
|
|
// from the font entry (passed as aUserData)
|
2019-02-26 01:07:19 +03:00
|
|
|
/*static*/
|
|
|
|
hb_blob_t* gfxFontEntry::HBGetTable(hb_face_t* face, uint32_t aTag,
|
|
|
|
void* aUserData) {
|
2014-09-16 13:58:12 +04:00
|
|
|
gfxFontEntry* fontEntry = static_cast<gfxFontEntry*>(aUserData);
|
|
|
|
|
|
|
|
// bug 589682 - ignore the GDEF table in buggy fonts (applies to
|
|
|
|
// Italic and BoldItalic faces of Times New Roman)
|
|
|
|
if (aTag == TRUETYPE_TAG('G', 'D', 'E', 'F') && fontEntry->IgnoreGDEF()) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
// bug 721719 - ignore the GSUB table in buggy fonts (applies to Roboto,
|
|
|
|
// at least on some Android ICS devices; set in gfxFT2FontList.cpp)
|
|
|
|
if (aTag == TRUETYPE_TAG('G', 'S', 'U', 'B') && fontEntry->IgnoreGSUB()) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
return fontEntry->GetFontTable(aTag);
|
|
|
|
}
|
|
|
|
|
2019-02-26 01:07:19 +03:00
|
|
|
/*static*/
|
|
|
|
void gfxFontEntry::HBFaceDeletedCallback(void* aUserData) {
|
2014-09-16 13:58:12 +04:00
|
|
|
gfxFontEntry* fe = static_cast<gfxFontEntry*>(aUserData);
|
|
|
|
fe->ForgetHBFace();
|
|
|
|
}
|
|
|
|
|
|
|
|
void gfxFontEntry::ForgetHBFace() { mHBFace = nullptr; }
|
|
|
|
|
|
|
|
hb_face_t* gfxFontEntry::GetHBFace() {
|
|
|
|
if (!mHBFace) {
|
|
|
|
mHBFace =
|
|
|
|
hb_face_create_for_tables(HBGetTable, this, HBFaceDeletedCallback);
|
|
|
|
return mHBFace;
|
|
|
|
}
|
|
|
|
return hb_face_reference(mHBFace);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*static*/ const void* gfxFontEntry::GrGetTable(const void* aAppFaceHandle,
|
|
|
|
unsigned int aName,
|
|
|
|
size_t* aLen) {
|
|
|
|
gfxFontEntry* fontEntry =
|
|
|
|
static_cast<gfxFontEntry*>(const_cast<void*>(aAppFaceHandle));
|
|
|
|
hb_blob_t* blob = fontEntry->GetFontTable(aName);
|
|
|
|
if (blob) {
|
|
|
|
unsigned int blobLength;
|
|
|
|
const void* tableData = hb_blob_get_data(blob, &blobLength);
|
|
|
|
fontEntry->mGrTableMap->Put(tableData, blob);
|
|
|
|
*aLen = blobLength;
|
|
|
|
return tableData;
|
|
|
|
}
|
|
|
|
*aLen = 0;
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2019-02-26 01:07:19 +03:00
|
|
|
/*static*/
|
|
|
|
void gfxFontEntry::GrReleaseTable(const void* aAppFaceHandle,
|
|
|
|
const void* aTableBuffer) {
|
2014-09-16 13:58:12 +04:00
|
|
|
gfxFontEntry* fontEntry =
|
|
|
|
static_cast<gfxFontEntry*>(const_cast<void*>(aAppFaceHandle));
|
|
|
|
void* value;
|
|
|
|
if (fontEntry->mGrTableMap->Remove(aTableBuffer, &value)) {
|
|
|
|
hb_blob_destroy(static_cast<hb_blob_t*>(value));
|
2015-08-03 11:04:59 +03:00
|
|
|
}
|
|
|
|
}
|
2014-09-16 13:58:12 +04:00
|
|
|
|
2016-04-21 20:58:59 +03:00
|
|
|
gr_face* gfxFontEntry::GetGrFace() {
|
2014-09-16 13:58:12 +04:00
|
|
|
if (!mGrFaceInitialized) {
|
2016-04-15 22:45:37 +03:00
|
|
|
gr_face_ops faceOps = {sizeof(gr_face_ops), GrGetTable, GrReleaseTable};
|
2016-04-21 20:58:59 +03:00
|
|
|
mGrTableMap = new nsDataHashtable<nsPtrHashKey<const void>, void*>;
|
2014-09-16 13:58:12 +04:00
|
|
|
mGrFace = gr_make_face_with_ops(this, &faceOps, gr_face_default);
|
|
|
|
mGrFaceInitialized = true;
|
|
|
|
}
|
|
|
|
++mGrFaceRefCnt;
|
|
|
|
return mGrFace;
|
|
|
|
}
|
|
|
|
|
|
|
|
void gfxFontEntry::ReleaseGrFace(gr_face* aFace) {
|
|
|
|
MOZ_ASSERT(aFace == mGrFace); // sanity-check
|
|
|
|
MOZ_ASSERT(mGrFaceRefCnt > 0);
|
|
|
|
if (--mGrFaceRefCnt == 0) {
|
|
|
|
gr_face_destroy(mGrFace);
|
|
|
|
mGrFace = nullptr;
|
|
|
|
mGrFaceInitialized = false;
|
|
|
|
delete mGrTableMap;
|
|
|
|
mGrTableMap = nullptr;
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
}
|
2014-09-16 13:58:12 +04:00
|
|
|
|
|
|
|
void gfxFontEntry::DisconnectSVG() {
|
|
|
|
if (mSVGInitialized && mSVGGlyphs) {
|
|
|
|
mSVGGlyphs = nullptr;
|
|
|
|
mSVGInitialized = false;
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
2014-09-16 13:58:12 +04:00
|
|
|
}
|
|
|
|
|
2016-04-21 20:58:59 +03:00
|
|
|
bool gfxFontEntry::HasFontTable(uint32_t aTableTag) {
|
|
|
|
AutoTable table(this, aTableTag);
|
2016-04-15 22:45:37 +03:00
|
|
|
return table && hb_blob_get_length(table) > 0;
|
2014-09-16 13:58:12 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void gfxFontEntry::CheckForGraphiteTables() {
|
|
|
|
mHasGraphiteTables = HasFontTable(TRUETYPE_TAG('S', 'i', 'l', 'f'));
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
2014-09-16 13:58:12 +04:00
|
|
|
|
|
|
|
bool gfxFontEntry::HasGraphiteSpaceContextuals() {
|
|
|
|
if (!mGraphiteSpaceContextualsInitialized) {
|
|
|
|
gr_face* face = GetGrFace();
|
2015-08-03 11:04:59 +03:00
|
|
|
if (face) {
|
2014-09-16 13:58:12 +04:00
|
|
|
const gr_faceinfo* faceInfo = gr_face_info(face, 0);
|
|
|
|
mHasGraphiteSpaceContextuals =
|
|
|
|
faceInfo->space_contextuals != gr_faceinfo::gr_space_none;
|
|
|
|
}
|
2015-11-20 09:09:59 +03:00
|
|
|
ReleaseGrFace(face); // always balance GetGrFace, even if face is null
|
2015-08-03 11:04:59 +03:00
|
|
|
mGraphiteSpaceContextualsInitialized = true;
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
2015-08-03 11:04:59 +03:00
|
|
|
return mHasGraphiteSpaceContextuals;
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
2014-09-16 13:58:12 +04:00
|
|
|
|
|
|
|
#define FEATURE_SCRIPT_MASK 0x000000ff // script index replaces low byte of tag
|
|
|
|
|
|
|
|
static_assert(int(Script::NUM_SCRIPT_CODES) <= FEATURE_SCRIPT_MASK,
|
|
|
|
"Too many script codes");
|
|
|
|
|
|
|
|
// high-order three bytes of tag with script in low-order byte
|
|
|
|
#define SCRIPT_FEATURE(s, tag) \
|
|
|
|
(((~FEATURE_SCRIPT_MASK) & (tag)) | \
|
|
|
|
((FEATURE_SCRIPT_MASK) & static_cast<uint32_t>(s)))
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2014-09-16 13:58:12 +04:00
|
|
|
bool gfxFontEntry::SupportsOpenTypeFeature(Script aScript,
|
|
|
|
uint32_t aFeatureTag) {
|
|
|
|
if (!mSupportedFeatures) {
|
|
|
|
mSupportedFeatures = MakeUnique<nsDataHashtable<nsUint32HashKey, bool>>();
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
|
2014-09-16 13:58:12 +04:00
|
|
|
// note: high-order three bytes *must* be unique for each feature
|
|
|
|
// listed below (see SCRIPT_FEATURE macro def'n)
|
|
|
|
NS_ASSERTION(aFeatureTag == HB_TAG('s', 'm', 'c', 'p') ||
|
|
|
|
aFeatureTag == HB_TAG('c', '2', 's', 'c') ||
|
|
|
|
aFeatureTag == HB_TAG('p', 'c', 'a', 'p') ||
|
|
|
|
aFeatureTag == HB_TAG('c', '2', 'p', 'c') ||
|
|
|
|
aFeatureTag == HB_TAG('s', 'u', 'p', 's') ||
|
2015-05-22 10:40:04 +03:00
|
|
|
aFeatureTag == HB_TAG('s', 'u', 'b', 's') ||
|
|
|
|
aFeatureTag == HB_TAG('v', 'e', 'r', 't'),
|
2014-09-16 13:58:12 +04:00
|
|
|
"use of unknown feature tag");
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2014-09-16 13:58:12 +04:00
|
|
|
// note: graphite feature support uses the last script index
|
2016-04-21 20:58:59 +03:00
|
|
|
NS_ASSERTION(int(aScript) < FEATURE_SCRIPT_MASK - 1,
|
2014-09-16 13:58:12 +04:00
|
|
|
"need to bump the size of the feature shift");
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2014-09-16 13:58:12 +04:00
|
|
|
uint32_t scriptFeature = SCRIPT_FEATURE(aScript, aFeatureTag);
|
|
|
|
bool result;
|
|
|
|
if (mSupportedFeatures->Get(scriptFeature, &result)) {
|
|
|
|
return result;
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
2014-09-16 13:58:12 +04:00
|
|
|
|
|
|
|
result = false;
|
|
|
|
|
|
|
|
hb_face_t* face = GetHBFace();
|
|
|
|
|
|
|
|
if (hb_ot_layout_has_substitution(face)) {
|
|
|
|
hb_script_t hbScript =
|
|
|
|
gfxHarfBuzzShaper::GetHBScriptUsedForShaping(aScript);
|
|
|
|
|
|
|
|
// Get the OpenType tag(s) that match this script code
|
2018-12-08 16:44:55 +03:00
|
|
|
unsigned int scriptCount = 4;
|
|
|
|
hb_tag_t scriptTags[4];
|
|
|
|
hb_ot_tags_from_script_and_language(hbScript, HB_LANGUAGE_INVALID,
|
|
|
|
&scriptCount, scriptTags, nullptr,
|
|
|
|
nullptr);
|
|
|
|
|
|
|
|
// Append DEFAULT to the returned tags, if room
|
|
|
|
if (scriptCount < 4) {
|
|
|
|
scriptTags[scriptCount++] = HB_OT_TAG_DEFAULT_SCRIPT;
|
2014-09-16 13:58:12 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Now check for 'smcp' under the first of those scripts that is present
|
|
|
|
const hb_tag_t kGSUB = HB_TAG('G', 'S', 'U', 'B');
|
2018-12-08 16:44:55 +03:00
|
|
|
for (unsigned int i = 0; i < scriptCount; i++) {
|
2014-09-16 13:58:12 +04:00
|
|
|
unsigned int scriptIndex;
|
2018-12-08 16:44:55 +03:00
|
|
|
if (hb_ot_layout_table_find_script(face, kGSUB, scriptTags[i],
|
2014-09-16 13:58:12 +04:00
|
|
|
&scriptIndex)) {
|
|
|
|
if (hb_ot_layout_language_find_feature(
|
|
|
|
face, kGSUB, scriptIndex, HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX,
|
|
|
|
aFeatureTag, nullptr)) {
|
|
|
|
result = true;
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
2014-09-16 13:58:12 +04:00
|
|
|
break;
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
2014-09-16 13:58:12 +04:00
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
2014-09-16 13:58:12 +04:00
|
|
|
|
2015-11-20 09:09:59 +03:00
|
|
|
hb_face_destroy(face);
|
2014-09-16 13:58:12 +04:00
|
|
|
|
|
|
|
mSupportedFeatures->Put(scriptFeature, result);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2018-01-30 12:57:39 +03:00
|
|
|
const hb_set_t* gfxFontEntry::InputsForOpenTypeFeature(Script aScript,
|
|
|
|
uint32_t aFeatureTag) {
|
|
|
|
if (!mFeatureInputs) {
|
|
|
|
mFeatureInputs = MakeUnique<nsDataHashtable<nsUint32HashKey, hb_set_t*>>();
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_ASSERTION(aFeatureTag == HB_TAG('s', 'u', 'p', 's') ||
|
|
|
|
aFeatureTag == HB_TAG('s', 'u', 'b', 's') ||
|
|
|
|
aFeatureTag == HB_TAG('v', 'e', 'r', 't'),
|
|
|
|
"use of unknown feature tag");
|
|
|
|
|
2014-09-16 13:58:12 +04:00
|
|
|
uint32_t scriptFeature = SCRIPT_FEATURE(aScript, aFeatureTag);
|
|
|
|
hb_set_t* inputGlyphs;
|
|
|
|
if (mFeatureInputs->Get(scriptFeature, &inputGlyphs)) {
|
|
|
|
return inputGlyphs;
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
|
2014-09-16 13:58:12 +04:00
|
|
|
inputGlyphs = hb_set_create();
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2018-01-30 12:57:39 +03:00
|
|
|
hb_face_t* face = GetHBFace();
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2014-09-16 13:58:12 +04:00
|
|
|
if (hb_ot_layout_has_substitution(face)) {
|
|
|
|
hb_script_t hbScript =
|
|
|
|
gfxHarfBuzzShaper::GetHBScriptUsedForShaping(aScript);
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2014-09-16 13:58:12 +04:00
|
|
|
// Get the OpenType tag(s) that match this script code
|
2018-12-08 16:44:55 +03:00
|
|
|
unsigned int scriptCount = 4;
|
|
|
|
hb_tag_t scriptTags[5]; // space for null terminator
|
|
|
|
hb_ot_tags_from_script_and_language(hbScript, HB_LANGUAGE_INVALID,
|
|
|
|
&scriptCount, scriptTags, nullptr,
|
|
|
|
nullptr);
|
|
|
|
|
|
|
|
// Append DEFAULT to the returned tags, if room
|
|
|
|
if (scriptCount < 4) {
|
|
|
|
scriptTags[scriptCount++] = HB_OT_TAG_DEFAULT_SCRIPT;
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
2018-12-08 16:44:55 +03:00
|
|
|
scriptTags[scriptCount++] = 0;
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2014-09-16 13:58:12 +04:00
|
|
|
const hb_tag_t kGSUB = HB_TAG('G', 'S', 'U', 'B');
|
|
|
|
hb_tag_t features[2] = {aFeatureTag, HB_TAG_NONE};
|
|
|
|
hb_set_t* featurelookups = hb_set_create();
|
|
|
|
hb_ot_layout_collect_lookups(face, kGSUB, scriptTags, nullptr, features,
|
|
|
|
featurelookups);
|
|
|
|
hb_codepoint_t index = -1;
|
|
|
|
while (hb_set_next(featurelookups, &index)) {
|
|
|
|
hb_ot_layout_lookup_collect_glyphs(face, kGSUB, index, nullptr,
|
|
|
|
inputGlyphs, nullptr, nullptr);
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
2014-10-15 03:38:03 +04:00
|
|
|
hb_set_destroy(featurelookups);
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
|
2014-09-16 13:58:12 +04:00
|
|
|
hb_face_destroy(face);
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2014-09-16 13:58:12 +04:00
|
|
|
mFeatureInputs->Put(scriptFeature, inputGlyphs);
|
|
|
|
return inputGlyphs;
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
|
2014-09-16 13:58:12 +04:00
|
|
|
bool gfxFontEntry::SupportsGraphiteFeature(uint32_t aFeatureTag) {
|
|
|
|
if (!mSupportedFeatures) {
|
2016-04-15 22:45:37 +03:00
|
|
|
mSupportedFeatures = MakeUnique<nsDataHashtable<nsUint32HashKey, bool>>();
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
|
2014-09-16 13:58:12 +04:00
|
|
|
// note: high-order three bytes *must* be unique for each feature
|
|
|
|
// listed below (see SCRIPT_FEATURE macro def'n)
|
|
|
|
NS_ASSERTION(aFeatureTag == HB_TAG('s', 'm', 'c', 'p') ||
|
|
|
|
aFeatureTag == HB_TAG('c', '2', 's', 'c') ||
|
|
|
|
aFeatureTag == HB_TAG('p', 'c', 'a', 'p') ||
|
|
|
|
aFeatureTag == HB_TAG('c', '2', 'p', 'c') ||
|
|
|
|
aFeatureTag == HB_TAG('s', 'u', 'p', 's') ||
|
|
|
|
aFeatureTag == HB_TAG('s', 'u', 'b', 's'),
|
|
|
|
"use of unknown feature tag");
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2014-09-16 13:58:12 +04:00
|
|
|
// graphite feature check uses the last script slot
|
|
|
|
uint32_t scriptFeature = SCRIPT_FEATURE(FEATURE_SCRIPT_MASK, aFeatureTag);
|
|
|
|
bool result;
|
|
|
|
if (mSupportedFeatures->Get(scriptFeature, &result)) {
|
|
|
|
return result;
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
|
2015-08-03 11:04:59 +03:00
|
|
|
gr_face* face = GetGrFace();
|
2015-11-20 09:09:59 +03:00
|
|
|
result = face ? gr_face_find_fref(face, aFeatureTag) != nullptr : false;
|
|
|
|
ReleaseGrFace(face);
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2014-09-16 13:58:12 +04:00
|
|
|
mSupportedFeatures->Put(scriptFeature, result);
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2014-09-16 13:58:12 +04:00
|
|
|
return result;
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
|
2018-01-30 12:57:39 +03:00
|
|
|
void gfxFontEntry::GetFeatureInfo(nsTArray<gfxFontFeatureInfo>& aFeatureInfo) {
|
|
|
|
// TODO: implement alternative code path for graphite fonts
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2018-01-30 12:57:39 +03:00
|
|
|
hb_face_t* face = GetHBFace();
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2018-01-30 12:57:39 +03:00
|
|
|
// Get the list of features for a specific <script,langSys> pair and
|
|
|
|
// append them to aFeatureInfo.
|
|
|
|
auto collectForLang = [=, &aFeatureInfo](
|
|
|
|
hb_tag_t aTableTag, unsigned int aScript,
|
|
|
|
hb_tag_t aScriptTag, unsigned int aLang,
|
|
|
|
hb_tag_t aLangTag) {
|
|
|
|
unsigned int featCount = hb_ot_layout_language_get_feature_tags(
|
|
|
|
face, aTableTag, aScript, aLang, 0, nullptr, nullptr);
|
|
|
|
AutoTArray<hb_tag_t, 32> featTags;
|
|
|
|
featTags.SetLength(featCount);
|
|
|
|
hb_ot_layout_language_get_feature_tags(face, aTableTag, aScript, aLang, 0,
|
|
|
|
&featCount, featTags.Elements());
|
|
|
|
MOZ_ASSERT(featCount <= featTags.Length());
|
|
|
|
// Just in case HB didn't fill featTags (i.e. in case it returned fewer
|
|
|
|
// tags than it promised), we truncate at the length it says it filled:
|
|
|
|
featTags.SetLength(featCount);
|
|
|
|
for (hb_tag_t t : featTags) {
|
|
|
|
aFeatureInfo.AppendElement(gfxFontFeatureInfo{t, aScriptTag, aLangTag});
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2018-01-30 12:57:39 +03:00
|
|
|
// Iterate over the language systems supported by a given script,
|
|
|
|
// and call collectForLang for each of them.
|
|
|
|
auto collectForScript = [=](hb_tag_t aTableTag, unsigned int aScript,
|
|
|
|
hb_tag_t aScriptTag) {
|
|
|
|
collectForLang(aTableTag, aScript, aScriptTag,
|
2014-09-16 13:58:12 +04:00
|
|
|
HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX,
|
2018-01-30 12:57:39 +03:00
|
|
|
HB_TAG('d', 'f', 'l', 't'));
|
|
|
|
unsigned int langCount = hb_ot_layout_script_get_language_tags(
|
|
|
|
face, aTableTag, aScript, 0, nullptr, nullptr);
|
|
|
|
AutoTArray<hb_tag_t, 32> langTags;
|
|
|
|
langTags.SetLength(langCount);
|
|
|
|
hb_ot_layout_script_get_language_tags(face, aTableTag, aScript, 0,
|
|
|
|
&langCount, langTags.Elements());
|
|
|
|
MOZ_ASSERT(langCount <= langTags.Length());
|
|
|
|
langTags.SetLength(langCount);
|
|
|
|
for (unsigned int lang = 0; lang < langCount; ++lang) {
|
|
|
|
collectForLang(aTableTag, aScript, aScriptTag, lang, langTags[lang]);
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2018-01-30 12:57:39 +03:00
|
|
|
// Iterate over the scripts supported by a table (GSUB or GPOS), and call
|
|
|
|
// collectForScript for each of them.
|
|
|
|
auto collectForTable = [=](hb_tag_t aTableTag) {
|
|
|
|
unsigned int scriptCount = hb_ot_layout_table_get_script_tags(
|
|
|
|
face, aTableTag, 0, nullptr, nullptr);
|
|
|
|
AutoTArray<hb_tag_t, 32> scriptTags;
|
|
|
|
scriptTags.SetLength(scriptCount);
|
|
|
|
hb_ot_layout_table_get_script_tags(face, aTableTag, 0, &scriptCount,
|
|
|
|
scriptTags.Elements());
|
|
|
|
MOZ_ASSERT(scriptCount <= scriptTags.Length());
|
|
|
|
scriptTags.SetLength(scriptCount);
|
|
|
|
for (unsigned int script = 0; script < scriptCount; ++script) {
|
|
|
|
collectForScript(aTableTag, script, scriptTags[script]);
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2018-01-30 12:57:39 +03:00
|
|
|
// Collect all OpenType Layout features, both substitution and positioning,
|
|
|
|
// supported by the font resource.
|
|
|
|
collectForTable(HB_TAG('G', 'S', 'U', 'B'));
|
|
|
|
collectForTable(HB_TAG('G', 'P', 'O', 'S'));
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2014-09-16 13:58:12 +04:00
|
|
|
hb_face_destroy(face);
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
|
2014-09-16 13:58:12 +04:00
|
|
|
bool gfxFontEntry::GetColorLayersInfo(
|
2016-07-06 12:10:17 +03:00
|
|
|
uint32_t aGlyphId, const mozilla::gfx::Color& aDefaultColor,
|
2014-09-16 13:58:12 +04:00
|
|
|
nsTArray<uint16_t>& aLayerGlyphs,
|
|
|
|
nsTArray<mozilla::gfx::Color>& aLayerColors) {
|
|
|
|
return gfxFontUtils::GetColorGlyphLayers(
|
2016-07-06 12:10:17 +03:00
|
|
|
mCOLR, mCPAL, aGlyphId, aDefaultColor, aLayerGlyphs, aLayerColors);
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
|
2018-04-25 09:18:23 +03:00
|
|
|
void gfxFontEntry::SetupVariationRanges() {
|
2018-04-25 16:03:44 +03:00
|
|
|
if (!gfxPlatform::GetPlatform()->HasVariationFontSupport() ||
|
2018-05-29 22:24:28 +03:00
|
|
|
!StaticPrefs::layout_css_font_variations_enabled() || !HasVariations() ||
|
2018-04-25 16:03:44 +03:00
|
|
|
IsUserFont()) {
|
2018-11-30 13:46:48 +03:00
|
|
|
return;
|
|
|
|
}
|
2018-04-25 09:18:23 +03:00
|
|
|
AutoTArray<gfxFontVariationAxis, 4> axes;
|
|
|
|
GetVariationAxes(axes);
|
|
|
|
for (const auto& axis : axes) {
|
|
|
|
switch (axis.mTag) {
|
|
|
|
case HB_TAG('w', 'g', 'h', 't'):
|
|
|
|
// If the axis range looks like it doesn't fit the CSS font-weight
|
2018-05-04 19:36:01 +03:00
|
|
|
// scale, we don't hook up the high-level property, and we mark
|
|
|
|
// the face (in mRangeFlags) as having non-standard weight. This
|
|
|
|
// means we won't map CSS font-weight to the axis. Setting 'wght'
|
2018-04-25 09:18:23 +03:00
|
|
|
// with font-variation-settings will still work.
|
|
|
|
// Strictly speaking, the min value should be checked against 1.0,
|
|
|
|
// not 0.0, but we'll allow font makers that amount of leeway, as
|
|
|
|
// in practice a number of fonts seem to use 0..1000.
|
2018-04-25 09:18:23 +03:00
|
|
|
if (axis.mMinValue >= 0.0f && axis.mMaxValue <= 1000.0f &&
|
2018-04-25 09:18:23 +03:00
|
|
|
// If axis.mMaxValue is less than the default weight we already
|
|
|
|
// set up, assume the axis has a non-standard range (like Skia)
|
|
|
|
// and don't try to map it.
|
|
|
|
Weight().Min() <= FontWeight(axis.mMaxValue)) {
|
2018-04-25 09:18:23 +03:00
|
|
|
if (FontWeight(axis.mDefaultValue) != Weight().Min()) {
|
|
|
|
mStandardFace = false;
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
2018-04-25 09:18:23 +03:00
|
|
|
mWeightRange = WeightRange(FontWeight(std::max(1.0f, axis.mMinValue)),
|
|
|
|
FontWeight(axis.mMaxValue));
|
2018-11-30 13:46:48 +03:00
|
|
|
} else {
|
2018-05-04 19:36:01 +03:00
|
|
|
mRangeFlags |= RangeFlags::eNonCSSWeight;
|
2018-01-30 12:57:39 +03:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case HB_TAG('w', 'd', 't', 'h'):
|
2014-09-16 13:58:12 +04:00
|
|
|
if (axis.mMinValue >= 0.0f && axis.mMaxValue <= 1000.0f &&
|
2018-04-25 16:03:44 +03:00
|
|
|
Stretch().Min() <= FontStretch(axis.mMaxValue)) {
|
2018-04-25 09:18:23 +03:00
|
|
|
if (FontStretch(axis.mDefaultValue) != Stretch().Min()) {
|
|
|
|
mStandardFace = false;
|
2018-05-04 19:36:01 +03:00
|
|
|
}
|
2018-04-25 09:18:23 +03:00
|
|
|
mStretchRange = StretchRange(FontStretch(axis.mMinValue),
|
|
|
|
FontStretch(axis.mMaxValue));
|
2018-05-09 15:49:24 +03:00
|
|
|
} else {
|
|
|
|
mRangeFlags |= RangeFlags::eNonCSSStretch;
|
2018-04-25 09:18:23 +03:00
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
break;
|
2018-04-25 09:18:23 +03:00
|
|
|
|
2018-05-09 15:49:24 +03:00
|
|
|
case HB_TAG('s', 'l', 'n', 't'):
|
|
|
|
if (axis.mMinValue >= -90.0f && axis.mMaxValue <= 90.0f) {
|
|
|
|
if (FontSlantStyle::Oblique(axis.mDefaultValue) !=
|
2018-04-25 09:18:23 +03:00
|
|
|
SlantStyle().Min()) {
|
2018-05-09 15:49:24 +03:00
|
|
|
mStandardFace = false;
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
2018-05-09 15:49:24 +03:00
|
|
|
mStyleRange =
|
|
|
|
SlantStyleRange(FontSlantStyle::Oblique(axis.mMinValue),
|
|
|
|
FontSlantStyle::Oblique(axis.mMaxValue));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2018-04-26 17:32:36 +03:00
|
|
|
case HB_TAG('i', 't', 'a', 'l'):
|
|
|
|
if (axis.mMinValue <= 0.0f && axis.mMaxValue >= 1.0f) {
|
2018-05-04 19:36:01 +03:00
|
|
|
if (axis.mDefaultValue != 0.0f) {
|
2018-05-09 15:49:24 +03:00
|
|
|
mStandardFace = false;
|
|
|
|
}
|
2018-04-26 17:32:36 +03:00
|
|
|
mStyleRange = SlantStyleRange(FontSlantStyle::Normal(),
|
|
|
|
FontSlantStyle::Italic());
|
|
|
|
}
|
2018-04-25 09:18:23 +03:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
continue;
|
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
2018-04-25 09:18:23 +03:00
|
|
|
}
|
|
|
|
|
2014-09-16 13:58:12 +04:00
|
|
|
void gfxFontEntry::CheckForVariationAxes() {
|
|
|
|
if (HasVariations()) {
|
|
|
|
AutoTArray<gfxFontVariationAxis, 4> axes;
|
|
|
|
GetVariationAxes(axes);
|
2018-04-25 09:18:23 +03:00
|
|
|
for (const auto& axis : axes) {
|
2014-09-16 13:58:12 +04:00
|
|
|
if (axis.mTag == HB_TAG('w', 'g', 'h', 't') && axis.mMaxValue >= 600.0f) {
|
|
|
|
mRangeFlags |= RangeFlags::eBoldVariableWeight;
|
2018-05-09 15:49:24 +03:00
|
|
|
} else if (axis.mTag == HB_TAG('i', 't', 'a', 'l') &&
|
2018-04-25 09:18:23 +03:00
|
|
|
axis.mMaxValue >= 1.0f) {
|
2014-09-16 13:58:12 +04:00
|
|
|
mRangeFlags |= RangeFlags::eItalicVariation;
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
2014-09-16 13:58:12 +04:00
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
2014-09-16 13:58:12 +04:00
|
|
|
mCheckedForVariationAxes = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool gfxFontEntry::HasBoldVariableWeight() {
|
|
|
|
MOZ_ASSERT(!mIsUserFontContainer,
|
|
|
|
"should not be called for user-font containers!");
|
|
|
|
|
|
|
|
if (!gfxPlatform::GetPlatform()->HasVariationFontSupport()) {
|
|
|
|
return false;
|
|
|
|
}
|
2016-05-03 14:14:35 +03:00
|
|
|
|
|
|
|
if (!mCheckedForVariationAxes) {
|
|
|
|
CheckForVariationAxes();
|
|
|
|
}
|
|
|
|
|
|
|
|
return bool(mRangeFlags & RangeFlags::eBoldVariableWeight);
|
2014-09-16 13:58:12 +04:00
|
|
|
}
|
|
|
|
|
2018-05-09 15:49:24 +03:00
|
|
|
bool gfxFontEntry::HasItalicVariation() {
|
2018-05-04 12:19:55 +03:00
|
|
|
MOZ_ASSERT(!mIsUserFontContainer,
|
|
|
|
"should not be called for user-font containers!");
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2018-05-04 12:19:55 +03:00
|
|
|
if (!gfxPlatform::GetPlatform()->HasVariationFontSupport()) {
|
|
|
|
return false;
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
|
2018-05-09 15:49:24 +03:00
|
|
|
if (!mCheckedForVariationAxes) {
|
|
|
|
CheckForVariationAxes();
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
|
2018-05-09 15:49:24 +03:00
|
|
|
return bool(mRangeFlags & RangeFlags::eItalicVariation);
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
|
2014-09-16 13:58:12 +04:00
|
|
|
void gfxFontEntry::GetVariationsForStyle(nsTArray<gfxFontVariation>& aResult,
|
2018-04-25 09:18:23 +03:00
|
|
|
const gfxFontStyle& aStyle) {
|
2018-04-25 16:03:44 +03:00
|
|
|
if (!gfxPlatform::GetPlatform()->HasVariationFontSupport() ||
|
2018-05-04 19:35:38 +03:00
|
|
|
!StaticPrefs::layout_css_font_variations_enabled()) {
|
2018-11-30 13:46:48 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-05-09 15:49:24 +03:00
|
|
|
if (!HasVariations()) {
|
2018-11-30 13:46:48 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-04-25 09:18:23 +03:00
|
|
|
// Resolve high-level CSS properties from the requested style
|
|
|
|
// (font-{style,weight,stretch}) to the appropriate variations.
|
2018-04-26 17:32:36 +03:00
|
|
|
// The value used is clamped to the range available in the font face,
|
|
|
|
// unless the face is a user font where no explicit descriptor was
|
|
|
|
// given, indicated by the corresponding 'auto' range-flag.
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2018-05-04 19:36:01 +03:00
|
|
|
// We don't do these mappings if the font entry has weight and/or stretch
|
|
|
|
// ranges that do not appear to use the CSS property scale. Some older
|
|
|
|
// fonts created for QuickDrawGX/AAT may use "normalized" values where the
|
|
|
|
// standard variation is 1.0 rather than 400.0 (weight) or 100.0 (stretch).
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2018-05-04 19:36:01 +03:00
|
|
|
if (!(mRangeFlags & RangeFlags::eNonCSSWeight)) {
|
|
|
|
float weight = (IsUserFont() && (mRangeFlags & RangeFlags::eAutoWeight))
|
|
|
|
? aStyle.weight.ToFloat()
|
|
|
|
: Weight().Clamp(aStyle.weight).ToFloat();
|
|
|
|
aResult.AppendElement(gfxFontVariation{HB_TAG('w', 'g', 'h', 't'), weight});
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
|
2018-05-04 19:36:01 +03:00
|
|
|
if (!(mRangeFlags & RangeFlags::eNonCSSStretch)) {
|
|
|
|
float stretch = (IsUserFont() && (mRangeFlags & RangeFlags::eAutoStretch))
|
|
|
|
? aStyle.stretch.Percentage()
|
|
|
|
: Stretch().Clamp(aStyle.stretch).Percentage();
|
|
|
|
aResult.AppendElement(
|
|
|
|
gfxFontVariation{HB_TAG('w', 'd', 't', 'h'), stretch});
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
|
2018-05-09 15:49:24 +03:00
|
|
|
if (aStyle.style.IsItalic() && SupportsItalic()) {
|
|
|
|
// The 'ital' axis is normally a binary toggle; intermediate values
|
|
|
|
// can only be set using font-variation-settings.
|
|
|
|
aResult.AppendElement(gfxFontVariation{HB_TAG('i', 't', 'a', 'l'), 1.0f});
|
|
|
|
} else if (SlantStyle().Min().IsOblique()) {
|
2018-04-26 17:32:36 +03:00
|
|
|
// Figure out what slant angle we should try to match from the
|
|
|
|
// requested style.
|
|
|
|
float angle = aStyle.style.IsNormal()
|
2018-11-30 13:46:48 +03:00
|
|
|
? 0.0f
|
2018-04-26 17:32:36 +03:00
|
|
|
: aStyle.style.IsItalic()
|
|
|
|
? FontSlantStyle::Oblique().ObliqueAngle()
|
|
|
|
: aStyle.style.ObliqueAngle();
|
|
|
|
// Clamp to the available range, unless the face is a user font
|
|
|
|
// with no explicit descriptor.
|
2018-05-04 19:36:01 +03:00
|
|
|
if (!(IsUserFont() && (mRangeFlags & RangeFlags::eAutoSlantStyle))) {
|
2018-06-03 23:33:53 +03:00
|
|
|
angle = SlantStyle().Clamp(FontSlantStyle::Oblique(angle)).ObliqueAngle();
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
2018-04-25 09:18:23 +03:00
|
|
|
aResult.AppendElement(gfxFontVariation{HB_TAG('s', 'l', 'n', 't'), angle});
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
|
2018-04-25 09:18:23 +03:00
|
|
|
auto replaceOrAppend = [&aResult](const gfxFontVariation& aSetting) {
|
|
|
|
struct TagEquals {
|
|
|
|
bool Equals(const gfxFontVariation& aIter, uint32_t aTag) const {
|
|
|
|
return aIter.mTag == aTag;
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
};
|
2018-04-25 09:18:23 +03:00
|
|
|
auto index = aResult.IndexOf(aSetting.mTag, 0, TagEquals());
|
|
|
|
if (index == aResult.NoIndex) {
|
|
|
|
aResult.AppendElement(aSetting);
|
2018-11-30 13:46:48 +03:00
|
|
|
} else {
|
2018-04-25 09:18:23 +03:00
|
|
|
aResult[index].mValue = aSetting.mValue;
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2018-04-25 09:18:23 +03:00
|
|
|
// The low-level font-variation-settings descriptor from @font-face,
|
|
|
|
// if present, takes precedence over automatic variation settings
|
|
|
|
// from high-level properties.
|
|
|
|
for (const auto& v : mVariationSettings) {
|
|
|
|
replaceOrAppend(v);
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
|
2018-04-25 09:18:23 +03:00
|
|
|
// And the low-level font-variation-settings property takes precedence
|
|
|
|
// over the descriptor.
|
|
|
|
for (const auto& v : aStyle.variationSettings) {
|
|
|
|
replaceOrAppend(v);
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-16 13:58:12 +04:00
|
|
|
size_t gfxFontEntry::FontTableHashEntry::SizeOfExcludingThis(
|
|
|
|
mozilla::MallocSizeOf aMallocSizeOf) const {
|
|
|
|
size_t n = 0;
|
|
|
|
if (mBlob) {
|
|
|
|
n += aMallocSizeOf(mBlob);
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
2014-09-16 13:58:12 +04:00
|
|
|
if (mSharedBlobData) {
|
2016-05-03 14:14:35 +03:00
|
|
|
n += mSharedBlobData->SizeOfIncludingThis(aMallocSizeOf);
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
2018-04-25 09:18:23 +03:00
|
|
|
return n;
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
|
2016-05-03 14:14:34 +03:00
|
|
|
void gfxFontEntry::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
|
2014-09-16 13:58:12 +04:00
|
|
|
FontListSizes* aSizes) const {
|
|
|
|
aSizes->mFontListSize += mName.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2014-09-16 13:58:12 +04:00
|
|
|
// cmaps are shared so only non-shared cmaps are included here
|
|
|
|
if (mCharacterMap && mCharacterMap->mBuildOnTheFly) {
|
|
|
|
aSizes->mCharMapsSize += mCharacterMap->SizeOfIncludingThis(aMallocSizeOf);
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
2014-09-16 13:58:12 +04:00
|
|
|
if (mFontTableCache) {
|
|
|
|
aSizes->mFontTableCacheSize +=
|
|
|
|
mFontTableCache->SizeOfIncludingThis(aMallocSizeOf);
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
|
2016-05-03 14:14:35 +03:00
|
|
|
// If the font has UVS data, we count that as part of the character map.
|
|
|
|
if (mUVSData) {
|
|
|
|
aSizes->mCharMapsSize += aMallocSizeOf(mUVSData.get());
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
|
2016-05-03 14:14:35 +03:00
|
|
|
// The following, if present, are essentially cached forms of font table
|
|
|
|
// data, so we'll accumulate them together with the basic table cache.
|
|
|
|
if (mUserFontData) {
|
2014-09-16 13:58:12 +04:00
|
|
|
aSizes->mFontTableCacheSize +=
|
2016-05-03 14:14:35 +03:00
|
|
|
mUserFontData->SizeOfIncludingThis(aMallocSizeOf);
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
2016-05-03 14:14:35 +03:00
|
|
|
if (mSVGGlyphs) {
|
2014-09-16 13:58:12 +04:00
|
|
|
aSizes->mFontTableCacheSize +=
|
2016-05-03 14:14:35 +03:00
|
|
|
mSVGGlyphs->SizeOfIncludingThis(aMallocSizeOf);
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
2016-05-03 14:14:35 +03:00
|
|
|
if (mSupportedFeatures) {
|
2014-09-16 13:58:12 +04:00
|
|
|
aSizes->mFontTableCacheSize +=
|
2016-05-03 14:14:35 +03:00
|
|
|
mSupportedFeatures->ShallowSizeOfIncludingThis(aMallocSizeOf);
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
2016-05-03 14:14:35 +03:00
|
|
|
if (mFeatureInputs) {
|
2014-09-16 13:58:12 +04:00
|
|
|
aSizes->mFontTableCacheSize +=
|
2016-05-03 14:14:35 +03:00
|
|
|
mFeatureInputs->ShallowSizeOfIncludingThis(aMallocSizeOf);
|
|
|
|
for (auto iter = mFeatureInputs->ConstIter(); !iter.Done(); iter.Next()) {
|
|
|
|
// There's no API to get the real size of an hb_set, so we'll use
|
|
|
|
// an approximation based on knowledge of the implementation.
|
|
|
|
aSizes->mFontTableCacheSize += 8192; // vector of 64K bits
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
}
|
2016-05-03 14:14:35 +03:00
|
|
|
// We don't include the size of mCOLR/mCPAL here, because (depending on the
|
|
|
|
// font backend implementation) they will either wrap blocks of data owned
|
|
|
|
// by the system (and potentially shared), or tables that are in our font
|
|
|
|
// table cache and therefore already counted.
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
|
2014-09-16 13:58:12 +04:00
|
|
|
void gfxFontEntry::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
|
|
|
|
FontListSizes* aSizes) const {
|
|
|
|
aSizes->mFontListSize += aMallocSizeOf(this);
|
|
|
|
AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
|
|
|
|
}
|
|
|
|
|
2016-05-03 14:14:34 +03:00
|
|
|
// This is used to report the size of an individual downloaded font in the
|
|
|
|
// user font cache. (Fonts that are part of the platform font list accumulate
|
|
|
|
// their sizes to the font list's reporter using the AddSizeOf... methods
|
|
|
|
// above.)
|
|
|
|
size_t gfxFontEntry::ComputedSizeOfExcludingThis(
|
|
|
|
MallocSizeOf aMallocSizeOf) const {
|
|
|
|
FontListSizes s = {0};
|
|
|
|
AddSizeOfExcludingThis(aMallocSizeOf, &s);
|
|
|
|
|
|
|
|
// When reporting memory used for the main platform font list,
|
|
|
|
// where we're typically summing the totals for a few hundred font faces,
|
|
|
|
// we report the fields of FontListSizes separately.
|
|
|
|
// But for downloaded user fonts, the actual resource data (added below)
|
|
|
|
// will dominate, and the minor overhead of these pieces isn't worth
|
|
|
|
// splitting out for an individual font.
|
|
|
|
size_t result = s.mFontListSize + s.mFontTableCacheSize + s.mCharMapsSize;
|
|
|
|
|
|
|
|
if (mIsDataUserFont) {
|
|
|
|
MOZ_ASSERT(mComputedSizeOfUserFont > 0, "user font with no data?");
|
|
|
|
result += mComputedSizeOfUserFont;
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2014-09-16 13:58:12 +04:00
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
|
|
// class gfxFontFamily
|
|
|
|
//
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2015-10-08 09:04:08 +03:00
|
|
|
// we consider faces with mStandardFace == true to be "less than" those with
|
|
|
|
// false, because during style matching, earlier entries are tried first
|
2014-09-16 13:58:12 +04:00
|
|
|
class FontEntryStandardFaceComparator {
|
|
|
|
public:
|
2015-10-18 08:24:48 +03:00
|
|
|
bool Equals(const RefPtr<gfxFontEntry>& a,
|
|
|
|
const RefPtr<gfxFontEntry>& b) const {
|
2014-09-16 13:58:12 +04:00
|
|
|
return a->mStandardFace == b->mStandardFace;
|
|
|
|
}
|
2015-10-18 08:24:48 +03:00
|
|
|
bool LessThan(const RefPtr<gfxFontEntry>& a,
|
|
|
|
const RefPtr<gfxFontEntry>& b) const {
|
2015-10-08 09:04:08 +03:00
|
|
|
return (a->mStandardFace == true && b->mStandardFace == false);
|
2014-09-16 13:58:12 +04:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
void gfxFontFamily::SortAvailableFonts() {
|
|
|
|
mAvailableFonts.Sort(FontEntryStandardFaceComparator());
|
|
|
|
}
|
|
|
|
|
|
|
|
bool gfxFontFamily::HasOtherFamilyNames() {
|
|
|
|
// need to read in other family names to determine this
|
|
|
|
if (!mOtherFamilyNamesInitialized) {
|
|
|
|
ReadOtherFamilyNames(
|
|
|
|
gfxPlatformFontList::PlatformFontList()); // sets mHasOtherFamilyNames
|
|
|
|
}
|
|
|
|
return mHasOtherFamilyNames;
|
|
|
|
}
|
|
|
|
|
|
|
|
gfxFontEntry* gfxFontFamily::FindFontForStyle(const gfxFontStyle& aFontStyle,
|
2017-08-07 19:27:33 +03:00
|
|
|
bool aIgnoreSizeTolerance) {
|
2016-02-02 18:36:30 +03:00
|
|
|
AutoTArray<gfxFontEntry*, 4> matched;
|
Bug 1449605 - part 1 - Rearrange thebes font code so that the decision whether to apply synthetic-bold is deferred until actually instantiating a font, not made during the font-matching process. r=jwatt
This rearranges how synthetic-bold use is determined in the font selection
& rendering code. Previously, we would decide during the font-selection
algorithm whether we need to apply synthetic-bold to the chosen face, and
then pass that decision through the fontgroup (storing it in the FamilyFace
entries of the mFonts array there) down to the actual rendering code that
instantiates fonts from the faces (font entries) we've selected.
That became a problem for variation fonts because in the case of a user
font, we may not have downloaded the resource yet, so we just have a "user
font container" entry, which carries the descriptors from the @font-face
rule and will fetch the actual resource when needed. But in the case of a
@font-face rule without a weight descriptor, we don't actually know at
font-selection time whether the face will support "true" bold (via a
variation axis) or not, so we can't reliably make the right decision about
applying synthetic bold.
So we now defer that decision until we actually instantiate a platform font
object to shape/measure/draw text. At that point, we have the requested
style and we also have the real font resource, so we can easily determine
whether fake-bold is required.
(This patch should not result in any visible behavior change; that will
come in a second patch now that the architecture supports it.)
2018-05-01 12:30:50 +03:00
|
|
|
FindAllFontsForStyle(aFontStyle, matched, aIgnoreSizeTolerance);
|
2014-11-06 07:42:50 +03:00
|
|
|
if (!matched.IsEmpty()) {
|
|
|
|
return matched[0];
|
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2018-04-25 09:18:23 +03:00
|
|
|
static inline double WeightStyleStretchDistance(
|
2015-10-19 05:16:43 +03:00
|
|
|
gfxFontEntry* aFontEntry, const gfxFontStyle& aTargetStyle) {
|
2019-04-01 17:33:04 +03:00
|
|
|
double stretchDist =
|
|
|
|
StretchDistance(aFontEntry->Stretch(), aTargetStyle.stretch);
|
|
|
|
double styleDist =
|
|
|
|
StyleDistance(aFontEntry->SlantStyle(), aTargetStyle.style);
|
|
|
|
double weightDist = WeightDistance(aFontEntry->Weight(), aTargetStyle.weight);
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2018-04-25 09:18:23 +03:00
|
|
|
// Sanity-check that the distances are within the expected range
|
|
|
|
// (update if implementation of the distance functions is changed).
|
|
|
|
MOZ_ASSERT(stretchDist >= 0.0 && stretchDist <= 2000.0);
|
|
|
|
MOZ_ASSERT(styleDist >= 0.0 && styleDist <= 500.0);
|
|
|
|
MOZ_ASSERT(weightDist >= 0.0 && weightDist <= 1600.0);
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2015-10-19 05:16:43 +03:00
|
|
|
// weight/style/stretch priority: stretch >> style >> weight
|
2018-04-25 09:18:23 +03:00
|
|
|
// so we multiply the stretch and style values to make them dominate
|
2014-09-16 13:58:12 +04:00
|
|
|
// the result
|
2018-04-25 09:18:23 +03:00
|
|
|
return stretchDist * 1.0e8 + styleDist * 1.0e4 + weightDist;
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
|
2018-04-25 09:18:23 +03:00
|
|
|
void gfxFontFamily::FindAllFontsForStyle(
|
2014-11-06 07:42:50 +03:00
|
|
|
const gfxFontStyle& aFontStyle, nsTArray<gfxFontEntry*>& aFontEntryList,
|
2018-04-25 09:18:23 +03:00
|
|
|
bool aIgnoreSizeTolerance) {
|
2014-11-06 07:42:50 +03:00
|
|
|
if (!mHasStyles) {
|
2018-04-25 09:18:23 +03:00
|
|
|
FindStyleVariations(); // collect faces for the family, if not already done
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
|
2018-04-25 09:18:23 +03:00
|
|
|
NS_ASSERTION(mAvailableFonts.Length() > 0, "font family with no faces!");
|
|
|
|
NS_ASSERTION(aFontEntryList.IsEmpty(), "non-empty fontlist passed in");
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2018-04-25 09:18:23 +03:00
|
|
|
gfxFontEntry* fe = nullptr;
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2018-04-25 09:18:23 +03:00
|
|
|
// If the family has only one face, we simply return it; no further
|
|
|
|
// checking needed
|
2014-11-06 07:42:50 +03:00
|
|
|
uint32_t count = mAvailableFonts.Length();
|
|
|
|
if (count == 1) {
|
2018-04-25 09:18:23 +03:00
|
|
|
fe = mAvailableFonts[0];
|
2014-11-06 07:42:50 +03:00
|
|
|
aFontEntryList.AppendElement(fe);
|
2018-11-30 13:46:48 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-09-16 13:58:12 +04:00
|
|
|
// Most families are "simple", having just Regular/Bold/Italic/BoldItalic,
|
|
|
|
// or some subset of these. In this case, we have exactly 4 entries in
|
2018-04-25 09:18:23 +03:00
|
|
|
// mAvailableFonts, stored in the above order; note that some of the entries
|
|
|
|
// may be nullptr. We can then pick the required entry based on whether the
|
|
|
|
// request is for bold or non-bold, italic or non-italic, without running the
|
|
|
|
// more complex matching algorithm used for larger families with many weights
|
2014-09-16 13:58:12 +04:00
|
|
|
// and/or widths.
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2018-04-25 09:18:23 +03:00
|
|
|
if (mIsSimpleFamily) {
|
|
|
|
// Family has no more than the "standard" 4 faces, at fixed indexes;
|
2014-09-16 13:58:12 +04:00
|
|
|
// calculate which one we want.
|
2018-04-25 09:18:23 +03:00
|
|
|
// Note that we cannot simply return it as not all 4 faces are necessarily
|
2014-09-16 13:58:12 +04:00
|
|
|
// present.
|
2018-04-25 09:18:23 +03:00
|
|
|
bool wantBold = aFontStyle.weight >= FontWeight(600);
|
|
|
|
bool wantItalic = !aFontStyle.style.IsNormal();
|
2014-09-16 13:58:12 +04:00
|
|
|
uint8_t faceIndex =
|
|
|
|
(wantItalic ? kItalicMask : 0) | (wantBold ? kBoldMask : 0);
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2018-04-25 09:18:23 +03:00
|
|
|
// if the desired style is available, return it directly
|
2014-11-06 07:42:50 +03:00
|
|
|
fe = mAvailableFonts[faceIndex];
|
2014-09-16 13:58:12 +04:00
|
|
|
if (fe) {
|
2014-11-06 07:42:50 +03:00
|
|
|
aFontEntryList.AppendElement(fe);
|
2017-08-07 19:27:33 +03:00
|
|
|
return;
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
|
2014-09-16 13:58:12 +04:00
|
|
|
// order to check fallback faces in a simple family, depending on requested
|
|
|
|
// style
|
|
|
|
static const uint8_t simpleFallbacks[4][3] = {
|
|
|
|
{kBoldFaceIndex, kItalicFaceIndex,
|
|
|
|
kBoldItalicFaceIndex}, // fallbacks for Regular
|
2014-11-06 07:42:50 +03:00
|
|
|
{kRegularFaceIndex, kBoldItalicFaceIndex, kItalicFaceIndex}, // Bold
|
|
|
|
{kBoldItalicFaceIndex, kRegularFaceIndex, kBoldFaceIndex}, // Italic
|
2014-09-16 13:58:12 +04:00
|
|
|
{kItalicFaceIndex, kBoldFaceIndex, kRegularFaceIndex} // BoldItalic
|
2018-11-30 13:46:48 +03:00
|
|
|
};
|
2014-11-06 07:42:50 +03:00
|
|
|
const uint8_t* order = simpleFallbacks[faceIndex];
|
2014-09-16 13:58:12 +04:00
|
|
|
|
2014-11-06 07:42:50 +03:00
|
|
|
for (uint8_t trial = 0; trial < 3; ++trial) {
|
|
|
|
// check remaining faces in order of preference to find the first that
|
|
|
|
// actually exists
|
|
|
|
fe = mAvailableFonts[order[trial]];
|
2014-09-16 13:58:12 +04:00
|
|
|
if (fe) {
|
2014-11-06 07:42:50 +03:00
|
|
|
aFontEntryList.AppendElement(fe);
|
|
|
|
return;
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-16 13:58:12 +04:00
|
|
|
// this can't happen unless we have totally broken the font-list manager!
|
2018-06-18 08:43:11 +03:00
|
|
|
MOZ_ASSERT_UNREACHABLE("no face found in simple font family!");
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
|
2014-11-06 07:42:50 +03:00
|
|
|
// Pick the font(s) that are closest to the desired weight, style, and
|
|
|
|
// stretch. Iterate over all fonts, measuring the weight/style distance.
|
|
|
|
// Because of unicode-range values, there may be more than one font for a
|
|
|
|
// given but the 99% use case is only a single font entry per
|
|
|
|
// weight/style/stretch distance value. To optimize this, only add entries
|
|
|
|
// to the matched font array when another entry already has the same
|
|
|
|
// weight/style/stretch distance and add the last matched font entry. For
|
|
|
|
// normal platform fonts with a single font entry for each
|
|
|
|
// weight/style/stretch combination, only the last matched font entry will
|
|
|
|
// be added.
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2018-05-15 16:59:25 +03:00
|
|
|
double minDistance = INFINITY;
|
2014-11-06 07:42:50 +03:00
|
|
|
gfxFontEntry* matched = nullptr;
|
2015-09-02 06:24:30 +03:00
|
|
|
// iterate in forward order so that faces like 'Bold' are matched before
|
|
|
|
// matching style distance faces such as 'Bold Outline' (see bug 1185812)
|
|
|
|
for (uint32_t i = 0; i < count; i++) {
|
2014-11-06 07:42:50 +03:00
|
|
|
fe = mAvailableFonts[i];
|
2015-10-19 05:16:43 +03:00
|
|
|
// weight/style/stretch priority: stretch >> style >> weight
|
2018-04-25 09:18:23 +03:00
|
|
|
double distance = WeightStyleStretchDistance(fe, aFontStyle);
|
2014-11-06 07:42:50 +03:00
|
|
|
if (distance < minDistance) {
|
|
|
|
matched = fe;
|
|
|
|
if (!aFontEntryList.IsEmpty()) {
|
|
|
|
aFontEntryList.Clear();
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
2014-11-06 07:42:50 +03:00
|
|
|
minDistance = distance;
|
|
|
|
} else if (distance == minDistance) {
|
|
|
|
if (matched) {
|
|
|
|
aFontEntryList.AppendElement(matched);
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
2014-11-06 07:42:50 +03:00
|
|
|
matched = fe;
|
2014-09-16 13:58:12 +04:00
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
2014-09-16 13:58:12 +04:00
|
|
|
|
|
|
|
NS_ASSERTION(matched, "didn't match a font within a family");
|
|
|
|
|
|
|
|
if (matched) {
|
2014-11-06 07:42:50 +03:00
|
|
|
aFontEntryList.AppendElement(matched);
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
2014-09-16 13:58:12 +04:00
|
|
|
}
|
|
|
|
|
2018-06-18 08:43:11 +03:00
|
|
|
void gfxFontFamily::CheckForSimpleFamily() {
|
2014-11-06 07:42:50 +03:00
|
|
|
// already checked this family
|
|
|
|
if (mIsSimpleFamily) {
|
|
|
|
return;
|
|
|
|
}
|
2014-09-16 13:58:12 +04:00
|
|
|
|
2014-11-06 07:42:50 +03:00
|
|
|
uint32_t count = mAvailableFonts.Length();
|
2014-09-16 13:58:12 +04:00
|
|
|
if (count > 4 || count == 0) {
|
2014-11-06 07:42:50 +03:00
|
|
|
return; // can't be "simple" if there are >4 faces;
|
|
|
|
// if none then the family is unusable anyway
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
2014-09-16 13:58:12 +04:00
|
|
|
|
2014-11-06 07:42:50 +03:00
|
|
|
if (count == 1) {
|
2014-09-16 13:58:12 +04:00
|
|
|
mIsSimpleFamily = true;
|
|
|
|
return;
|
2016-01-22 18:58:49 +03:00
|
|
|
}
|
2014-09-16 13:58:12 +04:00
|
|
|
|
|
|
|
StretchRange firstStretch = mAvailableFonts[0]->Stretch();
|
|
|
|
if (!firstStretch.IsSingle()) {
|
|
|
|
return; // family with variation fonts is not considered "simple"
|
|
|
|
}
|
|
|
|
|
|
|
|
gfxFontEntry* faces[4] = {0};
|
|
|
|
for (uint8_t i = 0; i < count; ++i) {
|
|
|
|
gfxFontEntry* fe = mAvailableFonts[i];
|
|
|
|
if (fe->Stretch() != firstStretch || fe->IsOblique()) {
|
|
|
|
// simple families don't have varying font-stretch or oblique
|
|
|
|
return;
|
|
|
|
}
|
2018-04-25 09:18:23 +03:00
|
|
|
if (!fe->Weight().IsSingle() || !fe->SlantStyle().IsSingle()) {
|
|
|
|
return; // family with variation fonts is not considered "simple"
|
|
|
|
}
|
2014-09-16 13:58:12 +04:00
|
|
|
uint8_t faceIndex = (fe->IsItalic() ? kItalicMask : 0) |
|
2018-05-04 12:19:55 +03:00
|
|
|
(fe->SupportsBold() ? kBoldMask : 0);
|
2014-09-16 13:58:12 +04:00
|
|
|
if (faces[faceIndex]) {
|
|
|
|
return; // two faces resolve to the same slot; family isn't "simple"
|
|
|
|
}
|
|
|
|
faces[faceIndex] = fe;
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
2014-09-16 13:58:12 +04:00
|
|
|
|
|
|
|
// we have successfully slotted the available faces into the standard
|
|
|
|
// 4-face framework
|
|
|
|
mAvailableFonts.SetLength(4);
|
|
|
|
for (uint8_t i = 0; i < 4; ++i) {
|
|
|
|
if (mAvailableFonts[i].get() != faces[i]) {
|
|
|
|
mAvailableFonts[i].swap(faces[i]);
|
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
2014-09-16 13:58:12 +04:00
|
|
|
|
|
|
|
mIsSimpleFamily = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
bool gfxFontFamily::ContainsFace(gfxFontEntry* aFontEntry) {
|
|
|
|
uint32_t i, numFonts = mAvailableFonts.Length();
|
|
|
|
for (i = 0; i < numFonts; i++) {
|
|
|
|
if (mAvailableFonts[i] == aFontEntry) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
// userfonts contain the actual real font entry
|
2014-09-18 13:48:00 +04:00
|
|
|
if (mAvailableFonts[i] && mAvailableFonts[i]->mIsUserFontContainer) {
|
2014-09-16 13:58:12 +04:00
|
|
|
gfxUserFontEntry* ufe =
|
|
|
|
static_cast<gfxUserFontEntry*>(mAvailableFonts[i].get());
|
|
|
|
if (ufe->GetPlatformFontEntry() == aFontEntry) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
2014-09-16 13:58:12 +04:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2018-09-12 22:34:57 +03:00
|
|
|
void gfxFontFamily::LocalizedName(nsACString& aLocalizedName) {
|
2014-09-16 13:58:12 +04:00
|
|
|
// just return the primary name; subclasses should override
|
|
|
|
aLocalizedName = mName;
|
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2018-05-15 16:59:25 +03:00
|
|
|
void gfxFontFamily::FindFontForChar(GlobalFontMatch* aMatchData) {
|
2014-09-16 13:58:12 +04:00
|
|
|
if (mFamilyCharacterMapInitialized && !TestCharacterMap(aMatchData->mCh)) {
|
|
|
|
// none of the faces in the family support the required char,
|
|
|
|
// so bail out immediately
|
|
|
|
return;
|
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2019-01-22 12:40:57 +03:00
|
|
|
#ifdef MOZ_GECKO_PROFILER
|
|
|
|
nsCString charAndName;
|
|
|
|
if (profiler_is_active()) {
|
|
|
|
charAndName = nsPrintfCString("\\u%x %s", aMatchData->mCh, mName.get());
|
|
|
|
}
|
|
|
|
|
|
|
|
AUTO_PROFILER_LABEL_DYNAMIC_NSCSTRING("gfxFontFamily::FindFontForChar",
|
|
|
|
LAYOUT, charAndName);
|
|
|
|
#endif
|
|
|
|
|
2019-02-15 11:15:57 +03:00
|
|
|
AutoTArray<gfxFontEntry*, 4> entries;
|
2019-02-08 13:05:56 +03:00
|
|
|
FindAllFontsForStyle(aMatchData->mStyle, entries,
|
|
|
|
/*aIgnoreSizeTolerance*/ true);
|
|
|
|
if (entries.IsEmpty()) {
|
2018-05-15 16:59:25 +03:00
|
|
|
return;
|
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2019-02-08 13:05:56 +03:00
|
|
|
gfxFontEntry* fe = nullptr;
|
2018-05-15 16:59:25 +03:00
|
|
|
float distance = INFINITY;
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2019-02-08 13:05:56 +03:00
|
|
|
for (auto e : entries) {
|
|
|
|
if (e->SkipDuringSystemFallback()) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
aMatchData->mCmapsTested++;
|
|
|
|
if (e->HasCharacter(aMatchData->mCh)) {
|
|
|
|
aMatchData->mCount++;
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2019-02-08 13:05:56 +03:00
|
|
|
LogModule* log = gfxPlatform::GetLog(eGfxLog_textrun);
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2019-02-08 13:05:56 +03:00
|
|
|
if (MOZ_UNLIKELY(MOZ_LOG_TEST(log, LogLevel::Debug))) {
|
|
|
|
Script script = GetScriptCode(aMatchData->mCh);
|
|
|
|
MOZ_LOG(log, LogLevel::Debug,
|
|
|
|
("(textrun-systemfallback-fonts) char: u+%6.6x "
|
2019-04-11 00:43:22 +03:00
|
|
|
"script: %d match: [%s]\n",
|
|
|
|
aMatchData->mCh, int(script), e->Name().get()));
|
2019-02-08 13:05:56 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
fe = e;
|
|
|
|
distance = WeightStyleStretchDistance(fe, aMatchData->mStyle);
|
|
|
|
break;
|
2014-09-16 13:58:12 +04:00
|
|
|
}
|
2019-02-08 13:05:56 +03:00
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2019-02-08 13:05:56 +03:00
|
|
|
if (!fe && !aMatchData->mStyle.IsNormalStyle()) {
|
2018-05-15 16:59:25 +03:00
|
|
|
// If style/weight/stretch was not Normal, see if we can
|
|
|
|
// fall back to a next-best face (e.g. Arial Black -> Bold,
|
|
|
|
// or Arial Narrow -> Regular).
|
|
|
|
GlobalFontMatch data(aMatchData->mCh, aMatchData->mStyle);
|
|
|
|
SearchAllFontsForChar(&data);
|
2019-02-08 13:05:56 +03:00
|
|
|
if (!data.mBestMatch) {
|
|
|
|
return;
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
2019-02-08 13:05:56 +03:00
|
|
|
fe = data.mBestMatch;
|
|
|
|
distance = data.mMatchDistance;
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
|
2019-02-08 13:05:56 +03:00
|
|
|
if (!fe) {
|
2018-11-30 13:46:48 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-05-15 17:32:33 +03:00
|
|
|
if (distance < aMatchData->mMatchDistance ||
|
2018-05-15 16:59:25 +03:00
|
|
|
(distance == aMatchData->mMatchDistance &&
|
2018-05-15 17:32:33 +03:00
|
|
|
Compare(fe->Name(), aMatchData->mBestMatch->Name()) > 0)) {
|
2018-05-15 16:59:25 +03:00
|
|
|
aMatchData->mBestMatch = fe;
|
|
|
|
aMatchData->mMatchedFamily = this;
|
|
|
|
aMatchData->mMatchDistance = distance;
|
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
|
2018-05-15 16:59:25 +03:00
|
|
|
void gfxFontFamily::SearchAllFontsForChar(GlobalFontMatch* aMatchData) {
|
2014-09-16 13:58:12 +04:00
|
|
|
uint32_t i, numFonts = mAvailableFonts.Length();
|
2018-05-15 16:59:25 +03:00
|
|
|
for (i = 0; i < numFonts; i++) {
|
|
|
|
gfxFontEntry* fe = mAvailableFonts[i];
|
|
|
|
if (fe && fe->HasCharacter(aMatchData->mCh)) {
|
|
|
|
float distance = WeightStyleStretchDistance(fe, aMatchData->mStyle);
|
|
|
|
if (distance < aMatchData->mMatchDistance ||
|
|
|
|
(distance == aMatchData->mMatchDistance &&
|
|
|
|
Compare(fe->Name(), aMatchData->mBestMatch->Name()) > 0)) {
|
|
|
|
aMatchData->mBestMatch = fe;
|
|
|
|
aMatchData->mMatchedFamily = this;
|
|
|
|
aMatchData->mMatchDistance = distance;
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
2014-09-16 13:58:12 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-04-08 01:49:44 +03:00
|
|
|
/*virtual*/
|
|
|
|
gfxFontFamily::~gfxFontFamily() {
|
|
|
|
// Should not be dropped by stylo
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2014-09-16 13:58:12 +04:00
|
|
|
// returns true if other names were found, false otherwise
|
|
|
|
bool gfxFontFamily::ReadOtherFamilyNamesForFace(
|
|
|
|
gfxPlatformFontList* aPlatformFontList, hb_blob_t* aNameTable,
|
|
|
|
bool useFullName) {
|
|
|
|
uint32_t dataLength;
|
|
|
|
const char* nameData = hb_blob_get_data(aNameTable, &dataLength);
|
2018-09-12 22:34:57 +03:00
|
|
|
AutoTArray<nsCString, 4> otherFamilyNames;
|
2014-09-16 13:58:12 +04:00
|
|
|
|
2019-04-01 17:33:46 +03:00
|
|
|
gfxFontUtils::ReadOtherFamilyNamesForFace(mName, nameData, dataLength,
|
|
|
|
otherFamilyNames, useFullName);
|
2014-09-16 13:58:12 +04:00
|
|
|
|
|
|
|
uint32_t n = otherFamilyNames.Length();
|
|
|
|
for (uint32_t i = 0; i < n; i++) {
|
|
|
|
aPlatformFontList->AddOtherFamilyName(this, otherFamilyNames[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
return n != 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void gfxFontFamily::ReadOtherFamilyNames(
|
|
|
|
gfxPlatformFontList* aPlatformFontList) {
|
|
|
|
if (mOtherFamilyNamesInitialized) return;
|
|
|
|
mOtherFamilyNamesInitialized = true;
|
|
|
|
|
|
|
|
FindStyleVariations();
|
|
|
|
|
2018-09-12 22:34:57 +03:00
|
|
|
// read in other family names for the first face in the list
|
2017-08-01 13:25:35 +03:00
|
|
|
uint32_t i, numFonts = mAvailableFonts.Length();
|
|
|
|
const uint32_t kNAME = TRUETYPE_TAG('n', 'a', 'm', 'e');
|
|
|
|
|
|
|
|
for (i = 0; i < numFonts; ++i) {
|
|
|
|
gfxFontEntry* fe = mAvailableFonts[i];
|
|
|
|
if (!fe) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
gfxFontEntry::AutoTable nameTable(fe, kNAME);
|
|
|
|
if (!nameTable) {
|
|
|
|
continue;
|
|
|
|
}
|
2014-09-16 13:58:12 +04:00
|
|
|
mHasOtherFamilyNames =
|
|
|
|
ReadOtherFamilyNamesForFace(aPlatformFontList, nameTable);
|
2018-11-30 13:46:48 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2014-09-16 13:58:12 +04:00
|
|
|
// read in other names for the first face in the list with the assumption
|
|
|
|
// that if extra names don't exist in that face then they don't exist in
|
|
|
|
// other faces for the same font
|
|
|
|
if (!mHasOtherFamilyNames) return;
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2014-09-16 13:58:12 +04:00
|
|
|
// read in names for all faces, needed to catch cases where fonts have
|
|
|
|
// family names for individual weights (e.g. Hiragino Kaku Gothic Pro W6)
|
|
|
|
for (; i < numFonts; i++) {
|
|
|
|
gfxFontEntry* fe = mAvailableFonts[i];
|
|
|
|
if (!fe) {
|
|
|
|
continue;
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
2014-09-16 13:58:12 +04:00
|
|
|
gfxFontEntry::AutoTable nameTable(fe, kNAME);
|
|
|
|
if (!nameTable) {
|
|
|
|
continue;
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
2014-09-16 13:58:12 +04:00
|
|
|
ReadOtherFamilyNamesForFace(aPlatformFontList, nameTable);
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-12 22:34:57 +03:00
|
|
|
static bool LookForLegacyFamilyName(const nsACString& aCanonicalName,
|
2017-08-01 13:25:35 +03:00
|
|
|
const char* aNameData, uint32_t aDataLength,
|
2018-09-12 22:34:57 +03:00
|
|
|
nsACString& aLegacyName /* outparam */) {
|
2017-08-01 13:25:35 +03:00
|
|
|
const gfxFontUtils::NameHeader* nameHeader =
|
|
|
|
reinterpret_cast<const gfxFontUtils::NameHeader*>(aNameData);
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2017-08-01 13:25:35 +03:00
|
|
|
uint32_t nameCount = nameHeader->count;
|
|
|
|
if (nameCount * sizeof(gfxFontUtils::NameRecord) > aDataLength) {
|
|
|
|
NS_WARNING("invalid font (name records)");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
const gfxFontUtils::NameRecord* nameRecord =
|
2018-05-08 22:54:02 +03:00
|
|
|
reinterpret_cast<const gfxFontUtils::NameRecord*>(
|
2017-08-01 13:25:35 +03:00
|
|
|
aNameData + sizeof(gfxFontUtils::NameHeader));
|
|
|
|
uint32_t stringsBase = uint32_t(nameHeader->stringOffset);
|
|
|
|
|
2014-09-16 13:58:12 +04:00
|
|
|
for (uint32_t i = 0; i < nameCount; i++, nameRecord++) {
|
|
|
|
uint32_t nameLen = nameRecord->length;
|
|
|
|
uint32_t nameOff = nameRecord->offset;
|
|
|
|
|
2018-09-12 22:34:57 +03:00
|
|
|
if (stringsBase + nameOff + nameLen > aDataLength) {
|
2014-09-16 13:58:12 +04:00
|
|
|
NS_WARNING("invalid font (name table strings)");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (uint16_t(nameRecord->nameID) == gfxFontUtils::NAME_ID_FAMILY) {
|
|
|
|
bool ok = gfxFontUtils::DecodeFontName(
|
|
|
|
aNameData + stringsBase + nameOff, nameLen,
|
|
|
|
uint32_t(nameRecord->platformID), uint32_t(nameRecord->encodingID),
|
|
|
|
uint32_t(nameRecord->languageID), aLegacyName);
|
|
|
|
// it's only a legacy name if it differs from the canonical name
|
|
|
|
if (ok && aLegacyName != aCanonicalName) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
2014-09-16 13:58:12 +04:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool gfxFontFamily::CheckForLegacyFamilyNames(gfxPlatformFontList* aFontList) {
|
2017-08-01 13:25:35 +03:00
|
|
|
if (mCheckedForLegacyFamilyNames) {
|
|
|
|
// we already did this, so there's nothing more to add
|
|
|
|
return false;
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
2017-08-01 13:25:35 +03:00
|
|
|
mCheckedForLegacyFamilyNames = true;
|
|
|
|
bool added = false;
|
2014-09-16 13:58:12 +04:00
|
|
|
const uint32_t kNAME = TRUETYPE_TAG('n', 'a', 'm', 'e');
|
2018-05-08 22:54:02 +03:00
|
|
|
// Make a local copy of the array of font faces, in case of changes
|
|
|
|
// during the iteration.
|
|
|
|
AutoTArray<RefPtr<gfxFontEntry>, 8> faces(mAvailableFonts);
|
|
|
|
for (auto& fe : faces) {
|
2014-09-16 13:58:12 +04:00
|
|
|
if (!fe) {
|
|
|
|
continue;
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
2014-09-16 13:58:12 +04:00
|
|
|
gfxFontEntry::AutoTable nameTable(fe, kNAME);
|
2018-09-12 22:34:57 +03:00
|
|
|
if (!nameTable) {
|
|
|
|
continue;
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
2018-09-12 22:34:57 +03:00
|
|
|
nsAutoCString legacyName;
|
2017-08-01 13:25:35 +03:00
|
|
|
uint32_t dataLength;
|
2018-09-12 22:34:57 +03:00
|
|
|
const char* nameData = hb_blob_get_data(nameTable, &dataLength);
|
2017-08-01 13:25:35 +03:00
|
|
|
if (LookForLegacyFamilyName(Name(), nameData, dataLength, legacyName)) {
|
|
|
|
if (aFontList->AddWithLegacyFamilyName(legacyName, fe)) {
|
|
|
|
added = true;
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-08-01 13:25:35 +03:00
|
|
|
return added;
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
|
2018-09-12 22:34:57 +03:00
|
|
|
void gfxFontFamily::ReadFaceNames(gfxPlatformFontList* aPlatformFontList,
|
|
|
|
bool aNeedFullnamePostscriptNames,
|
2014-09-16 13:58:12 +04:00
|
|
|
FontInfoData* aFontInfoData) {
|
|
|
|
// if all needed names have already been read, skip
|
|
|
|
if (mOtherFamilyNamesInitialized &&
|
2019-04-27 18:37:58 +03:00
|
|
|
(mFaceNamesInitialized || !aNeedFullnamePostscriptNames)) {
|
2018-11-30 13:46:48 +03:00
|
|
|
return;
|
2019-04-27 18:37:58 +03:00
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2014-09-16 13:58:12 +04:00
|
|
|
bool asyncFontLoaderDisabled = false;
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2014-09-16 13:58:12 +04:00
|
|
|
if (!mOtherFamilyNamesInitialized && aFontInfoData &&
|
|
|
|
aFontInfoData->mLoadOtherNames && !asyncFontLoaderDisabled) {
|
2018-09-12 22:34:57 +03:00
|
|
|
AutoTArray<nsCString, 4> otherFamilyNames;
|
2014-09-16 13:58:12 +04:00
|
|
|
bool foundOtherNames =
|
|
|
|
aFontInfoData->GetOtherFamilyNames(mName, otherFamilyNames);
|
|
|
|
if (foundOtherNames) {
|
|
|
|
uint32_t i, n = otherFamilyNames.Length();
|
|
|
|
for (i = 0; i < n; i++) {
|
|
|
|
aPlatformFontList->AddOtherFamilyName(this, otherFamilyNames[i]);
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
2014-09-16 13:58:12 +04:00
|
|
|
}
|
|
|
|
mOtherFamilyNamesInitialized = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// if all needed data has been initialized, return
|
|
|
|
if (mOtherFamilyNamesInitialized &&
|
|
|
|
(mFaceNamesInitialized || !aNeedFullnamePostscriptNames)) {
|
2018-11-30 13:46:48 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-09-16 13:58:12 +04:00
|
|
|
FindStyleVariations(aFontInfoData);
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2014-09-16 13:58:12 +04:00
|
|
|
// check again, as style enumeration code may have loaded names
|
|
|
|
if (mOtherFamilyNamesInitialized &&
|
|
|
|
(mFaceNamesInitialized || !aNeedFullnamePostscriptNames)) {
|
2018-11-30 13:46:48 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-09-16 13:58:12 +04:00
|
|
|
uint32_t i, numFonts = mAvailableFonts.Length();
|
|
|
|
const uint32_t kNAME = TRUETYPE_TAG('n', 'a', 'm', 'e');
|
|
|
|
|
|
|
|
bool firstTime = true, readAllFaces = false;
|
|
|
|
for (i = 0; i < numFonts; ++i) {
|
|
|
|
gfxFontEntry* fe = mAvailableFonts[i];
|
|
|
|
if (!fe) {
|
|
|
|
continue;
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
|
2014-09-16 13:58:12 +04:00
|
|
|
nsAutoCString fullname, psname;
|
|
|
|
bool foundFaceNames = false;
|
|
|
|
if (!mFaceNamesInitialized && aNeedFullnamePostscriptNames &&
|
|
|
|
aFontInfoData && aFontInfoData->mLoadFaceNames) {
|
|
|
|
aFontInfoData->GetFaceNames(fe->Name(), fullname, psname);
|
|
|
|
if (!fullname.IsEmpty()) {
|
|
|
|
aPlatformFontList->AddFullname(fe, fullname);
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
2014-09-16 13:58:12 +04:00
|
|
|
if (!psname.IsEmpty()) {
|
|
|
|
aPlatformFontList->AddPostscriptName(fe, psname);
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
2014-09-16 13:58:12 +04:00
|
|
|
foundFaceNames = true;
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2014-09-16 13:58:12 +04:00
|
|
|
// found everything needed? skip to next font
|
|
|
|
if (mOtherFamilyNamesInitialized) {
|
|
|
|
continue;
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-16 13:58:12 +04:00
|
|
|
// load directly from the name table
|
|
|
|
gfxFontEntry::AutoTable nameTable(fe, kNAME);
|
|
|
|
if (!nameTable) {
|
|
|
|
continue;
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
|
2014-09-16 13:58:12 +04:00
|
|
|
if (aNeedFullnamePostscriptNames && !foundFaceNames) {
|
|
|
|
if (gfxFontUtils::ReadCanonicalName(nameTable, gfxFontUtils::NAME_ID_FULL,
|
|
|
|
fullname) == NS_OK) {
|
|
|
|
aPlatformFontList->AddFullname(fe, fullname);
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
|
2014-09-16 13:58:12 +04:00
|
|
|
if (gfxFontUtils::ReadCanonicalName(
|
|
|
|
nameTable, gfxFontUtils::NAME_ID_POSTSCRIPT, psname) == NS_OK) {
|
|
|
|
aPlatformFontList->AddPostscriptName(fe, psname);
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-16 13:58:12 +04:00
|
|
|
if (!mOtherFamilyNamesInitialized && (firstTime || readAllFaces)) {
|
|
|
|
bool foundOtherName =
|
|
|
|
ReadOtherFamilyNamesForFace(aPlatformFontList, nameTable);
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2014-09-16 13:58:12 +04:00
|
|
|
// if the first face has a different name, scan all faces, otherwise
|
|
|
|
// assume the family doesn't have other names
|
|
|
|
if (firstTime && foundOtherName) {
|
|
|
|
mHasOtherFamilyNames = true;
|
|
|
|
readAllFaces = true;
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
2014-09-16 13:58:12 +04:00
|
|
|
firstTime = false;
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
|
2014-09-16 13:58:12 +04:00
|
|
|
// if not reading in any more names, skip other faces
|
|
|
|
if (!readAllFaces && !aNeedFullnamePostscriptNames) {
|
2018-11-30 13:46:48 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-16 13:58:12 +04:00
|
|
|
mFaceNamesInitialized = true;
|
|
|
|
mOtherFamilyNamesInitialized = true;
|
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2014-09-16 13:58:12 +04:00
|
|
|
gfxFontEntry* gfxFontFamily::FindFont(const nsACString& aPostscriptName) {
|
|
|
|
// find the font using a simple linear search
|
|
|
|
uint32_t numFonts = mAvailableFonts.Length();
|
2017-08-01 13:25:35 +03:00
|
|
|
for (uint32_t i = 0; i < numFonts; i++) {
|
2014-09-16 13:58:12 +04:00
|
|
|
gfxFontEntry* fe = mAvailableFonts[i].get();
|
|
|
|
if (fe && fe->Name() == aPostscriptName) return fe;
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
2014-09-16 13:58:12 +04:00
|
|
|
return nullptr;
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
|
2014-09-16 13:58:12 +04:00
|
|
|
void gfxFontFamily::ReadAllCMAPs(FontInfoData* aFontInfoData) {
|
|
|
|
FindStyleVariations(aFontInfoData);
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2014-09-16 13:58:12 +04:00
|
|
|
uint32_t i, numFonts = mAvailableFonts.Length();
|
|
|
|
for (i = 0; i < numFonts; i++) {
|
|
|
|
gfxFontEntry* fe = mAvailableFonts[i];
|
|
|
|
// don't try to load cmaps for downloadable fonts not yet loaded
|
|
|
|
if (!fe || fe->mIsUserFontContainer) {
|
2017-08-01 13:25:35 +03:00
|
|
|
continue;
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
2014-09-16 13:58:12 +04:00
|
|
|
fe->ReadCMAP(aFontInfoData);
|
|
|
|
mFamilyCharacterMap.Union(*(fe->mCharacterMap));
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
2014-09-16 13:58:12 +04:00
|
|
|
mFamilyCharacterMap.Compact();
|
|
|
|
mFamilyCharacterMapInitialized = true;
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
|
2014-09-16 13:58:12 +04:00
|
|
|
void gfxFontFamily::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
|
|
|
|
FontListSizes* aSizes) const {
|
|
|
|
aSizes->mFontListSize += mName.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
|
|
|
|
aSizes->mCharMapsSize +=
|
|
|
|
mFamilyCharacterMap.SizeOfExcludingThis(aMallocSizeOf);
|
|
|
|
|
|
|
|
aSizes->mFontListSize +=
|
2015-07-29 09:24:24 +03:00
|
|
|
mAvailableFonts.ShallowSizeOfExcludingThis(aMallocSizeOf);
|
2014-09-16 13:58:12 +04:00
|
|
|
for (uint32_t i = 0; i < mAvailableFonts.Length(); ++i) {
|
|
|
|
gfxFontEntry* fe = mAvailableFonts[i];
|
|
|
|
if (fe) {
|
|
|
|
fe->AddSizeOfIncludingThis(aMallocSizeOf, aSizes);
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-16 13:58:12 +04:00
|
|
|
void gfxFontFamily::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
|
|
|
|
FontListSizes* aSizes) const {
|
|
|
|
aSizes->mFontListSize += aMallocSizeOf(this);
|
|
|
|
AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
|
|
|
|
}
|