Block popups from content extensions.
[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
42 #if ENABLE(OPENTYPE_VERTICAL)
43 #include "OpenTypeVerticalData.h"
44 #endif
45
46 namespace WebCore {
47
48 unsigned GlyphPage::s_count = 0;
49
50 const float smallCapsFontSizeMultiplier = 0.7f;
51 const float emphasisMarkFontSizeMultiplier = 0.5f;
52
53 Font::Font(const FontPlatformData& platformData, bool isCustomFont, bool isLoading, bool isTextOrientationFallback)
54     : m_maxCharWidth(-1)
55     , m_avgCharWidth(-1)
56     , m_platformData(platformData)
57     , m_treatAsFixedPitch(false)
58     , m_isCustomFont(isCustomFont)
59     , m_isLoading(isLoading)
60     , m_isTextOrientationFallback(isTextOrientationFallback)
61     , m_isBrokenIdeographFallback(false)
62     , m_mathData(nullptr)
63 #if ENABLE(OPENTYPE_VERTICAL)
64     , m_verticalData(0)
65 #endif
66     , m_hasVerticalGlyphs(false)
67 {
68     platformInit();
69     platformGlyphInit();
70     platformCharWidthInit();
71 #if ENABLE(OPENTYPE_VERTICAL)
72     if (platformData.orientation() == Vertical && !isTextOrientationFallback) {
73         m_verticalData = platformData.verticalData();
74         m_hasVerticalGlyphs = m_verticalData.get() && m_verticalData->hasVerticalMetrics();
75     }
76 #endif
77 }
78
79 Font::Font(std::unique_ptr<SVGData> svgData, float fontSize, bool syntheticBold, bool syntheticItalic)
80     : m_platformData(FontPlatformData(fontSize, syntheticBold, syntheticItalic))
81     , m_svgData(WTF::move(svgData))
82     , m_treatAsFixedPitch(false)
83     , m_isCustomFont(true)
84     , m_isLoading(false)
85     , m_isTextOrientationFallback(false)
86     , m_isBrokenIdeographFallback(false)
87     , m_mathData(nullptr)
88 #if ENABLE(OPENTYPE_VERTICAL)
89     , m_verticalData(0)
90 #endif
91     , m_hasVerticalGlyphs(false)
92 #if PLATFORM(IOS)
93     , m_shouldNotBeUsedForArabic(false)
94 #endif
95 {
96     m_svgData->initializeFont(this, fontSize);
97 }
98
99 // Estimates of avgCharWidth and maxCharWidth for platforms that don't support accessing these values from the font.
100 void Font::initCharWidths()
101 {
102     auto* glyphPageZero = glyphPage(0);
103
104     // Treat the width of a '0' as the avgCharWidth.
105     if (m_avgCharWidth <= 0.f && glyphPageZero) {
106         static const UChar32 digitZeroChar = '0';
107         Glyph digitZeroGlyph = glyphPageZero->glyphDataForCharacter(digitZeroChar).glyph;
108         if (digitZeroGlyph)
109             m_avgCharWidth = widthForGlyph(digitZeroGlyph);
110     }
111
112     // If we can't retrieve the width of a '0', fall back to the x height.
113     if (m_avgCharWidth <= 0.f)
114         m_avgCharWidth = m_fontMetrics.xHeight();
115
116     if (m_maxCharWidth <= 0.f)
117         m_maxCharWidth = std::max(m_avgCharWidth, m_fontMetrics.floatAscent());
118 }
119
120 void Font::platformGlyphInit()
121 {
122     auto* glyphPageZero = glyphPage(0);
123     if (!glyphPageZero) {
124         m_spaceGlyph = 0;
125         m_spaceWidth = 0;
126         m_zeroGlyph = 0;
127         m_adjustedSpaceWidth = 0;
128         determinePitch();
129         m_zeroWidthSpaceGlyph = 0;
130         return;
131     }
132
133     // Ask for the glyph for 0 to avoid paging in ZERO WIDTH SPACE. Control characters, including 0,
134     // are mapped to the ZERO WIDTH SPACE glyph.
135     m_zeroWidthSpaceGlyph = glyphPageZero->glyphDataForCharacter(0).glyph;
136
137     // Nasty hack to determine if we should round or ceil space widths.
138     // If the font is monospace or fake monospace we ceil to ensure that 
139     // every character and the space are the same width. Otherwise we round.
140     m_spaceGlyph = glyphPageZero->glyphDataForCharacter(' ').glyph;
141     float width = widthForGlyph(m_spaceGlyph);
142     m_spaceWidth = width;
143     m_zeroGlyph = glyphPageZero->glyphDataForCharacter('0').glyph;
144     m_fontMetrics.setZeroWidth(widthForGlyph(m_zeroGlyph));
145     determinePitch();
146     m_adjustedSpaceWidth = m_treatAsFixedPitch ? ceilf(width) : roundf(width);
147
148     // Force the glyph for ZERO WIDTH SPACE to have zero width, unless it is shared with SPACE.
149     // Helvetica is an example of a non-zero width ZERO WIDTH SPACE glyph.
150     // See <http://bugs.webkit.org/show_bug.cgi?id=13178> and Font::isZeroWidthSpaceGlyph()
151     if (m_zeroWidthSpaceGlyph == m_spaceGlyph)
152         m_zeroWidthSpaceGlyph = 0;
153 }
154
155 Font::~Font()
156 {
157     removeFromSystemFallbackCache();
158 }
159
160 static bool fillGlyphPage(GlyphPage& pageToFill, unsigned offset, unsigned length, UChar* buffer, unsigned bufferLength, const Font* font)
161 {
162 #if ENABLE(SVG_FONTS)
163     if (auto* svgData = font->svgData())
164         return svgData->fillSVGGlyphPage(&pageToFill, offset, length, buffer, bufferLength, font);
165 #endif
166     bool hasGlyphs = pageToFill.fill(offset, length, buffer, bufferLength, font);
167 #if ENABLE(OPENTYPE_VERTICAL)
168     if (hasGlyphs && font->verticalData())
169         font->verticalData()->substituteWithVerticalGlyphs(font, &pageToFill, offset, length);
170 #endif
171     return hasGlyphs;
172 }
173
174 static RefPtr<GlyphPage> createAndFillGlyphPage(unsigned pageNumber, const Font* font)
175 {
176 #if PLATFORM(IOS)
177     // FIXME: Times New Roman contains Arabic glyphs, but Core Text doesn't know how to shape them. See <rdar://problem/9823975>.
178     // Once we have the fix for <rdar://problem/9823975> then remove this code together with Font::shouldNotBeUsedForArabic()
179     // in <rdar://problem/12096835>.
180     if (pageNumber == 6 && font->shouldNotBeUsedForArabic())
181         return nullptr;
182 #endif
183
184     unsigned start = pageNumber * GlyphPage::size;
185     UChar buffer[GlyphPage::size * 2 + 2];
186     unsigned bufferLength;
187     // Fill in a buffer with the entire "page" of characters that we want to look up glyphs for.
188     if (U_IS_BMP(start)) {
189         bufferLength = GlyphPage::size;
190         for (unsigned i = 0; i < GlyphPage::size; i++)
191             buffer[i] = start + i;
192
193         if (!start) {
194             // Control characters must not render at all.
195             for (unsigned i = 0; i < 0x20; ++i)
196                 buffer[i] = zeroWidthSpace;
197             for (unsigned i = 0x7F; i < 0xA0; i++)
198                 buffer[i] = zeroWidthSpace;
199             buffer[softHyphen] = zeroWidthSpace;
200
201             // \n, \t, and nonbreaking space must render as a space.
202             buffer[(int)'\n'] = ' ';
203             buffer[(int)'\t'] = ' ';
204             buffer[noBreakSpace] = ' ';
205         } else if (start == (leftToRightMark & ~(GlyphPage::size - 1))) {
206             // LRM, RLM, LRE, RLE, ZWNJ, ZWJ, and PDF must not render at all.
207             buffer[leftToRightMark - start] = zeroWidthSpace;
208             buffer[rightToLeftMark - start] = zeroWidthSpace;
209             buffer[leftToRightEmbed - start] = zeroWidthSpace;
210             buffer[rightToLeftEmbed - start] = zeroWidthSpace;
211             buffer[leftToRightOverride - start] = zeroWidthSpace;
212             buffer[rightToLeftOverride - start] = zeroWidthSpace;
213             buffer[zeroWidthNonJoiner - start] = zeroWidthSpace;
214             buffer[zeroWidthJoiner - start] = zeroWidthSpace;
215             buffer[popDirectionalFormatting - start] = zeroWidthSpace;
216         } else if (start == (objectReplacementCharacter & ~(GlyphPage::size - 1))) {
217             // Object replacement character must not render at all.
218             buffer[objectReplacementCharacter - start] = zeroWidthSpace;
219         } else if (start == (zeroWidthNoBreakSpace & ~(GlyphPage::size - 1))) {
220             // ZWNBS/BOM must not render at all.
221             buffer[zeroWidthNoBreakSpace - start] = zeroWidthSpace;
222         }
223     } else {
224         bufferLength = GlyphPage::size * 2;
225         for (unsigned i = 0; i < GlyphPage::size; i++) {
226             int c = i + start;
227             buffer[i * 2] = U16_LEAD(c);
228             buffer[i * 2 + 1] = U16_TRAIL(c);
229         }
230     }
231
232     // Now that we have a buffer full of characters, we want to get back an array
233     // of glyph indices. This part involves calling into the platform-specific
234     // routine of our glyph map for actually filling in the page with the glyphs.
235     // Success is not guaranteed. For example, Times fails to fill page 260, giving glyph data
236     // for only 128 out of 256 characters.
237     RefPtr<GlyphPage> glyphPage;
238     if (GlyphPage::mayUseMixedFontsWhenFilling(buffer, bufferLength, font))
239         glyphPage = GlyphPage::createForMixedFonts();
240     else
241         glyphPage = GlyphPage::createForSingleFont(font);
242
243     bool haveGlyphs = fillGlyphPage(*glyphPage, 0, GlyphPage::size, buffer, bufferLength, font);
244     if (!haveGlyphs)
245         return nullptr;
246
247     glyphPage->setImmutable();
248     return glyphPage;
249 }
250
251 const GlyphPage* Font::glyphPage(unsigned pageNumber) const
252 {
253     if (!pageNumber) {
254         if (!m_glyphPageZero)
255             m_glyphPageZero = createAndFillGlyphPage(0, this);
256         return m_glyphPageZero.get();
257     }
258     auto addResult = m_glyphPages.add(pageNumber, nullptr);
259     if (addResult.isNewEntry)
260         addResult.iterator->value = createAndFillGlyphPage(pageNumber, this);
261
262     return addResult.iterator->value.get();
263 }
264
265 Glyph Font::glyphForCharacter(UChar32 character) const
266 {
267     auto* page = glyphPage(character / GlyphPage::size);
268     if (!page)
269         return 0;
270     return page->glyphAt(character % GlyphPage::size);
271 }
272
273 GlyphData Font::glyphDataForCharacter(UChar32 character) const
274 {
275     auto* page = glyphPage(character / GlyphPage::size);
276     if (!page)
277         return GlyphData();
278     return page->glyphDataForCharacter(character);
279 }
280
281 PassRefPtr<Font> Font::verticalRightOrientationFont() const
282 {
283     if (!m_derivedFontData)
284         m_derivedFontData = std::make_unique<DerivedFontData>(isCustomFont());
285     if (!m_derivedFontData->verticalRightOrientation) {
286         FontPlatformData verticalRightPlatformData(m_platformData);
287         verticalRightPlatformData.setOrientation(Horizontal);
288         m_derivedFontData->verticalRightOrientation = create(verticalRightPlatformData, isCustomFont(), false, true);
289     }
290     ASSERT(m_derivedFontData->verticalRightOrientation != this);
291     return m_derivedFontData->verticalRightOrientation;
292 }
293
294 PassRefPtr<Font> Font::uprightOrientationFont() const
295 {
296     if (!m_derivedFontData)
297         m_derivedFontData = std::make_unique<DerivedFontData>(isCustomFont());
298     if (!m_derivedFontData->uprightOrientation)
299         m_derivedFontData->uprightOrientation = create(m_platformData, isCustomFont(), false, true);
300     ASSERT(m_derivedFontData->uprightOrientation != this);
301     return m_derivedFontData->uprightOrientation;
302 }
303
304 PassRefPtr<Font> Font::smallCapsFont(const FontDescription& fontDescription) const
305 {
306     if (!m_derivedFontData)
307         m_derivedFontData = std::make_unique<DerivedFontData>(isCustomFont());
308     if (!m_derivedFontData->smallCaps)
309         m_derivedFontData->smallCaps = createScaledFont(fontDescription, smallCapsFontSizeMultiplier);
310     ASSERT(m_derivedFontData->smallCaps != this);
311     return m_derivedFontData->smallCaps;
312 }
313
314 PassRefPtr<Font> Font::emphasisMarkFont(const FontDescription& fontDescription) const
315 {
316     if (!m_derivedFontData)
317         m_derivedFontData = std::make_unique<DerivedFontData>(isCustomFont());
318     if (!m_derivedFontData->emphasisMark)
319         m_derivedFontData->emphasisMark = createScaledFont(fontDescription, emphasisMarkFontSizeMultiplier);
320     ASSERT(m_derivedFontData->emphasisMark != this);
321     return m_derivedFontData->emphasisMark;
322 }
323
324 PassRefPtr<Font> Font::brokenIdeographFont() const
325 {
326     if (!m_derivedFontData)
327         m_derivedFontData = std::make_unique<DerivedFontData>(isCustomFont());
328     if (!m_derivedFontData->brokenIdeograph) {
329         m_derivedFontData->brokenIdeograph = create(m_platformData, isCustomFont(), false);
330         m_derivedFontData->brokenIdeograph->m_isBrokenIdeographFallback = true;
331     }
332     ASSERT(m_derivedFontData->brokenIdeograph != this);
333     return m_derivedFontData->brokenIdeograph;
334 }
335
336 PassRefPtr<Font> Font::nonSyntheticItalicFont() const
337 {
338     if (!m_derivedFontData)
339         m_derivedFontData = std::make_unique<DerivedFontData>(isCustomFont());
340     if (!m_derivedFontData->nonSyntheticItalic) {
341         FontPlatformData nonSyntheticItalicFontPlatformData(m_platformData);
342 #if PLATFORM(COCOA)
343         nonSyntheticItalicFontPlatformData.m_syntheticOblique = false;
344 #endif
345         m_derivedFontData->nonSyntheticItalic = create(nonSyntheticItalicFontPlatformData, isCustomFont());
346     }
347     ASSERT(m_derivedFontData->nonSyntheticItalic != this);
348     return m_derivedFontData->nonSyntheticItalic;
349 }
350
351 #ifndef NDEBUG
352 String Font::description() const
353 {
354     if (isSVGFont())
355         return "[SVG font]";
356     if (isCustomFont())
357         return "[custom font]";
358
359     return platformData().description();
360 }
361 #endif
362
363 const OpenTypeMathData* Font::mathData() const
364 {
365     if (m_isLoading)
366         return nullptr;
367     if (!m_mathData) {
368         m_mathData = OpenTypeMathData::create(m_platformData);
369         if (!m_mathData->hasMathData())
370             m_mathData.clear();
371     }
372     return m_mathData.get();
373 }
374
375 Font::DerivedFontData::~DerivedFontData()
376 {
377 }
378
379 PassRefPtr<Font> Font::createScaledFont(const FontDescription& fontDescription, float scaleFactor) const
380 {
381     if (isSVGFont())
382         return nullptr;
383
384     return platformCreateScaledFont(fontDescription, scaleFactor);
385 }
386
387 bool Font::applyTransforms(GlyphBufferGlyph* glyphs, GlyphBufferAdvance* advances, size_t glyphCount, TypesettingFeatures typesettingFeatures) const
388 {
389     // We need to handle transforms on SVG fonts internally, since they are rendered internally.
390     ASSERT(!isSVGFont());
391 #if PLATFORM(COCOA)
392     CTFontTransformOptions options = (typesettingFeatures & Kerning ? kCTFontTransformApplyPositioning : 0) | (typesettingFeatures & Ligatures ? kCTFontTransformApplyShaping : 0);
393     return CTFontTransformGlyphs(m_platformData.ctFont(), glyphs, reinterpret_cast<CGSize*>(advances), glyphCount, options);
394 #else
395     UNUSED_PARAM(glyphs);
396     UNUSED_PARAM(advances);
397     UNUSED_PARAM(glyphCount);
398     UNUSED_PARAM(typesettingFeatures);
399     return false;
400 #endif
401 }
402
403 // Fonts are not ref'd to avoid cycles.
404 typedef std::pair<UChar32, bool /* isForPlatformFont */> CharacterFallbackMapKey;
405 typedef HashMap<CharacterFallbackMapKey, Font*> CharacterFallbackMap;
406 typedef HashMap<const Font*, CharacterFallbackMap> SystemFallbackCache;
407
408 static SystemFallbackCache& systemFallbackCache()
409 {
410     static NeverDestroyed<SystemFallbackCache> map;
411     return map.get();
412 }
413
414 RefPtr<Font> Font::systemFallbackFontForCharacter(UChar32 character, const FontDescription& description, bool isForPlatformFont) const
415 {
416     auto fontAddResult = systemFallbackCache().add(this, CharacterFallbackMap());
417
418     if (!character) {
419         UChar codeUnit = 0;
420         return FontCache::singleton().systemFallbackForCharacters(description, this, isForPlatformFont, &codeUnit, 1);
421     }
422
423     auto key = std::make_pair(character, isForPlatformFont);
424     auto characterAddResult = fontAddResult.iterator->value.add(key, nullptr);
425
426     Font*& fallbackFont = characterAddResult.iterator->value;
427
428     if (!fallbackFont) {
429         UChar codeUnits[2];
430         unsigned codeUnitsLength;
431         if (U_IS_BMP(character)) {
432             codeUnits[0] = FontCascade::normalizeSpaces(character);
433             codeUnitsLength = 1;
434         } else {
435             codeUnits[0] = U16_LEAD(character);
436             codeUnits[1] = U16_TRAIL(character);
437             codeUnitsLength = 2;
438         }
439
440         fallbackFont = FontCache::singleton().systemFallbackForCharacters(description, this, isForPlatformFont, codeUnits, codeUnitsLength).get();
441         if (fallbackFont)
442             fallbackFont->m_isUsedInSystemFallbackCache = true;
443     }
444
445     return fallbackFont;
446 }
447
448 void Font::removeFromSystemFallbackCache()
449 {
450     systemFallbackCache().remove(this);
451
452     if (!m_isUsedInSystemFallbackCache)
453         return;
454
455     for (auto& characterMap : systemFallbackCache().values()) {
456         Vector<CharacterFallbackMapKey, 512> toRemove;
457         for (auto& entry : characterMap) {
458             if (entry.value == this)
459                 toRemove.append(entry.key);
460         }
461         for (auto& key : toRemove)
462             characterMap.remove(key);
463     }
464 }
465
466 } // namespace WebCore