CSS Font Loading: FontFaceSet.ready should return the same promise each time

Use ScriptPromiseProperty to return same promise every time, until the
FontFaceSet switches from loaded to loading state. This is in line with
the spec, and also simplifies the code a bit.

TEST=fast/css/fontfaceset-ready.html
BUG=510434

Review URL: https://codereview.chromium.org/1313853003

git-svn-id: svn://svn.chromium.org/blink/trunk@201857 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent 591abc73
<!DOCTYPE html>
<title>FontFaceSet.ready attribute</title>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<script>
promise_test(function(t) {
assert_equals(document.fonts.ready, document.fonts.ready,
'FontFaceSet.ready should return the same promise');
var face = new FontFace('test', 'url(../../resources/Ahem.ttf)');
return document.fonts.ready
.then(function(fonts) {
assert_equals(fonts, document.fonts,
'FontFaceSet.ready should be resolved with the FontFaceSet');
var oldReady = document.fonts.ready;
document.fonts.add(face);
assert_equals(document.fonts.ready, oldReady,
'FontFaceSet.ready should not be replaced when FontFace added to it is not loading');
assert_equals(document.fonts.status, 'loaded',
'FontFaceSet.status after adding unloaded FontFace');
face.load();
var newReady = document.fonts.ready;
assert_not_equals(newReady, oldReady,
'FontFaceSet.ready should be replaced when a FontFace in it started loading');
assert_equals(document.fonts.status, 'loading',
'FontFaceSet.status after calling load() on a FontFace in it');
return newReady;
}).then(function(fonts) {
assert_equals(face.status, 'loaded',
'FontFaceSet.ready should be resolved after all fonts have been loaded');
assert_equals(document.fonts.status, 'loaded',
'FontFaceSet.status after FontFaceSet.ready is resolved');
});
}, 'FontFaceSet.ready attribute');
</script>
......@@ -114,38 +114,11 @@ DEFINE_TRACE(LoadFontPromiseResolver)
LoadFontCallback::trace(visitor);
}
class FontsReadyPromiseResolver final : public GarbageCollected<FontsReadyPromiseResolver> {
public:
static FontsReadyPromiseResolver* create(ScriptState* scriptState)
{
return new FontsReadyPromiseResolver(scriptState);
}
void resolve(PassRefPtrWillBeRawPtr<FontFaceSet> fontFaceSet)
{
m_resolver->resolve(fontFaceSet);
}
ScriptPromise promise() { return m_resolver->promise(); }
DEFINE_INLINE_TRACE()
{
visitor->trace(m_resolver);
}
private:
explicit FontsReadyPromiseResolver(ScriptState* scriptState)
: m_resolver(ScriptPromiseResolver::create(scriptState))
{
}
Member<ScriptPromiseResolver> m_resolver;
};
FontFaceSet::FontFaceSet(Document& document)
: ActiveDOMObject(&document)
, m_shouldFireLoadingEvent(false)
, m_isLoading(false)
, m_ready(new ReadyProperty(executionContext(), this, ReadyProperty::Ready))
, m_asyncRunner(this, &FontFaceSet::handlePendingEventsAndPromises)
{
suspendIfNeeded();
......@@ -199,11 +172,18 @@ void FontFaceSet::didLayout()
{
if (document()->frame()->isMainFrame() && m_loadingFonts.isEmpty())
m_histogram.record();
if (!m_loadingFonts.isEmpty() || (!m_isLoading && m_readyResolvers.isEmpty()))
if (!shouldSignalReady())
return;
handlePendingEventsAndPromisesSoon();
}
bool FontFaceSet::shouldSignalReady() const
{
if (!m_loadingFonts.isEmpty())
return false;
return m_isLoading || m_ready->state() == ReadyProperty::Pending;
}
void FontFaceSet::handlePendingEventsAndPromises()
{
fireLoadingEvent();
......@@ -258,6 +238,8 @@ void FontFaceSet::addToLoadingFonts(PassRefPtrWillBeRawPtr<FontFace> fontFace)
if (!m_isLoading) {
m_isLoading = true;
m_shouldFireLoadingEvent = true;
if (m_ready->state() != ReadyProperty::Pending)
m_ready->reset();
handlePendingEventsAndPromisesSoon();
}
m_loadingFonts.add(fontFace);
......@@ -272,13 +254,7 @@ void FontFaceSet::removeFromLoadingFonts(PassRefPtrWillBeRawPtr<FontFace> fontFa
ScriptPromise FontFaceSet::ready(ScriptState* scriptState)
{
if (!inActiveDocumentContext())
return ScriptPromise();
FontsReadyPromiseResolver* resolver = FontsReadyPromiseResolver::create(scriptState);
ScriptPromise promise = resolver->promise();
m_readyResolvers.append(resolver);
handlePendingEventsAndPromisesSoon();
return promise;
return m_ready->promise(scriptState->world());
}
void FontFaceSet::add(FontFace* fontFace, ExceptionState& exceptionState)
......@@ -406,7 +382,7 @@ void FontFaceSet::fireDoneEventIfPossible()
{
if (m_shouldFireLoadingEvent)
return;
if (!m_loadingFonts.isEmpty() || (!m_isLoading && m_readyResolvers.isEmpty()))
if (!shouldSignalReady())
return;
// If the layout was invalidated in between when we thought layout
......@@ -431,12 +407,8 @@ void FontFaceSet::fireDoneEventIfPossible()
dispatchEvent(errorEvent);
}
if (!m_readyResolvers.isEmpty()) {
HeapVector<Member<FontsReadyPromiseResolver>> resolvers;
m_readyResolvers.swap(resolvers);
for (size_t index = 0; index < resolvers.size(); ++index)
resolvers[index]->resolve(this);
}
if (m_ready->state() == ReadyProperty::Pending)
m_ready->resolve(this);
}
ScriptPromise FontFaceSet::load(ScriptState* scriptState, const String& fontString, const String& text)
......@@ -582,8 +554,8 @@ void FontFaceSet::didLayout(Document& document)
DEFINE_TRACE(FontFaceSet)
{
#if ENABLE(OILPAN)
visitor->trace(m_ready);
visitor->trace(m_loadingFonts);
visitor->trace(m_readyResolvers);
visitor->trace(m_loadedFonts);
visitor->trace(m_failedFonts);
visitor->trace(m_nonCSSConnectedFaces);
......
......@@ -55,7 +55,6 @@ class ExceptionState;
class Font;
class FontFaceCache;
class FontResource;
class FontsReadyPromiseResolver;
class ExecutionContext;
#if ENABLE(OILPAN)
......@@ -145,11 +144,14 @@ private:
void handlePendingEventsAndPromises();
const WillBeHeapListHashSet<RefPtrWillBeMember<FontFace>>& cssConnectedFontFaceList() const;
bool isCSSConnectedFontFace(FontFace*) const;
bool shouldSignalReady() const;
typedef ScriptPromiseProperty<RawPtrWillBeMember<FontFaceSet>, RawPtrWillBeMember<FontFaceSet>, Member<DOMException>> ReadyProperty;
WillBeHeapHashSet<RefPtrWillBeMember<FontFace>> m_loadingFonts;
bool m_shouldFireLoadingEvent;
bool m_isLoading;
PersistentHeapVectorWillBeHeapVector<Member<FontsReadyPromiseResolver>> m_readyResolvers;
PersistentWillBeMember<ReadyProperty> m_ready;
FontFaceArray m_loadedFonts;
FontFaceArray m_failedFonts;
WillBeHeapListHashSet<RefPtrWillBeMember<FontFace>> m_nonCSSConnectedFaces;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment