source: webkit/trunk/Source/WebCore/css/CSSFontFaceSet.cpp

Last change on this file was 293292, checked in by Chris Dumez, 3 years ago

Start preparing the code base for making the AtomString(const String&) constructor explicit
https://bugs.webkit.org/show_bug.cgi?id=239658

Reviewed by Darin Adler.

Start preparing the code base for making the AtomString(const String&) constructor explicit.
This helps us find cases where we atomize unnecessarily or not early enough, thus causing
unnecessary String allocations.

  • Source/JavaScriptCore/runtime/JSString.cpp:

(JSC::JSRopeString::resolveRopeToAtomString const):

  • Source/WebKit/WebProcess/Plugins/Plugin.h:
  • Source/WebKit/WebProcess/WebCoreSupport/WebFrameLoaderClient.cpp:

(WebKit::WebFrameLoaderClient::createPlugin):

  • Source/WebKit/WebProcess/WebCoreSupport/WebFrameLoaderClient.h:
  • Source/WebKitLegacy/mac/DOM/DOMCustomXPathNSResolver.h:
  • Source/WebKitLegacy/mac/DOM/DOMCustomXPathNSResolver.mm:

(DOMCustomXPathNSResolver::lookupNamespaceURI):

  • Source/WebKitLegacy/mac/WebCoreSupport/WebFrameLoaderClient.h:
  • Source/WebKitLegacy/mac/WebCoreSupport/WebFrameLoaderClient.mm:

(parameterValue):
(WebFrameLoaderClient::createPlugin):

  • Source/WebKitLegacy/win/WebCoreSupport/WebFrameLoaderClient.cpp:

(WebFrameLoaderClient::createPlugin):

  • Source/WebKitLegacy/win/WebCoreSupport/WebFrameLoaderClient.h:
  • Source/WTF/wtf/persistence/PersistentCoders.cpp:

(WTF::Persistence::Coder<AtomString>::decode):

  • Source/WTF/wtf/text/StringBuilder.h:

(WTF::StringBuilder::toAtomString const):

  • Source/WTF/wtf/text/StringConcatenate.h:

(WTF::tryMakeAtomStringFromAdapters):

  • Source/WTF/wtf/text/StringView.cpp:

(WTF::convertASCIILowercaseAtom):

  • Source/WebCore/Modules/gamepad/GamepadEvent.idl:
  • Source/WebCore/Modules/mediasession/MediaMetadata.cpp:

(WebCore::ArtworkImageLoader::requestImageResource):

  • Source/WebCore/Modules/plugins/PluginReplacement.h:

(WebCore::ReplacementPlugin::create const):

  • Source/WebCore/Modules/plugins/YouTubePluginReplacement.cpp:

(WebCore::YouTubePluginReplacement::create):
(WebCore::YouTubePluginReplacement::YouTubePluginReplacement):
(WebCore::YouTubePluginReplacement::youTubeURL):
(WebCore::YouTubePluginReplacement::youTubeURLFromAbsoluteURL):

  • Source/WebCore/Modules/plugins/YouTubePluginReplacement.h:
  • Source/WebCore/Modules/websockets/CloseEvent.idl:
  • Source/WebCore/accessibility/AXObjectCache.cpp:

(WebCore::AXObjectCache::handleLiveRegionCreated):

  • Source/WebCore/accessibility/AccessibilityObject.cpp:

(WebCore::AccessibilityObject::supportsLiveRegion const):
(WebCore::AccessibilityObject::tagName const):

  • Source/WebCore/accessibility/AccessibilityObject.h:
  • Source/WebCore/accessibility/AccessibilityObjectInterface.h:
  • Source/WebCore/accessibility/AccessibilityRole.idl:
  • Source/WebCore/accessibility/AriaAttributes.idl:
  • Source/WebCore/accessibility/isolatedtree/AXIsolatedObject.cpp:

(WebCore::AXIsolatedObject::initializeProperties):

  • Source/WebCore/accessibility/isolatedtree/AXIsolatedObject.h:
  • Source/WebCore/accessibility/mac/WebAccessibilityObjectWrapperMac.mm:

(-[WebAccessibilityObjectWrapper accessibilityAttributeValue:]):

  • Source/WebCore/animation/KeyframeEffect.cpp:

