Unreviewed, rolling out r201887.
[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 "CSSParser.h"
33 #include "CSSPrimitiveValue.h"
34 #include "CSSSegmentedFontFace.h"
35 #include "CSSValueList.h"
36 #include "CSSValuePool.h"
37 #include "FontCache.h"
38 #include "StyleProperties.h"
39
40 namespace WebCore {
41
42 CSSFontFaceSet::CSSFontFaceSet()
43 {
44 }
45
46 CSSFontFaceSet::~CSSFontFaceSet()
47 {
48     for (auto& face : m_faces)
49         face->removeClient(*this);
50
51     for (auto& pair : m_locallyInstalledFacesLookupTable) {
52         for (auto& face : pair.value)
53             face->removeClient(*this);
54     }
55 }
56
57 void CSSFontFaceSet::addClient(CSSFontFaceSetClient& client)
58 {
59     m_clients.add(&client);
60 }
61
62 void CSSFontFaceSet::removeClient(CSSFontFaceSetClient& client)
63 {
64     ASSERT(m_clients.contains(&client));
65     m_clients.remove(&client);
66 }
67
68 void CSSFontFaceSet::incrementActiveCount()
69 {
70     ++m_activeCount;
71     if (m_activeCount == 1) {
72         m_status = Status::Loading;
73         for (auto* client : m_clients)
74             client->startedLoading();
75     }
76 }
77
78 void CSSFontFaceSet::decrementActiveCount()
79 {
80     --m_activeCount;
81     if (!m_activeCount) {
82         m_status = Status::Loaded;
83         for (auto* client : m_clients)
84             client->completedLoading();
85     }
86 }
87
88 bool CSSFontFaceSet::hasFace(const CSSFontFace& face) const
89 {
90     for (auto& myFace : m_faces) {
91         if (myFace.ptr() == &face)
92             return true;
93     }
94
95     return false;
96 }
97
98 void CSSFontFaceSet::registerLocalFontFacesForFamily(const String& familyName)
99 {
100     ASSERT(!m_locallyInstalledFacesLookupTable.contains(familyName));
101
102     Vector<FontTraitsMask> traitsMasks = FontCache::singleton().getTraitsInFamily(familyName);
103     if (traitsMasks.isEmpty())
104         return;
105
106     Vector<Ref<CSSFontFace>> faces;
107     for (auto mask : traitsMasks) {
108         Ref<CSSFontFace> face = CSSFontFace::create(nullptr, nullptr, nullptr, true);
109         
110         Ref<CSSValueList> familyList = CSSValueList::createCommaSeparated();
111         familyList->append(CSSValuePool::singleton().createFontFamilyValue(familyName));
112         face->setFamilies(familyList.get());
113         face->setTraitsMask(mask);
114         face->adoptSource(std::make_unique<CSSFontFaceSource>(face.get(), familyName));
115         ASSERT(!face->allSourcesFailed());
116         faces.append(WTFMove(face));
117     }
118     m_locallyInstalledFacesLookupTable.add(familyName, WTFMove(faces));
119 }
120
121 String CSSFontFaceSet::familyNameFromPrimitive(const CSSPrimitiveValue& value)
122 {
123     if (value.isFontFamily())
124         return value.fontFamily().familyName;
125     if (!value.isValueID())
126         return { };
127
128     // We need to use the raw text for all the generic family types, since @font-face is a way of actually
129     // defining what font to use for those types.
130     switch (value.getValueID()) {
131     case CSSValueSerif:
132         return serifFamily;
133     case CSSValueSansSerif:
134         return sansSerifFamily;
135     case CSSValueCursive:
136         return cursiveFamily;
137     case CSSValueFantasy:
138         return fantasyFamily;
139     case CSSValueMonospace:
140         return monospaceFamily;
141     case CSSValueWebkitPictograph:
142         return pictographFamily;
143     default:
144         return { };
145     }
146 }
147
148 void CSSFontFaceSet::addToFacesLookupTable(CSSFontFace& face)
149 {
150     if (!face.families())
151         return;
152
153     for (auto& item : *face.families()) {
154         String familyName = CSSFontFaceSet::familyNameFromPrimitive(downcast<CSSPrimitiveValue>(item.get()));
155         if (familyName.isEmpty())
156             continue;
157
158         auto addResult = m_facesLookupTable.add(familyName, Vector<Ref<CSSFontFace>>());
159         auto& familyFontFaces = addResult.iterator->value;
160         if (addResult.isNewEntry) {
161             // m_locallyInstalledFontFaces grows without bound, eventually encorporating every font installed on the system.
162             // This is by design.
163             registerLocalFontFacesForFamily(familyName);
164             familyFontFaces = { };
165         }
166
167         familyFontFaces.append(face);
168     }
169 }
170
171 void CSSFontFaceSet::add(CSSFontFace& face)
172 {
173     ASSERT(!hasFace(face));
174
175     for (auto* client : m_clients)
176         client->fontModified();
177
178     face.addClient(*this);
179     m_cache.clear();
180
181     if (face.cssConnection())
182         m_faces.insert(m_facesPartitionIndex++, face);
183     else
184         m_faces.append(face);
185
186     addToFacesLookupTable(face);
187
188     if (face.status() == CSSFontFace::Status::Loading || face.status() == CSSFontFace::Status::TimedOut)
189         incrementActiveCount();
190 }
191
192 void CSSFontFaceSet::removeFromFacesLookupTable(const CSSFontFace& face, const CSSValueList& familiesToSearchFor)
193 {
194     for (auto& item : familiesToSearchFor) {
195         String familyName = CSSFontFaceSet::familyNameFromPrimitive(downcast<CSSPrimitiveValue>(item.get()));
196         if (familyName.isEmpty())
197             continue;
198
199         auto iterator = m_facesLookupTable.find(familyName);
200         ASSERT(iterator != m_facesLookupTable.end());
201         bool found = false;
202         for (size_t i = 0; i < iterator->value.size(); ++i) {
203             if (iterator->value[i].ptr() == &face) {
204                 found = true;
205                 iterator->value.remove(i);
206                 break;
207             }
208         }
209         ASSERT_UNUSED(found, found);
210         if (!iterator->value.size())
211             m_facesLookupTable.remove(iterator);
212     }
213 }
214
215 void CSSFontFaceSet::remove(const CSSFontFace& face)
216 {
217     m_cache.clear();
218
219     for (auto* client : m_clients)
220         client->fontModified();
221
222     if (face.families())
223         removeFromFacesLookupTable(face, *face.families());
224
225     for (size_t i = 0; i < m_faces.size(); ++i) {
226         if (m_faces[i].ptr() == &face) {
227             if (i < m_facesPartitionIndex)
228                 --m_facesPartitionIndex;
229             m_faces[i]->removeClient(*this);
230             m_faces.remove(i);
231             if (face.status() == CSSFontFace::Status::Loading || face.status() == CSSFontFace::Status::TimedOut)
232                 decrementActiveCount();
233             return;
234         }
235     }
236     ASSERT_NOT_REACHED();
237 }
238
239 void CSSFontFaceSet::clear()
240 {
241     for (auto& face : m_faces)
242         face->removeClient(*this);
243     m_faces.clear();
244     m_facesLookupTable.clear();
245     m_locallyInstalledFacesLookupTable.clear();
246     m_cache.clear();
247     m_facesPartitionIndex = 0;
248     m_status = Status::Loaded;
249 }
250
251 CSSFontFace& CSSFontFaceSet::operator[](size_t i)
252 {
253     ASSERT(i < faceCount());
254     return m_faces[i];
255 }
256
257 static Optional<FontTraitsMask> computeFontTraitsMask(MutableStyleProperties& style)
258 {
259     RefPtr<CSSValue> styleValue = style.getPropertyCSSValue(CSSPropertyFontStyle).get();
260     if (!styleValue)
261         styleValue = CSSValuePool::singleton().createIdentifierValue(CSSValueNormal).ptr();
262
263     FontTraitsMask styleMask;
264     if (auto styleMaskOptional = CSSFontFace::calculateStyleMask(*styleValue))
265         styleMask = styleMaskOptional.value();
266     else
267         return Nullopt;
268
269     RefPtr<CSSValue> weightValue = style.getPropertyCSSValue(CSSPropertyFontWeight).get();
270     if (!weightValue)
271         weightValue = CSSValuePool::singleton().createIdentifierValue(CSSValueNormal).ptr();
272
273     FontTraitsMask weightMask;
274     if (auto weightMaskOptional = CSSFontFace::calculateWeightMask(*weightValue))
275         weightMask = weightMaskOptional.value();
276     else
277         return Nullopt;
278
279     return static_cast<FontTraitsMask>(static_cast<unsigned>(styleMask) | static_cast<unsigned>(weightMask));
280 }
281
282 Vector<std::reference_wrapper<CSSFontFace>> CSSFontFaceSet::matchingFaces(const String& font, const String&, ExceptionCode& ec)
283 {
284     Vector<std::reference_wrapper<CSSFontFace>> result;
285     auto style = MutableStyleProperties::create();
286     auto parseResult = CSSParser::parseValue(style, CSSPropertyFont, font, true, CSSStrictMode, nullptr);
287     if (parseResult == CSSParser::ParseResult::Error) {
288         ec = SYNTAX_ERR;
289         return result;
290     }
291
292     FontTraitsMask fontTraitsMask;
293     if (auto maskOptional = computeFontTraitsMask(style.get()))
294         fontTraitsMask = maskOptional.value();
295     else {
296         ec = SYNTAX_ERR;
297         return result;
298     }
299
300     RefPtr<CSSValue> family = style->getPropertyCSSValue(CSSPropertyFontFamily);
301     if (!is<CSSValueList>(family.get())) {
302         ec = SYNTAX_ERR;
303         return result;
304     }
305     CSSValueList& familyList = downcast<CSSValueList>(*family);
306
307     HashSet<AtomicString> uniqueFamilies;
308     for (auto& family : familyList) {
309         const CSSPrimitiveValue& primitive = downcast<CSSPrimitiveValue>(family.get());
310         if (!primitive.isFontFamily())
311             continue;
312         uniqueFamilies.add(primitive.fontFamily().familyName);
313     }
314
315     for (auto& family : uniqueFamilies) {
316         CSSSegmentedFontFace* faces = getFontFace(fontTraitsMask, family);
317         if (!faces)
318             continue;
319         for (auto& constituentFace : faces->constituentFaces())
320             result.append(constituentFace.get());
321     }
322
323     return result;
324 }
325
326 bool CSSFontFaceSet::check(const String& font, const String& text, ExceptionCode& ec)
327 {
328     auto matchingFaces = this->matchingFaces(font, text, ec);
329     if (ec)
330         return false;
331
332     for (auto& face : matchingFaces) {
333         if (face.get().status() == CSSFontFace::Status::Pending)
334             return false;
335     }
336     return true;
337 }
338
339 static bool fontFaceComparator(FontTraitsMask desiredTraitsMaskForComparison, const CSSFontFace& first, const CSSFontFace& second)
340 {
341     FontTraitsMask firstTraitsMask = first.traitsMask();
342     FontTraitsMask secondTraitsMask = second.traitsMask();
343
344     bool firstHasDesiredStyle = firstTraitsMask & desiredTraitsMaskForComparison & FontStyleMask;
345     bool secondHasDesiredStyle = secondTraitsMask & desiredTraitsMaskForComparison & FontStyleMask;
346
347     if (firstHasDesiredStyle != secondHasDesiredStyle)
348         return firstHasDesiredStyle;
349
350     if ((desiredTraitsMaskForComparison & FontStyleItalicMask) && !first.isLocalFallback() && !second.isLocalFallback()) {
351         // Prefer a font that has indicated that it can only support italics to a font that claims to support
352         // all styles. The specialized font is more likely to be the one the author wants used.
353         bool firstRequiresItalics = (firstTraitsMask & FontStyleItalicMask) && !(firstTraitsMask & FontStyleNormalMask);
354         bool secondRequiresItalics = (secondTraitsMask & FontStyleItalicMask) && !(secondTraitsMask & FontStyleNormalMask);
355         if (firstRequiresItalics != secondRequiresItalics)
356             return firstRequiresItalics;
357     }
358
359     if (secondTraitsMask & desiredTraitsMaskForComparison & FontWeightMask)
360         return false;
361     if (firstTraitsMask & desiredTraitsMaskForComparison & FontWeightMask)
362         return true;
363
364     // http://www.w3.org/TR/2011/WD-css3-fonts-20111004/#font-matching-algorithm says :
365     //   - If the desired weight is less than 400, weights below the desired weight are checked in descending order followed by weights above the desired weight in ascending order until a match is found.
366     //   - If the desired weight is greater than 500, weights above the desired weight are checked in ascending order followed by weights below the desired weight in descending order until a match is found.
367     //   - If the desired weight is 400, 500 is checked first and then the rule for desired weights less than 400 is used.
368     //   - If the desired weight is 500, 400 is checked first and then the rule for desired weights less than 400 is used.
369
370     static const unsigned fallbackRuleSets = 9;
371     static const unsigned rulesPerSet = 8;
372     static const FontTraitsMask weightFallbackRuleSets[fallbackRuleSets][rulesPerSet] = {
373         { FontWeight200Mask, FontWeight300Mask, FontWeight400Mask, FontWeight500Mask, FontWeight600Mask, FontWeight700Mask, FontWeight800Mask, FontWeight900Mask },
374         { FontWeight100Mask, FontWeight300Mask, FontWeight400Mask, FontWeight500Mask, FontWeight600Mask, FontWeight700Mask, FontWeight800Mask, FontWeight900Mask },
375         { FontWeight200Mask, FontWeight100Mask, FontWeight400Mask, FontWeight500Mask, FontWeight600Mask, FontWeight700Mask, FontWeight800Mask, FontWeight900Mask },
376         { FontWeight500Mask, FontWeight300Mask, FontWeight200Mask, FontWeight100Mask, FontWeight600Mask, FontWeight700Mask, FontWeight800Mask, FontWeight900Mask },
377         { FontWeight400Mask, FontWeight300Mask, FontWeight200Mask, FontWeight100Mask, FontWeight600Mask, FontWeight700Mask, FontWeight800Mask, FontWeight900Mask },
378         { FontWeight700Mask, FontWeight800Mask, FontWeight900Mask, FontWeight500Mask, FontWeight400Mask, FontWeight300Mask, FontWeight200Mask, FontWeight100Mask },
379         { FontWeight800Mask, FontWeight900Mask, FontWeight600Mask, FontWeight500Mask, FontWeight400Mask, FontWeight300Mask, FontWeight200Mask, FontWeight100Mask },
380         { FontWeight900Mask, FontWeight700Mask, FontWeight600Mask, FontWeight500Mask, FontWeight400Mask, FontWeight300Mask, FontWeight200Mask, FontWeight100Mask },
381         { FontWeight800Mask, FontWeight700Mask, FontWeight600Mask, FontWeight500Mask, FontWeight400Mask, FontWeight300Mask, FontWeight200Mask, FontWeight100Mask }
382     };
383
384     unsigned ruleSetIndex = 0;
385     for (; !(desiredTraitsMaskForComparison & (1 << (FontWeight100Bit + ruleSetIndex))); ruleSetIndex++) { }
386
387     const FontTraitsMask* weightFallbackRule = weightFallbackRuleSets[ruleSetIndex];
388     for (unsigned i = 0; i < rulesPerSet; ++i) {
389         if (secondTraitsMask & weightFallbackRule[i])
390             return false;
391         if (firstTraitsMask & weightFallbackRule[i])
392             return true;
393     }
394
395     return false;
396 }
397
398 CSSSegmentedFontFace* CSSFontFaceSet::getFontFace(FontTraitsMask traitsMask, const AtomicString& family)
399 {
400     auto iterator = m_facesLookupTable.find(family);
401     if (iterator == m_facesLookupTable.end())
402         return nullptr;
403     auto& familyFontFaces = iterator->value;
404
405     auto& segmentedFontFaceCache = m_cache.add(family, HashMap<unsigned, RefPtr<CSSSegmentedFontFace>>()).iterator->value;
406
407     auto& face = segmentedFontFaceCache.add(traitsMask, nullptr).iterator->value;
408     if (face)
409         return face.get();
410
411     face = CSSSegmentedFontFace::create();
412
413     Vector<std::reference_wrapper<CSSFontFace>, 32> candidateFontFaces;
414     for (int i = familyFontFaces.size() - 1; i >= 0; --i) {
415         CSSFontFace& candidate = familyFontFaces[i];
416         unsigned candidateTraitsMask = candidate.traitsMask();
417         if ((traitsMask & FontStyleNormalMask) && !(candidateTraitsMask & FontStyleNormalMask))
418             continue;
419         candidateFontFaces.append(candidate);
420     }
421
422     auto localIterator = m_locallyInstalledFacesLookupTable.find(family);
423     if (localIterator != m_locallyInstalledFacesLookupTable.end()) {
424         for (auto& candidate : localIterator->value) {
425             unsigned candidateTraitsMask = candidate->traitsMask();
426             if ((traitsMask & FontStyleNormalMask) && !(candidateTraitsMask & FontStyleNormalMask))
427                 continue;
428             candidateFontFaces.append(candidate);
429         }
430     }
431
432     std::stable_sort(candidateFontFaces.begin(), candidateFontFaces.end(), [traitsMask](const CSSFontFace& first, const CSSFontFace& second) {
433         return fontFaceComparator(traitsMask, first, second);
434     });
435     for (auto& candidate : candidateFontFaces)
436         face->appendFontFace(candidate.get());
437
438     return face.get();
439 }
440
441 void CSSFontFaceSet::fontStateChanged(CSSFontFace& face, CSSFontFace::Status oldState, CSSFontFace::Status newState)
442 {
443     ASSERT(hasFace(face));
444     if (oldState == CSSFontFace::Status::Pending) {
445         ASSERT(newState == CSSFontFace::Status::Loading);
446         incrementActiveCount();
447     }
448     if (newState == CSSFontFace::Status::Success || newState == CSSFontFace::Status::Failure) {
449         ASSERT(oldState == CSSFontFace::Status::Loading || oldState == CSSFontFace::Status::TimedOut);
450         for (auto* client : m_clients)
451             client->faceFinished(face, newState);
452         decrementActiveCount();
453     }
454 }
455
456 void CSSFontFaceSet::fontPropertyChanged(CSSFontFace& face, CSSValueList* oldFamilies)
457 {
458     m_cache.clear();
459
460     if (oldFamilies) {
461         removeFromFacesLookupTable(face, *oldFamilies);
462         addToFacesLookupTable(face);
463     }
464
465     for (auto* client : m_clients)
466         client->fontModified();
467 }
468
469 }