1/*
2 * Copyright (C) 2013-2017 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 "FontGenericFamilies.h"
28
29#include <wtf/Language.h>
30
31namespace WebCore {
32
33static bool setGenericFontFamilyForScript(ScriptFontFamilyMap& fontMap, const AtomicString& family, UScriptCode script)
34{
35 if (family.isEmpty())
36 return fontMap.remove(static_cast<int>(script));
37 auto& familyInMap = fontMap.add(static_cast<int>(script), AtomicString { }).iterator->value;
38 if (familyInMap == family)
39 return false;
40 familyInMap = family;
41 return true;
42}
43
44static inline bool computeUserPrefersSimplified()
45{
46 const Vector<String>& preferredLanguages = userPreferredLanguages();
47 for (auto& language : preferredLanguages) {
48 if (equalIgnoringASCIICase(language, "zh-tw"))
49 return false;
50 if (equalIgnoringASCIICase(language, "zh-cn"))
51 return true;
52 }
53 return true;
54}
55
56static bool& cachedUserPrefersSimplified()
57{
58 static bool cached = true;
59 return cached;
60}
61
62static void languageChanged(void*)
63{
64 cachedUserPrefersSimplified() = computeUserPrefersSimplified();
65}
66
67static const AtomicString& genericFontFamilyForScript(const ScriptFontFamilyMap& fontMap, UScriptCode script)
68{
69 ScriptFontFamilyMap::const_iterator it = fontMap.find(static_cast<int>(script));
70 if (it != fontMap.end())
71 return it->value;
72 // Content using USCRIPT_HAN doesn't tell us if we should be using Simplified Chinese or Traditional Chinese. In the
73 // absence of all other signals, we consult with the user's system preferences.
74 if (script == USCRIPT_HAN) {
75 it = fontMap.find(static_cast<int>(cachedUserPrefersSimplified() ? USCRIPT_SIMPLIFIED_HAN : USCRIPT_TRADITIONAL_HAN));
76 if (it != fontMap.end())
77 return it->value;
78 }
79 if (script != USCRIPT_COMMON)
80 return genericFontFamilyForScript(fontMap, USCRIPT_COMMON);
81 return emptyAtom();
82}
83
84FontGenericFamilies::FontGenericFamilies()
85{
86 addLanguageChangeObserver(this, &languageChanged);
87 languageChanged(nullptr);
88}
89
90const AtomicString& FontGenericFamilies::standardFontFamily(UScriptCode script) const
91{
92 return genericFontFamilyForScript(m_standardFontFamilyMap, script);
93}
94
95const AtomicString& FontGenericFamilies::fixedFontFamily(UScriptCode script) const
96{
97 return genericFontFamilyForScript(m_fixedFontFamilyMap, script);
98}
99
100const AtomicString& FontGenericFamilies::serifFontFamily(UScriptCode script) const
101{
102 return genericFontFamilyForScript(m_serifFontFamilyMap, script);
103}
104
105const AtomicString& FontGenericFamilies::sansSerifFontFamily(UScriptCode script) const
106{
107 return genericFontFamilyForScript(m_sansSerifFontFamilyMap, script);
108}
109
110const AtomicString& FontGenericFamilies::cursiveFontFamily(UScriptCode script) const
111{
112 return genericFontFamilyForScript(m_cursiveFontFamilyMap, script);
113}
114
115const AtomicString& FontGenericFamilies::fantasyFontFamily(UScriptCode script) const
116{
117 return genericFontFamilyForScript(m_fantasyFontFamilyMap, script);
118}
119
120const AtomicString& FontGenericFamilies::pictographFontFamily(UScriptCode script) const
121{
122 return genericFontFamilyForScript(m_pictographFontFamilyMap, script);
123}
124
125bool FontGenericFamilies::setStandardFontFamily(const AtomicString& family, UScriptCode script)
126{
127 return setGenericFontFamilyForScript(m_standardFontFamilyMap, family, script);
128}
129
130bool FontGenericFamilies::setFixedFontFamily(const AtomicString& family, UScriptCode script)
131{
132 return setGenericFontFamilyForScript(m_fixedFontFamilyMap, family, script);
133}
134
135bool FontGenericFamilies::setSerifFontFamily(const AtomicString& family, UScriptCode script)
136{
137 return setGenericFontFamilyForScript(m_serifFontFamilyMap, family, script);
138}
139
140bool FontGenericFamilies::setSansSerifFontFamily(const AtomicString& family, UScriptCode script)
141{
142 return setGenericFontFamilyForScript(m_sansSerifFontFamilyMap, family, script);
143}
144
145bool FontGenericFamilies::setCursiveFontFamily(const AtomicString& family, UScriptCode script)
146{
147 return setGenericFontFamilyForScript(m_cursiveFontFamilyMap, family, script);
148}
149
150bool FontGenericFamilies::setFantasyFontFamily(const AtomicString& family, UScriptCode script)
151{
152 return setGenericFontFamilyForScript(m_fantasyFontFamilyMap, family, script);
153}
154
155bool FontGenericFamilies::setPictographFontFamily(const AtomicString& family, UScriptCode script)
156{
157 return setGenericFontFamilyForScript(m_pictographFontFamilyMap, family, script);
158}
159
160}
161