(WebCore::IDLAttributeNameToAnimationPropertyName):
(WebCore::KeyframeEffect::copyPropertiesFromSource):
(WebCore::KeyframeEffect::updateBlendingKeyframes):
(WebCore::KeyframeEffect::computeCSSAnimationBlendingKeyframes):
(WebCore::KeyframeEffect::computeCSSTransitionBlendingKeyframes):

  • Source/WebCore/animation/KeyframeEffect.h:
  • Source/WebCore/animation/WebAnimation.cpp:

(WebCore::WebAnimation::commitStyles):

  • Source/WebCore/bindings/js/JSCustomElementInterface.cpp:

(WebCore::JSCustomElementInterface::setAttributeChangedCallback):

  • Source/WebCore/bindings/js/JSCustomElementInterface.h:
  • Source/WebCore/bindings/js/JSCustomElementRegistryCustom.cpp:

(WebCore::JSCustomElementRegistry::define):

  • Source/WebCore/bindings/js/JSExtendableMessageEventCustom.cpp:

(WebCore::constructJSExtendableMessageEvent):

  • Source/WebCore/css/CSSFontFaceSet.cpp:

(WebCore::CSSFontFaceSet::ensureLocalFontFacesForFamilyRegistered):
(WebCore::CSSFontFaceSet::matchingFacesExcludingPreinstalledFonts):

  • Source/WebCore/dom/Attr.cpp:

(WebCore::Attr::setNodeValue):

  • Source/WebCore/dom/ClipboardEvent.idl:
  • Source/WebCore/dom/CompositionEvent.idl:
  • Source/WebCore/dom/CustomElementRegistry.idl:
  • Source/WebCore/dom/CustomEvent.idl:
  • Source/WebCore/dom/Document+HTML.idl:
  • Source/WebCore/dom/DragEvent.idl:
  • Source/WebCore/dom/Element.idl:
  • Source/WebCore/dom/ErrorEvent.idl:
  • Source/WebCore/domjit/DOMJITIDLConvert.h:

(WebCore::DOMJIT::DirectConverter<IDLAtomStringAdaptor<IDLDOMString>>::directConvert):
(WebCore::DOMJIT::DirectConverter<IDLRequiresExistingAtomStringAdaptor<IDLDOMString>>::directConvert):

  • Source/WebCore/editing/cocoa/DataDetection.mm:

(WebCore::DataDetection::createElementForImageOverlay):

  • Source/WebCore/editing/cocoa/WebContentReaderCocoa.mm:

(WebCore::createFragmentForImageAttachment):

  • Source/WebCore/html/HTMLAnchorElement.h:
  • Source/WebCore/html/HTMLAnchorElement.idl:
  • Source/WebCore/html/HTMLAreaElement.idl:
  • Source/WebCore/html/HTMLEmbedElement.cpp:

(WebCore::HTMLEmbedElement::parametersForPlugin):
(WebCore::HTMLEmbedElement::updateWidget):

  • Source/WebCore/html/HTMLEmbedElement.h:
  • Source/WebCore/html/HTMLObjectElement.cpp:

(WebCore::mapDataParamToSrc):
(WebCore::HTMLObjectElement::parametersForPlugin):
(WebCore::HTMLObjectElement::updateWidget):

  • Source/WebCore/html/HTMLObjectElement.h:
  • Source/WebCore/html/HTMLParamElement.cpp:

(WebCore::HTMLParamElement::name const):
(WebCore::HTMLParamElement::value const):

  • Source/WebCore/html/HTMLParamElement.h:
  • Source/WebCore/html/HTMLPlugInElement.cpp:

(WebCore::HTMLPlugInElement::requestObject):

  • Source/WebCore/html/HTMLPlugInElement.h:
  • Source/WebCore/html/HTMLPlugInImageElement.cpp:

(WebCore::HTMLPlugInImageElement::requestObject):

  • Source/WebCore/html/HTMLPlugInImageElement.h:
  • Source/WebCore/html/track/TextTrack.h:

(WebCore::TextTrack::inBandMetadataTrackDispatchType const):

  • Source/WebCore/loader/EmptyClients.cpp:

