1/*
2 * Copyright (C) 2006, 2013 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 "SegmentedFontData.h"
35
36namespace WebCore {
37
38
39FontGlyphs::FontGlyphs(PassRefPtr<FontSelector> fontSelector)
40    : m_pageZero(0)
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
52FontGlyphs::FontGlyphs(const FontPlatformData& platformData)
53    : m_pageZero(0)
54    , m_cachedPrimarySimpleFontData(0)
55    , m_fontSelector(0)
56    , m_fontSelectorVersion(0)
57    , m_familyIndex(cAllFamiliesScanned)
58    , m_generation(fontCache().generation())
59    , m_pitch(UnknownPitch)
60    , m_loadingCustomFonts(false)
61    , m_isForPlatformFont(true)
62{
63    RefPtr<FontData> fontData = fontCache().getCachedFontData(&platformData);
64    m_realizedFontData.append(fontData.release());
65}
66
67void FontGlyphs::releaseFontData()
68{
69    unsigned numFonts = m_realizedFontData.size();
70    for (unsigned i = 0; i < numFonts; ++i) {
71        if (m_realizedFontData[i]->isCustomFont())
72            continue;
73        ASSERT(!m_realizedFontData[i]->isSegmented());
74        fontCache().releaseFontData(static_cast<const SimpleFontData*>(m_realizedFontData[i].get()));
75    }
76}
77
78void FontGlyphs::determinePitch(const FontDescription& description) const
79{
80    const FontData* fontData = primaryFontData(description);
81    if (!fontData->isSegmented())
82        m_pitch = static_cast<const SimpleFontData*>(fontData)->pitch();
83    else {
84        const SegmentedFontData* segmentedFontData = static_cast<const SegmentedFontData*>(fontData);
85        unsigned numRanges = segmentedFontData->numRanges();
86        if (numRanges == 1)
87            m_pitch = segmentedFontData->rangeAt(0).fontData()->pitch();
88        else
89            m_pitch = VariablePitch;
90    }
91}
92
93const FontData* FontGlyphs::realizeFontDataAt(const FontDescription& description, unsigned realizedFontIndex) const
94{
95    if (realizedFontIndex < m_realizedFontData.size())
96        return m_realizedFontData[realizedFontIndex].get(); // This fallback font is already in our list.
97
98    // Make sure we're not passing in some crazy value here.
99    ASSERT(realizedFontIndex == m_realizedFontData.size());
100
101    if (m_familyIndex <= cAllFamiliesScanned) {
102        if (!m_fontSelector)
103            return 0;
104
105        size_t index = cAllFamiliesScanned - m_familyIndex;
106        if (index == m_fontSelector->fallbackFontDataCount())
107            return 0;
108
109        m_familyIndex--;
110        RefPtr<FontData> fallback = m_fontSelector->getFallbackFontData(description, index);
111        if (fallback)
112            m_realizedFontData.append(fallback);
113        return fallback.get();
114    }
115
116    // Ask the font cache for the font data.
117    // We are obtaining this font for the first time. We keep track of the families we've looked at before
118    // in |m_familyIndex|, so that we never scan the same spot in the list twice. getFontData will adjust our
119    // |m_familyIndex| as it scans for the right font to make.
120    ASSERT(fontCache().generation() == m_generation);
121    RefPtr<FontData> result = fontCache().getFontData(description, m_familyIndex, m_fontSelector.get());
122    if (result) {
123        m_realizedFontData.append(result);
124        if (result->isLoading())
125            m_loadingCustomFonts = true;
126    }
127    return result.get();
128}
129
130static inline bool isInRange(UChar32 character, UChar32 lowerBound, UChar32 upperBound)
131{
132    return character >= lowerBound && character <= upperBound;
133}
134
135static bool shouldIgnoreRotation(UChar32 character)
136{
137    if (character == 0x000A7 || character == 0x000A9 || character == 0x000AE)
138        return true;
139
140    if (character == 0x000B6 || character == 0x000BC || character == 0x000BD || character == 0x000BE)
141        return true;
142
143    if (isInRange(character, 0x002E5, 0x002EB))
144        return true;
145
146    if (isInRange(character, 0x01100, 0x011FF) || isInRange(character, 0x01401, 0x0167F) || isInRange(character, 0x01800, 0x018FF))
147        return true;
148
149    if (character == 0x02016 || character == 0x02018 || character == 0x02019 || character == 0x02020 || character == 0x02021
150        || character == 0x2030 || character == 0x02031)
151        return true;
152
153    if (isInRange(character, 0x0203B, 0x0203D) || character == 0x02042 || character == 0x02044 || character == 0x02047
154        || character == 0x02048 || character == 0x02049 || character == 0x2051)
155        return true;
156
157    if (isInRange(character, 0x02065, 0x02069) || isInRange(character, 0x020DD, 0x020E0)
158        || isInRange(character, 0x020E2, 0x020E4) || isInRange(character, 0x02100, 0x02117)
159        || isInRange(character, 0x02119, 0x02131) || isInRange(character, 0x02133, 0x0213F))
160        return true;
161
162    if (isInRange(character, 0x02145, 0x0214A) || character == 0x0214C || character == 0x0214D
163        || isInRange(character, 0x0214F, 0x0218F))
164        return true;
165
166    if (isInRange(character, 0x02300, 0x02307) || isInRange(character, 0x0230C, 0x0231F)
167        || isInRange(character, 0x02322, 0x0232B) || isInRange(character, 0x0237D, 0x0239A)
168        || isInRange(character, 0x023B4, 0x023B6) || isInRange(character, 0x023BA, 0x023CF)
169        || isInRange(character, 0x023D1, 0x023DB) || isInRange(character, 0x023E2, 0x024FF))
170        return true;
171
172    if (isInRange(character, 0x025A0, 0x02619) || isInRange(character, 0x02620, 0x02767)
173        || isInRange(character, 0x02776, 0x02793) || isInRange(character, 0x02B12, 0x02B2F)
174        || isInRange(character, 0x02B4D, 0x02BFF) || isInRange(character, 0x02E80, 0x03007))
175        return true;
176
177    if (character == 0x03012 || character == 0x03013 || isInRange(character, 0x03020, 0x0302F)
178        || isInRange(character, 0x03031, 0x0309F) || isInRange(character, 0x030A1, 0x030FB)
179        || isInRange(character, 0x030FD, 0x0A4CF))
180        return true;
181
182    if (isInRange(character, 0x0A840, 0x0A87F) || isInRange(character, 0x0A960, 0x0A97F)
183        || isInRange(character, 0x0AC00, 0x0D7FF) || isInRange(character, 0x0E000, 0x0FAFF))
184        return true;
185
186    if (isInRange(character, 0x0FE10, 0x0FE1F) || isInRange(character, 0x0FE30, 0x0FE48)
187        || isInRange(character, 0x0FE50, 0x0FE57) || isInRange(character, 0x0FE5F, 0x0FE62)
188        || isInRange(character, 0x0FE67, 0x0FE6F))
189        return true;
190
191    if (isInRange(character, 0x0FF01, 0x0FF07) || isInRange(character, 0x0FF0A, 0x0FF0C)
192        || isInRange(character, 0x0FF0E, 0x0FF19) || character == 0x0FF1B || isInRange(character, 0x0FF1F, 0x0FF3A))
193        return true;
194
195    if (character == 0x0FF3C || character == 0x0FF3E)
196        return true;
197
198    if (isInRange(character, 0x0FF40, 0x0FF5A) || isInRange(character, 0x0FFE0, 0x0FFE2)
199        || isInRange(character, 0x0FFE4, 0x0FFE7) || isInRange(character, 0x0FFF0, 0x0FFF8)
200        || character == 0x0FFFD)
201        return true;
202
203    if (isInRange(character, 0x13000, 0x1342F) || isInRange(character, 0x1B000, 0x1B0FF)
204        || isInRange(character, 0x1D000, 0x1D1FF) || isInRange(character, 0x1D300, 0x1D37F)
205        || isInRange(character, 0x1F000, 0x1F64F) || isInRange(character, 0x1F680, 0x1F77F))
206        return true;
207
208    if (isInRange(character, 0x20000, 0x2FFFD) || isInRange(character, 0x30000, 0x3FFFD))
209        return true;
210
211    return false;
212}
213
214static inline std::pair<GlyphData, GlyphPage*> glyphDataAndPageForCJKCharacterWithoutSyntheticItalic(UChar32 character, GlyphData& data, GlyphPage* page, unsigned pageNumber)
215{
216    RefPtr<SimpleFontData> nonItalicFontData = data.fontData->nonSyntheticItalicFontData();
217    GlyphPageTreeNode* nonItalicNode = GlyphPageTreeNode::getRootChild(nonItalicFontData.get(), pageNumber);
218    GlyphPage* nonItalicPage = nonItalicNode->page();
219    if (nonItalicPage) {
220        GlyphData nonItalicData = nonItalicPage->glyphDataForCharacter(character);
221        if (nonItalicData.fontData)
222            return std::make_pair(nonItalicData, nonItalicPage);
223    }
224    return std::make_pair(data, page);
225}
226
227static inline std::pair<GlyphData, GlyphPage*> glyphDataAndPageForNonCJKCharacterWithGlyphOrientation(UChar32 character, NonCJKGlyphOrientation orientation, GlyphData& data, GlyphPage* page, unsigned pageNumber)
228{
229    if (orientation == NonCJKGlyphOrientationUpright || shouldIgnoreRotation(character)) {
230        RefPtr<SimpleFontData> uprightFontData = data.fontData->uprightOrientationFontData();
231        GlyphPageTreeNode* uprightNode = GlyphPageTreeNode::getRootChild(uprightFontData.get(), pageNumber);
232        GlyphPage* uprightPage = uprightNode->page();
233        if (uprightPage) {
234            GlyphData uprightData = uprightPage->glyphDataForCharacter(character);
235            // If the glyphs are the same, then we know we can just use the horizontal glyph rotated vertically to be upright.
236            if (data.glyph == uprightData.glyph)
237                return std::make_pair(data, page);
238            // The glyphs are distinct, meaning that the font has a vertical-right glyph baked into it. We can't use that
239            // glyph, so we fall back to the upright data and use the horizontal glyph.
240            if (uprightData.fontData)
241                return std::make_pair(uprightData, uprightPage);
242        }
243    } else if (orientation == NonCJKGlyphOrientationVerticalRight) {
244        RefPtr<SimpleFontData> verticalRightFontData = data.fontData->verticalRightOrientationFontData();
245        GlyphPageTreeNode* verticalRightNode = GlyphPageTreeNode::getRootChild(verticalRightFontData.get(), pageNumber);
246        GlyphPage* verticalRightPage = verticalRightNode->page();
247        if (verticalRightPage) {
248            GlyphData verticalRightData = verticalRightPage->glyphDataForCharacter(character);
249            // If the glyphs are distinct, we will make the assumption that the font has a vertical-right glyph baked
250            // into it.
251            if (data.glyph != verticalRightData.glyph)
252                return std::make_pair(data, page);
253            // The glyphs are identical, meaning that we should just use the horizontal glyph.
254            if (verticalRightData.fontData)
255                return std::make_pair(verticalRightData, verticalRightPage);
256        }
257    }
258    return std::make_pair(data, page);
259}
260
261std::pair<GlyphData, GlyphPage*> FontGlyphs::glyphDataAndPageForCharacter(const FontDescription& description, UChar32 c, bool mirror, FontDataVariant variant) const
262{
263    ASSERT(isMainThread());
264
265    if (variant == AutoVariant) {
266        if (description.smallCaps() && !primarySimpleFontData(description)->isSVGFont()) {
267            UChar32 upperC = u_toupper(c);
268            if (upperC != c) {
269                c = upperC;
270                variant = SmallCapsVariant;
271            } else
272                variant = NormalVariant;
273        } else
274            variant = NormalVariant;
275    }
276
277    if (mirror)
278        c = u_charMirror(c);
279
280    unsigned pageNumber = (c / GlyphPage::size);
281
282    GlyphPageTreeNode* node = pageNumber ? m_pages.get(pageNumber) : m_pageZero;
283    if (!node) {
284        node = GlyphPageTreeNode::getRootChild(realizeFontDataAt(description, 0), pageNumber);
285        if (pageNumber)
286            m_pages.set(pageNumber, node);
287        else
288            m_pageZero = node;
289    }
290
291    GlyphPage* page = 0;
292    if (variant == NormalVariant) {
293        // Fastest loop, for the common case (normal variant).
294        while (true) {
295            page = node->page();
296            if (page) {
297                GlyphData data = page->glyphDataForCharacter(c);
298                if (data.fontData && (data.fontData->platformData().orientation() == Horizontal || data.fontData->isTextOrientationFallback()))
299                    return std::make_pair(data, page);
300
301                if (data.fontData) {
302                    if (Font::isCJKIdeographOrSymbol(c)) {
303                        if (!data.fontData->hasVerticalGlyphs()) {
304                            // Use the broken ideograph font data. The broken ideograph font will use the horizontal width of glyphs
305                            // to make sure you get a square (even for broken glyphs like symbols used for punctuation).
306                            variant = BrokenIdeographVariant;
307                            break;
308                        }
309#if PLATFORM(COCOA)
310                        else if (data.fontData->platformData().syntheticOblique())
311                            return glyphDataAndPageForCJKCharacterWithoutSyntheticItalic(c, data, page, pageNumber);
312#endif
313                    } else
314                        return glyphDataAndPageForNonCJKCharacterWithGlyphOrientation(c, description.nonCJKGlyphOrientation(), data, page, pageNumber);
315
316                    return std::make_pair(data, page);
317                }
318
319                if (node->isSystemFallback())
320                    break;
321            }
322
323            node = node->getChild(realizeFontDataAt(description, node->level()), pageNumber);
324            if (pageNumber)
325                m_pages.set(pageNumber, node);
326            else
327                m_pageZero = node;
328        }
329    }
330    if (variant != NormalVariant) {
331        while (true) {
332            page = node->page();
333            if (page) {
334                GlyphData data = page->glyphDataForCharacter(c);
335                if (data.fontData) {
336                    // The variantFontData function should not normally return 0.
337                    // But if it does, we will just render the capital letter big.
338                    RefPtr<SimpleFontData> variantFontData = data.fontData->variantFontData(description, variant);
339                    if (!variantFontData)
340                        return std::make_pair(data, page);
341
342                    GlyphPageTreeNode* variantNode = GlyphPageTreeNode::getRootChild(variantFontData.get(), pageNumber);
343                    GlyphPage* variantPage = variantNode->page();
344                    if (variantPage) {
345                        GlyphData data = variantPage->glyphDataForCharacter(c);
346                        if (data.fontData)
347                            return std::make_pair(data, variantPage);
348                    }
349
350                    // Do not attempt system fallback off the variantFontData. This is the very unlikely case that
351                    // a font has the lowercase character but the small caps font does not have its uppercase version.
352                    return std::make_pair(variantFontData->missingGlyphData(), page);
353                }
354
355                if (node->isSystemFallback())
356                    break;
357            }
358
359            node = node->getChild(realizeFontDataAt(description, node->level()), pageNumber);
360            if (pageNumber)
361                m_pages.set(pageNumber, node);
362            else
363                m_pageZero = node;
364        }
365    }
366
367    ASSERT(page);
368    ASSERT(node->isSystemFallback());
369
370    // System fallback is character-dependent. When we get here, we
371    // know that the character in question isn't in the system fallback
372    // font's glyph page. Try to lazily create it here.
373    UChar codeUnits[2];
374    int codeUnitsLength;
375    if (c <= 0xFFFF) {
376        codeUnits[0] = Font::normalizeSpaces(c);
377        codeUnitsLength = 1;
378    } else {
379        codeUnits[0] = U16_LEAD(c);
380        codeUnits[1] = U16_TRAIL(c);
381        codeUnitsLength = 2;
382    }
383    const SimpleFontData* originalFontData = primaryFontData(description)->fontDataForCharacter(c);
384    RefPtr<SimpleFontData> characterFontData = fontCache().systemFallbackForCharacters(description, originalFontData, m_isForPlatformFont, codeUnits, codeUnitsLength);
385    if (characterFontData) {
386        if (characterFontData->platformData().orientation() == Vertical && !characterFontData->hasVerticalGlyphs() && Font::isCJKIdeographOrSymbol(c))
387            variant = BrokenIdeographVariant;
388        if (variant != NormalVariant)
389            characterFontData = characterFontData->variantFontData(description, variant);
390    }
391    if (characterFontData) {
392        // Got the fallback glyph and font.
393        GlyphPage* fallbackPage = GlyphPageTreeNode::getRootChild(characterFontData.get(), pageNumber)->page();
394        GlyphData data = fallbackPage && fallbackPage->fontDataForCharacter(c) ? fallbackPage->glyphDataForCharacter(c) : characterFontData->missingGlyphData();
395        // Cache it so we don't have to do system fallback again next time.
396        if (variant == NormalVariant) {
397#if OS(WINCE)
398            // missingGlyphData returns a null character, which is not suitable for GDI to display.
399            // Also, sometimes we cannot map a font for the character on WINCE, but GDI can still
400            // display the character, probably because the font package is not installed correctly.
401            // So we just always set the glyph to be same as the character, and let GDI solve it.
402            page->setGlyphDataForCharacter(c, c, characterFontData.get());
403            characterFontData->setMaxGlyphPageTreeLevel(std::max(characterFontData->maxGlyphPageTreeLevel(), node->level()));
404            return std::make_pair(page->glyphDataForCharacter(c), page);
405#else
406            page->setGlyphDataForCharacter(c, data.glyph, data.fontData);
407            data.fontData->setMaxGlyphPageTreeLevel(std::max(data.fontData->maxGlyphPageTreeLevel(), node->level()));
408            if (!Font::isCJKIdeographOrSymbol(c) && data.fontData->platformData().orientation() != Horizontal && !data.fontData->isTextOrientationFallback())
409                return glyphDataAndPageForNonCJKCharacterWithGlyphOrientation(c, description.nonCJKGlyphOrientation(), data, fallbackPage, pageNumber);
410#endif
411        }
412        return std::make_pair(data, page);
413    }
414
415    // Even system fallback can fail; use the missing glyph in that case.
416    // FIXME: It would be nicer to use the missing glyph from the last resort font instead.
417    GlyphData data = primarySimpleFontData(description)->missingGlyphData();
418    if (variant == NormalVariant) {
419#if OS(WINCE)
420        // See comment about WINCE GDI handling near setGlyphDataForCharacter above.
421        page->setGlyphDataForCharacter(c, c, data.fontData);
422        data.fontData->setMaxGlyphPageTreeLevel(std::max(data.fontData->maxGlyphPageTreeLevel(), node->level()));
423        return std::make_pair(page->glyphDataForCharacter(c), page);
424#else
425        page->setGlyphDataForCharacter(c, data.glyph, data.fontData);
426        data.fontData->setMaxGlyphPageTreeLevel(std::max(data.fontData->maxGlyphPageTreeLevel(), node->level()));
427#endif
428    }
429    return std::make_pair(data, page);
430}
431
432
433}
434