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, 2010, 2011 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 "FloatRect.h"
28#include "FontCache.h"
29#include "FontTranscoder.h"
30#include "IntPoint.h"
31#include "GlyphBuffer.h"
32#include "TextRun.h"
33#include "WidthIterator.h"
34#include <wtf/MathExtras.h>
35#include <wtf/UnusedParam.h>
36
37using namespace WTF;
38using namespace Unicode;
39
40namespace WebCore {
41
42Font::CodePath Font::s_codePath = Auto;
43
44// ============================================================================================
45// Font Implementation (Cross-Platform Portion)
46// ============================================================================================
47
48Font::Font()
49    : m_letterSpacing(0)
50    , m_wordSpacing(0)
51    , m_isPlatformFont(false)
52    , m_needsTranscoding(false)
53{
54}
55
56Font::Font(const FontDescription& fd, short letterSpacing, short wordSpacing)
57    : m_fontDescription(fd)
58    , m_letterSpacing(letterSpacing)
59    , m_wordSpacing(wordSpacing)
60    , m_isPlatformFont(false)
61    , m_needsTranscoding(fontTranscoder().needsTranscoding(fd))
62{
63}
64
65Font::Font(const FontPlatformData& fontData, bool isPrinterFont, FontSmoothingMode fontSmoothingMode)
66    : m_fontList(FontFallbackList::create())
67    , m_letterSpacing(0)
68    , m_wordSpacing(0)
69    , m_isPlatformFont(true)
70{
71    m_fontDescription.setUsePrinterFont(isPrinterFont);
72    m_fontDescription.setFontSmoothing(fontSmoothingMode);
73    m_needsTranscoding = fontTranscoder().needsTranscoding(fontDescription());
74    m_fontList->setPlatformFont(fontData);
75}
76
77Font::Font(const Font& other)
78    : m_fontDescription(other.m_fontDescription)
79    , m_fontList(other.m_fontList)
80    , m_letterSpacing(other.m_letterSpacing)
81    , m_wordSpacing(other.m_wordSpacing)
82    , m_isPlatformFont(other.m_isPlatformFont)
83    , m_needsTranscoding(fontTranscoder().needsTranscoding(other.m_fontDescription))
84{
85}
86
87Font& Font::operator=(const Font& other)
88{
89    m_fontDescription = other.m_fontDescription;
90    m_fontList = other.m_fontList;
91    m_letterSpacing = other.m_letterSpacing;
92    m_wordSpacing = other.m_wordSpacing;
93    m_isPlatformFont = other.m_isPlatformFont;
94    m_needsTranscoding = other.m_needsTranscoding;
95    return *this;
96}
97
98bool Font::operator==(const Font& other) const
99{
100    // Our FontData don't have to be checked, since checking the font description will be fine.
101    // FIXME: This does not work if the font was made with the FontPlatformData constructor.
102    if (loadingCustomFonts() || other.loadingCustomFonts())
103        return false;
104
105    FontSelector* first = m_fontList ? m_fontList->fontSelector() : 0;
106    FontSelector* second = other.m_fontList ? other.m_fontList->fontSelector() : 0;
107
108    return first == second
109           && m_fontDescription == other.m_fontDescription
110           && m_letterSpacing == other.m_letterSpacing
111           && m_wordSpacing == other.m_wordSpacing
112           && (m_fontList ? m_fontList->generation() : 0) == (other.m_fontList ? other.m_fontList->generation() : 0);
113}
114
115void Font::update(PassRefPtr<FontSelector> fontSelector) const
116{
117    // FIXME: It is pretty crazy that we are willing to just poke into a RefPtr, but it ends up
118    // being reasonably safe (because inherited fonts in the render tree pick up the new
119    // style anyway. Other copies are transient, e.g., the state in the GraphicsContext, and
120    // won't stick around long enough to get you in trouble). Still, this is pretty disgusting,
121    // and could eventually be rectified by using RefPtrs for Fonts themselves.
122    if (!m_fontList)
123        m_fontList = FontFallbackList::create();
124    m_fontList->invalidate(fontSelector);
125}
126
127void Font::drawText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, int from, int to) const
128{
129    // Don't draw anything while we are using custom fonts that are in the process of loading.
130    if (loadingCustomFonts())
131        return;
132
133    to = (to == -1 ? run.length() : to);
134
135#if ENABLE(SVG_FONTS)
136    if (primaryFont()->isSVGFont()) {
137        drawTextUsingSVGFont(context, run, point, from, to);
138        return;
139    }
140#endif
141
142    if (codePath(run) != Complex)
143        return drawSimpleText(context, run, point, from, to);
144
145    return drawComplexText(context, run, point, from, to);
146}
147
148void Font::drawEmphasisMarks(GraphicsContext* context, const TextRun& run, const AtomicString& mark, const FloatPoint& point, int from, int to) const
149{
150    if (loadingCustomFonts())
151        return;
152
153    if (to < 0)
154        to = run.length();
155
156#if ENABLE(SVG_FONTS)
157    // FIXME: Implement for SVG fonts.
158    if (primaryFont()->isSVGFont())
159        return;
160#endif
161
162    if (codePath(run) != Complex)
163        drawEmphasisMarksForSimpleText(context, run, mark, point, from, to);
164    else
165        drawEmphasisMarksForComplexText(context, run, mark, point, from, to);
166}
167
168float Font::width(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const
169{
170#if ENABLE(SVG_FONTS)
171    if (primaryFont()->isSVGFont())
172        return floatWidthUsingSVGFont(run);
173#endif
174
175    CodePath codePathToUse = codePath(run);
176    if (codePathToUse != Complex) {
177        // If the complex text implementation cannot return fallback fonts, avoid
178        // returning them for simple text as well.
179        static bool returnFallbackFonts = canReturnFallbackFontsForComplexText();
180        return floatWidthForSimpleText(run, 0, returnFallbackFonts ? fallbackFonts : 0, codePathToUse == SimpleWithGlyphOverflow || (glyphOverflow && glyphOverflow->computeBounds) ? glyphOverflow : 0);
181    }
182
183    return floatWidthForComplexText(run, fallbackFonts, glyphOverflow);
184}
185
186float Font::width(const TextRun& run, int extraCharsAvailable, int& charsConsumed, String& glyphName) const
187{
188#if !ENABLE(SVG_FONTS)
189    UNUSED_PARAM(extraCharsAvailable);
190#else
191    if (primaryFont()->isSVGFont())
192        return floatWidthUsingSVGFont(run, extraCharsAvailable, charsConsumed, glyphName);
193#endif
194
195    charsConsumed = run.length();
196    glyphName = "";
197
198    if (codePath(run) != Complex)
199        return floatWidthForSimpleText(run, 0);
200
201    return floatWidthForComplexText(run);
202}
203
204FloatRect Font::selectionRectForText(const TextRun& run, const FloatPoint& point, int h, int from, int to) const
205{
206#if ENABLE(SVG_FONTS)
207    if (primaryFont()->isSVGFont())
208        return selectionRectForTextUsingSVGFont(run, point, h, from, to);
209#endif
210
211    to = (to == -1 ? run.length() : to);
212
213    if (codePath(run) != Complex)
214        return selectionRectForSimpleText(run, point, h, from, to);
215
216    return selectionRectForComplexText(run, point, h, from, to);
217}
218
219int Font::offsetForPosition(const TextRun& run, float x, bool includePartialGlyphs) const
220{
221#if ENABLE(SVG_FONTS)
222    if (primaryFont()->isSVGFont())
223        return offsetForPositionForTextUsingSVGFont(run, x, includePartialGlyphs);
224#endif
225
226    if (codePath(run) != Complex)
227        return offsetForPositionForSimpleText(run, x, includePartialGlyphs);
228
229    return offsetForPositionForComplexText(run, x, includePartialGlyphs);
230}
231
232#if ENABLE(SVG_FONTS)
233bool Font::isSVGFont() const
234{
235    return primaryFont()->isSVGFont();
236}
237#endif
238
239String Font::normalizeSpaces(const UChar* characters, unsigned length)
240{
241    UChar* buffer;
242    String normalized = String::createUninitialized(length, buffer);
243
244    for (unsigned i = 0; i < length; ++i)
245        buffer[i] = normalizeSpaces(characters[i]);
246
247    return normalized;
248}
249
250static bool shouldUseFontSmoothing = true;
251
252void Font::setShouldUseSmoothing(bool shouldUseSmoothing)
253{
254    ASSERT(isMainThread());
255    shouldUseFontSmoothing = shouldUseSmoothing;
256}
257
258bool Font::shouldUseSmoothing()
259{
260    return shouldUseFontSmoothing;
261}
262
263void Font::setCodePath(CodePath p)
264{
265    s_codePath = p;
266}
267
268Font::CodePath Font::codePath()
269{
270    return s_codePath;
271}
272
273Font::CodePath Font::codePath(const TextRun& run) const
274{
275    if (s_codePath != Auto)
276        return s_codePath;
277
278#if PLATFORM(QT)
279    if (run.expansion() || run.rtl() || isSmallCaps() || wordSpacing() || letterSpacing())
280        return Complex;
281#endif
282
283    CodePath result = Simple;
284
285    // Start from 0 since drawing and highlighting also measure the characters before run->from
286    for (int i = 0; i < run.length(); i++) {
287        const UChar c = run[i];
288        if (c < 0x300) // U+0300 through U+036F Combining diacritical marks
289            continue;
290        if (c <= 0x36F)
291            return Complex;
292
293        if (c < 0x0591 || c == 0x05BE) // U+0591 through U+05CF excluding U+05BE Hebrew combining marks, Hebrew punctuation Paseq, Sof Pasuq and Nun Hafukha
294            continue;
295        if (c <= 0x05CF)
296            return Complex;
297
298        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
299            continue;
300        if (c <= 0x1059)
301            return Complex;
302
303        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)
304            continue;
305        if (c <= 0x11FF)
306            return Complex;
307
308        if (c < 0x1780) // U+1780 through U+18AF Khmer, Mongolian
309            continue;
310        if (c <= 0x18AF)
311            return Complex;
312
313        if (c < 0x1900) // U+1900 through U+194F Limbu (Unicode 4.0)
314            continue;
315        if (c <= 0x194F)
316            return Complex;
317
318        if (c < 0x1E00) // U+1E00 through U+2000 characters with diacritics and stacked diacritics
319            continue;
320        if (c <= 0x2000) {
321            result = SimpleWithGlyphOverflow;
322            continue;
323        }
324
325        if (c < 0x20D0) // U+20D0 through U+20FF Combining marks for symbols
326            continue;
327        if (c <= 0x20FF)
328            return Complex;
329
330        if (c < 0xFE20) // U+FE20 through U+FE2F Combining half marks
331            continue;
332        if (c <= 0xFE2F)
333            return Complex;
334    }
335
336    if (typesettingFeatures())
337        return Complex;
338
339    return result;
340}
341
342bool Font::isCJKIdeograph(UChar32 c)
343{
344    // The basic CJK Unified Ideographs block.
345    if (c >= 0x4E00 && c <= 0x9FFF)
346        return true;
347
348    // CJK Unified Ideographs Extension A.
349    if (c >= 0x3400 && c <= 0x4DBF)
350        return true;
351
352    // CJK Radicals Supplement.
353    if (c >= 0x2E80 && c <= 0x2EFF)
354        return true;
355
356    // Kangxi Radicals.
357    if (c >= 0x2F00 && c <= 0x2FDF)
358        return true;
359
360    // CJK Strokes.
361    if (c >= 0x31C0 && c <= 0x31EF)
362        return true;
363
364    // CJK Compatibility Ideographs.
365    if (c >= 0xF900 && c <= 0xFAFF)
366        return true;
367
368    // CJK Unified Ideographs Extension B.
369    if (c >= 0x20000 && c <= 0x2A6DF)
370        return true;
371
372    // CJK Unified Ideographs Extension C.
373    if (c >= 0x2A700 && c <= 0x2B73F)
374        return true;
375
376    // CJK Unified Ideographs Extension D.
377    if (c >= 0x2B740 && c <= 0x2B81F)
378        return true;
379
380    // CJK Compatibility Ideographs Supplement.
381    if (c >= 0x2F800 && c <= 0x2FA1F)
382        return true;
383
384    return false;
385}
386
387bool Font::isCJKIdeographOrSymbol(UChar32 c)
388{
389    // 0x2C7 Caron, Mandarin Chinese 3rd Tone
390    // 0x2CA Modifier Letter Acute Accent, Mandarin Chinese 2nd Tone
391    // 0x2CB Modifier Letter Grave Access, Mandarin Chinese 4th Tone
392    // 0x2D9 Dot Above, Mandarin Chinese 5th Tone
393    if ((c == 0x2C7) || (c == 0x2CA) || (c == 0x2CB) || (c == 0x2D9))
394        return true;
395
396    // Ideographic Description Characters.
397    if (c >= 0x2FF0 && c <= 0x2FFF)
398        return true;
399
400    // CJK Symbols and Punctuation.
401    if (c >= 0x3000 && c <= 0x303F)
402        return true;
403
404    // Hiragana
405    if (c >= 0x3040 && c <= 0x309F)
406        return true;
407
408    // Katakana
409    if (c >= 0x30A0 && c <= 0x30FF)
410        return true;
411
412    // Bopomofo
413    if (c >= 0x3100 && c <= 0x312F)
414        return true;
415
416    // Bopomofo Extended
417    if (c >= 0x31A0 && c <= 0x31BF)
418        return true;
419
420    // Enclosed CJK Letters and Months.
421    if (c >= 0x3200 && c <= 0x32FF)
422        return true;
423
424    // CJK Compatibility.
425    if (c >= 0x3300 && c <= 0x33FF)
426        return true;
427
428    // CJK Compatibility Forms.
429    if (c >= 0xFE30 && c <= 0xFE4F)
430        return true;
431
432    // Halfwidth and Fullwidth Forms
433    // Usually only used in CJK
434    if (c >= 0xFF00 && c <= 0xFFEF)
435        return true;
436
437    // Emoji.
438    if (c >= 0x1F200 && c <= 0x1F6F)
439        return true;
440
441    return isCJKIdeograph(c);
442}
443
444unsigned Font::expansionOpportunityCount(const UChar* characters, size_t length, TextDirection direction, bool& isAfterExpansion)
445{
446    static bool expandAroundIdeographs = canExpandAroundIdeographsInComplexText();
447    unsigned count = 0;
448    if (direction == LTR) {
449        for (size_t i = 0; i < length; ++i) {
450            UChar32 character = characters[i];
451            if (treatAsSpace(character)) {
452                count++;
453                isAfterExpansion = true;
454                continue;
455            }
456            if (U16_IS_LEAD(character) && i + 1 < length && U16_IS_TRAIL(characters[i + 1])) {
457                character = U16_GET_SUPPLEMENTARY(character, characters[i + 1]);
458                i++;
459            }
460            if (expandAroundIdeographs && isCJKIdeographOrSymbol(character)) {
461                if (!isAfterExpansion)
462                    count++;
463                count++;
464                isAfterExpansion = true;
465                continue;
466            }
467            isAfterExpansion = false;
468        }
469    } else {
470        for (size_t i = length; i > 0; --i) {
471            UChar32 character = characters[i - 1];
472            if (treatAsSpace(character)) {
473                count++;
474                isAfterExpansion = true;
475                continue;
476            }
477            if (U16_IS_TRAIL(character) && i > 1 && U16_IS_LEAD(characters[i - 2])) {
478                character = U16_GET_SUPPLEMENTARY(characters[i - 2], character);
479                i--;
480            }
481            if (expandAroundIdeographs && isCJKIdeographOrSymbol(character)) {
482                if (!isAfterExpansion)
483                    count++;
484                count++;
485                isAfterExpansion = true;
486                continue;
487            }
488            isAfterExpansion = false;
489        }
490    }
491    return count;
492}
493
494bool Font::canReceiveTextEmphasis(UChar32 c)
495{
496    CharCategory category = Unicode::category(c);
497    if (category & (Separator_Space | Separator_Line | Separator_Paragraph | Other_NotAssigned | Other_Control | Other_Format))
498        return false;
499
500    // Additional word-separator characters listed in CSS Text Level 3 Editor's Draft 3 November 2010.
501    if (c == ethiopicWordspace || c == aegeanWordSeparatorLine || c == aegeanWordSeparatorDot
502        || c == ugariticWordDivider || c == tibetanMarkIntersyllabicTsheg || c == tibetanMarkDelimiterTshegBstar)
503        return false;
504
505    return true;
506}
507
508}
509