(WebCore::EmptyFrameLoaderClient::createPlugin):

  • Source/WebCore/loader/EmptyFrameLoaderClient.h:
  • Source/WebCore/loader/FrameLoaderClient.h:
  • Source/WebCore/loader/SubframeLoader.cpp:

(WebCore::FrameLoader::SubframeLoader::requestPlugin):
(WebCore::FrameLoader::SubframeLoader::requestObject):
(WebCore::FrameLoader::SubframeLoader::loadPlugin):

  • Source/WebCore/loader/SubframeLoader.h:
  • Source/WebCore/platform/graphics/avfoundation/AVTrackPrivateAVFObjCImpl.mm:

(WebCore::AVTrackPrivateAVFObjCImpl::language const):

  • Source/WebCore/platform/graphics/avfoundation/CDMFairPlayStreaming.cpp:

(WebCore::CDMPrivateFairPlayStreaming::supportsConfiguration const):

  • Source/WebCore/platform/graphics/avfoundation/objc/InbandChapterTrackPrivateAVFObjC.h:
  • Source/WebCore/platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.mm:

(WebCore::SourceBufferPrivateAVFObjC::rendererWasAutomaticallyFlushed):

  • Source/WebCore/platform/mediastream/mac/AVVideoCaptureSource.mm:

(WebCore::AVVideoCaptureSource::settings):
(WebCore::AVVideoCaptureSource::capabilities):

  • Source/WebCore/platform/network/ResourceResponseBase.h:

(WebCore::ResourceResponseBase::decode):

  • Source/WebCore/platform/network/cocoa/ResourceResponseCocoa.mm:

(WebCore::stripLeadingAndTrailingDoubleQuote):
(WebCore::ResourceResponse::platformLazyInit):

  • Source/WebCore/platform/text/PlatformLocale.h:

(WebCore::Locale::createDefault):

  • Source/WebCore/plugins/DOMMimeTypeArray.idl:
  • Source/WebCore/plugins/DOMPlugin.idl:
  • Source/WebCore/plugins/DOMPluginArray.idl:
  • Source/WebCore/rendering/RenderThemeCocoa.mm:

(WebCore::RenderThemeCocoa::paintApplePayButton):

  • Source/WebCore/style/PropertyCascade.h:

(WebCore::Style::PropertyCascade::hasCustomProperty const):
(WebCore::Style::PropertyCascade::customProperty const):

  • Source/WebCore/style/StyleBuilderConverter.h:

(WebCore::Style::BuilderConverter::convertFontPalette):
(WebCore::Style::BuilderConverter::convertContainerName):

  • Source/WebCore/svg/SVGFEBlendElement.h:
  • Source/WebCore/svg/SVGFEColorMatrixElement.h:
  • Source/WebCore/svg/SVGFEComponentTransferElement.h:
  • Source/WebCore/svg/SVGFECompositeElement.h:
  • Source/WebCore/svg/SVGFEConvolveMatrixElement.h:
  • Source/WebCore/svg/SVGFEDiffuseLightingElement.h:
  • Source/WebCore/svg/SVGFEDisplacementMapElement.h:
  • Source/WebCore/svg/SVGFEDropShadowElement.h:
  • Source/WebCore/svg/SVGFEGaussianBlurElement.h:
  • Source/WebCore/svg/SVGFEMorphologyElement.h:
  • Source/WebCore/svg/SVGFEOffsetElement.h:
  • Source/WebCore/svg/SVGFESpecularLightingElement.h:
  • Source/WebCore/svg/SVGFETileElement.h:
  • Source/WebCore/svg/SVGScriptElement.h:
  • Source/WebCore/svg/graphics/filters/SVGFilterBuilder.cpp:

(WebCore::SVGFilterBuilder::buildFilterExpression):

  • Source/WebCore/xml/CustomXPathNSResolver.cpp:

(WebCore::CustomXPathNSResolver::lookupNamespaceURI):

  • Source/WebCore/xml/CustomXPathNSResolver.h:
  • Source/WebCore/xml/CustomXPathNSResolver.idl:
  • Source/WebCore/xml/NativeXPathNSResolver.cpp:

