Font.cpp revision 1cbdecfa9fc428ac2d8aca0fa91c9580b3d57353
1/*
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 *           (C) 1999 Antti Koivisto (koivisto@kde.org)
4 *           (C) 2000 Dirk Mueller (mueller@kde.org)
5 * Copyright (C) 2003, 2006 Apple Inc. All rights reserved.
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 * Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public License
18 * along with this library; see the file COPYING.LIB.  If not, write to
19 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
21 *
22 */
23
24#include "config.h"
25#include "Font.h"
26
27#include "CharacterNames.h"
28#include "FloatRect.h"
29#include "FontCache.h"
30#include "FontFallbackList.h"
31#include "IntPoint.h"
32#include "GlyphBuffer.h"
33#include "WidthIterator.h"
34#include <wtf/MathExtras.h>
35
36using namespace WTF;
37using namespace Unicode;
38
39namespace WebCore {
40
41const uint8_t Font::gRoundingHackCharacterTable[256] = {
42    0, 0, 0, 0, 0, 0, 0, 0, 0, 1 /*\t*/, 1 /*\n*/, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
43    1 /*space*/, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 /*-*/, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 /*?*/,
44    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
45    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
46    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
47    1 /*no-break space*/, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
48    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
49    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
50};
51
52Font::CodePath Font::s_codePath = Auto;
53
54// ============================================================================================
55// Font Implementation (Cross-Platform Portion)
56// ============================================================================================
57
58Font::Font()
59    : m_pageZero(0)
60    , m_cachedPrimaryFont(0)
61    , m_letterSpacing(0)
62    , m_wordSpacing(0)
63    , m_isPlatformFont(false)
64{
65}
66
67Font::Font(const FontDescription& fd, short letterSpacing, short wordSpacing)
68    : m_fontDescription(fd)
69    , m_pageZero(0)
70    , m_cachedPrimaryFont(0)
71    , m_letterSpacing(letterSpacing)
72    , m_wordSpacing(wordSpacing)
73    , m_isPlatformFont(false)
74{
75}
76
77Font::Font(const FontPlatformData& fontData, bool isPrinterFont)
78    : m_fontList(FontFallbackList::create())
79    , m_pageZero(0)
80    , m_cachedPrimaryFont(0)
81    , m_letterSpacing(0)
82    , m_wordSpacing(0)
83    , m_isPlatformFont(true)
84{
85    m_fontDescription.setUsePrinterFont(isPrinterFont);
86    m_fontList->setPlatformFont(fontData);
87}
88
89Font::Font(const Font& other)
90    : m_fontDescription(other.m_fontDescription)
91    , m_fontList(other.m_fontList)
92    , m_pages(other.m_pages)
93    , m_pageZero(other.m_pageZero)
94    , m_cachedPrimaryFont(other.m_cachedPrimaryFont)
95    , m_letterSpacing(other.m_letterSpacing)
96    , m_wordSpacing(other.m_wordSpacing)
97    , m_isPlatformFont(other.m_isPlatformFont)
98{
99}
100
101Font& Font::operator=(const Font& other)
102{
103    m_fontDescription = other.m_fontDescription;
104    m_fontList = other.m_fontList;
105    m_pages = other.m_pages;
106    m_pageZero = other.m_pageZero;
107    m_cachedPrimaryFont = other.m_cachedPrimaryFont;
108    m_letterSpacing = other.m_letterSpacing;
109    m_wordSpacing = other.m_wordSpacing;
110    m_isPlatformFont = other.m_isPlatformFont;
111    return *this;
112}
113
114Font::~Font()
115{
116}
117
118bool Font::operator==(const Font& other) const
119{
120    // Our FontData don't have to be checked, since checking the font description will be fine.
121    // FIXME: This does not work if the font was made with the FontPlatformData constructor.
122    if ((m_fontList && m_fontList->loadingCustomFonts()) ||
123        (other.m_fontList && other.m_fontList->loadingCustomFonts()))
124        return false;
125
126    FontSelector* first = m_fontList ? m_fontList->fontSelector() : 0;
127    FontSelector* second = other.m_fontList ? other.m_fontList->fontSelector() : 0;
128
129    return first == second
130           && m_fontDescription == other.m_fontDescription
131           && m_letterSpacing == other.m_letterSpacing
132           && m_wordSpacing == other.m_wordSpacing
133           && (m_fontList ? m_fontList->generation() : 0) == (other.m_fontList ? other.m_fontList->generation() : 0);
134}
135
136const GlyphData& Font::glyphDataForCharacter(UChar32 c, bool mirror, bool forceSmallCaps) const
137{
138    bool useSmallCapsFont = forceSmallCaps;
139    if (m_fontDescription.smallCaps()) {
140        UChar32 upperC = Unicode::toUpper(c);
141        if (upperC != c) {
142            c = upperC;
143            useSmallCapsFont = true;
144        }
145    }
146
147    if (mirror)
148        c = mirroredChar(c);
149
150    unsigned pageNumber = (c / GlyphPage::size);
151
152    GlyphPageTreeNode* node = pageNumber ? m_pages.get(pageNumber) : m_pageZero;
153    if (!node) {
154        node = GlyphPageTreeNode::getRootChild(fontDataAt(0), pageNumber);
155        if (pageNumber)
156            m_pages.set(pageNumber, node);
157        else
158            m_pageZero = node;
159    }
160
161    GlyphPage* page;
162    if (!useSmallCapsFont) {
163        // Fastest loop, for the common case (not small caps).
164        while (true) {
165            page = node->page();
166            if (page) {
167                const GlyphData& data = page->glyphDataForCharacter(c);
168                if (data.fontData)
169                    return data;
170                if (node->isSystemFallback())
171                    break;
172            }
173
174            // Proceed with the fallback list.
175            node = node->getChild(fontDataAt(node->level()), pageNumber);
176            if (pageNumber)
177                m_pages.set(pageNumber, node);
178            else
179                m_pageZero = node;
180        }
181    } else {
182        while (true) {
183            page = node->page();
184            if (page) {
185                const GlyphData& data = page->glyphDataForCharacter(c);
186                if (data.fontData) {
187                    // The smallCapsFontData function should not normally return 0.
188                    // But if it does, we will just render the capital letter big.
189                    const SimpleFontData* smallCapsFontData = data.fontData->smallCapsFontData(m_fontDescription);
190                    if (!smallCapsFontData)
191                        return data;
192
193                    GlyphPageTreeNode* smallCapsNode = GlyphPageTreeNode::getRootChild(smallCapsFontData, pageNumber);
194                    const GlyphPage* smallCapsPage = smallCapsNode->page();
195                    if (smallCapsPage) {
196                        const GlyphData& data = smallCapsPage->glyphDataForCharacter(c);
197                        if (data.fontData)
198                            return data;
199                    }
200
201                    // Do not attempt system fallback off the smallCapsFontData. This is the very unlikely case that
202                    // a font has the lowercase character but the small caps font does not have its uppercase version.
203                    return smallCapsFontData->missingGlyphData();
204                }
205
206                if (node->isSystemFallback())
207                    break;
208            }
209
210            // Proceed with the fallback list.
211            node = node->getChild(fontDataAt(node->level()), pageNumber);
212            if (pageNumber)
213                m_pages.set(pageNumber, node);
214            else
215                m_pageZero = node;
216        }
217    }
218
219    ASSERT(page);
220    ASSERT(node->isSystemFallback());
221
222    // System fallback is character-dependent. When we get here, we
223    // know that the character in question isn't in the system fallback
224    // font's glyph page. Try to lazily create it here.
225    UChar codeUnits[2];
226    int codeUnitsLength;
227    if (c <= 0xFFFF) {
228        UChar c16 = c;
229        if (Font::treatAsSpace(c16))
230            codeUnits[0] = ' ';
231        else if (Font::treatAsZeroWidthSpace(c16))
232            codeUnits[0] = zeroWidthSpace;
233        else
234            codeUnits[0] = c16;
235        codeUnitsLength = 1;
236    } else {
237        codeUnits[0] = U16_LEAD(c);
238        codeUnits[1] = U16_TRAIL(c);
239        codeUnitsLength = 2;
240    }
241    const SimpleFontData* characterFontData = FontCache::getFontDataForCharacters(*this, codeUnits, codeUnitsLength);
242    if (useSmallCapsFont)
243        characterFontData = characterFontData->smallCapsFontData(m_fontDescription);
244    if (characterFontData) {
245        // Got the fallback glyph and font.
246        GlyphPage* fallbackPage = GlyphPageTreeNode::getRootChild(characterFontData, pageNumber)->page();
247        const GlyphData& data = fallbackPage && fallbackPage->glyphDataForCharacter(c).fontData ? fallbackPage->glyphDataForCharacter(c) : characterFontData->missingGlyphData();
248        // Cache it so we don't have to do system fallback again next time.
249        if (!useSmallCapsFont)
250            page->setGlyphDataForCharacter(c, data.glyph, data.fontData);
251        return data;
252    }
253
254    // Even system fallback can fail; use the missing glyph in that case.
255    // FIXME: It would be nicer to use the missing glyph from the last resort font instead.
256    const GlyphData& data = primaryFont()->missingGlyphData();
257    if (!useSmallCapsFont)
258        page->setGlyphDataForCharacter(c, data.glyph, data.fontData);
259    return data;
260}
261
262void Font::cachePrimaryFont() const
263{
264    ASSERT(m_fontList);
265    ASSERT(!m_cachedPrimaryFont);
266    m_cachedPrimaryFont = m_fontList->primaryFont(this)->fontDataForCharacter(' ');
267}
268
269const FontData* Font::fontDataAt(unsigned index) const
270{
271    ASSERT(m_fontList);
272    return m_fontList->fontDataAt(this, index);
273}
274
275const FontData* Font::fontDataForCharacters(const UChar* characters, int length) const
276{
277    ASSERT(m_fontList);
278    return m_fontList->fontDataForCharacters(this, characters, length);
279}
280
281void Font::update(PassRefPtr<FontSelector> fontSelector) const
282{
283    // FIXME: It is pretty crazy that we are willing to just poke into a RefPtr, but it ends up
284    // being reasonably safe (because inherited fonts in the render tree pick up the new
285    // style anyway. Other copies are transient, e.g., the state in the GraphicsContext, and
286    // won't stick around long enough to get you in trouble). Still, this is pretty disgusting,
287    // and could eventually be rectified by using RefPtrs for Fonts themselves.
288    if (!m_fontList)
289        m_fontList = FontFallbackList::create();
290    m_fontList->invalidate(fontSelector);
291    m_cachedPrimaryFont = 0;
292    m_pageZero = 0;
293    m_pages.clear();
294}
295
296int Font::width(const TextRun& run) const
297{
298    return lroundf(floatWidth(run));
299}
300
301int Font::ascent() const
302{
303    return primaryFont()->ascent();
304}
305
306int Font::descent() const
307{
308    return primaryFont()->descent();
309}
310
311int Font::lineSpacing() const
312{
313    return primaryFont()->lineSpacing();
314}
315
316int Font::lineGap() const
317{
318    return primaryFont()->lineGap();
319}
320
321float Font::xHeight() const
322{
323    return primaryFont()->xHeight();
324}
325
326unsigned Font::unitsPerEm() const
327{
328    return primaryFont()->unitsPerEm();
329}
330
331int Font::spaceWidth() const
332{
333    return (int)ceilf(primaryFont()->m_adjustedSpaceWidth + m_letterSpacing);
334}
335
336bool Font::isFixedPitch() const
337{
338    ASSERT(m_fontList);
339    return m_fontList->isFixedPitch(this);
340}
341
342void Font::setCodePath(CodePath p)
343{
344    s_codePath = p;
345}
346
347Font::CodePath Font::codePath()
348{
349    return s_codePath;
350}
351
352bool Font::canUseGlyphCache(const TextRun& run) const
353{
354    switch (s_codePath) {
355        case Auto:
356            break;
357        case Simple:
358            return true;
359        case Complex:
360            return false;
361    }
362
363    // Start from 0 since drawing and highlighting also measure the characters before run->from
364    for (int i = 0; i < run.length(); i++) {
365        const UChar c = run[i];
366        if (c < 0x300)      // U+0300 through U+036F Combining diacritical marks
367            continue;
368        if (c <= 0x36F)
369            return false;
370
371        if (c < 0x0591 || c == 0x05BE)     // U+0591 through U+05CF excluding U+05BE Hebrew combining marks, Hebrew punctuation Paseq, Sof Pasuq and Nun Hafukha
372            continue;
373        if (c <= 0x05CF)
374            return false;
375
376        if (c < 0x0600)     // U+0600 through U+1059 Arabic, Syriac, Thaana, Devanagari, Bengali, Gurmukhi, Gujarati, Oriya, Tamil, Telugu, Kannada, Malayalam, Sinhala, Thai, Lao, Tibetan, Myanmar
377            continue;
378        if (c <= 0x1059)
379            return false;
380
381        if (c < 0x1100)     // U+1100 through U+11FF Hangul Jamo (only Ancient Korean should be left here if you precompose; Modern Korean will be precomposed as a result of step A)
382            continue;
383        if (c <= 0x11FF)
384            return false;
385
386        if (c < 0x1780)     // U+1780 through U+18AF Khmer, Mongolian
387            continue;
388        if (c <= 0x18AF)
389            return false;
390
391        if (c < 0x1900)     // U+1900 through U+194F Limbu (Unicode 4.0)
392            continue;
393        if (c <= 0x194F)
394            return false;
395
396        if (c < 0x20D0)     // U+20D0 through U+20FF Combining marks for symbols
397            continue;
398        if (c <= 0x20FF)
399            return false;
400
401        if (c < 0xFE20)     // U+FE20 through U+FE2F Combining half marks
402            continue;
403        if (c <= 0xFE2F)
404            return false;
405    }
406
407    return true;
408
409}
410
411void Font::drawSimpleText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, int from, int to) const
412{
413    // This glyph buffer holds our glyphs+advances+font data for each glyph.
414    GlyphBuffer glyphBuffer;
415
416    float startX = point.x();
417    WidthIterator it(this, run);
418    it.advance(from);
419    float beforeWidth = it.m_runWidthSoFar;
420#ifdef ANDROID_GLYPHBUFFER_HAS_ADJUSTED_WIDTHS
421    bool adjustedWidths =
422#endif
423    it.advance(to, &glyphBuffer);
424
425    // We couldn't generate any glyphs for the run.  Give up.
426    if (glyphBuffer.isEmpty())
427        return;
428
429    float afterWidth = it.m_runWidthSoFar;
430
431    if (run.rtl()) {
432        float finalRoundingWidth = it.m_finalRoundingWidth;
433        it.advance(run.length());
434        startX += finalRoundingWidth + it.m_runWidthSoFar - afterWidth;
435#ifdef ANDROID_GLYPHBUFFER_HAS_ADJUSTED_WIDTHS
436        adjustedWidths = true;  // give up on simple/fast case
437#endif
438    } else
439        startX += beforeWidth;
440
441    // Swap the order of the glyphs if right-to-left.
442    if (run.rtl())
443        for (int i = 0, end = glyphBuffer.size() - 1; i < glyphBuffer.size() / 2; ++i, --end)
444            glyphBuffer.swap(i, end);
445
446#ifdef ANDROID_GLYPHBUFFER_HAS_ADJUSTED_WIDTHS
447    // mark the GlyphBuffer as having adjusted widths or not
448    // used by drawGlyph as an optimization hint
449    glyphBuffer.setHasAdjustedWidths(adjustedWidths);
450#endif
451    // Calculate the starting point of the glyphs to be displayed by adding
452    // all the advances up to the first glyph.
453    FloatPoint startPoint(startX, point.y());
454    drawGlyphBuffer(context, glyphBuffer, run, startPoint);
455}
456
457void Font::drawGlyphBuffer(GraphicsContext* context, const GlyphBuffer& glyphBuffer,
458                           const TextRun& run, const FloatPoint& point) const
459{
460    // Draw each contiguous run of glyphs that use the same font data.
461    const SimpleFontData* fontData = glyphBuffer.fontDataAt(0);
462    FloatSize offset = glyphBuffer.offsetAt(0);
463    FloatPoint startPoint(point);
464    float nextX = startPoint.x();
465    int lastFrom = 0;
466    int nextGlyph = 0;
467    while (nextGlyph < glyphBuffer.size()) {
468        const SimpleFontData* nextFontData = glyphBuffer.fontDataAt(nextGlyph);
469        FloatSize nextOffset = glyphBuffer.offsetAt(nextGlyph);
470        if (nextFontData != fontData || nextOffset != offset) {
471            drawGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint);
472
473            lastFrom = nextGlyph;
474            fontData = nextFontData;
475            offset = nextOffset;
476            startPoint.setX(nextX);
477        }
478        nextX += glyphBuffer.advanceAt(nextGlyph);
479        nextGlyph++;
480    }
481
482    drawGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint);
483}
484
485void Font::drawText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, int from, int to) const
486{
487    // Don't draw anything while we are using custom fonts that are in the process of loading.
488    if (m_fontList && m_fontList->loadingCustomFonts())
489        return;
490
491    to = (to == -1 ? run.length() : to);
492
493#if ENABLE(SVG_FONTS)
494    if (primaryFont()->isSVGFont()) {
495        drawTextUsingSVGFont(context, run, point, from, to);
496        return;
497    }
498#endif
499
500    if (canUseGlyphCache(run))
501        drawSimpleText(context, run, point, from, to);
502    else
503        drawComplexText(context, run, point, from, to);
504}
505
506float Font::floatWidth(const TextRun& run) const
507{
508#if ENABLE(SVG_FONTS)
509    if (primaryFont()->isSVGFont())
510        return floatWidthUsingSVGFont(run);
511#endif
512
513    if (canUseGlyphCache(run))
514        return floatWidthForSimpleText(run, 0);
515    return floatWidthForComplexText(run);
516}
517
518float Font::floatWidth(const TextRun& run, int extraCharsAvailable, int& charsConsumed, String& glyphName) const
519{
520#if ENABLE(SVG_FONTS)
521    if (primaryFont()->isSVGFont())
522        return floatWidthUsingSVGFont(run, extraCharsAvailable, charsConsumed, glyphName);
523#endif
524
525    charsConsumed = run.length();
526    glyphName = "";
527    if (canUseGlyphCache(run))
528        return floatWidthForSimpleText(run, 0);
529    return floatWidthForComplexText(run);
530}
531
532float Font::floatWidthForSimpleText(const TextRun& run, GlyphBuffer* glyphBuffer) const
533{
534    WidthIterator it(this, run);
535    it.advance(run.length(), glyphBuffer);
536    return it.m_runWidthSoFar;
537}
538
539FloatRect Font::selectionRectForText(const TextRun& run, const IntPoint& point, int h, int from, int to) const
540{
541#if ENABLE(SVG_FONTS)
542    if (primaryFont()->isSVGFont())
543        return selectionRectForTextUsingSVGFont(run, point, h, from, to);
544#endif
545
546    to = (to == -1 ? run.length() : to);
547    if (canUseGlyphCache(run))
548        return selectionRectForSimpleText(run, point, h, from, to);
549    return selectionRectForComplexText(run, point, h, from, to);
550}
551
552FloatRect Font::selectionRectForSimpleText(const TextRun& run, const IntPoint& point, int h, int from, int to) const
553{
554    WidthIterator it(this, run);
555    it.advance(from);
556    float beforeWidth = it.m_runWidthSoFar;
557    it.advance(to);
558    float afterWidth = it.m_runWidthSoFar;
559
560    // Using roundf() rather than ceilf() for the right edge as a compromise to ensure correct caret positioning
561    if (run.rtl()) {
562        it.advance(run.length());
563        float totalWidth = it.m_runWidthSoFar;
564        return FloatRect(point.x() + floorf(totalWidth - afterWidth), point.y(), roundf(totalWidth - beforeWidth) - floorf(totalWidth - afterWidth), h);
565    } else {
566        return FloatRect(point.x() + floorf(beforeWidth), point.y(), roundf(afterWidth) - floorf(beforeWidth), h);
567    }
568}
569
570int Font::offsetForPosition(const TextRun& run, int x, bool includePartialGlyphs) const
571{
572#if ENABLE(SVG_FONTS)
573    if (primaryFont()->isSVGFont())
574        return offsetForPositionForTextUsingSVGFont(run, x, includePartialGlyphs);
575#endif
576
577    if (canUseGlyphCache(run))
578        return offsetForPositionForSimpleText(run, x, includePartialGlyphs);
579    return offsetForPositionForComplexText(run, x, includePartialGlyphs);
580}
581
582int Font::offsetForPositionForSimpleText(const TextRun& run, int x, bool includePartialGlyphs) const
583{
584    float delta = (float)x;
585
586    WidthIterator it(this, run);
587    GlyphBuffer localGlyphBuffer;
588    unsigned offset;
589    if (run.rtl()) {
590        delta -= floatWidthForSimpleText(run, 0);
591        while (1) {
592            offset = it.m_currentCharacter;
593            float w;
594            if (!it.advanceOneCharacter(w, &localGlyphBuffer))
595                break;
596            delta += w;
597            if (includePartialGlyphs) {
598                if (delta - w / 2 >= 0)
599                    break;
600            } else {
601                if (delta >= 0)
602                    break;
603            }
604        }
605    } else {
606        while (1) {
607            offset = it.m_currentCharacter;
608            float w;
609            if (!it.advanceOneCharacter(w, &localGlyphBuffer))
610                break;
611            delta -= w;
612            if (includePartialGlyphs) {
613                if (delta + w / 2 <= 0)
614                    break;
615            } else {
616                if (delta <= 0)
617                    break;
618            }
619        }
620    }
621
622    return offset;
623}
624
625#if ENABLE(SVG_FONTS)
626bool Font::isSVGFont() const
627{
628    return primaryFont()->isSVGFont();
629}
630#endif
631
632FontSelector* Font::fontSelector() const
633{
634    return m_fontList ? m_fontList->fontSelector() : 0;
635}
636
637}
638