mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-03-03 23:30:46 +00:00
Bug 1756468 - Add locking to gfxFont, to allow worker threads to do text shaping. r=lsalzman
We protect the shaped-word cache in each font with a RWLock, so that multiple threads can shape in parallel using cached data; only when a new entry needs to be cached will we need to take a write lock. (To improve clarity, this patch also constifys a bunch of methods that do not mutate the font instance.) Differential Revision: https://phabricator.services.mozilla.com/D141473
This commit is contained in:
parent
68dd7e07df
commit
6bbbf58763
@ -980,7 +980,7 @@ class SharedFTFace : public external::AtomicRefCounted<SharedFTFace> {
|
||||
* If no owner is given, then the user should avoid modifying any state on
|
||||
* the face so as not to invalidate the prior owner's modification.
|
||||
*/
|
||||
bool Lock(void* aOwner = nullptr) CAPABILITY_ACQUIRE(mLock) {
|
||||
bool Lock(const void* aOwner = nullptr) CAPABILITY_ACQUIRE(mLock) {
|
||||
mLock.Lock();
|
||||
return !aOwner || mLastLockOwner.exchange(aOwner) == aOwner;
|
||||
}
|
||||
@ -989,7 +989,7 @@ class SharedFTFace : public external::AtomicRefCounted<SharedFTFace> {
|
||||
/** Should be called when a lock owner is destroyed so that we don't have
|
||||
* a dangling pointer to a destroyed owner.
|
||||
*/
|
||||
void ForgetLockOwner(void* aOwner) {
|
||||
void ForgetLockOwner(const void* aOwner) {
|
||||
if (aOwner) {
|
||||
mLastLockOwner.compareExchange(aOwner, nullptr);
|
||||
}
|
||||
@ -1002,7 +1002,7 @@ class SharedFTFace : public external::AtomicRefCounted<SharedFTFace> {
|
||||
// Remember the last owner of the lock, even after unlocking, to allow users
|
||||
// to avoid reinitializing state on the FT face if the last owner hasn't
|
||||
// changed by the next time it is locked with the same owner.
|
||||
Atomic<void*> mLastLockOwner;
|
||||
Atomic<const void*> mLastLockOwner;
|
||||
};
|
||||
#endif
|
||||
|
||||
|
@ -107,7 +107,12 @@ gfxDWriteFont::gfxDWriteFont(const RefPtr<UnscaledFontDWrite>& aUnscaledFont,
|
||||
ComputeMetrics(anAAOption);
|
||||
}
|
||||
|
||||
gfxDWriteFont::~gfxDWriteFont() { delete mMetrics; }
|
||||
gfxDWriteFont::~gfxDWriteFont() {
|
||||
if (auto* scaledFont = mAzureScaledFontGDI.exchange(nullptr)) {
|
||||
scaledFont->Release();
|
||||
}
|
||||
delete mMetrics;
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool gfxDWriteFont::InitDWriteSupport() {
|
||||
@ -272,17 +277,12 @@ void gfxDWriteFont::UpdateClearTypeVars() {
|
||||
pixelGeometry, renderingModePref);
|
||||
}
|
||||
|
||||
UniquePtr<gfxFont> gfxDWriteFont::CopyWithAntialiasOption(
|
||||
AntialiasOption anAAOption) {
|
||||
gfxFont* gfxDWriteFont::CopyWithAntialiasOption(
|
||||
AntialiasOption anAAOption) const {
|
||||
auto entry = static_cast<gfxDWriteFontEntry*>(mFontEntry.get());
|
||||
RefPtr<UnscaledFontDWrite> unscaledFont =
|
||||
static_cast<UnscaledFontDWrite*>(mUnscaledFont.get());
|
||||
return MakeUnique<gfxDWriteFont>(unscaledFont, entry, &mStyle, mFontFace,
|
||||
anAAOption);
|
||||
}
|
||||
|
||||
const gfxFont::Metrics& gfxDWriteFont::GetHorizontalMetrics() {
|
||||
return *mMetrics;
|
||||
return new gfxDWriteFont(unscaledFont, entry, &mStyle, mFontFace, anAAOption);
|
||||
}
|
||||
|
||||
bool gfxDWriteFont::GetFakeMetricsForArialBlack(
|
||||
@ -743,7 +743,7 @@ gfxFloat gfxDWriteFont::MeasureGlyphWidth(uint16_t aGlyph) {
|
||||
}
|
||||
|
||||
bool gfxDWriteFont::GetGlyphBounds(uint16_t aGID, gfxRect* aBounds,
|
||||
bool aTight) {
|
||||
bool aTight) const {
|
||||
DWRITE_GLYPH_METRICS m;
|
||||
HRESULT hr = mFontFace->GetDesignGlyphMetrics(&aGID, 1, &m, FALSE);
|
||||
if (FAILED(hr)) {
|
||||
@ -780,32 +780,50 @@ void gfxDWriteFont::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
|
||||
|
||||
already_AddRefed<ScaledFont> gfxDWriteFont::GetScaledFont(
|
||||
const TextRunDrawParams& aRunParams) {
|
||||
if (mAzureScaledFontUsedClearType != UsingClearType()) {
|
||||
mAzureScaledFont = nullptr;
|
||||
mAzureScaledFontGDI = nullptr;
|
||||
bool useClearType = UsingClearType();
|
||||
if (mAzureScaledFontUsedClearType != useClearType) {
|
||||
if (auto* oldScaledFont = mAzureScaledFont.exchange(nullptr)) {
|
||||
oldScaledFont->Release();
|
||||
}
|
||||
if (auto* oldScaledFont = mAzureScaledFontGDI.exchange(nullptr)) {
|
||||
oldScaledFont->Release();
|
||||
}
|
||||
}
|
||||
bool forceGDI = aRunParams.allowGDI && GetForceGDIClassic();
|
||||
RefPtr<ScaledFont>& azureScaledFont =
|
||||
forceGDI ? mAzureScaledFontGDI : mAzureScaledFont;
|
||||
if (!azureScaledFont) {
|
||||
gfxDWriteFontEntry* fe = static_cast<gfxDWriteFontEntry*>(mFontEntry.get());
|
||||
bool useEmbeddedBitmap =
|
||||
(gfxVars::SystemTextRenderingMode() == DWRITE_RENDERING_MODE_DEFAULT ||
|
||||
forceGDI) &&
|
||||
fe->IsCJKFont() && HasBitmapStrikeForSize(NS_lround(mAdjustedSize));
|
||||
|
||||
const gfxFontStyle* fontStyle = GetStyle();
|
||||
azureScaledFont = Factory::CreateScaledFontForDWriteFont(
|
||||
mFontFace, fontStyle, GetUnscaledFont(), GetAdjustedSize(),
|
||||
useEmbeddedBitmap, ApplySyntheticBold(), forceGDI);
|
||||
if (!azureScaledFont) {
|
||||
return nullptr;
|
||||
}
|
||||
InitializeScaledFont(azureScaledFont);
|
||||
mAzureScaledFontUsedClearType = UsingClearType();
|
||||
ScaledFont* scaledFont = forceGDI ? mAzureScaledFontGDI : mAzureScaledFont;
|
||||
if (scaledFont) {
|
||||
return do_AddRef(scaledFont);
|
||||
}
|
||||
|
||||
return do_AddRef(azureScaledFont);
|
||||
gfxDWriteFontEntry* fe = static_cast<gfxDWriteFontEntry*>(mFontEntry.get());
|
||||
bool useEmbeddedBitmap =
|
||||
(gfxVars::SystemTextRenderingMode() == DWRITE_RENDERING_MODE_DEFAULT ||
|
||||
forceGDI) &&
|
||||
fe->IsCJKFont() && HasBitmapStrikeForSize(NS_lround(mAdjustedSize));
|
||||
|
||||
const gfxFontStyle* fontStyle = GetStyle();
|
||||
RefPtr<ScaledFont> newScaledFont = Factory::CreateScaledFontForDWriteFont(
|
||||
mFontFace, fontStyle, GetUnscaledFont(), GetAdjustedSize(),
|
||||
useEmbeddedBitmap, ApplySyntheticBold(), forceGDI);
|
||||
if (!newScaledFont) {
|
||||
return nullptr;
|
||||
}
|
||||
InitializeScaledFont(newScaledFont);
|
||||
|
||||
if (forceGDI) {
|
||||
if (mAzureScaledFontGDI.compareExchange(nullptr, newScaledFont.get())) {
|
||||
Unused << newScaledFont.forget();
|
||||
mAzureScaledFontUsedClearType = useClearType;
|
||||
}
|
||||
scaledFont = mAzureScaledFontGDI;
|
||||
} else {
|
||||
if (mAzureScaledFont.compareExchange(nullptr, newScaledFont.get())) {
|
||||
Unused << newScaledFont.forget();
|
||||
mAzureScaledFontUsedClearType = useClearType;
|
||||
}
|
||||
scaledFont = mAzureScaledFont;
|
||||
}
|
||||
return do_AddRef(scaledFont);
|
||||
}
|
||||
|
||||
bool gfxDWriteFont::ShouldRoundXOffset(cairo_t* aCairo) const {
|
||||
|
@ -39,10 +39,9 @@ class gfxDWriteFont final : public gfxFont {
|
||||
|
||||
static void SystemTextQualityChanged();
|
||||
|
||||
mozilla::UniquePtr<gfxFont> CopyWithAntialiasOption(
|
||||
AntialiasOption anAAOption) override;
|
||||
gfxFont* CopyWithAntialiasOption(AntialiasOption anAAOption) const override;
|
||||
|
||||
bool AllowSubpixelAA() override { return mAllowManualShowGlyphs; }
|
||||
bool AllowSubpixelAA() const override { return mAllowManualShowGlyphs; }
|
||||
|
||||
bool IsValid() const;
|
||||
|
||||
@ -59,7 +58,8 @@ class gfxDWriteFont final : public gfxFont {
|
||||
|
||||
int32_t GetGlyphWidth(uint16_t aGID) override;
|
||||
|
||||
bool GetGlyphBounds(uint16_t aGID, gfxRect* aBounds, bool aTight) override;
|
||||
bool GetGlyphBounds(uint16_t aGID, gfxRect* aBounds,
|
||||
bool aTight) const override;
|
||||
|
||||
void AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
|
||||
FontCacheSizes* aSizes) const override;
|
||||
@ -74,7 +74,7 @@ class gfxDWriteFont final : public gfxFont {
|
||||
bool ShouldRoundXOffset(cairo_t* aCairo) const override;
|
||||
|
||||
protected:
|
||||
const Metrics& GetHorizontalMetrics() override;
|
||||
const Metrics& GetHorizontalMetrics() const override { return *mMetrics; }
|
||||
|
||||
bool GetFakeMetricsForArialBlack(DWRITE_FONT_METRICS* aFontMetrics);
|
||||
|
||||
@ -102,12 +102,12 @@ class gfxDWriteFont final : public gfxFont {
|
||||
|
||||
// Used to record the sUseClearType setting at the time mAzureScaledFont
|
||||
// was set up, so we can tell if it's stale and needs to be re-created.
|
||||
bool mAzureScaledFontUsedClearType;
|
||||
mozilla::Atomic<bool> mAzureScaledFontUsedClearType;
|
||||
|
||||
// Cache the GDI version of the ScaledFont so that font keys and other
|
||||
// meta-data can remain stable even if there is thrashing between GDI and
|
||||
// non-GDI usage.
|
||||
RefPtr<mozilla::gfx::ScaledFont> mAzureScaledFontGDI;
|
||||
mozilla::Atomic<mozilla::gfx::ScaledFont*> mAzureScaledFontGDI;
|
||||
|
||||
bool UsingClearType() {
|
||||
return mozilla::gfx::gfxVars::SystemTextQuality() == CLEARTYPE_QUALITY;
|
||||
|
@ -41,7 +41,7 @@ gfxFT2FontBase::gfxFT2FontBase(
|
||||
|
||||
gfxFT2FontBase::~gfxFT2FontBase() { mFTFace->ForgetLockOwner(this); }
|
||||
|
||||
FT_Face gfxFT2FontBase::LockFTFace()
|
||||
FT_Face gfxFT2FontBase::LockFTFace() const
|
||||
CAPABILITY_ACQUIRE(mFTFace) NO_THREAD_SAFETY_ANALYSIS {
|
||||
if (!mFTFace->Lock(this)) {
|
||||
FT_Set_Transform(mFTFace->GetFace(), nullptr, nullptr);
|
||||
@ -52,7 +52,7 @@ FT_Face gfxFT2FontBase::LockFTFace()
|
||||
return mFTFace->GetFace();
|
||||
}
|
||||
|
||||
void gfxFT2FontBase::UnlockFTFace()
|
||||
void gfxFT2FontBase::UnlockFTFace() const
|
||||
CAPABILITY_RELEASE(mFTFace) NO_THREAD_SAFETY_ANALYSIS {
|
||||
mFTFace->Unlock();
|
||||
}
|
||||
@ -553,10 +553,6 @@ void gfxFT2FontBase::InitMetrics() {
|
||||
#endif
|
||||
}
|
||||
|
||||
const gfxFont::Metrics& gfxFT2FontBase::GetHorizontalMetrics() {
|
||||
return mMetrics;
|
||||
}
|
||||
|
||||
uint32_t gfxFT2FontBase::GetGlyph(uint32_t unicode,
|
||||
uint32_t variation_selector) {
|
||||
if (variation_selector) {
|
||||
@ -597,7 +593,7 @@ bool gfxFT2FontBase::ShouldRoundXOffset(cairo_t* aCairo) const {
|
||||
gfx_text_subpixel_position_force_enabled_AtStartup()));
|
||||
}
|
||||
|
||||
FT_Vector gfxFT2FontBase::GetEmboldenStrength(FT_Face aFace) {
|
||||
FT_Vector gfxFT2FontBase::GetEmboldenStrength(FT_Face aFace) const {
|
||||
FT_Vector strength = {0, 0};
|
||||
if (!mEmbolden) {
|
||||
return strength;
|
||||
@ -628,7 +624,7 @@ FT_Vector gfxFT2FontBase::GetEmboldenStrength(FT_Face aFace) {
|
||||
}
|
||||
|
||||
bool gfxFT2FontBase::GetFTGlyphExtents(uint16_t aGID, int32_t* aAdvance,
|
||||
IntRect* aBounds) {
|
||||
IntRect* aBounds) const {
|
||||
gfxFT2LockedFace face(this);
|
||||
MOZ_ASSERT(face.get());
|
||||
if (!face.get()) {
|
||||
@ -715,7 +711,7 @@ bool gfxFT2FontBase::GetFTGlyphExtents(uint16_t aGID, int32_t* aAdvance,
|
||||
* FreeType for the glyph extents and initialize the glyph metrics.
|
||||
*/
|
||||
const gfxFT2FontBase::GlyphMetrics& gfxFT2FontBase::GetCachedGlyphMetrics(
|
||||
uint16_t aGID, IntRect* aBounds) {
|
||||
uint16_t aGID, IntRect* aBounds) const {
|
||||
if (!mGlyphMetrics) {
|
||||
mGlyphMetrics =
|
||||
mozilla::MakeUnique<nsTHashMap<nsUint32HashKey, GlyphMetrics>>(128);
|
||||
@ -739,7 +735,7 @@ int32_t gfxFT2FontBase::GetGlyphWidth(uint16_t aGID) {
|
||||
}
|
||||
|
||||
bool gfxFT2FontBase::GetGlyphBounds(uint16_t aGID, gfxRect* aBounds,
|
||||
bool aTight) {
|
||||
bool aTight) const {
|
||||
IntRect bounds;
|
||||
const GlyphMetrics& metrics = GetCachedGlyphMetrics(aGID, &bounds);
|
||||
if (!metrics.HasValidBounds()) {
|
||||
|
@ -51,7 +51,8 @@ class gfxFT2FontBase : public gfxFont {
|
||||
uint32_t variation_selector) override;
|
||||
bool ProvidesGlyphWidths() const override { return true; }
|
||||
int32_t GetGlyphWidth(uint16_t aGID) override;
|
||||
bool GetGlyphBounds(uint16_t aGID, gfxRect* aBounds, bool aTight) override;
|
||||
bool GetGlyphBounds(uint16_t aGID, gfxRect* aBounds,
|
||||
bool aTight) const override;
|
||||
|
||||
FontType GetType() const override { return FONT_TYPE_FT2; }
|
||||
|
||||
@ -61,8 +62,8 @@ class gfxFT2FontBase : public gfxFont {
|
||||
const nsTArray<gfxFontVariation>& aVariations,
|
||||
FT_Face aFTFace);
|
||||
|
||||
FT_Face LockFTFace();
|
||||
void UnlockFTFace();
|
||||
FT_Face LockFTFace() const;
|
||||
void UnlockFTFace() const;
|
||||
|
||||
private:
|
||||
uint32_t GetCharExtents(uint32_t aChar, gfxFloat* aWidth,
|
||||
@ -71,12 +72,12 @@ class gfxFT2FontBase : public gfxFont {
|
||||
// Get advance (and optionally bounds) of a single glyph from FreeType,
|
||||
// and return true, or return false if we failed.
|
||||
bool GetFTGlyphExtents(uint16_t aGID, int32_t* aWidth,
|
||||
mozilla::gfx::IntRect* aBounds = nullptr);
|
||||
mozilla::gfx::IntRect* aBounds = nullptr) const;
|
||||
|
||||
protected:
|
||||
void InitMetrics();
|
||||
const Metrics& GetHorizontalMetrics() override;
|
||||
FT_Vector GetEmboldenStrength(FT_Face aFace);
|
||||
const Metrics& GetHorizontalMetrics() const override { return mMetrics; }
|
||||
FT_Vector GetEmboldenStrength(FT_Face aFace) const;
|
||||
|
||||
RefPtr<mozilla::gfx::SharedFTFace> mFTFace;
|
||||
|
||||
@ -133,9 +134,10 @@ class gfxFT2FontBase : public gfxFont {
|
||||
};
|
||||
|
||||
const GlyphMetrics& GetCachedGlyphMetrics(
|
||||
uint16_t aGID, mozilla::gfx::IntRect* aBounds = nullptr);
|
||||
uint16_t aGID, mozilla::gfx::IntRect* aBounds = nullptr) const;
|
||||
|
||||
mozilla::UniquePtr<nsTHashMap<nsUint32HashKey, GlyphMetrics>> mGlyphMetrics;
|
||||
mutable mozilla::UniquePtr<nsTHashMap<nsUint32HashKey, GlyphMetrics>>
|
||||
mGlyphMetrics;
|
||||
};
|
||||
|
||||
// Helper classes used for clearing out user font data when FT font
|
||||
|
@ -166,15 +166,24 @@ gfxFT2Font::~gfxFT2Font() {}
|
||||
|
||||
already_AddRefed<ScaledFont> gfxFT2Font::GetScaledFont(
|
||||
const TextRunDrawParams& aRunParams) {
|
||||
if (!mAzureScaledFont) {
|
||||
mAzureScaledFont = Factory::CreateScaledFontForFreeTypeFont(
|
||||
GetUnscaledFont(), GetAdjustedSize(), mFTFace,
|
||||
GetStyle()->NeedsSyntheticBold(GetFontEntry()));
|
||||
InitializeScaledFont();
|
||||
if (ScaledFont* scaledFont = mAzureScaledFont) {
|
||||
return do_AddRef(scaledFont);
|
||||
}
|
||||
|
||||
RefPtr<ScaledFont> scaledFont(mAzureScaledFont);
|
||||
return scaledFont.forget();
|
||||
RefPtr<ScaledFont> newScaledFont = Factory::CreateScaledFontForFreeTypeFont(
|
||||
GetUnscaledFont(), GetAdjustedSize(), mFTFace,
|
||||
GetStyle()->NeedsSyntheticBold(GetFontEntry()));
|
||||
if (!newScaledFont) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
InitializeScaledFont(newScaledFont);
|
||||
|
||||
if (mAzureScaledFont.compareExchange(nullptr, newScaledFont.get())) {
|
||||
Unused << newScaledFont.forget();
|
||||
}
|
||||
ScaledFont* scaledFont = mAzureScaledFont;
|
||||
return do_AddRef(scaledFont);
|
||||
}
|
||||
|
||||
bool gfxFT2Font::ShouldHintMetrics() const {
|
||||
|
@ -28,7 +28,7 @@ typedef struct FT_FaceRec_* FT_Face;
|
||||
*/
|
||||
class MOZ_STACK_CLASS gfxFT2LockedFace {
|
||||
public:
|
||||
explicit gfxFT2LockedFace(gfxFT2FontBase* aFont)
|
||||
explicit gfxFT2LockedFace(const gfxFT2FontBase* aFont)
|
||||
: mGfxFont(aFont), mFace(aFont->LockFTFace()) {}
|
||||
~gfxFT2LockedFace() {
|
||||
if (mFace) {
|
||||
@ -54,7 +54,7 @@ class MOZ_STACK_CLASS gfxFT2LockedFace {
|
||||
FT_ULong variantSelector);
|
||||
CharVariantFunction FindCharVariantFunction();
|
||||
|
||||
gfxFT2FontBase* MOZ_NON_OWNING_REF mGfxFont; // owned by caller
|
||||
const gfxFT2FontBase* MOZ_NON_OWNING_REF mGfxFont; // owned by caller
|
||||
FT_Face mFace;
|
||||
};
|
||||
|
||||
|
@ -1272,14 +1272,23 @@ gfxFontconfigFont::~gfxFontconfigFont() = default;
|
||||
|
||||
already_AddRefed<ScaledFont> gfxFontconfigFont::GetScaledFont(
|
||||
const TextRunDrawParams& aRunParams) {
|
||||
if (!mAzureScaledFont) {
|
||||
mAzureScaledFont = Factory::CreateScaledFontForFontconfigFont(
|
||||
GetUnscaledFont(), GetAdjustedSize(), mFTFace, GetPattern());
|
||||
InitializeScaledFont();
|
||||
if (ScaledFont* scaledFont = mAzureScaledFont) {
|
||||
return do_AddRef(scaledFont);
|
||||
}
|
||||
|
||||
RefPtr<ScaledFont> scaledFont(mAzureScaledFont);
|
||||
return scaledFont.forget();
|
||||
RefPtr<ScaledFont> newScaledFont = Factory::CreateScaledFontForFontconfigFont(
|
||||
GetUnscaledFont(), GetAdjustedSize(), mFTFace, GetPattern());
|
||||
if (!newScaledFont) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
InitializeScaledFont(newScaledFont);
|
||||
|
||||
if (mAzureScaledFont.compareExchange(nullptr, newScaledFont.get())) {
|
||||
Unused << newScaledFont.forget();
|
||||
}
|
||||
ScaledFont* scaledFont = mAzureScaledFont;
|
||||
return do_AddRef(scaledFont);
|
||||
}
|
||||
|
||||
bool gfxFontconfigFont::ShouldHintMetrics() const {
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "mozilla/intl/Segmenter.h"
|
||||
#include "mozilla/MathAlgorithms.h"
|
||||
#include "mozilla/StaticPrefs_gfx.h"
|
||||
#include "mozilla/ScopeExit.h"
|
||||
#include "mozilla/SVGContextPaint.h"
|
||||
|
||||
#include "mozilla/Logging.h"
|
||||
@ -844,6 +845,7 @@ gfxFont::gfxFont(const RefPtr<UnscaledFont>& aUnscaledFont,
|
||||
gfxFontEntry* aFontEntry, const gfxFontStyle* aFontStyle,
|
||||
AntialiasOption anAAOption)
|
||||
: mFontEntry(aFontEntry),
|
||||
mLock("gfxFont lock"),
|
||||
mUnscaledFont(aUnscaledFont),
|
||||
mStyle(*aFontStyle),
|
||||
mAdjustedSize(-1.0), // negative to indicate "not yet initialized"
|
||||
@ -873,6 +875,23 @@ gfxFont::gfxFont(const RefPtr<UnscaledFont>& aUnscaledFont,
|
||||
gfxFont::~gfxFont() {
|
||||
mFontEntry->NotifyFontDestroyed(this);
|
||||
|
||||
// Delete objects owned through atomic pointers. (Some of these may be null,
|
||||
// but that's OK.)
|
||||
auto* verticalMetrics = mVerticalMetrics.exchange(nullptr);
|
||||
delete verticalMetrics;
|
||||
auto* hbShaper = mHarfBuzzShaper.exchange(nullptr);
|
||||
delete hbShaper;
|
||||
auto* grShaper = mGraphiteShaper.exchange(nullptr);
|
||||
delete grShaper;
|
||||
auto* mathTable = mMathTable.exchange(nullptr);
|
||||
delete mathTable;
|
||||
auto* nonAAfont = mNonAAFont.exchange(nullptr);
|
||||
delete nonAAfont;
|
||||
|
||||
if (auto* scaledFont = mAzureScaledFont.exchange(nullptr)) {
|
||||
scaledFont->Release();
|
||||
}
|
||||
|
||||
if (mGlyphChangeObservers) {
|
||||
for (const auto& key : *mGlyphChangeObservers) {
|
||||
key->ForgetFont();
|
||||
@ -927,26 +946,37 @@ gfxFont::RoundingFlags gfxFont::GetRoundOffsetsToPixels(
|
||||
}
|
||||
}
|
||||
|
||||
gfxHarfBuzzShaper* gfxFont::GetHarfBuzzShaper() {
|
||||
if (!mHarfBuzzShaper) {
|
||||
auto* shaper = new gfxHarfBuzzShaper(this);
|
||||
shaper->Initialize();
|
||||
if (!mHarfBuzzShaper.compareExchange(nullptr, shaper)) {
|
||||
delete shaper;
|
||||
}
|
||||
}
|
||||
gfxHarfBuzzShaper* shaper = mHarfBuzzShaper;
|
||||
return shaper->IsInitialized() ? shaper : nullptr;
|
||||
}
|
||||
|
||||
gfxFloat gfxFont::GetGlyphAdvance(uint16_t aGID, bool aVertical) {
|
||||
if (!aVertical && ProvidesGlyphWidths()) {
|
||||
return GetGlyphWidth(aGID) / 65536.0;
|
||||
}
|
||||
if (mFUnitsConvFactor < 0.0f) {
|
||||
GetMetrics(nsFontMetrics::eHorizontal);
|
||||
// Metrics haven't been initialized; lock while we do that.
|
||||
AutoWriteLock lock(mLock);
|
||||
if (mFUnitsConvFactor < 0.0f) {
|
||||
GetMetrics(nsFontMetrics::eHorizontal);
|
||||
}
|
||||
}
|
||||
NS_ASSERTION(mFUnitsConvFactor >= 0.0f,
|
||||
"missing font unit conversion factor");
|
||||
if (!mHarfBuzzShaper) {
|
||||
mHarfBuzzShaper = MakeUnique<gfxHarfBuzzShaper>(this);
|
||||
if (gfxHarfBuzzShaper* shaper = GetHarfBuzzShaper()) {
|
||||
return (aVertical ? shaper->GetGlyphVAdvance(aGID)
|
||||
: shaper->GetGlyphHAdvance(aGID)) /
|
||||
65536.0;
|
||||
}
|
||||
gfxHarfBuzzShaper* shaper =
|
||||
static_cast<gfxHarfBuzzShaper*>(mHarfBuzzShaper.get());
|
||||
if (!shaper->Initialize()) {
|
||||
return 0;
|
||||
}
|
||||
return (aVertical ? shaper->GetGlyphVAdvance(aGID)
|
||||
: shaper->GetGlyphHAdvance(aGID)) /
|
||||
65536.0;
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
gfxFloat gfxFont::GetCharAdvance(uint32_t aUnicode, bool aVertical) {
|
||||
@ -954,15 +984,9 @@ gfxFloat gfxFont::GetCharAdvance(uint32_t aUnicode, bool aVertical) {
|
||||
if (ProvidesGetGlyph()) {
|
||||
gid = GetGlyph(aUnicode, 0);
|
||||
} else {
|
||||
if (!mHarfBuzzShaper) {
|
||||
mHarfBuzzShaper = MakeUnique<gfxHarfBuzzShaper>(this);
|
||||
if (gfxHarfBuzzShaper* shaper = GetHarfBuzzShaper()) {
|
||||
gid = shaper->GetNominalGlyph(aUnicode);
|
||||
}
|
||||
gfxHarfBuzzShaper* shaper =
|
||||
static_cast<gfxHarfBuzzShaper*>(mHarfBuzzShaper.get());
|
||||
if (!shaper->Initialize()) {
|
||||
return -1.0;
|
||||
}
|
||||
gid = shaper->GetNominalGlyph(aUnicode);
|
||||
}
|
||||
if (!gid) {
|
||||
return -1.0;
|
||||
@ -1177,8 +1201,9 @@ static const hb_tag_t defaultFeatures[] = {
|
||||
HB_TAG('t', 'j', 'm', 'o'), HB_TAG('v', 'a', 't', 'u'),
|
||||
HB_TAG('v', 'e', 'r', 't'), HB_TAG('v', 'j', 'm', 'o')};
|
||||
|
||||
void gfxFont::CheckForFeaturesInvolvingSpace() {
|
||||
mFontEntry->mHasSpaceFeaturesInitialized = true;
|
||||
void gfxFont::CheckForFeaturesInvolvingSpace() const {
|
||||
auto setInitializedFlag =
|
||||
MakeScopeExit([&]() { mFontEntry->mHasSpaceFeaturesInitialized = true; });
|
||||
|
||||
bool log = LOG_FONTINIT_ENABLED();
|
||||
TimeStamp start;
|
||||
@ -1305,7 +1330,7 @@ void gfxFont::CheckForFeaturesInvolvingSpace() {
|
||||
}
|
||||
}
|
||||
|
||||
bool gfxFont::HasSubstitutionRulesWithSpaceLookups(Script aRunScript) {
|
||||
bool gfxFont::HasSubstitutionRulesWithSpaceLookups(Script aRunScript) const {
|
||||
NS_ASSERTION(GetFontEntry()->mHasSpaceFeaturesInitialized,
|
||||
"need to initialize space lookup flags");
|
||||
NS_ASSERTION(aRunScript < Script::NUM_SCRIPT_CODES, "weird script code");
|
||||
@ -1332,7 +1357,8 @@ bool gfxFont::HasSubstitutionRulesWithSpaceLookups(Script aRunScript) {
|
||||
return false;
|
||||
}
|
||||
|
||||
tainted_boolean_hint gfxFont::SpaceMayParticipateInShaping(Script aRunScript) {
|
||||
tainted_boolean_hint gfxFont::SpaceMayParticipateInShaping(
|
||||
Script aRunScript) const {
|
||||
// avoid checking fonts known not to include default space-dependent features
|
||||
if (MOZ_UNLIKELY(mFontEntry->mSkipDefaultFeatureSpaceCheck)) {
|
||||
if (!mKerningSet && mStyle.featureSettings.IsEmpty() &&
|
||||
@ -1468,16 +1494,14 @@ bool gfxFont::SupportsSubSuperscript(uint32_t aSubSuperscript,
|
||||
}
|
||||
|
||||
// xxx - for graphite, don't really know how to sniff lookups so bail
|
||||
if (mGraphiteShaper && gfxPlatform::GetPlatform()->UseGraphiteShaping()) {
|
||||
return true;
|
||||
{
|
||||
if (mGraphiteShaper && gfxPlatform::GetPlatform()->UseGraphiteShaping()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!mHarfBuzzShaper) {
|
||||
mHarfBuzzShaper = MakeUnique<gfxHarfBuzzShaper>(this);
|
||||
}
|
||||
gfxHarfBuzzShaper* shaper =
|
||||
static_cast<gfxHarfBuzzShaper*>(mHarfBuzzShaper.get());
|
||||
if (!shaper->Initialize()) {
|
||||
gfxHarfBuzzShaper* shaper = GetHarfBuzzShaper();
|
||||
if (!shaper) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1521,21 +1545,16 @@ bool gfxFont::FeatureWillHandleChar(Script aRunScript, uint32_t aFeature,
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!mHarfBuzzShaper) {
|
||||
mHarfBuzzShaper = MakeUnique<gfxHarfBuzzShaper>(this);
|
||||
}
|
||||
gfxHarfBuzzShaper* shaper =
|
||||
static_cast<gfxHarfBuzzShaper*>(mHarfBuzzShaper.get());
|
||||
if (!shaper->Initialize()) {
|
||||
return false;
|
||||
if (gfxHarfBuzzShaper* shaper = GetHarfBuzzShaper()) {
|
||||
// get the hbset containing input glyphs for the feature
|
||||
const hb_set_t* inputGlyphs =
|
||||
mFontEntry->InputsForOpenTypeFeature(aRunScript, aFeature);
|
||||
|
||||
hb_codepoint_t gid = shaper->GetNominalGlyph(aUnicode);
|
||||
return hb_set_has(inputGlyphs, gid);
|
||||
}
|
||||
|
||||
// get the hbset containing input glyphs for the feature
|
||||
const hb_set_t* inputGlyphs =
|
||||
mFontEntry->InputsForOpenTypeFeature(aRunScript, aFeature);
|
||||
|
||||
hb_codepoint_t gid = shaper->GetNominalGlyph(aUnicode);
|
||||
return hb_set_has(inputGlyphs, gid);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool gfxFont::HasFeatureSet(uint32_t aFeature, bool& aFeatureOn) {
|
||||
@ -2490,11 +2509,8 @@ bool gfxFont::HasColorGlyphFor(uint32_t aCh, uint32_t aNextCh) {
|
||||
return true;
|
||||
}
|
||||
// Use harfbuzz shaper to look up the default glyph ID for the character.
|
||||
if (!mHarfBuzzShaper) {
|
||||
mHarfBuzzShaper = MakeUnique<gfxHarfBuzzShaper>(this);
|
||||
}
|
||||
auto* shaper = static_cast<gfxHarfBuzzShaper*>(mHarfBuzzShaper.get());
|
||||
if (!shaper->Initialize()) {
|
||||
auto* shaper = GetHarfBuzzShaper();
|
||||
if (!shaper) {
|
||||
return false;
|
||||
}
|
||||
uint32_t gid = 0;
|
||||
@ -2559,15 +2575,22 @@ gfxFont::RunMetrics gfxFont::Measure(const gfxTextRun* aTextRun,
|
||||
// This is only used by MathML layout at present.
|
||||
if (aBoundingBoxType == TIGHT_HINTED_OUTLINE_EXTENTS &&
|
||||
mAntialiasOption != kAntialiasNone) {
|
||||
if (!mNonAAFont) {
|
||||
mNonAAFont = CopyWithAntialiasOption(kAntialiasNone);
|
||||
gfxFont* nonAA = mNonAAFont;
|
||||
if (!nonAA) {
|
||||
nonAA = CopyWithAntialiasOption(kAntialiasNone);
|
||||
if (nonAA) {
|
||||
if (!mNonAAFont.compareExchange(nullptr, nonAA)) {
|
||||
delete nonAA;
|
||||
nonAA = mNonAAFont;
|
||||
}
|
||||
}
|
||||
}
|
||||
// if font subclass doesn't implement CopyWithAntialiasOption(),
|
||||
// it will return null and we'll proceed to use the existing font
|
||||
if (mNonAAFont) {
|
||||
return mNonAAFont->Measure(aTextRun, aStart, aEnd,
|
||||
TIGHT_HINTED_OUTLINE_EXTENTS, aRefDrawTarget,
|
||||
aSpacing, aOrientation);
|
||||
if (nonAA) {
|
||||
return nonAA->Measure(aTextRun, aStart, aEnd,
|
||||
TIGHT_HINTED_OUTLINE_EXTENTS, aRefDrawTarget,
|
||||
aSpacing, aOrientation);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2761,6 +2784,7 @@ gfxFont::RunMetrics gfxFont::Measure(const gfxTextRun* aTextRun,
|
||||
}
|
||||
|
||||
bool gfxFont::AgeCachedWords() {
|
||||
mozilla::AutoWriteLock lock(mLock);
|
||||
if (mWordCache) {
|
||||
for (auto it = mWordCache->Iter(); !it.Done(); it.Next()) {
|
||||
CacheHashEntry* entry = it.Get();
|
||||
@ -2776,7 +2800,8 @@ bool gfxFont::AgeCachedWords() {
|
||||
return true;
|
||||
}
|
||||
|
||||
void gfxFont::NotifyGlyphsChanged() {
|
||||
void gfxFont::NotifyGlyphsChanged() const {
|
||||
AutoReadLock lock(const_cast<gfxFont*>(this)->mLock);
|
||||
uint32_t i, count = mGlyphExtentsArray.Length();
|
||||
for (i = 0; i < count; ++i) {
|
||||
// Flush cached extents array
|
||||
@ -2814,51 +2839,84 @@ gfxShapedWord* gfxFont::GetShapedWord(
|
||||
// if the cache is getting too big, flush it and start over
|
||||
uint32_t wordCacheMaxEntries =
|
||||
gfxPlatform::GetPlatform()->WordCacheMaxEntries();
|
||||
mLock.ReadLock();
|
||||
if (mWordCache->Count() > wordCacheMaxEntries) {
|
||||
// Flush the cache if it is getting overly big.
|
||||
// There's a chance another thread could race with the lock-twiddling here,
|
||||
// but that's OK; it's harmless if we end up calling ClearCacheWords twice
|
||||
// from separate threads. Internally, it will hold the lock exclusively
|
||||
// while doing its thing.
|
||||
mLock.ReadUnlock();
|
||||
NS_WARNING("flushing shaped-word cache");
|
||||
ClearCachedWords();
|
||||
mLock.ReadLock();
|
||||
// Once we've reclaimed a read lock, we can proceed knowing the cache
|
||||
// isn't growing uncontrollably.
|
||||
}
|
||||
|
||||
// if there's a cached entry for this word, just return it
|
||||
CacheHashKey key(aText, aLength, aHash, aRunScript, aLanguage,
|
||||
aAppUnitsPerDevUnit, aFlags, aRounding);
|
||||
|
||||
CacheHashEntry* entry = mWordCache->PutEntry(key, fallible);
|
||||
if (!entry) {
|
||||
NS_WARNING("failed to create word cache entry - expect missing text");
|
||||
return nullptr;
|
||||
}
|
||||
gfxShapedWord* sw = entry->mShapedWord.get();
|
||||
|
||||
if (sw) {
|
||||
CacheHashEntry* entry = mWordCache->GetEntry(key);
|
||||
if (entry) {
|
||||
gfxShapedWord* sw = entry->mShapedWord.get();
|
||||
sw->ResetAge();
|
||||
#ifndef RELEASE_OR_BETA
|
||||
if (aTextPerf) {
|
||||
// XXX we should make sure this is atomic
|
||||
aTextPerf->current.wordCacheHit++;
|
||||
}
|
||||
#endif
|
||||
mLock.ReadUnlock();
|
||||
return sw;
|
||||
}
|
||||
mLock.ReadUnlock();
|
||||
|
||||
#ifndef RELEASE_OR_BETA
|
||||
if (aTextPerf) {
|
||||
aTextPerf->current.wordCacheMiss++;
|
||||
}
|
||||
#endif
|
||||
|
||||
sw = gfxShapedWord::Create(aText, aLength, aRunScript, aLanguage,
|
||||
aAppUnitsPerDevUnit, aFlags, aRounding);
|
||||
entry->mShapedWord.reset(sw);
|
||||
gfxShapedWord* sw =
|
||||
gfxShapedWord::Create(aText, aLength, aRunScript, aLanguage,
|
||||
aAppUnitsPerDevUnit, aFlags, aRounding);
|
||||
if (!sw) {
|
||||
NS_WARNING("failed to create gfxShapedWord - expect missing text");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
DebugOnly<bool> ok = ShapeText(aDrawTarget, aText, 0, aLength, aRunScript,
|
||||
aLanguage, aVertical, aRounding, sw);
|
||||
|
||||
NS_WARNING_ASSERTION(ok, "failed to shape word - expect garbled text");
|
||||
|
||||
{
|
||||
// We're going to cache the new shaped word, so lock for writing.
|
||||
AutoWriteLock lock(mLock);
|
||||
entry = mWordCache->PutEntry(key, fallible);
|
||||
if (!entry) {
|
||||
NS_WARNING("failed to create word cache entry - expect missing text");
|
||||
delete sw;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// It's unlikely, but maybe another thread got there before us...
|
||||
if (entry->mShapedWord) {
|
||||
// Just discard the newly-created word, and use the existing one.
|
||||
delete sw;
|
||||
sw = entry->mShapedWord.get();
|
||||
sw->ResetAge();
|
||||
#ifndef RELEASE_OR_BETA
|
||||
if (aTextPerf) {
|
||||
aTextPerf->current.wordCacheHit++;
|
||||
}
|
||||
#endif
|
||||
return sw;
|
||||
}
|
||||
|
||||
entry->mShapedWord.reset(sw);
|
||||
|
||||
#ifndef RELEASE_OR_BETA
|
||||
if (aTextPerf) {
|
||||
aTextPerf->current.wordCacheMiss++;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
gfxFontCache::GetCache()->RunWordCacheExpirationTimer();
|
||||
|
||||
return sw;
|
||||
@ -2929,13 +2987,18 @@ bool gfxFont::ShapeText(DrawTarget* aDrawTarget, const char16_t* aText,
|
||||
// Vertical graphite support may be wanted as a future enhancement.
|
||||
if (FontCanSupportGraphite() && !aVertical) {
|
||||
if (gfxPlatform::GetPlatform()->UseGraphiteShaping()) {
|
||||
if (!mGraphiteShaper) {
|
||||
mGraphiteShaper = MakeUnique<gfxGraphiteShaper>(this);
|
||||
Telemetry::ScalarAdd(Telemetry::ScalarID::BROWSER_USAGE_GRAPHITE, 1);
|
||||
gfxGraphiteShaper* shaper = mGraphiteShaper;
|
||||
if (!shaper) {
|
||||
shaper = new gfxGraphiteShaper(this);
|
||||
if (mGraphiteShaper.compareExchange(nullptr, shaper)) {
|
||||
Telemetry::ScalarAdd(Telemetry::ScalarID::BROWSER_USAGE_GRAPHITE, 1);
|
||||
} else {
|
||||
delete shaper;
|
||||
shaper = mGraphiteShaper;
|
||||
}
|
||||
}
|
||||
if (mGraphiteShaper->ShapeText(aDrawTarget, aText, aOffset, aLength,
|
||||
aScript, aLanguage, aVertical, aRounding,
|
||||
aShapedText)) {
|
||||
if (shaper->ShapeText(aDrawTarget, aText, aOffset, aLength, aScript,
|
||||
aLanguage, aVertical, aRounding, aShapedText)) {
|
||||
PostShapingFixup(aDrawTarget, aText, aOffset, aLength, aVertical,
|
||||
aShapedText);
|
||||
return true;
|
||||
@ -2943,12 +3006,10 @@ bool gfxFont::ShapeText(DrawTarget* aDrawTarget, const char16_t* aText,
|
||||
}
|
||||
}
|
||||
|
||||
if (!mHarfBuzzShaper) {
|
||||
mHarfBuzzShaper = MakeUnique<gfxHarfBuzzShaper>(this);
|
||||
}
|
||||
if (mHarfBuzzShaper->ShapeText(aDrawTarget, aText, aOffset, aLength, aScript,
|
||||
aLanguage, aVertical, aRounding,
|
||||
aShapedText)) {
|
||||
gfxHarfBuzzShaper* shaper = GetHarfBuzzShaper();
|
||||
if (shaper &&
|
||||
shaper->ShapeText(aDrawTarget, aText, aOffset, aLength, aScript,
|
||||
aLanguage, aVertical, aRounding, aShapedText)) {
|
||||
PostShapingFixup(aDrawTarget, aText, aOffset, aLength, aVertical,
|
||||
aShapedText);
|
||||
if (GetFontEntry()->HasTrackingTable()) {
|
||||
@ -3502,7 +3563,7 @@ bool gfxFont::InitFakeSmallCapsRun(
|
||||
aSyntheticUpper);
|
||||
}
|
||||
|
||||
gfxFont* gfxFont::GetSmallCapsFont() {
|
||||
gfxFont* gfxFont::GetSmallCapsFont() const {
|
||||
gfxFontStyle style(*GetStyle());
|
||||
style.size *= SMALL_CAPS_SCALE_FACTOR;
|
||||
style.variantCaps = NS_FONT_VARIANT_CAPS_NORMAL;
|
||||
@ -3510,7 +3571,7 @@ gfxFont* gfxFont::GetSmallCapsFont() {
|
||||
return fe->FindOrMakeFont(&style, mUnicodeRangeMap);
|
||||
}
|
||||
|
||||
gfxFont* gfxFont::GetSubSuperscriptFont(int32_t aAppUnitsPerDevPixel) {
|
||||
gfxFont* gfxFont::GetSubSuperscriptFont(int32_t aAppUnitsPerDevPixel) const {
|
||||
gfxFontStyle style(*GetStyle());
|
||||
style.AdjustForSubSuperscript(aAppUnitsPerDevPixel);
|
||||
gfxFontEntry* fe = GetFontEntry();
|
||||
@ -3518,6 +3579,16 @@ gfxFont* gfxFont::GetSubSuperscriptFont(int32_t aAppUnitsPerDevPixel) {
|
||||
}
|
||||
|
||||
gfxGlyphExtents* gfxFont::GetOrCreateGlyphExtents(int32_t aAppUnitsPerDevUnit) {
|
||||
{
|
||||
AutoReadLock lock(mLock);
|
||||
uint32_t i, count = mGlyphExtentsArray.Length();
|
||||
for (i = 0; i < count; ++i) {
|
||||
if (mGlyphExtentsArray[i]->GetAppUnitsPerDevUnit() == aAppUnitsPerDevUnit)
|
||||
return mGlyphExtentsArray[i].get();
|
||||
}
|
||||
}
|
||||
AutoWriteLock lock(mLock);
|
||||
// Re-check in case of race.
|
||||
uint32_t i, count = mGlyphExtentsArray.Length();
|
||||
for (i = 0; i < count; ++i) {
|
||||
if (mGlyphExtentsArray[i]->GetAppUnitsPerDevUnit() == aAppUnitsPerDevUnit)
|
||||
@ -3849,8 +3920,7 @@ void gfxFont::CreateVerticalMetrics() {
|
||||
const uint32_t kOS_2TableTag = TRUETYPE_TAG('O', 'S', '/', '2');
|
||||
uint32_t len;
|
||||
|
||||
mVerticalMetrics = MakeUnique<Metrics>();
|
||||
auto* metrics = mVerticalMetrics.get();
|
||||
auto* metrics = new Metrics();
|
||||
::memset(metrics, 0, sizeof(Metrics));
|
||||
|
||||
// Some basic defaults, in case the font lacks any real metrics tables.
|
||||
@ -3997,6 +4067,10 @@ void gfxFont::CreateVerticalMetrics() {
|
||||
metrics->maxHeight = metrics->maxAscent + metrics->maxDescent;
|
||||
metrics->xHeight = metrics->emHeight / 2;
|
||||
metrics->capHeight = metrics->maxAscent;
|
||||
|
||||
if (!mVerticalMetrics.compareExchange(nullptr, metrics)) {
|
||||
delete metrics;
|
||||
}
|
||||
}
|
||||
|
||||
gfxFloat gfxFont::SynthesizeSpaceWidth(uint32_t aCh) {
|
||||
@ -4037,6 +4111,7 @@ gfxFloat gfxFont::SynthesizeSpaceWidth(uint32_t aCh) {
|
||||
|
||||
void gfxFont::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
|
||||
FontCacheSizes* aSizes) const {
|
||||
AutoReadLock lock(const_cast<gfxFont*>(this)->mLock);
|
||||
for (uint32_t i = 0; i < mGlyphExtentsArray.Length(); ++i) {
|
||||
aSizes->mFontInstances +=
|
||||
mGlyphExtentsArray[i]->SizeOfIncludingThis(aMallocSizeOf);
|
||||
@ -4053,6 +4128,7 @@ void gfxFont::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
|
||||
}
|
||||
|
||||
void gfxFont::AddGlyphChangeObserver(GlyphChangeObserver* aObserver) {
|
||||
AutoWriteLock lock(mLock);
|
||||
if (!mGlyphChangeObservers) {
|
||||
mGlyphChangeObservers = MakeUnique<nsTHashSet<GlyphChangeObserver*>>();
|
||||
}
|
||||
@ -4060,6 +4136,7 @@ void gfxFont::AddGlyphChangeObserver(GlyphChangeObserver* aObserver) {
|
||||
}
|
||||
|
||||
void gfxFont::RemoveGlyphChangeObserver(GlyphChangeObserver* aObserver) {
|
||||
AutoWriteLock lock(mLock);
|
||||
NS_ASSERTION(mGlyphChangeObservers, "No observers registered");
|
||||
NS_ASSERTION(mGlyphChangeObservers->Contains(aObserver),
|
||||
"Observer not registered");
|
||||
@ -4199,17 +4276,21 @@ void gfxFontStyle::AdjustForSubSuperscript(int32_t aAppUnitsPerDevPixel) {
|
||||
}
|
||||
|
||||
bool gfxFont::TryGetMathTable() {
|
||||
if (!mMathInitialized) {
|
||||
mMathInitialized = true;
|
||||
|
||||
hb_face_t* face = GetFontEntry()->GetHBFace();
|
||||
if (face) {
|
||||
if (hb_ot_math_has_data(face)) {
|
||||
mMathTable = MakeUnique<gfxMathTable>(face, GetAdjustedSize());
|
||||
}
|
||||
hb_face_destroy(face);
|
||||
}
|
||||
if (mMathInitialized) {
|
||||
return !!mMathTable;
|
||||
}
|
||||
|
||||
hb_face_t* face = GetFontEntry()->GetHBFace();
|
||||
if (face) {
|
||||
if (hb_ot_math_has_data(face)) {
|
||||
auto* mathTable = new gfxMathTable(face, GetAdjustedSize());
|
||||
if (!mMathTable.compareExchange(nullptr, mathTable)) {
|
||||
delete mathTable;
|
||||
}
|
||||
}
|
||||
hb_face_destroy(face);
|
||||
}
|
||||
mMathInitialized = true;
|
||||
|
||||
return !!mMathTable;
|
||||
}
|
||||
|
@ -60,6 +60,8 @@
|
||||
#include "nsMathUtils.h"
|
||||
|
||||
class gfxContext;
|
||||
class gfxGraphiteShaper;
|
||||
class gfxHarfBuzzShaper;
|
||||
class gfxGlyphExtents;
|
||||
class gfxMathTable;
|
||||
class gfxPattern;
|
||||
@ -1417,7 +1419,8 @@ class gfxShapedWord final : public gfxShapedText {
|
||||
|
||||
gfxFontShaper::RoundingFlags mRounding;
|
||||
|
||||
uint32_t mAgeCounter;
|
||||
// With multithreaded shaping, this may be updated by any thread.
|
||||
std::atomic<uint32_t> mAgeCounter;
|
||||
|
||||
// The mCharGlyphsStorage array is actually a variable-size member;
|
||||
// when the ShapedWord is created, its size will be increased as necessary
|
||||
@ -1449,7 +1452,12 @@ class gfxFont {
|
||||
|
||||
nsrefcnt AddRef(void) {
|
||||
MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt");
|
||||
if (mExpirationState.IsTracked()) {
|
||||
nsExpirationState state;
|
||||
{
|
||||
mozilla::AutoReadLock lock(mLock);
|
||||
state = mExpirationState;
|
||||
}
|
||||
if (state.IsTracked()) {
|
||||
gfxFontCache::GetCache()->RemoveObject(this);
|
||||
}
|
||||
++mRefCnt;
|
||||
@ -1460,15 +1468,15 @@ class gfxFont {
|
||||
MOZ_ASSERT(0 != mRefCnt, "dup release");
|
||||
--mRefCnt;
|
||||
NS_LOG_RELEASE(this, mRefCnt, "gfxFont");
|
||||
if (mRefCnt == 0) {
|
||||
nsrefcnt rval = mRefCnt;
|
||||
if (!rval) {
|
||||
NotifyReleased();
|
||||
// |this| may have been deleted.
|
||||
return 0;
|
||||
}
|
||||
return mRefCnt;
|
||||
return rval;
|
||||
}
|
||||
|
||||
int32_t GetRefCount() { return mRefCnt; }
|
||||
int32_t GetRefCount() { return int32_t(mRefCnt); }
|
||||
|
||||
// options to specify the kind of AA to be used when creating a font
|
||||
typedef enum : uint8_t {
|
||||
@ -1479,7 +1487,7 @@ class gfxFont {
|
||||
} AntialiasOption;
|
||||
|
||||
protected:
|
||||
nsAutoRefCnt mRefCnt;
|
||||
mozilla::ThreadSafeAutoRefCnt mRefCnt;
|
||||
|
||||
void NotifyReleased() {
|
||||
gfxFontCache* cache = gfxFontCache::GetCache();
|
||||
@ -1532,8 +1540,7 @@ class gfxFont {
|
||||
const nsCString& GetName() const { return mFontEntry->Name(); }
|
||||
const gfxFontStyle* GetStyle() const { return &mStyle; }
|
||||
|
||||
virtual mozilla::UniquePtr<gfxFont> CopyWithAntialiasOption(
|
||||
AntialiasOption anAAOption) {
|
||||
virtual gfxFont* CopyWithAntialiasOption(AntialiasOption anAAOption) const {
|
||||
// platforms where this actually matters should override
|
||||
return nullptr;
|
||||
}
|
||||
@ -1557,15 +1564,17 @@ class gfxFont {
|
||||
}
|
||||
|
||||
// check whether this is an sfnt we can potentially use with harfbuzz
|
||||
bool FontCanSupportHarfBuzz() { return mFontEntry->HasCmapTable(); }
|
||||
bool FontCanSupportHarfBuzz() const { return mFontEntry->HasCmapTable(); }
|
||||
|
||||
// check whether this is an sfnt we can potentially use with Graphite
|
||||
bool FontCanSupportGraphite() { return mFontEntry->HasGraphiteTables(); }
|
||||
bool FontCanSupportGraphite() const {
|
||||
return mFontEntry->HasGraphiteTables();
|
||||
}
|
||||
|
||||
// Whether this is a font that may be doing full-color rendering,
|
||||
// and therefore needs us to use a mask for text-shadow even when
|
||||
// we're not actually blurring.
|
||||
bool AlwaysNeedsMaskForShadow() {
|
||||
bool AlwaysNeedsMaskForShadow() const {
|
||||
return mFontEntry->TryGetColorGlyphs() || mFontEntry->TryGetSVGData(this) ||
|
||||
mFontEntry->HasFontTable(TRUETYPE_TAG('C', 'B', 'D', 'T')) ||
|
||||
mFontEntry->HasFontTable(TRUETYPE_TAG('s', 'b', 'i', 'x'));
|
||||
@ -1621,6 +1630,10 @@ class gfxFont {
|
||||
virtual bool ShouldHintMetrics() const { return true; }
|
||||
virtual bool ShouldRoundXOffset(cairo_t* aCairo) const { return true; }
|
||||
|
||||
// Return the font's owned harfbuzz shaper, creating and initializing it if
|
||||
// necessary; returns null if shaper initialization has failed.
|
||||
gfxHarfBuzzShaper* GetHarfBuzzShaper();
|
||||
|
||||
// Font metrics
|
||||
struct Metrics {
|
||||
gfxFloat capHeight;
|
||||
@ -1786,14 +1799,14 @@ class gfxFont {
|
||||
nsExpirationState* GetExpirationState() { return &mExpirationState; }
|
||||
|
||||
// Get the glyphID of a space
|
||||
uint16_t GetSpaceGlyph() { return mSpaceGlyph; }
|
||||
uint16_t GetSpaceGlyph() const { return mSpaceGlyph; }
|
||||
|
||||
gfxGlyphExtents* GetOrCreateGlyphExtents(int32_t aAppUnitsPerDevUnit);
|
||||
|
||||
void SetupGlyphExtents(DrawTarget* aDrawTarget, uint32_t aGlyphID,
|
||||
bool aNeedTight, gfxGlyphExtents* aExtents);
|
||||
|
||||
virtual bool AllowSubpixelAA() { return true; }
|
||||
virtual bool AllowSubpixelAA() const { return true; }
|
||||
|
||||
bool ApplySyntheticBold() const { return mApplySyntheticBold; }
|
||||
|
||||
@ -1804,7 +1817,7 @@ class gfxFont {
|
||||
// For size S up to a threshold size T, we use (0.25 + 3S / 4T),
|
||||
// so that the result ranges from 0.25 to 1.0; thereafter,
|
||||
// simply use (S / T).
|
||||
gfxFloat GetSyntheticBoldOffset() {
|
||||
gfxFloat GetSyntheticBoldOffset() const {
|
||||
gfxFloat size = GetAdjustedSize();
|
||||
const gfxFloat threshold = 48.0;
|
||||
return size < threshold ? (0.25 + 0.75 * size / threshold)
|
||||
@ -1812,7 +1825,7 @@ class gfxFont {
|
||||
}
|
||||
|
||||
gfxFontEntry* GetFontEntry() const { return mFontEntry.get(); }
|
||||
bool HasCharacter(uint32_t ch) {
|
||||
bool HasCharacter(uint32_t ch) const {
|
||||
if (!mIsValid || (mUnicodeRangeMap && !mUnicodeRangeMap->test(ch))) {
|
||||
return false;
|
||||
}
|
||||
@ -1827,7 +1840,7 @@ class gfxFont {
|
||||
mUnicodeRangeMap = aUnicodeRangeMap;
|
||||
}
|
||||
|
||||
uint16_t GetUVSGlyph(uint32_t aCh, uint32_t aVS) {
|
||||
uint16_t GetUVSGlyph(uint32_t aCh, uint32_t aVS) const {
|
||||
if (!mIsValid) {
|
||||
return 0;
|
||||
}
|
||||
@ -1867,8 +1880,15 @@ class gfxFont {
|
||||
// Ensure the ShapedWord cache is initialized. This MUST be called before
|
||||
// any attempt to use GetShapedWord().
|
||||
void InitWordCache() {
|
||||
mLock.ReadLock();
|
||||
if (!mWordCache) {
|
||||
mWordCache = mozilla::MakeUnique<nsTHashtable<CacheHashEntry>>();
|
||||
mLock.ReadUnlock();
|
||||
mozilla::AutoWriteLock lock(mLock);
|
||||
if (!mWordCache) {
|
||||
mWordCache = mozilla::MakeUnique<nsTHashtable<CacheHashEntry>>();
|
||||
}
|
||||
} else {
|
||||
mLock.ReadUnlock();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1879,13 +1899,14 @@ class gfxFont {
|
||||
|
||||
// Discard all cached word records; called on memory-pressure notification.
|
||||
void ClearCachedWords() {
|
||||
mozilla::AutoWriteLock lock(mLock);
|
||||
if (mWordCache) {
|
||||
mWordCache->Clear();
|
||||
}
|
||||
}
|
||||
|
||||
// Glyph rendering/geometry has changed, so invalidate data as necessary.
|
||||
void NotifyGlyphsChanged();
|
||||
void NotifyGlyphsChanged() const;
|
||||
|
||||
virtual void AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
|
||||
FontCacheSizes* aSizes) const;
|
||||
@ -1915,12 +1936,11 @@ class gfxFont {
|
||||
|
||||
// gfxFont implementations may cache ScaledFont versions other than the
|
||||
// default, so InitializeScaledFont must support explicitly specifying
|
||||
// other ScaledFonts than the default to initialize.
|
||||
// which ScaledFonts to initialize.
|
||||
void InitializeScaledFont(
|
||||
const RefPtr<mozilla::gfx::ScaledFont>& aScaledFont);
|
||||
void InitializeScaledFont() { InitializeScaledFont(mAzureScaledFont); }
|
||||
|
||||
bool KerningDisabled() { return mKerningSet && !mKerningEnabled; }
|
||||
bool KerningDisabled() const { return mKerningSet && !mKerningEnabled; }
|
||||
|
||||
/**
|
||||
* Subclass this object to be notified of glyph changes. Delete the object
|
||||
@ -1947,7 +1967,7 @@ class gfxFont {
|
||||
};
|
||||
friend class GlyphChangeObserver;
|
||||
|
||||
bool GlyphsMayChange() {
|
||||
bool GlyphsMayChange() const {
|
||||
// Currently only fonts with SVG glyphs can have animated glyphs
|
||||
return mFontEntry->TryGetSVGData(this);
|
||||
}
|
||||
@ -1961,21 +1981,21 @@ class gfxFont {
|
||||
// If (and ONLY if) TryGetMathTable() has returned true, the MathTable()
|
||||
// method may be called to access the gfxMathTable data.
|
||||
bool TryGetMathTable();
|
||||
gfxMathTable* MathTable() {
|
||||
gfxMathTable* MathTable() const {
|
||||
MOZ_RELEASE_ASSERT(mMathTable,
|
||||
"A successful call to TryGetMathTable() must be "
|
||||
"performed before calling this function");
|
||||
return mMathTable.get();
|
||||
return mMathTable;
|
||||
}
|
||||
|
||||
// Return a cloned font resized and offset to simulate sub/superscript
|
||||
// glyphs. This does not add a reference to the returned font.
|
||||
gfxFont* GetSubSuperscriptFont(int32_t aAppUnitsPerDevPixel);
|
||||
gfxFont* GetSubSuperscriptFont(int32_t aAppUnitsPerDevPixel) const;
|
||||
|
||||
bool HasColorGlyphFor(uint32_t aCh, uint32_t aNextCh);
|
||||
|
||||
protected:
|
||||
virtual const Metrics& GetHorizontalMetrics() = 0;
|
||||
virtual const Metrics& GetHorizontalMetrics() const = 0;
|
||||
|
||||
void CreateVerticalMetrics();
|
||||
|
||||
@ -2021,7 +2041,7 @@ class gfxFont {
|
||||
// Return a font that is a "clone" of this one, but reduced to 80% size
|
||||
// (and with variantCaps set to normal). This does not add a reference to
|
||||
// the returned font.
|
||||
gfxFont* GetSmallCapsFont();
|
||||
gfxFont* GetSmallCapsFont() const;
|
||||
|
||||
// subclasses may provide (possibly hinted) glyph widths (in font units);
|
||||
// if they do not override this, harfbuzz will use unhinted widths
|
||||
@ -2033,7 +2053,7 @@ class gfxFont {
|
||||
virtual int32_t GetGlyphWidth(uint16_t aGID) { return -1; }
|
||||
|
||||
virtual bool GetGlyphBounds(uint16_t aGID, gfxRect* aBounds,
|
||||
bool aTight = false) {
|
||||
bool aTight = false) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -2044,13 +2064,13 @@ class gfxFont {
|
||||
void RemoveGlyphChangeObserver(GlyphChangeObserver* aObserver);
|
||||
|
||||
// whether font contains substitution lookups containing spaces
|
||||
bool HasSubstitutionRulesWithSpaceLookups(Script aRunScript);
|
||||
bool HasSubstitutionRulesWithSpaceLookups(Script aRunScript) const;
|
||||
|
||||
// do spaces participate in shaping rules? if so, can't used word cache
|
||||
// Note that this function uses HasGraphiteSpaceContextuals, so it can only
|
||||
// return a "hint" to the correct answer. The calling code must ensure it
|
||||
// performs safe actions independent of the value returned.
|
||||
tainted_boolean_hint SpaceMayParticipateInShaping(Script aRunScript);
|
||||
tainted_boolean_hint SpaceMayParticipateInShaping(Script aRunScript) const;
|
||||
|
||||
// For 8-bit text, expand to 16-bit and then call the following method.
|
||||
bool ShapeText(DrawTarget* aContext, const uint8_t* aText,
|
||||
@ -2100,7 +2120,7 @@ class gfxFont {
|
||||
bool aVertical, RoundingFlags aRounding,
|
||||
gfxTextRun* aTextRun);
|
||||
|
||||
void CheckForFeaturesInvolvingSpace();
|
||||
void CheckForFeaturesInvolvingSpace() const;
|
||||
|
||||
// whether a given feature is included in feature settings from both the
|
||||
// font and the style. aFeatureOn set if resolved feature value is non-zero
|
||||
@ -2111,6 +2131,7 @@ class gfxFont {
|
||||
static nsTHashSet<uint32_t>* sDefaultFeatures;
|
||||
|
||||
RefPtr<gfxFontEntry> mFontEntry;
|
||||
mozilla::RWLock mLock;
|
||||
|
||||
struct CacheHashKey {
|
||||
union {
|
||||
@ -2197,35 +2218,40 @@ class gfxFont {
|
||||
mozilla::UniquePtr<gfxShapedWord> mShapedWord;
|
||||
};
|
||||
|
||||
mozilla::UniquePtr<nsTHashtable<CacheHashEntry>> mWordCache;
|
||||
mozilla::UniquePtr<nsTHashtable<CacheHashEntry>> mWordCache GUARDED_BY(mLock);
|
||||
|
||||
static const uint32_t kShapedWordCacheMaxAge = 3;
|
||||
|
||||
nsTArray<mozilla::UniquePtr<gfxGlyphExtents>> mGlyphExtentsArray;
|
||||
mozilla::UniquePtr<nsTHashSet<GlyphChangeObserver*>> mGlyphChangeObservers;
|
||||
nsTArray<mozilla::UniquePtr<gfxGlyphExtents>> mGlyphExtentsArray
|
||||
GUARDED_BY(mLock);
|
||||
mozilla::UniquePtr<nsTHashSet<GlyphChangeObserver*>> mGlyphChangeObservers
|
||||
GUARDED_BY(mLock);
|
||||
|
||||
// a copy of the font without antialiasing, if needed for separate
|
||||
// measurement by mathml code
|
||||
mozilla::UniquePtr<gfxFont> mNonAAFont;
|
||||
mozilla::Atomic<gfxFont*> mNonAAFont;
|
||||
|
||||
// we create either or both of these shapers when needed, depending
|
||||
// whether the font has graphite tables, and whether graphite shaping
|
||||
// is actually enabled
|
||||
mozilla::UniquePtr<gfxFontShaper> mHarfBuzzShaper;
|
||||
mozilla::UniquePtr<gfxFontShaper> mGraphiteShaper;
|
||||
mozilla::Atomic<gfxHarfBuzzShaper*> mHarfBuzzShaper;
|
||||
mozilla::Atomic<gfxGraphiteShaper*> mGraphiteShaper;
|
||||
|
||||
// if a userfont with unicode-range specified, contains map of *possible*
|
||||
// ranges supported by font
|
||||
// If a userfont with unicode-range specified, contains map of *possible*
|
||||
// ranges supported by font. This is set during user-font initialization,
|
||||
// before the font is available to other threads, and thereafter is inert
|
||||
// so no guard is needed.
|
||||
RefPtr<gfxCharacterMap> mUnicodeRangeMap;
|
||||
|
||||
RefPtr<mozilla::gfx::UnscaledFont> mUnscaledFont;
|
||||
RefPtr<mozilla::gfx::ScaledFont> mAzureScaledFont;
|
||||
RefPtr<mozilla::gfx::UnscaledFont> mUnscaledFont GUARDED_BY(mLock);
|
||||
|
||||
mozilla::Atomic<mozilla::gfx::ScaledFont*> mAzureScaledFont;
|
||||
|
||||
// For vertical metrics, created on demand.
|
||||
mozilla::UniquePtr<Metrics> mVerticalMetrics;
|
||||
mozilla::Atomic<Metrics*> mVerticalMetrics;
|
||||
|
||||
// Table used for MathML layout.
|
||||
mozilla::UniquePtr<gfxMathTable> mMathTable;
|
||||
mozilla::Atomic<gfxMathTable*> mMathTable;
|
||||
|
||||
gfxFontStyle mStyle;
|
||||
mutable gfxFloat mAdjustedSize;
|
||||
@ -2235,7 +2261,7 @@ class gfxFont {
|
||||
// This is OK because we only multiply by this factor, never divide.
|
||||
float mFUnitsConvFactor;
|
||||
|
||||
nsExpirationState mExpirationState;
|
||||
nsExpirationState mExpirationState GUARDED_BY(mLock);
|
||||
|
||||
// Glyph ID of the font's <space> glyph, zero if missing
|
||||
uint16_t mSpaceGlyph = 0;
|
||||
@ -2252,7 +2278,7 @@ class gfxFont {
|
||||
bool mKerningSet; // kerning explicitly set?
|
||||
bool mKerningEnabled; // if set, on or off?
|
||||
|
||||
bool mMathInitialized; // TryGetMathTable() called?
|
||||
mozilla::Atomic<bool> mMathInitialized; // TryGetMathTable() called?
|
||||
|
||||
// Helper for subclasses that want to initialize standard metrics from the
|
||||
// tables of sfnt (TrueType/OpenType) fonts.
|
||||
|
@ -339,7 +339,7 @@ void gfxFontEntry::RenderSVGGlyph(gfxContext* aContext, uint32_t aGlyphId,
|
||||
mSVGGlyphs->RenderGlyph(aContext, aGlyphId, aContextPaint);
|
||||
}
|
||||
|
||||
bool gfxFontEntry::TryGetSVGData(gfxFont* aFont) {
|
||||
bool gfxFontEntry::TryGetSVGData(const gfxFont* aFont) {
|
||||
if (!gfxPlatform::GetPlatform()->OpenTypeSVGEnabled()) {
|
||||
return false;
|
||||
}
|
||||
@ -377,7 +377,7 @@ void gfxFontEntry::NotifyFontDestroyed(gfxFont* aFont) {
|
||||
|
||||
void gfxFontEntry::NotifyGlyphsChanged() {
|
||||
for (uint32_t i = 0, count = mFontsUsingSVGGlyphs.Length(); i < count; ++i) {
|
||||
gfxFont* font = mFontsUsingSVGGlyphs[i];
|
||||
const gfxFont* font = mFontsUsingSVGGlyphs[i];
|
||||
font->NotifyGlyphsChanged();
|
||||
}
|
||||
}
|
||||
|
@ -251,7 +251,7 @@ class gfxFontEntry {
|
||||
// can be safely dereferenced.
|
||||
virtual nsresult ReadCMAP(FontInfoData* aFontInfoData = nullptr);
|
||||
|
||||
bool TryGetSVGData(gfxFont* aFont);
|
||||
bool TryGetSVGData(const gfxFont* aFont);
|
||||
bool HasSVGGlyph(uint32_t aGlyphId);
|
||||
bool GetSVGGlyphExtents(DrawTarget* aDrawTarget, uint32_t aGlyphId,
|
||||
gfxFloat aSize, gfxRect* aResult);
|
||||
@ -472,7 +472,7 @@ class gfxFontEntry {
|
||||
mozilla::UniquePtr<gfxUserFontData> mUserFontData;
|
||||
mozilla::UniquePtr<gfxSVGGlyphs> mSVGGlyphs;
|
||||
// list of gfxFonts that are using SVG glyphs
|
||||
nsTArray<gfxFont*> mFontsUsingSVGGlyphs;
|
||||
nsTArray<const gfxFont*> mFontsUsingSVGGlyphs;
|
||||
nsTArray<gfxFontFeature> mFeatureSettings;
|
||||
nsTArray<gfxFontVariation> mVariationSettings;
|
||||
mozilla::UniquePtr<nsTHashMap<nsUint32HashKey, bool>> mSupportedFeatures;
|
||||
|
@ -51,10 +51,9 @@ gfxGDIFont::~gfxGDIFont() {
|
||||
delete mMetrics;
|
||||
}
|
||||
|
||||
UniquePtr<gfxFont> gfxGDIFont::CopyWithAntialiasOption(
|
||||
AntialiasOption anAAOption) {
|
||||
gfxFont* gfxGDIFont::CopyWithAntialiasOption(AntialiasOption anAAOption) const {
|
||||
auto entry = static_cast<GDIFontEntry*>(mFontEntry.get());
|
||||
return MakeUnique<gfxGDIFont>(entry, &mStyle, anAAOption);
|
||||
return new gfxGDIFont(entry, &mStyle, anAAOption);
|
||||
}
|
||||
|
||||
bool gfxGDIFont::ShapeText(DrawTarget* aDrawTarget, const char16_t* aText,
|
||||
@ -71,21 +70,28 @@ bool gfxGDIFont::ShapeText(DrawTarget* aDrawTarget, const char16_t* aText,
|
||||
aLanguage, aVertical, aRounding, aShapedText);
|
||||
}
|
||||
|
||||
const gfxFont::Metrics& gfxGDIFont::GetHorizontalMetrics() { return *mMetrics; }
|
||||
|
||||
already_AddRefed<ScaledFont> gfxGDIFont::GetScaledFont(
|
||||
const TextRunDrawParams& aRunParams) {
|
||||
if (!mAzureScaledFont) {
|
||||
LOGFONT lf;
|
||||
GetObject(GetHFONT(), sizeof(LOGFONT), &lf);
|
||||
|
||||
mAzureScaledFont = Factory::CreateScaledFontForGDIFont(
|
||||
&lf, GetUnscaledFont(), GetAdjustedSize());
|
||||
InitializeScaledFont();
|
||||
if (ScaledFont* scaledFont = mAzureScaledFont) {
|
||||
return do_AddRef(scaledFont);
|
||||
}
|
||||
|
||||
RefPtr<ScaledFont> scaledFont(mAzureScaledFont);
|
||||
return scaledFont.forget();
|
||||
LOGFONT lf;
|
||||
GetObject(GetHFONT(), sizeof(LOGFONT), &lf);
|
||||
|
||||
RefPtr<ScaledFont> newScaledFont = Factory::CreateScaledFontForGDIFont(
|
||||
&lf, GetUnscaledFont(), GetAdjustedSize());
|
||||
if (!newScaledFont) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
InitializeScaledFont(newScaledFont);
|
||||
|
||||
if (mAzureScaledFont.compareExchange(nullptr, newScaledFont.get())) {
|
||||
Unused << newScaledFont.forget();
|
||||
}
|
||||
ScaledFont* scaledFont = mAzureScaledFont;
|
||||
return do_AddRef(scaledFont);
|
||||
}
|
||||
|
||||
gfxFont::RunMetrics gfxGDIFont::Measure(const gfxTextRun* aTextRun,
|
||||
@ -485,7 +491,8 @@ int32_t gfxGDIFont::GetGlyphWidth(uint16_t aGID) {
|
||||
});
|
||||
}
|
||||
|
||||
bool gfxGDIFont::GetGlyphBounds(uint16_t aGID, gfxRect* aBounds, bool aTight) {
|
||||
bool gfxGDIFont::GetGlyphBounds(uint16_t aGID, gfxRect* aBounds,
|
||||
bool aTight) const {
|
||||
DCForMetrics dc;
|
||||
AutoSelectFont fs(dc, GetHFONT());
|
||||
|
||||
|
@ -22,7 +22,7 @@ class gfxGDIFont : public gfxFont {
|
||||
|
||||
virtual ~gfxGDIFont();
|
||||
|
||||
HFONT GetHFONT() { return mFont; }
|
||||
HFONT GetHFONT() const { return mFont; }
|
||||
|
||||
already_AddRefed<mozilla::gfx::ScaledFont> GetScaledFont(
|
||||
const TextRunDrawParams& aRunParams) override;
|
||||
@ -35,8 +35,7 @@ class gfxGDIFont : public gfxFont {
|
||||
mozilla::gfx::ShapedTextFlags aOrientation) override;
|
||||
|
||||
/* required for MathML to suppress effects of ClearType "padding" */
|
||||
mozilla::UniquePtr<gfxFont> CopyWithAntialiasOption(
|
||||
AntialiasOption anAAOption) override;
|
||||
gfxFont* CopyWithAntialiasOption(AntialiasOption anAAOption) const override;
|
||||
|
||||
// If the font has a cmap table, we handle it purely with harfbuzz;
|
||||
// but if not (e.g. .fon fonts), we'll use a GDI callback to get glyphs.
|
||||
@ -49,7 +48,8 @@ class gfxGDIFont : public gfxFont {
|
||||
// get hinted glyph width in pixels as 16.16 fixed-point value
|
||||
int32_t GetGlyphWidth(uint16_t aGID) override;
|
||||
|
||||
bool GetGlyphBounds(uint16_t aGID, gfxRect* aBounds, bool aTight) override;
|
||||
bool GetGlyphBounds(uint16_t aGID, gfxRect* aBounds,
|
||||
bool aTight) const override;
|
||||
|
||||
void AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
|
||||
FontCacheSizes* aSizes) const;
|
||||
@ -59,7 +59,7 @@ class gfxGDIFont : public gfxFont {
|
||||
FontType GetType() const override { return FONT_TYPE_GDI; }
|
||||
|
||||
protected:
|
||||
const Metrics& GetHorizontalMetrics() override;
|
||||
const Metrics& GetHorizontalMetrics() const override { return *mMetrics; }
|
||||
|
||||
bool ShapeText(DrawTarget* aDrawTarget, const char16_t* aText,
|
||||
uint32_t aOffset, uint32_t aLength, Script aScript,
|
||||
|
@ -25,8 +25,12 @@ class gfxHarfBuzzShaper : public gfxFontShaper {
|
||||
gfxHarfBuzzShaper* mShaper;
|
||||
};
|
||||
|
||||
// Initializes the shaper and returns whether this was successful.
|
||||
bool Initialize();
|
||||
|
||||
// Returns whether the shaper has been successfully initialized.
|
||||
bool IsInitialized() const { return mHBFont != nullptr; }
|
||||
|
||||
bool ShapeText(DrawTarget* aDrawTarget, const char16_t* aText,
|
||||
uint32_t aOffset, uint32_t aLength, Script aScript,
|
||||
nsAtom* aLanguage, bool aVertical, RoundingFlags aRounding,
|
||||
|
@ -518,7 +518,8 @@ int32_t gfxMacFont::GetGlyphWidth(uint16_t aGID) {
|
||||
return advance.width * 0x10000;
|
||||
}
|
||||
|
||||
bool gfxMacFont::GetGlyphBounds(uint16_t aGID, gfxRect* aBounds, bool aTight) {
|
||||
bool gfxMacFont::GetGlyphBounds(uint16_t aGID, gfxRect* aBounds,
|
||||
bool aTight) const {
|
||||
CGRect bb;
|
||||
if (!::CGFontGetGlyphBBoxes(mCGFont, &aGID, 1, &bb)) {
|
||||
return false;
|
||||
@ -581,21 +582,27 @@ void gfxMacFont::InitMetricsFromPlatform() {
|
||||
|
||||
already_AddRefed<ScaledFont> gfxMacFont::GetScaledFont(
|
||||
const TextRunDrawParams& aRunParams) {
|
||||
if (!mAzureScaledFont) {
|
||||
gfxFontEntry* fe = GetFontEntry();
|
||||
bool hasColorGlyphs = fe->HasColorBitmapTable() || fe->TryGetColorGlyphs();
|
||||
mAzureScaledFont = Factory::CreateScaledFontForMacFont(
|
||||
GetCGFontRef(), GetUnscaledFont(), GetAdjustedSize(),
|
||||
ToDeviceColor(mFontSmoothingBackgroundColor),
|
||||
!mStyle.useGrayscaleAntialiasing, ApplySyntheticBold(), hasColorGlyphs);
|
||||
if (!mAzureScaledFont) {
|
||||
return nullptr;
|
||||
}
|
||||
InitializeScaledFont();
|
||||
if (ScaledFont* scaledFont = mAzureScaledFont) {
|
||||
return do_AddRef(scaledFont);
|
||||
}
|
||||
|
||||
RefPtr<ScaledFont> scaledFont(mAzureScaledFont);
|
||||
return scaledFont.forget();
|
||||
gfxFontEntry* fe = GetFontEntry();
|
||||
bool hasColorGlyphs = fe->HasColorBitmapTable() || fe->TryGetColorGlyphs();
|
||||
RefPtr<ScaledFont> newScaledFont = Factory::CreateScaledFontForMacFont(
|
||||
GetCGFontRef(), GetUnscaledFont(), GetAdjustedSize(),
|
||||
ToDeviceColor(mFontSmoothingBackgroundColor),
|
||||
!mStyle.useGrayscaleAntialiasing, ApplySyntheticBold(), hasColorGlyphs);
|
||||
if (!newScaledFont) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
InitializeScaledFont(newScaledFont);
|
||||
|
||||
if (mAzureScaledFont.compareExchange(nullptr, newScaledFont.get())) {
|
||||
Unused << newScaledFont.forget();
|
||||
}
|
||||
ScaledFont* scaledFont = mAzureScaledFont;
|
||||
return do_AddRef(scaledFont);
|
||||
}
|
||||
|
||||
bool gfxMacFont::ShouldRoundXOffset(cairo_t* aCairo) const {
|
||||
|
@ -37,7 +37,7 @@ class gfxMacFont : public gfxFont {
|
||||
|
||||
int32_t GetGlyphWidth(uint16_t aGID) override;
|
||||
|
||||
bool GetGlyphBounds(uint16_t aGID, gfxRect* aBounds, bool aTight) override;
|
||||
bool GetGlyphBounds(uint16_t aGID, gfxRect* aBounds, bool aTight) const override;
|
||||
|
||||
already_AddRefed<mozilla::gfx::ScaledFont> GetScaledFont(
|
||||
const TextRunDrawParams& aRunParams) override;
|
||||
@ -59,7 +59,7 @@ class gfxMacFont : public gfxFont {
|
||||
CTFontDescriptorRef aFontDesc = nullptr);
|
||||
|
||||
protected:
|
||||
const Metrics& GetHorizontalMetrics() override { return mMetrics; }
|
||||
const Metrics& GetHorizontalMetrics() const override { return mMetrics; }
|
||||
|
||||
// override to prefer CoreText shaping with fonts that depend on AAT
|
||||
bool ShapeText(DrawTarget* aDrawTarget, const char16_t* aText, uint32_t aOffset, uint32_t aLength,
|
||||
|
Loading…
x
Reference in New Issue
Block a user