Rename AtomicString to AtomString
[WebKit-https.git] / Source / WebCore / css / CSSFontFaceSet.cpp
1 /*
2  * Copyright (C) 2016 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 #include "config.h"
27 #include "CSSFontFaceSet.h"
28
29 #include "CSSFontFaceSource.h"
30 #include "CSSFontFamily.h"
31 #include "CSSFontSelector.h"
32 #include "CSSFontStyleValue.h"
33 #include "CSSParser.h"
34 #include "CSSPrimitiveValue.h"
35 #include "CSSSegmentedFontFace.h"
36 #include "CSSValueList.h"
37 #include "CSSValuePool.h"
38 #include "FontCache.h"
39 #include "StyleBuilderConverter.h"
40 #include "StyleProperties.h"
41
42 namespace WebCore {
43
44 CSSFontFaceSet::CSSFontFaceSet(CSSFontSelector* owningFontSelector)
45     : m_owningFontSelector(makeWeakPtr(owningFontSelector))
46 {
47 }
48
49 CSSFontFaceSet::~CSSFontFaceSet()
50 {
51     for (auto& face : m_faces)
52         face->removeClient(*this);
53
54     for (auto& pair : m_locallyInstalledFacesLookupTable) {
55         for (auto& face : pair.value)
56             face->removeClient(*this);
57     }
58 }
59
60 void CSSFontFaceSet::addClient(CSSFontFaceSetClient& client)
61 {
62     m_clients.add(&client);
63 }
64
65 void CSSFontFaceSet::removeClient(CSSFontFaceSetClient& client)
66 {
67     ASSERT(m_clients.contains(&client));
68     m_clients.remove(&client);
69 }
70
71 void CSSFontFaceSet::incrementActiveCount()
72 {
73     ++m_activeCount;
74     if (m_activeCount == 1) {
75         m_status = Status::Loading;
76         for (auto* client : m_clients)
77             client->startedLoading();
78     }
79 }
80
81 void CSSFontFaceSet::decrementActiveCount()
82 {
83     --m_activeCount;
84     if (!m_activeCount) {
85         m_status = Status::Loaded;
86         for (auto* client : m_clients)
87             client->completedLoading();
88     }
89 }
90
91 bool CSSFontFaceSet::hasFace(const CSSFontFace& face) const
92 {
93     for (auto& myFace : m_faces) {
94         if (myFace.ptr() == &face)
95             return true;
96     }
97
98     return false;
99 }
100
101 void CSSFontFaceSet::ensureLocalFontFacesForFamilyRegistered(const String& familyName)
102 {
103     ASSERT(m_owningFontSelector);
104     if (m_locallyInstalledFacesLookupTable.contains(familyName))
105         return;
106
107     AllowUserInstalledFonts allowUserInstalledFonts = AllowUserInstalledFonts::Yes;
108     if (m_owningFontSelector->document())
109         allowUserInstalledFonts = m_owningFontSelector->document()->settings().shouldAllowUserInstalledFonts() ? AllowUserInstalledFonts::Yes : AllowUserInstalledFonts::No;
110     Vector<FontSelectionCapabilities> capabilities = FontCache::singleton().getFontSelectionCapabilitiesInFamily(familyName, allowUserInstalledFonts);
111     if (capabilities.isEmpty())
112         return;
113
114     Vector<Ref<CSSFontFace>> faces;
115     for (auto item : capabilities) {
116         Ref<CSSFontFace> face = CSSFontFace::create(m_owningFontSelector.get(), nullptr, nullptr, true);
117         
118         Ref<CSSValueList> familyList = CSSValueList::createCommaSeparated();
119         familyList->append(CSSValuePool::singleton().createFontFamilyValue(familyName));
120         face->setFamilies(familyList.get());
121         face->setFontSelectionCapabilities(item);
122         face->adoptSource(std::make_unique<CSSFontFaceSource>(face.get(), familyName));
123         ASSERT(!face->computeFailureState());
124         faces.append(WTFMove(face));
125     }
126     m_locallyInstalledFacesLookupTable.add(familyName, WTFMove(faces));
127 }
128
129 String CSSFontFaceSet::familyNameFromPrimitive(const CSSPrimitiveValue& value)
130 {
131     if (value.isFontFamily())
132         return value.fontFamily().familyName;
133     if (!value.isValueID())
134         return { };
135
136     // We need to use the raw text for all the generic family types, since @font-face is a way of actually
137     // defining what font to use for those types.
138     switch (value.valueID()) {
139     case CSSValueSerif:
140         return serifFamily.get();
141     case CSSValueSansSerif:
142         return sansSerifFamily.get();
143     case CSSValueCursive:
144         return cursiveFamily.get();
145     case CSSValueFantasy:
146         return fantasyFamily.get();
147     case CSSValueMonospace:
148         return monospaceFamily.get();
149     case CSSValueWebkitPictograph:
150         return pictographFamily.get();
151     case CSSValueSystemUi:
152         return systemUiFamily.get();
153     default:
154         return { };
155     }
156 }
157
158 void CSSFontFaceSet::addToFacesLookupTable(CSSFontFace& face)
159 {
160     if (!face.families())
161         return;
162
163     for (auto& item : *face.families()) {
164         String familyName = CSSFontFaceSet::familyNameFromPrimitive(downcast<CSSPrimitiveValue>(item.get()));
165         if (familyName.isEmpty())
166             continue;
167
168         auto addResult = m_facesLookupTable.add(familyName, Vector<Ref<CSSFontFace>>());
169         auto& familyFontFaces = addResult.iterator->value;
170         if (addResult.isNewEntry) {
171             // m_locallyInstalledFontFaces grows without bound, eventually encorporating every font installed on the system.
172             // This is by design.
173             if (m_owningFontSelector)
174                 ensureLocalFontFacesForFamilyRegistered(familyName);
175             familyFontFaces = { };
176         }
177
178         familyFontFaces.append(face);
179     }
180 }
181
182 void CSSFontFaceSet::add(CSSFontFace& face)
183 {
184     ASSERT(!hasFace(face));
185
186     for (auto* client : m_clients)
187         client->fontModified();
188
189     face.addClient(*this);
190     m_cache.clear();
191
192     if (face.cssConnection())
193         m_faces.insert(m_facesPartitionIndex++, face);
194     else
195         m_faces.append(face);
196
197     addToFacesLookupTable(face);
198
199     if (face.status() == CSSFontFace::Status::Loading || face.status() == CSSFontFace::Status::TimedOut)
200         incrementActiveCount();
201
202     if (face.cssConnection()) {
203         ASSERT(!m_constituentCSSConnections.contains(face.cssConnection()));
204         m_constituentCSSConnections.add(face.cssConnection(), &face);
205     }
206 }
207
208 void CSSFontFaceSet::removeFromFacesLookupTable(const CSSFontFace& face, const CSSValueList& familiesToSearchFor)
209 {
210     for (auto& item : familiesToSearchFor) {
211         String familyName = CSSFontFaceSet::familyNameFromPrimitive(downcast<CSSPrimitiveValue>(item.get()));
212         if (familyName.isEmpty())
213             continue;
214
215         auto iterator = m_facesLookupTable.find(familyName);
216         ASSERT(iterator != m_facesLookupTable.end());
217         bool found = false;
218         for (size_t i = 0; i < iterator->value.size(); ++i) {
219             if (iterator->value[i].ptr() == &face) {
220                 found = true;
221                 iterator->value.remove(i);
222                 break;
223             }
224         }
225         ASSERT_UNUSED(found, found);
226         if (!iterator->value.size())
227             m_facesLookupTable.remove(iterator);
228     }
229 }
230
231 void CSSFontFaceSet::remove(const CSSFontFace& face)
232 {
233     auto protect = makeRef(face);
234
235     m_cache.clear();
236
237     for (auto* client : m_clients)
238         client->fontModified();
239
240     if (face.families())
241         removeFromFacesLookupTable(face, *face.families());
242
243     if (face.cssConnection()) {
244         ASSERT(m_constituentCSSConnections.get(face.cssConnection()) == &face);
245         m_constituentCSSConnections.remove(face.cssConnection());
246     }
247
248     for (size_t i = 0; i < m_faces.size(); ++i) {
249         if (m_faces[i].ptr() == &face) {
250             if (i < m_facesPartitionIndex)
251                 --m_facesPartitionIndex;
252             m_faces[i]->removeClient(*this);
253             m_faces.remove(i);
254             if (face.status() == CSSFontFace::Status::Loading || face.status() == CSSFontFace::Status::TimedOut)
255                 decrementActiveCount();
256             return;
257         }
258     }
259     ASSERT_NOT_REACHED();
260 }
261
262 CSSFontFace* CSSFontFaceSet::lookUpByCSSConnection(StyleRuleFontFace& target)
263 {
264     return m_constituentCSSConnections.get(&target);
265 }
266
267 void CSSFontFaceSet::purge()
268 {
269     Vector<Ref<CSSFontFace>> toRemove;
270     for (auto& face : m_faces) {
271         if (face->purgeable())
272             toRemove.append(face.copyRef());
273     }
274
275     for (auto& item : toRemove)
276         remove(item.get());
277 }
278
279 void CSSFontFaceSet::emptyCaches()
280 {
281     m_cache.clear();
282 }
283
284 void CSSFontFaceSet::clear()
285 {
286     for (auto& face : m_faces)
287         face->removeClient(*this);
288     m_faces.clear();
289     m_facesLookupTable.clear();
290     m_locallyInstalledFacesLookupTable.clear();
291     m_cache.clear();
292     m_constituentCSSConnections.clear();
293     m_facesPartitionIndex = 0;
294     m_status = Status::Loaded;
295 }
296
297 CSSFontFace& CSSFontFaceSet::operator[](size_t i)
298 {
299     ASSERT(i < faceCount());
300     return m_faces[i];
301 }
302
303 static FontSelectionRequest computeFontSelectionRequest(MutableStyleProperties& style)
304 {
305     RefPtr<CSSValue> weightValue = style.getPropertyCSSValue(CSSPropertyFontWeight).get();
306     if (!weightValue)
307         weightValue = CSSValuePool::singleton().createIdentifierValue(CSSValueNormal).ptr();
308
309     RefPtr<CSSValue> stretchValue = style.getPropertyCSSValue(CSSPropertyFontStretch).get();
310     if (!stretchValue)
311         stretchValue = CSSValuePool::singleton().createIdentifierValue(CSSValueNormal).ptr();
312
313     RefPtr<CSSValue> styleValue = style.getPropertyCSSValue(CSSPropertyFontStyle).get();
314     if (!styleValue)
315         styleValue = CSSFontStyleValue::create(CSSValuePool::singleton().createIdentifierValue(CSSValueNormal));
316
317     auto weightSelectionValue = StyleBuilderConverter::convertFontWeightFromValue(*weightValue);
318     auto stretchSelectionValue = StyleBuilderConverter::convertFontStretchFromValue(*stretchValue);
319     auto styleSelectionValue = StyleBuilderConverter::convertFontStyleFromValue(*styleValue);
320
321     return { weightSelectionValue, stretchSelectionValue, styleSelectionValue };
322 }
323
324 static HashSet<UChar32> codePointsFromString(StringView stringView)
325 {
326     HashSet<UChar32> result;
327     auto graphemeClusters = stringView.graphemeClusters();
328     for (auto cluster : graphemeClusters) {
329         ASSERT(cluster.length() > 0);
330         UChar32 character = 0;
331         if (cluster.is8Bit())
332             character = cluster[0];
333         else
334             U16_GET(cluster.characters16(), 0, 0, cluster.length(), character);
335         result.add(character);
336     }
337     return result;
338 }
339
340 ExceptionOr<Vector<std::reference_wrapper<CSSFontFace>>> CSSFontFaceSet::matchingFacesExcludingPreinstalledFonts(const String& font, const String& string)
341 {
342     auto style = MutableStyleProperties::create();
343     auto parseResult = CSSParser::parseValue(style, CSSPropertyFont, font, true, HTMLStandardMode);
344     if (parseResult == CSSParser::ParseResult::Error)
345         return Exception { SyntaxError };
346
347     FontSelectionRequest request = computeFontSelectionRequest(style.get());
348
349     auto family = style->getPropertyCSSValue(CSSPropertyFontFamily);
350     if (!is<CSSValueList>(family))
351         return Exception { SyntaxError };
352     CSSValueList& familyList = downcast<CSSValueList>(*family);
353
354     HashSet<AtomString> uniqueFamilies;
355     Vector<AtomString> familyOrder;
356     for (auto& family : familyList) {
357         auto& primitive = downcast<CSSPrimitiveValue>(family.get());
358         if (!primitive.isFontFamily())
359             continue;
360         if (uniqueFamilies.add(primitive.fontFamily().familyName).isNewEntry)
361             familyOrder.append(primitive.fontFamily().familyName);
362     }
363
364     HashSet<CSSFontFace*> resultConstituents;
365     for (auto codePoint : codePointsFromString(string)) {
366         bool found = false;
367         for (auto& family : familyOrder) {
368             auto* faces = fontFace(request, family);
369             if (!faces)
370                 continue;
371             for (auto& constituentFace : faces->constituentFaces()) {
372                 if (constituentFace->isLocalFallback())
373                     continue;
374                 if (constituentFace->rangesMatchCodePoint(codePoint)) {
375                     resultConstituents.add(constituentFace.ptr());
376                     found = true;
377                     break;
378                 }
379             }
380             if (found)
381                 break;
382         }
383     }
384
385     Vector<std::reference_wrapper<CSSFontFace>> result;
386     result.reserveInitialCapacity(resultConstituents.size());
387     for (auto* constituent : resultConstituents)
388         result.uncheckedAppend(*constituent);
389     return result;
390 }
391
392 ExceptionOr<bool> CSSFontFaceSet::check(const String& font, const String& text)
393 {
394     auto matchingFaces = this->matchingFacesExcludingPreinstalledFonts(font, text);
395     if (matchingFaces.hasException())
396         return matchingFaces.releaseException();
397
398     for (auto& face : matchingFaces.releaseReturnValue()) {
399         if (face.get().status() == CSSFontFace::Status::Pending)
400             return false;
401     }
402     return true;
403 }
404
405 CSSSegmentedFontFace* CSSFontFaceSet::fontFace(FontSelectionRequest request, const AtomString& family)
406 {
407     auto iterator = m_facesLookupTable.find(family);
408     if (iterator == m_facesLookupTable.end())
409         return nullptr;
410     auto& familyFontFaces = iterator->value;
411
412     auto& segmentedFontFaceCache = m_cache.add(family, FontSelectionHashMap()).iterator->value;
413
414     auto& face = segmentedFontFaceCache.add(request, nullptr).iterator->value;
415     if (face)
416         return face.get();
417
418     face = CSSSegmentedFontFace::create();
419
420     Vector<std::reference_wrapper<CSSFontFace>, 32> candidateFontFaces;
421     for (int i = familyFontFaces.size() - 1; i >= 0; --i) {
422         CSSFontFace& candidate = familyFontFaces[i];
423         auto capabilities = candidate.fontSelectionCapabilities();
424         if (!isItalic(request.slope) && isItalic(capabilities.slope.minimum))
425             continue;
426         candidateFontFaces.append(candidate);
427     }
428
429     auto localIterator = m_locallyInstalledFacesLookupTable.find(family);
430     if (localIterator != m_locallyInstalledFacesLookupTable.end()) {
431         for (auto& candidate : localIterator->value) {
432             auto capabilities = candidate->fontSelectionCapabilities();
433             if (!isItalic(request.slope) && isItalic(capabilities.slope.minimum))
434                 continue;
435             candidateFontFaces.append(candidate);
436         }
437     }
438
439     if (!candidateFontFaces.isEmpty()) {
440         Vector<FontSelectionCapabilities> capabilities;
441         capabilities.reserveInitialCapacity(candidateFontFaces.size());
442         for (auto& face : candidateFontFaces)
443             capabilities.uncheckedAppend(face.get().fontSelectionCapabilities());
444         FontSelectionAlgorithm fontSelectionAlgorithm(request, capabilities);
445         std::stable_sort(candidateFontFaces.begin(), candidateFontFaces.end(), [&fontSelectionAlgorithm](const CSSFontFace& first, const CSSFontFace& second) {
446             auto firstCapabilities = first.fontSelectionCapabilities();
447             auto secondCapabilities = second.fontSelectionCapabilities();
448
449             auto stretchDistanceFirst = fontSelectionAlgorithm.stretchDistance(firstCapabilities).distance;
450             auto stretchDistanceSecond = fontSelectionAlgorithm.stretchDistance(secondCapabilities).distance;
451             if (stretchDistanceFirst < stretchDistanceSecond)
452                 return true;
453             if (stretchDistanceFirst > stretchDistanceSecond)
454                 return false;
455
456             auto styleDistanceFirst = fontSelectionAlgorithm.styleDistance(firstCapabilities).distance;
457             auto styleDistanceSecond = fontSelectionAlgorithm.styleDistance(secondCapabilities).distance;
458             if (styleDistanceFirst < styleDistanceSecond)
459                 return true;
460             if (styleDistanceFirst > styleDistanceSecond)
461                 return false;
462
463             auto weightDistanceFirst = fontSelectionAlgorithm.weightDistance(firstCapabilities).distance;
464             auto weightDistanceSecond = fontSelectionAlgorithm.weightDistance(secondCapabilities).distance;
465             if (weightDistanceFirst < weightDistanceSecond)
466                 return true;
467             return false;
468         });
469         for (auto& candidate : candidateFontFaces)
470             face->appendFontFace(candidate.get());
471     }
472
473     return face.get();
474 }
475
476 void CSSFontFaceSet::fontStateChanged(CSSFontFace& face, CSSFontFace::Status oldState, CSSFontFace::Status newState)
477 {
478     ASSERT(hasFace(face));
479     if (oldState == CSSFontFace::Status::Pending) {
480         ASSERT(newState == CSSFontFace::Status::Loading);
481         incrementActiveCount();
482     }
483     if (newState == CSSFontFace::Status::Success || newState == CSSFontFace::Status::Failure) {
484         ASSERT(oldState == CSSFontFace::Status::Loading || oldState == CSSFontFace::Status::TimedOut);
485         for (auto* client : m_clients)
486             client->faceFinished(face, newState);
487         decrementActiveCount();
488     }
489 }
490
491 void CSSFontFaceSet::fontPropertyChanged(CSSFontFace& face, CSSValueList* oldFamilies)
492 {
493     m_cache.clear();
494
495     if (oldFamilies) {
496         removeFromFacesLookupTable(face, *oldFamilies);
497         addToFacesLookupTable(face);
498     }
499
500     for (auto* client : m_clients)
501         client->fontModified();
502 }
503
504 }