1 | /* |
2 | * This file is part of the internal font implementation. |
3 | * |
4 | * Copyright (C) 2006, 2008, 2010, 2015-2016 Apple Inc. All rights reserved. |
5 | * Copyright (C) 2007-2008 Torch Mobile, Inc. |
6 | * |
7 | * This library is free software; you can redistribute it and/or |
8 | * modify it under the terms of the GNU Library General Public |
9 | * License as published by the Free Software Foundation; either |
10 | * version 2 of the License, or (at your option) any later version. |
11 | * |
12 | * This library is distributed in the hope that it will be useful, |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
15 | * Library General Public License for more details. |
16 | * |
17 | * You should have received a copy of the GNU Library General Public License |
18 | * along with this library; see the file COPYING.LIB. If not, write to |
19 | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
20 | * Boston, MA 02110-1301, USA. |
21 | * |
22 | */ |
23 | |
24 | #ifndef Font_h |
25 | #define Font_h |
26 | |
27 | #include "FloatRect.h" |
28 | #include "FontMetrics.h" |
29 | #include "FontPlatformData.h" |
30 | #include "GlyphBuffer.h" |
31 | #include "GlyphMetricsMap.h" |
32 | #include "GlyphPage.h" |
33 | #include "OpenTypeMathData.h" |
34 | #if ENABLE(OPENTYPE_VERTICAL) |
35 | #include "OpenTypeVerticalData.h" |
36 | #endif |
37 | #include <wtf/BitVector.h> |
38 | #include <wtf/Optional.h> |
39 | #include <wtf/text/StringHash.h> |
40 | |
41 | #if PLATFORM(COCOA) |
42 | #include <wtf/RetainPtr.h> |
43 | #endif |
44 | |
45 | #if PLATFORM(WIN) |
46 | #include <usp10.h> |
47 | #endif |
48 | |
49 | #if USE(CG) |
50 | #include <pal/spi/cg/CoreGraphicsSPI.h> |
51 | #endif |
52 | |
53 | #if USE(DIRECT2D) |
54 | interface IDWriteFactory; |
55 | interface IDWriteGdiInterop; |
56 | #endif |
57 | |
58 | namespace WebCore { |
59 | |
60 | class GlyphPage; |
61 | class FontDescription; |
62 | class SharedBuffer; |
63 | struct GlyphData; |
64 | struct WidthIterator; |
65 | |
66 | enum FontVariant { AutoVariant, NormalVariant, SmallCapsVariant, EmphasisMarkVariant, BrokenIdeographVariant }; |
67 | enum Pitch { UnknownPitch, FixedPitch, VariablePitch }; |
68 | enum class IsForPlatformFont : uint8_t { No, Yes }; |
69 | |
70 | class Font : public RefCounted<Font> { |
71 | public: |
72 | // Used to create platform fonts. |
73 | enum class Origin : uint8_t { |
74 | Remote, |
75 | Local |
76 | }; |
77 | enum class Interstitial : uint8_t { |
78 | Yes, |
79 | No |
80 | }; |
81 | enum class Visibility : uint8_t { |
82 | Visible, |
83 | Invisible |
84 | }; |
85 | enum class OrientationFallback : uint8_t { |
86 | Yes, |
87 | No |
88 | }; |
89 | static Ref<Font> create(const FontPlatformData& platformData, Origin origin = Origin::Local, Interstitial interstitial = Interstitial::No, Visibility visibility = Visibility::Visible, OrientationFallback orientationFallback = OrientationFallback::No) |
90 | { |
91 | return adoptRef(*new Font(platformData, origin, interstitial, visibility, orientationFallback)); |
92 | } |
93 | |
94 | WEBCORE_EXPORT ~Font(); |
95 | |
96 | static const Font* systemFallback() { return reinterpret_cast<const Font*>(-1); } |
97 | |
98 | const FontPlatformData& platformData() const { return m_platformData; } |
99 | const OpenTypeMathData* mathData() const; |
100 | #if ENABLE(OPENTYPE_VERTICAL) |
101 | const OpenTypeVerticalData* verticalData() const { return m_verticalData.get(); } |
102 | #endif |
103 | |
104 | const Font* smallCapsFont(const FontDescription&) const; |
105 | const Font& noSynthesizableFeaturesFont() const; |
106 | const Font* emphasisMarkFont(const FontDescription&) const; |
107 | const Font& brokenIdeographFont() const; |
108 | |
109 | const Font* variantFont(const FontDescription& description, FontVariant variant) const |
110 | { |
111 | #if PLATFORM(COCOA) |
112 | ASSERT(variant != SmallCapsVariant); |
113 | #endif |
114 | switch (variant) { |
115 | case SmallCapsVariant: |
116 | return smallCapsFont(description); |
117 | case EmphasisMarkVariant: |
118 | return emphasisMarkFont(description); |
119 | case BrokenIdeographVariant: |
120 | return &brokenIdeographFont(); |
121 | case AutoVariant: |
122 | case NormalVariant: |
123 | break; |
124 | } |
125 | ASSERT_NOT_REACHED(); |
126 | return const_cast<Font*>(this); |
127 | } |
128 | |
129 | bool variantCapsSupportsCharacterForSynthesis(FontVariantCaps, UChar32) const; |
130 | |
131 | const Font& verticalRightOrientationFont() const; |
132 | const Font& uprightOrientationFont() const; |
133 | const Font& invisibleFont() const; |
134 | |
135 | bool hasVerticalGlyphs() const { return m_hasVerticalGlyphs; } |
136 | bool isTextOrientationFallback() const { return m_isTextOrientationFallback; } |
137 | |
138 | FontMetrics& fontMetrics() { return m_fontMetrics; } |
139 | const FontMetrics& fontMetrics() const { return m_fontMetrics; } |
140 | float sizePerUnit() const { return platformData().size() / (fontMetrics().unitsPerEm() ? fontMetrics().unitsPerEm() : 1); } |
141 | |
142 | float maxCharWidth() const { return m_maxCharWidth; } |
143 | void setMaxCharWidth(float maxCharWidth) { m_maxCharWidth = maxCharWidth; } |
144 | |
145 | float avgCharWidth() const { return m_avgCharWidth; } |
146 | void setAvgCharWidth(float avgCharWidth) { m_avgCharWidth = avgCharWidth; } |
147 | |
148 | FloatRect boundsForGlyph(Glyph) const; |
149 | float widthForGlyph(Glyph) const; |
150 | const Path& pathForGlyph(Glyph) const; // Don't store the result of this! The hash map is free to rehash at any point, leaving this reference dangling. |
151 | FloatRect platformBoundsForGlyph(Glyph) const; |
152 | float platformWidthForGlyph(Glyph) const; |
153 | Path platformPathForGlyph(Glyph) const; |
154 | |
155 | float spaceWidth() const { return m_spaceWidth; } |
156 | float adjustedSpaceWidth() const { return m_adjustedSpaceWidth; } |
157 | void setSpaceWidths(float spaceWidth) |
158 | { |
159 | m_spaceWidth = spaceWidth; |
160 | m_adjustedSpaceWidth = spaceWidth; |
161 | } |
162 | |
163 | #if USE(CG) || USE(DIRECT2D) || USE(CAIRO) |
164 | float syntheticBoldOffset() const { return m_syntheticBoldOffset; } |
165 | #endif |
166 | |
167 | Glyph spaceGlyph() const { return m_spaceGlyph; } |
168 | void setSpaceGlyph(Glyph spaceGlyph) { m_spaceGlyph = spaceGlyph; } |
169 | Glyph zeroWidthSpaceGlyph() const { return m_zeroWidthSpaceGlyph; } |
170 | void setZeroWidthSpaceGlyph(Glyph spaceGlyph) { m_zeroWidthSpaceGlyph = spaceGlyph; } |
171 | bool isZeroWidthSpaceGlyph(Glyph glyph) const { return glyph == m_zeroWidthSpaceGlyph && glyph; } |
172 | Glyph zeroGlyph() const { return m_zeroGlyph; } |
173 | void setZeroGlyph(Glyph zeroGlyph) { m_zeroGlyph = zeroGlyph; } |
174 | |
175 | GlyphData glyphDataForCharacter(UChar32) const; |
176 | Glyph glyphForCharacter(UChar32) const; |
177 | bool supportsCodePoint(UChar32) const; |
178 | bool platformSupportsCodePoint(UChar32, Optional<UChar32> variation = WTF::nullopt) const; |
179 | |
180 | RefPtr<Font> systemFallbackFontForCharacter(UChar32, const FontDescription&, IsForPlatformFont) const; |
181 | |
182 | const GlyphPage* glyphPage(unsigned pageNumber) const; |
183 | |
184 | void determinePitch(); |
185 | Pitch pitch() const { return m_treatAsFixedPitch ? FixedPitch : VariablePitch; } |
186 | |
187 | Origin origin() const { return m_origin; } |
188 | bool isInterstitial() const { return m_isInterstitial; } |
189 | Visibility visibility() const { return m_visibility; } |
190 | |
191 | #if !LOG_DISABLED |
192 | String description() const; |
193 | #endif |
194 | |
195 | #if PLATFORM(IOS_FAMILY) |
196 | bool shouldNotBeUsedForArabic() const { return m_shouldNotBeUsedForArabic; }; |
197 | #endif |
198 | #if PLATFORM(COCOA) |
199 | CTFontRef getCTFont() const { return m_platformData.font(); } |
200 | CFDictionaryRef getCFStringAttributes(bool enableKerning, FontOrientation) const; |
201 | const BitVector& glyphsSupportedBySmallCaps() const; |
202 | const BitVector& glyphsSupportedByAllSmallCaps() const; |
203 | const BitVector& glyphsSupportedByPetiteCaps() const; |
204 | const BitVector& glyphsSupportedByAllPetiteCaps() const; |
205 | #endif |
206 | |
207 | bool canRenderCombiningCharacterSequence(const UChar*, size_t) const; |
208 | bool applyTransforms(GlyphBufferGlyph*, GlyphBufferAdvance*, size_t glyphCount, bool enableKerning, bool requiresShaping) const; |
209 | |
210 | #if PLATFORM(WIN) |
211 | SCRIPT_FONTPROPERTIES* scriptFontProperties() const; |
212 | SCRIPT_CACHE* scriptCache() const { return &m_scriptCache; } |
213 | static void setShouldApplyMacAscentHack(bool); |
214 | static bool shouldApplyMacAscentHack(); |
215 | static float ascentConsideringMacAscentHack(const WCHAR*, float ascent, float descent); |
216 | #endif |
217 | |
218 | #if USE(DIRECT2D) |
219 | WEBCORE_EXPORT static IDWriteFactory* systemDWriteFactory(); |
220 | WEBCORE_EXPORT static IDWriteGdiInterop* systemDWriteGdiInterop(); |
221 | #endif |
222 | |
223 | private: |
224 | Font(const FontPlatformData&, Origin, Interstitial, Visibility, OrientationFallback); |
225 | |
226 | void platformInit(); |
227 | void platformGlyphInit(); |
228 | void platformCharWidthInit(); |
229 | void platformDestroy(); |
230 | |
231 | void initCharWidths(); |
232 | |
233 | RefPtr<Font> createFontWithoutSynthesizableFeatures() const; |
234 | RefPtr<Font> createScaledFont(const FontDescription&, float scaleFactor) const; |
235 | RefPtr<Font> platformCreateScaledFont(const FontDescription&, float scaleFactor) const; |
236 | |
237 | void removeFromSystemFallbackCache(); |
238 | |
239 | struct DerivedFonts; |
240 | DerivedFonts& ensureDerivedFontData() const; |
241 | |
242 | #if PLATFORM(WIN) |
243 | void initGDIFont(); |
244 | void platformCommonDestroy(); |
245 | FloatRect boundsForGDIGlyph(Glyph) const; |
246 | float widthForGDIGlyph(Glyph) const; |
247 | #endif |
248 | |
249 | FontMetrics m_fontMetrics; |
250 | float m_maxCharWidth { -1 }; |
251 | float m_avgCharWidth { -1 }; |
252 | |
253 | const FontPlatformData m_platformData; |
254 | |
255 | mutable RefPtr<GlyphPage> m_glyphPageZero; |
256 | mutable HashMap<unsigned, RefPtr<GlyphPage>> m_glyphPages; |
257 | mutable std::unique_ptr<GlyphMetricsMap<FloatRect>> m_glyphToBoundsMap; |
258 | mutable GlyphMetricsMap<float> m_glyphToWidthMap; |
259 | mutable GlyphMetricsMap<Optional<Path>> m_glyphPathMap; |
260 | mutable BitVector m_codePointSupport; |
261 | |
262 | mutable RefPtr<OpenTypeMathData> m_mathData; |
263 | #if ENABLE(OPENTYPE_VERTICAL) |
264 | RefPtr<OpenTypeVerticalData> m_verticalData; |
265 | #endif |
266 | |
267 | struct DerivedFonts { |
268 | #if !COMPILER(MSVC) |
269 | WTF_MAKE_FAST_ALLOCATED; |
270 | #endif |
271 | public: |
272 | |
273 | RefPtr<Font> smallCapsFont; |
274 | RefPtr<Font> noSynthesizableFeaturesFont; |
275 | RefPtr<Font> emphasisMarkFont; |
276 | RefPtr<Font> brokenIdeographFont; |
277 | RefPtr<Font> verticalRightOrientationFont; |
278 | RefPtr<Font> uprightOrientationFont; |
279 | RefPtr<Font> invisibleFont; |
280 | }; |
281 | |
282 | mutable std::unique_ptr<DerivedFonts> m_derivedFontData; |
283 | |
284 | #if PLATFORM(COCOA) |
285 | mutable RetainPtr<CFMutableDictionaryRef> m_nonKernedCFStringAttributes; |
286 | mutable RetainPtr<CFMutableDictionaryRef> m_kernedCFStringAttributes; |
287 | mutable Optional<BitVector> m_glyphsSupportedBySmallCaps; |
288 | mutable Optional<BitVector> m_glyphsSupportedByAllSmallCaps; |
289 | mutable Optional<BitVector> m_glyphsSupportedByPetiteCaps; |
290 | mutable Optional<BitVector> m_glyphsSupportedByAllPetiteCaps; |
291 | #endif |
292 | |
293 | #if PLATFORM(WIN) |
294 | mutable SCRIPT_CACHE m_scriptCache; |
295 | mutable SCRIPT_FONTPROPERTIES* m_scriptFontProperties; |
296 | #endif |
297 | |
298 | Glyph m_spaceGlyph { 0 }; |
299 | Glyph m_zeroGlyph { 0 }; |
300 | Glyph m_zeroWidthSpaceGlyph { 0 }; |
301 | |
302 | Origin m_origin; // Whether or not we are custom font loaded via @font-face |
303 | Visibility m_visibility; // @font-face's internal timer can cause us to show fonts even when a font is being downloaded. |
304 | |
305 | float m_spaceWidth { 0 }; |
306 | float m_adjustedSpaceWidth { 0 }; |
307 | |
308 | #if USE(CG) || USE(DIRECT2D) || USE(CAIRO) |
309 | float m_syntheticBoldOffset { 0 }; |
310 | #endif |
311 | |
312 | unsigned m_treatAsFixedPitch : 1; |
313 | unsigned m_isInterstitial : 1; // Whether or not this custom font is the last resort placeholder for a loading font |
314 | |
315 | unsigned m_isTextOrientationFallback : 1; |
316 | unsigned m_isBrokenIdeographFallback : 1; |
317 | unsigned m_hasVerticalGlyphs : 1; |
318 | |
319 | unsigned m_isUsedInSystemFallbackCache : 1; |
320 | |
321 | #if PLATFORM(IOS_FAMILY) |
322 | unsigned m_shouldNotBeUsedForArabic : 1; |
323 | #endif |
324 | }; |
325 | |
326 | #if PLATFORM(IOS_FAMILY) |
327 | bool fontFamilyShouldNotBeUsedForArabic(CFStringRef); |
328 | #endif |
329 | |
330 | ALWAYS_INLINE FloatRect Font::boundsForGlyph(Glyph glyph) const |
331 | { |
332 | if (isZeroWidthSpaceGlyph(glyph)) |
333 | return FloatRect(); |
334 | |
335 | FloatRect bounds; |
336 | if (m_glyphToBoundsMap) { |
337 | bounds = m_glyphToBoundsMap->metricsForGlyph(glyph); |
338 | if (bounds.width() != cGlyphSizeUnknown) |
339 | return bounds; |
340 | } |
341 | |
342 | bounds = platformBoundsForGlyph(glyph); |
343 | if (!m_glyphToBoundsMap) |
344 | m_glyphToBoundsMap = std::make_unique<GlyphMetricsMap<FloatRect>>(); |
345 | m_glyphToBoundsMap->setMetricsForGlyph(glyph, bounds); |
346 | return bounds; |
347 | } |
348 | |
349 | ALWAYS_INLINE float Font::widthForGlyph(Glyph glyph) const |
350 | { |
351 | // The optimization of returning 0 for the zero-width-space glyph is incorrect for the LastResort font, |
352 | // used in place of the actual font when isLoading() is true on both macOS and iOS. |
353 | // The zero-width-space glyph in that font does not have a width of zero and, further, that glyph is used |
354 | // for many other characters and must not be zero width when used for them. |
355 | if (isZeroWidthSpaceGlyph(glyph) && !isInterstitial()) |
356 | return 0; |
357 | |
358 | float width = m_glyphToWidthMap.metricsForGlyph(glyph); |
359 | if (width != cGlyphSizeUnknown) |
360 | return width; |
361 | |
362 | #if ENABLE(OPENTYPE_VERTICAL) |
363 | if (m_verticalData) { |
364 | #if USE(CG) || USE(DIRECT2D) || USE(CAIRO) |
365 | width = m_verticalData->advanceHeight(this, glyph) + m_syntheticBoldOffset; |
366 | #else |
367 | width = m_verticalData->advanceHeight(this, glyph); |
368 | #endif |
369 | } else |
370 | #endif |
371 | width = platformWidthForGlyph(glyph); |
372 | |
373 | m_glyphToWidthMap.setMetricsForGlyph(glyph, width); |
374 | return width; |
375 | } |
376 | |
377 | } // namespace WebCore |
378 | |
379 | #endif // Font_h |
380 | |