988486969b5c752ed5fc2416fe8f4b44595f97c0
[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     RefPtr<FontData> fontData = fontCache().getCachedFontData(&platformData);
63     m_realizedFontData.append(fontData.release());
64 }
65
66 void FontGlyphs::releaseFontData()
67 {
68     unsigned numFonts = m_realizedFontData.size();
69     for (unsigned i = 0; i < numFonts; ++i) {
70         if (m_realizedFontData[i]->isCustomFont())
71             continue;
72         fontCache().releaseFontData(downcast<SimpleFontData>(m_realizedFontData[i].get()));
73     }
74 }
75
76 void FontGlyphs::determinePitch(const FontDescription& description)
77 {
78     const FontData* fontData = primaryFontData(description);
79     if (is<SimpleFontData>(*fontData))
80         m_pitch = downcast<SimpleFontData>(*fontData).pitch();
81     else {
82         const SegmentedFontData& segmentedFontData = downcast<SegmentedFontData>(*fontData);
83         unsigned numRanges = segmentedFontData.numRanges();
84         if (numRanges == 1)
85             m_pitch = segmentedFontData.rangeAt(0).fontData()->pitch();
86         else
87             m_pitch = VariablePitch;
88     }
89 }
90
91 const FontData* FontGlyphs::realizeFontDataAt(const FontDescription& description, unsigned realizedFontIndex)
92 {
93     if (realizedFontIndex < m_realizedFontData.size())
94         return m_realizedFontData[realizedFontIndex].get(); // This fallback font is already in our list.
95
96     // Make sure we're not passing in some crazy value here.
97     ASSERT(realizedFontIndex == m_realizedFontData.size());
98
99     if (m_familyIndex <= cAllFamiliesScanned) {
100         if (!m_fontSelector)
101             return 0;
102
103         size_t index = cAllFamiliesScanned - m_familyIndex;
104         if (index == m_fontSelector->fallbackFontDataCount())
105             return 0;
106
107         m_familyIndex--;
108         RefPtr<FontData> fallback = m_fontSelector->getFallbackFontData(description, index);
109         if (fallback)
110             m_realizedFontData.append(fallback);
111         return fallback.get();
112     }
113
114     // Ask the font cache for the font data.
115     // We are obtaining this font for the first time. We keep track of the families we've looked at before
116     // in |m_familyIndex|, so that we never scan the same spot in the list twice. getFontData will adjust our
117     // |m_familyIndex| as it scans for the right font to make.
118     ASSERT(fontCache().generation() == m_generation);
119     RefPtr<FontData> result = fontCache().getFontData(description, m_familyIndex, m_fontSelector.get());
120     if (result) {
121         m_realizedFontData.append(result);
122         if (result->isLoading())
123             m_loadingCustomFonts = true;
124     }
125     return result.get();
126 }
127
128 static inline bool isInRange(UChar32 character, UChar32 lowerBound, UChar32 upperBound)
129 {
130     return character >= lowerBound && character <= upperBound;
131 }
132
133 static bool shouldIgnoreRotation(UChar32 character)
134 {
135     if (character == 0x000A7 || character == 0x000A9 || character == 0x000AE)
136         return true;
137
138     if (character == 0x000B6 || character == 0x000BC || character == 0x000BD || character == 0x000BE)
139         return true;
140
141     if (isInRange(character, 0x002E5, 0x002EB))
142         return true;
143     
144     if (isInRange(character, 0x01100, 0x011FF) || isInRange(character, 0x01401, 0x0167F) || isInRange(character, 0x01800, 0x018FF))
145         return true;
146
147     if (character == 0x02016 || character == 0x02020 || character == 0x02021 || character == 0x2030 || character == 0x02031)
148         return true;
149
150     if (isInRange(character, 0x0203B, 0x0203D) || character == 0x02042 || character == 0x02044 || character == 0x02047
151         || character == 0x02048 || character == 0x02049 || character == 0x2051)
152         return true;
153
154     if (isInRange(character, 0x02065, 0x02069) || isInRange(character, 0x020DD, 0x020E0)
155         || isInRange(character, 0x020E2, 0x020E4) || isInRange(character, 0x02100, 0x02117)
156         || isInRange(character, 0x02119, 0x02131) || isInRange(character, 0x02133, 0x0213F))
157         return true;
158
159     if (isInRange(character, 0x02145, 0x0214A) || character == 0x0214C || character == 0x0214D
160         || isInRange(character, 0x0214F, 0x0218F))
161         return true;
162
163     if (isInRange(character, 0x02300, 0x02307) || isInRange(character, 0x0230C, 0x0231F)
164         || isInRange(character, 0x02322, 0x0232B) || isInRange(character, 0x0237D, 0x0239A)
165         || isInRange(character, 0x023B4, 0x023B6) || isInRange(character, 0x023BA, 0x023CF)
166         || isInRange(character, 0x023D1, 0x023DB) || isInRange(character, 0x023E2, 0x024FF))
167         return true;
168
169     if (isInRange(character, 0x025A0, 0x02619) || isInRange(character, 0x02620, 0x02767)
170         || isInRange(character, 0x02776, 0x02793) || isInRange(character, 0x02B12, 0x02B2F)
171         || isInRange(character, 0x02B4D, 0x02BFF) || isInRange(character, 0x02E80, 0x03007))
172         return true;
173
174     if (character == 0x03012 || character == 0x03013 || isInRange(character, 0x03020, 0x0302F)
175         || isInRange(character, 0x03031, 0x0309F) || isInRange(character, 0x030A1, 0x030FB)
176         || isInRange(character, 0x030FD, 0x0A4CF))
177         return true;
178
179     if (isInRange(character, 0x0A840, 0x0A87F) || isInRange(character, 0x0A960, 0x0A97F)
180         || isInRange(character, 0x0AC00, 0x0D7FF) || isInRange(character, 0x0E000, 0x0FAFF))
181         return true;
182
183     if (isInRange(character, 0x0FE10, 0x0FE1F) || isInRange(character, 0x0FE30, 0x0FE48)
184         || isInRange(character, 0x0FE50, 0x0FE57) || isInRange(character, 0x0FE5F, 0x0FE62)
185         || isInRange(character, 0x0FE67, 0x0FE6F))
186         return true;
187
188     if (isInRange(character, 0x0FF01, 0x0FF07) || isInRange(character, 0x0FF0A, 0x0FF0C)
189         || isInRange(character, 0x0FF0E, 0x0FF19) || character == 0x0FF1B || isInRange(character, 0x0FF1F, 0x0FF3A))
190         return true;
191
192     if (character == 0x0FF3C || character == 0x0FF3E)
193         return true;
194
195     if (isInRange(character, 0x0FF40, 0x0FF5A) || isInRange(character, 0x0FFE0, 0x0FFE2)
196         || isInRange(character, 0x0FFE4, 0x0FFE7) || isInRange(character, 0x0FFF0, 0x0FFF8)
197         || character == 0x0FFFD)
198         return true;
199
200     if (isInRange(character, 0x13000, 0x1342F) || isInRange(character, 0x1B000, 0x1B0FF)
201         || isInRange(character, 0x1D000, 0x1D1FF) || isInRange(character, 0x1D300, 0x1D37F)
202         || isInRange(character, 0x1F000, 0x1F64F) || isInRange(character, 0x1F680, 0x1F77F))
203         return true;
204     
205     if (isInRange(character, 0x20000, 0x2FFFD) || isInRange(character, 0x30000, 0x3FFFD))
206         return true;
207
208     return false;
209 }
210
211 #if PLATFORM(COCOA)
212 static GlyphData glyphDataForCJKCharacterWithoutSyntheticItalic(UChar32 character, GlyphData& data)
213 {
214     GlyphData nonItalicData = data.fontData->nonSyntheticItalicFontData()->glyphDataForCharacter(character);
215     if (nonItalicData.fontData)
216         return nonItalicData;
217     return data;
218 }
219 #endif
220     
221 static GlyphData glyphDataForNonCJKCharacterWithGlyphOrientation(UChar32 character, NonCJKGlyphOrientation orientation, const GlyphData& data)
222 {
223     if (orientation == NonCJKGlyphOrientationUpright || shouldIgnoreRotation(character)) {
224         GlyphData uprightData = data.fontData->uprightOrientationFontData()->glyphDataForCharacter(character);
225         // If the glyphs are the same, then we know we can just use the horizontal glyph rotated vertically to be upright.
226         if (data.glyph == uprightData.glyph)
227             return data;
228         // The glyphs are distinct, meaning that the font has a vertical-right glyph baked into it. We can't use that
229         // glyph, so we fall back to the upright data and use the horizontal glyph.
230         if (uprightData.fontData)
231             return uprightData;
232     } else if (orientation == NonCJKGlyphOrientationVerticalRight) {
233         GlyphData verticalRightData = data.fontData->verticalRightOrientationFontData()->glyphDataForCharacter(character);
234         // If the glyphs are distinct, we will make the assumption that the font has a vertical-right glyph baked
235         // into it.
236         if (data.glyph != verticalRightData.glyph)
237             return data;
238         // The glyphs are identical, meaning that we should just use the horizontal glyph.
239         if (verticalRightData.fontData)
240             return verticalRightData;
241     }
242     return data;
243 }
244
245 GlyphData FontGlyphs::glyphDataForSystemFallback(UChar32 c, const FontDescription& description, FontDataVariant variant)
246 {
247     // System fallback is character-dependent.
248     auto* originalFontData = primaryFontData(description)->simpleFontDataForCharacter(c);
249     if (!originalFontData)
250         originalFontData = &primaryFontData(description)->simpleFontDataForFirstRange();
251
252     RefPtr<SimpleFontData> systemFallbackFontData = originalFontData->systemFallbackFontDataForCharacter(c, description, m_isForPlatformFont);
253     if (!systemFallbackFontData)
254         return GlyphData();
255
256     if (systemFallbackFontData->platformData().orientation() == Vertical && !systemFallbackFontData->hasVerticalGlyphs() && Font::isCJKIdeographOrSymbol(c))
257         variant = BrokenIdeographVariant;
258
259     GlyphData fallbackGlyphData;
260     if (variant == NormalVariant)
261         fallbackGlyphData = systemFallbackFontData->glyphDataForCharacter(c);
262     else
263         fallbackGlyphData = systemFallbackFontData->variantFontData(description, variant)->glyphDataForCharacter(c);
264
265     if (variant == NormalVariant && fallbackGlyphData.fontData) {
266         if (!Font::isCJKIdeographOrSymbol(c) && fallbackGlyphData.fontData->platformData().orientation() == Vertical && !fallbackGlyphData.fontData->isTextOrientationFallback())
267             fallbackGlyphData = glyphDataForNonCJKCharacterWithGlyphOrientation(c, description.nonCJKGlyphOrientation(), fallbackGlyphData);
268     }
269
270     // Keep the system fallback fonts we use alive.
271     if (fallbackGlyphData.glyph)
272         m_systemFallbackFontDataSet.add(systemFallbackFontData.release());
273
274     return fallbackGlyphData;
275 }
276
277 GlyphData FontGlyphs::glyphDataForVariant(UChar32 c, const FontDescription& description, FontDataVariant variant, unsigned fallbackLevel)
278 {
279     for (; fallbackLevel <= description.familyCount(); ++fallbackLevel) {
280         auto* fontData = realizeFontDataAt(description, fallbackLevel);
281         if (!fontData)
282             break;
283
284         auto* simpleFontData = fontData->simpleFontDataForCharacter(c);
285         GlyphData data = simpleFontData ? simpleFontData->glyphDataForCharacter(c) : GlyphData();
286         if (data.fontData) {
287             // The variantFontData function should not normally return 0.
288             // But if it does, we will just render the capital letter big.
289             RefPtr<SimpleFontData> variantFontData = data.fontData->variantFontData(description, variant);
290             if (!variantFontData)
291                 return data;
292
293             return variantFontData->glyphDataForCharacter(c);
294         }
295     }
296
297     return glyphDataForSystemFallback(c, description, variant);
298 }
299
300 GlyphData FontGlyphs::glyphDataForNormalVariant(UChar32 c, const FontDescription& description)
301 {
302     const unsigned pageNumber = c / GlyphPage::size;
303
304     for (unsigned fallbackLevel = 0; fallbackLevel <= description.familyCount(); ++fallbackLevel) {
305         auto* fontData = realizeFontDataAt(description, fallbackLevel);
306         if (!fontData)
307             break;
308         auto* simpleFontData = fontData->simpleFontDataForCharacter(c);
309         auto* page = simpleFontData ? simpleFontData->glyphPage(pageNumber) : nullptr;
310         if (!page)
311             continue;
312         GlyphData data = page->glyphDataForCharacter(c);
313         if (data.fontData) {
314             if (data.fontData->platformData().orientation() == Vertical && !data.fontData->isTextOrientationFallback()) {
315                 if (!Font::isCJKIdeographOrSymbol(c))
316                     return glyphDataForNonCJKCharacterWithGlyphOrientation(c, description.nonCJKGlyphOrientation(), data);
317
318                 if (!data.fontData->hasVerticalGlyphs()) {
319                     // Use the broken ideograph font data. The broken ideograph font will use the horizontal width of glyphs
320                     // to make sure you get a square (even for broken glyphs like symbols used for punctuation).
321                     return glyphDataForVariant(c, description, BrokenIdeographVariant, fallbackLevel);
322                 }
323 #if PLATFORM(COCOA)
324                 if (data.fontData->platformData().syntheticOblique())
325                     return glyphDataForCJKCharacterWithoutSyntheticItalic(c, data);
326 #endif
327             }
328
329             return data;
330         }
331     }
332
333     return glyphDataForSystemFallback(c, description, NormalVariant);
334 }
335
336 static RefPtr<GlyphPage> glyphPageFromFontData(unsigned pageNumber, const FontData& fontData)
337 {
338     const SimpleFontData* simpleFontData = nullptr;
339     if (fontData.isSegmented()) {
340         UChar32 pageRangeFrom = pageNumber * GlyphPage::size;
341         UChar32 pageRangeTo = pageRangeFrom + GlyphPage::size - 1;
342         auto& segmentedFontData = downcast<SegmentedFontData>(fontData);
343         for (unsigned i = 0; i < segmentedFontData.numRanges(); ++i) {
344             auto& range = segmentedFontData.rangeAt(i);
345             if (range.to()) {
346                 if (range.from() <= pageRangeFrom && pageRangeTo <= range.to())
347                     simpleFontData = range.fontData().get();
348                 break;
349             }
350         }
351         if (!simpleFontData)
352             return nullptr;
353     } else
354         simpleFontData = &downcast<SimpleFontData>(fontData);
355
356     if (simpleFontData->platformData().orientation() == Vertical)
357         return nullptr;
358
359     return const_cast<GlyphPage*>(simpleFontData->glyphPage(pageNumber));
360 }
361
362 GlyphData FontGlyphs::glyphDataForCharacter(const FontDescription& description, UChar32 c, bool mirror, FontDataVariant variant)
363 {
364     ASSERT(isMainThread());
365
366     if (variant == AutoVariant) {
367         if (description.smallCaps() && !primarySimpleFontData(description)->isSVGFont()) {
368             UChar32 upperC = u_toupper(c);
369             if (upperC != c) {
370                 c = upperC;
371                 variant = SmallCapsVariant;
372             } else
373                 variant = NormalVariant;
374         } else
375             variant = NormalVariant;
376     }
377
378     if (mirror)
379         c = u_charMirror(c);
380
381     if (variant != NormalVariant)
382         return glyphDataForVariant(c, description, variant, 0);
383
384     const unsigned pageNumber = c / GlyphPage::size;
385
386     RefPtr<GlyphPage>& cachedPage = pageNumber ? m_cachedPages.add(pageNumber, nullptr).iterator->value : m_cachedPageZero;
387     if (!cachedPage)
388         cachedPage = glyphPageFromFontData(pageNumber, *primaryFontData(description));
389
390     GlyphData glyphData = cachedPage ? cachedPage->glyphDataForCharacter(c) : GlyphData();
391     if (!glyphData.glyph) {
392         if (!cachedPage)
393             cachedPage = GlyphPage::createForMixedFontData();
394         else if (cachedPage->isImmutable())
395             cachedPage = GlyphPage::createCopyForMixedFontData(*cachedPage);
396
397         glyphData = glyphDataForNormalVariant(c, description);
398         cachedPage->setGlyphDataForCharacter(c, glyphData.glyph, glyphData.fontData);
399     }
400     return glyphData;
401 }
402
403 }