Bug 1798036 - Attach a SharedFTFaceData (recording the filename) when instantiating SharedFTFace for an installed variation font. r=lsalzman

This is needed so that UnscaledFontFreeType::CreateScaledFont can later call CloneFace
if it needs to apply variation settings.

Tested locally with an emulator running Android 13; not testable in CI as the older Android
versions we have there don't use the new variable-font version of Roboto.

Differential Revision: https://phabricator.services.mozilla.com/D161762
This commit is contained in:
Jonathan Kew 2022-11-10 17:24:11 +00:00
Родитель 1563f74dd5
Коммит c9e98f8fad
10 изменённых файлов: 138 добавлений и 107 удалений

Просмотреть файл

@ -1067,6 +1067,40 @@ class SharedFTFaceRefCountedData : public SharedFTFaceData {
void ReleaseData() { static_cast<T*>(this)->Release(); }
};
// Helper class used for clearing out user font data when FT font
// face is destroyed. Since multiple faces may use the same data, be
// careful to assure that the data is only cleared out when all uses
// expire. The font entry object contains a refptr to FTUserFontData and
// each FT face created from that font entry contains a refptr to that
// same FTUserFontData object.
// This is also attached to FT faces for installed fonts (recording the
// filename, rather than storing the font data) if variations are present.
class FTUserFontData final
: public mozilla::gfx::SharedFTFaceRefCountedData<FTUserFontData> {
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(FTUserFontData)
FTUserFontData(const uint8_t* aData, uint32_t aLength)
: mFontData(aData), mLength(aLength) {}
explicit FTUserFontData(const char* aFilename) : mFilename(aFilename) {}
const uint8_t* FontData() const { return mFontData; }
already_AddRefed<mozilla::gfx::SharedFTFace> CloneFace(
int aFaceIndex = 0) override;
private:
~FTUserFontData() {
if (mFontData) {
free((void*)mFontData);
}
}
std::string mFilename;
const uint8_t* mFontData = nullptr;
uint32_t mLength = 0;
};
/** SharedFTFace is a shared wrapper around an FT_Face. It is ref-counted,
* unlike FT_Face itself, so that it may be shared among many users with
* RefPtr. Users should take care to lock SharedFTFace before accessing any
@ -1078,7 +1112,7 @@ class SharedFTFace : public external::AtomicRefCounted<SharedFTFace> {
public:
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(SharedFTFace)
explicit SharedFTFace(FT_Face aFace, SharedFTFaceData* aData = nullptr);
explicit SharedFTFace(FT_Face aFace, SharedFTFaceData* aData);
virtual ~SharedFTFace();
FT_Face GetFace() const { return mFace; }

Просмотреть файл

@ -200,6 +200,25 @@ namespace mozilla::gfx {
#ifdef MOZ_ENABLE_FREETYPE
FT_Library Factory::mFTLibrary = nullptr;
StaticMutex Factory::mFTLock;
already_AddRefed<SharedFTFace> FTUserFontData::CloneFace(int aFaceIndex) {
if (mFontData) {
RefPtr<SharedFTFace> face = Factory::NewSharedFTFaceFromData(
nullptr, mFontData, mLength, aFaceIndex, this);
if (!face ||
(FT_Select_Charmap(face->GetFace(), FT_ENCODING_UNICODE) != FT_Err_Ok &&
FT_Select_Charmap(face->GetFace(), FT_ENCODING_MS_SYMBOL) !=
FT_Err_Ok)) {
return nullptr;
}
return face.forget();
}
FT_Face face = Factory::NewFTFace(nullptr, mFilename.c_str(), aFaceIndex);
if (face) {
return MakeAndAddRef<SharedFTFace>(face, this);
}
return nullptr;
}
#endif
#ifdef WIN32
@ -649,11 +668,19 @@ FT_Face Factory::NewFTFace(FT_Library aFTLibrary, const char* aFileName,
already_AddRefed<SharedFTFace> Factory::NewSharedFTFace(FT_Library aFTLibrary,
const char* aFilename,
int aFaceIndex) {
if (FT_Face face = NewFTFace(aFTLibrary, aFilename, aFaceIndex)) {
return MakeAndAddRef<SharedFTFace>(face);
} else {
FT_Face face = NewFTFace(aFTLibrary, aFilename, aFaceIndex);
if (!face) {
return nullptr;
}
// If the font has variations, we may later need to "clone" it in
// UnscaledFontFreeType::CreateScaledFont. To support this, we attach an
// FTUserFontData that records the filename used to instantiate the face.
RefPtr<FTUserFontData> data;
if (face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS) {
data = new FTUserFontData(aFilename);
}
return MakeAndAddRef<SharedFTFace>(face, data);
}
FT_Face Factory::NewFTFaceFromData(FT_Library aFTLibrary, const uint8_t* aData,

Просмотреть файл

@ -127,50 +127,6 @@ ScaledFontFreeType::InstanceData::InstanceData(
}
}
already_AddRefed<ScaledFont> UnscaledFontFreeType::CreateScaledFont(
Float aGlyphSize, const uint8_t* aInstanceData,
uint32_t aInstanceDataLength, const FontVariation* aVariations,
uint32_t aNumVariations) {
if (aInstanceDataLength < sizeof(ScaledFontFreeType::InstanceData)) {
gfxWarning() << "FreeType scaled font instance data is truncated.";
return nullptr;
}
const ScaledFontFreeType::InstanceData& instanceData =
*reinterpret_cast<const ScaledFontFreeType::InstanceData*>(aInstanceData);
RefPtr<SharedFTFace> face(InitFace());
if (!face) {
gfxWarning() << "Attempted to deserialize FreeType scaled font without "
"FreeType face";
return nullptr;
}
if (aNumVariations > 0 && face->GetData()) {
if (RefPtr<SharedFTFace> varFace = face->GetData()->CloneFace()) {
face = varFace;
}
}
// Only apply variations if we have an explicitly cloned face.
if (aNumVariations > 0 && face != GetFace()) {
ApplyVariationsToFace(aVariations, aNumVariations, face->GetFace());
}
RefPtr<ScaledFontFreeType> scaledFont = new ScaledFontFreeType(
std::move(face), this, aGlyphSize, instanceData.mApplySyntheticBold);
return scaledFont.forget();
}
already_AddRefed<ScaledFont> UnscaledFontFreeType::CreateScaledFontFromWRFont(
Float aGlyphSize, const wr::FontInstanceOptions* aOptions,
const wr::FontInstancePlatformOptions* aPlatformOptions,
const FontVariation* aVariations, uint32_t aNumVariations) {
ScaledFontFreeType::InstanceData instanceData(aOptions, aPlatformOptions);
return CreateScaledFont(aGlyphSize, reinterpret_cast<uint8_t*>(&instanceData),
sizeof(instanceData), aVariations, aNumVariations);
}
bool ScaledFontFreeType::HasVariationSettings() {
// Check if the FT face has been cloned.
return mFace &&
@ -179,17 +135,5 @@ bool ScaledFontFreeType::HasVariationSettings() {
static_cast<UnscaledFontFreeType*>(mUnscaledFont.get())->GetFace();
}
already_AddRefed<UnscaledFont> UnscaledFontFreeType::CreateFromFontDescriptor(
const uint8_t* aData, uint32_t aDataLength, uint32_t aIndex) {
if (aDataLength == 0) {
gfxWarning() << "FreeType font descriptor is truncated.";
return nullptr;
}
const char* path = reinterpret_cast<const char*>(aData);
RefPtr<UnscaledFont> unscaledFont =
new UnscaledFontFreeType(std::string(path, aDataLength), aIndex);
return unscaledFont.forget();
}
} // namespace gfx
} // namespace mozilla

Просмотреть файл

@ -179,4 +179,64 @@ void UnscaledFontFreeType::ApplyVariationsToFace(
}
}
#ifdef MOZ_WIDGET_ANDROID
already_AddRefed<ScaledFont> UnscaledFontFreeType::CreateScaledFont(
Float aGlyphSize, const uint8_t* aInstanceData,
uint32_t aInstanceDataLength, const FontVariation* aVariations,
uint32_t aNumVariations) {
if (aInstanceDataLength < sizeof(ScaledFontFreeType::InstanceData)) {
gfxWarning() << "FreeType scaled font instance data is truncated.";
return nullptr;
}
const ScaledFontFreeType::InstanceData& instanceData =
*reinterpret_cast<const ScaledFontFreeType::InstanceData*>(aInstanceData);
RefPtr<SharedFTFace> face(InitFace());
if (!face) {
gfxWarning() << "Attempted to deserialize FreeType scaled font without "
"FreeType face";
return nullptr;
}
if (aNumVariations > 0 && face->GetData()) {
if (RefPtr<SharedFTFace> varFace = face->GetData()->CloneFace()) {
face = varFace;
}
}
// Only apply variations if we have an explicitly cloned face.
if (aNumVariations > 0 && face != GetFace()) {
ApplyVariationsToFace(aVariations, aNumVariations, face->GetFace());
}
RefPtr<ScaledFontFreeType> scaledFont = new ScaledFontFreeType(
std::move(face), this, aGlyphSize, instanceData.mApplySyntheticBold);
return scaledFont.forget();
}
already_AddRefed<ScaledFont> UnscaledFontFreeType::CreateScaledFontFromWRFont(
Float aGlyphSize, const wr::FontInstanceOptions* aOptions,
const wr::FontInstancePlatformOptions* aPlatformOptions,
const FontVariation* aVariations, uint32_t aNumVariations) {
ScaledFontFreeType::InstanceData instanceData(aOptions, aPlatformOptions);
return CreateScaledFont(aGlyphSize, reinterpret_cast<uint8_t*>(&instanceData),
sizeof(instanceData), aVariations, aNumVariations);
}
already_AddRefed<UnscaledFont> UnscaledFontFreeType::CreateFromFontDescriptor(
const uint8_t* aData, uint32_t aDataLength, uint32_t aIndex) {
if (aDataLength == 0) {
gfxWarning() << "FreeType font descriptor is truncated.";
return nullptr;
}
const char* path = reinterpret_cast<const char*>(aData);
RefPtr<UnscaledFont> unscaledFont =
new UnscaledFontFreeType(std::string(path, aDataLength), aIndex);
return unscaledFont.forget();
}
#endif // MOZ_WIDGET_ANDROID
} // namespace mozilla::gfx

Просмотреть файл

@ -822,15 +822,3 @@ void gfxFT2FontBase::SetupVarCoords(
#endif
}
}
already_AddRefed<SharedFTFace> FTUserFontData::CloneFace(int aFaceIndex) {
RefPtr<SharedFTFace> face = Factory::NewSharedFTFaceFromData(
nullptr, mFontData, mLength, aFaceIndex, this);
if (!face ||
(FT_Select_Charmap(face->GetFace(), FT_ENCODING_UNICODE) != FT_Err_Ok &&
FT_Select_Charmap(face->GetFace(), FT_ENCODING_MS_SYMBOL) !=
FT_Err_Ok)) {
return nullptr;
}
return face.forget();
}

Просмотреть файл

@ -150,35 +150,4 @@ class gfxFT2FontBase : public gfxFont {
mGlyphMetrics MOZ_GUARDED_BY(mLock);
};
// Helper classes used for clearing out user font data when FT font
// face is destroyed. Since multiple faces may use the same data, be
// careful to assure that the data is only cleared out when all uses
// expire. The font entry object contains a refptr to FTUserFontData and
// each FT face created from that font entry contains a refptr to that
// same FTUserFontData object.
class FTUserFontData final
: public mozilla::gfx::SharedFTFaceRefCountedData<FTUserFontData> {
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(FTUserFontData)
FTUserFontData(const uint8_t* aData, uint32_t aLength)
: mFontData(aData), mLength(aLength) {}
const uint8_t* FontData() const { return mFontData; }
already_AddRefed<mozilla::gfx::SharedFTFace> CloneFace(
int aFaceIndex = 0) override;
private:
~FTUserFontData() {
if (mFontData) {
free((void*)mFontData);
}
}
const uint8_t* mFontData;
uint32_t mLength;
};
#endif /* GFX_FT2FONTBASE_H */

