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.
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.
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.
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.
27
#include "FloatRect.h"
28
#include "FontCache.h"
29
#include "FontTranscoder.h"
31
#include "GlyphBuffer.h"
33
#include "WidthIterator.h"
34
#include <wtf/MainThread.h>
35
#include <wtf/MathExtras.h>
36
#include <wtf/text/StringBuilder.h>
37
#include <wtf/UnusedParam.h>
40
using namespace Unicode;
44
// allow compilation of OwnPtr<TextLayout> in source files that don't have access to the TextLayout class definition
45
template <> void deleteOwnedPtr<WebCore::TextLayout>(WebCore::TextLayout* ptr)
47
WebCore::Font::deleteLayout(ptr);
54
const uint8_t Font::s_roundingHackCharacterTable[256] = {
55
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,
56
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 /*?*/,
57
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,
58
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,
59
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,
60
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,
61
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,
62
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
65
Font::CodePath Font::s_codePath = Auto;
67
TypesettingFeatures Font::s_defaultTypesettingFeatures = 0;
69
// ============================================================================================
70
// Font Implementation (Cross-Platform Portion)
71
// ============================================================================================
76
, m_isPlatformFont(false)
77
, m_needsTranscoding(false)
78
, m_typesettingFeatures(0)
82
Font::Font(const FontDescription& fd, short letterSpacing, short wordSpacing)
83
: m_fontDescription(fd)
84
, m_letterSpacing(letterSpacing)
85
, m_wordSpacing(wordSpacing)
86
, m_isPlatformFont(false)
87
, m_needsTranscoding(fontTranscoder().needsTranscoding(fd))
88
, m_typesettingFeatures(computeTypesettingFeatures())
92
Font::Font(const FontPlatformData& fontData, bool isPrinterFont, FontSmoothingMode fontSmoothingMode)
93
: m_fontFallbackList(FontFallbackList::create())
96
, m_isPlatformFont(true)
97
, m_typesettingFeatures(computeTypesettingFeatures())
99
m_fontDescription.setUsePrinterFont(isPrinterFont);
100
m_fontDescription.setFontSmoothing(fontSmoothingMode);
101
m_needsTranscoding = fontTranscoder().needsTranscoding(fontDescription());
102
m_fontFallbackList->setPlatformFont(fontData);
105
Font::Font(const Font& other)
106
: m_fontDescription(other.m_fontDescription)
107
, m_fontFallbackList(other.m_fontFallbackList)
108
, m_letterSpacing(other.m_letterSpacing)
109
, m_wordSpacing(other.m_wordSpacing)
110
, m_isPlatformFont(other.m_isPlatformFont)
111
, m_needsTranscoding(other.m_needsTranscoding)
112
, m_typesettingFeatures(computeTypesettingFeatures())
116
Font& Font::operator=(const Font& other)
118
m_fontDescription = other.m_fontDescription;
119
m_fontFallbackList = other.m_fontFallbackList;
120
m_letterSpacing = other.m_letterSpacing;
121
m_wordSpacing = other.m_wordSpacing;
122
m_isPlatformFont = other.m_isPlatformFont;
123
m_needsTranscoding = other.m_needsTranscoding;
124
m_typesettingFeatures = other.m_typesettingFeatures;
128
bool Font::operator==(const Font& other) const
130
// Our FontData don't have to be checked, since checking the font description will be fine.
131
// FIXME: This does not work if the font was made with the FontPlatformData constructor.
132
if (loadingCustomFonts() || other.loadingCustomFonts())
135
FontSelector* first = m_fontFallbackList ? m_fontFallbackList->fontSelector() : 0;
136
FontSelector* second = other.m_fontFallbackList ? other.m_fontFallbackList->fontSelector() : 0;
138
return first == second
139
&& m_fontDescription == other.m_fontDescription
140
&& m_letterSpacing == other.m_letterSpacing
141
&& m_wordSpacing == other.m_wordSpacing
142
&& (m_fontFallbackList ? m_fontFallbackList->fontSelectorVersion() : 0) == (other.m_fontFallbackList ? other.m_fontFallbackList->fontSelectorVersion() : 0)
143
&& (m_fontFallbackList ? m_fontFallbackList->generation() : 0) == (other.m_fontFallbackList ? other.m_fontFallbackList->generation() : 0);
146
void Font::update(PassRefPtr<FontSelector> fontSelector) const
148
// FIXME: It is pretty crazy that we are willing to just poke into a RefPtr, but it ends up
149
// being reasonably safe (because inherited fonts in the render tree pick up the new
150
// style anyway. Other copies are transient, e.g., the state in the GraphicsContext, and
151
// won't stick around long enough to get you in trouble). Still, this is pretty disgusting,
152
// and could eventually be rectified by using RefPtrs for Fonts themselves.
153
if (!m_fontFallbackList)
154
m_fontFallbackList = FontFallbackList::create();
155
m_fontFallbackList->invalidate(fontSelector);
156
m_typesettingFeatures = computeTypesettingFeatures();
159
void Font::drawText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, int from, int to, CustomFontNotReadyAction customFontNotReadyAction) const
161
// Don't draw anything while we are using custom fonts that are in the process of loading,
162
// except if the 'force' argument is set to true (in which case it will use a fallback
164
if (loadingCustomFonts() && customFontNotReadyAction == DoNotPaintIfFontNotReady)
167
to = (to == -1 ? run.length() : to);
169
CodePath codePathToUse = codePath(run);
170
// FIXME: Use the fast code path once it handles partial runs with kerning and ligatures. See http://webkit.org/b/100050
171
if (codePathToUse != Complex && typesettingFeatures() && (from || to != run.length()))
172
codePathToUse = Complex;
174
if (codePathToUse != Complex)
175
return drawSimpleText(context, run, point, from, to);
177
return drawComplexText(context, run, point, from, to);
180
void Font::drawEmphasisMarks(GraphicsContext* context, const TextRun& run, const AtomicString& mark, const FloatPoint& point, int from, int to) const
182
if (loadingCustomFonts())
188
CodePath codePathToUse = codePath(run);
189
// FIXME: Use the fast code path once it handles partial runs with kerning and ligatures. See http://webkit.org/b/100050
190
if (codePathToUse != Complex && typesettingFeatures() && (from || to != run.length()))
191
codePathToUse = Complex;
193
if (codePathToUse != Complex)
194
drawEmphasisMarksForSimpleText(context, run, mark, point, from, to);
196
drawEmphasisMarksForComplexText(context, run, mark, point, from, to);
199
float Font::width(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const
201
CodePath codePathToUse = codePath(run);
202
if (codePathToUse != Complex) {
203
// The complex path is more restrictive about returning fallback fonts than the simple path, so we need an explicit test to make their behaviors match.
204
if (!canReturnFallbackFontsForComplexText())
206
// The simple path can optimize the case where glyph overflow is not observable.
207
if (codePathToUse != SimpleWithGlyphOverflow && (glyphOverflow && !glyphOverflow->computeBounds))
211
bool hasKerningOrLigatures = typesettingFeatures() & (Kerning | Ligatures);
212
bool hasWordSpacingOrLetterSpacing = wordSpacing() | letterSpacing();
213
float* cacheEntry = m_fontFallbackList->widthCache().add(run, std::numeric_limits<float>::quiet_NaN(), hasKerningOrLigatures, hasWordSpacingOrLetterSpacing, glyphOverflow);
214
if (cacheEntry && !isnan(*cacheEntry))
218
if (codePathToUse == Complex)
219
result = floatWidthForComplexText(run, fallbackFonts, glyphOverflow);
221
result = floatWidthForSimpleText(run, fallbackFonts, glyphOverflow);
223
if (cacheEntry && (!fallbackFonts || fallbackFonts->isEmpty()))
224
*cacheEntry = result;
228
float Font::width(const TextRun& run, int& charsConsumed, String& glyphName) const
230
#if ENABLE(SVG_FONTS)
231
if (TextRun::RenderingContext* renderingContext = run.renderingContext())
232
return renderingContext->floatWidthUsingSVGFont(*this, run, charsConsumed, glyphName);
235
charsConsumed = run.length();
240
#if !(PLATFORM(MAC) || (PLATFORM(CHROMIUM) && OS(DARWIN)))
242
PassOwnPtr<TextLayout> Font::createLayout(RenderText*, float, bool) const
247
void Font::deleteLayout(TextLayout*)
251
float Font::width(TextLayout&, unsigned, unsigned, HashSet<const SimpleFontData*>*)
253
ASSERT_NOT_REACHED();
259
FloatRect Font::selectionRectForText(const TextRun& run, const FloatPoint& point, int h, int from, int to) const
261
to = (to == -1 ? run.length() : to);
263
CodePath codePathToUse = codePath(run);
264
// FIXME: Use the fast code path once it handles partial runs with kerning and ligatures. See http://webkit.org/b/100050
265
if (codePathToUse != Complex && typesettingFeatures() && (from || to != run.length()))
266
codePathToUse = Complex;
268
if (codePathToUse != Complex)
269
return selectionRectForSimpleText(run, point, h, from, to);
271
return selectionRectForComplexText(run, point, h, from, to);
274
int Font::offsetForPosition(const TextRun& run, float x, bool includePartialGlyphs) const
276
// FIXME: Use the fast code path once it handles partial runs with kerning and ligatures. See http://webkit.org/b/100050
277
if (codePath(run) != Complex && !typesettingFeatures())
278
return offsetForPositionForSimpleText(run, x, includePartialGlyphs);
280
return offsetForPositionForComplexText(run, x, includePartialGlyphs);
283
template <typename CharacterType>
284
static inline String normalizeSpacesInternal(const CharacterType* characters, unsigned length)
286
StringBuilder normalized;
287
normalized.reserveCapacity(length);
289
for (unsigned i = 0; i < length; ++i)
290
normalized.append(Font::normalizeSpaces(characters[i]));
292
return normalized.toString();
295
String Font::normalizeSpaces(const LChar* characters, unsigned length)
297
return normalizeSpacesInternal(characters, length);
300
String Font::normalizeSpaces(const UChar* characters, unsigned length)
302
return normalizeSpacesInternal(characters, length);
305
static bool shouldUseFontSmoothing = true;
307
void Font::setShouldUseSmoothing(bool shouldUseSmoothing)
309
ASSERT(isMainThread());
310
shouldUseFontSmoothing = shouldUseSmoothing;
313
bool Font::shouldUseSmoothing()
315
return shouldUseFontSmoothing;
318
void Font::setCodePath(CodePath p)
323
Font::CodePath Font::codePath()
328
void Font::setDefaultTypesettingFeatures(TypesettingFeatures typesettingFeatures)
330
s_defaultTypesettingFeatures = typesettingFeatures;
333
TypesettingFeatures Font::defaultTypesettingFeatures()
335
return s_defaultTypesettingFeatures;
338
Font::CodePath Font::codePath(const TextRun& run) const
340
if (s_codePath != Auto)
343
#if ENABLE(SVG_FONTS)
344
if (run.renderingContext())
348
#if PLATFORM(QT) && !HAVE(QRAWFONT)
349
if (run.expansion() || run.rtl() || isSmallCaps() || wordSpacing() || letterSpacing())
353
if (m_fontDescription.featureSettings() && m_fontDescription.featureSettings()->size() > 0)
356
if (run.length() > 1 && !WidthIterator::supportsTypesettingFeatures(*this))
359
if (!run.characterScanForCodePath())
365
// Start from 0 since drawing and highlighting also measure the characters before run->from.
366
return characterRangeCodePath(run.characters16(), run.length());
369
Font::CodePath Font::characterRangeCodePath(const UChar* characters, unsigned len)
371
// FIXME: Should use a UnicodeSet in ports where ICU is used. Note that we
372
// can't simply use UnicodeCharacter Property/class because some characters
373
// are not 'combining', but still need to go to the complex path.
374
// Alternatively, we may as well consider binary search over a sorted
376
CodePath result = Simple;
377
for (unsigned i = 0; i < len; i++) {
378
const UChar c = characters[i];
379
if (c < 0x2E5) // U+02E5 through U+02E9 (Modifier Letters : Tone letters)
384
if (c < 0x300) // U+0300 through U+036F Combining diacritical marks
389
if (c < 0x0591 || c == 0x05BE) // U+0591 through U+05CF excluding U+05BE Hebrew combining marks, Hebrew punctuation Paseq, Sof Pasuq and Nun Hafukha
394
// U+0600 through U+109F Arabic, Syriac, Thaana, NKo, Samaritan, Mandaic,
395
// Devanagari, Bengali, Gurmukhi, Gujarati, Oriya, Tamil, Telugu, Kannada,
396
// Malayalam, Sinhala, Thai, Lao, Tibetan, Myanmar
402
// U+1100 through U+11FF Hangul Jamo (only Ancient Korean should be left here if you precompose;
403
// Modern Korean will be precomposed as a result of step A)
409
if (c < 0x135D) // U+135D through U+135F Ethiopic combining marks
414
if (c < 0x1700) // U+1780 through U+18AF Tagalog, Hanunoo, Buhid, Taghanwa,Khmer, Mongolian
419
if (c < 0x1900) // U+1900 through U+194F Limbu (Unicode 4.0)
424
if (c < 0x1980) // U+1980 through U+19DF New Tai Lue
429
if (c < 0x1A00) // U+1A00 through U+1CFF Buginese, Tai Tham, Balinese, Batak, Lepcha, Vedic
434
if (c < 0x1DC0) // U+1DC0 through U+1DFF Comining diacritical mark supplement
439
// U+1E00 through U+2000 characters with diacritics and stacked diacritics
441
result = SimpleWithGlyphOverflow;
445
if (c < 0x20D0) // U+20D0 through U+20FF Combining marks for symbols
450
if (c < 0x2CEF) // U+2CEF through U+2CF1 Combining marks for Coptic
455
if (c < 0x302A) // U+302A through U+302F Ideographic and Hangul Tone marks
460
if (c < 0xA67C) // U+A67C through U+A67D Combining marks for old Cyrillic
465
if (c < 0xA6F0) // U+A6F0 through U+A6F1 Combining mark for Bamum
470
// U+A800 through U+ABFF Nagri, Phags-pa, Saurashtra, Devanagari Extended,
471
// Hangul Jamo Ext. A, Javanese, Myanmar Extended A, Tai Viet, Meetei Mayek,
477
if (c < 0xD7B0) // U+D7B0 through U+D7FF Hangul Jamo Ext. B
488
UChar next = characters[++i];
489
if (!U16_IS_TRAIL(next))
492
UChar32 supplementaryCharacter = U16_GET_SUPPLEMENTARY(c, next);
494
if (supplementaryCharacter < 0x1F1E6) // U+1F1E6 through U+1F1FF Regional Indicator Symbols
496
if (supplementaryCharacter <= 0x1F1FF)
499
if (supplementaryCharacter < 0xE0100) // U+E0100 through U+E01EF Unicode variation selectors.
501
if (supplementaryCharacter <= 0xE01EF)
504
// FIXME: Check for Brahmi (U+11000 block), Kaithi (U+11080 block) and other complex scripts
505
// in plane 1 or higher.
510
if (c < 0xFE00) // U+FE00 through U+FE0F Unicode variation selectors
515
if (c < 0xFE20) // U+FE20 through U+FE2F Combining half marks
523
bool Font::isCJKIdeograph(UChar32 c)
525
// The basic CJK Unified Ideographs block.
526
if (c >= 0x4E00 && c <= 0x9FFF)
529
// CJK Unified Ideographs Extension A.
530
if (c >= 0x3400 && c <= 0x4DBF)
533
// CJK Radicals Supplement.
534
if (c >= 0x2E80 && c <= 0x2EFF)
538
if (c >= 0x2F00 && c <= 0x2FDF)
542
if (c >= 0x31C0 && c <= 0x31EF)
545
// CJK Compatibility Ideographs.
546
if (c >= 0xF900 && c <= 0xFAFF)
549
// CJK Unified Ideographs Extension B.
550
if (c >= 0x20000 && c <= 0x2A6DF)
553
// CJK Unified Ideographs Extension C.
554
if (c >= 0x2A700 && c <= 0x2B73F)
557
// CJK Unified Ideographs Extension D.
558
if (c >= 0x2B740 && c <= 0x2B81F)
561
// CJK Compatibility Ideographs Supplement.
562
if (c >= 0x2F800 && c <= 0x2FA1F)
568
bool Font::isCJKIdeographOrSymbol(UChar32 c)
570
// 0x2C7 Caron, Mandarin Chinese 3rd Tone
571
// 0x2CA Modifier Letter Acute Accent, Mandarin Chinese 2nd Tone
572
// 0x2CB Modifier Letter Grave Access, Mandarin Chinese 4th Tone
573
// 0x2D9 Dot Above, Mandarin Chinese 5th Tone
574
if ((c == 0x2C7) || (c == 0x2CA) || (c == 0x2CB) || (c == 0x2D9))
577
// Ideographic Description Characters.
578
if (c >= 0x2FF0 && c <= 0x2FFF)
581
// CJK Symbols and Punctuation.
582
if (c >= 0x3000 && c <= 0x303F)
586
if (c >= 0x3040 && c <= 0x309F)
590
if (c >= 0x30A0 && c <= 0x30FF)
594
if (c >= 0x3100 && c <= 0x312F)
598
if (c >= 0x31A0 && c <= 0x31BF)
601
// Enclosed CJK Letters and Months.
602
if (c >= 0x3200 && c <= 0x32FF)
605
// CJK Compatibility.
606
if (c >= 0x3300 && c <= 0x33FF)
609
// CJK Compatibility Forms.
610
if (c >= 0xFE30 && c <= 0xFE4F)
613
// Halfwidth and Fullwidth Forms
614
// Usually only used in CJK
615
if (c >= 0xFF00 && c <= 0xFFEF)
619
if (c >= 0x1F200 && c <= 0x1F6F)
622
return isCJKIdeograph(c);
625
unsigned Font::expansionOpportunityCount(const LChar* characters, size_t length, TextDirection direction, bool& isAfterExpansion)
628
if (direction == LTR) {
629
for (size_t i = 0; i < length; ++i) {
630
if (treatAsSpace(characters[i])) {
632
isAfterExpansion = true;
634
isAfterExpansion = false;
637
for (size_t i = length; i > 0; --i) {
638
if (treatAsSpace(characters[i - 1])) {
640
isAfterExpansion = true;
642
isAfterExpansion = false;
648
unsigned Font::expansionOpportunityCount(const UChar* characters, size_t length, TextDirection direction, bool& isAfterExpansion)
650
static bool expandAroundIdeographs = canExpandAroundIdeographsInComplexText();
652
if (direction == LTR) {
653
for (size_t i = 0; i < length; ++i) {
654
UChar32 character = characters[i];
655
if (treatAsSpace(character)) {
657
isAfterExpansion = true;
660
if (U16_IS_LEAD(character) && i + 1 < length && U16_IS_TRAIL(characters[i + 1])) {
661
character = U16_GET_SUPPLEMENTARY(character, characters[i + 1]);
664
if (expandAroundIdeographs && isCJKIdeographOrSymbol(character)) {
665
if (!isAfterExpansion)
668
isAfterExpansion = true;
671
isAfterExpansion = false;
674
for (size_t i = length; i > 0; --i) {
675
UChar32 character = characters[i - 1];
676
if (treatAsSpace(character)) {
678
isAfterExpansion = true;
681
if (U16_IS_TRAIL(character) && i > 1 && U16_IS_LEAD(characters[i - 2])) {
682
character = U16_GET_SUPPLEMENTARY(characters[i - 2], character);
685
if (expandAroundIdeographs && isCJKIdeographOrSymbol(character)) {
686
if (!isAfterExpansion)
689
isAfterExpansion = true;
692
isAfterExpansion = false;
698
bool Font::canReceiveTextEmphasis(UChar32 c)
700
CharCategory category = Unicode::category(c);
701
if (category & (Separator_Space | Separator_Line | Separator_Paragraph | Other_NotAssigned | Other_Control | Other_Format))
704
// Additional word-separator characters listed in CSS Text Level 3 Editor's Draft 3 November 2010.
705
if (c == ethiopicWordspace || c == aegeanWordSeparatorLine || c == aegeanWordSeparatorDot
706
|| c == ugariticWordDivider || c == tibetanMarkIntersyllabicTsheg || c == tibetanMarkDelimiterTshegBstar)