[Font Loading] Crash when a single load request causes multiple fonts to fail loading
[WebKit-https.git] / Source / WebCore / css / FontFaceSet.h
index c05ed18e4ce8af51f8f2e8041251ab54001dc2c7..870d1335ebd2cb57bce9b43aecc8b1379b0a6bd3 100644 (file)
@@ -31,6 +31,7 @@
 #include "DOMCoreException.h"
 #include "EventTarget.h"
 #include "JSDOMPromise.h"
+#include <wtf/HashTraits.h>
 #include <wtf/Optional.h>
 #include <wtf/Ref.h>
 #include <wtf/RefCounted.h>
 #include <wtf/Vector.h>
 #include <wtf/text/WTFString.h>
 
+namespace JSC {
+class ExecState;
+}
+
 namespace WebCore {
 
 class Document;
@@ -45,22 +50,18 @@ class FontFace;
 
 class FontFaceSet final : public RefCounted<FontFaceSet>, public CSSFontFaceSetClient, public EventTargetWithInlineData, public ActiveDOMObject {
 public:
-    static Ref<FontFaceSet> create(JSC::ExecState& execState, Document& document, const Vector<RefPtr<FontFace>>& initialFaces)
-    {
-        Ref<FontFaceSet> result = adoptRef(*new FontFaceSet(execState, document, initialFaces));
-        result->suspendIfNeeded();
-        return result;
-    }
+    static Ref<FontFaceSet> create(Document&, const Vector<RefPtr<FontFace>>& initialFaces);
+    static Ref<FontFaceSet> create(Document&, CSSFontFaceSet& backing);
     virtual ~FontFaceSet();
 
-    bool has(FontFace*) const;
+    bool has(RefPtr<WebCore::FontFace>) const;
     size_t size() const;
-    FontFaceSet& add(FontFace*);
-    bool remove(FontFace*);
+    FontFaceSet& add(RefPtr<WebCore::FontFace>);
+    bool remove(RefPtr<WebCore::FontFace>);
     void clear();
 
-    void load(const String& font, DeferredWrapper&& promise, ExceptionCode& ec) { load(font, String(" ", String::ConstructFromLiteral), WTFMove(promise), ec); }
-    void load(const String& font, const String& text, DeferredWrapper&& promise, ExceptionCode&);
+    void load(JSC::ExecState& execState, const String& font, DeferredWrapper&& promise, ExceptionCode& ec) { load(execState, font, String(" ", String::ConstructFromLiteral), WTFMove(promise), ec); }
+    void load(JSC::ExecState&, const String& font, const String& text, DeferredWrapper&& promise, ExceptionCode&);
     bool check(const String& font, ExceptionCode& ec) { return check(font, String(" ", String::ConstructFromLiteral), ec); }
     bool check(const String& font, const String& text, ExceptionCode&);
 
@@ -69,18 +70,16 @@ public:
     typedef DOMPromise<FontFaceSet&, DOMCoreException&> Promise;
     Promise& promise(JSC::ExecState&);
 
+    CSSFontFaceSet& backing() { return m_backing; }
+
     class Iterator {
     public:
         explicit Iterator(FontFaceSet&);
-
-        using Key = RefPtr<FontFace>;
-        using Value = RefPtr<FontFace>;
-
-        bool next(Key& nextKey, Value& nextValue);
+        Optional<WTF::KeyValuePair<RefPtr<FontFace>, RefPtr<FontFace>>> next(JSC::ExecState&);
 
     private:
         Ref<FontFaceSet> m_target;
-        size_t m_index { 0 };
+        size_t m_index { 0 }; // FIXME: There needs to be a mechanism to handle when fonts are added or removed from the middle of the FontFaceSet.
     };
     Iterator createIterator() { return Iterator(*this); }
 
@@ -102,29 +101,31 @@ private:
     public:
         Vector<RefPtr<FontFace>> faces;
         Promise promise;
+        bool hasReachedTerminalState { false };
     };
 
-    FontFaceSet(JSC::ExecState&, Document&, const Vector<RefPtr<FontFace>>&);
+    FontFaceSet(Document&, const Vector<RefPtr<FontFace>>&);
+    FontFaceSet(Document&, CSSFontFaceSet&);
 
     void fulfillPromise();
 
     // CSSFontFaceSetClient
-    virtual void startedLoading() override;
-    virtual void completedLoading() override;
-    virtual void faceFinished(CSSFontFace&, CSSFontFace::Status) override;
+    void startedLoading() override;
+    void completedLoading() override;
+    void faceFinished(CSSFontFace&, CSSFontFace::Status) override;
 
     // ActiveDOMObject
-    virtual const char* activeDOMObjectName() const override { return "FontFaceSet"; }
-    virtual bool canSuspendForDocumentSuspension() const override;
+    const char* activeDOMObjectName() const override { return "FontFaceSet"; }
+    bool canSuspendForDocumentSuspension() const override;
 
     // EventTarget
-    virtual EventTargetInterface eventTargetInterface() const override { return FontFaceSetEventTargetInterfaceType; }
-    virtual ScriptExecutionContext* scriptExecutionContext() const override { return ActiveDOMObject::scriptExecutionContext(); }
-    virtual void refEventTarget() override { ref(); }
-    virtual void derefEventTarget() override { deref(); }
+    EventTargetInterface eventTargetInterface() const override { return FontFaceSetEventTargetInterfaceType; }
+    ScriptExecutionContext* scriptExecutionContext() const override { return ActiveDOMObject::scriptExecutionContext(); }
+    void refEventTarget() override { ref(); }
+    void derefEventTarget() override { deref(); }
 
-    CSSFontFaceSet m_backing;
-    HashMap<RefPtr<FontFace>, Vector<Ref<PendingPromise>>> m_pendingPromises;
+    Ref<CSSFontFaceSet> m_backing;
+    HashMap<RefPtr<CSSFontFace>, Vector<Ref<PendingPromise>>> m_pendingPromises;
     Optional<Promise> m_promise;
 };