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
35namespace WebCore {
36
37CSSSegmentedFontFace::CSSSegmentedFontFace()
38{
39}
40
41CSSSegmentedFontFace::~CSSSegmentedFontFace()
42{
43 for (auto& face : m_fontFaces)
44 face->removeClient(*this);
45}
46
47void CSSSegmentedFontFace::appendFontFace(Ref<CSSFontFace>&& fontFace)
48{
49 m_cache.clear();
50 fontFace->addClient(*this);
51 m_fontFaces.append(WTFMove(fontFace));
52}
53
54void CSSSegmentedFontFace::fontLoaded(CSSFontFace&)
55{
56 m_cache.clear();
57}
58
59class CSSFontAccessor final : public FontAccessor {
60public:
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
77private:
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
98static 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
109FontRanges 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