Bug 1771493 - Part 1. Split FontFace(Set) into DOM facing and implementation classes. r=emilio

This patch aims to split the implementation details of FontFace(Set)
into FontFace(Set)Impl classes. The Impl variants have threadsafe
refcounting and are intended to be the basis for worker support for
FontFace(Set). We need threadsafe objects to pass around because parts
of the stack can only run on the main thread (network loading of font
data, graphics initialization of a font) even if the FontFace(Set)
itself lives on a DOM worker thread. Given the DOM facing objects are
cycle collected, we need additional indirection to support this use
case.

This patch should be a non-functional change.

Differential Revision: https://phabricator.services.mozilla.com/D147505
This commit is contained in:
Andrew Osmond
2022-06-28 21:46:59 +00:00
parent 1625c54d5f
commit c4c2b34441
15 changed files with 3164 additions and 2547 deletions

View File

@@ -65,6 +65,7 @@
#include "mozilla/dom/PBrowserParent.h"
#include "mozilla/dom/BrowserChild.h"
#include "mozilla/dom/BrowserParent.h"
#include "mozilla/dom/FontFaceSet.h"
#include "mozilla/StaticPresData.h"
#include "nsRefreshDriver.h"
#include "Layers.h"

View File

@@ -72,7 +72,7 @@ CSSFontFaceRule* InspectorFontFace::GetRule() {
FontFaceSet::UserFontSet* fontSet =
static_cast<FontFaceSet::UserFontSet*>(mFontGroup->GetUserFontSet());
if (fontSet) {
FontFaceSet* fontFaceSet = fontSet->GetFontFaceSet();
FontFaceSetImpl* fontFaceSet = fontSet->GetFontFaceSet();
if (fontFaceSet) {
rule = fontFaceSet->FindRuleForEntry(mFontEntry);
}

View File

@@ -7,9 +7,9 @@
#include "mozilla/dom/FontFace.h"
#include <algorithm>
#include "gfxPlatformFontList.h"
#include "mozilla/dom/CSSFontFaceRule.h"
#include "mozilla/dom/FontFaceBinding.h"
#include "mozilla/dom/FontFaceImpl.h"
#include "mozilla/dom/FontFaceSet.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/TypedArray.h"
@@ -26,47 +26,6 @@
namespace mozilla {
namespace dom {
// -- FontFaceBufferSource ---------------------------------------------------
/**
* An object that wraps a FontFace object and exposes its ArrayBuffer
* or ArrayBufferView data in a form the user font set can consume.
*/
class FontFaceBufferSource : public gfxFontFaceBufferSource {
public:
explicit FontFaceBufferSource(FontFace* aFontFace) : mFontFace(aFontFace) {}
virtual void TakeBuffer(uint8_t*& aBuffer, uint32_t& aLength) override;
private:
RefPtr<FontFace> mFontFace;
};
void FontFaceBufferSource::TakeBuffer(uint8_t*& aBuffer, uint32_t& aLength) {
MOZ_ASSERT(mFontFace,
"only call TakeBuffer once on a given "
"FontFaceBufferSource object");
mFontFace->TakeBuffer(aBuffer, aLength);
mFontFace = nullptr;
}
// -- Utility functions ------------------------------------------------------
template <typename T>
static void GetDataFrom(const T& aObject, uint8_t*& aBuffer,
uint32_t& aLength) {
MOZ_ASSERT(!aBuffer);
aObject.ComputeState();
// We use malloc here rather than a FallibleTArray or fallible
// operator new[] since the gfxUserFontEntry will be calling free
// on it.
aBuffer = (uint8_t*)malloc(aObject.Length());
if (!aBuffer) {
return;
}
memcpy((void*)aBuffer, aObject.Data(), aObject.Length());
aLength = aObject.Length();
}
// -- FontFace ---------------------------------------------------------------
NS_IMPL_CYCLE_COLLECTION_CLASS(FontFace)
@@ -74,17 +33,12 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(FontFace)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(FontFace)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLoaded)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFontFaceSet)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOtherFontFaceSets)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(FontFace)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mParent)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mLoaded)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mFontFaceSet)
tmp->mInFontFaceSet = false;
tmp->SetUserFontEntry(nullptr);
NS_IMPL_CYCLE_COLLECTION_UNLINK(mOtherFontFaceSets)
tmp->Destroy();
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
@@ -100,58 +54,31 @@ NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTING_ADDREF(FontFace)
NS_IMPL_CYCLE_COLLECTING_RELEASE(FontFace)
FontFace::FontFace(nsISupports* aParent, FontFaceSet* aFontFaceSet)
: mParent(aParent),
mLoadedRejection(NS_OK),
mStatus(FontFaceLoadStatus::Unloaded),
mSourceType(SourceType(0)),
mSourceBuffer(nullptr),
mSourceBufferLength(0),
mFontFaceSet(aFontFaceSet),
mUnicodeRangeDirty(true),
mInFontFaceSet(false) {}
FontFace::FontFace(nsISupports* aParent)
: mParent(aParent), mLoadedRejection(NS_OK) {}
FontFace::~FontFace() {
// Assert that we don't drop any FontFace objects during a Servo traversal,
// since PostTraversalTask objects can hold raw pointers to FontFaces.
MOZ_ASSERT(!ServoStyleSet::IsInServoTraversal());
SetUserFontEntry(nullptr);
if (mSourceBuffer) {
free(mSourceBuffer);
}
Destroy();
}
void FontFace::Destroy() { mImpl->Destroy(); }
JSObject* FontFace::WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto) {
return FontFace_Binding::Wrap(aCx, this, aGivenProto);
}
static FontFaceLoadStatus LoadStateToStatus(
gfxUserFontEntry::UserFontLoadState aLoadState) {
switch (aLoadState) {
case gfxUserFontEntry::UserFontLoadState::STATUS_NOT_LOADED:
return FontFaceLoadStatus::Unloaded;
case gfxUserFontEntry::UserFontLoadState::STATUS_LOAD_PENDING:
case gfxUserFontEntry::UserFontLoadState::STATUS_LOADING:
return FontFaceLoadStatus::Loading;
case gfxUserFontEntry::UserFontLoadState::STATUS_LOADED:
return FontFaceLoadStatus::Loaded;
case gfxUserFontEntry::UserFontLoadState::STATUS_FAILED:
return FontFaceLoadStatus::Error;
}
MOZ_ASSERT_UNREACHABLE("invalid aLoadState value");
return FontFaceLoadStatus::Error;
}
already_AddRefed<FontFace> FontFace::CreateForRule(
nsISupports* aGlobal, FontFaceSet* aFontFaceSet,
RawServoFontFaceRule* aRule) {
RefPtr<FontFace> obj = new FontFace(aGlobal, aFontFaceSet);
obj->mRule = aRule;
obj->mSourceType = eSourceType_FontFaceRule;
obj->mInFontFaceSet = true;
FontFaceSetImpl* setImpl = aFontFaceSet->GetImpl();
MOZ_ASSERT(setImpl);
RefPtr<FontFace> obj = new FontFace(aGlobal);
obj->mImpl = FontFaceImpl::CreateForRule(obj, setImpl, aRule);
return obj.forget();
}
@@ -172,211 +99,116 @@ already_AddRefed<FontFace> FontFace::Constructor(
return nullptr;
}
RefPtr<FontFace> obj = new FontFace(global, doc->Fonts());
if (!obj->SetDescriptors(aFamily, aDescriptors)) {
return obj.forget();
FontFaceSetImpl* setImpl = doc->Fonts()->GetImpl();
MOZ_ASSERT(setImpl);
RefPtr<FontFace> obj = new FontFace(global);
obj->mImpl = new FontFaceImpl(obj, setImpl);
if (obj->mImpl->SetDescriptors(aFamily, aDescriptors)) {
obj->mImpl->InitializeSource(aSource);
}
obj->InitializeSource(aSource);
return obj.forget();
}
void FontFace::InitializeSource(
const UTF8StringOrArrayBufferOrArrayBufferView& aSource) {
if (aSource.IsUTF8String()) {
IgnoredErrorResult rv;
SetDescriptor(eCSSFontDesc_Src, aSource.GetAsUTF8String(), rv);
if (rv.Failed()) {
Reject(NS_ERROR_DOM_SYNTAX_ERR);
SetStatus(FontFaceLoadStatus::Error);
return;
}
mSourceType = eSourceType_URLs;
return;
}
mSourceType = FontFace::eSourceType_Buffer;
if (aSource.IsArrayBuffer()) {
GetDataFrom(aSource.GetAsArrayBuffer(), mSourceBuffer, mSourceBufferLength);
} else {
MOZ_ASSERT(aSource.IsArrayBufferView());
GetDataFrom(aSource.GetAsArrayBufferView(), mSourceBuffer,
mSourceBufferLength);
}
SetStatus(FontFaceLoadStatus::Loading);
DoLoad();
}
void FontFace::GetFamily(nsACString& aResult) {
GetDesc(eCSSFontDesc_Family, aResult);
}
void FontFace::GetFamily(nsACString& aResult) { mImpl->GetFamily(aResult); }
void FontFace::SetFamily(const nsACString& aValue, ErrorResult& aRv) {
mFontFaceSet->FlushUserFontSet();
if (SetDescriptor(eCSSFontDesc_Family, aValue, aRv)) {
DescriptorUpdated();
}
mImpl->SetFamily(aValue, aRv);
}
void FontFace::GetStyle(nsACString& aResult) {
GetDesc(eCSSFontDesc_Style, aResult);
}
void FontFace::GetStyle(nsACString& aResult) { mImpl->GetStyle(aResult); }
void FontFace::SetStyle(const nsACString& aValue, ErrorResult& aRv) {
if (SetDescriptor(eCSSFontDesc_Style, aValue, aRv)) {
DescriptorUpdated();
}
mImpl->SetStyle(aValue, aRv);
}
void FontFace::GetWeight(nsACString& aResult) {
GetDesc(eCSSFontDesc_Weight, aResult);
}
void FontFace::GetWeight(nsACString& aResult) { mImpl->GetWeight(aResult); }
void FontFace::SetWeight(const nsACString& aValue, ErrorResult& aRv) {
mFontFaceSet->FlushUserFontSet();
if (SetDescriptor(eCSSFontDesc_Weight, aValue, aRv)) {
DescriptorUpdated();
}
mImpl->SetWeight(aValue, aRv);
}
void FontFace::GetStretch(nsACString& aResult) {
GetDesc(eCSSFontDesc_Stretch, aResult);
}
void FontFace::GetStretch(nsACString& aResult) { mImpl->GetStretch(aResult); }
void FontFace::SetStretch(const nsACString& aValue, ErrorResult& aRv) {
mFontFaceSet->FlushUserFontSet();
if (SetDescriptor(eCSSFontDesc_Stretch, aValue, aRv)) {
DescriptorUpdated();
}
mImpl->SetStretch(aValue, aRv);
}
void FontFace::GetUnicodeRange(nsACString& aResult) {
GetDesc(eCSSFontDesc_UnicodeRange, aResult);
mImpl->GetUnicodeRange(aResult);
}
void FontFace::SetUnicodeRange(const nsACString& aValue, ErrorResult& aRv) {
mFontFaceSet->FlushUserFontSet();
if (SetDescriptor(eCSSFontDesc_UnicodeRange, aValue, aRv)) {
DescriptorUpdated();
}
mImpl->SetUnicodeRange(aValue, aRv);
}
void FontFace::GetVariant(nsACString& aResult) {
// XXX Just expose the font-variant descriptor as "normal" until we
// support it properly (bug 1055385).
aResult.AssignLiteral("normal");
}
void FontFace::GetVariant(nsACString& aResult) { mImpl->GetVariant(aResult); }
void FontFace::SetVariant(const nsACString& aValue, ErrorResult& aRv) {
// XXX Ignore assignments to variant until we support font-variant
// descriptors (bug 1055385).
mImpl->SetVariant(aValue, aRv);
}
void FontFace::GetFeatureSettings(nsACString& aResult) {
GetDesc(eCSSFontDesc_FontFeatureSettings, aResult);
mImpl->GetFeatureSettings(aResult);
}
void FontFace::SetFeatureSettings(const nsACString& aValue, ErrorResult& aRv) {
mFontFaceSet->FlushUserFontSet();
if (SetDescriptor(eCSSFontDesc_FontFeatureSettings, aValue, aRv)) {
DescriptorUpdated();
}
mImpl->SetFeatureSettings(aValue, aRv);
}
void FontFace::GetVariationSettings(nsACString& aResult) {
GetDesc(eCSSFontDesc_FontVariationSettings, aResult);
mImpl->GetVariationSettings(aResult);
}
void FontFace::SetVariationSettings(const nsACString& aValue,
ErrorResult& aRv) {
mFontFaceSet->FlushUserFontSet();
if (SetDescriptor(eCSSFontDesc_FontVariationSettings, aValue, aRv)) {
DescriptorUpdated();
}
mImpl->SetVariationSettings(aValue, aRv);
}
void FontFace::GetDisplay(nsACString& aResult) {
GetDesc(eCSSFontDesc_Display, aResult);
}
void FontFace::GetDisplay(nsACString& aResult) { mImpl->GetDisplay(aResult); }
void FontFace::SetDisplay(const nsACString& aValue, ErrorResult& aRv) {
if (SetDescriptor(eCSSFontDesc_Display, aValue, aRv)) {
DescriptorUpdated();
}
mImpl->SetDisplay(aValue, aRv);
}
void FontFace::GetAscentOverride(nsACString& aResult) {
GetDesc(eCSSFontDesc_AscentOverride, aResult);
mImpl->GetAscentOverride(aResult);
}
void FontFace::SetAscentOverride(const nsACString& aValue, ErrorResult& aRv) {
if (SetDescriptor(eCSSFontDesc_AscentOverride, aValue, aRv)) {
DescriptorUpdated();
}
mImpl->SetAscentOverride(aValue, aRv);
}
void FontFace::GetDescentOverride(nsACString& aResult) {
GetDesc(eCSSFontDesc_DescentOverride, aResult);
mImpl->GetDescentOverride(aResult);
}
void FontFace::SetDescentOverride(const nsACString& aValue, ErrorResult& aRv) {
if (SetDescriptor(eCSSFontDesc_DescentOverride, aValue, aRv)) {
DescriptorUpdated();
}
mImpl->SetDescentOverride(aValue, aRv);
}
void FontFace::GetLineGapOverride(nsACString& aResult) {
GetDesc(eCSSFontDesc_LineGapOverride, aResult);
mImpl->GetLineGapOverride(aResult);
}
void FontFace::SetLineGapOverride(const nsACString& aValue, ErrorResult& aRv) {
if (SetDescriptor(eCSSFontDesc_LineGapOverride, aValue, aRv)) {
DescriptorUpdated();
}
mImpl->SetLineGapOverride(aValue, aRv);
}
void FontFace::GetSizeAdjust(nsACString& aResult) {
GetDesc(eCSSFontDesc_SizeAdjust, aResult);
mImpl->GetSizeAdjust(aResult);
}
void FontFace::SetSizeAdjust(const nsACString& aValue, ErrorResult& aRv) {
if (SetDescriptor(eCSSFontDesc_SizeAdjust, aValue, aRv)) {
DescriptorUpdated();
}
mImpl->SetSizeAdjust(aValue, aRv);
}
void FontFace::DescriptorUpdated() {
// If we haven't yet initialized mUserFontEntry, no need to do anything here;
// we'll respect the updated descriptor when the time comes to create it.
if (!mUserFontEntry) {
return;
}
// Behind the scenes, this will actually update the existing entry and return
// it, rather than create a new one.
RefPtr<gfxUserFontEntry> newEntry =
mFontFaceSet->FindOrCreateUserFontEntryFromFontFace(this);
SetUserFontEntry(newEntry);
if (mInFontFaceSet) {
mFontFaceSet->MarkUserFontSetDirty();
}
for (auto& set : mOtherFontFaceSets) {
set->MarkUserFontSetDirty();
}
}
FontFaceLoadStatus FontFace::Status() { return mStatus; }
FontFaceLoadStatus FontFace::Status() { return mImpl->Status(); }
Promise* FontFace::Load(ErrorResult& aRv) {
MOZ_ASSERT(NS_IsMainThread());
mFontFaceSet->FlushUserFontSet();
EnsurePromise();
if (!mLoaded) {
@@ -384,47 +216,10 @@ Promise* FontFace::Load(ErrorResult& aRv) {
return nullptr;
}
// Calling Load on a FontFace constructed with an ArrayBuffer data source,
// or on one that is already loading (or has finished loading), has no
// effect.
if (mSourceType == eSourceType_Buffer ||
mStatus != FontFaceLoadStatus::Unloaded) {
return mLoaded;
}
// Calling the user font entry's Load method will end up setting our
// status to Loading, but the spec requires us to set it to Loading
// here.
SetStatus(FontFaceLoadStatus::Loading);
DoLoad();
mImpl->Load(aRv);
return mLoaded;
}
gfxUserFontEntry* FontFace::CreateUserFontEntry() {
if (!mUserFontEntry) {
MOZ_ASSERT(!HasRule(),
"Rule backed FontFace objects should already have a user font "
"entry by the time Load() can be called on them");
RefPtr<gfxUserFontEntry> newEntry =
mFontFaceSet->FindOrCreateUserFontEntryFromFontFace(this);
if (newEntry) {
SetUserFontEntry(newEntry);
}
}
return mUserFontEntry;
}
void FontFace::DoLoad() {
if (!CreateUserFontEntry()) {
return;
}
mUserFontEntry->Load();
}
Promise* FontFace::GetLoaded(ErrorResult& aRv) {
MOZ_ASSERT(NS_IsMainThread());
@@ -438,48 +233,13 @@ Promise* FontFace::GetLoaded(ErrorResult& aRv) {
return mLoaded;
}
void FontFace::SetStatus(FontFaceLoadStatus aStatus) {
void FontFace::MaybeResolve() {
AssertIsMainThreadOrServoFontMetricsLocked();
if (mStatus == aStatus) {
if (!mLoaded) {
return;
}
if (aStatus < mStatus) {
// We're being asked to go backwards in status! Normally, this shouldn't
// happen. But it can if the FontFace had a user font entry that had
// loaded, but then was given a new one by FontFaceSet::InsertRuleFontFace
// if we used a local() rule. For now, just ignore the request to
// go backwards in status.
return;
}
mStatus = aStatus;
if (mInFontFaceSet) {
mFontFaceSet->OnFontFaceStatusChanged(this);
}
for (FontFaceSet* otherSet : mOtherFontFaceSets) {
otherSet->OnFontFaceStatusChanged(this);
}
if (mStatus == FontFaceLoadStatus::Loaded) {
if (mLoaded) {
DoResolve();
}
} else if (mStatus == FontFaceLoadStatus::Error) {
if (mSourceType == eSourceType_Buffer) {
Reject(NS_ERROR_DOM_SYNTAX_ERR);
} else {
Reject(NS_ERROR_DOM_NETWORK_ERR);
}
}
}
void FontFace::DoResolve() {
AssertIsMainThreadOrServoFontMetricsLocked();
if (ServoStyleSet* ss = ServoStyleSet::Current()) {
// See comments in Gecko_GetFontMetrics.
ss->AppendTask(PostTraversalTask::ResolveFontFaceLoadedPromise(this));
@@ -489,7 +249,7 @@ void FontFace::DoResolve() {
mLoaded->MaybeResolve(this);
}
void FontFace::DoReject(nsresult aResult) {
void FontFace::MaybeReject(nsresult aResult) {
AssertIsMainThreadOrServoFontMetricsLocked();
if (ServoStyleSet* ss = ServoStyleSet::Current()) {
@@ -499,7 +259,11 @@ void FontFace::DoReject(nsresult aResult) {
return;
}
mLoaded->MaybeReject(aResult);
if (mLoaded) {
mLoaded->MaybeReject(aResult);
} else if (mLoadedRejection == NS_OK) {
mLoadedRejection = aResult;
}
}
already_AddRefed<URLExtraData> FontFace::GetURLExtraData() const {
@@ -519,306 +283,10 @@ already_AddRefed<URLExtraData> FontFace::GetURLExtraData() const {
return url.forget();
}
// Boolean result indicates whether the value of the descriptor was actually
// changed.
bool FontFace::SetDescriptor(nsCSSFontDesc aFontDesc, const nsACString& aValue,
ErrorResult& aRv) {
// FIXME We probably don't need to distinguish between this anymore
// since we have common backend now.
NS_ASSERTION(!HasRule(), "we don't handle rule backed FontFace objects yet");
if (HasRule()) {
return false;
}
// FIXME(heycam): Should not allow modification of FontFaces that are
// CSS-connected and whose rule is read only.
RefPtr<URLExtraData> url = GetURLExtraData();
bool changed;
if (!Servo_FontFaceRule_SetDescriptor(GetData(), aFontDesc, &aValue, url,
&changed)) {
aRv.ThrowSyntaxError("Invalid font descriptor");
return false;
}
if (!changed) {
return false;
}
if (aFontDesc == eCSSFontDesc_UnicodeRange) {
mUnicodeRangeDirty = true;
}
return true;
}
bool FontFace::SetDescriptors(const nsACString& aFamily,
const FontFaceDescriptors& aDescriptors) {
MOZ_ASSERT(!HasRule());
MOZ_ASSERT(!mDescriptors);
mDescriptors = Servo_FontFaceRule_CreateEmpty().Consume();
// Helper to call SetDescriptor and return true on success, false on failure.
auto setDesc = [=](nsCSSFontDesc aDesc, const nsACString& aVal) -> bool {
IgnoredErrorResult rv;
SetDescriptor(aDesc, aVal, rv);
return !rv.Failed();
};
// Parse all of the mDescriptors in aInitializer, which are the values
// we got from the JS constructor.
if (!setDesc(eCSSFontDesc_Family, aFamily) ||
!setDesc(eCSSFontDesc_Style, aDescriptors.mStyle) ||
!setDesc(eCSSFontDesc_Weight, aDescriptors.mWeight) ||
!setDesc(eCSSFontDesc_Stretch, aDescriptors.mStretch) ||
!setDesc(eCSSFontDesc_UnicodeRange, aDescriptors.mUnicodeRange) ||
!setDesc(eCSSFontDesc_FontFeatureSettings,
aDescriptors.mFeatureSettings) ||
(StaticPrefs::layout_css_font_variations_enabled() &&
!setDesc(eCSSFontDesc_FontVariationSettings,
aDescriptors.mVariationSettings)) ||
!setDesc(eCSSFontDesc_Display, aDescriptors.mDisplay) ||
(StaticPrefs::layout_css_font_metrics_overrides_enabled() &&
(!setDesc(eCSSFontDesc_AscentOverride, aDescriptors.mAscentOverride) ||
!setDesc(eCSSFontDesc_DescentOverride, aDescriptors.mDescentOverride) ||
!setDesc(eCSSFontDesc_LineGapOverride,
aDescriptors.mLineGapOverride))) ||
(StaticPrefs::layout_css_size_adjust_enabled() &&
!setDesc(eCSSFontDesc_SizeAdjust, aDescriptors.mSizeAdjust))) {
// XXX Handle font-variant once we support it (bug 1055385).
// If any of the descriptors failed to parse, none of them should be set
// on the FontFace.
mDescriptors = Servo_FontFaceRule_CreateEmpty().Consume();
Reject(NS_ERROR_DOM_SYNTAX_ERR);
SetStatus(FontFaceLoadStatus::Error);
return false;
}
return true;
}
void FontFace::GetDesc(nsCSSFontDesc aDescID, nsACString& aResult) const {
aResult.Truncate();
Servo_FontFaceRule_GetDescriptorCssText(GetData(), aDescID, &aResult);
// Fill in a default value for missing descriptors.
if (aResult.IsEmpty()) {
if (aDescID == eCSSFontDesc_UnicodeRange) {
aResult.AssignLiteral("U+0-10FFFF");
} else if (aDescID == eCSSFontDesc_Display) {
aResult.AssignLiteral("auto");
} else if (aDescID != eCSSFontDesc_Family && aDescID != eCSSFontDesc_Src) {
aResult.AssignLiteral("normal");
}
}
}
void FontFace::SetUserFontEntry(gfxUserFontEntry* aEntry) {
if (mUserFontEntry) {
mUserFontEntry->mFontFaces.RemoveElement(this);
}
mUserFontEntry = static_cast<Entry*>(aEntry);
if (mUserFontEntry) {
mUserFontEntry->mFontFaces.AppendElement(this);
MOZ_ASSERT(
mUserFontEntry->GetUserFontSet() == mFontFaceSet->GetUserFontSet(),
"user font entry must be associated with the same user font set "
"as the FontFace");
// Our newly assigned user font entry might be in the process of or
// finished loading, so set our status accordingly. But only do so
// if we're not going "backwards" in status, which could otherwise
// happen in this case:
//
// new FontFace("ABC", "url(x)").load();
//
// where the SetUserFontEntry call (from the after-initialization
// DoLoad call) comes after the author's call to load(), which set mStatus
// to Loading.
FontFaceLoadStatus newStatus =
LoadStateToStatus(mUserFontEntry->LoadState());
if (newStatus > mStatus) {
SetStatus(newStatus);
}
}
}
Maybe<StyleComputedFontWeightRange> FontFace::GetFontWeight() const {
StyleComputedFontWeightRange range;
if (!Servo_FontFaceRule_GetFontWeight(GetData(), &range)) {
return Nothing();
}
return Some(range);
}
Maybe<StyleComputedFontStretchRange> FontFace::GetFontStretch() const {
StyleComputedFontStretchRange range;
if (!Servo_FontFaceRule_GetFontStretch(GetData(), &range)) {
return Nothing();
}
return Some(range);
}
Maybe<StyleComputedFontStyleDescriptor> FontFace::GetFontStyle() const {
auto descriptor = StyleComputedFontStyleDescriptor::Normal();
if (!Servo_FontFaceRule_GetFontStyle(GetData(), &descriptor)) {
return Nothing();
}
return Some(descriptor);
}
Maybe<StyleFontDisplay> FontFace::GetFontDisplay() const {
StyleFontDisplay display;
if (!Servo_FontFaceRule_GetFontDisplay(GetData(), &display)) {
return Nothing();
}
return Some(display);
}
Maybe<StyleFontLanguageOverride> FontFace::GetFontLanguageOverride() const {
StyleFontLanguageOverride langOverride;
if (!Servo_FontFaceRule_GetFontLanguageOverride(GetData(), &langOverride)) {
return Nothing();
}
return Some(langOverride);
}
Maybe<StylePercentage> FontFace::GetAscentOverride() const {
StylePercentage ascent{0};
if (!Servo_FontFaceRule_GetAscentOverride(GetData(), &ascent)) {
return Nothing();
}
return Some(ascent);
}
Maybe<StylePercentage> FontFace::GetDescentOverride() const {
StylePercentage descent{0};
if (!Servo_FontFaceRule_GetDescentOverride(GetData(), &descent)) {
return Nothing();
}
return Some(descent);
}
Maybe<StylePercentage> FontFace::GetLineGapOverride() const {
StylePercentage lineGap{0};
if (!Servo_FontFaceRule_GetLineGapOverride(GetData(), &lineGap)) {
return Nothing();
}
return Some(lineGap);
}
Maybe<StylePercentage> FontFace::GetSizeAdjust() const {
StylePercentage sizeAdjust;
if (!Servo_FontFaceRule_GetSizeAdjust(GetData(), &sizeAdjust)) {
return Nothing();
}
return Some(sizeAdjust);
}
bool FontFace::HasLocalSrc() const {
AutoTArray<StyleFontFaceSourceListComponent, 8> components;
GetSources(components);
for (auto& component : components) {
if (component.tag == StyleFontFaceSourceListComponent::Tag::Local) {
return true;
}
}
return false;
}
void FontFace::GetFontFeatureSettings(
nsTArray<gfxFontFeature>& aFeatures) const {
Servo_FontFaceRule_GetFeatureSettings(GetData(), &aFeatures);
}
void FontFace::GetFontVariationSettings(
nsTArray<gfxFontVariation>& aVariations) const {
Servo_FontFaceRule_GetVariationSettings(GetData(), &aVariations);
}
void FontFace::GetSources(
nsTArray<StyleFontFaceSourceListComponent>& aSources) const {
Servo_FontFaceRule_GetSources(GetData(), &aSources);
}
nsAtom* FontFace::GetFamilyName() const {
return Servo_FontFaceRule_GetFamilyName(GetData());
}
void FontFace::DisconnectFromRule() {
MOZ_ASSERT(HasRule());
// Make a copy of the descriptors.
mDescriptors = Servo_FontFaceRule_Clone(mRule).Consume();
mRule = nullptr;
mInFontFaceSet = false;
}
bool FontFace::HasFontData() const {
return mSourceType == eSourceType_Buffer && mSourceBuffer;
}
void FontFace::TakeBuffer(uint8_t*& aBuffer, uint32_t& aLength) {
MOZ_ASSERT(HasFontData());
aBuffer = mSourceBuffer;
aLength = mSourceBufferLength;
mSourceBuffer = nullptr;
mSourceBufferLength = 0;
}
already_AddRefed<gfxFontFaceBufferSource> FontFace::CreateBufferSource() {
RefPtr<FontFaceBufferSource> bufferSource = new FontFaceBufferSource(this);
return bufferSource.forget();
}
bool FontFace::IsInFontFaceSet(FontFaceSet* aFontFaceSet) const {
if (mFontFaceSet == aFontFaceSet) {
return mInFontFaceSet;
}
return mOtherFontFaceSets.Contains(aFontFaceSet);
}
void FontFace::AddFontFaceSet(FontFaceSet* aFontFaceSet) {
MOZ_ASSERT(!IsInFontFaceSet(aFontFaceSet));
if (mFontFaceSet == aFontFaceSet) {
mInFontFaceSet = true;
} else {
mOtherFontFaceSets.AppendElement(aFontFaceSet);
}
}
void FontFace::RemoveFontFaceSet(FontFaceSet* aFontFaceSet) {
MOZ_ASSERT(IsInFontFaceSet(aFontFaceSet));
if (mFontFaceSet == aFontFaceSet) {
mInFontFaceSet = false;
} else {
mOtherFontFaceSets.RemoveElement(aFontFaceSet);
}
}
void FontFace::Reject(nsresult aResult) {
AssertIsMainThreadOrServoFontMetricsLocked();
if (mLoaded) {
DoReject(aResult);
} else if (mLoadedRejection == NS_OK) {
mLoadedRejection = aResult;
}
}
void FontFace::EnsurePromise() {
MOZ_ASSERT(NS_IsMainThread());
if (mLoaded) {
if (mLoaded || !mImpl) {
return;
}
@@ -831,7 +299,7 @@ void FontFace::EnsurePromise() {
ErrorResult rv;
mLoaded = Promise::Create(global, rv);
if (mStatus == FontFaceLoadStatus::Loaded) {
if (mImpl->Status() == FontFaceLoadStatus::Loaded) {
mLoaded->MaybeResolve(this);
} else if (mLoadedRejection != NS_OK) {
mLoaded->MaybeReject(mLoadedRejection);
@@ -839,64 +307,5 @@ void FontFace::EnsurePromise() {
}
}
gfxCharacterMap* FontFace::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()) {
RefPtr<gfxCharacterMap> charMap = new 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;
}
mUnicodeRangeDirty = false;
return mUnicodeRange;
}
// -- FontFace::Entry --------------------------------------------------------
/* virtual */
void FontFace::Entry::SetLoadState(UserFontLoadState aLoadState) {
gfxUserFontEntry::SetLoadState(aLoadState);
for (size_t i = 0; i < mFontFaces.Length(); i++) {
mFontFaces[i]->SetStatus(LoadStateToStatus(aLoadState));
}
}
/* virtual */
void FontFace::Entry::GetUserFontSets(nsTArray<gfxUserFontSet*>& aResult) {
aResult.Clear();
for (FontFace* f : mFontFaces) {
if (f->mInFontFaceSet) {
aResult.AppendElement(f->mFontFaceSet->GetUserFontSet());
}
for (FontFaceSet* s : f->mOtherFontFaceSets) {
aResult.AppendElement(s->GetUserFontSet());
}
}
// Remove duplicates.
aResult.Sort();
auto it = std::unique(aResult.begin(), aResult.end());
aResult.TruncateLength(it - aResult.begin());
}
} // namespace dom
} // namespace mozilla

View File

@@ -26,7 +26,9 @@ namespace dom {
class CSSFontFaceRule;
class FontFaceBufferSource;
struct FontFaceDescriptors;
class FontFaceImpl;
class FontFaceSet;
class FontFaceSetImpl;
class Promise;
class UTF8StringOrArrayBufferOrArrayBufferView;
} // namespace dom
@@ -36,41 +38,8 @@ namespace mozilla::dom {
class FontFace final : public nsISupports, public nsWrapperCache {
friend class mozilla::PostTraversalTask;
friend class FontFaceBufferSource;
friend class Entry;
public:
class Entry final : public gfxUserFontEntry {
friend class FontFace;
public:
Entry(gfxUserFontSet* aFontSet,
const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList, WeightRange aWeight,
StretchRange aStretch, SlantStyleRange aStyle,
const nsTArray<gfxFontFeature>& aFeatureSettings,
const nsTArray<gfxFontVariation>& aVariationSettings,
uint32_t aLanguageOverride, gfxCharacterMap* aUnicodeRanges,
StyleFontDisplay aFontDisplay, RangeFlags aRangeFlags,
float aAscentOverride, float aDescentOverride, float aLineGapOverride,
float aSizeAdjust)
: gfxUserFontEntry(aFontSet, aFontFaceSrcList, aWeight, aStretch,
aStyle, aFeatureSettings, aVariationSettings,
aLanguageOverride, aUnicodeRanges, aFontDisplay,
aRangeFlags, aAscentOverride, aDescentOverride,
aLineGapOverride, aSizeAdjust) {}
virtual void SetLoadState(UserFontLoadState aLoadState) override;
virtual void GetUserFontSets(nsTArray<gfxUserFontSet*>& aResult) override;
const AutoTArray<FontFace*, 1>& GetFontFaces() { return mFontFaces; }
protected:
// The FontFace objects that use this user font entry. We need to store
// an array of these, not just a single pointer, since the user font
// cache can return the same entry for different FontFaces that have
// the same descriptor values and come from the same origin.
AutoTArray<FontFace*, 1> mFontFaces;
};
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(FontFace)
@@ -82,77 +51,6 @@ class FontFace final : public nsISupports, public nsWrapperCache {
FontFaceSet* aFontFaceSet,
RawServoFontFaceRule* aRule);
RawServoFontFaceRule* GetRule() { return mRule; }
bool HasLocalSrc() const;
Maybe<StyleComputedFontWeightRange> GetFontWeight() const;
Maybe<StyleComputedFontStretchRange> GetFontStretch() const;
Maybe<StyleComputedFontStyleDescriptor> GetFontStyle() const;
Maybe<StyleFontDisplay> GetFontDisplay() const;
void GetFontFeatureSettings(nsTArray<gfxFontFeature>&) const;
void GetFontVariationSettings(nsTArray<gfxFontVariation>&) const;
void GetSources(nsTArray<StyleFontFaceSourceListComponent>&) const;
Maybe<StyleFontLanguageOverride> GetFontLanguageOverride() const;
Maybe<StylePercentage> GetAscentOverride() const;
Maybe<StylePercentage> GetDescentOverride() const;
Maybe<StylePercentage> GetLineGapOverride() const;
Maybe<StylePercentage> GetSizeAdjust() const;
gfxUserFontEntry* CreateUserFontEntry();
gfxUserFontEntry* GetUserFontEntry() const { return mUserFontEntry; }
void SetUserFontEntry(gfxUserFontEntry* aEntry);
/**
* Returns whether this object is in the specified FontFaceSet.
*/
bool IsInFontFaceSet(FontFaceSet* aFontFaceSet) const;
void AddFontFaceSet(FontFaceSet* aFontFaceSet);
void RemoveFontFaceSet(FontFaceSet* aFontFaceSet);
FontFaceSet* GetPrimaryFontFaceSet() const { return mFontFaceSet; }
/**
* Gets the family name of the FontFace as a raw string (such as 'Times', as
* opposed to GetFamily, which returns a CSS-escaped string, such as
* '"Times"'). Returns null if a valid family name was not available.
*/
nsAtom* GetFamilyName() const;
/**
* Returns whether this object is CSS-connected, i.e. reflecting an
* @font-face rule.
*/
bool HasRule() const { return mRule; }
/**
* Breaks the connection between this FontFace and its @font-face rule.
*/
void DisconnectFromRule();
/**
* Returns whether there is an ArrayBuffer or ArrayBufferView of font
* data.
*/
bool HasFontData() const;
/**
* Creates a gfxFontFaceBufferSource to represent the font data
* in this object.
*/
already_AddRefed<gfxFontFaceBufferSource> CreateBufferSource();
/**
* Gets a pointer to and the length of the font data stored in the
* ArrayBuffer or ArrayBufferView.
*/
bool GetData(uint8_t*& aBuffer, uint32_t& aLength);
/**
* Returns the value of the unicode-range descriptor as a gfxCharacterMap.
*/
gfxCharacterMap* GetUnicodeRangeAsCharacterMap();
// Web IDL
static already_AddRefed<FontFace> Constructor(
const GlobalObject& aGlobal, const nsACString& aFamily,
@@ -190,66 +88,31 @@ class FontFace final : public nsISupports, public nsWrapperCache {
Promise* Load(ErrorResult& aRv);
Promise* GetLoaded(ErrorResult& aRv);
private:
FontFace(nsISupports* aParent, FontFaceSet* aFontFaceSet);
~FontFace();
FontFaceImpl* GetImpl() const { return mImpl; }
void InitializeSource(const UTF8StringOrArrayBufferOrArrayBufferView&);
// Helper function for Load.
void DoLoad();
// Helper function for the descriptor setter methods.
// Returns true if the descriptor was modified, false if descriptor is
// unchanged (which may not be an error: check aRv for actual failure).
bool SetDescriptor(nsCSSFontDesc aFontDesc, const nsACString& aValue,
ErrorResult& aRv);
/**
* Sets all of the descriptor values in mDescriptors using values passed
* to the JS constructor.
* Returns true on success, false if parsing any descriptor failed.
*/
bool SetDescriptors(const nsACString& aFamily,
const FontFaceDescriptors& aDescriptors);
/**
* Called when a descriptor has been modified, so font-face sets can
* be told to refresh.
*/
void DescriptorUpdated();
/**
* Sets the current loading status.
*/
void SetStatus(FontFaceLoadStatus aStatus);
void GetDesc(nsCSSFontDesc aDescID, nsACString& aResult) const;
void Destroy();
void MaybeResolve();
void MaybeReject(nsresult aResult);
already_AddRefed<URLExtraData> GetURLExtraData() const;
RawServoFontFaceRule* GetData() const {
return HasRule() ? mRule : mDescriptors;
}
private:
explicit FontFace(nsISupports* aParent);
~FontFace();
/**
* Returns and takes ownership of the buffer storing the font data.
*/
void TakeBuffer(uint8_t*& aBuffer, uint32_t& aLength);
// Acts like mLoaded->MaybeReject(aResult), except it doesn't create mLoaded
// if it doesn't already exist.
void Reject(nsresult aResult);
// Creates mLoaded if it doesn't already exist. It may immediately resolve or
// reject mLoaded based on mStatus and mLoadedRejection.
void EnsurePromise();
void DoResolve();
void DoReject(nsresult aResult);
nsCOMPtr<nsISupports> mParent;
RefPtr<FontFaceImpl> mImpl;
// A Promise that is fulfilled once the font represented by this FontFace is
// loaded, and is rejected if the load fails. This promise is created lazily
// when JS asks for it.
@@ -257,62 +120,6 @@ class FontFace final : public nsISupports, public nsWrapperCache {
// Saves the rejection code for mLoaded if mLoaded hasn't been created yet.
nsresult mLoadedRejection;
// The @font-face rule this FontFace object is reflecting, if it is a
// rule backed FontFace.
RefPtr<RawServoFontFaceRule> mRule;
// The FontFace object's user font entry. This is initially null, but is set
// during FontFaceSet::UpdateRules and when a FontFace is explicitly loaded.
RefPtr<Entry> mUserFontEntry;
// The current load status of the font represented by this FontFace.
// Note that we can't just reflect the value of the gfxUserFontEntry's
// status, since the spec sometimes requires us to go through the event
// loop before updating the status, rather than doing it immediately.
FontFaceLoadStatus mStatus;
// Represents where a FontFace's data is coming from.
enum SourceType {
eSourceType_FontFaceRule = 1,
eSourceType_URLs,
eSourceType_Buffer
};
// Where the font data for this FontFace is coming from.
SourceType mSourceType;
// If the FontFace was constructed with an ArrayBuffer(View), this is a
// copy of the data from it.
uint8_t* mSourceBuffer;
uint32_t mSourceBufferLength;
// The values corresponding to the font face descriptors, if we are not
// a rule backed FontFace object. For rule backed objects, we use
// the descriptors stored in mRule.
// FIXME This should hold a unique ptr to just the descriptors inside,
// so that we don't need to create a rule for it and don't need to
// assign a fake line number and column number. See bug 1450904.
RefPtr<RawServoFontFaceRule> mDescriptors;
// The value of the unicode-range descriptor as a gfxCharacterMap. Valid
// only when mUnicodeRangeDirty is false.
RefPtr<gfxCharacterMap> mUnicodeRange;
// The primary FontFaceSet this FontFace is associated with,
// regardless of whether it is currently "in" the set.
RefPtr<FontFaceSet> mFontFaceSet;
// Other FontFaceSets (apart from mFontFaceSet) that this FontFace
// appears in.
nsTArray<RefPtr<FontFaceSet>> mOtherFontFaceSets;
// Whether mUnicodeRange needs to be rebuilt before being returned from
// GetUnicodeRangeAsCharacterMap.
bool mUnicodeRangeDirty;
// Whether this FontFace appears in mFontFaceSet.
bool mInFontFaceSet;
};
} // namespace mozilla::dom

View File

@@ -0,0 +1,761 @@
/* -*- 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 "mozilla/dom/FontFaceImpl.h"
#include <algorithm>
#include "gfxPlatformFontList.h"
#include "mozilla/dom/CSSFontFaceRule.h"
#include "mozilla/dom/FontFaceBinding.h"
#include "mozilla/dom/FontFaceSetImpl.h"
#include "mozilla/dom/TypedArray.h"
#include "mozilla/dom/UnionTypes.h"
#include "mozilla/ServoBindings.h"
#include "mozilla/ServoCSSParser.h"
#include "mozilla/ServoStyleSet.h"
#include "mozilla/ServoUtils.h"
#include "mozilla/StaticPrefs_layout.h"
#include "mozilla/dom/Document.h"
#include "nsStyleUtil.h"
namespace mozilla {
namespace dom {
// -- FontFaceBufferSource ---------------------------------------------------
/**
* An object that wraps a FontFace object and exposes its ArrayBuffer
* or ArrayBufferView data in a form the user font set can consume.
*/
class FontFaceBufferSource : public gfxFontFaceBufferSource {
public:
explicit FontFaceBufferSource(FontFaceImpl* aFontFace)
: mFontFace(aFontFace) {}
virtual void TakeBuffer(uint8_t*& aBuffer, uint32_t& aLength) override;
private:
RefPtr<FontFaceImpl> mFontFace;
};
void FontFaceBufferSource::TakeBuffer(uint8_t*& aBuffer, uint32_t& aLength) {
MOZ_ASSERT(mFontFace,
"only call TakeBuffer once on a given "
"FontFaceBufferSource object");
mFontFace->TakeBuffer(aBuffer, aLength);
mFontFace = nullptr;
}
// -- Utility functions ------------------------------------------------------
template <typename T>
static void GetDataFrom(const T& aObject, uint8_t*& aBuffer,
uint32_t& aLength) {
MOZ_ASSERT(!aBuffer);
aObject.ComputeState();
// We use malloc here rather than a FallibleTArray or fallible
// operator new[] since the gfxUserFontEntry will be calling free
// on it.
aBuffer = (uint8_t*)malloc(aObject.Length());
if (!aBuffer) {
return;
}
memcpy((void*)aBuffer, aObject.Data(), aObject.Length());
aLength = aObject.Length();
}
// -- FontFaceImpl -----------------------------------------------------------
FontFaceImpl::FontFaceImpl(FontFace* aOwner, FontFaceSetImpl* aFontFaceSet)
: mOwner(aOwner),
mStatus(FontFaceLoadStatus::Unloaded),
mSourceType(SourceType(0)),
mSourceBuffer(nullptr),
mSourceBufferLength(0),
mFontFaceSet(aFontFaceSet),
mUnicodeRangeDirty(true),
mInFontFaceSet(false) {}
FontFaceImpl::~FontFaceImpl() {
// Assert that we don't drop any FontFace objects during a Servo traversal,
// since PostTraversalTask objects can hold raw pointers to FontFaces.
MOZ_ASSERT(!ServoStyleSet::IsInServoTraversal());
SetUserFontEntry(nullptr);
if (mSourceBuffer) {
free(mSourceBuffer);
}
}
void FontFaceImpl::Destroy() {
mInFontFaceSet = false;
SetUserFontEntry(nullptr);
mOwner = nullptr;
}
static FontFaceLoadStatus LoadStateToStatus(
gfxUserFontEntry::UserFontLoadState aLoadState) {
switch (aLoadState) {
case gfxUserFontEntry::UserFontLoadState::STATUS_NOT_LOADED:
return FontFaceLoadStatus::Unloaded;
case gfxUserFontEntry::UserFontLoadState::STATUS_LOAD_PENDING:
case gfxUserFontEntry::UserFontLoadState::STATUS_LOADING:
return FontFaceLoadStatus::Loading;
case gfxUserFontEntry::UserFontLoadState::STATUS_LOADED:
return FontFaceLoadStatus::Loaded;
case gfxUserFontEntry::UserFontLoadState::STATUS_FAILED:
return FontFaceLoadStatus::Error;
}
MOZ_ASSERT_UNREACHABLE("invalid aLoadState value");
return FontFaceLoadStatus::Error;
}
already_AddRefed<FontFaceImpl> FontFaceImpl::CreateForRule(
FontFace* aOwner, FontFaceSetImpl* aFontFaceSet,
RawServoFontFaceRule* aRule) {
RefPtr<FontFaceImpl> obj = new FontFaceImpl(aOwner, aFontFaceSet);
obj->mRule = aRule;
obj->mSourceType = eSourceType_FontFaceRule;
obj->mInFontFaceSet = true;
return obj.forget();
}
void FontFaceImpl::InitializeSource(
const UTF8StringOrArrayBufferOrArrayBufferView& aSource) {
if (aSource.IsUTF8String()) {
IgnoredErrorResult rv;
SetDescriptor(eCSSFontDesc_Src, aSource.GetAsUTF8String(), rv);
if (rv.Failed()) {
if (mOwner) {
mOwner->MaybeReject(NS_ERROR_DOM_SYNTAX_ERR);
}
SetStatus(FontFaceLoadStatus::Error);
return;
}
mSourceType = eSourceType_URLs;
return;
}
mSourceType = FontFaceImpl::eSourceType_Buffer;
if (aSource.IsArrayBuffer()) {
GetDataFrom(aSource.GetAsArrayBuffer(), mSourceBuffer, mSourceBufferLength);
} else {
MOZ_ASSERT(aSource.IsArrayBufferView());
GetDataFrom(aSource.GetAsArrayBufferView(), mSourceBuffer,
mSourceBufferLength);
}
SetStatus(FontFaceLoadStatus::Loading);
DoLoad();
}
void FontFaceImpl::GetFamily(nsACString& aResult) {
GetDesc(eCSSFontDesc_Family, aResult);
}
void FontFaceImpl::SetFamily(const nsACString& aValue, ErrorResult& aRv) {
mFontFaceSet->FlushUserFontSet();
if (SetDescriptor(eCSSFontDesc_Family, aValue, aRv)) {
DescriptorUpdated();
}
}
void FontFaceImpl::GetStyle(nsACString& aResult) {
GetDesc(eCSSFontDesc_Style, aResult);
}
void FontFaceImpl::SetStyle(const nsACString& aValue, ErrorResult& aRv) {
if (SetDescriptor(eCSSFontDesc_Style, aValue, aRv)) {
DescriptorUpdated();
}
}
void FontFaceImpl::GetWeight(nsACString& aResult) {
GetDesc(eCSSFontDesc_Weight, aResult);
}
void FontFaceImpl::SetWeight(const nsACString& aValue, ErrorResult& aRv) {
mFontFaceSet->FlushUserFontSet();
if (SetDescriptor(eCSSFontDesc_Weight, aValue, aRv)) {
DescriptorUpdated();
}
}
void FontFaceImpl::GetStretch(nsACString& aResult) {
GetDesc(eCSSFontDesc_Stretch, aResult);
}
void FontFaceImpl::SetStretch(const nsACString& aValue, ErrorResult& aRv) {
mFontFaceSet->FlushUserFontSet();
if (SetDescriptor(eCSSFontDesc_Stretch, aValue, aRv)) {
DescriptorUpdated();
}
}
void FontFaceImpl::GetUnicodeRange(nsACString& aResult) {
GetDesc(eCSSFontDesc_UnicodeRange, aResult);
}
void FontFaceImpl::SetUnicodeRange(const nsACString& aValue, ErrorResult& aRv) {
mFontFaceSet->FlushUserFontSet();
if (SetDescriptor(eCSSFontDesc_UnicodeRange, aValue, aRv)) {
DescriptorUpdated();
}
}
void FontFaceImpl::GetVariant(nsACString& aResult) {
// XXX Just expose the font-variant descriptor as "normal" until we
// support it properly (bug 1055385).
aResult.AssignLiteral("normal");
}
void FontFaceImpl::SetVariant(const nsACString& aValue, ErrorResult& aRv) {
// XXX Ignore assignments to variant until we support font-variant
// descriptors (bug 1055385).
}
void FontFaceImpl::GetFeatureSettings(nsACString& aResult) {
GetDesc(eCSSFontDesc_FontFeatureSettings, aResult);
}
void FontFaceImpl::SetFeatureSettings(const nsACString& aValue,
ErrorResult& aRv) {
mFontFaceSet->FlushUserFontSet();
if (SetDescriptor(eCSSFontDesc_FontFeatureSettings, aValue, aRv)) {
DescriptorUpdated();
}
}
void FontFaceImpl::GetVariationSettings(nsACString& aResult) {
GetDesc(eCSSFontDesc_FontVariationSettings, aResult);
}
void FontFaceImpl::SetVariationSettings(const nsACString& aValue,
ErrorResult& aRv) {
mFontFaceSet->FlushUserFontSet();
if (SetDescriptor(eCSSFontDesc_FontVariationSettings, aValue, aRv)) {
DescriptorUpdated();
}
}
void FontFaceImpl::GetDisplay(nsACString& aResult) {
GetDesc(eCSSFontDesc_Display, aResult);
}
void FontFaceImpl::SetDisplay(const nsACString& aValue, ErrorResult& aRv) {
if (SetDescriptor(eCSSFontDesc_Display, aValue, aRv)) {
DescriptorUpdated();
}
}
void FontFaceImpl::GetAscentOverride(nsACString& aResult) {
GetDesc(eCSSFontDesc_AscentOverride, aResult);
}
void FontFaceImpl::SetAscentOverride(const nsACString& aValue,
ErrorResult& aRv) {
if (SetDescriptor(eCSSFontDesc_AscentOverride, aValue, aRv)) {
DescriptorUpdated();
}
}
void FontFaceImpl::GetDescentOverride(nsACString& aResult) {
GetDesc(eCSSFontDesc_DescentOverride, aResult);
}
void FontFaceImpl::SetDescentOverride(const nsACString& aValue,
ErrorResult& aRv) {
if (SetDescriptor(eCSSFontDesc_DescentOverride, aValue, aRv)) {
DescriptorUpdated();
}
}
void FontFaceImpl::GetLineGapOverride(nsACString& aResult) {
GetDesc(eCSSFontDesc_LineGapOverride, aResult);
}
void FontFaceImpl::SetLineGapOverride(const nsACString& aValue,
ErrorResult& aRv) {
if (SetDescriptor(eCSSFontDesc_LineGapOverride, aValue, aRv)) {
DescriptorUpdated();
}
}
void FontFaceImpl::GetSizeAdjust(nsACString& aResult) {
GetDesc(eCSSFontDesc_SizeAdjust, aResult);
}
void FontFaceImpl::SetSizeAdjust(const nsACString& aValue, ErrorResult& aRv) {
if (SetDescriptor(eCSSFontDesc_SizeAdjust, aValue, aRv)) {
DescriptorUpdated();
}
}
void FontFaceImpl::DescriptorUpdated() {
// If we haven't yet initialized mUserFontEntry, no need to do anything here;
// we'll respect the updated descriptor when the time comes to create it.
if (!mUserFontEntry) {
return;
}
// Behind the scenes, this will actually update the existing entry and return
// it, rather than create a new one.
RefPtr<gfxUserFontEntry> newEntry =
mFontFaceSet->FindOrCreateUserFontEntryFromFontFace(this);
SetUserFontEntry(newEntry);
if (mInFontFaceSet) {
mFontFaceSet->MarkUserFontSetDirty();
}
for (auto& set : mOtherFontFaceSets) {
set->MarkUserFontSetDirty();
}
}
FontFaceLoadStatus FontFaceImpl::Status() { return mStatus; }
void FontFaceImpl::Load(ErrorResult& aRv) {
MOZ_ASSERT(NS_IsMainThread());
mFontFaceSet->FlushUserFontSet();
// Calling Load on a FontFace constructed with an ArrayBuffer data source,
// or on one that is already loading (or has finished loading), has no
// effect.
if (mSourceType == eSourceType_Buffer ||
mStatus != FontFaceLoadStatus::Unloaded) {
return;
}
// Calling the user font entry's Load method will end up setting our
// status to Loading, but the spec requires us to set it to Loading
// here.
SetStatus(FontFaceLoadStatus::Loading);
DoLoad();
}
gfxUserFontEntry* FontFaceImpl::CreateUserFontEntry() {
if (!mUserFontEntry) {
MOZ_ASSERT(!HasRule(),
"Rule backed FontFace objects should already have a user font "
"entry by the time Load() can be called on them");
RefPtr<gfxUserFontEntry> newEntry =
mFontFaceSet->FindOrCreateUserFontEntryFromFontFace(this);
if (newEntry) {
SetUserFontEntry(newEntry);
}
}
return mUserFontEntry;
}
void FontFaceImpl::DoLoad() {
if (!CreateUserFontEntry()) {
return;
}
mUserFontEntry->Load();
}
void FontFaceImpl::SetStatus(FontFaceLoadStatus aStatus) {
AssertIsMainThreadOrServoFontMetricsLocked();
if (mStatus == aStatus) {
return;
}
if (aStatus < mStatus) {
// We're being asked to go backwards in status! Normally, this shouldn't
// happen. But it can if the FontFace had a user font entry that had
// loaded, but then was given a new one by FontFaceSet::InsertRuleFontFace
// if we used a local() rule. For now, just ignore the request to
// go backwards in status.
return;
}
mStatus = aStatus;
if (mInFontFaceSet) {
mFontFaceSet->OnFontFaceStatusChanged(this);
}
for (FontFaceSetImpl* otherSet : mOtherFontFaceSets) {
otherSet->OnFontFaceStatusChanged(this);
}
if (NS_WARN_IF(!mOwner)) {
return;
}
if (mStatus == FontFaceLoadStatus::Loaded) {
mOwner->MaybeResolve();
} else if (mStatus == FontFaceLoadStatus::Error) {
if (mSourceType == eSourceType_Buffer) {
mOwner->MaybeReject(NS_ERROR_DOM_SYNTAX_ERR);
} else {
mOwner->MaybeReject(NS_ERROR_DOM_NETWORK_ERR);
}
}
}
// Boolean result indicates whether the value of the descriptor was actually
// changed.
bool FontFaceImpl::SetDescriptor(nsCSSFontDesc aFontDesc,
const nsACString& aValue, ErrorResult& aRv) {
// FIXME We probably don't need to distinguish between this anymore
// since we have common backend now.
NS_ASSERTION(!HasRule(), "we don't handle rule backed FontFace objects yet");
if (HasRule()) {
return false;
}
if (NS_WARN_IF(!mOwner)) {
return false;
}
// FIXME(heycam): Should not allow modification of FontFaces that are
// CSS-connected and whose rule is read only.
RefPtr<URLExtraData> url = mOwner->GetURLExtraData();
bool changed;
if (!Servo_FontFaceRule_SetDescriptor(GetData(), aFontDesc, &aValue, url,
&changed)) {
aRv.ThrowSyntaxError("Invalid font descriptor");
return false;
}
if (!changed) {
return false;
}
if (aFontDesc == eCSSFontDesc_UnicodeRange) {
mUnicodeRangeDirty = true;
}
return true;
}
bool FontFaceImpl::SetDescriptors(const nsACString& aFamily,
const FontFaceDescriptors& aDescriptors) {
MOZ_ASSERT(!HasRule());
MOZ_ASSERT(!mDescriptors);
mDescriptors = Servo_FontFaceRule_CreateEmpty().Consume();
// Helper to call SetDescriptor and return true on success, false on failure.
auto setDesc = [=](nsCSSFontDesc aDesc, const nsACString& aVal) -> bool {
IgnoredErrorResult rv;
SetDescriptor(aDesc, aVal, rv);
return !rv.Failed();
};
// Parse all of the mDescriptors in aInitializer, which are the values
// we got from the JS constructor.
if (!setDesc(eCSSFontDesc_Family, aFamily) ||
!setDesc(eCSSFontDesc_Style, aDescriptors.mStyle) ||
!setDesc(eCSSFontDesc_Weight, aDescriptors.mWeight) ||
!setDesc(eCSSFontDesc_Stretch, aDescriptors.mStretch) ||
!setDesc(eCSSFontDesc_UnicodeRange, aDescriptors.mUnicodeRange) ||
!setDesc(eCSSFontDesc_FontFeatureSettings,
aDescriptors.mFeatureSettings) ||
(StaticPrefs::layout_css_font_variations_enabled() &&
!setDesc(eCSSFontDesc_FontVariationSettings,
aDescriptors.mVariationSettings)) ||
!setDesc(eCSSFontDesc_Display, aDescriptors.mDisplay) ||
(StaticPrefs::layout_css_font_metrics_overrides_enabled() &&
(!setDesc(eCSSFontDesc_AscentOverride, aDescriptors.mAscentOverride) ||
!setDesc(eCSSFontDesc_DescentOverride, aDescriptors.mDescentOverride) ||
!setDesc(eCSSFontDesc_LineGapOverride,
aDescriptors.mLineGapOverride))) ||
(StaticPrefs::layout_css_size_adjust_enabled() &&
!setDesc(eCSSFontDesc_SizeAdjust, aDescriptors.mSizeAdjust))) {
// XXX Handle font-variant once we support it (bug 1055385).
// If any of the descriptors failed to parse, none of them should be set
// on the FontFace.
mDescriptors = Servo_FontFaceRule_CreateEmpty().Consume();
if (mOwner) {
mOwner->MaybeReject(NS_ERROR_DOM_SYNTAX_ERR);
}
SetStatus(FontFaceLoadStatus::Error);
return false;
}
return true;
}
void FontFaceImpl::GetDesc(nsCSSFontDesc aDescID, nsACString& aResult) const {
aResult.Truncate();
Servo_FontFaceRule_GetDescriptorCssText(GetData(), aDescID, &aResult);
// Fill in a default value for missing descriptors.
if (aResult.IsEmpty()) {
if (aDescID == eCSSFontDesc_UnicodeRange) {
aResult.AssignLiteral("U+0-10FFFF");
} else if (aDescID == eCSSFontDesc_Display) {
aResult.AssignLiteral("auto");
} else if (aDescID != eCSSFontDesc_Family && aDescID != eCSSFontDesc_Src) {
aResult.AssignLiteral("normal");
}
}
}
void FontFaceImpl::SetUserFontEntry(gfxUserFontEntry* aEntry) {
if (mUserFontEntry) {
mUserFontEntry->mFontFaces.RemoveElement(this);
}
mUserFontEntry = static_cast<Entry*>(aEntry);
if (mUserFontEntry) {
mUserFontEntry->mFontFaces.AppendElement(this);
MOZ_ASSERT(
mUserFontEntry->GetUserFontSet() == mFontFaceSet->GetUserFontSet(),
"user font entry must be associated with the same user font set "
"as the FontFace");
// Our newly assigned user font entry might be in the process of or
// finished loading, so set our status accordingly. But only do so
// if we're not going "backwards" in status, which could otherwise
// happen in this case:
//
// new FontFace("ABC", "url(x)").load();
//
// where the SetUserFontEntry call (from the after-initialization
// DoLoad call) comes after the author's call to load(), which set mStatus
// to Loading.
FontFaceLoadStatus newStatus =
LoadStateToStatus(mUserFontEntry->LoadState());
if (newStatus > mStatus) {
SetStatus(newStatus);
}
}
}
Maybe<StyleComputedFontWeightRange> FontFaceImpl::GetFontWeight() const {
StyleComputedFontWeightRange range;
if (!Servo_FontFaceRule_GetFontWeight(GetData(), &range)) {
return Nothing();
}
return Some(range);
}
Maybe<StyleComputedFontStretchRange> FontFaceImpl::GetFontStretch() const {
StyleComputedFontStretchRange range;
if (!Servo_FontFaceRule_GetFontStretch(GetData(), &range)) {
return Nothing();
}
return Some(range);
}
Maybe<StyleComputedFontStyleDescriptor> FontFaceImpl::GetFontStyle() const {
auto descriptor = StyleComputedFontStyleDescriptor::Normal();
if (!Servo_FontFaceRule_GetFontStyle(GetData(), &descriptor)) {
return Nothing();
}
return Some(descriptor);
}
Maybe<StyleFontDisplay> FontFaceImpl::GetFontDisplay() const {
StyleFontDisplay display;
if (!Servo_FontFaceRule_GetFontDisplay(GetData(), &display)) {
return Nothing();
}
return Some(display);
}
Maybe<StyleFontLanguageOverride> FontFaceImpl::GetFontLanguageOverride() const {
StyleFontLanguageOverride langOverride;
if (!Servo_FontFaceRule_GetFontLanguageOverride(GetData(), &langOverride)) {
return Nothing();
}
return Some(langOverride);
}
Maybe<StylePercentage> FontFaceImpl::GetAscentOverride() const {
StylePercentage ascent{0};
if (!Servo_FontFaceRule_GetAscentOverride(GetData(), &ascent)) {
return Nothing();
}
return Some(ascent);
}
Maybe<StylePercentage> FontFaceImpl::GetDescentOverride() const {
StylePercentage descent{0};
if (!Servo_FontFaceRule_GetDescentOverride(GetData(), &descent)) {
return Nothing();
}
return Some(descent);
}
Maybe<StylePercentage> FontFaceImpl::GetLineGapOverride() const {
StylePercentage lineGap{0};
if (!Servo_FontFaceRule_GetLineGapOverride(GetData(), &lineGap)) {
return Nothing();
}
return Some(lineGap);
}
Maybe<StylePercentage> FontFaceImpl::GetSizeAdjust() const {
StylePercentage sizeAdjust;
if (!Servo_FontFaceRule_GetSizeAdjust(GetData(), &sizeAdjust)) {
return Nothing();
}
return Some(sizeAdjust);
}
bool FontFaceImpl::HasLocalSrc() const {
AutoTArray<StyleFontFaceSourceListComponent, 8> components;
GetSources(components);
for (auto& component : components) {
if (component.tag == StyleFontFaceSourceListComponent::Tag::Local) {
return true;
}
}
return false;
}
void FontFaceImpl::GetFontFeatureSettings(
nsTArray<gfxFontFeature>& aFeatures) const {
Servo_FontFaceRule_GetFeatureSettings(GetData(), &aFeatures);
}
void FontFaceImpl::GetFontVariationSettings(
nsTArray<gfxFontVariation>& aVariations) const {
Servo_FontFaceRule_GetVariationSettings(GetData(), &aVariations);
}
void FontFaceImpl::GetSources(
nsTArray<StyleFontFaceSourceListComponent>& aSources) const {
Servo_FontFaceRule_GetSources(GetData(), &aSources);
}
nsAtom* FontFaceImpl::GetFamilyName() const {
return Servo_FontFaceRule_GetFamilyName(GetData());
}
void FontFaceImpl::DisconnectFromRule() {
MOZ_ASSERT(HasRule());
// Make a copy of the descriptors.
mDescriptors = Servo_FontFaceRule_Clone(mRule).Consume();
mRule = nullptr;
mInFontFaceSet = false;
}
bool FontFaceImpl::HasFontData() const {
return mSourceType == eSourceType_Buffer && mSourceBuffer;
}
void FontFaceImpl::TakeBuffer(uint8_t*& aBuffer, uint32_t& aLength) {
MOZ_ASSERT(HasFontData());
aBuffer = mSourceBuffer;
aLength = mSourceBufferLength;
mSourceBuffer = nullptr;
mSourceBufferLength = 0;
}
already_AddRefed<gfxFontFaceBufferSource> FontFaceImpl::CreateBufferSource() {
RefPtr<FontFaceBufferSource> bufferSource = new FontFaceBufferSource(this);
return bufferSource.forget();
}
bool FontFaceImpl::IsInFontFaceSet(FontFaceSetImpl* aFontFaceSet) const {
if (mFontFaceSet == aFontFaceSet) {
return mInFontFaceSet;
}
return mOtherFontFaceSets.Contains(aFontFaceSet);
}
void FontFaceImpl::AddFontFaceSet(FontFaceSetImpl* aFontFaceSet) {
MOZ_ASSERT(!IsInFontFaceSet(aFontFaceSet));
if (mFontFaceSet == aFontFaceSet) {
mInFontFaceSet = true;
} else {
mOtherFontFaceSets.AppendElement(aFontFaceSet);
}
}
void FontFaceImpl::RemoveFontFaceSet(FontFaceSetImpl* aFontFaceSet) {
MOZ_ASSERT(IsInFontFaceSet(aFontFaceSet));
if (mFontFaceSet == aFontFaceSet) {
mInFontFaceSet = false;
} else {
mOtherFontFaceSets.RemoveElement(aFontFaceSet);
}
}
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()) {
RefPtr<gfxCharacterMap> charMap = new 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;
}
mUnicodeRangeDirty = false;
return mUnicodeRange;
}
// -- FontFaceImpl::Entry
// --------------------------------------------------------
/* virtual */
void FontFaceImpl::Entry::SetLoadState(UserFontLoadState aLoadState) {
gfxUserFontEntry::SetLoadState(aLoadState);
for (size_t i = 0; i < mFontFaces.Length(); i++) {
mFontFaces[i]->SetStatus(LoadStateToStatus(aLoadState));
}
}
/* virtual */
void FontFaceImpl::Entry::GetUserFontSets(nsTArray<gfxUserFontSet*>& aResult) {
aResult.Clear();
for (FontFaceImpl* f : mFontFaces) {
if (f->mInFontFaceSet) {
aResult.AppendElement(f->mFontFaceSet->GetUserFontSet());
}
for (FontFaceSetImpl* s : f->mOtherFontFaceSets) {
aResult.AppendElement(s->GetUserFontSet());
}
}
// Remove duplicates.
aResult.Sort();
auto it = std::unique(aResult.begin(), aResult.end());
aResult.TruncateLength(it - aResult.begin());
}
} // namespace dom
} // namespace mozilla

292
layout/style/FontFaceImpl.h Normal file
View File

@@ -0,0 +1,292 @@
/* -*- 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_dom_FontFaceImpl_h
#define mozilla_dom_FontFaceImpl_h
#include "mozilla/dom/FontFaceBinding.h"
#include "mozilla/FontPropertyTypes.h"
#include "mozilla/Maybe.h"
#include "mozilla/ServoStyleConsts.h"
#include "gfxUserFontSet.h"
#include "nsCSSPropertyID.h"
#include "nsCSSValue.h"
class gfxFontFaceBufferSource;
struct RawServoFontFaceRule;
namespace mozilla {
struct CSSFontFaceDescriptors;
class PostTraversalTask;
namespace dom {
class CSSFontFaceRule;
class FontFace;
class FontFaceBufferSource;
struct FontFaceDescriptors;
class FontFaceSetImpl;
class UTF8StringOrArrayBufferOrArrayBufferView;
} // namespace dom
} // namespace mozilla
namespace mozilla::dom {
class FontFaceImpl final {
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(FontFaceImpl)
friend class mozilla::PostTraversalTask;
friend class FontFaceBufferSource;
friend class Entry;
public:
class Entry final : public gfxUserFontEntry {
friend class FontFaceImpl;
public:
Entry(gfxUserFontSet* aFontSet,
const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList, WeightRange aWeight,
StretchRange aStretch, SlantStyleRange aStyle,
const nsTArray<gfxFontFeature>& aFeatureSettings,
const nsTArray<gfxFontVariation>& aVariationSettings,
uint32_t aLanguageOverride, gfxCharacterMap* aUnicodeRanges,
StyleFontDisplay aFontDisplay, RangeFlags aRangeFlags,
float aAscentOverride, float aDescentOverride, float aLineGapOverride,
float aSizeAdjust)
: gfxUserFontEntry(aFontSet, aFontFaceSrcList, aWeight, aStretch,
aStyle, aFeatureSettings, aVariationSettings,
aLanguageOverride, aUnicodeRanges, aFontDisplay,
aRangeFlags, aAscentOverride, aDescentOverride,
aLineGapOverride, aSizeAdjust) {}
virtual void SetLoadState(UserFontLoadState aLoadState) override;
virtual void GetUserFontSets(nsTArray<gfxUserFontSet*>& aResult) override;
const AutoTArray<FontFaceImpl*, 1>& GetFontFaces() { return mFontFaces; }
protected:
// The FontFace objects that use this user font entry. We need to store
// an array of these, not just a single pointer, since the user font
// cache can return the same entry for different FontFaces that have
// the same descriptor values and come from the same origin.
AutoTArray<FontFaceImpl*, 1> mFontFaces;
};
FontFace* GetOwner() const { return mOwner; }
static already_AddRefed<FontFaceImpl> CreateForRule(
FontFace* aOwner, FontFaceSetImpl* aFontFaceSet,
RawServoFontFaceRule* aRule);
RawServoFontFaceRule* GetRule() { return mRule; }
bool HasLocalSrc() const;
Maybe<StyleComputedFontWeightRange> GetFontWeight() const;
Maybe<StyleComputedFontStretchRange> GetFontStretch() const;
Maybe<StyleComputedFontStyleDescriptor> GetFontStyle() const;
Maybe<StyleFontDisplay> GetFontDisplay() const;
void GetFontFeatureSettings(nsTArray<gfxFontFeature>&) const;
void GetFontVariationSettings(nsTArray<gfxFontVariation>&) const;
void GetSources(nsTArray<StyleFontFaceSourceListComponent>&) const;
Maybe<StyleFontLanguageOverride> GetFontLanguageOverride() const;
Maybe<StylePercentage> GetAscentOverride() const;
Maybe<StylePercentage> GetDescentOverride() const;
Maybe<StylePercentage> GetLineGapOverride() const;
Maybe<StylePercentage> GetSizeAdjust() const;
gfxUserFontEntry* CreateUserFontEntry();
gfxUserFontEntry* GetUserFontEntry() const { return mUserFontEntry; }
void SetUserFontEntry(gfxUserFontEntry* aEntry);
/**
* Returns whether this object is in the specified FontFaceSet.
*/
bool IsInFontFaceSet(FontFaceSetImpl* aFontFaceSet) const;
void AddFontFaceSet(FontFaceSetImpl* aFontFaceSet);
void RemoveFontFaceSet(FontFaceSetImpl* aFontFaceSet);
FontFaceSetImpl* GetPrimaryFontFaceSet() const { return mFontFaceSet; }
/**
* Gets the family name of the FontFace as a raw string (such as 'Times', as
* opposed to GetFamily, which returns a CSS-escaped string, such as
* '"Times"'). Returns null if a valid family name was not available.
*/
nsAtom* GetFamilyName() const;
/**
* Returns whether this object is CSS-connected, i.e. reflecting an
* @font-face rule.
*/
bool HasRule() const { return mRule; }
/**
* Breaks the connection between this FontFace and its @font-face rule.
*/
void DisconnectFromRule();
/**
* Returns whether there is an ArrayBuffer or ArrayBufferView of font
* data.
*/
bool HasFontData() const;
/**
* Creates a gfxFontFaceBufferSource to represent the font data
* in this object.
*/
already_AddRefed<gfxFontFaceBufferSource> CreateBufferSource();
/**
* Gets a pointer to and the length of the font data stored in the
* ArrayBuffer or ArrayBufferView.
*/
bool GetData(uint8_t*& aBuffer, uint32_t& aLength);
/**
* Returns the value of the unicode-range descriptor as a gfxCharacterMap.
*/
gfxCharacterMap* GetUnicodeRangeAsCharacterMap();
// Web IDL
void GetFamily(nsACString& aResult);
void SetFamily(const nsACString& aValue, ErrorResult& aRv);
void GetStyle(nsACString& aResult);
void SetStyle(const nsACString& aValue, ErrorResult& aRv);
void GetWeight(nsACString& aResult);
void SetWeight(const nsACString& aValue, ErrorResult& aRv);
void GetStretch(nsACString& aResult);
void SetStretch(const nsACString& aValue, ErrorResult& aRv);
void GetUnicodeRange(nsACString& aResult);
void SetUnicodeRange(const nsACString& aValue, ErrorResult& aRv);
void GetVariant(nsACString& aResult);
void SetVariant(const nsACString& aValue, ErrorResult& aRv);
void GetFeatureSettings(nsACString& aResult);
void SetFeatureSettings(const nsACString& aValue, ErrorResult& aRv);
void GetVariationSettings(nsACString& aResult);
void SetVariationSettings(const nsACString& aValue, ErrorResult& aRv);
void GetDisplay(nsACString& aResult);
void SetDisplay(const nsACString& aValue, ErrorResult& aRv);
void GetAscentOverride(nsACString& aResult);
void SetAscentOverride(const nsACString& aValue, ErrorResult& aRv);
void GetDescentOverride(nsACString& aResult);
void SetDescentOverride(const nsACString& aValue, ErrorResult& aRv);
void GetLineGapOverride(nsACString& aResult);
void SetLineGapOverride(const nsACString& aValue, ErrorResult& aRv);
void GetSizeAdjust(nsACString& aResult);
void SetSizeAdjust(const nsACString& aValue, ErrorResult& aRv);
FontFaceLoadStatus Status();
void Load(ErrorResult& aRv);
void Destroy();
FontFaceImpl(FontFace* aOwner, FontFaceSetImpl* aFontFaceSet);
void InitializeSource(const UTF8StringOrArrayBufferOrArrayBufferView&);
/**
* Sets all of the descriptor values in mDescriptors using values passed
* to the JS constructor.
* Returns true on success, false if parsing any descriptor failed.
*/
bool SetDescriptors(const nsACString& aFamily,
const FontFaceDescriptors& aDescriptors);
private:
~FontFaceImpl();
// Helper function for Load.
void DoLoad();
// Helper function for the descriptor setter methods.
// Returns true if the descriptor was modified, false if descriptor is
// unchanged (which may not be an error: check aRv for actual failure).
bool SetDescriptor(nsCSSFontDesc aFontDesc, const nsACString& aValue,
ErrorResult& aRv);
/**
* Called when a descriptor has been modified, so font-face sets can
* be told to refresh.
*/
void DescriptorUpdated();
/**
* Sets the current loading status.
*/
void SetStatus(FontFaceLoadStatus aStatus);
void GetDesc(nsCSSFontDesc aDescID, nsACString& aResult) const;
RawServoFontFaceRule* GetData() const {
return HasRule() ? mRule : mDescriptors;
}
/**
* Returns and takes ownership of the buffer storing the font data.
*/
void TakeBuffer(uint8_t*& aBuffer, uint32_t& aLength);
FontFace* MOZ_NON_OWNING_REF mOwner;
// The @font-face rule this FontFace object is reflecting, if it is a
// rule backed FontFace.
RefPtr<RawServoFontFaceRule> mRule;
// The FontFace object's user font entry. This is initially null, but is set
// during FontFaceSet::UpdateRules and when a FontFace is explicitly loaded.
RefPtr<Entry> mUserFontEntry;
// The current load status of the font represented by this FontFace.
// Note that we can't just reflect the value of the gfxUserFontEntry's
// status, since the spec sometimes requires us to go through the event
// loop before updating the status, rather than doing it immediately.
FontFaceLoadStatus mStatus;
// Represents where a FontFace's data is coming from.
enum SourceType {
eSourceType_FontFaceRule = 1,
eSourceType_URLs,
eSourceType_Buffer
};
// Where the font data for this FontFace is coming from.
SourceType mSourceType;
// If the FontFace was constructed with an ArrayBuffer(View), this is a
// copy of the data from it.
uint8_t* mSourceBuffer;
uint32_t mSourceBufferLength;
// The values corresponding to the font face descriptors, if we are not
// a rule backed FontFace object. For rule backed objects, we use
// the descriptors stored in mRule.
// FIXME This should hold a unique ptr to just the descriptors inside,
// so that we don't need to create a rule for it and don't need to
// assign a fake line number and column number. See bug 1450904.
RefPtr<RawServoFontFaceRule> mDescriptors;
// The value of the unicode-range descriptor as a gfxCharacterMap. Valid
// only when mUnicodeRangeDirty is false.
RefPtr<gfxCharacterMap> mUnicodeRange;
// The primary FontFaceSet this FontFace is associated with,
// regardless of whether it is currently "in" the set.
RefPtr<FontFaceSetImpl> mFontFaceSet;
// Other FontFaceSets (apart from mFontFaceSet) that this FontFace
// appears in.
nsTArray<RefPtr<FontFaceSetImpl>> mOtherFontFaceSets;
// Whether mUnicodeRange needs to be rebuilt before being returned from
// GetUnicodeRangeAsCharacterMap.
bool mUnicodeRangeDirty;
// Whether this FontFace appears in mFontFaceSet.
bool mInFontFaceSet;
};
} // namespace mozilla::dom
#endif // !defined(mozilla_dom_FontFaceImpl_h)

File diff suppressed because it is too large Load Diff

View File

@@ -9,6 +9,7 @@
#include "mozilla/dom/FontFace.h"
#include "mozilla/dom/FontFaceSetBinding.h"
#include "mozilla/dom/FontFaceSetImpl.h"
#include "mozilla/DOMEventTargetHelper.h"
#include "gfxUserFontSet.h"
#include "nsICSSLoaderObserver.h"
@@ -26,124 +27,28 @@ namespace mozilla {
class PostTraversalTask;
class SharedFontList;
namespace dom {
class FontFace;
class Promise;
} // namespace dom
} // namespace mozilla
namespace mozilla::dom {
class FontFaceSet final : public DOMEventTargetHelper,
public nsIDOMEventListener,
public nsICSSLoaderObserver {
class FontFaceSet final : public DOMEventTargetHelper {
friend class mozilla::PostTraversalTask;
friend class UserFontSet;
public:
/**
* A gfxUserFontSet that integrates with the layout and style systems to
* manage @font-face rules and handle network requests for font loading.
*
* We would combine this class and FontFaceSet into the one class if it were
* possible; it's not because FontFaceSet is cycle collected and
* gfxUserFontSet isn't (and can't be, as gfx classes don't use the cycle
* collector). So UserFontSet exists just to override the needed virtual
* methods from gfxUserFontSet and to forward them on FontFaceSet.
*/
class UserFontSet final : public gfxUserFontSet {
friend class FontFaceSet;
public:
explicit UserFontSet(FontFaceSet* aFontFaceSet)
: mFontFaceSet(aFontFaceSet) {}
FontFaceSet* GetFontFaceSet() { return mFontFaceSet; }
gfxFontSrcPrincipal* GetStandardFontLoadPrincipal() const final {
return mFontFaceSet ? mFontFaceSet->mStandardFontLoadPrincipal.get()
: nullptr;
}
nsPresContext* GetPresContext() const final {
return mFontFaceSet ? mFontFaceSet->GetPresContext() : nullptr;
}
bool IsFontLoadAllowed(const gfxFontFaceSrc&) final;
void DispatchFontLoadViolations(
nsTArray<nsCOMPtr<nsIRunnable>>& aViolations) override;
virtual nsresult StartLoad(gfxUserFontEntry* aUserFontEntry,
uint32_t aSrcIndex) override;
void RecordFontLoadDone(uint32_t aFontSize, TimeStamp aDoneTime) override;
bool BypassCache() final {
return mFontFaceSet && mFontFaceSet->mBypassCache;
}
protected:
virtual bool GetPrivateBrowsing() override;
virtual nsresult SyncLoadFontData(gfxUserFontEntry* aFontToLoad,
const gfxFontFaceSrc* aFontFaceSrc,
uint8_t*& aBuffer,
uint32_t& aBufferLength) override;
virtual nsresult LogMessage(gfxUserFontEntry* aUserFontEntry,
uint32_t aSrcIndex, const char* aMessage,
uint32_t aFlags = nsIScriptError::errorFlag,
nsresult aStatus = NS_OK) override;
virtual void DoRebuildUserFontSet() override;
already_AddRefed<gfxUserFontEntry> CreateUserFontEntry(
const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList, WeightRange aWeight,
StretchRange aStretch, SlantStyleRange aStyle,
const nsTArray<gfxFontFeature>& aFeatureSettings,
const nsTArray<gfxFontVariation>& aVariationSettings,
uint32_t aLanguageOverride, gfxCharacterMap* aUnicodeRanges,
StyleFontDisplay aFontDisplay, RangeFlags aRangeFlags,
float aAscentOverride, float aDescentOverride, float aLineGapOverride,
float aSizeAdjust) override;
private:
RefPtr<FontFaceSet> mFontFaceSet;
};
using UserFontSet = FontFaceSetImpl::UserFontSet;
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(FontFaceSet, DOMEventTargetHelper)
NS_DECL_NSIDOMEVENTLISTENER
FontFaceSet(nsPIDOMWindowInner* aWindow, dom::Document* aDocument);
virtual JSObject* WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto) override;
UserFontSet* GetUserFontSet() { return mUserFontSet; }
// Called by nsFontFaceLoader when the loader has completed normally.
// It's removed from the mLoaders set.
void RemoveLoader(nsFontFaceLoader* aLoader);
bool UpdateRules(const nsTArray<nsFontFaceRuleContainer>& aRules);
nsPresContext* GetPresContext();
// search for @font-face rule that matches a platform font entry
RawServoFontFaceRule* FindRuleForEntry(gfxFontEntry* aFontEntry);
void IncrementGeneration(bool aIsRebuild = false);
/**
* Finds an existing entry in the user font cache or creates a new user
* font entry for the given FontFace object.
*/
static already_AddRefed<gfxUserFontEntry>
FindOrCreateUserFontEntryFromFontFace(FontFace* aFontFace);
/**
* Notification method called by a FontFace to indicate that its loading
* status has changed.
*/
void OnFontFaceStatusChanged(FontFace* aFontFace);
/**
* Notification method called by the nsPresContext to indicate that the
* refresh driver ticked and flushed style and layout.
@@ -156,22 +61,17 @@ class FontFaceSet final : public DOMEventTargetHelper,
*/
static bool PrefEnabled();
// nsICSSLoaderObserver
NS_IMETHOD StyleSheetLoaded(StyleSheet* aSheet, bool aWasDeferred,
nsresult aStatus) override;
void FlushUserFontSet();
static nsPresContext* GetPresContextFor(gfxUserFontSet* aUserFontSet) {
FontFaceSet* set = static_cast<UserFontSet*>(aUserFontSet)->mFontFaceSet;
return set ? set->GetPresContext() : nullptr;
}
void RefreshStandardFontLoadPrincipal();
void CopyNonRuleFacesTo(FontFaceSet* aFontFaceSet) const;
dom::Document* Document() const { return mDocument; }
UserFontSet* GetUserFontSet() const { return mImpl->GetUserFontSet(); }
void CacheFontLoadability() { mImpl->CacheFontLoadability(); }
FontFaceSetImpl* GetImpl() const { return mImpl; }
// -- Web IDL --------------------------------------------------------------
@@ -199,16 +99,24 @@ class FontFaceSet final : public DOMEventTargetHelper,
void ForEach(JSContext* aCx, FontFaceSetForEachCallback& aCallback,
JS::Handle<JS::Value> aThisArg, ErrorResult& aRv);
// For ServoStyleSet to know ahead of time whether a font is loadable.
void CacheFontLoadability();
void MarkUserFontSetDirty();
/**
* Unlike Size(), this returns the size including non-Author origin fonts.
*/
uint32_t SizeIncludingNonAuthorOrigins();
void MaybeResolve();
void DispatchLoadingFinishedEvent(
const nsAString& aType, nsTArray<OwningNonNull<FontFace>>&& aFontFaces);
void DispatchLoadingEventAndReplaceReadyPromise();
void DispatchCheckLoadingFinishedAfterDelay();
// Whether mReady is pending, or would be when created.
bool ReadyPromiseIsPending() const;
void InsertRuleFontFace(FontFace* aFontFace, StyleOrigin aOrigin);
private:
friend mozilla::dom::FontFaceSetIterator; // needs GetFontFaceAt()
@@ -222,33 +130,7 @@ class FontFaceSet final : public DOMEventTargetHelper,
/**
* Removes any listeners and observers.
*/
void Disconnect();
void RemoveDOMContentLoadedListener();
/**
* Returns whether there might be any pending font loads, which should cause
* the mReady Promise not to be resolved yet.
*/
bool MightHavePendingFontLoads();
/**
* Checks to see whether it is time to replace mReady and dispatch a
* "loading" event.
*/
void CheckLoadingStarted();
/**
* Checks to see whether it is time to resolve mReady and dispatch any
* "loadingdone" and "loadingerror" events.
*/
void CheckLoadingFinished();
/**
* Callback for invoking CheckLoadingFinished after going through the
* event loop. See OnFontFaceStatusChanged.
*/
void CheckLoadingFinishedAfterDelay();
void Destroy();
/**
* Returns the font at aIndex if it's an Author origin font, or nullptr
@@ -256,12 +138,6 @@ class FontFaceSet final : public DOMEventTargetHelper,
*/
FontFace* GetFontFaceAt(uint32_t aIndex);
/**
* Dispatches a FontFaceSetLoadEvent to this object.
*/
void DispatchLoadingFinishedEvent(
const nsAString& aType, nsTArray<OwningNonNull<FontFace>>&& aFontFaces);
// Note: if you add new cycle collected objects to FontFaceRecord,
// make sure to update FontFaceSet's cycle collection macros
// accordingly.
@@ -275,76 +151,12 @@ class FontFaceSet final : public DOMEventTargetHelper,
bool mLoadEventShouldFire;
};
static already_AddRefed<gfxUserFontEntry>
FindOrCreateUserFontEntryFromFontFace(const nsACString& aFamilyName,
FontFace* aFontFace, StyleOrigin);
// search for @font-face rule that matches a userfont font entry
RawServoFontFaceRule* FindRuleForUserFontEntry(
gfxUserFontEntry* aUserFontEntry);
nsresult StartLoad(gfxUserFontEntry* aUserFontEntry, uint32_t aSrcIndex);
gfxFontSrcPrincipal* GetStandardFontLoadPrincipal();
nsresult CheckFontLoad(const gfxFontFaceSrc* aFontFaceSrc,
gfxFontSrcPrincipal** aPrincipal, bool* aBypassCache);
bool IsFontLoadAllowed(const gfxFontFaceSrc& aSrc);
void DispatchFontLoadViolations(nsTArray<nsCOMPtr<nsIRunnable>>& aViolations);
nsresult SyncLoadFontData(gfxUserFontEntry* aFontToLoad,
const gfxFontFaceSrc* aFontFaceSrc,
uint8_t*& aBuffer, uint32_t& aBufferLength);
nsresult LogMessage(gfxUserFontEntry* aUserFontEntry, uint32_t aSrcIndex,
const char* aMessage, uint32_t aFlags, nsresult aStatus);
void InsertRuleFontFace(FontFace* aFontFace, StyleOrigin aOrigin,
nsTArray<FontFaceRecord>& aOldRecords,
bool& aFontSetModified);
void InsertNonRuleFontFace(FontFace* aFontFace, bool& aFontSetModified);
#ifdef DEBUG
bool HasRuleFontFace(FontFace* aFontFace);
#endif
/**
* Returns whether we have any loading FontFace objects in the FontFaceSet.
*/
bool HasLoadingFontFaces();
// Whether mReady is pending, or would be when created.
bool ReadyPromiseIsPending() const;
// Helper function for HasLoadingFontFaces.
void UpdateHasLoadingFontFaces();
void ParseFontShorthandForMatching(const nsACString& aFont,
StyleFontFamilyList& aFamilyList,
FontWeight& aWeight, FontStretch& aStretch,
FontSlantStyle& aStyle, ErrorResult& aRv);
void FindMatchingFontFaces(const nsACString& aFont, const nsAString& aText,
nsTArray<FontFace*>& aFontFaces, ErrorResult& aRv);
void DispatchLoadingEventAndReplaceReadyPromise();
void DispatchCheckLoadingFinishedAfterDelay();
TimeStamp GetNavigationStartTimeStamp();
RefPtr<UserFontSet> mUserFontSet;
// The document this is a FontFaceSet for.
RefPtr<dom::Document> mDocument;
// The document's node principal, which is the principal font loads for
// this FontFaceSet will generally use. (This principal is not used for
// @font-face rules in UA and user sheets, where the principal of the
// sheet is used instead.)
//
// This field is used from GetStandardFontLoadPrincipal. When on a
// style worker thread, we use mStandardFontLoadPrincipal assuming
// it is up to date.
//
// Because mDocument's principal can change over time,
// its value must be updated by a call to ResetStandardFontLoadPrincipal.
RefPtr<gfxFontSrcPrincipal> mStandardFontLoadPrincipal;
// The underlying implementation for FontFaceSet.
RefPtr<FontFaceSetImpl> mImpl;
// A Promise that is fulfilled once all of the FontFace objects
// in mRuleFaces and mNonRuleFaces that started or were loading at the
@@ -355,12 +167,7 @@ class FontFaceSet final : public DOMEventTargetHelper,
// Note that mReady is created lazily when GetReady() is called.
RefPtr<dom::Promise> mReady;
// Whether the ready promise must be resolved when it's created.
bool mResolveLazilyCreatedReadyPromise;
// Set of all loaders pointing to us. These are not strong pointers,
// but that's OK because nsFontFaceLoader always calls RemoveLoader on
// us before it dies (unless we die first).
nsTHashtable<nsPtrHashKey<nsFontFaceLoader>> mLoaders;
bool mResolveLazilyCreatedReadyPromise = false;
// The @font-face rule backed FontFace objects in the FontFaceSet.
nsTArray<FontFaceRecord> mRuleFaces;
@@ -368,40 +175,6 @@ class FontFaceSet final : public DOMEventTargetHelper,
// The non rule backed FontFace objects that have been added to this
// FontFaceSet.
nsTArray<FontFaceRecord> mNonRuleFaces;
// The overall status of the loading or loaded fonts in the FontFaceSet.
dom::FontFaceSetLoadStatus mStatus;
// A map from gfxFontFaceSrc pointer identity to whether the load is allowed
// by CSP or other checks. We store this here because querying CSP off the
// main thread is not a great idea.
//
// We could use just the pointer and use this as a hash set, but then we'd
// have no way to verify that we've checked all the loads we should.
nsTHashMap<nsPtrHashKey<const gfxFontFaceSrc>, bool> mAllowedFontLoads;
// Whether mNonRuleFaces has changed since last time UpdateRules ran.
bool mNonRuleFacesDirty;
// Whether any FontFace objects in mRuleFaces or mNonRuleFaces are
// loading. Only valid when mHasLoadingFontFacesIsDirty is false. Don't use
// this variable directly; call the HasLoadingFontFaces method instead.
bool mHasLoadingFontFaces;
// This variable is only valid when mLoadingDirty is false.
bool mHasLoadingFontFacesIsDirty;
// Whether CheckLoadingFinished calls should be ignored. See comment in
// OnFontFaceStatusChanged.
bool mDelayedLoadCheck;
// Whether the docshell for our document indicated that loads should
// bypass the cache.
bool mBypassCache;
// Whether the docshell for our document indicates that we are in private
// browsing mode.
bool mPrivateBrowsing;
};
} // namespace mozilla::dom

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,352 @@
/* -*- 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_dom_FontFaceSetImpl_h
#define mozilla_dom_FontFaceSetImpl_h
#include "mozilla/dom/FontFace.h"
#include "mozilla/dom/FontFaceSetBinding.h"
#include "mozilla/DOMEventTargetHelper.h"
#include "mozilla/FontPropertyTypes.h"
#include "gfxUserFontSet.h"
#include "nsICSSLoaderObserver.h"
#include "nsIDOMEventListener.h"
struct gfxFontFaceSrc;
class gfxFontSrcPrincipal;
class gfxUserFontEntry;
class nsFontFaceLoader;
class nsIPrincipal;
class nsPIDOMWindowInner;
struct RawServoFontFaceRule;
namespace mozilla {
class PostTraversalTask;
class SharedFontList;
namespace dom {
class FontFace;
} // namespace dom
} // namespace mozilla
namespace mozilla::dom {
class FontFaceSetImpl final : public nsIDOMEventListener,
public nsICSSLoaderObserver {
NS_DECL_THREADSAFE_ISUPPORTS
friend class UserFontSet;
public:
/**
* A gfxUserFontSet that integrates with the layout and style systems to
* manage @font-face rules and handle network requests for font loading.
*
* We would combine this class and FontFaceSet into the one class if it were
* possible; it's not because FontFaceSet is cycle collected and
* gfxUserFontSet isn't (and can't be, as gfx classes don't use the cycle
* collector). So UserFontSet exists just to override the needed virtual
* methods from gfxUserFontSet and to forward them on FontFaceSet.
*/
class UserFontSet final : public gfxUserFontSet {
friend class FontFaceSetImpl;
public:
explicit UserFontSet(FontFaceSetImpl* aFontFaceSet)
: mFontFaceSet(aFontFaceSet) {}
FontFaceSetImpl* GetFontFaceSet() { return mFontFaceSet; }
gfxFontSrcPrincipal* GetStandardFontLoadPrincipal() const final {
return mFontFaceSet ? mFontFaceSet->mStandardFontLoadPrincipal.get()
: nullptr;
}
nsPresContext* GetPresContext() const final {
return mFontFaceSet ? mFontFaceSet->GetPresContext() : nullptr;
}
bool IsFontLoadAllowed(const gfxFontFaceSrc&) final;
void DispatchFontLoadViolations(
nsTArray<nsCOMPtr<nsIRunnable>>& aViolations) override;
virtual nsresult StartLoad(gfxUserFontEntry* aUserFontEntry,
uint32_t aSrcIndex) override;
void RecordFontLoadDone(uint32_t aFontSize, TimeStamp aDoneTime) override;
bool BypassCache() final {
return mFontFaceSet && mFontFaceSet->mBypassCache;
}
protected:
virtual bool GetPrivateBrowsing() override;
virtual nsresult SyncLoadFontData(gfxUserFontEntry* aFontToLoad,
const gfxFontFaceSrc* aFontFaceSrc,
uint8_t*& aBuffer,
uint32_t& aBufferLength) override;
virtual nsresult LogMessage(gfxUserFontEntry* aUserFontEntry,
uint32_t aSrcIndex, const char* aMessage,
uint32_t aFlags = nsIScriptError::errorFlag,
nsresult aStatus = NS_OK) override;
virtual void DoRebuildUserFontSet() override;
already_AddRefed<gfxUserFontEntry> CreateUserFontEntry(
const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList, WeightRange aWeight,
StretchRange aStretch, SlantStyleRange aStyle,
const nsTArray<gfxFontFeature>& aFeatureSettings,
const nsTArray<gfxFontVariation>& aVariationSettings,
uint32_t aLanguageOverride, gfxCharacterMap* aUnicodeRanges,
StyleFontDisplay aFontDisplay, RangeFlags aRangeFlags,
float aAscentOverride, float aDescentOverride, float aLineGapOverride,
float aSizeAdjust) override;
private:
RefPtr<FontFaceSetImpl> mFontFaceSet;
};
NS_DECL_NSIDOMEVENTLISTENER
FontFaceSetImpl(FontFaceSet* aOwner, dom::Document* aDocument);
void Initialize();
void Destroy();
UserFontSet* GetUserFontSet() const { return mUserFontSet; }
// Called by nsFontFaceLoader when the loader has completed normally.
// It's removed from the mLoaders set.
void RemoveLoader(nsFontFaceLoader* aLoader);
bool UpdateRules(const nsTArray<nsFontFaceRuleContainer>& aRules);
nsPresContext* GetPresContext();
// search for @font-face rule that matches a platform font entry
RawServoFontFaceRule* FindRuleForEntry(gfxFontEntry* aFontEntry);
void IncrementGeneration(bool aIsRebuild = false);
/**
* Finds an existing entry in the user font cache or creates a new user
* font entry for the given FontFace object.
*/
static already_AddRefed<gfxUserFontEntry>
FindOrCreateUserFontEntryFromFontFace(FontFaceImpl* aFontFace);
/**
* Notification method called by a FontFace to indicate that its loading
* status has changed.
*/
void OnFontFaceStatusChanged(FontFaceImpl* aFontFace);
/**
* Notification method called by the nsPresContext to indicate that the
* refresh driver ticked and flushed style and layout.
* were just flushed.
*/
void DidRefresh();
/**
* Returns whether the "layout.css.font-loading-api.enabled" pref is true.
*/
static bool PrefEnabled();
// nsICSSLoaderObserver
NS_IMETHOD StyleSheetLoaded(StyleSheet* aSheet, bool aWasDeferred,
nsresult aStatus) override;
void FlushUserFontSet();
static nsPresContext* GetPresContextFor(gfxUserFontSet* aUserFontSet) {
FontFaceSetImpl* set =
static_cast<UserFontSet*>(aUserFontSet)->mFontFaceSet;
return set ? set->GetPresContext() : nullptr;
}
void RefreshStandardFontLoadPrincipal();
dom::Document* Document() const { return mDocument; }
// -- Web IDL --------------------------------------------------------------
void EnsureReady();
dom::FontFaceSetLoadStatus Status();
bool Add(FontFaceImpl* aFontFace, ErrorResult& aRv);
void Clear();
bool Delete(FontFaceImpl* aFontFace);
// For ServoStyleSet to know ahead of time whether a font is loadable.
void CacheFontLoadability();
void MarkUserFontSetDirty();
/**
* Checks to see whether it is time to resolve mReady and dispatch any
* "loadingdone" and "loadingerror" events.
*/
void CheckLoadingFinished();
void FindMatchingFontFaces(const nsACString& aFont, const nsAString& aText,
nsTArray<FontFace*>& aFontFaces, ErrorResult& aRv);
void DispatchCheckLoadingFinishedAfterDelay();
private:
~FontFaceSetImpl();
/**
* Returns whether the given FontFace is currently "in" the FontFaceSet.
*/
bool HasAvailableFontFace(FontFaceImpl* aFontFace);
void RemoveDOMContentLoadedListener();
/**
* Returns whether there might be any pending font loads, which should cause
* the mReady Promise not to be resolved yet.
*/
bool MightHavePendingFontLoads();
/**
* Checks to see whether it is time to replace mReady and dispatch a
* "loading" event.
*/
void CheckLoadingStarted();
/**
* Callback for invoking CheckLoadingFinished after going through the
* event loop. See OnFontFaceStatusChanged.
*/
void CheckLoadingFinishedAfterDelay();
// Note: if you add new cycle collected objects to FontFaceRecord,
// make sure to update FontFaceSet's cycle collection macros
// accordingly.
struct FontFaceRecord {
RefPtr<FontFaceImpl> mFontFace;
Maybe<StyleOrigin> mOrigin; // only relevant for mRuleFaces entries
};
static already_AddRefed<gfxUserFontEntry>
FindOrCreateUserFontEntryFromFontFace(const nsACString& aFamilyName,
FontFaceImpl* aFontFace, StyleOrigin);
// search for @font-face rule that matches a userfont font entry
RawServoFontFaceRule* FindRuleForUserFontEntry(
gfxUserFontEntry* aUserFontEntry);
nsresult StartLoad(gfxUserFontEntry* aUserFontEntry, uint32_t aSrcIndex);
gfxFontSrcPrincipal* GetStandardFontLoadPrincipal();
nsresult CheckFontLoad(const gfxFontFaceSrc* aFontFaceSrc,
gfxFontSrcPrincipal** aPrincipal, bool* aBypassCache);
bool IsFontLoadAllowed(const gfxFontFaceSrc& aSrc);
void DispatchFontLoadViolations(nsTArray<nsCOMPtr<nsIRunnable>>& aViolations);
nsresult SyncLoadFontData(gfxUserFontEntry* aFontToLoad,
const gfxFontFaceSrc* aFontFaceSrc,
uint8_t*& aBuffer, uint32_t& aBufferLength);
nsresult LogMessage(gfxUserFontEntry* aUserFontEntry, uint32_t aSrcIndex,
const char* aMessage, uint32_t aFlags, nsresult aStatus);
void InsertRuleFontFace(FontFaceImpl* aFontFace, FontFace* aFontFaceOwner,
StyleOrigin aOrigin,
nsTArray<FontFaceRecord>& aOldRecords,
bool& aFontSetModified);
void InsertNonRuleFontFace(FontFaceImpl* aFontFace, bool& aFontSetModified);
#ifdef DEBUG
bool HasRuleFontFace(FontFaceImpl* aFontFace);
#endif
/**
* Returns whether we have any loading FontFace objects in the FontFaceSet.
*/
bool HasLoadingFontFaces();
// Whether mReady is pending, or would be when created.
bool ReadyPromiseIsPending() const;
// Helper function for HasLoadingFontFaces.
void UpdateHasLoadingFontFaces();
void ParseFontShorthandForMatching(const nsACString& aFont,
StyleFontFamilyList& aFamilyList,
FontWeight& aWeight, FontStretch& aStretch,
FontSlantStyle& aStyle, ErrorResult& aRv);
TimeStamp GetNavigationStartTimeStamp();
FontFaceSet* MOZ_NON_OWNING_REF mOwner;
RefPtr<UserFontSet> mUserFontSet;
// The document this is a FontFaceSet for.
RefPtr<dom::Document> mDocument;
// The document's node principal, which is the principal font loads for
// this FontFaceSet will generally use. (This principal is not used for
// @font-face rules in UA and user sheets, where the principal of the
// sheet is used instead.)
//
// This field is used from GetStandardFontLoadPrincipal. When on a
// style worker thread, we use mStandardFontLoadPrincipal assuming
// it is up to date.
//
// Because mDocument's principal can change over time,
// its value must be updated by a call to ResetStandardFontLoadPrincipal.
RefPtr<gfxFontSrcPrincipal> mStandardFontLoadPrincipal;
// Set of all loaders pointing to us. These are not strong pointers,
// but that's OK because nsFontFaceLoader always calls RemoveLoader on
// us before it dies (unless we die first).
nsTHashtable<nsPtrHashKey<nsFontFaceLoader>> mLoaders;
// The @font-face rule backed FontFace objects in the FontFaceSet.
nsTArray<FontFaceRecord> mRuleFaces;
// The non rule backed FontFace objects that have been added to this
// FontFaceSet.
nsTArray<FontFaceRecord> mNonRuleFaces;
// The overall status of the loading or loaded fonts in the FontFaceSet.
dom::FontFaceSetLoadStatus mStatus;
// A map from gfxFontFaceSrc pointer identity to whether the load is allowed
// by CSP or other checks. We store this here because querying CSP off the
// main thread is not a great idea.
//
// We could use just the pointer and use this as a hash set, but then we'd
// have no way to verify that we've checked all the loads we should.
nsTHashMap<nsPtrHashKey<const gfxFontFaceSrc>, bool> mAllowedFontLoads;
// Whether mNonRuleFaces has changed since last time UpdateRules ran.
bool mNonRuleFacesDirty;
// Whether any FontFace objects in mRuleFaces or mNonRuleFaces are
// loading. Only valid when mHasLoadingFontFacesIsDirty is false. Don't use
// this variable directly; call the HasLoadingFontFaces method instead.
bool mHasLoadingFontFaces;
// This variable is only valid when mLoadingDirty is false.
bool mHasLoadingFontFacesIsDirty;
// Whether CheckLoadingFinished calls should be ignored. See comment in
// OnFontFaceStatusChanged.
bool mDelayedLoadCheck;
// Whether the docshell for our document indicated that loads should
// bypass the cache.
bool mBypassCache;
// Whether the docshell for our document indicates that we are in private
// browsing mode.
bool mPrivateBrowsing;
};
} // namespace mozilla::dom
#endif // !defined(mozilla_dom_FontFaceSetImpl_h)

View File

@@ -8,6 +8,7 @@
#include "mozilla/dom/FontFace.h"
#include "mozilla/dom/FontFaceSet.h"
#include "mozilla/dom/FontFaceSetImpl.h"
#include "gfxPlatformFontList.h"
#include "gfxTextRun.h"
#include "ServoStyleSet.h"
@@ -20,11 +21,11 @@ using namespace dom;
void PostTraversalTask::Run() {
switch (mType) {
case Type::ResolveFontFaceLoadedPromise:
static_cast<FontFace*>(mTarget)->DoResolve();
static_cast<FontFace*>(mTarget)->MaybeResolve();
break;
case Type::RejectFontFaceLoadedPromise:
static_cast<FontFace*>(mTarget)->DoReject(mResult);
static_cast<FontFace*>(mTarget)->MaybeReject(mResult);
break;
case Type::DispatchLoadingEventAndReplaceReadyPromise:
@@ -33,7 +34,7 @@ void PostTraversalTask::Run() {
break;
case Type::DispatchFontFaceSetCheckLoadingFinishedAfterDelay:
static_cast<FontFaceSet*>(mTarget)
static_cast<FontFaceSetImpl*>(mTarget)
->DispatchCheckLoadingFinishedAfterDelay();
break;

View File

@@ -16,6 +16,7 @@ class ServoStyleSet;
namespace dom {
class FontFace;
class FontFaceSet;
class FontFaceSetImpl;
} // namespace dom
namespace fontlist {
struct Family;
@@ -59,7 +60,7 @@ class PostTraversalTask {
}
static PostTraversalTask DispatchFontFaceSetCheckLoadingFinishedAfterDelay(
dom::FontFaceSet* aFontFaceSet) {
dom::FontFaceSetImpl* aFontFaceSet) {
auto task = PostTraversalTask(
Type::DispatchFontFaceSetCheckLoadingFinishedAfterDelay);
task.mTarget = aFontFaceSet;
@@ -101,7 +102,7 @@ class PostTraversalTask {
// mTarget (FontFaceSet*)
DispatchLoadingEventAndReplaceReadyPromise,
// mTarget (FontFaceSet*)
// mTarget (FontFaceSetImpl*)
DispatchFontFaceSetCheckLoadingFinishedAfterDelay,
// mTarget (gfxUserFontEntry*)

View File

@@ -140,7 +140,9 @@ EXPORTS.mozilla.dom += [
"CSSSupportsRule.h",
"CSSValue.h",
"FontFace.h",
"FontFaceImpl.h",
"FontFaceSet.h",
"FontFaceSetImpl.h",
"FontFaceSetIterator.h",
"MediaList.h",
"MediaQueryList.h",
@@ -188,7 +190,9 @@ UNIFIED_SOURCES += [
"DocumentStyleRootIterator.cpp",
"ErrorReporter.cpp",
"FontFace.cpp",
"FontFaceImpl.cpp",
"FontFaceSet.cpp",
"FontFaceSetImpl.cpp",
"FontFaceSetIterator.cpp",
"FontPreloader.cpp",
"GeckoBindings.cpp",

View File

@@ -45,7 +45,7 @@ static uint32_t GetShortFallbackDelay() {
nsFontFaceLoader::nsFontFaceLoader(gfxUserFontEntry* aUserFontEntry,
uint32_t aSrcIndex,
FontFaceSet* aFontFaceSet,
FontFaceSetImpl* aFontFaceSet,
nsIChannel* aChannel)
: mUserFontEntry(aUserFontEntry),
mFontFaceSet(aFontFaceSet),
@@ -187,7 +187,7 @@ void nsFontFaceLoader::LoadTimerCallback(nsITimer* aTimer, void* aClosure) {
nsTArray<gfxUserFontSet*> fontSets;
ufe->GetUserFontSets(fontSets);
for (gfxUserFontSet* fontSet : fontSets) {
nsPresContext* ctx = FontFaceSet::GetPresContextFor(fontSet);
nsPresContext* ctx = FontFaceSetImpl::GetPresContextFor(fontSet);
if (ctx) {
fontSet->IncrementGeneration();
ctx->UserFontSetUpdated(ufe);
@@ -299,7 +299,7 @@ nsresult nsFontFaceLoader::FontLoadComplete() {
nsTArray<gfxUserFontSet*> fontSets;
mUserFontEntry->GetUserFontSets(fontSets);
for (gfxUserFontSet* fontSet : fontSets) {
nsPresContext* ctx = FontFaceSet::GetPresContextFor(fontSet);
nsPresContext* ctx = FontFaceSetImpl::GetPresContextFor(fontSet);
if (ctx) {
// Update layout for the presence of the new font. Since this is
// asynchronous, reflows will coalesce.

View File

@@ -11,7 +11,7 @@
#include "mozilla/Attributes.h"
#include "mozilla/TimeStamp.h"
#include "mozilla/dom/FontFaceSet.h"
#include "mozilla/dom/FontFaceSetImpl.h"
#include "nsCOMPtr.h"
#include "nsIFontLoadCompleteCallback.h"
#include "nsIStreamLoader.h"
@@ -29,7 +29,7 @@ class nsFontFaceLoader final : public nsIStreamLoaderObserver,
public nsIFontLoadCompleteCallback {
public:
nsFontFaceLoader(gfxUserFontEntry* aUserFontEntry, uint32_t aSrcIndex,
mozilla::dom::FontFaceSet* aFontFaceSet,
mozilla::dom::FontFaceSetImpl* aFontFaceSet,
nsIChannel* aChannel);
NS_DECL_ISUPPORTS
@@ -61,7 +61,7 @@ class nsFontFaceLoader final : public nsIStreamLoaderObserver,
RefPtr<gfxUserFontEntry> mUserFontEntry;
nsCOMPtr<nsIURI> mFontURI;
// Cleared in FontFaceSet::~FontFaceSet, and on cancelation and such too.
mozilla::dom::FontFaceSet* MOZ_NON_OWNING_REF mFontFaceSet;
mozilla::dom::FontFaceSetImpl* MOZ_NON_OWNING_REF mFontFaceSet;
nsCOMPtr<nsIChannel> mChannel;
nsCOMPtr<nsITimer> mLoadTimer;
mozilla::TimeStamp mStartTime;