Bug 1963212 - Reuse FontFaceImpl more aggressively. r=jfkthame
When deep-cloning a stylesheet (like we do for devtools), we end up with new (identical) LockedFontFaceRule object, but we'd fail to re-use it, triggering new font loads. Since we don't cache failed loads, this caused flashing and a temporary state where the used fonts were not what this DevTools test expects. Rejigger the code a little bit to push down the decision of whether to reuse the FontFaceImpl object further down. That allows us to reuse the FontFace object for the stylesheet caching / deep cloning use-case. Differential Revision: https://phabricator.services.mozilla.com/D247704
This commit is contained in:
committed by
ealvarez@mozilla.com
parent
fd3e0c3fcd
commit
a0a14bcfb9
@@ -570,8 +570,35 @@ bool FontFaceImpl::GetAttributes(gfxUserFontAttributes& aAttr) {
|
||||
if (!data) {
|
||||
return false;
|
||||
}
|
||||
return GetAttributesFromRule(data, aAttr,
|
||||
Some(GetUnicodeRangeAsCharacterMap()));
|
||||
}
|
||||
|
||||
nsAtom* fontFamily = Servo_FontFaceRule_GetFamilyName(data);
|
||||
static already_AddRefed<gfxCharacterMap> ComputeCharacterMap(StyleLockedFontFaceRule* aData) {
|
||||
size_t len;
|
||||
const StyleUnicodeRange* rangesPtr =
|
||||
Servo_FontFaceRule_GetUnicodeRanges(aData, &len);
|
||||
|
||||
Span<const StyleUnicodeRange> ranges(rangesPtr, len);
|
||||
if (ranges.IsEmpty()) {
|
||||
return nullptr;
|
||||
}
|
||||
auto charMap = MakeRefPtr<gfxCharacterMap>();
|
||||
for (auto& range : ranges) {
|
||||
charMap->SetRange(range.start, range.end);
|
||||
}
|
||||
charMap->Compact();
|
||||
// As it's common for multiple font resources to have the same
|
||||
// unicode-range list, look for an existing copy of this map to share,
|
||||
// or add this one to the sharing cache if not already present.
|
||||
return gfxPlatformFontList::PlatformFontList()->FindCharMap(charMap);
|
||||
}
|
||||
|
||||
|
||||
bool FontFaceImpl::GetAttributesFromRule(
|
||||
StyleLockedFontFaceRule* aData, gfxUserFontAttributes& aAttr,
|
||||
const Maybe<gfxCharacterMap*>& aKnownCharMap) {
|
||||
nsAtom* fontFamily = Servo_FontFaceRule_GetFamilyName(aData);
|
||||
if (!fontFamily) {
|
||||
return false;
|
||||
}
|
||||
@@ -579,20 +606,20 @@ bool FontFaceImpl::GetAttributes(gfxUserFontAttributes& aAttr) {
|
||||
aAttr.mFamilyName = nsAtomCString(fontFamily);
|
||||
|
||||
StyleComputedFontWeightRange weightRange;
|
||||
if (Servo_FontFaceRule_GetFontWeight(data, &weightRange)) {
|
||||
if (Servo_FontFaceRule_GetFontWeight(aData, &weightRange)) {
|
||||
aAttr.mRangeFlags &= ~gfxFontEntry::RangeFlags::eAutoWeight;
|
||||
aAttr.mWeight = WeightRange(FontWeight::FromFloat(weightRange._0),
|
||||
FontWeight::FromFloat(weightRange._1));
|
||||
}
|
||||
|
||||
StyleComputedFontStretchRange stretchRange;
|
||||
if (Servo_FontFaceRule_GetFontStretch(data, &stretchRange)) {
|
||||
if (Servo_FontFaceRule_GetFontStretch(aData, &stretchRange)) {
|
||||
aAttr.mRangeFlags &= ~gfxFontEntry::RangeFlags::eAutoStretch;
|
||||
aAttr.mStretch = StretchRange(stretchRange._0, stretchRange._1);
|
||||
}
|
||||
|
||||
auto styleDesc = StyleComputedFontStyleDescriptor::Normal();
|
||||
if (Servo_FontFaceRule_GetFontStyle(data, &styleDesc)) {
|
||||
if (Servo_FontFaceRule_GetFontStyle(aData, &styleDesc)) {
|
||||
aAttr.mRangeFlags &= ~gfxFontEntry::RangeFlags::eAutoSlantStyle;
|
||||
switch (styleDesc.tag) {
|
||||
case StyleComputedFontStyleDescriptor::Tag::Italic:
|
||||
@@ -609,47 +636,40 @@ bool FontFaceImpl::GetAttributes(gfxUserFontAttributes& aAttr) {
|
||||
}
|
||||
|
||||
StylePercentage ascent{0};
|
||||
if (Servo_FontFaceRule_GetAscentOverride(data, &ascent)) {
|
||||
if (Servo_FontFaceRule_GetAscentOverride(aData, &ascent)) {
|
||||
aAttr.mAscentOverride = ascent._0;
|
||||
}
|
||||
|
||||
StylePercentage descent{0};
|
||||
if (Servo_FontFaceRule_GetDescentOverride(data, &descent)) {
|
||||
if (Servo_FontFaceRule_GetDescentOverride(aData, &descent)) {
|
||||
aAttr.mDescentOverride = descent._0;
|
||||
}
|
||||
|
||||
StylePercentage lineGap{0};
|
||||
if (Servo_FontFaceRule_GetLineGapOverride(data, &lineGap)) {
|
||||
if (Servo_FontFaceRule_GetLineGapOverride(aData, &lineGap)) {
|
||||
aAttr.mLineGapOverride = lineGap._0;
|
||||
}
|
||||
|
||||
StylePercentage sizeAdjust;
|
||||
if (Servo_FontFaceRule_GetSizeAdjust(data, &sizeAdjust)) {
|
||||
if (Servo_FontFaceRule_GetSizeAdjust(aData, &sizeAdjust)) {
|
||||
aAttr.mSizeAdjust = sizeAdjust._0;
|
||||
}
|
||||
|
||||
StyleFontLanguageOverride langOverride;
|
||||
if (Servo_FontFaceRule_GetFontLanguageOverride(data, &langOverride)) {
|
||||
if (Servo_FontFaceRule_GetFontLanguageOverride(aData, &langOverride)) {
|
||||
aAttr.mLanguageOverride = langOverride._0;
|
||||
}
|
||||
|
||||
Servo_FontFaceRule_GetFontDisplay(data, &aAttr.mFontDisplay);
|
||||
Servo_FontFaceRule_GetFeatureSettings(data, &aAttr.mFeatureSettings);
|
||||
Servo_FontFaceRule_GetVariationSettings(data, &aAttr.mVariationSettings);
|
||||
Servo_FontFaceRule_GetSources(data, &aAttr.mSources);
|
||||
aAttr.mUnicodeRanges = GetUnicodeRangeAsCharacterMap();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FontFaceImpl::HasLocalSrc() const {
|
||||
AutoTArray<StyleFontFaceSourceListComponent, 8> components;
|
||||
Servo_FontFaceRule_GetSources(GetData(), &components);
|
||||
for (auto& component : components) {
|
||||
if (component.tag == StyleFontFaceSourceListComponent::Tag::Local) {
|
||||
return true;
|
||||
Servo_FontFaceRule_GetFontDisplay(aData, &aAttr.mFontDisplay);
|
||||
Servo_FontFaceRule_GetFeatureSettings(aData, &aAttr.mFeatureSettings);
|
||||
Servo_FontFaceRule_GetVariationSettings(aData, &aAttr.mVariationSettings);
|
||||
Servo_FontFaceRule_GetSources(aData, &aAttr.mSources);
|
||||
if (aKnownCharMap) {
|
||||
aAttr.mUnicodeRanges = aKnownCharMap.value();
|
||||
} else {
|
||||
aAttr.mUnicodeRanges = ComputeCharacterMap(aData);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
nsAtom* FontFaceImpl::GetFamilyName() const {
|
||||
@@ -725,27 +745,7 @@ gfxCharacterMap* FontFaceImpl::GetUnicodeRangeAsCharacterMap() {
|
||||
if (!mUnicodeRangeDirty) {
|
||||
return mUnicodeRange;
|
||||
}
|
||||
|
||||
size_t len;
|
||||
const StyleUnicodeRange* rangesPtr =
|
||||
Servo_FontFaceRule_GetUnicodeRanges(GetData(), &len);
|
||||
|
||||
Span<const StyleUnicodeRange> ranges(rangesPtr, len);
|
||||
if (!ranges.IsEmpty()) {
|
||||
auto charMap = MakeRefPtr<gfxCharacterMap>();
|
||||
for (auto& range : ranges) {
|
||||
charMap->SetRange(range.start, range.end);
|
||||
}
|
||||
charMap->Compact();
|
||||
// As it's common for multiple font resources to have the same
|
||||
// unicode-range list, look for an existing copy of this map to share,
|
||||
// or add this one to the sharing cache if not already present.
|
||||
mUnicodeRange =
|
||||
gfxPlatformFontList::PlatformFontList()->FindCharMap(charMap);
|
||||
} else {
|
||||
mUnicodeRange = nullptr;
|
||||
}
|
||||
|
||||
mUnicodeRange = ComputeCharacterMap(GetData());
|
||||
mUnicodeRangeDirty = false;
|
||||
return mUnicodeRange;
|
||||
}
|
||||
|
||||
@@ -98,8 +98,9 @@ class FontFaceImpl final {
|
||||
|
||||
StyleLockedFontFaceRule* GetRule() { return mRule; }
|
||||
|
||||
bool HasLocalSrc() const;
|
||||
|
||||
static bool GetAttributesFromRule(
|
||||
StyleLockedFontFaceRule*, gfxUserFontAttributes& aAttr,
|
||||
const Maybe<gfxCharacterMap*>& aKnownCharMap = Nothing());
|
||||
bool GetAttributes(gfxUserFontAttributes& aAttr);
|
||||
gfxUserFontEntry* CreateUserFontEntry();
|
||||
gfxUserFontEntry* GetUserFontEntry() const { return mUserFontEntry; }
|
||||
@@ -128,6 +129,13 @@ class FontFaceImpl final {
|
||||
*/
|
||||
bool HasRule() const { return mRule; }
|
||||
|
||||
/** Set the font-face block we're reflecting when reusing a FontFace object */
|
||||
void SetRule(StyleLockedFontFaceRule* aData) {
|
||||
MOZ_ASSERT(HasRule());
|
||||
AssertIsOnOwningThread();
|
||||
mRule = aData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Breaks the connection between this FontFace and its @font-face rule.
|
||||
*/
|
||||
@@ -202,6 +210,11 @@ class FontFaceImpl final {
|
||||
bool SetDescriptors(const nsACString& aFamily,
|
||||
const FontFaceDescriptors& aDescriptors);
|
||||
|
||||
StyleLockedFontFaceRule* GetData() const {
|
||||
AssertIsOnOwningThread();
|
||||
return HasRule() ? mRule : mDescriptors;
|
||||
}
|
||||
|
||||
private:
|
||||
~FontFaceImpl();
|
||||
|
||||
@@ -228,11 +241,6 @@ class FontFaceImpl final {
|
||||
|
||||
void GetDesc(nsCSSFontDesc aDescID, nsACString& aResult) const;
|
||||
|
||||
StyleLockedFontFaceRule* GetData() const {
|
||||
AssertIsOnOwningThread();
|
||||
return HasRule() ? mRule : mDescriptors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns and takes ownership of the buffer storing the font data.
|
||||
*/
|
||||
|
||||
@@ -406,16 +406,6 @@ bool FontFaceSetDocumentImpl::UpdateRules(
|
||||
// same rules are still present.
|
||||
nsTArray<FontFaceRecord> oldRecords = std::move(mRuleFaces);
|
||||
|
||||
// reuse existing FontFace objects mapped to particular rules already
|
||||
nsTHashMap<nsPtrHashKey<StyleLockedFontFaceRule>, FontFaceImpl*> ruleFaceMap;
|
||||
for (const FontFaceRecord& record : oldRecords) {
|
||||
FontFaceImpl* f = record.mFontFace;
|
||||
if (!f || !f->GetOwner()) {
|
||||
continue;
|
||||
}
|
||||
ruleFaceMap.InsertOrUpdate(f->GetRule(), f);
|
||||
}
|
||||
|
||||
// Remove faces from the font family records; we need to re-insert them
|
||||
// because we might end up with faces in a different order even if they're
|
||||
// the same font entries as before. (The order can affect font selection
|
||||
@@ -441,13 +431,7 @@ bool FontFaceSetDocumentImpl::UpdateRules(
|
||||
// rule was already present in the hashtable
|
||||
continue;
|
||||
}
|
||||
RefPtr<FontFaceImpl> faceImpl = ruleFaceMap.Get(rule);
|
||||
RefPtr<FontFace> face = faceImpl ? faceImpl->GetOwner() : nullptr;
|
||||
if (mOwner && (!faceImpl || !face)) {
|
||||
face = FontFace::CreateForRule(mOwner->GetParentObject(), mOwner, rule);
|
||||
faceImpl = face->GetImpl();
|
||||
}
|
||||
InsertRuleFontFace(faceImpl, face, container.mOrigin, oldRecords, modified);
|
||||
modified |= InsertRuleFontFace(rule, container.mOrigin, oldRecords);
|
||||
}
|
||||
|
||||
for (const FontFaceRecord& record : mNonRuleFaces) {
|
||||
@@ -512,16 +496,20 @@ bool FontFaceSetDocumentImpl::UpdateRules(
|
||||
return modified;
|
||||
}
|
||||
|
||||
void FontFaceSetDocumentImpl::InsertRuleFontFace(
|
||||
FontFaceImpl* aFontFace, FontFace* aFontFaceOwner, StyleOrigin aSheetType,
|
||||
nsTArray<FontFaceRecord>& aOldRecords, bool& aFontSetModified) {
|
||||
bool FontFaceSetDocumentImpl::InsertRuleFontFace(
|
||||
StyleLockedFontFaceRule* aRule, StyleOrigin aSheetType,
|
||||
nsTArray<FontFaceRecord>& aOldRecords) {
|
||||
RecursiveMutexAutoLock lock(mMutex);
|
||||
|
||||
if (MOZ_UNLIKELY(!mOwner)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
gfxUserFontAttributes attr;
|
||||
if (!aFontFace->GetAttributes(attr)) {
|
||||
if (!FontFaceImpl::GetAttributesFromRule(aRule, attr)) {
|
||||
// If there is no family name, this rule cannot contribute a
|
||||
// usable font, so there is no point in processing it further.
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool remove = false;
|
||||
@@ -533,11 +521,27 @@ void FontFaceSetDocumentImpl::InsertRuleFontFace(
|
||||
for (size_t i = 0; i < aOldRecords.Length(); ++i) {
|
||||
FontFaceRecord& rec = aOldRecords[i];
|
||||
|
||||
if (rec.mFontFace == aFontFace && rec.mOrigin == Some(aSheetType)) {
|
||||
const bool matches =
|
||||
rec.mOrigin == Some(aSheetType) &&
|
||||
Servo_FontFaceRule_Equals(rec.mFontFace->GetData(), aRule);
|
||||
if (!matches) {
|
||||
continue;
|
||||
}
|
||||
|
||||
FontFace* owner = rec.mFontFace->GetOwner();
|
||||
// if local rules were used, don't use the old font entry
|
||||
// for rules containing src local usage
|
||||
if (mLocalRulesUsed && mRebuildLocalRules) {
|
||||
if (aFontFace->HasLocalSrc()) {
|
||||
const bool hasLocalSource = [&] {
|
||||
for (auto& source : attr.mSources) {
|
||||
if (source.IsLocal()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}();
|
||||
|
||||
if (hasLocalSource) {
|
||||
// Remove the old record, but wait to see if we successfully create a
|
||||
// new user font entry below.
|
||||
remove = true;
|
||||
@@ -546,6 +550,7 @@ void FontFaceSetDocumentImpl::InsertRuleFontFace(
|
||||
}
|
||||
}
|
||||
|
||||
rec.mFontFace->SetRule(aRule);
|
||||
gfxUserFontEntry* entry = rec.mFontFace->GetUserFontEntry();
|
||||
MOZ_ASSERT(entry, "FontFace should have a gfxUserFontEntry by now");
|
||||
|
||||
@@ -557,26 +562,25 @@ void FontFaceSetDocumentImpl::InsertRuleFontFace(
|
||||
mRuleFaces.AppendElement(rec);
|
||||
aOldRecords.RemoveElementAt(i);
|
||||
|
||||
if (mOwner && aFontFaceOwner) {
|
||||
mOwner->InsertRuleFontFace(aFontFaceOwner, aSheetType);
|
||||
if (owner) {
|
||||
mOwner->InsertRuleFontFace(owner, aSheetType);
|
||||
}
|
||||
|
||||
// note the set has been modified if an old rule was skipped to find
|
||||
// this one - something has been dropped, or ordering changed
|
||||
if (i > 0) {
|
||||
aFontSetModified = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
return i > 0;
|
||||
}
|
||||
|
||||
RefPtr<FontFace> fontFace =
|
||||
FontFace::CreateForRule(mOwner->GetParentObject(), mOwner, aRule);
|
||||
RefPtr<FontFaceImpl> impl = fontFace->GetImpl();
|
||||
// this is a new rule:
|
||||
nsAutoCString family(attr.mFamilyName);
|
||||
RefPtr<gfxUserFontEntry> entry = FindOrCreateUserFontEntryFromFontFace(
|
||||
aFontFace, std::move(attr), aSheetType);
|
||||
RefPtr<gfxUserFontEntry> entry =
|
||||
FindOrCreateUserFontEntryFromFontFace(impl, std::move(attr), aSheetType);
|
||||
|
||||
if (!entry) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (remove) {
|
||||
@@ -590,22 +594,17 @@ void FontFaceSetDocumentImpl::InsertRuleFontFace(
|
||||
}
|
||||
|
||||
FontFaceRecord rec;
|
||||
rec.mFontFace = aFontFace;
|
||||
rec.mFontFace = impl;
|
||||
rec.mOrigin = Some(aSheetType);
|
||||
|
||||
aFontFace->SetUserFontEntry(entry);
|
||||
impl->SetUserFontEntry(entry);
|
||||
|
||||
MOZ_ASSERT(!HasRuleFontFace(aFontFace),
|
||||
MOZ_ASSERT(!HasRuleFontFace(impl),
|
||||
"FontFace should not occur in mRuleFaces twice");
|
||||
|
||||
mRuleFaces.AppendElement(rec);
|
||||
|
||||
if (mOwner && aFontFaceOwner) {
|
||||
mOwner->InsertRuleFontFace(aFontFaceOwner, aSheetType);
|
||||
}
|
||||
|
||||
// this was a new rule and font entry, so note that the set was modified
|
||||
aFontSetModified = true;
|
||||
mOwner->InsertRuleFontFace(fontFace, aSheetType);
|
||||
|
||||
// Add the entry to the end of the list. If an existing userfont entry was
|
||||
// returned by FindOrCreateUserFontEntryFromFontFace that was already stored
|
||||
@@ -613,6 +612,7 @@ void FontFaceSetDocumentImpl::InsertRuleFontFace(
|
||||
// calls, will automatically remove the earlier occurrence of the same
|
||||
// userfont entry.
|
||||
AddUserFontEntry(family, entry);
|
||||
return true;
|
||||
}
|
||||
|
||||
StyleLockedFontFaceRule* FontFaceSetDocumentImpl::FindRuleForEntry(
|
||||
|
||||
@@ -91,10 +91,9 @@ class FontFaceSetDocumentImpl final : public FontFaceSetImpl,
|
||||
void FindMatchingFontFaces(const nsTHashSet<FontFace*>& aMatchingFaces,
|
||||
nsTArray<FontFace*>& aFontFaces) override;
|
||||
|
||||
void InsertRuleFontFace(FontFaceImpl* aFontFace, FontFace* aFontFaceOwner,
|
||||
StyleOrigin aOrigin,
|
||||
nsTArray<FontFaceRecord>& aOldRecords,
|
||||
bool& aFontSetModified);
|
||||
/* Returns whether the font set was modified. */
|
||||
bool InsertRuleFontFace(StyleLockedFontFaceRule*, StyleOrigin,
|
||||
nsTArray<FontFaceRecord>& aOldRecords);
|
||||
|
||||
// Helper function for HasLoadingFontFaces.
|
||||
void UpdateHasLoadingFontFaces() override;
|
||||
|
||||
@@ -3251,6 +3251,21 @@ pub unsafe extern "C" fn Servo_FontFaceRule_Clone(
|
||||
with_maybe_worker_shared_lock(|lock| Arc::new(lock.wrap(clone)).into())
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Servo_FontFaceRule_Equals(
|
||||
a: &LockedFontFaceRule,
|
||||
b: &LockedFontFaceRule,
|
||||
) -> bool {
|
||||
if a as *const _ == b as *const _ {
|
||||
return true;
|
||||
}
|
||||
read_locked_arc_worker(a, |a: &FontFaceRule| {
|
||||
read_locked_arc_worker(b, |b: &FontFaceRule| {
|
||||
a == b
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Servo_FontFaceRule_GetSourceLocation(
|
||||
rule: &LockedFontFaceRule,
|
||||
|
||||
Reference in New Issue
Block a user