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.
25 #include "platform/fonts/Font.h"
27 #include "platform/fonts/WidthIterator.h"
28 #include "platform/geometry/FloatRect.h"
29 #include "platform/text/TextRun.h"
30 #include "wtf/MainThread.h"
31 #include "wtf/StdLibExtras.h"
32 #include "wtf/text/StringBuilder.h"
35 using namespace Unicode;
39 const uint8_t Font::s_roundingHackCharacterTable[256] = {
40 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,
41 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 /*?*/,
42 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,
43 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,
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 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,
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 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 static const UChar32 cjkIsolatedSymbolsArray[] = {
51 // 0x2C7 Caron, Mandarin Chinese 3rd Tone
53 // 0x2CA Modifier Letter Acute Accent, Mandarin Chinese 2nd Tone
55 // 0x2CB Modifier Letter Grave Access, Mandarin Chinese 4th Tone
57 // 0x2D9 Dot Above, Mandarin Chinese 5th Tone
59 0x2020, 0x2021, 0x2030, 0x203B, 0x203C, 0x2042, 0x2047, 0x2048, 0x2049, 0x2051,
60 0x20DD, 0x20DE, 0x2100, 0x2103, 0x2105, 0x2109, 0x210A, 0x2113, 0x2116, 0x2121,
61 0x212B, 0x213B, 0x2150, 0x2151, 0x2152, 0x217F, 0x2189, 0x2307, 0x2312, 0x23CE,
62 0x2423, 0x25A0, 0x25A1, 0x25A2, 0x25AA, 0x25AB, 0x25B1, 0x25B2, 0x25B3, 0x25B6,
63 0x25B7, 0x25BC, 0x25BD, 0x25C0, 0x25C1, 0x25C6, 0x25C7, 0x25C9, 0x25CB, 0x25CC,
64 0x25EF, 0x2605, 0x2606, 0x260E, 0x2616, 0x2617, 0x2640, 0x2642, 0x26A0, 0x26BD,
65 0x26BE, 0x2713, 0x271A, 0x273F, 0x2740, 0x2756, 0x2B1A, 0xFE10, 0xFE11, 0xFE12,
71 CodePath Font::s_codePath = AutoPath;
73 TypesettingFeatures Font::s_defaultTypesettingFeatures = 0;
75 // ============================================================================================
76 // Font Implementation (Cross-Platform Portion)
77 // ============================================================================================
82 , m_typesettingFeatures(0)
86 Font::Font(const FontDescription& fd, float letterSpacing, float wordSpacing)
87 : m_fontDescription(fd)
88 , m_letterSpacing(letterSpacing)
89 , m_wordSpacing(wordSpacing)
90 , m_typesettingFeatures(computeTypesettingFeatures())
94 Font::Font(const Font& other)
95 : m_fontDescription(other.m_fontDescription)
96 , m_fontFallbackList(other.m_fontFallbackList)
97 , m_letterSpacing(other.m_letterSpacing)
98 , m_wordSpacing(other.m_wordSpacing)
99 , m_typesettingFeatures(computeTypesettingFeatures())
103 Font& Font::operator=(const Font& other)
105 m_fontDescription = other.m_fontDescription;
106 m_fontFallbackList = other.m_fontFallbackList;
107 m_letterSpacing = other.m_letterSpacing;
108 m_wordSpacing = other.m_wordSpacing;
109 m_typesettingFeatures = other.m_typesettingFeatures;
113 bool Font::operator==(const Font& other) const
115 // Our FontData don't have to be checked, since checking the font description will be fine.
116 // FIXME: This does not work if the font was made with the FontPlatformData constructor.
117 if (loadingCustomFonts() || other.loadingCustomFonts())
120 FontSelector* first = m_fontFallbackList ? m_fontFallbackList->fontSelector() : 0;
121 FontSelector* second = other.m_fontFallbackList ? other.m_fontFallbackList->fontSelector() : 0;
123 return first == second
124 && m_fontDescription == other.m_fontDescription
125 && m_letterSpacing == other.m_letterSpacing
126 && m_wordSpacing == other.m_wordSpacing
127 && (m_fontFallbackList ? m_fontFallbackList->fontSelectorVersion() : 0) == (other.m_fontFallbackList ? other.m_fontFallbackList->fontSelectorVersion() : 0)
128 && (m_fontFallbackList ? m_fontFallbackList->generation() : 0) == (other.m_fontFallbackList ? other.m_fontFallbackList->generation() : 0);
131 void Font::update(PassRefPtr<FontSelector> fontSelector) const
133 // FIXME: It is pretty crazy that we are willing to just poke into a RefPtr, but it ends up
134 // being reasonably safe (because inherited fonts in the render tree pick up the new
135 // style anyway. Other copies are transient, e.g., the state in the GraphicsContext, and
136 // won't stick around long enough to get you in trouble). Still, this is pretty disgusting,
137 // and could eventually be rectified by using RefPtrs for Fonts themselves.
138 if (!m_fontFallbackList)
139 m_fontFallbackList = FontFallbackList::create();
140 m_fontFallbackList->invalidate(fontSelector);
141 m_typesettingFeatures = computeTypesettingFeatures();
144 void Font::drawText(GraphicsContext* context, const TextRunPaintInfo& runInfo, const FloatPoint& point, CustomFontNotReadyAction customFontNotReadyAction) const
146 // Don't draw anything while we are using custom fonts that are in the process of loading,
147 // except if the 'force' argument is set to true (in which case it will use a fallback
149 if (loadingCustomFonts() && customFontNotReadyAction == DoNotPaintIfFontNotReady)
152 CodePath codePathToUse = codePath(runInfo.run);
153 // FIXME: Use the fast code path once it handles partial runs with kerning and ligatures. See http://webkit.org/b/100050
154 if (codePathToUse != ComplexPath && typesettingFeatures() && (runInfo.from || runInfo.to != runInfo.run.length()))
155 codePathToUse = ComplexPath;
157 if (codePathToUse != ComplexPath)
158 return drawSimpleText(context, runInfo, point);
160 return drawComplexText(context, runInfo, point);
163 void Font::drawEmphasisMarks(GraphicsContext* context, const TextRunPaintInfo& runInfo, const AtomicString& mark, const FloatPoint& point) const
165 if (loadingCustomFonts())
168 CodePath codePathToUse = codePath(runInfo.run);
169 // FIXME: Use the fast code path once it handles partial runs with kerning and ligatures. See http://webkit.org/b/100050
170 if (codePathToUse != ComplexPath && typesettingFeatures() && (runInfo.from || runInfo.to != runInfo.run.length()))
171 codePathToUse = ComplexPath;
173 if (codePathToUse != ComplexPath)
174 drawEmphasisMarksForSimpleText(context, runInfo, mark, point);
176 drawEmphasisMarksForComplexText(context, runInfo, mark, point);
179 float Font::width(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const
181 CodePath codePathToUse = codePath(run);
182 if (codePathToUse != ComplexPath) {
183 // 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.
184 if (!canReturnFallbackFontsForComplexText())
186 // The simple path can optimize the case where glyph overflow is not observable.
187 if (codePathToUse != SimpleWithGlyphOverflowPath && (glyphOverflow && !glyphOverflow->computeBounds))
191 bool hasKerningOrLigatures = typesettingFeatures() & (Kerning | Ligatures);
192 bool hasWordSpacingOrLetterSpacing = wordSpacing() || letterSpacing();
193 float* cacheEntry = m_fontFallbackList->widthCache().add(run, std::numeric_limits<float>::quiet_NaN(), hasKerningOrLigatures, hasWordSpacingOrLetterSpacing, glyphOverflow);
194 if (cacheEntry && !std::isnan(*cacheEntry))
198 if (codePathToUse == ComplexPath)
199 result = floatWidthForComplexText(run, fallbackFonts, glyphOverflow);
201 result = floatWidthForSimpleText(run, fallbackFonts, glyphOverflow);
203 if (cacheEntry && (!fallbackFonts || fallbackFonts->isEmpty()))
204 *cacheEntry = result;
208 float Font::width(const TextRun& run, int& charsConsumed, String& glyphName) const
210 #if ENABLE(SVG_FONTS)
211 if (TextRun::RenderingContext* renderingContext = run.renderingContext())
212 return renderingContext->floatWidthUsingSVGFont(*this, run, charsConsumed, glyphName);
215 charsConsumed = run.length();
220 FloatRect Font::selectionRectForText(const TextRun& run, const FloatPoint& point, int h, int from, int to) const
222 to = (to == -1 ? run.length() : to);
224 CodePath codePathToUse = codePath(run);
225 // FIXME: Use the fast code path once it handles partial runs with kerning and ligatures. See http://webkit.org/b/100050
226 if (codePathToUse != ComplexPath && typesettingFeatures() && (from || to != run.length()))
227 codePathToUse = ComplexPath;
229 if (codePathToUse != ComplexPath)
230 return selectionRectForSimpleText(run, point, h, from, to);
232 return selectionRectForComplexText(run, point, h, from, to);
235 int Font::offsetForPosition(const TextRun& run, float x, bool includePartialGlyphs) const
237 // FIXME: Use the fast code path once it handles partial runs with kerning and ligatures. See http://webkit.org/b/100050
238 if (codePath(run) != ComplexPath && !typesettingFeatures())
239 return offsetForPositionForSimpleText(run, x, includePartialGlyphs);
241 return offsetForPositionForComplexText(run, x, includePartialGlyphs);
244 template <typename CharacterType>
245 static inline String normalizeSpacesInternal(const CharacterType* characters, unsigned length)
247 StringBuilder normalized;
248 normalized.reserveCapacity(length);
250 for (unsigned i = 0; i < length; ++i)
251 normalized.append(Font::normalizeSpaces(characters[i]));
253 return normalized.toString();
256 String Font::normalizeSpaces(const LChar* characters, unsigned length)
258 return normalizeSpacesInternal(characters, length);
261 String Font::normalizeSpaces(const UChar* characters, unsigned length)
263 return normalizeSpacesInternal(characters, length);
266 static bool shouldUseFontSmoothing = true;
268 void Font::setShouldUseSmoothing(bool shouldUseSmoothing)
270 ASSERT(isMainThread());
271 shouldUseFontSmoothing = shouldUseSmoothing;
274 bool Font::shouldUseSmoothing()
276 return shouldUseFontSmoothing;
279 void Font::setCodePath(CodePath p)
284 CodePath Font::codePath()
289 void Font::setDefaultTypesettingFeatures(TypesettingFeatures typesettingFeatures)
291 s_defaultTypesettingFeatures = typesettingFeatures;
294 TypesettingFeatures Font::defaultTypesettingFeatures()
296 return s_defaultTypesettingFeatures;
299 CodePath Font::codePath(const TextRun& run) const
301 if (s_codePath != AutoPath)
304 #if ENABLE(SVG_FONTS)
305 if (run.renderingContext())
309 if (m_fontDescription.featureSettings() && m_fontDescription.featureSettings()->size() > 0)
312 if (run.length() > 1 && !WidthIterator::supportsTypesettingFeatures(*this))
315 if (!run.characterScanForCodePath())
321 // Start from 0 since drawing and highlighting also measure the characters before run->from.
322 return characterRangeCodePath(run.characters16(), run.length());
325 // Takes a flattened list of closed intervals
326 template <class T, size_t size>
327 bool valueInIntervalList(const T (&intervalList)[size], const T& value)
329 const T* bound = std::upper_bound(&intervalList[0], &intervalList[size], value);
330 if ((bound - intervalList) % 2 == 1)
332 return bound > intervalList && *(bound - 1) == value;
335 CodePath Font::characterRangeCodePath(const UChar* characters, unsigned len)
337 static const UChar complexCodePathRanges[] = {
338 // U+02E5 through U+02E9 (Modifier Letters : Tone letters)
340 // U+0300 through U+036F Combining diacritical marks
342 // U+0591 through U+05CF excluding U+05BE Hebrew combining marks, ...
344 // ... Hebrew punctuation Paseq, Sof Pasuq and Nun Hafukha
346 // U+0600 through U+109F Arabic, Syriac, Thaana, NKo, Samaritan, Mandaic,
347 // Devanagari, Bengali, Gurmukhi, Gujarati, Oriya, Tamil, Telugu, Kannada,
348 // Malayalam, Sinhala, Thai, Lao, Tibetan, Myanmar
350 // U+1100 through U+11FF Hangul Jamo (only Ancient Korean should be left
351 // here if you precompose; Modern Korean will be precomposed as a result of step A)
353 // U+135D through U+135F Ethiopic combining marks
355 // U+1780 through U+18AF Tagalog, Hanunoo, Buhid, Taghanwa,Khmer, Mongolian
357 // U+1900 through U+194F Limbu (Unicode 4.0)
359 // U+1980 through U+19DF New Tai Lue
361 // U+1A00 through U+1CFF Buginese, Tai Tham, Balinese, Batak, Lepcha, Vedic
363 // U+1DC0 through U+1DFF Comining diacritical mark supplement
365 // U+20D0 through U+20FF Combining marks for symbols
367 // U+2CEF through U+2CF1 Combining marks for Coptic
369 // U+302A through U+302F Ideographic and Hangul Tone marks
371 // U+A67C through U+A67D Combining marks for old Cyrillic
373 // U+A6F0 through U+A6F1 Combining mark for Bamum
375 // U+A800 through U+ABFF Nagri, Phags-pa, Saurashtra, Devanagari Extended,
376 // Hangul Jamo Ext. A, Javanese, Myanmar Extended A, Tai Viet, Meetei Mayek
378 // U+D7B0 through U+D7FF Hangul Jamo Ext. B
380 // U+FE00 through U+FE0F Unicode variation selectors
382 // U+FE20 through U+FE2F Combining half marks
386 CodePath result = SimplePath;
387 for (unsigned i = 0; i < len; i++) {
388 const UChar c = characters[i];
390 // Shortcut for common case
394 // U+1E00 through U+2000 characters with diacritics and stacked diacritics
395 if (c >= 0x1E00 && c <= 0x2000) {
396 result = SimpleWithGlyphOverflowPath;
401 if (c > 0xD7FF && c <= 0xDBFF) {
405 UChar next = characters[++i];
406 if (!U16_IS_TRAIL(next))
409 UChar32 supplementaryCharacter = U16_GET_SUPPLEMENTARY(c, next);
411 if (supplementaryCharacter < 0x1F1E6) // U+1F1E6 through U+1F1FF Regional Indicator Symbols
413 if (supplementaryCharacter <= 0x1F1FF)
416 if (supplementaryCharacter < 0xE0100) // U+E0100 through U+E01EF Unicode variation selectors.
418 if (supplementaryCharacter <= 0xE01EF)
421 // FIXME: Check for Brahmi (U+11000 block), Kaithi (U+11080 block) and other complex scripts
422 // in plane 1 or higher.
427 // Search for other Complex cases
428 if (valueInIntervalList(complexCodePathRanges, c))
435 bool Font::isCJKIdeograph(UChar32 c)
437 static const UChar32 cjkIdeographRanges[] = {
438 // CJK Radicals Supplement and Kangxi Radicals.
442 // CJK Unified Ideographs Extension A.
444 // The basic CJK Unified Ideographs block.
446 // CJK Compatibility Ideographs.
448 // CJK Unified Ideographs Extension B.
450 // CJK Unified Ideographs Extension C.
451 // CJK Unified Ideographs Extension D.
453 // CJK Compatibility Ideographs Supplement.
456 static size_t cjkIdeographRangesCount = WTF_ARRAY_LENGTH(cjkIdeographRanges);
459 if (c < cjkIdeographRanges[0] || c > cjkIdeographRanges[cjkIdeographRangesCount - 1])
462 return valueInIntervalList(cjkIdeographRanges, c);
465 bool Font::isCJKIdeographOrSymbol(UChar32 c)
467 // Likely common case
471 // Hash lookup for isolated symbols (those not part of a contiguous range)
472 static HashSet<UChar32>* cjkIsolatedSymbols = 0;
473 if (!cjkIsolatedSymbols) {
474 cjkIsolatedSymbols = new HashSet<UChar32>();
475 for (size_t i = 0; i < WTF_ARRAY_LENGTH(cjkIsolatedSymbolsArray); ++i)
476 cjkIsolatedSymbols->add(cjkIsolatedSymbolsArray[i]);
478 if (cjkIsolatedSymbols->contains(c))
481 if (isCJKIdeograph(c))
484 static const UChar32 cjkSymbolRanges[] = {
497 // Ideographic Description Characters, with CJK Symbols and Punctuation, excluding 0x3030.
498 // Then Hiragana 0x3040 .. 0x309F, Katakana 0x30A0 .. 0x30FF, Bopomofo 0x3100 .. 0x312F
501 // More Bopomofo and Bopomofo Extended 0x31A0 .. 0x31BF
503 // Enclosed CJK Letters and Months (0x3200 .. 0x32FF).
504 // CJK Compatibility (0x3300 .. 0x33FF).
507 // CJK Compatibility Forms.
509 // Halfwidth and Fullwidth Forms
510 // Usually only used in CJK
522 return valueInIntervalList(cjkSymbolRanges, c);
525 unsigned Font::expansionOpportunityCount(const LChar* characters, size_t length, TextDirection direction, bool& isAfterExpansion)
528 if (direction == LTR) {
529 for (size_t i = 0; i < length; ++i) {
530 if (treatAsSpace(characters[i])) {
532 isAfterExpansion = true;
534 isAfterExpansion = false;
537 for (size_t i = length; i > 0; --i) {
538 if (treatAsSpace(characters[i - 1])) {
540 isAfterExpansion = true;
542 isAfterExpansion = false;
548 unsigned Font::expansionOpportunityCount(const UChar* characters, size_t length, TextDirection direction, bool& isAfterExpansion)
550 static bool expandAroundIdeographs = canExpandAroundIdeographsInComplexText();
552 if (direction == LTR) {
553 for (size_t i = 0; i < length; ++i) {
554 UChar32 character = characters[i];
555 if (treatAsSpace(character)) {
557 isAfterExpansion = true;
560 if (U16_IS_LEAD(character) && i + 1 < length && U16_IS_TRAIL(characters[i + 1])) {
561 character = U16_GET_SUPPLEMENTARY(character, characters[i + 1]);
564 if (expandAroundIdeographs && isCJKIdeographOrSymbol(character)) {
565 if (!isAfterExpansion)
568 isAfterExpansion = true;
571 isAfterExpansion = false;
574 for (size_t i = length; i > 0; --i) {
575 UChar32 character = characters[i - 1];
576 if (treatAsSpace(character)) {
578 isAfterExpansion = true;
581 if (U16_IS_TRAIL(character) && i > 1 && U16_IS_LEAD(characters[i - 2])) {
582 character = U16_GET_SUPPLEMENTARY(characters[i - 2], character);
585 if (expandAroundIdeographs && isCJKIdeographOrSymbol(character)) {
586 if (!isAfterExpansion)
589 isAfterExpansion = true;
592 isAfterExpansion = false;
598 bool Font::canReceiveTextEmphasis(UChar32 c)
600 CharCategory category = Unicode::category(c);
601 if (category & (Separator_Space | Separator_Line | Separator_Paragraph | Other_NotAssigned | Other_Control | Other_Format))
604 // Additional word-separator characters listed in CSS Text Level 3 Editor's Draft 3 November 2010.
605 if (c == ethiopicWordspace || c == aegeanWordSeparatorLine || c == aegeanWordSeparatorDot
606 || c == ugariticWordDivider || c == tibetanMarkIntersyllabicTsheg || c == tibetanMarkDelimiterTshegBstar)
612 void Font::willUseFontData() const
614 const FontFamily& family = fontDescription().family();
615 if (m_fontFallbackList && m_fontFallbackList->fontSelector() && !family.familyIsEmpty())
616 m_fontFallbackList->fontSelector()->willUseFontData(fontDescription(), family.family());