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 "GlyphBuffer.h"
30 #include "LayoutRect.h"
32 #include "WidthIterator.h"
33 #include <wtf/MainThread.h>
34 #include <wtf/MathExtras.h>
35 #include <wtf/text/AtomicStringHash.h>
36 #include <wtf/text/StringBuilder.h>
39 using namespace Unicode;
43 // allow compilation of OwnPtr<TextLayout> in source files that don't have access to the TextLayout class definition
44 template <> void deleteOwnedPtr<WebCore::TextLayout>(WebCore::TextLayout* ptr)
46 WebCore::Font::deleteLayout(ptr);
53 static PassRef<FontGlyphs> retrieveOrAddCachedFontGlyphs(const FontDescription&, PassRefPtr<FontSelector>);
55 const uint8_t Font::s_roundingHackCharacterTable[256] = {
56 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,
57 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 /*?*/,
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 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,
61 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,
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,
63 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
66 static bool isDrawnWithSVGFont(const TextRun& run)
68 return run.renderingContext();
71 static bool useBackslashAsYenSignForFamily(const AtomicString& family)
75 static HashSet<AtomicString>* set;
77 set = new HashSet<AtomicString>;
78 set->add("MS PGothic");
79 UChar unicodeNameMSPGothic[] = {0xFF2D, 0xFF33, 0x0020, 0xFF30, 0x30B4, 0x30B7, 0x30C3, 0x30AF};
80 set->add(AtomicString(unicodeNameMSPGothic, WTF_ARRAY_LENGTH(unicodeNameMSPGothic)));
82 set->add("MS PMincho");
83 UChar unicodeNameMSPMincho[] = {0xFF2D, 0xFF33, 0x0020, 0xFF30, 0x660E, 0x671D};
84 set->add(AtomicString(unicodeNameMSPMincho, WTF_ARRAY_LENGTH(unicodeNameMSPMincho)));
86 set->add("MS Gothic");
87 UChar unicodeNameMSGothic[] = {0xFF2D, 0xFF33, 0x0020, 0x30B4, 0x30B7, 0x30C3, 0x30AF};
88 set->add(AtomicString(unicodeNameMSGothic, WTF_ARRAY_LENGTH(unicodeNameMSGothic)));
90 set->add("MS Mincho");
91 UChar unicodeNameMSMincho[] = {0xFF2D, 0xFF33, 0x0020, 0x660E, 0x671D};
92 set->add(AtomicString(unicodeNameMSMincho, WTF_ARRAY_LENGTH(unicodeNameMSMincho)));
95 UChar unicodeNameMeiryo[] = {0x30E1, 0x30A4, 0x30EA, 0x30AA};
96 set->add(AtomicString(unicodeNameMeiryo, WTF_ARRAY_LENGTH(unicodeNameMeiryo)));
98 return set->contains(family);
101 Font::CodePath Font::s_codePath = Auto;
103 TypesettingFeatures Font::s_defaultTypesettingFeatures = 0;
105 // ============================================================================================
106 // Font Implementation (Cross-Platform Portion)
107 // ============================================================================================
112 , m_useBackslashAsYenSymbol(false)
113 , m_typesettingFeatures(0)
117 Font::Font(const FontDescription& fd, float letterSpacing, float wordSpacing)
118 : m_fontDescription(fd)
119 , m_letterSpacing(letterSpacing)
120 , m_wordSpacing(wordSpacing)
121 , m_useBackslashAsYenSymbol(useBackslashAsYenSignForFamily(fd.firstFamily()))
122 , m_typesettingFeatures(computeTypesettingFeatures())
126 // FIXME: We should make this constructor platform-independent.
127 Font::Font(const FontPlatformData& fontData, bool isPrinterFont, FontSmoothingMode fontSmoothingMode)
128 : m_glyphs(FontGlyphs::createForPlatformFont(fontData))
131 , m_useBackslashAsYenSymbol(false)
132 , m_typesettingFeatures(computeTypesettingFeatures())
134 m_fontDescription.setUsePrinterFont(isPrinterFont);
135 m_fontDescription.setFontSmoothing(fontSmoothingMode);
137 m_fontDescription.setSpecifiedSize(CTFontGetSize(fontData.font()));
138 m_fontDescription.setComputedSize(CTFontGetSize(fontData.font()));
139 m_fontDescription.setItalic(CTFontGetSymbolicTraits(fontData.font()) & kCTFontTraitItalic);
140 m_fontDescription.setWeight((CTFontGetSymbolicTraits(fontData.font()) & kCTFontTraitBold) ? FontWeightBold : FontWeightNormal);
144 // FIXME: We should make this constructor platform-independent.
146 Font::Font(const FontPlatformData& fontData, PassRefPtr<FontSelector> fontSelector)
147 : m_glyphs(FontGlyphs::createForPlatformFont(fontData))
150 , m_typesettingFeatures(computeTypesettingFeatures())
152 CTFontRef primaryFont = fontData.font();
153 m_fontDescription.setSpecifiedSize(CTFontGetSize(primaryFont));
154 m_fontDescription.setComputedSize(CTFontGetSize(primaryFont));
155 m_fontDescription.setItalic(CTFontGetSymbolicTraits(primaryFont) & kCTFontTraitItalic);
156 m_fontDescription.setWeight((CTFontGetSymbolicTraits(primaryFont) & kCTFontTraitBold) ? FontWeightBold : FontWeightNormal);
157 m_fontDescription.setUsePrinterFont(fontData.isPrinterFont());
158 m_glyphs = retrieveOrAddCachedFontGlyphs(m_fontDescription, fontSelector.get());
162 Font::Font(const Font& other)
163 : m_fontDescription(other.m_fontDescription)
164 , m_glyphs(other.m_glyphs)
165 , m_letterSpacing(other.m_letterSpacing)
166 , m_wordSpacing(other.m_wordSpacing)
167 , m_useBackslashAsYenSymbol(other.m_useBackslashAsYenSymbol)
168 , m_typesettingFeatures(computeTypesettingFeatures())
172 Font& Font::operator=(const Font& other)
174 m_fontDescription = other.m_fontDescription;
175 m_glyphs = other.m_glyphs;
176 m_letterSpacing = other.m_letterSpacing;
177 m_wordSpacing = other.m_wordSpacing;
178 m_useBackslashAsYenSymbol = other.m_useBackslashAsYenSymbol;
179 m_typesettingFeatures = other.m_typesettingFeatures;
183 bool Font::operator==(const Font& other) const
185 // Our FontData don't have to be checked, since checking the font description will be fine.
186 // FIXME: This does not work if the font was made with the FontPlatformData constructor.
187 if (loadingCustomFonts() || other.loadingCustomFonts())
190 if (m_fontDescription != other.m_fontDescription || m_letterSpacing != other.m_letterSpacing || m_wordSpacing != other.m_wordSpacing)
192 if (m_glyphs == other.m_glyphs)
194 if (!m_glyphs || !other.m_glyphs)
196 if (m_glyphs->fontSelector() != other.m_glyphs->fontSelector())
198 // Can these cases actually somehow occur? All fonts should get wiped out by full style recalc.
199 if (m_glyphs->fontSelectorVersion() != other.m_glyphs->fontSelectorVersion())
201 if (m_glyphs->generation() != other.m_glyphs->generation())
206 struct FontGlyphsCacheKey {
207 // This part of the key is shared with the lower level FontCache (caching FontData objects).
208 FontDescriptionFontDataCacheKey fontDescriptionCacheKey;
209 Vector<AtomicString, 3> families;
210 unsigned fontSelectorId;
211 unsigned fontSelectorVersion;
212 unsigned fontSelectorFlags;
215 struct FontGlyphsCacheEntry {
216 WTF_MAKE_FAST_ALLOCATED;
218 FontGlyphsCacheEntry(FontGlyphsCacheKey&& k, PassRef<FontGlyphs> g) : key(WTF::move(k)), glyphs(WTF::move(g)) { }
219 FontGlyphsCacheKey key;
220 Ref<FontGlyphs> glyphs;
223 typedef HashMap<unsigned, OwnPtr<FontGlyphsCacheEntry>, AlreadyHashed> FontGlyphsCache;
225 static bool operator==(const FontGlyphsCacheKey& a, const FontGlyphsCacheKey& b)
227 if (a.fontDescriptionCacheKey != b.fontDescriptionCacheKey)
229 if (a.fontSelectorId != b.fontSelectorId || a.fontSelectorVersion != b.fontSelectorVersion || a.fontSelectorFlags != b.fontSelectorFlags)
231 if (a.families.size() != b.families.size())
233 for (unsigned i = 0; i < a.families.size(); ++i) {
234 if (!equalIgnoringCase(a.families[i].impl(), b.families[i].impl()))
240 static FontGlyphsCache& fontGlyphsCache()
242 DEPRECATED_DEFINE_STATIC_LOCAL(FontGlyphsCache, cache, ());
246 void invalidateFontGlyphsCache()
248 fontGlyphsCache().clear();
251 void clearWidthCaches()
253 for (auto it = fontGlyphsCache().begin(), end = fontGlyphsCache().end(); it != end; ++it)
254 it->value->glyphs.get().widthCache().clear();
257 static unsigned makeFontSelectorFlags(const FontDescription& description)
259 return static_cast<unsigned>(description.script()) << 1 | static_cast<unsigned>(description.smallCaps());
262 static void makeFontGlyphsCacheKey(FontGlyphsCacheKey& key, const FontDescription& description, FontSelector* fontSelector)
264 key.fontDescriptionCacheKey = FontDescriptionFontDataCacheKey(description);
265 for (unsigned i = 0; i < description.familyCount(); ++i)
266 key.families.append(description.familyAt(i));
267 key.fontSelectorId = fontSelector ? fontSelector->uniqueId() : 0;
268 key.fontSelectorVersion = fontSelector ? fontSelector->version() : 0;
269 key.fontSelectorFlags = fontSelector && fontSelector->resolvesFamilyFor(description) ? makeFontSelectorFlags(description) : 0;
272 static unsigned computeFontGlyphsCacheHash(const FontGlyphsCacheKey& key)
274 Vector<unsigned, 7> hashCodes;
275 hashCodes.reserveInitialCapacity(4 + key.families.size());
277 hashCodes.uncheckedAppend(key.fontDescriptionCacheKey.computeHash());
278 hashCodes.uncheckedAppend(key.fontSelectorId);
279 hashCodes.uncheckedAppend(key.fontSelectorVersion);
280 hashCodes.uncheckedAppend(key.fontSelectorFlags);
281 for (unsigned i = 0; i < key.families.size(); ++i)
282 hashCodes.uncheckedAppend(key.families[i].impl() ? CaseFoldingHash::hash(key.families[i]) : 0);
284 return StringHasher::hashMemory(hashCodes.data(), hashCodes.size() * sizeof(unsigned));
287 void pruneUnreferencedEntriesFromFontGlyphsCache()
289 Vector<unsigned, 50> toRemove;
290 FontGlyphsCache::iterator end = fontGlyphsCache().end();
291 for (FontGlyphsCache::iterator it = fontGlyphsCache().begin(); it != end; ++it) {
292 if (it->value->glyphs.get().hasOneRef())
293 toRemove.append(it->key);
295 for (unsigned i = 0; i < toRemove.size(); ++i)
296 fontGlyphsCache().remove(toRemove[i]);
299 static PassRef<FontGlyphs> retrieveOrAddCachedFontGlyphs(const FontDescription& fontDescription, PassRefPtr<FontSelector> fontSelector)
301 FontGlyphsCacheKey key;
302 makeFontGlyphsCacheKey(key, fontDescription, fontSelector.get());
304 unsigned hash = computeFontGlyphsCacheHash(key);
305 FontGlyphsCache::AddResult addResult = fontGlyphsCache().add(hash, PassOwnPtr<FontGlyphsCacheEntry>());
306 if (!addResult.isNewEntry && addResult.iterator->value->key == key)
307 return addResult.iterator->value->glyphs.get();
309 OwnPtr<FontGlyphsCacheEntry>& newEntry = addResult.iterator->value;
310 newEntry = adoptPtr(new FontGlyphsCacheEntry(WTF::move(key), FontGlyphs::create(fontSelector)));
311 PassRef<FontGlyphs> glyphs = newEntry->glyphs.get();
313 static const unsigned unreferencedPruneInterval = 50;
314 static const int maximumEntries = 400;
315 static unsigned pruneCounter;
316 // Referenced FontGlyphs would exist anyway so pruning them saves little memory.
317 if (!(++pruneCounter % unreferencedPruneInterval))
318 pruneUnreferencedEntriesFromFontGlyphsCache();
319 // Prevent pathological growth.
320 if (fontGlyphsCache().size() > maximumEntries)
321 fontGlyphsCache().remove(fontGlyphsCache().begin());
325 void Font::update(PassRefPtr<FontSelector> fontSelector) const
327 m_glyphs = retrieveOrAddCachedFontGlyphs(m_fontDescription, fontSelector.get());
328 m_useBackslashAsYenSymbol = useBackslashAsYenSignForFamily(firstFamily());
329 m_typesettingFeatures = computeTypesettingFeatures();
332 float Font::drawText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, int from, int to, CustomFontNotReadyAction customFontNotReadyAction) const
334 // Don't draw anything while we are using custom fonts that are in the process of loading,
335 // except if the 'force' argument is set to true (in which case it will use a fallback
337 if (loadingCustomFonts() && customFontNotReadyAction == DoNotPaintIfFontNotReady)
340 to = (to == -1 ? run.length() : to);
342 CodePath codePathToUse = codePath(run);
343 // FIXME: Use the fast code path once it handles partial runs with kerning and ligatures. See http://webkit.org/b/100050
344 if (codePathToUse != Complex && typesettingFeatures() && (from || static_cast<unsigned>(to) != run.length()) && !isDrawnWithSVGFont(run))
345 codePathToUse = Complex;
347 if (codePathToUse != Complex)
348 return drawSimpleText(context, run, point, from, to);
350 return drawComplexText(context, run, point, from, to);
353 void Font::drawEmphasisMarks(GraphicsContext* context, const TextRun& run, const AtomicString& mark, const FloatPoint& point, int from, int to) const
355 if (loadingCustomFonts())
361 CodePath codePathToUse = codePath(run);
362 // FIXME: Use the fast code path once it handles partial runs with kerning and ligatures. See http://webkit.org/b/100050
363 if (codePathToUse != Complex && typesettingFeatures() && (from || static_cast<unsigned>(to) != run.length()) && !isDrawnWithSVGFont(run))
364 codePathToUse = Complex;
366 if (codePathToUse != Complex)
367 drawEmphasisMarksForSimpleText(context, run, mark, point, from, to);
369 drawEmphasisMarksForComplexText(context, run, mark, point, from, to);
372 float Font::width(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const
374 CodePath codePathToUse = codePath(run);
375 if (codePathToUse != Complex) {
376 // 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.
377 if (!canReturnFallbackFontsForComplexText())
379 // The simple path can optimize the case where glyph overflow is not observable.
380 if (codePathToUse != SimpleWithGlyphOverflow && (glyphOverflow && !glyphOverflow->computeBounds))
384 bool hasKerningOrLigatures = typesettingFeatures() & (Kerning | Ligatures);
385 bool hasWordSpacingOrLetterSpacing = wordSpacing() || letterSpacing();
386 float* cacheEntry = m_glyphs->widthCache().add(run, std::numeric_limits<float>::quiet_NaN(), hasKerningOrLigatures, hasWordSpacingOrLetterSpacing, glyphOverflow);
387 if (cacheEntry && !std::isnan(*cacheEntry))
390 HashSet<const SimpleFontData*> localFallbackFonts;
392 fallbackFonts = &localFallbackFonts;
395 if (codePathToUse == Complex)
396 result = floatWidthForComplexText(run, fallbackFonts, glyphOverflow);
398 result = floatWidthForSimpleText(run, fallbackFonts, glyphOverflow);
400 if (cacheEntry && fallbackFonts->isEmpty())
401 *cacheEntry = result;
405 float Font::width(const TextRun& run, int& charsConsumed, String& glyphName) const
407 #if ENABLE(SVG_FONTS)
408 if (isDrawnWithSVGFont(run))
409 return run.renderingContext()->floatWidthUsingSVGFont(*this, run, charsConsumed, glyphName);
412 charsConsumed = run.length();
418 PassOwnPtr<TextLayout> Font::createLayout(RenderText*, float, bool) const
423 void Font::deleteLayout(TextLayout*)
427 float Font::width(TextLayout&, unsigned, unsigned, HashSet<const SimpleFontData*>*)
429 ASSERT_NOT_REACHED();
436 static const char* fontFamiliesWithInvalidCharWidth[] = {
437 "American Typewriter",
473 // For font families where any of the fonts don't have a valid entry in the OS/2 table
474 // for avgCharWidth, fallback to the legacy webkit behavior of getting the avgCharWidth
475 // from the width of a '0'. This only seems to apply to a fixed number of Mac fonts,
476 // but, in order to get similar rendering across platforms, we do this check for
478 bool Font::hasValidAverageCharWidth() const
480 AtomicString family = firstFamily();
481 if (family.isEmpty())
484 #if PLATFORM(MAC) || PLATFORM(IOS)
485 // Internal fonts on OS X and iOS also have an invalid entry in the table for avgCharWidth.
486 if (primaryFontDataIsSystemFont())
490 static HashSet<AtomicString>* fontFamiliesWithInvalidCharWidthMap = 0;
492 if (!fontFamiliesWithInvalidCharWidthMap) {
493 fontFamiliesWithInvalidCharWidthMap = new HashSet<AtomicString>;
495 for (size_t i = 0; i < WTF_ARRAY_LENGTH(fontFamiliesWithInvalidCharWidth); ++i)
496 fontFamiliesWithInvalidCharWidthMap->add(AtomicString(fontFamiliesWithInvalidCharWidth[i]));
499 return !fontFamiliesWithInvalidCharWidthMap->contains(family);
502 bool Font::fastAverageCharWidthIfAvailable(float& width) const
504 bool success = hasValidAverageCharWidth();
506 width = roundf(primaryFont()->avgCharWidth()); // FIXME: primaryFont() might not correspond to firstFamily().
510 void Font::adjustSelectionRectForText(const TextRun& run, LayoutRect& selectionRect, int from, int to) const
512 to = (to == -1 ? run.length() : to);
514 CodePath codePathToUse = codePath(run);
515 // FIXME: Use the fast code path once it handles partial runs with kerning and ligatures. See http://webkit.org/b/100050
516 if (codePathToUse != Complex && typesettingFeatures() && (from || static_cast<unsigned>(to) != run.length()) && !isDrawnWithSVGFont(run))
517 codePathToUse = Complex;
519 if (codePathToUse != Complex)
520 return adjustSelectionRectForSimpleText(run, selectionRect, from, to);
522 return adjustSelectionRectForComplexText(run, selectionRect, from, to);
525 int Font::offsetForPosition(const TextRun& run, float x, bool includePartialGlyphs) const
527 // FIXME: Use the fast code path once it handles partial runs with kerning and ligatures. See http://webkit.org/b/100050
528 if (codePath(run) != Complex && (!typesettingFeatures() || isDrawnWithSVGFont(run)))
529 return offsetForPositionForSimpleText(run, x, includePartialGlyphs);
531 return offsetForPositionForComplexText(run, x, includePartialGlyphs);
534 template <typename CharacterType>
535 static inline String normalizeSpacesInternal(const CharacterType* characters, unsigned length)
537 StringBuilder normalized;
538 normalized.reserveCapacity(length);
540 for (unsigned i = 0; i < length; ++i)
541 normalized.append(Font::normalizeSpaces(characters[i]));
543 return normalized.toString();
546 String Font::normalizeSpaces(const LChar* characters, unsigned length)
548 return normalizeSpacesInternal(characters, length);
551 String Font::normalizeSpaces(const UChar* characters, unsigned length)
553 return normalizeSpacesInternal(characters, length);
556 static bool shouldUseFontSmoothing = true;
558 void Font::setShouldUseSmoothing(bool shouldUseSmoothing)
560 ASSERT(isMainThread());
561 shouldUseFontSmoothing = shouldUseSmoothing;
564 bool Font::shouldUseSmoothing()
566 return shouldUseFontSmoothing;
569 void Font::setCodePath(CodePath p)
574 Font::CodePath Font::codePath()
579 void Font::setDefaultTypesettingFeatures(TypesettingFeatures typesettingFeatures)
581 s_defaultTypesettingFeatures = typesettingFeatures;
584 TypesettingFeatures Font::defaultTypesettingFeatures()
586 return s_defaultTypesettingFeatures;
589 Font::CodePath Font::codePath(const TextRun& run) const
591 if (s_codePath != Auto)
594 #if ENABLE(SVG_FONTS)
595 if (isDrawnWithSVGFont(run))
599 if (m_fontDescription.featureSettings() && m_fontDescription.featureSettings()->size() > 0)
602 if (run.length() > 1 && !WidthIterator::supportsTypesettingFeatures(*this))
605 if (!run.characterScanForCodePath())
611 // Start from 0 since drawing and highlighting also measure the characters before run->from.
612 return characterRangeCodePath(run.characters16(), run.length());
615 Font::CodePath Font::characterRangeCodePath(const UChar* characters, unsigned len)
617 // FIXME: Should use a UnicodeSet in ports where ICU is used. Note that we
618 // can't simply use UnicodeCharacter Property/class because some characters
619 // are not 'combining', but still need to go to the complex path.
620 // Alternatively, we may as well consider binary search over a sorted
622 CodePath result = Simple;
623 for (unsigned i = 0; i < len; i++) {
624 const UChar c = characters[i];
625 if (c < 0x2E5) // U+02E5 through U+02E9 (Modifier Letters : Tone letters)
630 if (c < 0x300) // U+0300 through U+036F Combining diacritical marks
635 if (c < 0x0591 || c == 0x05BE) // U+0591 through U+05CF excluding U+05BE Hebrew combining marks, Hebrew punctuation Paseq, Sof Pasuq and Nun Hafukha
640 // U+0600 through U+109F Arabic, Syriac, Thaana, NKo, Samaritan, Mandaic,
641 // Devanagari, Bengali, Gurmukhi, Gujarati, Oriya, Tamil, Telugu, Kannada,
642 // Malayalam, Sinhala, Thai, Lao, Tibetan, Myanmar
648 // U+1100 through U+11FF Hangul Jamo (only Ancient Korean should be left here if you precompose;
649 // Modern Korean will be precomposed as a result of step A)
655 if (c < 0x135D) // U+135D through U+135F Ethiopic combining marks
660 if (c < 0x1700) // U+1780 through U+18AF Tagalog, Hanunoo, Buhid, Taghanwa,Khmer, Mongolian
665 if (c < 0x1900) // U+1900 through U+194F Limbu (Unicode 4.0)
670 if (c < 0x1980) // U+1980 through U+19DF New Tai Lue
675 if (c < 0x1A00) // U+1A00 through U+1CFF Buginese, Tai Tham, Balinese, Batak, Lepcha, Vedic
680 if (c < 0x1DC0) // U+1DC0 through U+1DFF Comining diacritical mark supplement
685 // U+1E00 through U+2000 characters with diacritics and stacked diacritics
687 result = SimpleWithGlyphOverflow;
691 if (c < 0x20D0) // U+20D0 through U+20FF Combining marks for symbols
696 if (c < 0x2CEF) // U+2CEF through U+2CF1 Combining marks for Coptic
701 if (c < 0x302A) // U+302A through U+302F Ideographic and Hangul Tone marks
706 if (c < 0xA67C) // U+A67C through U+A67D Combining marks for old Cyrillic
711 if (c < 0xA6F0) // U+A6F0 through U+A6F1 Combining mark for Bamum
716 // U+A800 through U+ABFF Nagri, Phags-pa, Saurashtra, Devanagari Extended,
717 // Hangul Jamo Ext. A, Javanese, Myanmar Extended A, Tai Viet, Meetei Mayek,
723 if (c < 0xD7B0) // U+D7B0 through U+D7FF Hangul Jamo Ext. B
734 UChar next = characters[++i];
735 if (!U16_IS_TRAIL(next))
738 UChar32 supplementaryCharacter = U16_GET_SUPPLEMENTARY(c, next);
740 if (supplementaryCharacter < 0x1F1E6) // U+1F1E6 through U+1F1FF Regional Indicator Symbols
742 if (supplementaryCharacter <= 0x1F1FF)
745 if (supplementaryCharacter < 0xE0100) // U+E0100 through U+E01EF Unicode variation selectors.
747 if (supplementaryCharacter <= 0xE01EF)
750 // FIXME: Check for Brahmi (U+11000 block), Kaithi (U+11080 block) and other complex scripts
751 // in plane 1 or higher.
756 if (c < 0xFE00) // U+FE00 through U+FE0F Unicode variation selectors
761 if (c < 0xFE20) // U+FE20 through U+FE2F Combining half marks
769 bool Font::isCJKIdeograph(UChar32 c)
771 // The basic CJK Unified Ideographs block.
772 if (c >= 0x4E00 && c <= 0x9FFF)
775 // CJK Unified Ideographs Extension A.
776 if (c >= 0x3400 && c <= 0x4DBF)
779 // CJK Radicals Supplement.
780 if (c >= 0x2E80 && c <= 0x2EFF)
784 if (c >= 0x2F00 && c <= 0x2FDF)
788 if (c >= 0x31C0 && c <= 0x31EF)
791 // CJK Compatibility Ideographs.
792 if (c >= 0xF900 && c <= 0xFAFF)
795 // CJK Unified Ideographs Extension B.
796 if (c >= 0x20000 && c <= 0x2A6DF)
799 // CJK Unified Ideographs Extension C.
800 if (c >= 0x2A700 && c <= 0x2B73F)
803 // CJK Unified Ideographs Extension D.
804 if (c >= 0x2B740 && c <= 0x2B81F)
807 // CJK Compatibility Ideographs Supplement.
808 if (c >= 0x2F800 && c <= 0x2FA1F)
814 bool Font::isCJKIdeographOrSymbol(UChar32 c)
816 // 0x2C7 Caron, Mandarin Chinese 3rd Tone
817 // 0x2CA Modifier Letter Acute Accent, Mandarin Chinese 2nd Tone
818 // 0x2CB Modifier Letter Grave Access, Mandarin Chinese 4th Tone
819 // 0x2D9 Dot Above, Mandarin Chinese 5th Tone
820 if ((c == 0x2C7) || (c == 0x2CA) || (c == 0x2CB) || (c == 0x2D9))
823 if ((c == 0x2020) || (c == 0x2021) || (c == 0x2030) || (c == 0x203B) || (c == 0x203C)
824 || (c == 0x2042) || (c == 0x2047) || (c == 0x2048) || (c == 0x2049) || (c == 0x2051)
825 || (c == 0x20DD) || (c == 0x20DE) || (c == 0x2100) || (c == 0x2103) || (c == 0x2105)
826 || (c == 0x2109) || (c == 0x210A) || (c == 0x2113) || (c == 0x2116) || (c == 0x2121)
827 || (c == 0x212B) || (c == 0x213B) || (c == 0x2150) || (c == 0x2151) || (c == 0x2152))
830 if (c >= 0x2156 && c <= 0x215A)
833 if (c >= 0x2160 && c <= 0x216B)
836 if (c >= 0x2170 && c <= 0x217B)
839 if ((c == 0x217F) || (c == 0x2189) || (c == 0x2307) || (c == 0x2312) || (c == 0x23BE) || (c == 0x23BF))
842 if (c >= 0x23C0 && c <= 0x23CC)
845 if ((c == 0x23CE) || (c == 0x2423))
848 if (c >= 0x2460 && c <= 0x2492)
851 if (c >= 0x249C && c <= 0x24FF)
854 if ((c == 0x25A0) || (c == 0x25A1) || (c == 0x25A2) || (c == 0x25AA) || (c == 0x25AB))
857 if ((c == 0x25B1) || (c == 0x25B2) || (c == 0x25B3) || (c == 0x25B6) || (c == 0x25B7) || (c == 0x25BC) || (c == 0x25BD))
860 if ((c == 0x25C0) || (c == 0x25C1) || (c == 0x25C6) || (c == 0x25C7) || (c == 0x25C9) || (c == 0x25CB) || (c == 0x25CC))
863 if (c >= 0x25CE && c <= 0x25D3)
866 if (c >= 0x25E2 && c <= 0x25E6)
872 if (c >= 0x2600 && c <= 0x2603)
875 if ((c == 0x2605) || (c == 0x2606) || (c == 0x260E) || (c == 0x2616) || (c == 0x2617) || (c == 0x2640) || (c == 0x2642))
878 if (c >= 0x2660 && c <= 0x266F)
881 if (c >= 0x2672 && c <= 0x267D)
884 if ((c == 0x26A0) || (c == 0x26BD) || (c == 0x26BE) || (c == 0x2713) || (c == 0x271A) || (c == 0x273F) || (c == 0x2740) || (c == 0x2756))
887 if (c >= 0x2776 && c <= 0x277F)
893 // Ideographic Description Characters.
894 if (c >= 0x2FF0 && c <= 0x2FFF)
897 // CJK Symbols and Punctuation, excluding 0x3030.
898 if (c >= 0x3000 && c < 0x3030)
901 if (c > 0x3030 && c <= 0x303F)
905 if (c >= 0x3040 && c <= 0x309F)
909 if (c >= 0x30A0 && c <= 0x30FF)
913 if (c >= 0x3100 && c <= 0x312F)
916 if (c >= 0x3190 && c <= 0x319F)
920 if (c >= 0x31A0 && c <= 0x31BF)
923 // Enclosed CJK Letters and Months.
924 if (c >= 0x3200 && c <= 0x32FF)
927 // CJK Compatibility.
928 if (c >= 0x3300 && c <= 0x33FF)
931 if (c >= 0xF860 && c <= 0xF862)
934 // CJK Compatibility Forms.
935 if (c >= 0xFE30 && c <= 0xFE4F)
938 if ((c == 0xFE10) || (c == 0xFE11) || (c == 0xFE12) || (c == 0xFE19))
941 if ((c == 0xFF0D) || (c == 0xFF1B) || (c == 0xFF1C) || (c == 0xFF1E))
944 // Halfwidth and Fullwidth Forms
945 // Usually only used in CJK
946 if (c >= 0xFF00 && c <= 0xFFEF)
953 if (c >= 0x1F110 && c <= 0x1F129)
956 if (c >= 0x1F130 && c <= 0x1F149)
959 if (c >= 0x1F150 && c <= 0x1F169)
962 if (c >= 0x1F170 && c <= 0x1F189)
965 if (c >= 0x1F200 && c <= 0x1F6C5)
968 return isCJKIdeograph(c);
971 unsigned Font::expansionOpportunityCount(const LChar* characters, size_t length, TextDirection direction, bool& isAfterExpansion)
974 if (direction == LTR) {
975 for (size_t i = 0; i < length; ++i) {
976 if (treatAsSpace(characters[i])) {
978 isAfterExpansion = true;
980 isAfterExpansion = false;
983 for (size_t i = length; i > 0; --i) {
984 if (treatAsSpace(characters[i - 1])) {
986 isAfterExpansion = true;
988 isAfterExpansion = false;
994 unsigned Font::expansionOpportunityCount(const UChar* characters, size_t length, TextDirection direction, bool& isAfterExpansion)
996 static bool expandAroundIdeographs = canExpandAroundIdeographsInComplexText();
998 if (direction == LTR) {
999 for (size_t i = 0; i < length; ++i) {
1000 UChar32 character = characters[i];
1001 if (treatAsSpace(character)) {
1003 isAfterExpansion = true;
1006 if (U16_IS_LEAD(character) && i + 1 < length && U16_IS_TRAIL(characters[i + 1])) {
1007 character = U16_GET_SUPPLEMENTARY(character, characters[i + 1]);
1010 if (expandAroundIdeographs && isCJKIdeographOrSymbol(character)) {
1011 if (!isAfterExpansion)
1014 isAfterExpansion = true;
1017 isAfterExpansion = false;
1020 for (size_t i = length; i > 0; --i) {
1021 UChar32 character = characters[i - 1];
1022 if (treatAsSpace(character)) {
1024 isAfterExpansion = true;
1027 if (U16_IS_TRAIL(character) && i > 1 && U16_IS_LEAD(characters[i - 2])) {
1028 character = U16_GET_SUPPLEMENTARY(characters[i - 2], character);
1031 if (expandAroundIdeographs && isCJKIdeographOrSymbol(character)) {
1032 if (!isAfterExpansion)
1035 isAfterExpansion = true;
1038 isAfterExpansion = false;
1044 bool Font::canReceiveTextEmphasis(UChar32 c)
1046 if (U_GET_GC_MASK(c) & (U_GC_Z_MASK | U_GC_CN_MASK | U_GC_CC_MASK | U_GC_CF_MASK))
1049 // Additional word-separator characters listed in CSS Text Level 3 Editor's Draft 3 November 2010.
1050 if (c == ethiopicWordspace || c == aegeanWordSeparatorLine || c == aegeanWordSeparatorDot
1051 || c == ugariticWordDivider || c == tibetanMarkIntersyllabicTsheg || c == tibetanMarkDelimiterTshegBstar)
1057 GlyphToPathTranslator::GlyphUnderlineType computeUnderlineType(const TextRun& textRun, const GlyphBuffer& glyphBuffer, int index)
1059 // In general, we want to skip descenders. However, skipping descenders on CJK characters leads to undesirable renderings,
1060 // so we want to draw through CJK characters (on a character-by-character basis).
1061 UChar32 baseCharacter;
1062 unsigned offsetInString = glyphBuffer.offsetInString(index);
1064 if (offsetInString == GlyphBuffer::noOffset) {
1065 // We have no idea which character spawned this glyph. Bail.
1066 return GlyphToPathTranslator::GlyphUnderlineType::DrawOverGlyph;
1069 if (textRun.is8Bit())
1070 baseCharacter = textRun.characters8()[offsetInString];
1072 U16_NEXT(textRun.characters16(), offsetInString, textRun.length(), baseCharacter);
1074 // u_getIntPropertyValue with UCHAR_IDEOGRAPHIC doesn't return true for Japanese or Korean codepoints.
1075 // Instead, we can use the "Unicode allocation block" for the character.
1076 UBlockCode blockCode = ublock_getCode(baseCharacter);
1077 switch (blockCode) {
1078 case UBLOCK_CJK_RADICALS_SUPPLEMENT:
1079 case UBLOCK_CJK_SYMBOLS_AND_PUNCTUATION:
1080 case UBLOCK_ENCLOSED_CJK_LETTERS_AND_MONTHS:
1081 case UBLOCK_CJK_COMPATIBILITY:
1082 case UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A:
1083 case UBLOCK_CJK_UNIFIED_IDEOGRAPHS:
1084 case UBLOCK_CJK_COMPATIBILITY_IDEOGRAPHS:
1085 case UBLOCK_CJK_COMPATIBILITY_FORMS:
1086 case UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B:
1087 case UBLOCK_CJK_COMPATIBILITY_IDEOGRAPHS_SUPPLEMENT:
1088 case UBLOCK_CJK_STROKES:
1089 case UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_C:
1090 case UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_D:
1091 case UBLOCK_IDEOGRAPHIC_DESCRIPTION_CHARACTERS:
1092 case UBLOCK_LINEAR_B_IDEOGRAMS:
1093 case UBLOCK_ENCLOSED_IDEOGRAPHIC_SUPPLEMENT:
1094 case UBLOCK_HIRAGANA:
1095 case UBLOCK_KATAKANA:
1096 case UBLOCK_BOPOMOFO:
1097 case UBLOCK_BOPOMOFO_EXTENDED:
1098 case UBLOCK_HANGUL_JAMO:
1099 case UBLOCK_HANGUL_COMPATIBILITY_JAMO:
1100 case UBLOCK_HANGUL_SYLLABLES:
1101 case UBLOCK_HANGUL_JAMO_EXTENDED_A:
1102 case UBLOCK_HANGUL_JAMO_EXTENDED_B:
1103 return GlyphToPathTranslator::GlyphUnderlineType::DrawOverGlyph;
1105 return GlyphToPathTranslator::GlyphUnderlineType::SkipDescenders;