(WebCore::NativeXPathNSResolver::lookupNamespaceURI):

  • Source/WebCore/xml/NativeXPathNSResolver.h:
  • Source/WebCore/xml/XPathGrammar.cpp:
  • Source/WebCore/xml/XPathNSResolver.h:
  • Source/WebCore/xml/XPathNSResolver.idl:
  • Source/WebCore/xml/XPathParser.cpp:

(WebCore::XPath::Parser::expandQualifiedName):

  • Source/WebCore/xml/XPathParser.h:
  • Source/WebCore/xml/parser/XMLDocumentParserLibxml2.cpp:

(WebCore::handleNamespaceAttributes):
(WebCore::handleElementAttributes):

Canonical link: https://commits.webkit.org/249917@main

  • Property svn:eol-style set to native
File size: 19.5 KB
Line 
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 "CSSPropertyParserHelpers.h"
36#include "CSSPropertyParserWorkerSafe.h"
37#include "CSSSegmentedFontFace.h"
38#include "CSSValueList.h"
39#include "CSSValuePool.h"
40#include "FontCache.h"
41#include "StyleBuilderConverter.h"
42#include "StyleProperties.h"
43
44namespace WebCore {
45
46CSSFontFaceSet::CSSFontFaceSet(CSSFontSelector* owningFontSelector)
47 : m_owningFontSelector(owningFontSelector)
48{
49}
50
51CSSFontFaceSet::~CSSFontFaceSet()
52{
53 for (auto& face : m_faces)
54 face->removeClient(*this);
55
56 for (auto& pair : m_locallyInstalledFacesLookupTable) {
57 for (auto& face : pair.value)
58 face->removeClient(*this);
59 }
60}
61
62void CSSFontFaceSet::addFontModifiedObserver(const FontModifiedObserver& fontModifiedObserver)
63{
64 auto result = m_fontModifiedObservers.add(fontModifiedObserver);
65 ASSERT_UNUSED(result, result.isNewEntry);
66}
67
68void CSSFontFaceSet::addFontEventClient(const FontEventClient& fontEventClient)
69{
70 auto result = m_fontEventClients.add(fontEventClient);
71 ASSERT_UNUSED(result, result.isNewEntry);
72}
73
74void CSSFontFaceSet::incrementActiveCount()
75{
76 ++m_activeCount;
77 if (m_activeCount == 1) {
78 m_status = Status::Loading;
79 m_fontEventClients.forEach([] (auto& client) {
80 client.startedLoading();
81 });
82 }
83}
84
85void CSSFontFaceSet::decrementActiveCount()
86{
87 --m_activeCount;
88 if (!m_activeCount) {
89 m_status = Status::Loaded;
90 m_fontEventClients.forEach([] (auto& client) {
91 client.completedLoading();
92 });
93 }
94}
95
96bool CSSFontFaceSet::hasFace(const CSSFontFace& face) const
97{
98 for (auto& myFace : m_faces) {
99 if (myFace.ptr() == &face)
100 return true;
101 }
102
103 return false;
104}
105
106// Calling updateStyleIfNeeded() might delete |this|.
107void CSSFontFaceSet::updateStyleIfNeeded()
108{
109 if (m_owningFontSelector)
110 m_owningFontSelector->updateStyleIfNeeded();
111}
112
113void CSSFontFaceSet::ensureLocalFontFacesForFamilyRegistered(const String& familyName)
114{
115 ASSERT(m_owningFontSelector);
116 if (m_locallyInstalledFacesLookupTable.contains(familyName))
117 return;
118
119 if (!m_owningFontSelector->scriptExecutionContext())
120 return;
121 AllowUserInstalledFonts allowUserInstalledFonts = m_owningFontSelector->scriptExecutionContext()->settingsValues().shouldAllowUserInstalledFonts ? AllowUserInstalledFonts::Yes : AllowUserInstalledFonts::No;
122 Vector<FontSelectionCapabilities> capabilities = FontCache::forCurrentThread().getFontSelectionCapabilitiesInFamily(AtomString { familyName }, allowUserInstalledFonts);
123 if (capabilities.isEmpty())
124 return;
125
126 Vector<Ref<CSSFontFace>> faces;
127 for (auto item : capabilities) {
128 auto face = CSSFontFace::create(*m_owningFontSelector, nullptr, nullptr, true);
129
130 Ref<CSSValueList> familyList = CSSValueList::createCommaSeparated();
131 familyList->append(m_owningFontSelector->scriptExecutionContext()->cssValuePool().createFontFamilyValue(familyName));
132 face->setFamilies(familyList.get());
133 face->setFontSelectionCapabilities(item);
134 face->adoptSource(makeUnique<CSSFontFaceSource>(face.get(), familyName));
135 ASSERT(!face->computeFailureState());
136 faces.append(WTFMove(face));
137 }
138 m_locallyInstalledFacesLookupTable.add(familyName, WTFMove(faces));
139}
140
141String CSSFontFaceSet::familyNameFromPrimitive(const CSSPrimitiveValue& value)
142{
143 if (value.isFontFamily())
144 return value.fontFamily().familyName;
145 if (!value.isValueID())
146 return { };
147
148 // We need to use the raw text for all the generic family types, since @font-face is a way of actually
149 // defining what font to use for those types.
150 switch (value.valueID()) {
151 case CSSValueSerif:
152 return serifFamily.get();
153 case CSSValueSansSerif:
154 return sansSerifFamily.get();
155 case CSSValueCursive:
156 return cursiveFamily.get();
157 case CSSValueFantasy:
158 return fantasyFamily.get();
159 case CSSValueMonospace:
160 return monospaceFamily.get();
161 case CSSValueWebkitPictograph:
162 return pictographFamily.get();
163 case CSSValueSystemUi:
164 return systemUiFamily.get();
165 default:
166 return { };
167 }
168}
169
170void CSSFontFaceSet::addToFacesLookupTable(CSSFontFace& face)
171{
172 if (!face.families()) {
173 // If the font has failed, there's no point in actually adding it to m_facesLookupTable,
174 // because no font requests can actually use it for anything. So, let's just ... not add it.
175 return;
176 }
177 auto families = face.families().value();
178
179 for (auto& item : *families) {
180 String familyName = CSSFontFaceSet::familyNameFromPrimitive(downcast<CSSPrimitiveValue>(item.get()));
181 if (familyName.isEmpty())
182 continue;
183
184 auto addResult = m_facesLookupTable.add(familyName, Vector<Ref<CSSFontFace>>());
185 auto& familyFontFaces = addResult.iterator->value;
186 if (addResult.isNewEntry) {
187 // m_locallyInstalledFontFaces grows without bound, eventually encorporating every font installed on the system.
188 // This is by design.
189 if (m_owningFontSelector)
190 ensureLocalFontFacesForFamilyRegistered(familyName);
191 familyFontFaces = { };
192 }
193
194 familyFontFaces.append(face);
195 }
196}
197
198void CSSFontFaceSet::add(CSSFontFace& face)
199{
200 ASSERT(!hasFace(face));
201
202 m_fontModifiedObservers.forEach([] (auto& observer) {
203 observer();
204 });
205
206 face.addClient(*this);
207 m_cache.clear();
208
209 if (face.cssConnection())
210 m_faces.insert(m_facesPartitionIndex++, face);
211 else
212 m_faces.append(face);
213
214 addToFacesLookupTable(face);
215
216 if (face.status() == CSSFontFace::Status::Loading || face.status() == CSSFontFace::Status::TimedOut)
217 incrementActiveCount();
218
219 if (face.cssConnection()) {
220 ASSERT(!m_constituentCSSConnections.contains(face.cssConnection()));
221 m_constituentCSSConnections.add(face.cssConnection(), &face);
222 }
223}
224
225void CSSFontFaceSet::removeFromFacesLookupTable(const CSSFontFace& face, const CSSValueList& familiesToSearchFor)
226{
227 for (auto& item : familiesToSearchFor) {
228 String familyName = CSSFontFaceSet::familyNameFromPrimitive(downcast<CSSPrimitiveValue>(item.get()));
229 if (familyName.isEmpty())
230 continue;
231
232 auto iterator = m_facesLookupTable.find(familyName);
233 if (iterator == m_facesLookupTable.end()) {
234 // The font may have failed even before addToFacesLookupTable() was called on it,
235 // which means we never added it (because there's no point in adding a failed font).
236 // So, if it was never added, removing it is free! Woohoo!
237 return;
238 }
239 bool found = false;
240 for (size_t i = 0; i < iterator->value.size(); ++i) {
241 if (iterator->value[i].ptr() == &face) {
242 found = true;
243 iterator->value.remove(i);
244 break;
245 }
246 }
247 ASSERT_UNUSED(found, found);
248 if (!iterator->value.size())
249 m_facesLookupTable.remove(iterator);
250 }
251}
252
253void CSSFontFaceSet::remove(const CSSFontFace& face)
254{
255 Ref protect { face };
256
257 m_cache.clear();
258
259 m_fontModifiedObservers.forEach([] (auto& observer) {
260 observer();
261 });
262
263 if (face.families())
264 removeFromFacesLookupTable(face, *face.families().value());
265
266 if (face.cssConnection()) {
267 ASSERT(m_constituentCSSConnections.get(face.cssConnection()) == &face);
268 m_constituentCSSConnections.remove(face.cssConnection());
269 }
270
271 for (size_t i = 0; i < m_faces.size(); ++i) {
272 if (m_faces[i].ptr() == &face) {
273 if (i < m_facesPartitionIndex)
274 --m_facesPartitionIndex;
275 m_faces[i]->removeClient(*this);
276 m_faces.remove(i);
277 if (face.status() == CSSFontFace::Status::Loading || face.status() == CSSFontFace::Status::TimedOut)
278 decrementActiveCount();
279 return;
280 }
281 }
282 ASSERT_NOT_REACHED();
283}
284
285CSSFontFace* CSSFontFaceSet::lookUpByCSSConnection(StyleRuleFontFace& target)
286{
287 return m_constituentCSSConnections.get(&target);
288}
289
290void CSSFontFaceSet::purge()
291{
292 Vector<Ref<CSSFontFace>> toRemove;
293 for (auto& face : m_faces) {
294 if (face->purgeable())
295 toRemove.append(face.copyRef());
296 }
297
298 for (auto& item : toRemove)
299 remove(item.get());
300}
301
302void CSSFontFaceSet::emptyCaches()
303{
304 m_cache.clear();
305}
306
307void CSSFontFaceSet::clear()
308{
309 for (auto& face : m_faces)
310 face->removeClient(*this);
311 m_faces.clear();
312 m_facesLookupTable.clear();
313 m_locallyInstalledFacesLookupTable.clear();
314 m_cache.clear();
315 m_constituentCSSConnections.clear();
316 m_facesPartitionIndex = 0;
317 m_status = Status::Loaded;
318}
319
320CSSFontFace& CSSFontFaceSet::operator[](size_t i)
321{
322 ASSERT(i < faceCount());
323 return m_faces[i];
324}
325
326static FontSelectionRequest computeFontSelectionRequest(CSSPropertyParserHelpers::FontRaw& font)
327{
328 auto weightSelectionValue = font.weight
329 ? WTF::switchOn(*font.weight, [&] (CSSValueID keyword) {
330 switch (keyword) {
331 case CSSValueNormal:
332 return normalWeightValue();
333 case CSSValueBold:
334 case CSSValueBolder:
335 return boldWeightValue();
336 case CSSValueLighter:
337 return lightWeightValue();
338 default:
339 ASSERT_NOT_REACHED();
340 return normalWeightValue();
341 }
342 }, [&] (double weight) {
343 return FontSelectionValue::clampFloat(weight);
344 }) : normalWeightValue();
345
346 // Because this is a FontRaw, we know we should be able to dereference stretchSelectionValue as
347 // consumeFontStretchKeywordValueRaw only returns results valid to pass to fontStretchValue.
348 auto stretchSelectionValue = fontStretchValue(font.stretch.value_or(CSSValueNormal));
349 ASSERT(stretchSelectionValue);
350
351 auto styleKeyword = font.style ? font.style->style : CSSValueNormal;
352 auto styleSelectionValue = [&] () -> std::optional<FontSelectionValue> {
353 if (styleKeyword == CSSValueNormal)
354 return std::nullopt;
355 if (styleKeyword == CSSValueItalic)
356 return italicValue();
357 ASSERT(font.style && styleKeyword == CSSValueOblique);
358 float degrees = 0;
359 if (font.style->angle)
360 degrees = static_cast<float>(CSSPrimitiveValue::computeDegrees(font.style->angle->type, font.style->angle->value));
361 return FontSelectionValue(degrees);
362 }();
363
364 return { weightSelectionValue, *stretchSelectionValue, styleSelectionValue };
365}
366
367using CodePointsMap = HashSet<UChar32, DefaultHash<UChar32>, WTF::UnsignedWithZeroKeyHashTraits<UChar32>>;
368static CodePointsMap codePointsFromString(StringView stringView)
369{
370 CodePointsMap result;
371 auto graphemeClusters = stringView.graphemeClusters();
372 for (auto cluster : graphemeClusters) {
373 ASSERT(cluster.length() > 0);
374 UChar32 character = 0;
375 if (cluster.is8Bit())
376 character = cluster[0];
377 else
378 U16_GET(cluster.characters16(), 0, 0, cluster.length(), character);
379 result.add(character);
380 }
381 return result;
382}
383
384ExceptionOr<Vector<std::reference_wrapper<CSSFontFace>>> CSSFontFaceSet::matchingFacesExcludingPreinstalledFonts(const String& fontShorthand, const String& string)
385{
386 auto font = CSSPropertyParserWorkerSafe::parseFont(fontShorthand, HTMLStandardMode);
387 if (!font)
388 return Exception { SyntaxError };
389
390 HashSet<AtomString> uniqueFamilies;
391 Vector<AtomString> familyOrder;
392 for (auto& familyRaw : font->family) {
393 AtomString familyAtom;
394 WTF::switchOn(familyRaw, [&] (CSSValueID familyKeyword) {
395 if (familyKeyword != CSSValueWebkitBody)
396 familyAtom = familyNamesData->at(CSSPropertyParserHelpers::genericFontFamilyIndex(familyKeyword));
397 else {
398 ASSERT(m_owningFontSelector && m_owningFontSelector->scriptExecutionContext());
399 familyAtom = AtomString { m_owningFontSelector->scriptExecutionContext()->settingsValues().fontGenericFamilies.standardFontFamily() };
400 }
401 }, [&] (const AtomString& familyString) {
402 familyAtom = familyString;
403 });
404
405 if (!familyAtom.isEmpty() && uniqueFamilies.add(familyAtom).isNewEntry)
406 familyOrder.append(familyAtom);
407 }
408
409 HashSet<CSSFontFace*> resultConstituents;
410 auto request = computeFontSelectionRequest(*font);
411 for (auto codePoint : codePointsFromString(string)) {
412 bool found = false;
413 for (auto& family : familyOrder) {
414 auto* faces = fontFace(request, family);
415 if (!faces)
416 continue;
417 for (auto& constituentFace : faces->constituentFaces()) {
418 if (constituentFace->isLocalFallback())
419 continue;
420 if (constituentFace->rangesMatchCodePoint(codePoint)) {
421 resultConstituents.add(constituentFace.ptr());
422 found = true;
423 break;
424 }
425 }
426 if (found)
427 break;
428 }
429 }
430
431 return WTF::map(resultConstituents, [](auto* constituent) -> std::reference_wrapper<CSSFontFace> {
432 return *constituent;
433 });
434}
435
436ExceptionOr<bool> CSSFontFaceSet::check(const String& font, const String& text)
437{
438 auto matchingFaces = this->matchingFacesExcludingPreinstalledFonts(font, text);
439 if (matchingFaces.hasException())
440 return matchingFaces.releaseException();
441
442 for (auto& face : matchingFaces.releaseReturnValue()) {
443 if (face.get().status() == CSSFontFace::Status::Pending
444 || face.get().status() == CSSFontFace::Status::Loading)
445 return false;
446 }
447 return true;
448}
449
450CSSSegmentedFontFace* CSSFontFaceSet::fontFace(FontSelectionRequest request, const AtomString& family)
451{
452 auto iterator = m_facesLookupTable.find(family);
453 if (iterator == m_facesLookupTable.end())
454 return nullptr;
455 auto& familyFontFaces = iterator->value;
456
457 auto& segmentedFontFaceCache = m_cache.add(family, FontSelectionHashMap()).iterator->value;
458
459 auto& face = segmentedFontFaceCache.add(request, nullptr).iterator->value;
460 if (face)
461 return face.get();
462
463 face = CSSSegmentedFontFace::create();
464
465 Vector<std::reference_wrapper<CSSFontFace>, 32> candidateFontFaces;
466 for (int i = familyFontFaces.size() - 1; i >= 0; --i) {
467 CSSFontFace& candidate = familyFontFaces[i];
468 if (auto capabilities = candidate.fontSelectionCapabilities()) {
469 if (!isItalic(request.slope) && isItalic(capabilities->slope.minimum))
470 continue;
471 candidateFontFaces.append(candidate);
472 }
473 }
474
475 auto localIterator = m_locallyInstalledFacesLookupTable.find(family);
476 if (localIterator != m_locallyInstalledFacesLookupTable.end()) {
477 for (auto& candidate : localIterator->value) {
478 if (auto capabilities = candidate->fontSelectionCapabilities()) {
479 if (!isItalic(request.slope) && isItalic(capabilities->slope.minimum))
480 continue;
481 candidateFontFaces.append(candidate);
482 }
483 }
484 }
485
486 if (!candidateFontFaces.isEmpty()) {
487 auto capabilities = candidateFontFaces.map([](auto& face) {
488 return *face.get().fontSelectionCapabilities();
489 });
490 FontSelectionAlgorithm fontSelectionAlgorithm(request, capabilities);
491 std::stable_sort(candidateFontFaces.begin(), candidateFontFaces.end(), [&fontSelectionAlgorithm](const CSSFontFace& first, const CSSFontFace& second) {
492 auto firstCapabilities = first.fontSelectionCapabilities();
493 auto secondCapabilities = second.fontSelectionCapabilities();
494
495 auto stretchDistanceFirst = fontSelectionAlgorithm.stretchDistance(*firstCapabilities).distance;
496 auto stretchDistanceSecond = fontSelectionAlgorithm.stretchDistance(*secondCapabilities).distance;
497 if (stretchDistanceFirst < stretchDistanceSecond)
498 return true;
499 if (stretchDistanceFirst > stretchDistanceSecond)
500 return false;
501
502 auto styleDistanceFirst = fontSelectionAlgorithm.styleDistance(*firstCapabilities).distance;
503 auto styleDistanceSecond = fontSelectionAlgorithm.styleDistance(*secondCapabilities).distance;
504 if (styleDistanceFirst < styleDistanceSecond)
505 return true;
506 if (styleDistanceFirst > styleDistanceSecond)
507 return false;
508
509 auto weightDistanceFirst = fontSelectionAlgorithm.weightDistance(*firstCapabilities).distance;
510 auto weightDistanceSecond = fontSelectionAlgorithm.weightDistance(*secondCapabilities).distance;
511 if (weightDistanceFirst < weightDistanceSecond)
512 return true;
513 return false;
514 });
515 CSSFontFace* previousCandidate = nullptr;
516 for (auto& candidate : candidateFontFaces) {
517 if (&candidate.get() == previousCandidate)
518 continue;
519 previousCandidate = &candidate.get();
520 face->appendFontFace(candidate.get());
521 }
522 }
523
524 return face.get();
525}
526
527void CSSFontFaceSet::fontStateChanged(CSSFontFace& face, CSSFontFace::Status oldState, CSSFontFace::Status newState)
528{
529 ASSERT(hasFace(face));
530 if (oldState == CSSFontFace::Status::Pending) {
531 ASSERT(newState == CSSFontFace::Status::Loading);
532 incrementActiveCount();
533 }
534 if (newState == CSSFontFace::Status::Success || newState == CSSFontFace::Status::Failure) {
535 ASSERT(oldState == CSSFontFace::Status::Loading || oldState == CSSFontFace::Status::TimedOut);
536 m_fontEventClients.forEach([&] (auto& client) {
537 client.faceFinished(face, newState);
538 });
539 decrementActiveCount();
540 }
541}
542
543void CSSFontFaceSet::fontPropertyChanged(CSSFontFace& face, CSSValueList* oldFamilies)
544{
545 m_cache.clear();
546
547 if (oldFamilies) {
548 removeFromFacesLookupTable(face, *oldFamilies);
549 addToFacesLookupTable(face);
550 }
551
552 m_fontModifiedObservers.forEach([] (auto& observer) {
553 observer();
554 });
555}
556
557}
Note: See TracBrowser for help on using the repository browser.