1/*
2 * Copyright (C) 2016-2017 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#pragma once
27
28#include "CSSFontFace.h"
29#include <wtf/HashMap.h>
30#include <wtf/Vector.h>
31#include <wtf/text/StringHash.h>
32
33namespace WebCore {
34
35class CSSPrimitiveValue;
36class FontFaceSet;
37
38class CSSFontFaceSetClient {
39public:
40 virtual ~CSSFontFaceSetClient() = default;
41 virtual void faceFinished(CSSFontFace&, CSSFontFace::Status) { };
42 virtual void fontModified() { };
43 virtual void startedLoading() { };
44 virtual void completedLoading() { };
45};
46
47class CSSFontFaceSet final : public RefCounted<CSSFontFaceSet>, public CSSFontFace::Client {
48public:
49 static Ref<CSSFontFaceSet> create(CSSFontSelector* owningFontSelector = nullptr)
50 {
51 return adoptRef(*new CSSFontFaceSet(owningFontSelector));
52 }
53 ~CSSFontFaceSet();
54
55 void addClient(CSSFontFaceSetClient&);
56 void removeClient(CSSFontFaceSetClient&);
57
58 bool hasFace(const CSSFontFace&) const;
59 size_t faceCount() const { return m_faces.size(); }
60 void add(CSSFontFace&);
61 void remove(const CSSFontFace&);
62 void purge();
63 void emptyCaches();
64 void clear();
65 CSSFontFace& operator[](size_t i);
66
67 CSSFontFace* lookUpByCSSConnection(StyleRuleFontFace&);
68
69 ExceptionOr<bool> check(const String& font, const String& text);
70
71 CSSSegmentedFontFace* fontFace(FontSelectionRequest, const AtomicString& family);
72
73 enum class Status { Loading, Loaded };
74 Status status() const { return m_status; }
75
76 bool hasActiveFontFaces() { return status() == Status::Loading; }
77
78 ExceptionOr<Vector<std::reference_wrapper<CSSFontFace>>> matchingFacesExcludingPreinstalledFonts(const String& font, const String& text);
79
80 // CSSFontFace::Client needs to be able to be held in a RefPtr.
81 void ref() final { RefCounted::ref(); }
82 void deref() final { RefCounted::deref(); }
83
84private:
85 CSSFontFaceSet(CSSFontSelector*);
86
87 void removeFromFacesLookupTable(const CSSFontFace&, const CSSValueList& familiesToSearchFor);
88 void addToFacesLookupTable(CSSFontFace&);
89
90 void incrementActiveCount();
91 void decrementActiveCount();
92
93 void fontStateChanged(CSSFontFace&, CSSFontFace::Status oldState, CSSFontFace::Status newState) final;
94 void fontPropertyChanged(CSSFontFace&, CSSValueList* oldFamilies = nullptr) final;
95
96 void ensureLocalFontFacesForFamilyRegistered(const String&);
97
98 static String familyNameFromPrimitive(const CSSPrimitiveValue&);
99
100 using FontSelectionKey = Optional<FontSelectionRequest>;
101 struct FontSelectionKeyHash {
102 static unsigned hash(const FontSelectionKey& key) { return computeHash(key); }
103 static bool equal(const FontSelectionKey& a, const FontSelectionKey& b) { return a == b; }
104 static const bool safeToCompareToEmptyOrDeleted = true;
105 };
106 struct FontSelectionKeyHashTraits : SimpleClassHashTraits<FontSelectionKey> {
107 static const bool emptyValueIsZero = false;
108 static FontSelectionKey emptyValue() { return FontSelectionRequest { }; }
109 static void constructDeletedValue(FontSelectionKey& slot) { slot = WTF::nullopt; }
110 static bool isDeletedValue(const FontSelectionKey& value) { return !value; }
111 };
112 using FontSelectionHashMap = HashMap<FontSelectionKey, RefPtr<CSSSegmentedFontFace>, FontSelectionKeyHash, FontSelectionKeyHashTraits>;
113
114 // m_faces should hold all the same fonts as the ones inside inside m_facesLookupTable.
115 Vector<Ref<CSSFontFace>> m_faces; // We should investigate moving m_faces to FontFaceSet and making it reference FontFaces. This may clean up the font loading design.
116 HashMap<String, Vector<Ref<CSSFontFace>>, ASCIICaseInsensitiveHash> m_facesLookupTable;
117 HashMap<String, Vector<Ref<CSSFontFace>>, ASCIICaseInsensitiveHash> m_locallyInstalledFacesLookupTable;
118 HashMap<String, FontSelectionHashMap, ASCIICaseInsensitiveHash> m_cache;
119 HashMap<StyleRuleFontFace*, CSSFontFace*> m_constituentCSSConnections;
120 size_t m_facesPartitionIndex { 0 }; // All entries in m_faces before this index are CSS-connected.
121 Status m_status { Status::Loaded };
122 HashSet<CSSFontFaceSetClient*> m_clients;
123 WeakPtr<CSSFontSelector> m_owningFontSelector;
124 unsigned m_activeCount { 0 };
125};
126
127}
128