1 /*
2  * Copyright (C) 2007, 2008, 2011 Apple Inc. All rights reserved.
3  *           (C) 2007, 2008 Nikolas Zimmermann <zimmermann@kde.org>
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26 
27 #include "third_party/blink/renderer/core/css/css_font_selector.h"
28 
29 #include "build/build_config.h"
30 #include "third_party/blink/renderer/core/css/css_segmented_font_face.h"
31 #include "third_party/blink/renderer/core/css/css_value_list.h"
32 #include "third_party/blink/renderer/core/css/font_face_set_document.h"
33 #include "third_party/blink/renderer/core/css/resolver/style_resolver.h"
34 #include "third_party/blink/renderer/core/dom/document.h"
35 #include "third_party/blink/renderer/core/frame/local_frame.h"
36 #include "third_party/blink/renderer/core/frame/settings.h"
37 #include "third_party/blink/renderer/core/frame/web_feature.h"
38 #include "third_party/blink/renderer/core/loader/frame_loader.h"
39 #include "third_party/blink/renderer/platform/fonts/font_cache.h"
40 #include "third_party/blink/renderer/platform/fonts/font_fallback_map.h"
41 #include "third_party/blink/renderer/platform/fonts/font_matching_metrics.h"
42 #include "third_party/blink/renderer/platform/fonts/font_selector_client.h"
43 #include "third_party/blink/renderer/platform/fonts/simple_font_data.h"
44 #include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
45 #include "third_party/blink/renderer/platform/wtf/text/atomic_string.h"
46 
47 namespace blink {
48 
CSSFontSelector(Document * document)49 CSSFontSelector::CSSFontSelector(Document* document)
50     : document_(document),
51       generic_font_family_settings_(
52           document->GetFrame()->GetSettings()->GetGenericFontFamilySettings()) {
53   // FIXME: An old comment used to say there was no need to hold a reference to
54   // document_ because "we are guaranteed to be destroyed before the document".
55   // But there does not seem to be any such guarantee.
56   DCHECK(document_);
57   DCHECK(document_->GetFrame());
58   FontCache::GetFontCache()->AddClient(this);
59   FontFaceSetDocument::From(*document)->AddFontFacesToFontFaceCache(
60       &font_face_cache_);
61 }
62 
63 CSSFontSelector::~CSSFontSelector() = default;
64 
RegisterForInvalidationCallbacks(FontSelectorClient * client)65 void CSSFontSelector::RegisterForInvalidationCallbacks(
66     FontSelectorClient* client) {
67   CHECK(client);
68   clients_.insert(client);
69 }
70 
UnregisterForInvalidationCallbacks(FontSelectorClient * client)71 void CSSFontSelector::UnregisterForInvalidationCallbacks(
72     FontSelectorClient* client) {
73   clients_.erase(client);
74 }
75 
DispatchInvalidationCallbacks(FontInvalidationReason reason)76 void CSSFontSelector::DispatchInvalidationCallbacks(
77     FontInvalidationReason reason) {
78   font_face_cache_.IncrementVersion();
79 
80   HeapVector<Member<FontSelectorClient>> clients;
81   CopyToVector(clients_, clients);
82   for (auto& client : clients) {
83     if (client) {
84       client->FontsNeedUpdate(this, reason);
85     }
86   }
87 }
88 
FontFaceInvalidated(FontInvalidationReason reason)89 void CSSFontSelector::FontFaceInvalidated(FontInvalidationReason reason) {
90   DispatchInvalidationCallbacks(reason);
91 }
92 
FontCacheInvalidated()93 void CSSFontSelector::FontCacheInvalidated() {
94   DispatchInvalidationCallbacks(FontInvalidationReason::kGeneralInvalidation);
95 }
96 
GetFontData(const FontDescription & font_description,const AtomicString & family_name)97 scoped_refptr<FontData> CSSFontSelector::GetFontData(
98     const FontDescription& font_description,
99     const AtomicString& family_name) {
100   if (CSSSegmentedFontFace* face =
101           font_face_cache_.Get(font_description, family_name)) {
102     document_->GetFontMatchingMetrics()->ReportWebFontFamily(family_name);
103     return face->GetFontData(font_description);
104   }
105 
106   document_->GetFontMatchingMetrics()->ReportSystemFontFamily(family_name);
107 
108   // Try to return the correct font based off our settings, in case we were
109   // handed the generic font family name.
110   AtomicString settings_family_name = FamilyNameFromSettings(
111       generic_font_family_settings_, font_description, family_name);
112   if (settings_family_name.IsEmpty())
113     return nullptr;
114 
115   document_->GetFontMatchingMetrics()->ReportFontFamilyLookupByGenericFamily(
116       family_name, font_description.GetScript(),
117       font_description.GenericFamily(), settings_family_name);
118 
119   scoped_refptr<SimpleFontData> font_data =
120       FontCache::GetFontCache()->GetFontData(font_description,
121                                              settings_family_name);
122 
123   document_->GetFontMatchingMetrics()->ReportFontLookupByUniqueOrFamilyName(
124       settings_family_name, font_description, font_data.get());
125 
126   return font_data;
127 }
128 
WillUseFontData(const FontDescription & font_description,const AtomicString & family,const String & text)129 void CSSFontSelector::WillUseFontData(const FontDescription& font_description,
130                                       const AtomicString& family,
131                                       const String& text) {
132   CSSSegmentedFontFace* face = font_face_cache_.Get(font_description, family);
133   if (face)
134     face->WillUseFontData(font_description, text);
135 }
136 
WillUseRange(const FontDescription & font_description,const AtomicString & family,const FontDataForRangeSet & range_set)137 void CSSFontSelector::WillUseRange(const FontDescription& font_description,
138                                    const AtomicString& family,
139                                    const FontDataForRangeSet& range_set) {
140   CSSSegmentedFontFace* face = font_face_cache_.Get(font_description, family);
141   if (face)
142     face->WillUseRange(font_description, range_set);
143 }
144 
IsPlatformFamilyMatchAvailable(const FontDescription & font_description,const AtomicString & passed_family)145 bool CSSFontSelector::IsPlatformFamilyMatchAvailable(
146     const FontDescription& font_description,
147     const AtomicString& passed_family) {
148   AtomicString family = FamilyNameFromSettings(generic_font_family_settings_,
149                                                font_description, passed_family);
150   if (family.IsEmpty())
151     family = passed_family;
152   return FontCache::GetFontCache()->IsPlatformFamilyMatchAvailable(
153       font_description, family);
154 }
155 
UpdateGenericFontFamilySettings(Document & document)156 void CSSFontSelector::UpdateGenericFontFamilySettings(Document& document) {
157   if (!document.GetSettings())
158     return;
159   generic_font_family_settings_ =
160       document.GetSettings()->GetGenericFontFamilySettings();
161   FontCacheInvalidated();
162 }
163 
ReportNotDefGlyph() const164 void CSSFontSelector::ReportNotDefGlyph() const {
165   DCHECK(document_);
166   UseCounter::Count(document_, WebFeature::kFontShapingNotDefGlyphObserved);
167 }
168 
ReportSuccessfulFontFamilyMatch(const AtomicString & font_family_name)169 void CSSFontSelector::ReportSuccessfulFontFamilyMatch(
170     const AtomicString& font_family_name) {
171   DCHECK(document_);
172   document_->GetFontMatchingMetrics()->ReportSuccessfulFontFamilyMatch(
173       font_family_name);
174 }
175 
ReportFailedFontFamilyMatch(const AtomicString & font_family_name)176 void CSSFontSelector::ReportFailedFontFamilyMatch(
177     const AtomicString& font_family_name) {
178   DCHECK(document_);
179   document_->GetFontMatchingMetrics()->ReportFailedFontFamilyMatch(
180       font_family_name);
181 }
182 
ReportSuccessfulLocalFontMatch(const AtomicString & font_name)183 void CSSFontSelector::ReportSuccessfulLocalFontMatch(
184     const AtomicString& font_name) {
185   DCHECK(document_);
186   document_->GetFontMatchingMetrics()->ReportSuccessfulLocalFontMatch(
187       font_name);
188 }
189 
ReportFailedLocalFontMatch(const AtomicString & font_name)190 void CSSFontSelector::ReportFailedLocalFontMatch(
191     const AtomicString& font_name) {
192   DCHECK(document_);
193   document_->GetFontMatchingMetrics()->ReportFailedLocalFontMatch(font_name);
194 }
195 
ReportFontLookupByUniqueOrFamilyName(const AtomicString & name,const FontDescription & font_description,SimpleFontData * resulting_font_data)196 void CSSFontSelector::ReportFontLookupByUniqueOrFamilyName(
197     const AtomicString& name,
198     const FontDescription& font_description,
199     SimpleFontData* resulting_font_data) {
200   DCHECK(document_);
201   document_->GetFontMatchingMetrics()->ReportFontLookupByUniqueOrFamilyName(
202       name, font_description, resulting_font_data);
203 }
204 
ReportFontLookupByUniqueNameOnly(const AtomicString & name,const FontDescription & font_description,SimpleFontData * resulting_font_data,bool is_loading_fallback)205 void CSSFontSelector::ReportFontLookupByUniqueNameOnly(
206     const AtomicString& name,
207     const FontDescription& font_description,
208     SimpleFontData* resulting_font_data,
209     bool is_loading_fallback) {
210   DCHECK(document_);
211   document_->GetFontMatchingMetrics()->ReportFontLookupByUniqueNameOnly(
212       name, font_description, resulting_font_data, is_loading_fallback);
213 }
214 
ReportFontLookupByFallbackCharacter(UChar32 fallback_character,FontFallbackPriority fallback_priority,const FontDescription & font_description,SimpleFontData * resulting_font_data)215 void CSSFontSelector::ReportFontLookupByFallbackCharacter(
216     UChar32 fallback_character,
217     FontFallbackPriority fallback_priority,
218     const FontDescription& font_description,
219     SimpleFontData* resulting_font_data) {
220   DCHECK(document_);
221   document_->GetFontMatchingMetrics()->ReportFontLookupByFallbackCharacter(
222       fallback_character, fallback_priority, font_description,
223       resulting_font_data);
224 }
225 
ReportLastResortFallbackFontLookup(const FontDescription & font_description,SimpleFontData * resulting_font_data)226 void CSSFontSelector::ReportLastResortFallbackFontLookup(
227     const FontDescription& font_description,
228     SimpleFontData* resulting_font_data) {
229   DCHECK(document_);
230   document_->GetFontMatchingMetrics()->ReportLastResortFallbackFontLookup(
231       font_description, resulting_font_data);
232 }
233 
Trace(Visitor * visitor) const234 void CSSFontSelector::Trace(Visitor* visitor) const {
235   visitor->Trace(document_);
236   visitor->Trace(font_face_cache_);
237   visitor->Trace(clients_);
238   FontSelector::Trace(visitor);
239 }
240 
241 }  // namespace blink
242