Revert r187626 (and r188025) as it caused a PLT regression
[WebKit-https.git] / Source / WebCore / platform / graphics / Font.cpp
1 /*
2  * Copyright (C) 2005, 2008, 2010, 2015 Apple Inc. All rights reserved.
3  * Copyright (C) 2006 Alexey Proskuryakov
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1.  Redistributions of source code must retain the above copyright
10  *     notice, this list of conditions and the following disclaimer. 
11  * 2.  Redistributions in binary form must reproduce the above copyright
12  *     notice, this list of conditions and the following disclaimer in the
13  *     documentation and/or other materials provided with the distribution. 
14  * 3.  Neither the name of Apple Inc. ("Apple") nor the names of
15  *     its contributors may be used to endorse or promote products derived
16  *     from this software without specific prior written permission. 
17  *
18  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
19  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
22  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 #include "config.h"
31 #include "Font.h"
32
33 #if PLATFORM(COCOA)
34 #include "CoreTextSPI.h"
35 #endif
36 #include "FontCache.h"
37 #include "FontCascade.h"
38 #include "OpenTypeMathData.h"
39 #include <wtf/MathExtras.h>
40 #include <wtf/NeverDestroyed.h>
41 #include <wtf/text/AtomicStringHash.h>
42
43 #if ENABLE(OPENTYPE_VERTICAL)
44 #include "OpenTypeVerticalData.h"
45 #endif
46
47 namespace WebCore {
48
49 unsigned GlyphPage::s_count = 0;
50
51 const float smallCapsFontSizeMultiplier = 0.7f;
52 const float emphasisMarkFontSizeMultiplier = 0.5f;
53
54 Font::Font(const FontPlatformData& platformData, std::unique_ptr<SVGData>&& svgData, bool isCustomFont, bool isLoading, bool isTextOrientationFallback)
55     : m_maxCharWidth(-1)
56     , m_avgCharWidth(-1)
57     , m_platformData(platformData)
58     , m_svgData(WTF::move(svgData))
59     , m_mathData(nullptr)
60     , m_treatAsFixedPitch(false)
61     , m_isCustomFont(isCustomFont)
62     , m_isLoading(isLoading)
63     , m_isTextOrientationFallback(isTextOrientationFallback)
64     , m_isBrokenIdeographFallback(false)
65     , m_hasVerticalGlyphs(false)
66     , m_isUsedInSystemFallbackCache(false)
67 #if PLATFORM(COCOA) || PLATFORM(WIN)
68     , m_isSystemFont(false)
69 #endif
70 #if PLATFORM(IOS)
71     , m_shouldNotBeUsedForArabic(false)
72 #endif
73 {
74 }
75
76 Font::Font(const FontPlatformData& platformData, bool isCustomFont, bool isLoading, bool isTextOrientationFallback)
77     : Font(platformData, std::unique_ptr<SVGData>(), isCustomFont, isLoading, isTextOrientationFallback)
78 {
79     platformInit();
80     platformGlyphInit();
81     platformCharWidthInit();
82 #if ENABLE(OPENTYPE_VERTICAL)
83     if (platformData.orientation() == Vertical && !isTextOrientationFallback) {
84         m_verticalData = platformData.verticalData();
85         m_hasVerticalGlyphs = m_verticalData.get() && m_verticalData->hasVerticalMetrics();
86     }
87 #endif
88 }
89
90 Font::Font(std::unique_ptr<SVGData> svgData, float fontSize, bool syntheticBold, bool syntheticItalic)
91     : Font(FontPlatformData(fontSize, syntheticBold, syntheticItalic), WTF::move(svgData), true, false, false)
92 {
93     m_svgData->initializeFont(this, fontSize);
94 }
95
96 // Estimates of avgCharWidth and maxCharWidth for platforms that don't support accessing these values from the font.
97 void Font::initCharWidths()
98 {
99     auto* glyphPageZero = glyphPage(0);
100
101     // Treat the width of a '0' as the avgCharWidth.
102     if (m_avgCharWidth <= 0.f && glyphPageZero) {
103         static const UChar32 digitZeroChar = '0';
104         Glyph digitZeroGlyph = glyphPageZero->glyphDataForCharacter(digitZeroChar).glyph;
105         if (digitZeroGlyph)
106             m_avgCharWidth = widthForGlyph(digitZeroGlyph);
107     }
108
109     // If we can't retrieve the width of a '0', fall back to the x height.
110     if (m_avgCharWidth <= 0.f)
111         m_avgCharWidth = m_fontMetrics.xHeight();
112
113     if (m_maxCharWidth <= 0.f)
114         m_maxCharWidth = std::max(m_avgCharWidth, m_fontMetrics.floatAscent());
115 }
116
117 void Font::platformGlyphInit()
118 {
119     auto* glyphPageZero = glyphPage(0);
120     if (!glyphPageZero) {
121         determinePitch();
122         return;
123     }
124
125     // Ask for the glyph for 0 to avoid paging in ZERO WIDTH SPACE. Control characters, including 0,
126     // are mapped to the ZERO WIDTH SPACE glyph.
127     m_zeroWidthSpaceGlyph = glyphPageZero->glyphDataForCharacter(0).glyph;
128
129     // Nasty hack to determine if we should round or ceil space widths.
130     // If the font is monospace or fake monospace we ceil to ensure that 
131     // every character and the space are the same width. Otherwise we round.
132     m_spaceGlyph = glyphPageZero->glyphDataForCharacter(' ').glyph;
133     float width = widthForGlyph(m_spaceGlyph);
134     m_spaceWidth = width;
135     m_zeroGlyph = glyphPageZero->glyphDataForCharacter('0').glyph;
136     m_fontMetrics.setZeroWidth(widthForGlyph(m_zeroGlyph));
137     determinePitch();
138     m_adjustedSpaceWidth = m_treatAsFixedPitch ? ceilf(width) : roundf(width);
139
140     // Force the glyph for ZERO WIDTH SPACE to have zero width, unless it is shared with SPACE.
141     // Helvetica is an example of a non-zero width ZERO WIDTH SPACE glyph.
142     // See <http://bugs.webkit.org/show_bug.cgi?id=13178> and Font::isZeroWidthSpaceGlyph()
143     if (m_zeroWidthSpaceGlyph == m_spaceGlyph)
144         m_zeroWidthSpaceGlyph = 0;
145 }
146
147 Font::~Font()
148 {
149     removeFromSystemFallbackCache();
150 }
151
152 static bool fillGlyphPage(GlyphPage& pageToFill, UChar* buffer, unsigned bufferLength, const Font& font)
153 {
154 #if ENABLE(SVG_FONTS)
155     if (auto* svgData = font.svgData())
156         return svgData->fillSVGGlyphPage(&pageToFill, buffer, bufferLength);
157 #endif
158     bool hasGlyphs = pageToFill.fill(buffer, bufferLength, &font);
159 #if ENABLE(OPENTYPE_VERTICAL)
160     if (hasGlyphs && font.verticalData())
161         font.verticalData()->substituteWithVerticalGlyphs(&font, &pageToFill);
162 #endif
163     return hasGlyphs;
164 }
165
166 static RefPtr<GlyphPage> createAndFillGlyphPage(unsigned pageNumber, const Font& font)
167 {
168 #if PLATFORM(IOS)
169     // FIXME: Times New Roman contains Arabic glyphs, but Core Text doesn't know how to shape them. See <rdar://problem/9823975>.
170     // Once we have the fix for <rdar://problem/9823975> then remove this code together with Font::shouldNotBeUsedForArabic()
171     // in <rdar://problem/12096835>.
172     if (pageNumber == 6 && font.shouldNotBeUsedForArabic())
173         return nullptr;
174 #endif
175
176     unsigned start = pageNumber * GlyphPage::size;
177     UChar buffer[GlyphPage::size * 2 + 2];
178     unsigned bufferLength;
179     // Fill in a buffer with the entire "page" of characters that we want to look up glyphs for.
180     if (U_IS_BMP(start)) {
181         bufferLength = GlyphPage::size;
182         for (unsigned i = 0; i < GlyphPage::size; i++)
183             buffer[i] = start + i;
184
185         if (!start) {
186             // Control characters must not render at all.
187             for (unsigned i = 0; i < 0x20; ++i)
188                 buffer[i] = zeroWidthSpace;
189             for (unsigned i = 0x7F; i < 0xA0; i++)
190                 buffer[i] = zeroWidthSpace;
191             buffer[softHyphen] = zeroWidthSpace;
192
193             // \n, \t, and nonbreaking space must render as a space.
194             buffer[(int)'\n'] = ' ';
195             buffer[(int)'\t'] = ' ';
196             buffer[noBreakSpace] = ' ';
197         } else if (start == (leftToRightMark & ~(GlyphPage::size - 1))) {
198             // LRM, RLM, LRE, RLE, ZWNJ, ZWJ, and PDF must not render at all.
199             buffer[leftToRightMark - start] = zeroWidthSpace;
200             buffer[rightToLeftMark - start] = zeroWidthSpace;
201             buffer[leftToRightEmbed - start] = zeroWidthSpace;
202             buffer[rightToLeftEmbed - start] = zeroWidthSpace;
203             buffer[leftToRightOverride - start] = zeroWidthSpace;
204             buffer[rightToLeftOverride - start] = zeroWidthSpace;
205             buffer[zeroWidthNonJoiner - start] = zeroWidthSpace;
206             buffer[zeroWidthJoiner - start] = zeroWidthSpace;
207             buffer[popDirectionalFormatting - start] = zeroWidthSpace;
208         } else if (start == (objectReplacementCharacter & ~(GlyphPage::size - 1))) {
209             // Object replacement character must not render at all.
210             buffer[objectReplacementCharacter - start] = zeroWidthSpace;
211         } else if (start == (zeroWidthNoBreakSpace & ~(GlyphPage::size - 1))) {
212             // ZWNBS/BOM must not render at all.
213             buffer[zeroWidthNoBreakSpace - start] = zeroWidthSpace;
214         }
215     } else {
216         bufferLength = GlyphPage::size * 2;
217         for (unsigned i = 0; i < GlyphPage::size; i++) {
218             int c = i + start;
219             buffer[i * 2] = U16_LEAD(c);
220             buffer[i * 2 + 1] = U16_TRAIL(c);
221         }
222     }
223
224     // Now that we have a buffer full of characters, we want to get back an array
225     // of glyph indices. This part involves calling into the platform-specific
226     // routine of our glyph map for actually filling in the page with the glyphs.
227     // Success is not guaranteed. For example, Times fails to fill page 260, giving glyph data
228     // for only 128 out of 256 characters.
229     Ref<GlyphPage> glyphPage = GlyphPage::create(font);
230
231     bool haveGlyphs = fillGlyphPage(glyphPage, buffer, bufferLength, font);
232     if (!haveGlyphs)
233         return nullptr;
234
235     return WTF::move(glyphPage);
236 }
237
238 const GlyphPage* Font::glyphPage(unsigned pageNumber) const
239 {
240     if (!pageNumber) {
241         if (!m_glyphPageZero)
242             m_glyphPageZero = createAndFillGlyphPage(0, *this);
243         return m_glyphPageZero.get();
244     }
245     auto addResult = m_glyphPages.add(pageNumber, nullptr);
246     if (addResult.isNewEntry)
247         addResult.iterator->value = createAndFillGlyphPage(pageNumber, *this);
248
249     return addResult.iterator->value.get();
250 }
251
252 Glyph Font::glyphForCharacter(UChar32 character) const
253 {
254     auto* page = glyphPage(character / GlyphPage::size);
255     if (!page)
256         return 0;
257     return page->glyphForCharacter(character);
258 }
259
260 GlyphData Font::glyphDataForCharacter(UChar32 character) const
261 {
262     auto* page = glyphPage(character / GlyphPage::size);
263     if (!page)
264         return GlyphData();
265     return page->glyphDataForCharacter(character);
266 }
267
268 PassRefPtr<Font> Font::verticalRightOrientationFont() const
269 {
270     if (!m_derivedFontData)
271         m_derivedFontData = std::make_unique<DerivedFontData>(isCustomFont());
272     if (!m_derivedFontData->verticalRightOrientation) {
273         FontPlatformData verticalRightPlatformData(m_platformData);
274         verticalRightPlatformData.setOrientation(Horizontal);
275         m_derivedFontData->verticalRightOrientation = create(verticalRightPlatformData, isCustomFont(), false, true);
276     }
277     ASSERT(m_derivedFontData->verticalRightOrientation != this);
278     return m_derivedFontData->verticalRightOrientation;
279 }
280
281 PassRefPtr<Font> Font::uprightOrientationFont() const
282 {
283     if (!m_derivedFontData)
284         m_derivedFontData = std::make_unique<DerivedFontData>(isCustomFont());
285     if (!m_derivedFontData->uprightOrientation)
286         m_derivedFontData->uprightOrientation = create(m_platformData, isCustomFont(), false, true);
287     ASSERT(m_derivedFontData->uprightOrientation != this);
288     return m_derivedFontData->uprightOrientation;
289 }
290
291 PassRefPtr<Font> Font::smallCapsFont(const FontDescription& fontDescription) const
292 {
293     if (!m_derivedFontData)
294         m_derivedFontData = std::make_unique<DerivedFontData>(isCustomFont());
295     if (!m_derivedFontData->smallCaps)
296         m_derivedFontData->smallCaps = createScaledFont(fontDescription, smallCapsFontSizeMultiplier);
297     ASSERT(m_derivedFontData->smallCaps != this);
298     return m_derivedFontData->smallCaps;
299 }
300
301 PassRefPtr<Font> Font::emphasisMarkFont(const FontDescription& fontDescription) const
302 {
303     if (!m_derivedFontData)
304         m_derivedFontData = std::make_unique<DerivedFontData>(isCustomFont());
305     if (!m_derivedFontData->emphasisMark)
306         m_derivedFontData->emphasisMark = createScaledFont(fontDescription, emphasisMarkFontSizeMultiplier);
307     ASSERT(m_derivedFontData->emphasisMark != this);
308     return m_derivedFontData->emphasisMark;
309 }
310
311 PassRefPtr<Font> Font::brokenIdeographFont() const
312 {
313     if (!m_derivedFontData)
314         m_derivedFontData = std::make_unique<DerivedFontData>(isCustomFont());
315     if (!m_derivedFontData->brokenIdeograph) {
316         m_derivedFontData->brokenIdeograph = create(m_platformData, isCustomFont(), false);
317         m_derivedFontData->brokenIdeograph->m_isBrokenIdeographFallback = true;
318     }
319     ASSERT(m_derivedFontData->brokenIdeograph != this);
320     return m_derivedFontData->brokenIdeograph;
321 }
322
323 PassRefPtr<Font> Font::nonSyntheticItalicFont() const
324 {
325     if (!m_derivedFontData)
326         m_derivedFontData = std::make_unique<DerivedFontData>(isCustomFont());
327     if (!m_derivedFontData->nonSyntheticItalic) {
328         FontPlatformData nonSyntheticItalicFontPlatformData(m_platformData);
329 #if PLATFORM(COCOA) || USE(CAIRO)
330         nonSyntheticItalicFontPlatformData.setSyntheticOblique(false);
331 #endif
332         m_derivedFontData->nonSyntheticItalic = create(nonSyntheticItalicFontPlatformData, isCustomFont());
333     }
334     ASSERT(m_derivedFontData->nonSyntheticItalic != this);
335     return m_derivedFontData->nonSyntheticItalic;
336 }
337
338 #ifndef NDEBUG
339 String Font::description() const
340 {
341     if (isSVGFont())
342         return "[SVG font]";
343     if (isCustomFont())
344         return "[custom font]";
345
346     return platformData().description();
347 }
348 #endif
349
350 const OpenTypeMathData* Font::mathData() const
351 {
352     if (m_isLoading)
353         return nullptr;
354     if (!m_mathData) {
355         m_mathData = OpenTypeMathData::create(m_platformData);
356         if (!m_mathData->hasMathData())
357             m_mathData = nullptr;
358     }
359     return m_mathData.get();
360 }
361
362 Font::DerivedFontData::~DerivedFontData()
363 {
364 }
365
366 PassRefPtr<Font> Font::createScaledFont(const FontDescription& fontDescription, float scaleFactor) const
367 {
368     if (isSVGFont())
369         return nullptr;
370
371     return platformCreateScaledFont(fontDescription, scaleFactor);
372 }
373
374 bool Font::applyTransforms(GlyphBufferGlyph* glyphs, GlyphBufferAdvance* advances, size_t glyphCount, TypesettingFeatures typesettingFeatures) const
375 {
376     // We need to handle transforms on SVG fonts internally, since they are rendered internally.
377     ASSERT(!isSVGFont());
378 #if PLATFORM(COCOA)
379     CTFontTransformOptions options = (typesettingFeatures & Kerning ? kCTFontTransformApplyPositioning : 0) | (typesettingFeatures & Ligatures ? kCTFontTransformApplyShaping : 0);
380     return CTFontTransformGlyphs(m_platformData.ctFont(), glyphs, reinterpret_cast<CGSize*>(advances), glyphCount, options);
381 #else
382     UNUSED_PARAM(glyphs);
383     UNUSED_PARAM(advances);
384     UNUSED_PARAM(glyphCount);
385     UNUSED_PARAM(typesettingFeatures);
386     return false;
387 #endif
388 }
389
390 class CharacterFallbackMapKey {
391 public:
392     CharacterFallbackMapKey()
393     {
394     }
395
396     CharacterFallbackMapKey(UChar32 character, bool isForPlatformFont)
397         : character(character)
398         , isForPlatformFont(isForPlatformFont)
399     {
400     }
401
402     CharacterFallbackMapKey(WTF::HashTableDeletedValueType)
403         : character(-1)
404     {
405     }
406
407     bool isHashTableDeletedValue() const { return character == -1; }
408
409     bool operator==(const CharacterFallbackMapKey& other) const
410     {
411         return character == other.character && isForPlatformFont == other.isForPlatformFont;
412     }
413
414     static const bool emptyValueIsZero = true;
415
416 private:
417     friend struct CharacterFallbackMapKeyHash;
418
419     UChar32 character { 0 };
420     bool isForPlatformFont { false };
421 };
422
423 struct CharacterFallbackMapKeyHash {
424     static unsigned hash(const CharacterFallbackMapKey& key)
425     {
426         return WTF::pairIntHash(key.character, key.isForPlatformFont);
427     }
428
429     static bool equal(const CharacterFallbackMapKey& a, const CharacterFallbackMapKey& b)
430     {
431         return a == b;
432     }
433
434     static const bool safeToCompareToEmptyOrDeleted = true;
435 };
436
437 // Fonts are not ref'd to avoid cycles.
438 // FIXME: Shouldn't these be WeakPtrs?
439 typedef HashMap<CharacterFallbackMapKey, Font*, CharacterFallbackMapKeyHash, WTF::SimpleClassHashTraits<CharacterFallbackMapKey>> CharacterFallbackMap;
440 typedef HashMap<const Font*, CharacterFallbackMap> SystemFallbackCache;
441
442 static SystemFallbackCache& systemFallbackCache()
443 {
444     static NeverDestroyed<SystemFallbackCache> map;
445     return map.get();
446 }
447
448 RefPtr<Font> Font::systemFallbackFontForCharacter(UChar32 character, const FontDescription& description, bool isForPlatformFont) const
449 {
450     auto fontAddResult = systemFallbackCache().add(this, CharacterFallbackMap());
451
452     if (!character) {
453         UChar codeUnit = 0;
454         return FontCache::singleton().systemFallbackForCharacters(description, this, isForPlatformFont, &codeUnit, 1);
455     }
456
457     auto key = CharacterFallbackMapKey(character, isForPlatformFont);
458     auto characterAddResult = fontAddResult.iterator->value.add(WTF::move(key), nullptr);
459
460     Font*& fallbackFont = characterAddResult.iterator->value;
461
462     if (!fallbackFont) {
463         UChar codeUnits[2];
464         unsigned codeUnitsLength;
465         if (U_IS_BMP(character)) {
466             codeUnits[0] = FontCascade::normalizeSpaces(character);
467             codeUnitsLength = 1;
468         } else {
469             codeUnits[0] = U16_LEAD(character);
470             codeUnits[1] = U16_TRAIL(character);
471             codeUnitsLength = 2;
472         }
473
474         fallbackFont = FontCache::singleton().systemFallbackForCharacters(description, this, isForPlatformFont, codeUnits, codeUnitsLength).get();
475         if (fallbackFont)
476             fallbackFont->m_isUsedInSystemFallbackCache = true;
477     }
478
479     return fallbackFont;
480 }
481
482 void Font::removeFromSystemFallbackCache()
483 {
484     systemFallbackCache().remove(this);
485
486     if (!m_isUsedInSystemFallbackCache)
487         return;
488
489     for (auto& characterMap : systemFallbackCache().values()) {
490         Vector<CharacterFallbackMapKey, 512> toRemove;
491         for (auto& entry : characterMap) {
492             if (entry.value == this)
493                 toRemove.append(entry.key);
494         }
495         for (auto& key : toRemove)
496             characterMap.remove(key);
497     }
498 }
499
500 } // namespace WebCore