Просмотреть файл

@ -114,7 +114,8 @@ already_AddRefed<SharedFTFace> FT2FontEntry::GetFTFace(bool aCommit) {
}
}
} else {
face = Factory::NewSharedFTFace(nullptr, mFilename.get(), mFTFontIndex);
RefPtr<FTUserFontData> fd = new FTUserFontData(mFilename.get());
face = fd->CloneFace(mFTFontIndex);
if (!face) {
NS_WARNING("failed to create freetype face");
return nullptr;

Просмотреть файл

@ -15,18 +15,21 @@ namespace mozilla {
namespace dom {
class SystemFontListEntry;
};
namespace gfx {
class FTUserFontData;
};
}; // namespace mozilla
class FontNameCache;
typedef struct FT_FaceRec_* FT_Face;
class nsZipArchive;
class WillShutdownObserver;
class FTUserFontData;
class FT2FontEntry final : public gfxFT2FontEntryBase {
friend class gfxFT2FontList;
using FontListEntry = mozilla::dom::SystemFontListEntry;
using FTUserFontData = mozilla::gfx::FTUserFontData;
public:
explicit FT2FontEntry(const nsACString& aFaceName)

Просмотреть файл

@ -503,7 +503,9 @@ bool gfxFontconfigFontEntry::TestCharacterMap(uint32_t aCh) {
bool gfxFontconfigFontEntry::HasFontTable(uint32_t aTableTag) {
if (FTUserFontData* ufd = GetUserFontData()) {
return !!gfxFontUtils::FindTableDirEntry(ufd->FontData(), aTableTag);
if (ufd->FontData()) {
return !!gfxFontUtils::FindTableDirEntry(ufd->FontData(), aTableTag);
}
}
return gfxFT2FontEntryBase::FaceHasTable(GetFTFace(), aTableTag);
}
@ -511,7 +513,9 @@ bool gfxFontconfigFontEntry::HasFontTable(uint32_t aTableTag) {
hb_blob_t* gfxFontconfigFontEntry::GetFontTable(uint32_t aTableTag) {
// for data fonts, read directly from the font data
if (FTUserFontData* ufd = GetUserFontData()) {
return gfxFontUtils::GetTableFromFontData(ufd->FontData(), aTableTag);
if (ufd->FontData()) {
return gfxFontUtils::GetTableFromFontData(ufd->FontData(), aTableTag);
}
}
return gfxFontEntry::GetFontTable(aTableTag);

Просмотреть файл

@ -66,6 +66,7 @@ class DefaultDelete<FcObjectSet> {
class gfxFontconfigFontEntry final : public gfxFT2FontEntryBase {
friend class gfxFcPlatformFontList;
using FTUserFontData = mozilla::gfx::FTUserFontData;
public:
// used for system fonts with explicit patterns