From 3cff1c818b7b67540f94c5cc83808d47072dface Mon Sep 17 00:00:00 2001 From: Lee Salzman Date: Wed, 4 Jan 2017 14:01:12 -0500 Subject: [PATCH] Bug 1309205 - part 2 - provide NativeFontResourceFontconfig so that print_via_parent works on Linux. r=jfkthame MozReview-Commit-ID: 94XcLKgwTPq --- gfx/2d/2D.h | 19 +- gfx/2d/Factory.cpp | 23 +- gfx/2d/NativeFontResourceDWrite.cpp | 3 +- gfx/2d/NativeFontResourceDWrite.h | 5 +- gfx/2d/NativeFontResourceFontconfig.cpp | 65 +++++ gfx/2d/NativeFontResourceFontconfig.h | 41 +++ gfx/2d/NativeFontResourceGDI.cpp | 3 +- gfx/2d/NativeFontResourceGDI.h | 5 +- gfx/2d/NativeFontResourceMac.cpp | 3 +- gfx/2d/NativeFontResourceMac.h | 3 +- gfx/2d/RecordedEvent.cpp | 37 +-- gfx/2d/RecordedEvent.h | 28 ++- gfx/2d/ScaledFontFontconfig.cpp | 315 ++++++++++++++++++++++++ gfx/2d/ScaledFontFontconfig.h | 59 ++++- gfx/2d/ScaledFontWin.cpp | 17 ++ gfx/2d/ScaledFontWin.h | 4 + gfx/2d/moz.build | 1 + 17 files changed, 592 insertions(+), 39 deletions(-) create mode 100644 gfx/2d/NativeFontResourceFontconfig.cpp create mode 100644 gfx/2d/NativeFontResourceFontconfig.h diff --git a/gfx/2d/2D.h b/gfx/2d/2D.h index 5848df26fdcc..ee609a25bab4 100644 --- a/gfx/2d/2D.h +++ b/gfx/2d/2D.h @@ -679,8 +679,9 @@ public: MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(ScaledFont) virtual ~ScaledFont() {} - typedef void (*FontFileDataOutput)(const uint8_t *aData, uint32_t aLength, uint32_t aIndex, Float aGlyphSize, void *aBaton); - typedef void (*FontDescriptorOutput)(const uint8_t *aData, uint32_t aLength, Float aFontSize, void *aBaton); + typedef void (*FontFileDataOutput)(const uint8_t* aData, uint32_t aLength, uint32_t aIndex, Float aGlyphSize, void* aBaton); + typedef void (*FontInstanceDataOutput)(const uint8_t* aData, uint32_t aLength, void* aBaton); + typedef void (*FontDescriptorOutput)(const uint8_t* aData, uint32_t aLength, Float aFontSize, void* aBaton); virtual FontType GetType() const = 0; virtual AntialiasMode GetDefaultAAMode() { @@ -711,6 +712,8 @@ public: virtual bool GetFontFileData(FontFileDataOutput, void *) { return false; } + virtual bool GetFontInstanceData(FontInstanceDataOutput, void *) { return false; } + virtual bool GetFontDescriptor(FontDescriptorOutput, void *) { return false; } void AddUserData(UserDataKey *key, void *userData, void (*destroy)(void*)) { @@ -741,10 +744,13 @@ public: * * @param aIndex index for the font within the resource. * @param aGlyphSize the size of ScaledFont required. + * @param aInstanceData pointer to read-only buffer of any available instance data. + * @param aInstanceDataLength the size of the instance data. * @return an already_addrefed ScaledFont, containing nullptr if failed. */ virtual already_AddRefed - CreateScaledFont(uint32_t aIndex, Float aGlyphSize) = 0; + CreateScaledFont(uint32_t aIndex, Float aGlyphSize, + const uint8_t* aInstanceData, uint32_t aInstanceDataLength) = 0; virtual ~NativeFontResource() {}; }; @@ -1398,6 +1404,13 @@ public: static already_AddRefed CreateNativeFontResource(uint8_t *aData, uint32_t aSize, FontType aType); + /** + * This creates a scaled font of the given type based on font descriptor + * data retrieved from ScaledFont::GetFontDescriptor. + */ + static already_AddRefed + CreateScaledFontFromFontDescriptor(FontType aType, const uint8_t* aData, uint32_t aDataLength, Float aSize); + /** * This creates a scaled font with an associated cairo_scaled_font_t, and * must be used when using the Cairo backend. The NativeFont and diff --git a/gfx/2d/Factory.cpp b/gfx/2d/Factory.cpp index 2b01cd08c727..5f8f2c705c79 100644 --- a/gfx/2d/Factory.cpp +++ b/gfx/2d/Factory.cpp @@ -32,6 +32,7 @@ #ifdef MOZ_WIDGET_GTK #include "ScaledFontFontconfig.h" +#include "NativeFontResourceFontconfig.h" #endif #ifdef WIN32 @@ -524,8 +525,10 @@ Factory::CreateNativeFontResource(uint8_t *aData, uint32_t aSize, return NativeFontResourceGDI::Create(aData, aSize, /* aNeedsCairo = */ true); } -#elif XP_DARWIN +#elif defined(XP_DARWIN) return NativeFontResourceMac::Create(aData, aSize); +#elif defined(MOZ_WIDGET_GTK) + return NativeFontResourceFontconfig::Create(aData, aSize); #else gfxWarning() << "Unable to create cairo scaled font from truetype data"; return nullptr; @@ -537,6 +540,24 @@ Factory::CreateNativeFontResource(uint8_t *aData, uint32_t aSize, } } +already_AddRefed +Factory::CreateScaledFontFromFontDescriptor(FontType aType, const uint8_t* aData, uint32_t aDataLength, Float aSize) +{ + switch (aType) { +#ifdef WIN32 + case FontType::GDI: + return ScaledFontWin::CreateFromFontDescriptor(aData, aDataLength, aSize); +#endif +#ifdef MOZ_WIDGET_GTK + case FontType::FONTCONFIG: + return ScaledFontFontconfig::CreateFromFontDescriptor(aData, aDataLength, aSize); +#endif + default: + gfxWarning() << "Invalid type specified for ScaledFont font descriptor"; + return nullptr; + } +} + already_AddRefed Factory::CreateScaledFontWithCairo(const NativeFont& aNativeFont, Float aSize, cairo_scaled_font_t* aScaledFont) { diff --git a/gfx/2d/NativeFontResourceDWrite.cpp b/gfx/2d/NativeFontResourceDWrite.cpp index 6f0893a8a45c..e4d12ad872d1 100644 --- a/gfx/2d/NativeFontResourceDWrite.cpp +++ b/gfx/2d/NativeFontResourceDWrite.cpp @@ -259,7 +259,8 @@ NativeFontResourceDWrite::Create(uint8_t *aFontData, uint32_t aDataLength, } already_AddRefed -NativeFontResourceDWrite::CreateScaledFont(uint32_t aIndex, Float aGlyphSize) +NativeFontResourceDWrite::CreateScaledFont(uint32_t aIndex, Float aGlyphSize, + const uint8_t* aInstanceData, uint32_t aInstanceDataLength) { if (aIndex >= mNumberOfFaces) { gfxWarning() << "Font face index is too high for font resource."; diff --git a/gfx/2d/NativeFontResourceDWrite.h b/gfx/2d/NativeFontResourceDWrite.h index 7b65d5b87807..fc11c7b0dfd2 100644 --- a/gfx/2d/NativeFontResourceDWrite.h +++ b/gfx/2d/NativeFontResourceDWrite.h @@ -32,7 +32,8 @@ public: Create(uint8_t *aFontData, uint32_t aDataLength, bool aNeedsCairo); already_AddRefed - CreateScaledFont(uint32_t aIndex, Float aGlyphSize) final; + CreateScaledFont(uint32_t aIndex, Float aGlyphSize, + const uint8_t* aInstanceData, uint32_t aInstanceDataLength) final; private: NativeFontResourceDWrite(IDWriteFactory *aFactory, @@ -53,4 +54,4 @@ private: } // gfx } // mozilla -#endif // mozilla_gfx_NativeFontResourceDWrite_h \ No newline at end of file +#endif // mozilla_gfx_NativeFontResourceDWrite_h diff --git a/gfx/2d/NativeFontResourceFontconfig.cpp b/gfx/2d/NativeFontResourceFontconfig.cpp new file mode 100644 index 000000000000..a205f98fae08 --- /dev/null +++ b/gfx/2d/NativeFontResourceFontconfig.cpp @@ -0,0 +1,65 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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/. */ + +#include "NativeFontResourceFontconfig.h" +#include "ScaledFontFontconfig.h" +#include "Logging.h" + +namespace mozilla { +namespace gfx { + +NativeFontResourceFontconfig::NativeFontResourceFontconfig(UniquePtr&& aFontData, FT_Face aFace) + : mFontData(Move(aFontData)), + mFace(aFace) +{ +} + +NativeFontResourceFontconfig::~NativeFontResourceFontconfig() +{ + if (mFace) { + FT_Done_Face(mFace); + mFace = nullptr; + } +} + +already_AddRefed +NativeFontResourceFontconfig::Create(uint8_t *aFontData, uint32_t aDataLength) +{ + if (!aFontData || !aDataLength) { + return nullptr; + } + UniquePtr fontData(new uint8_t[aDataLength]); + memcpy(fontData.get(), aFontData, aDataLength); + + FT_Face face; + if (FT_New_Memory_Face(Factory::GetFTLibrary(), fontData.get(), aDataLength, 0, &face) != FT_Err_Ok) { + return nullptr; + } + if (FT_Select_Charmap(face, FT_ENCODING_UNICODE) != FT_Err_Ok) { + FT_Done_Face(face); + return nullptr; + } + + RefPtr resource = + new NativeFontResourceFontconfig(Move(fontData), face); + return resource.forget(); +} + +already_AddRefed +NativeFontResourceFontconfig::CreateScaledFont(uint32_t aIndex, Float aGlyphSize, + const uint8_t* aInstanceData, uint32_t aInstanceDataLength) +{ + if (aInstanceDataLength < sizeof(ScaledFontFontconfig::InstanceData)) { + gfxWarning() << "Fontconfig scaled font instance data is truncated."; + return nullptr; + } + return ScaledFontFontconfig::CreateFromInstanceData( + *reinterpret_cast(aInstanceData), + mFace, nullptr, 0, aGlyphSize); +} + +} // gfx +} // mozilla diff --git a/gfx/2d/NativeFontResourceFontconfig.h b/gfx/2d/NativeFontResourceFontconfig.h new file mode 100644 index 000000000000..e2c386198896 --- /dev/null +++ b/gfx/2d/NativeFontResourceFontconfig.h @@ -0,0 +1,41 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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/. */ + +#ifndef mozilla_gfx_NativeFontResourceFontconfig_h +#define mozilla_gfx_NativeFontResourceFontconfig_h + +#include "2D.h" + +#include + +namespace mozilla { +namespace gfx { + +class NativeFontResourceFontconfig final : public NativeFontResource +{ +public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(NativeFontResourceFontconfig) + + static already_AddRefed + Create(uint8_t *aFontData, uint32_t aDataLength); + + already_AddRefed + CreateScaledFont(uint32_t aIndex, Float aGlyphSize, + const uint8_t* aInstanceData, uint32_t aInstanceDataLength) final; + + ~NativeFontResourceFontconfig(); + +private: + NativeFontResourceFontconfig(UniquePtr&& aFontData, FT_Face aFace); + + UniquePtr mFontData; + FT_Face mFace; +}; + +} // gfx +} // mozilla + +#endif // mozilla_gfx_NativeFontResourceFontconfig_h diff --git a/gfx/2d/NativeFontResourceGDI.cpp b/gfx/2d/NativeFontResourceGDI.cpp index 24bb66a56d83..e92ca85d244c 100644 --- a/gfx/2d/NativeFontResourceGDI.cpp +++ b/gfx/2d/NativeFontResourceGDI.cpp @@ -65,7 +65,8 @@ NativeFontResourceGDI::~NativeFontResourceGDI() } already_AddRefed -NativeFontResourceGDI::CreateScaledFont(uint32_t aIndex, Float aGlyphSize) +NativeFontResourceGDI::CreateScaledFont(uint32_t aIndex, Float aGlyphSize, + const uint8_t* aInstanceData, uint32_t aInstanceDataLength) { if (aIndex >= mFontNames.length()) { gfxWarning() << "Font index is too high for font resource."; diff --git a/gfx/2d/NativeFontResourceGDI.h b/gfx/2d/NativeFontResourceGDI.h index e7fb5dcdbbda..96d045e14446 100644 --- a/gfx/2d/NativeFontResourceGDI.h +++ b/gfx/2d/NativeFontResourceGDI.h @@ -36,7 +36,8 @@ public: ~NativeFontResourceGDI(); already_AddRefed - CreateScaledFont(uint32_t aIndex, Float aGlyphSize) final; + CreateScaledFont(uint32_t aIndex, Float aGlyphSize, + const uint8_t* aInstanceData, uint32_t aInstanceDataLength) final; private: NativeFontResourceGDI(HANDLE aFontResourceHandle, @@ -54,4 +55,4 @@ private: } // gfx } // mozilla -#endif // mozilla_gfx_NativeFontResourceGDI_h \ No newline at end of file +#endif // mozilla_gfx_NativeFontResourceGDI_h diff --git a/gfx/2d/NativeFontResourceMac.cpp b/gfx/2d/NativeFontResourceMac.cpp index 09ef31c41487..aaf6db181309 100644 --- a/gfx/2d/NativeFontResourceMac.cpp +++ b/gfx/2d/NativeFontResourceMac.cpp @@ -50,7 +50,8 @@ NativeFontResourceMac::Create(uint8_t *aFontData, uint32_t aDataLength) } already_AddRefed -NativeFontResourceMac::CreateScaledFont(uint32_t aIndex, Float aGlyphSize) +NativeFontResourceMac::CreateScaledFont(uint32_t aIndex, Float aGlyphSize, + const uint8_t* aInstanceData, uint32_t aInstanceDataLength) { RefPtr scaledFont = new ScaledFontMac(mFontRef, aGlyphSize); diff --git a/gfx/2d/NativeFontResourceMac.h b/gfx/2d/NativeFontResourceMac.h index 3f51e3297cda..47ca92e68f50 100644 --- a/gfx/2d/NativeFontResourceMac.h +++ b/gfx/2d/NativeFontResourceMac.h @@ -23,7 +23,8 @@ public: Create(uint8_t *aFontData, uint32_t aDataLength); already_AddRefed - CreateScaledFont(uint32_t aIndex, Float aGlyphSize); + CreateScaledFont(uint32_t aIndex, Float aGlyphSize, + const uint8_t* aInstanceData, uint32_t aInstanceDataLength) final; ~NativeFontResourceMac() { diff --git a/gfx/2d/RecordedEvent.cpp b/gfx/2d/RecordedEvent.cpp index d929669b838c..d298572df59c 100644 --- a/gfx/2d/RecordedEvent.cpp +++ b/gfx/2d/RecordedEvent.cpp @@ -1586,18 +1586,13 @@ RecordedFontDescriptor::~RecordedFontDescriptor() bool RecordedFontDescriptor::PlayEvent(Translator *aTranslator) const { - MOZ_ASSERT(mType == FontType::GDI); - - NativeFont nativeFont; - nativeFont.mType = (NativeFontType)mType; - nativeFont.mFont = (void*)&mData[0]; - RefPtr font = - Factory::CreateScaledFontForNativeFont(nativeFont, mFontSize); - -#ifdef USE_CAIRO_SCALED_FONT - static_cast(font.get())->PopulateCairoScaledFont(); -#endif + Factory::CreateScaledFontFromFontDescriptor(mType, mData.data(), mData.size(), mFontSize); + if (!font) { + gfxDevCrash(LogReason::InvalidFont) << + "Failed creating ScaledFont of type " << int(mType) << " from font descriptor"; + return false; + } aTranslator->AddScaledFont(mRefPtr, font); return true; @@ -1611,7 +1606,7 @@ RecordedFontDescriptor::RecordToStream(std::ostream &aStream) const WriteElement(aStream, mFontSize); WriteElement(aStream, mRefPtr); WriteElement(aStream, (size_t)mData.size()); - aStream.write((char*)&mData[0], mData.size()); + aStream.write((char*)mData.data(), mData.size()); } void @@ -1637,7 +1632,7 @@ RecordedFontDescriptor::RecordedFontDescriptor(istream &aStream) size_t size; ReadElement(aStream, size); mData.resize(size); - aStream.read((char*)&mData[0], size); + aStream.read((char*)mData.data(), size); } bool @@ -1650,7 +1645,8 @@ RecordedScaledFontCreation::PlayEvent(Translator *aTranslator) const return false; } - RefPtr scaledFont = fontResource->CreateScaledFont(mIndex, mGlyphSize); + RefPtr scaledFont = + fontResource->CreateScaledFont(mIndex, mGlyphSize, mInstanceData.data(), mInstanceData.size()); aTranslator->AddScaledFont(mRefPtr, scaledFont); return true; } @@ -1662,6 +1658,8 @@ RecordedScaledFontCreation::RecordToStream(std::ostream &aStream) const WriteElement(aStream, mFontDataKey); WriteElement(aStream, mIndex); WriteElement(aStream, mGlyphSize); + WriteElement(aStream, (size_t)mInstanceData.size()); + aStream.write((char*)mInstanceData.data(), mInstanceData.size()); } void @@ -1670,6 +1668,12 @@ RecordedScaledFontCreation::OutputSimpleEventInfo(stringstream &aStringStream) c aStringStream << "[" << mRefPtr << "] ScaledFont Created"; } +void +RecordedScaledFontCreation::SetFontInstanceData(const uint8_t *aData, uint32_t aSize) +{ + mInstanceData.assign(aData, aData + aSize); +} + RecordedScaledFontCreation::RecordedScaledFontCreation(istream &aStream) : RecordedEvent(SCALEDFONTCREATION) { @@ -1677,6 +1681,11 @@ RecordedScaledFontCreation::RecordedScaledFontCreation(istream &aStream) ReadElement(aStream, mFontDataKey); ReadElement(aStream, mIndex); ReadElement(aStream, mGlyphSize); + + size_t size; + ReadElement(aStream, size); + mInstanceData.resize(size); + aStream.read((char*)mInstanceData.data(), size); } bool diff --git a/gfx/2d/RecordedEvent.h b/gfx/2d/RecordedEvent.h index b6662cb641fd..dcf4d9e36e02 100644 --- a/gfx/2d/RecordedEvent.h +++ b/gfx/2d/RecordedEvent.h @@ -24,7 +24,7 @@ const uint32_t kMagicInt = 0xc001feed; // loss of backwards compatibility. Old streams will not work in a player // using a newer major revision. And new streams will not work in a player // using an older major revision. -const uint16_t kMajorRevision = 5; +const uint16_t kMajorRevision = 6; // A change in minor revision means additions of new events. New streams will // not play in older players. const uint16_t kMinorRevision = 0; @@ -1047,7 +1047,7 @@ private: uint8_t *mData; RecordedFontDetails mFontDetails; - bool mGetFontFileDataSucceeded = false; + bool mGetFontFileDataSucceeded; MOZ_IMPLICIT RecordedFontData(std::istream &aStream); }; @@ -1055,7 +1055,7 @@ private: class RecordedFontDescriptor : public RecordedEvent { public: - static void FontDescCb(const uint8_t *aData, uint32_t aSize, + static void FontDescCb(const uint8_t* aData, uint32_t aSize, Float aFontSize, void* aBaton) { auto recordedFontDesc = static_cast(aBaton); @@ -1100,12 +1100,21 @@ private: class RecordedScaledFontCreation : public RecordedEvent { public: - RecordedScaledFontCreation(ReferencePtr aRefPtr, - RecordedFontDetails aFontDetails) - : RecordedEvent(SCALEDFONTCREATION), mRefPtr(aRefPtr) - , mFontDataKey(aFontDetails.fontDataKey) - , mGlyphSize(aFontDetails.glyphSize) , mIndex(aFontDetails.index) + static void FontInstanceDataProc(const uint8_t* aData, uint32_t aSize, void* aBaton) { + auto recordedScaledFontCreation = static_cast(aBaton); + recordedScaledFontCreation->SetFontInstanceData(aData, aSize); + } + + RecordedScaledFontCreation(ScaledFont* aScaledFont, + RecordedFontDetails aFontDetails) + : RecordedEvent(SCALEDFONTCREATION) + , mRefPtr(aScaledFont) + , mFontDataKey(aFontDetails.fontDataKey) + , mGlyphSize(aFontDetails.glyphSize) + , mIndex(aFontDetails.index) + { + aScaledFont->GetFontInstanceData(FontInstanceDataProc, this); } virtual bool PlayEvent(Translator *aTranslator) const; @@ -1116,6 +1125,8 @@ public: virtual std::string GetName() const { return "ScaledFont Creation"; } virtual ReferencePtr GetObjectRef() const { return mRefPtr; } + void SetFontInstanceData(const uint8_t *aData, uint32_t aSize); + private: friend class RecordedEvent; @@ -1123,6 +1134,7 @@ private: uint64_t mFontDataKey; Float mGlyphSize; uint32_t mIndex; + std::vector mInstanceData; MOZ_IMPLICIT RecordedScaledFontCreation(std::istream &aStream); }; diff --git a/gfx/2d/ScaledFontFontconfig.cpp b/gfx/2d/ScaledFontFontconfig.cpp index d4751f86dac1..0695eebbeaa7 100644 --- a/gfx/2d/ScaledFontFontconfig.cpp +++ b/gfx/2d/ScaledFontFontconfig.cpp @@ -10,6 +10,10 @@ #include "skia/include/ports/SkTypeface_cairo.h" #endif +#include FT_TRUETYPE_TABLES_H + +#include + namespace mozilla { namespace gfx { @@ -43,5 +47,316 @@ SkTypeface* ScaledFontFontconfig::GetSkTypeface() } #endif +bool +ScaledFontFontconfig::GetFontFileData(FontFileDataOutput aDataCallback, void* aBaton) +{ + bool success = false; + // Lock the Cairo scaled font to force it to resolve the Fontconfig pattern to an FT_Face. + if (FT_Face face = cairo_ft_scaled_font_lock_face(GetCairoScaledFont())) { + FT_ULong length = 0; + // Request the SFNT file. This may not always succeed for all font types. + if (FT_Load_Sfnt_Table(face, 0, 0, nullptr, &length) == FT_Err_Ok) { + uint8_t* fontData = new uint8_t[length]; + if (FT_Load_Sfnt_Table(face, 0, 0, fontData, &length) == FT_Err_Ok) { + aDataCallback(fontData, length, 0, mSize, aBaton); + success = true; + } + delete[] fontData; + } + cairo_ft_scaled_font_unlock_face(GetCairoScaledFont()); + } + return success; +} + +ScaledFontFontconfig::InstanceData::InstanceData(cairo_scaled_font_t* aScaledFont, FcPattern* aPattern) + : mFlags(0) + , mHintStyle(FC_HINT_NONE) + , mSubpixelOrder(FC_RGBA_UNKNOWN) + , mLcdFilter(FC_LCD_LEGACY) +{ + // Record relevant Fontconfig properties into instance data. + FcBool autohint; + if (FcPatternGetBool(aPattern, FC_AUTOHINT, 0, &autohint) == FcResultMatch && autohint) { + mFlags |= AUTOHINT; + } + FcBool bitmap; + if (FcPatternGetBool(aPattern, FC_EMBEDDED_BITMAP, 0, &bitmap) == FcResultMatch && bitmap) { + mFlags |= EMBEDDED_BITMAP; + } + FcBool embolden; + if (FcPatternGetBool(aPattern, FC_EMBOLDEN, 0, &embolden) == FcResultMatch && embolden) { + mFlags |= EMBOLDEN; + } + FcBool vertical; + if (FcPatternGetBool(aPattern, FC_VERTICAL_LAYOUT, 0, &vertical) == FcResultMatch && vertical) { + mFlags |= VERTICAL_LAYOUT; + } + + FcBool antialias; + if (FcPatternGetBool(aPattern, FC_ANTIALIAS, 0, &antialias) != FcResultMatch || antialias) { + mFlags |= ANTIALIAS; + + // Only record subpixel order and lcd filtering if antialiasing is enabled. + int rgba; + if (FcPatternGetInteger(aPattern, FC_RGBA, 0, &rgba) == FcResultMatch) { + mSubpixelOrder = rgba; + } + int filter; + if (FcPatternGetInteger(aPattern, FC_LCD_FILTER, 0, &filter) == FcResultMatch) { + mLcdFilter = filter; + } + } + + cairo_font_options_t* fontOptions = cairo_font_options_create(); + cairo_scaled_font_get_font_options(aScaledFont, fontOptions); + // For printer fonts, Cairo hint metrics and hinting will be disabled. + // For other fonts, allow hint metrics and hinting. + if (cairo_font_options_get_hint_metrics(fontOptions) != CAIRO_HINT_METRICS_OFF) { + mFlags |= HINT_METRICS; + + FcBool hinting; + if (FcPatternGetBool(aPattern, FC_HINTING, 0, &hinting) != FcResultMatch || hinting) { + int hintstyle; + if (FcPatternGetInteger(aPattern, FC_HINT_STYLE, 0, &hintstyle) != FcResultMatch) { + hintstyle = FC_HINT_FULL; + } + mHintStyle = hintstyle; + } + } + cairo_font_options_destroy(fontOptions); + + // Some fonts supply an adjusted size or otherwise use the font matrix for italicization. + // Record the scale and the skew to accomodate both of these cases. + cairo_matrix_t fontMatrix; + cairo_scaled_font_get_font_matrix(aScaledFont, &fontMatrix); + mScale = Float(fontMatrix.xx); + mSkew = Float(fontMatrix.xy); +} + +void +ScaledFontFontconfig::InstanceData::SetupPattern(FcPattern* aPattern) const +{ + if (mFlags & AUTOHINT) { + FcPatternAddBool(aPattern, FC_AUTOHINT, FcTrue); + } + if (mFlags & EMBEDDED_BITMAP) { + FcPatternAddBool(aPattern, FC_EMBEDDED_BITMAP, FcTrue); + } + if (mFlags & EMBOLDEN) { + FcPatternAddBool(aPattern, FC_EMBOLDEN, FcTrue); + } + if (mFlags & VERTICAL_LAYOUT) { + FcPatternAddBool(aPattern, FC_VERTICAL_LAYOUT, FcTrue); + } + + if (mFlags & ANTIALIAS) { + FcPatternAddBool(aPattern, FC_ANTIALIAS, FcTrue); + if (mSubpixelOrder != FC_RGBA_UNKNOWN) { + FcPatternAddInteger(aPattern, FC_RGBA, mSubpixelOrder); + } + if (mLcdFilter != FC_LCD_LEGACY) { + FcPatternAddInteger(aPattern, FC_LCD_FILTER, mLcdFilter); + } + } else { + FcPatternAddBool(aPattern, FC_ANTIALIAS, FcFalse); + } + + if (mHintStyle) { + FcPatternAddBool(aPattern, FC_HINTING, FcTrue); + FcPatternAddInteger(aPattern, FC_HINT_STYLE, mHintStyle); + } else { + FcPatternAddBool(aPattern, FC_HINTING, FcFalse); + } +} + +void +ScaledFontFontconfig::InstanceData::SetupFontOptions(cairo_font_options_t* aFontOptions) const +{ + // Try to build a sane initial set of Cairo font options based on the Fontconfig + // pattern. + if (mFlags & HINT_METRICS) { + // For regular (non-printer) fonts, enable hint metrics as well as hinting + // and (possibly subpixel) antialiasing. + cairo_font_options_set_hint_metrics(aFontOptions, CAIRO_HINT_METRICS_ON); + + cairo_hint_style_t hinting; + switch (mHintStyle) { + case FC_HINT_NONE: + hinting = CAIRO_HINT_STYLE_NONE; + break; + case FC_HINT_SLIGHT: + hinting = CAIRO_HINT_STYLE_SLIGHT; + break; + case FC_HINT_MEDIUM: + default: + hinting = CAIRO_HINT_STYLE_MEDIUM; + break; + case FC_HINT_FULL: + hinting = CAIRO_HINT_STYLE_FULL; + break; + } + cairo_font_options_set_hint_style(aFontOptions, hinting); + + if (mFlags & ANTIALIAS) { + cairo_subpixel_order_t subpixel = CAIRO_SUBPIXEL_ORDER_DEFAULT; + switch (mSubpixelOrder) { + case FC_RGBA_RGB: + subpixel = CAIRO_SUBPIXEL_ORDER_RGB; + break; + case FC_RGBA_BGR: + subpixel = CAIRO_SUBPIXEL_ORDER_BGR; + break; + case FC_RGBA_VRGB: + subpixel = CAIRO_SUBPIXEL_ORDER_VRGB; + break; + case FC_RGBA_VBGR: + subpixel = CAIRO_SUBPIXEL_ORDER_VBGR; + break; + default: + break; + } + if (subpixel != CAIRO_SUBPIXEL_ORDER_DEFAULT) { + cairo_font_options_set_antialias(aFontOptions, CAIRO_ANTIALIAS_SUBPIXEL); + cairo_font_options_set_subpixel_order(aFontOptions, subpixel); + } else { + cairo_font_options_set_antialias(aFontOptions, CAIRO_ANTIALIAS_GRAY); + } + } else { + cairo_font_options_set_antialias(aFontOptions, CAIRO_ANTIALIAS_NONE); + } + } else { + // For printer fonts, disable hint metrics and hinting. Don't allow subpixel + // antialiasing. + cairo_font_options_set_hint_metrics(aFontOptions, CAIRO_HINT_METRICS_OFF); + cairo_font_options_set_hint_style(aFontOptions, CAIRO_HINT_STYLE_NONE); + cairo_font_options_set_antialias(aFontOptions, + mFlags & ANTIALIAS ? CAIRO_ANTIALIAS_GRAY : CAIRO_ANTIALIAS_NONE); + } +} + +void +ScaledFontFontconfig::InstanceData::SetupFontMatrix(cairo_matrix_t* aFontMatrix) const +{ + // Build a font matrix that will reproduce a possibly adjusted size + // and any italics/skew. This is just the concatenation of a simple + // scale matrix with a matrix that skews on the X axis. + cairo_matrix_init(aFontMatrix, mScale, 0, mSkew, mScale, 0, 0); +} + +bool +ScaledFontFontconfig::GetFontInstanceData(FontInstanceDataOutput aCb, void* aBaton) +{ + InstanceData instance(GetCairoScaledFont(), mPattern); + + aCb(reinterpret_cast(&instance), sizeof(instance), aBaton); + return true; +} + +bool +ScaledFontFontconfig::GetFontDescriptor(FontDescriptorOutput aCb, void* aBaton) +{ + // Check if the Fontconfig pattern uses a font file and index to specify which + // font to load. If so, record these as a font descriptor along with any instance + // data required to rebuild a scaled font from it. + FcChar8* pathname = nullptr; + if (FcPatternGetString(mPattern, FC_FILE, 0, &pathname) != FcResultMatch) { + return false; + } + int index = 0; + FcPatternGetInteger(mPattern, FC_INDEX, 0, &index); + if (index < 0) { + return false; + } + + size_t pathLength = strlen(reinterpret_cast(pathname)) + 1; + size_t dataLength = sizeof(FontDescriptor) + pathLength; + uint8_t* data = new uint8_t[dataLength]; + FontDescriptor* desc = reinterpret_cast(data); + desc->mPathLength = pathLength; + desc->mIndex = index; + desc->mInstanceData = InstanceData(GetCairoScaledFont(), mPattern); + memcpy(data + sizeof(FontDescriptor), pathname, pathLength); + + aCb(data, dataLength, mSize, aBaton); + return true; +} + +already_AddRefed +ScaledFontFontconfig::CreateFromInstanceData(const InstanceData& aInstanceData, + FT_Face aFace, const char* aPathname, uint32_t aIndex, + Float aSize) + +{ + FcPattern* pattern = FcPatternCreate(); + if (!pattern) { + gfxWarning() << "Failing initializing Fontconfig pattern for scaled font"; + return nullptr; + } + if (aFace) { + FcPatternAddFTFace(pattern, FC_FT_FACE, aFace); + } else { + FcPatternAddString(pattern, FC_FILE, reinterpret_cast(aPathname)); + FcPatternAddInteger(pattern, FC_INDEX, aIndex); + } + FcPatternAddDouble(pattern, FC_PIXEL_SIZE, aSize); + aInstanceData.SetupPattern(pattern); + + cairo_font_face_t* font = cairo_ft_font_face_create_for_pattern(pattern); + if (cairo_font_face_status(font) != CAIRO_STATUS_SUCCESS) { + gfxWarning() << "Failed creating Cairo font face for Fontconfig pattern"; + FcPatternDestroy(pattern); + return nullptr; + } + + cairo_matrix_t sizeMatrix; + aInstanceData.SetupFontMatrix(&sizeMatrix); + + cairo_matrix_t identityMatrix; + cairo_matrix_init_identity(&identityMatrix); + + cairo_font_options_t *fontOptions = cairo_font_options_create(); + aInstanceData.SetupFontOptions(fontOptions); + + cairo_scaled_font_t* cairoScaledFont = + cairo_scaled_font_create(font, &sizeMatrix, &identityMatrix, fontOptions); + + cairo_font_options_destroy(fontOptions); + cairo_font_face_destroy(font); + + if (cairo_scaled_font_status(cairoScaledFont) != CAIRO_STATUS_SUCCESS) { + gfxWarning() << "Failed creating Cairo scaled font for font face"; + FcPatternDestroy(pattern); + return nullptr; + } + + RefPtr scaledFont = + new ScaledFontFontconfig(cairoScaledFont, pattern, aSize); + + FcPatternDestroy(pattern); + + return scaledFont.forget(); +} + +already_AddRefed +ScaledFontFontconfig::CreateFromFontDescriptor(const uint8_t* aData, uint32_t aDataLength, Float aSize) +{ + if (aDataLength < sizeof(FontDescriptor)) { + gfxWarning() << "Fontconfig font descriptor is truncated."; + return nullptr; + } + const FontDescriptor* desc = reinterpret_cast(aData); + if (desc->mPathLength < 1 || + desc->mPathLength > aDataLength - sizeof(FontDescriptor)) { + gfxWarning() << "Pathname in Fontconfig font descriptor has invalid size."; + return nullptr; + } + const char* pathname = reinterpret_cast(aData + sizeof(FontDescriptor)); + if (pathname[desc->mPathLength - 1] != '\0') { + gfxWarning() << "Pathname in Fontconfig font descriptor is not terminated."; + return nullptr; + } + return CreateFromInstanceData(desc->mInstanceData, nullptr, pathname, desc->mIndex, aSize); +} + } // namespace gfx } // namespace mozilla diff --git a/gfx/2d/ScaledFontFontconfig.h b/gfx/2d/ScaledFontFontconfig.h index 4d4e8217dc1f..b24928d9db05 100644 --- a/gfx/2d/ScaledFontFontconfig.h +++ b/gfx/2d/ScaledFontFontconfig.h @@ -8,26 +8,75 @@ #include "ScaledFontBase.h" -#include -#include +#include namespace mozilla { namespace gfx { +class NativeFontResourceFontconfig; + class ScaledFontFontconfig : public ScaledFontBase { public: - MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(ScaledFontFontconfig) + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(ScaledFontFontconfig, override) ScaledFontFontconfig(cairo_scaled_font_t* aScaledFont, FcPattern* aPattern, Float aSize); ~ScaledFontFontconfig(); - virtual FontType GetType() const { return FontType::FONTCONFIG; } + FontType GetType() const override { return FontType::FONTCONFIG; } #ifdef USE_SKIA - virtual SkTypeface* GetSkTypeface(); + SkTypeface* GetSkTypeface() override; #endif + bool GetFontFileData(FontFileDataOutput aDataCallback, void* aBaton) override; + + bool GetFontInstanceData(FontInstanceDataOutput aCb, void* aBaton) override; + + bool GetFontDescriptor(FontDescriptorOutput aCb, void* aBaton) override; + + static already_AddRefed + CreateFromFontDescriptor(const uint8_t* aData, uint32_t aDataLength, Float aSize); + private: + friend class NativeFontResourceFontconfig; + + struct InstanceData + { + enum { + ANTIALIAS = 1 << 0, + AUTOHINT = 1 << 1, + EMBEDDED_BITMAP = 1 << 2, + EMBOLDEN = 1 << 3, + VERTICAL_LAYOUT = 1 << 4, + HINT_METRICS = 1 << 5 + }; + + InstanceData(cairo_scaled_font_t* aScaledFont, FcPattern* aPattern); + + void SetupPattern(FcPattern* aPattern) const; + void SetupFontOptions(cairo_font_options_t* aFontOptions) const; + void SetupFontMatrix(cairo_matrix_t* aFontMatrix) const; + + uint8_t mFlags; + uint8_t mHintStyle; + uint8_t mSubpixelOrder; + uint8_t mLcdFilter; + Float mScale; + Float mSkew; + }; + + struct FontDescriptor + { + uint32_t mPathLength; + uint32_t mIndex; + InstanceData mInstanceData; + }; + + static already_AddRefed + CreateFromInstanceData(const InstanceData& aInstanceData, + FT_Face aFace, const char* aPathname, uint32_t aIndex, + Float aSize); + FcPattern* mPattern; }; diff --git a/gfx/2d/ScaledFontWin.cpp b/gfx/2d/ScaledFontWin.cpp index 8ce370c960b3..d722c443273b 100644 --- a/gfx/2d/ScaledFontWin.cpp +++ b/gfx/2d/ScaledFontWin.cpp @@ -88,6 +88,23 @@ ScaledFontWin::GetFontDescriptor(FontDescriptorOutput aCb, void* aBaton) return true; } +already_AddRefed +ScaledFontWin::CreateFromFontDescriptor(const uint8_t* aData, uint32_t aDataLength, Float aSize) +{ + NativeFont nativeFont; + nativeFont.mType = NativeFontType::GDI_FONT_FACE; + nativeFont.mFont = (void*)aData; + + RefPtr font = + Factory::CreateScaledFontForNativeFont(nativeFont, aSize); + +#ifdef USE_CAIRO_SCALED_FONT + static_cast(font.get())->PopulateCairoScaledFont(); +#endif + + return font.forget(); +} + AntialiasMode ScaledFontWin::GetDefaultAAMode() { diff --git a/gfx/2d/ScaledFontWin.h b/gfx/2d/ScaledFontWin.h index e8f6168a4009..d09db75699e1 100644 --- a/gfx/2d/ScaledFontWin.h +++ b/gfx/2d/ScaledFontWin.h @@ -23,6 +23,10 @@ public: bool GetFontFileData(FontFileDataOutput aDataCallback, void *aBaton) override; virtual bool GetFontDescriptor(FontDescriptorOutput aCb, void* aBaton) override; + + static already_AddRefed + CreateFromFontDescriptor(const uint8_t* aData, uint32_t aDataLength, Float aSize); + virtual AntialiasMode GetDefaultAAMode() override; #ifdef USE_SKIA diff --git a/gfx/2d/moz.build b/gfx/2d/moz.build index 5437ae9cd5bc..8f7c18ade9b1 100644 --- a/gfx/2d/moz.build +++ b/gfx/2d/moz.build @@ -90,6 +90,7 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] != 'windows': if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('gtk2', 'gtk3'): SOURCES += [ + 'NativeFontResourceFontconfig.cpp', 'ScaledFontFontconfig.cpp', ]