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)
54interface IDWriteFactory;
55interface IDWriteGdiInterop;
56#endif
57
58namespace WebCore {
59
60class GlyphPage;
61class FontDescription;
62class SharedBuffer;
63struct GlyphData;
64struct WidthIterator;
65
66enum FontVariant { AutoVariant, NormalVariant, SmallCapsVariant, EmphasisMarkVariant, BrokenIdeographVariant };
67enum Pitch { UnknownPitch, FixedPitch, VariablePitch };
68enum class IsForPlatformFont : uint8_t { No, Yes };
69
70class Font : public RefCounted<Font> {
71public:
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
223private:
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)
327bool fontFamilyShouldNotBeUsedForArabic(CFStringRef);
328#endif
329
330ALWAYS_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
349ALWAYS_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