FontFastPath.cpp revision 2bde8e466a4451c7319e3a072d118917957d6554
1/**
2 * Copyright (C) 2003, 2006, 2010 Apple Inc. All rights reserved.
3 * Copyright (C) 2008 Holger Hans Peter Freyther
4 * Copyright (C) 2009 Torch Mobile, Inc.
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 * Library General Public License for more details.
15 *
16 * You should have received a copy of the GNU Library General Public License
17 * along with this library; see the file COPYING.LIB.  If not, write to
18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
20 *
21 */
22
23#include "config.h"
24#include "Font.h"
25
26#include "FloatRect.h"
27#include "FontCache.h"
28#include "FontFallbackList.h"
29#include "GlyphBuffer.h"
30#include "GlyphPageTreeNode.h"
31#include "SimpleFontData.h"
32#include "TextRun.h"
33#include "WidthIterator.h"
34#include <wtf/MathExtras.h>
35#include <wtf/unicode/CharacterNames.h>
36#include <wtf/unicode/Unicode.h>
37
38using namespace WTF;
39using namespace Unicode;
40
41namespace WebCore {
42
43GlyphData Font::glyphDataForCharacter(UChar32 c, bool mirror, FontDataVariant variant) const
44{
45    ASSERT(isMainThread());
46
47    if (variant == AutoVariant) {
48        if (m_fontDescription.smallCaps()) {
49            UChar32 upperC = toUpper(c);
50            if (upperC != c) {
51                c = upperC;
52                variant = SmallCapsVariant;
53            } else
54                variant = NormalVariant;
55        } else
56            variant = NormalVariant;
57    }
58
59    if (mirror)
60        c = mirroredChar(c);
61
62    unsigned pageNumber = (c / GlyphPage::size);
63
64    GlyphPageTreeNode* node = pageNumber ? m_fontList->m_pages.get(pageNumber) : m_fontList->m_pageZero;
65    if (!node) {
66        node = GlyphPageTreeNode::getRootChild(fontDataAt(0), pageNumber);
67        if (pageNumber)
68            m_fontList->m_pages.set(pageNumber, node);
69        else
70            m_fontList->m_pageZero = node;
71    }
72
73    GlyphPage* page;
74    if (variant == NormalVariant) {
75        // Fastest loop, for the common case (normal variant).
76        while (true) {
77            page = node->page();
78            if (page) {
79                GlyphData data = page->glyphDataForCharacter(c);
80                if (data.fontData && (data.fontData->platformData().orientation() == Horizontal || data.fontData->isTextOrientationFallback()))
81                    return data;
82
83                if (data.fontData) {
84                    if (isCJKIdeographOrSymbol(c)) {
85                        if (!data.fontData->hasVerticalGlyphs()) {
86                            // Use the broken ideograph font data. The broken ideograph font will use the horizontal width of glyphs
87                            // to make sure you get a square (even for broken glyphs like symbols used for punctuation).
88                            const SimpleFontData* brokenIdeographFontData = data.fontData->brokenIdeographFontData();
89                            GlyphPageTreeNode* brokenIdeographNode = GlyphPageTreeNode::getRootChild(brokenIdeographFontData, pageNumber);
90                            const GlyphPage* brokenIdeographPage = brokenIdeographNode->page();
91                            if (brokenIdeographPage) {
92                                GlyphData brokenIdeographData = brokenIdeographPage->glyphDataForCharacter(c);
93                                if (brokenIdeographData.fontData)
94                                    return brokenIdeographData;
95                            }
96
97                            // Shouldn't be possible to even reach this point.
98                            ASSERT_NOT_REACHED();
99                        }
100                    } else {
101                        if (m_fontDescription.textOrientation() == TextOrientationVerticalRight) {
102                            const SimpleFontData* verticalRightFontData = data.fontData->verticalRightOrientationFontData();
103                            GlyphPageTreeNode* verticalRightNode = GlyphPageTreeNode::getRootChild(verticalRightFontData, pageNumber);
104                            const GlyphPage* verticalRightPage = verticalRightNode->page();
105                            if (verticalRightPage) {
106                                GlyphData verticalRightData = verticalRightPage->glyphDataForCharacter(c);
107                                // If the glyphs are distinct, we will make the assumption that the font has a vertical-right glyph baked
108                                // into it.
109                                if (data.glyph != verticalRightData.glyph)
110                                    return data;
111                                // The glyphs are identical, meaning that we should just use the horizontal glyph.
112                                if (verticalRightData.fontData)
113                                    return verticalRightData;
114                            }
115                        } else if (m_fontDescription.textOrientation() == TextOrientationUpright) {
116                            const SimpleFontData* uprightFontData = data.fontData->uprightOrientationFontData();
117                            GlyphPageTreeNode* uprightNode = GlyphPageTreeNode::getRootChild(uprightFontData, pageNumber);
118                            const GlyphPage* uprightPage = uprightNode->page();
119                            if (uprightPage) {
120                                GlyphData uprightData = uprightPage->glyphDataForCharacter(c);
121                                // If the glyphs are the same, then we know we can just use the horizontal glyph rotated vertically to be upright.
122                                if (data.glyph == uprightData.glyph)
123                                    return data;
124                                // The glyphs are distinct, meaning that the font has a vertical-right glyph baked into it. We can't use that
125                                // glyph, so we fall back to the upright data and use the horizontal glyph.
126                                if (uprightData.fontData)
127                                    return uprightData;
128                            }
129                        }
130
131                        // Shouldn't be possible to even reach this point.
132                        ASSERT_NOT_REACHED();
133                    }
134                    return data;
135                }
136
137                if (node->isSystemFallback())
138                    break;
139            }
140
141            // Proceed with the fallback list.
142            node = node->getChild(fontDataAt(node->level()), pageNumber);
143            if (pageNumber)
144                m_fontList->m_pages.set(pageNumber, node);
145            else
146                m_fontList->m_pageZero = node;
147        }
148    } else {
149        while (true) {
150            page = node->page();
151            if (page) {
152                GlyphData data = page->glyphDataForCharacter(c);
153                if (data.fontData) {
154                    // The variantFontData function should not normally return 0.
155                    // But if it does, we will just render the capital letter big.
156                    const SimpleFontData* variantFontData = data.fontData->variantFontData(m_fontDescription, variant);
157                    if (!variantFontData)
158                        return data;
159
160                    GlyphPageTreeNode* variantNode = GlyphPageTreeNode::getRootChild(variantFontData, pageNumber);
161                    const GlyphPage* variantPage = variantNode->page();
162                    if (variantPage) {
163                        GlyphData data = variantPage->glyphDataForCharacter(c);
164                        if (data.fontData)
165                            return data;
166                    }
167
168                    // Do not attempt system fallback off the variantFontData. This is the very unlikely case that
169                    // a font has the lowercase character but the small caps font does not have its uppercase version.
170                    return variantFontData->missingGlyphData();
171                }
172
173                if (node->isSystemFallback())
174                    break;
175            }
176
177            // Proceed with the fallback list.
178            node = node->getChild(fontDataAt(node->level()), pageNumber);
179            if (pageNumber)
180                m_fontList->m_pages.set(pageNumber, node);
181            else
182                m_fontList->m_pageZero = node;
183        }
184    }
185
186    ASSERT(page);
187    ASSERT(node->isSystemFallback());
188
189    // System fallback is character-dependent. When we get here, we
190    // know that the character in question isn't in the system fallback
191    // font's glyph page. Try to lazily create it here.
192    UChar codeUnits[2];
193    int codeUnitsLength;
194    if (c <= 0xFFFF) {
195        codeUnits[0] = Font::normalizeSpaces(c);
196        codeUnitsLength = 1;
197    } else {
198        codeUnits[0] = U16_LEAD(c);
199        codeUnits[1] = U16_TRAIL(c);
200        codeUnitsLength = 2;
201    }
202    const SimpleFontData* characterFontData = fontCache()->getFontDataForCharacters(*this, codeUnits, codeUnitsLength);
203    if (variant != NormalVariant && characterFontData)
204        characterFontData = characterFontData->variantFontData(m_fontDescription, variant);
205    if (characterFontData) {
206        // Got the fallback glyph and font.
207        GlyphPage* fallbackPage = GlyphPageTreeNode::getRootChild(characterFontData, pageNumber)->page();
208        GlyphData data = fallbackPage && fallbackPage->fontDataForCharacter(c) ? fallbackPage->glyphDataForCharacter(c) : characterFontData->missingGlyphData();
209        // Cache it so we don't have to do system fallback again next time.
210        if (variant == NormalVariant) {
211#if OS(WINCE)
212            // missingGlyphData returns a null character, which is not suitable for GDI to display.
213            // Also, sometimes we cannot map a font for the character on WINCE, but GDI can still
214            // display the character, probably because the font package is not installed correctly.
215            // So we just always set the glyph to be same as the character, and let GDI solve it.
216            page->setGlyphDataForCharacter(c, c, characterFontData);
217            return page->glyphDataForCharacter(c);
218#else
219            page->setGlyphDataForCharacter(c, data.glyph, data.fontData);
220#endif
221        }
222        return data;
223    }
224
225    // Even system fallback can fail; use the missing glyph in that case.
226    // FIXME: It would be nicer to use the missing glyph from the last resort font instead.
227    GlyphData data = primaryFont()->missingGlyphData();
228    if (variant == NormalVariant) {
229#if OS(WINCE)
230        // See comment about WINCE GDI handling near setGlyphDataForCharacter above.
231        page->setGlyphDataForCharacter(c, c, data.fontData);
232        return page->glyphDataForCharacter(c);
233#else
234        page->setGlyphDataForCharacter(c, data.glyph, data.fontData);
235#endif
236    }
237    return data;
238}
239
240bool Font::primaryFontHasGlyphForCharacter(UChar32 character) const
241{
242    unsigned pageNumber = (character / GlyphPage::size);
243
244    GlyphPageTreeNode* node = GlyphPageTreeNode::getRootChild(primaryFont(), pageNumber);
245    GlyphPage* page = node->page();
246
247    return page && page->fontDataForCharacter(character);
248}
249
250// FIXME: This function may not work if the emphasis mark uses a complex script, but none of the
251// standard emphasis marks do so.
252bool Font::getEmphasisMarkGlyphData(const AtomicString& mark, GlyphData& glyphData) const
253{
254    if (mark.isEmpty())
255        return false;
256
257#if ENABLE(SVG_FONTS)
258    // FIXME: Implement for SVG fonts.
259    if (primaryFont()->isSVGFont())
260        return false;
261#endif
262
263    UChar32 character = mark[0];
264
265    if (U16_IS_SURROGATE(character)) {
266        if (!U16_IS_SURROGATE_LEAD(character))
267            return false;
268
269        if (mark.length() < 2)
270            return false;
271
272        UChar low = mark[1];
273        if (!U16_IS_TRAIL(low))
274            return false;
275
276        character = U16_GET_SUPPLEMENTARY(character, low);
277    }
278
279    glyphData = glyphDataForCharacter(character, false, EmphasisMarkVariant);
280    return true;
281}
282
283int Font::emphasisMarkAscent(const AtomicString& mark) const
284{
285    GlyphData markGlyphData;
286    if (!getEmphasisMarkGlyphData(mark, markGlyphData))
287        return 0;
288
289    const SimpleFontData* markFontData = markGlyphData.fontData;
290    ASSERT(markFontData);
291    if (!markFontData)
292        return 0;
293
294    return markFontData->fontMetrics().ascent();
295}
296
297int Font::emphasisMarkDescent(const AtomicString& mark) const
298{
299    GlyphData markGlyphData;
300    if (!getEmphasisMarkGlyphData(mark, markGlyphData))
301        return 0;
302
303    const SimpleFontData* markFontData = markGlyphData.fontData;
304    ASSERT(markFontData);
305    if (!markFontData)
306        return 0;
307
308    return markFontData->fontMetrics().descent();
309}
310
311int Font::emphasisMarkHeight(const AtomicString& mark) const
312{
313    GlyphData markGlyphData;
314    if (!getEmphasisMarkGlyphData(mark, markGlyphData))
315        return 0;
316
317    const SimpleFontData* markFontData = markGlyphData.fontData;
318    ASSERT(markFontData);
319    if (!markFontData)
320        return 0;
321
322    return markFontData->fontMetrics().height();
323}
324
325float Font::getGlyphsAndAdvancesForSimpleText(const TextRun& run, int from, int to, GlyphBuffer& glyphBuffer, ForTextEmphasisOrNot forTextEmphasis) const
326{
327    float initialAdvance;
328
329    WidthIterator it(this, run, 0, false, forTextEmphasis);
330    it.advance(from);
331    float beforeWidth = it.m_runWidthSoFar;
332    it.advance(to, &glyphBuffer);
333
334    if (glyphBuffer.isEmpty())
335        return 0;
336
337    float afterWidth = it.m_runWidthSoFar;
338
339    if (run.rtl()) {
340        it.advance(run.length());
341        initialAdvance = it.m_runWidthSoFar - afterWidth;
342    } else
343        initialAdvance = beforeWidth;
344
345    if (run.rtl()) {
346        for (int i = 0, end = glyphBuffer.size() - 1; i < glyphBuffer.size() / 2; ++i, --end)
347            glyphBuffer.swap(i, end);
348    }
349
350    return initialAdvance;
351}
352
353void Font::drawSimpleText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, int from, int to) const
354{
355    // This glyph buffer holds our glyphs+advances+font data for each glyph.
356    GlyphBuffer glyphBuffer;
357
358    float startX = point.x() + getGlyphsAndAdvancesForSimpleText(run, from, to, glyphBuffer);
359
360    if (glyphBuffer.isEmpty())
361        return;
362
363    FloatPoint startPoint(startX, point.y());
364    drawGlyphBuffer(context, glyphBuffer, startPoint);
365}
366
367void Font::drawEmphasisMarksForSimpleText(GraphicsContext* context, const TextRun& run, const AtomicString& mark, const FloatPoint& point, int from, int to) const
368{
369    GlyphBuffer glyphBuffer;
370    float initialAdvance = getGlyphsAndAdvancesForSimpleText(run, from, to, glyphBuffer, ForTextEmphasis);
371
372    if (glyphBuffer.isEmpty())
373        return;
374
375    drawEmphasisMarks(context, glyphBuffer, mark, FloatPoint(point.x() + initialAdvance, point.y()));
376}
377
378void Font::drawGlyphBuffer(GraphicsContext* context, const GlyphBuffer& glyphBuffer, const FloatPoint& point) const
379{
380    // Draw each contiguous run of glyphs that use the same font data.
381    const SimpleFontData* fontData = glyphBuffer.fontDataAt(0);
382    FloatSize offset = glyphBuffer.offsetAt(0);
383    FloatPoint startPoint(point);
384    float nextX = startPoint.x();
385    int lastFrom = 0;
386    int nextGlyph = 0;
387    while (nextGlyph < glyphBuffer.size()) {
388        const SimpleFontData* nextFontData = glyphBuffer.fontDataAt(nextGlyph);
389        FloatSize nextOffset = glyphBuffer.offsetAt(nextGlyph);
390        if (nextFontData != fontData || nextOffset != offset) {
391            drawGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint);
392
393            lastFrom = nextGlyph;
394            fontData = nextFontData;
395            offset = nextOffset;
396            startPoint.setX(nextX);
397        }
398        nextX += glyphBuffer.advanceAt(nextGlyph);
399        nextGlyph++;
400    }
401
402    drawGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint);
403}
404
405inline static float offsetToMiddleOfGlyph(const SimpleFontData* fontData, Glyph glyph)
406{
407    if (fontData->platformData().orientation() == Horizontal) {
408        FloatRect bounds = fontData->boundsForGlyph(glyph);
409        return bounds.x() + bounds.width() / 2;
410    }
411    // FIXME: Use glyph bounds once they make sense for vertical fonts.
412    return fontData->widthForGlyph(glyph) / 2;
413}
414
415inline static float offsetToMiddleOfGlyphAtIndex(const GlyphBuffer& glyphBuffer, size_t i)
416{
417    return offsetToMiddleOfGlyph(glyphBuffer.fontDataAt(i), glyphBuffer.glyphAt(i));
418}
419
420void Font::drawEmphasisMarks(GraphicsContext* context, const GlyphBuffer& glyphBuffer, const AtomicString& mark, const FloatPoint& point) const
421{
422    GlyphData markGlyphData;
423    if (!getEmphasisMarkGlyphData(mark, markGlyphData))
424        return;
425
426    const SimpleFontData* markFontData = markGlyphData.fontData;
427    ASSERT(markFontData);
428    if (!markFontData)
429        return;
430
431    Glyph markGlyph = markGlyphData.glyph;
432    Glyph spaceGlyph = markFontData->spaceGlyph();
433
434    float middleOfLastGlyph = offsetToMiddleOfGlyphAtIndex(glyphBuffer, 0);
435    FloatPoint startPoint(point.x() + middleOfLastGlyph - offsetToMiddleOfGlyph(markFontData, markGlyph), point.y());
436
437    GlyphBuffer markBuffer;
438    for (int i = 0; i + 1 < glyphBuffer.size(); ++i) {
439        float middleOfNextGlyph = offsetToMiddleOfGlyphAtIndex(glyphBuffer, i + 1);
440        float advance = glyphBuffer.advanceAt(i) - middleOfLastGlyph + middleOfNextGlyph;
441        markBuffer.add(glyphBuffer.glyphAt(i) ? markGlyph : spaceGlyph, markFontData, advance);
442        middleOfLastGlyph = middleOfNextGlyph;
443    }
444    markBuffer.add(glyphBuffer.glyphAt(glyphBuffer.size() - 1) ? markGlyph : spaceGlyph, markFontData, 0);
445
446    drawGlyphBuffer(context, markBuffer, startPoint);
447}
448
449float Font::floatWidthForSimpleText(const TextRun& run, GlyphBuffer* glyphBuffer, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const
450{
451    WidthIterator it(this, run, fallbackFonts, glyphOverflow);
452    it.advance(run.length(), glyphBuffer);
453
454    if (glyphOverflow) {
455        glyphOverflow->top = max<int>(glyphOverflow->top, ceilf(-it.minGlyphBoundingBoxY()) - (glyphOverflow->computeBounds ? 0 : fontMetrics().ascent()));
456        glyphOverflow->bottom = max<int>(glyphOverflow->bottom, ceilf(it.maxGlyphBoundingBoxY()) - (glyphOverflow->computeBounds ? 0 : fontMetrics().descent()));
457        glyphOverflow->left = ceilf(it.firstGlyphOverflow());
458        glyphOverflow->right = ceilf(it.lastGlyphOverflow());
459    }
460
461    return it.m_runWidthSoFar;
462}
463
464FloatRect Font::selectionRectForSimpleText(const TextRun& run, const FloatPoint& point, int h, int from, int to) const
465{
466    WidthIterator it(this, run);
467    it.advance(from);
468    float beforeWidth = it.m_runWidthSoFar;
469    it.advance(to);
470    float afterWidth = it.m_runWidthSoFar;
471
472    // Using roundf() rather than ceilf() for the right edge as a compromise to ensure correct caret positioning.
473    if (run.rtl()) {
474        it.advance(run.length());
475        float totalWidth = it.m_runWidthSoFar;
476        return FloatRect(point.x() + floorf(totalWidth - afterWidth), point.y(), roundf(totalWidth - beforeWidth) - floorf(totalWidth - afterWidth), h);
477    }
478
479    return FloatRect(point.x() + floorf(beforeWidth), point.y(), roundf(afterWidth) - floorf(beforeWidth), h);
480}
481
482int Font::offsetForPositionForSimpleText(const TextRun& run, float x, bool includePartialGlyphs) const
483{
484    float delta = x;
485
486    WidthIterator it(this, run);
487    GlyphBuffer localGlyphBuffer;
488    unsigned offset;
489    if (run.rtl()) {
490        delta -= floatWidthForSimpleText(run, 0);
491        while (1) {
492            offset = it.m_currentCharacter;
493            float w;
494            if (!it.advanceOneCharacter(w, &localGlyphBuffer))
495                break;
496            delta += w;
497            if (includePartialGlyphs) {
498                if (delta - w / 2 >= 0)
499                    break;
500            } else {
501                if (delta >= 0)
502                    break;
503            }
504        }
505    } else {
506        while (1) {
507            offset = it.m_currentCharacter;
508            float w;
509            if (!it.advanceOneCharacter(w, &localGlyphBuffer))
510                break;
511            delta -= w;
512            if (includePartialGlyphs) {
513                if (delta + w / 2 <= 0)
514                    break;
515            } else {
516                if (delta <= 0)
517                    break;
518            }
519        }
520    }
521
522    return offset;
523}
524
525}
526