1 | /* |
2 | * Copyright (C) 2008, 2013 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 "CSSSegmentedFontFace.h" |
28 | |
29 | #include "CSSFontFace.h" |
30 | #include "Font.h" |
31 | #include "FontCache.h" |
32 | #include "FontDescription.h" |
33 | #include "FontSelector.h" |
34 | |
35 | namespace WebCore { |
36 | |
37 | CSSSegmentedFontFace::CSSSegmentedFontFace() |
38 | { |
39 | } |
40 | |
41 | CSSSegmentedFontFace::~CSSSegmentedFontFace() |
42 | { |
43 | for (auto& face : m_fontFaces) |
44 | face->removeClient(*this); |
45 | } |
46 | |
47 | void CSSSegmentedFontFace::appendFontFace(Ref<CSSFontFace>&& fontFace) |
48 | { |
49 | m_cache.clear(); |
50 | fontFace->addClient(*this); |
51 | m_fontFaces.append(WTFMove(fontFace)); |
52 | } |
53 | |
54 | void CSSSegmentedFontFace::fontLoaded(CSSFontFace&) |
55 | { |
56 | m_cache.clear(); |
57 | } |
58 | |
59 | class CSSFontAccessor final : public FontAccessor { |
60 | public: |
61 | static Ref<CSSFontAccessor> create(CSSFontFace& fontFace, const FontDescription& fontDescription, bool syntheticBold, bool syntheticItalic) |
62 | { |
63 | return adoptRef(*new CSSFontAccessor(fontFace, fontDescription, syntheticBold, syntheticItalic)); |
64 | } |
65 | |
66 | const Font* font(ExternalResourceDownloadPolicy policy) const final |
67 | { |
68 | if (!m_result || (policy == ExternalResourceDownloadPolicy::Allow |
69 | && (m_fontFace->status() == CSSFontFace::Status::Pending || m_fontFace->status() == CSSFontFace::Status::Loading || m_fontFace->status() == CSSFontFace::Status::TimedOut))) { |
70 | const auto result = m_fontFace->font(m_fontDescription, m_syntheticBold, m_syntheticItalic, policy); |
71 | if (!m_result) |
72 | m_result = result; |
73 | } |
74 | return m_result.value().get(); |
75 | } |
76 | |
77 | private: |
78 | CSSFontAccessor(CSSFontFace& fontFace, const FontDescription& fontDescription, bool syntheticBold, bool syntheticItalic) |
79 | : m_fontFace(fontFace) |
80 | , m_fontDescription(fontDescription) |
81 | , m_syntheticBold(syntheticBold) |
82 | , m_syntheticItalic(syntheticItalic) |
83 | { |
84 | } |
85 | |
86 | bool isLoading() const final |
87 | { |
88 | return m_result && m_result.value() && m_result.value()->isInterstitial(); |
89 | } |
90 | |
91 | mutable Optional<RefPtr<Font>> m_result; // Caches nullptr too |
92 | mutable Ref<CSSFontFace> m_fontFace; |
93 | FontDescription m_fontDescription; |
94 | bool m_syntheticBold; |
95 | bool m_syntheticItalic; |
96 | }; |
97 | |
98 | static void appendFont(FontRanges& ranges, Ref<FontAccessor>&& fontAccessor, const Vector<CSSFontFace::UnicodeRange>& unicodeRanges) |
99 | { |
100 | if (unicodeRanges.isEmpty()) { |
101 | ranges.appendRange({ 0, 0x7FFFFFFF, WTFMove(fontAccessor) }); |
102 | return; |
103 | } |
104 | |
105 | for (auto& range : unicodeRanges) |
106 | ranges.appendRange({ range.from, range.to, fontAccessor.copyRef() }); |
107 | } |
108 | |
109 | FontRanges CSSSegmentedFontFace::fontRanges(const FontDescription& fontDescription) |
110 | { |
111 | auto desiredRequest = fontDescription.fontSelectionRequest(); |
112 | |
113 | auto addResult = m_cache.add(FontDescriptionKey(fontDescription), FontRanges()); |
114 | auto& result = addResult.iterator->value; |
115 | |
116 | if (addResult.isNewEntry) { |
117 | for (auto& face : m_fontFaces) { |
118 | if (face->computeFailureState()) |
119 | continue; |
120 | |
121 | auto selectionCapabilities = face->fontSelectionCapabilities(); |
122 | bool syntheticBold = (fontDescription.fontSynthesis() & FontSynthesisWeight) && !isFontWeightBold(selectionCapabilities.weight.maximum) && isFontWeightBold(desiredRequest.weight); |
123 | bool syntheticItalic = (fontDescription.fontSynthesis() & FontSynthesisStyle) && !isItalic(selectionCapabilities.slope.maximum) && isItalic(desiredRequest.slope); |
124 | |
125 | // Metrics used for layout come from FontRanges::fontForFirstRange(), which assumes that the first font is non-null. |
126 | auto fontAccessor = CSSFontAccessor::create(face, fontDescription, syntheticBold, syntheticItalic); |
127 | if (result.isNull() && !fontAccessor->font(ExternalResourceDownloadPolicy::Forbid)) |
128 | continue; |
129 | appendFont(result, WTFMove(fontAccessor), face->ranges()); |
130 | } |
131 | } |
132 | return result; |
133 | } |
134 | |
135 | } |
136 | |