dd90cba810d9e544cc3a5a2c7a8cccc1e1af57da
[WebKit-https.git] / Source / WebCore / platform / graphics / FontGlyphs.cpp
1 /*
2  * Copyright (C) 2006, 2013-2015 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  *
8  * 1.  Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer. 
10  * 2.  Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution. 
13  * 3.  Neither the name of Apple Inc. ("Apple") nor the names of
14  *     its contributors may be used to endorse or promote products derived
15  *     from this software without specific prior written permission. 
16  *
17  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #include "config.h"
30 #include "FontGlyphs.h"
31
32 #include "Font.h"
33 #include "FontCache.h"
34 #include "GlyphPage.h"
35 #include "SegmentedFontData.h"
36
37 namespace WebCore {
38
39
40 FontGlyphs::FontGlyphs(PassRefPtr<FontSelector> fontSelector)
41     : m_cachedPrimarySimpleFontData(0)
42     , m_fontSelector(fontSelector)
43     , m_fontSelectorVersion(m_fontSelector ? m_fontSelector->version() : 0)
44     , m_familyIndex(0)
45     , m_generation(fontCache().generation())
46     , m_pitch(UnknownPitch)
47     , m_loadingCustomFonts(false)
48     , m_isForPlatformFont(false)
49 {
50 }
51
52 FontGlyphs::FontGlyphs(const FontPlatformData& platformData)
53     : m_cachedPrimarySimpleFontData(0)
54     , m_fontSelector(0)
55     , m_fontSelectorVersion(0)
56     , m_familyIndex(cAllFamiliesScanned)
57     , m_generation(fontCache().generation())
58     , m_pitch(UnknownPitch)
59     , m_loadingCustomFonts(false)
60     , m_isForPlatformFont(true)
61 {
62     m_realizedFontData.append(fontCache().fontForPlatformData(platformData));
63 }
64
65 FontGlyphs::~FontGlyphs()
66 {
67 }
68
69 void FontGlyphs::determinePitch(const FontDescription& description)
70 {
71     const FontData& fontData = *realizeFontDataAt(description, 0);
72     if (is<SimpleFontData>(fontData))
73         m_pitch = downcast<SimpleFontData>(fontData).pitch();
74     else {
75         const SegmentedFontData& segmentedFontData = downcast<SegmentedFontData>(fontData);
76         unsigned numRanges = segmentedFontData.numRanges();
77         if (numRanges == 1)
78             m_pitch = segmentedFontData.rangeAt(0).fontData()->pitch();
79         else
80             m_pitch = VariablePitch;
81     }
82 }
83
84 const FontData* FontGlyphs::realizeFontDataAt(const FontDescription& description, unsigned realizedFontIndex)
85 {
86     if (realizedFontIndex < m_realizedFontData.size())
87         return m_realizedFontData[realizedFontIndex].get(); // This fallback font is already in our list.
88
89     // Make sure we're not passing in some crazy value here.
90     ASSERT(realizedFontIndex == m_realizedFontData.size());
91
92     if (m_familyIndex <= cAllFamiliesScanned) {
93         if (!m_fontSelector)
94             return 0;
95
96         size_t index = cAllFamiliesScanned - m_familyIndex;
97         if (index == m_fontSelector->fallbackFontDataCount())
98             return 0;
99
100         m_familyIndex--;
101         RefPtr<FontData> fallback = m_fontSelector->getFallbackFontData(description, index);
102         if (fallback)
103             m_realizedFontData.append(fallback);
104         return fallback.get();
105     }
106
107     // Ask the font cache for the font data.
108     // We are obtaining this font for the first time. We keep track of the families we've looked at before
109     // in |m_familyIndex|, so that we never scan the same spot in the list twice. fontForFamilyAtIndex will adjust our
110     // |m_familyIndex| as it scans for the right font to make.
111     ASSERT(fontCache().generation() == m_generation);
112     RefPtr<FontData> result = fontCache().fontForFamilyAtIndex(description, m_familyIndex, m_fontSelector.get());
113     if (result) {
114         m_realizedFontData.append(result);
115         if (result->isLoading())
116             m_loadingCustomFonts = true;
117     }
118     return result.get();
119 }
120
121 static inline bool isInRange(UChar32 character, UChar32 lowerBound, UChar32 upperBound)
122 {
123     return character >= lowerBound && character <= upperBound;
124 }
125
126 static bool shouldIgnoreRotation(UChar32 character)
127 {
128     if (character == 0x000A7 || character == 0x000A9 || character == 0x000AE)
129         return true;
130
131     if (character == 0x000B6 || character == 0x000BC || character == 0x000BD || character == 0x000BE)
132         return true;
133
134     if (isInRange(character, 0x002E5, 0x002EB))
135         return true;
136     
137     if (isInRange(character, 0x01100, 0x011FF) || isInRange(character, 0x01401, 0x0167F) || isInRange(character, 0x01800, 0x018FF))
138         return true;
139
140     if (character == 0x02016 || character == 0x02020 || character == 0x02021 || character == 0x2030 || character == 0x02031)
141         return true;
142
143     if (isInRange(character, 0x0203B, 0x0203D) || character == 0x02042 || character == 0x02044 || character == 0x02047
144         || character == 0x02048 || character == 0x02049 || character == 0x2051)
145         return true;
146
147     if (isInRange(character, 0x02065, 0x02069) || isInRange(character, 0x020DD, 0x020E0)
148         || isInRange(character, 0x020E2, 0x020E4) || isInRange(character, 0x02100, 0x02117)
149         || isInRange(character, 0x02119, 0x02131) || isInRange(character, 0x02133, 0x0213F))
150         return true;
151
152     if (isInRange(character, 0x02145, 0x0214A) || character == 0x0214C || character == 0x0214D
153         || isInRange(character, 0x0214F, 0x0218F))
154         return true;
155
156     if (isInRange(character, 0x02300, 0x02307) || isInRange(character, 0x0230C, 0x0231F)
157         || isInRange(character, 0x02322, 0x0232B) || isInRange(character, 0x0237D, 0x0239A)
158         || isInRange(character, 0x023B4, 0x023B6) || isInRange(character, 0x023BA, 0x023CF)
159         || isInRange(character, 0x023D1, 0x023DB) || isInRange(character, 0x023E2, 0x024FF))
160         return true;
161
162     if (isInRange(character, 0x025A0, 0x02619) || isInRange(character, 0x02620, 0x02767)
163         || isInRange(character, 0x02776, 0x02793) || isInRange(character, 0x02B12, 0x02B2F)
164         || isInRange(character, 0x02B4D, 0x02BFF) || isInRange(character, 0x02E80, 0x03007))
165         return true;
166
167     if (character == 0x03012 || character == 0x03013 || isInRange(character, 0x03020, 0x0302F)
168         || isInRange(character, 0x03031, 0x0309F) || isInRange(character, 0x030A1, 0x030FB)
169         || isInRange(character, 0x030FD, 0x0A4CF))
170         return true;
171
172     if (isInRange(character, 0x0A840, 0x0A87F) || isInRange(character, 0x0A960, 0x0A97F)
173         || isInRange(character, 0x0AC00, 0x0D7FF) || isInRange(character, 0x0E000, 0x0FAFF))
174         return true;
175
176     if (isInRange(character, 0x0FE10, 0x0FE1F) || isInRange(character, 0x0FE30, 0x0FE48)
177         || isInRange(character, 0x0FE50, 0x0FE57) || isInRange(character, 0x0FE5F, 0x0FE62)
178         || isInRange(character, 0x0FE67, 0x0FE6F))
179         return true;
180
181     if (isInRange(character, 0x0FF01, 0x0FF07) || isInRange(character, 0x0FF0A, 0x0FF0C)
182         || isInRange(character, 0x0FF0E, 0x0FF19) || character == 0x0FF1B || isInRange(character, 0x0FF1F, 0x0FF3A))
183         return true;
184
185     if (character == 0x0FF3C || character == 0x0FF3E)
186         return true;
187
188     if (isInRange(character, 0x0FF40, 0x0FF5A) || isInRange(character, 0x0FFE0, 0x0FFE2)
189         || isInRange(character, 0x0FFE4, 0x0FFE7) || isInRange(character, 0x0FFF0, 0x0FFF8)
190         || character == 0x0FFFD)
191         return true;
192
193     if (isInRange(character, 0x13000, 0x1342F) || isInRange(character, 0x1B000, 0x1B0FF)
194         || isInRange(character, 0x1D000, 0x1D1FF) || isInRange(character, 0x1D300, 0x1D37F)
195         || isInRange(character, 0x1F000, 0x1F64F) || isInRange(character, 0x1F680, 0x1F77F))
196         return true;
197     
198     if (isInRange(character, 0x20000, 0x2FFFD) || isInRange(character, 0x30000, 0x3FFFD))
199         return true;
200
201     return false;
202 }
203
204 #if PLATFORM(COCOA)
205 static GlyphData glyphDataForCJKCharacterWithoutSyntheticItalic(UChar32 character, GlyphData& data)
206 {
207     GlyphData nonItalicData = data.fontData->nonSyntheticItalicFontData()->glyphDataForCharacter(character);
208     if (nonItalicData.fontData)
209         return nonItalicData;
210     return data;
211 }
212 #endif
213     
214 static GlyphData glyphDataForNonCJKCharacterWithGlyphOrientation(UChar32 character, NonCJKGlyphOrientation orientation, const GlyphData& data)
215 {
216     if (orientation == NonCJKGlyphOrientationUpright || shouldIgnoreRotation(character)) {
217         GlyphData uprightData = data.fontData->uprightOrientationFontData()->glyphDataForCharacter(character);
218         // If the glyphs are the same, then we know we can just use the horizontal glyph rotated vertically to be upright.
219         if (data.glyph == uprightData.glyph)
220             return data;
221         // The glyphs are distinct, meaning that the font has a vertical-right glyph baked into it. We can't use that
222         // glyph, so we fall back to the upright data and use the horizontal glyph.
223         if (uprightData.fontData)
224             return uprightData;
225     } else if (orientation == NonCJKGlyphOrientationVerticalRight) {
226         GlyphData verticalRightData = data.fontData->verticalRightOrientationFontData()->glyphDataForCharacter(character);
227         // If the glyphs are distinct, we will make the assumption that the font has a vertical-right glyph baked
228         // into it.
229         if (data.glyph != verticalRightData.glyph)
230             return data;
231         // The glyphs are identical, meaning that we should just use the horizontal glyph.
232         if (verticalRightData.fontData)
233             return verticalRightData;
234     }
235     return data;
236 }
237
238 GlyphData FontGlyphs::glyphDataForSystemFallback(UChar32 c, const FontDescription& description, FontDataVariant variant)
239 {
240     // System fallback is character-dependent.
241     auto& primaryFontData = *realizeFontDataAt(description, 0);
242     auto* originalFontData = primaryFontData.simpleFontDataForCharacter(c);
243     if (!originalFontData)
244         originalFontData = &primaryFontData.simpleFontDataForFirstRange();
245
246     RefPtr<SimpleFontData> systemFallbackFontData = originalFontData->systemFallbackFontDataForCharacter(c, description, m_isForPlatformFont);
247     if (!systemFallbackFontData)
248         return GlyphData();
249
250     if (systemFallbackFontData->platformData().orientation() == Vertical && !systemFallbackFontData->hasVerticalGlyphs() && Font::isCJKIdeographOrSymbol(c))
251         variant = BrokenIdeographVariant;
252
253     GlyphData fallbackGlyphData;
254     if (variant == NormalVariant)
255         fallbackGlyphData = systemFallbackFontData->glyphDataForCharacter(c);
256     else
257         fallbackGlyphData = systemFallbackFontData->variantFontData(description, variant)->glyphDataForCharacter(c);
258
259     if (variant == NormalVariant && fallbackGlyphData.fontData) {
260         if (!Font::isCJKIdeographOrSymbol(c) && fallbackGlyphData.fontData->platformData().orientation() == Vertical && !fallbackGlyphData.fontData->isTextOrientationFallback())
261             fallbackGlyphData = glyphDataForNonCJKCharacterWithGlyphOrientation(c, description.nonCJKGlyphOrientation(), fallbackGlyphData);
262     }
263
264     // Keep the system fallback fonts we use alive.
265     if (fallbackGlyphData.glyph)
266         m_systemFallbackFontDataSet.add(systemFallbackFontData.release());
267
268     return fallbackGlyphData;
269 }
270
271 GlyphData FontGlyphs::glyphDataForVariant(UChar32 c, const FontDescription& description, FontDataVariant variant, unsigned fallbackLevel)
272 {
273     for (; fallbackLevel <= description.familyCount(); ++fallbackLevel) {
274         auto* fontData = realizeFontDataAt(description, fallbackLevel);
275         if (!fontData)
276             break;
277
278         auto* simpleFontData = fontData->simpleFontDataForCharacter(c);
279         GlyphData data = simpleFontData ? simpleFontData->glyphDataForCharacter(c) : GlyphData();
280         if (data.fontData) {
281             // The variantFontData function should not normally return 0.
282             // But if it does, we will just render the capital letter big.
283             RefPtr<SimpleFontData> variantFontData = data.fontData->variantFontData(description, variant);
284             if (!variantFontData)
285                 return data;
286
287             return variantFontData->glyphDataForCharacter(c);
288         }
289     }
290
291     return glyphDataForSystemFallback(c, description, variant);
292 }
293
294 GlyphData FontGlyphs::glyphDataForNormalVariant(UChar32 c, const FontDescription& description)
295 {
296     const unsigned pageNumber = c / GlyphPage::size;
297
298     for (unsigned fallbackLevel = 0; fallbackLevel <= description.familyCount(); ++fallbackLevel) {
299         auto* fontData = realizeFontDataAt(description, fallbackLevel);
300         if (!fontData)
301             break;
302         auto* simpleFontData = fontData->simpleFontDataForCharacter(c);
303         auto* page = simpleFontData ? simpleFontData->glyphPage(pageNumber) : nullptr;
304         if (!page)
305             continue;
306         GlyphData data = page->glyphDataForCharacter(c);
307         if (data.fontData) {
308             if (data.fontData->platformData().orientation() == Vertical && !data.fontData->isTextOrientationFallback()) {
309                 if (!Font::isCJKIdeographOrSymbol(c))
310                     return glyphDataForNonCJKCharacterWithGlyphOrientation(c, description.nonCJKGlyphOrientation(), data);
311
312                 if (!data.fontData->hasVerticalGlyphs()) {
313                     // Use the broken ideograph font data. The broken ideograph font will use the horizontal width of glyphs
314                     // to make sure you get a square (even for broken glyphs like symbols used for punctuation).
315                     return glyphDataForVariant(c, description, BrokenIdeographVariant, fallbackLevel);
316                 }
317 #if PLATFORM(COCOA)
318                 if (data.fontData->platformData().syntheticOblique())
319                     return glyphDataForCJKCharacterWithoutSyntheticItalic(c, data);
320 #endif
321             }
322
323             return data;
324         }
325     }
326
327     return glyphDataForSystemFallback(c, description, NormalVariant);
328 }
329
330 static RefPtr<GlyphPage> glyphPageFromFontData(unsigned pageNumber, const FontData& fontData)
331 {
332     const SimpleFontData* simpleFontData = nullptr;
333     if (fontData.isSegmented()) {
334         UChar32 pageRangeFrom = pageNumber * GlyphPage::size;
335         UChar32 pageRangeTo = pageRangeFrom + GlyphPage::size - 1;
336         auto& segmentedFontData = downcast<SegmentedFontData>(fontData);
337         for (unsigned i = 0; i < segmentedFontData.numRanges(); ++i) {
338             auto& range = segmentedFontData.rangeAt(i);
339             if (range.to()) {
340                 if (range.from() <= pageRangeFrom && pageRangeTo <= range.to())
341                     simpleFontData = range.fontData().get();
342                 break;
343             }
344         }
345         if (!simpleFontData)
346             return nullptr;
347     } else
348         simpleFontData = &downcast<SimpleFontData>(fontData);
349
350     if (simpleFontData->platformData().orientation() == Vertical)
351         return nullptr;
352
353     return const_cast<GlyphPage*>(simpleFontData->glyphPage(pageNumber));
354 }
355
356 GlyphData FontGlyphs::glyphDataForCharacter(UChar32 c, const FontDescription& description, FontDataVariant variant)
357 {
358     ASSERT(isMainThread());
359     ASSERT(variant != AutoVariant);
360
361     if (variant != NormalVariant)
362         return glyphDataForVariant(c, description, variant, 0);
363
364     const unsigned pageNumber = c / GlyphPage::size;
365
366     RefPtr<GlyphPage>& cachedPage = pageNumber ? m_cachedPages.add(pageNumber, nullptr).iterator->value : m_cachedPageZero;
367     if (!cachedPage)
368         cachedPage = glyphPageFromFontData(pageNumber, *realizeFontDataAt(description, 0));
369
370     GlyphData glyphData = cachedPage ? cachedPage->glyphDataForCharacter(c) : GlyphData();
371     if (!glyphData.glyph) {
372         if (!cachedPage)
373             cachedPage = GlyphPage::createForMixedFontData();
374         else if (cachedPage->isImmutable())
375             cachedPage = GlyphPage::createCopyForMixedFontData(*cachedPage);
376
377         glyphData = glyphDataForNormalVariant(c, description);
378         cachedPage->setGlyphDataForCharacter(c, glyphData.glyph, glyphData.fontData);
379     }
380     return glyphData;
381 }
382
383 }