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>
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 const uint8_t Font::s_roundingHackCharacterTable[256] = {
54 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,
55 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 /*?*/,
56 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,
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 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,
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 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
64 Font::CodePath Font::s_codePath = Auto;
66 TypesettingFeatures Font::s_defaultTypesettingFeatures = 0;
68 // ============================================================================================
69 // Font Implementation (Cross-Platform Portion)
70 // ============================================================================================
75 , m_needsTranscoding(false)
76 , m_typesettingFeatures(0)
80 Font::Font(const FontDescription& fd, short letterSpacing, short wordSpacing)
81 : m_fontDescription(fd)
82 , m_letterSpacing(letterSpacing)
83 , m_wordSpacing(wordSpacing)
84 , m_needsTranscoding(fontTranscoder().needsTranscoding(fd))
85 , m_typesettingFeatures(computeTypesettingFeatures())
89 Font::Font(const FontPlatformData& fontData, bool isPrinterFont, FontSmoothingMode fontSmoothingMode)
90 : m_glyphs(FontGlyphs::createForPlatformFont(fontData))
93 , m_typesettingFeatures(computeTypesettingFeatures())
95 m_fontDescription.setUsePrinterFont(isPrinterFont);
96 m_fontDescription.setFontSmoothing(fontSmoothingMode);
97 m_needsTranscoding = fontTranscoder().needsTranscoding(fontDescription());
100 Font::Font(const Font& other)
101 : m_fontDescription(other.m_fontDescription)
102 , m_glyphs(other.m_glyphs)
103 , m_letterSpacing(other.m_letterSpacing)
104 , m_wordSpacing(other.m_wordSpacing)
105 , m_needsTranscoding(other.m_needsTranscoding)
106 , m_typesettingFeatures(computeTypesettingFeatures())
110 Font& Font::operator=(const Font& other)
112 m_fontDescription = other.m_fontDescription;
113 m_glyphs = other.m_glyphs;
114 m_letterSpacing = other.m_letterSpacing;
115 m_wordSpacing = other.m_wordSpacing;
116 m_needsTranscoding = other.m_needsTranscoding;
117 m_typesettingFeatures = other.m_typesettingFeatures;
121 bool Font::operator==(const Font& other) const
123 // Our FontData don't have to be checked, since checking the font description will be fine.
124 // FIXME: This does not work if the font was made with the FontPlatformData constructor.
125 if (loadingCustomFonts() || other.loadingCustomFonts())
128 if (m_fontDescription != other.m_fontDescription || m_letterSpacing != other.m_letterSpacing || m_wordSpacing != other.m_wordSpacing)
130 if (m_glyphs == other.m_glyphs)
132 if (!m_glyphs || !other.m_glyphs)
134 if (m_glyphs->fontSelector() != other.m_glyphs->fontSelector())
136 // Can these cases actually somehow occur? All fonts should get wiped out by full style recalc.
137 if (m_glyphs->fontSelectorVersion() != other.m_glyphs->fontSelectorVersion())
139 if (m_glyphs->generation() != other.m_glyphs->generation())
144 struct FontGlyphsCacheKey {
145 // This part of the key is shared with the lower level FontCache (caching FontData objects).
146 FontDescriptionFontDataCacheKey fontDescriptionCacheKey;
147 Vector<AtomicString, 3> families;
148 unsigned fontSelectorId;
149 unsigned fontSelectorVersion;
150 unsigned fontSelectorFlags;
153 struct FontGlyphsCacheEntry {
154 WTF_MAKE_FAST_ALLOCATED;
156 FontGlyphsCacheKey key;
157 RefPtr<FontGlyphs> glyphs;
160 typedef HashMap<unsigned, OwnPtr<FontGlyphsCacheEntry>, AlreadyHashed> FontGlyphsCache;
162 static bool operator==(const FontGlyphsCacheKey& a, const FontGlyphsCacheKey& b)
164 if (a.fontDescriptionCacheKey != b.fontDescriptionCacheKey)
166 if (a.families != b.families)
168 if (a.fontSelectorId != b.fontSelectorId || a.fontSelectorVersion != b.fontSelectorVersion || a.fontSelectorFlags != b.fontSelectorFlags)
173 static FontGlyphsCache& fontGlyphsCache()
175 DEFINE_STATIC_LOCAL(FontGlyphsCache, cache, ());
179 void invalidateFontGlyphsCache()
181 fontGlyphsCache().clear();
184 static unsigned makeFontSelectorFlags(const FontDescription& description)
186 return static_cast<unsigned>(description.script()) << 1 | static_cast<unsigned>(description.smallCaps());
189 static void makeFontGlyphsCacheKey(FontGlyphsCacheKey& key, const FontDescription& description, FontSelector* fontSelector)
191 key.fontDescriptionCacheKey = FontDescriptionFontDataCacheKey(description);
192 for (unsigned i = 0; i < description.familyCount(); ++i)
193 key.families.append(description.familyAt(i).lower());
194 key.fontSelectorId = fontSelector ? fontSelector->uniqueId() : 0;
195 key.fontSelectorVersion = fontSelector ? fontSelector->version() : 0;
196 key.fontSelectorFlags = fontSelector && fontSelector->resolvesFamilyFor(description) ? makeFontSelectorFlags(description) : 0;
199 static unsigned computeFontGlyphsCacheHash(const FontGlyphsCacheKey& key)
201 unsigned hashCodes[5] = {
202 StringHasher::hashMemory(key.families.data(), key.families.size() * sizeof(key.families[0])),
203 key.fontDescriptionCacheKey.computeHash(),
205 key.fontSelectorVersion,
206 key.fontSelectorFlags
208 return StringHasher::hashMemory<sizeof(hashCodes)>(hashCodes);
211 void pruneUnreferencedEntriesFromFontGlyphsCache()
213 Vector<unsigned, 50> toRemove;
214 FontGlyphsCache::iterator end = fontGlyphsCache().end();
215 for (FontGlyphsCache::iterator it = fontGlyphsCache().begin(); it != end; ++it) {
216 if (it->value->glyphs->hasOneRef())
217 toRemove.append(it->key);
219 for (unsigned i = 0; i < toRemove.size(); ++i)
220 fontGlyphsCache().remove(toRemove[i]);
223 static PassRefPtr<FontGlyphs> retrieveOrAddCachedFontGlyphs(const FontDescription& fontDescription, PassRefPtr<FontSelector> fontSelector)
225 FontGlyphsCacheKey key;
226 makeFontGlyphsCacheKey(key, fontDescription, fontSelector.get());
228 unsigned hash = computeFontGlyphsCacheHash(key);
229 FontGlyphsCache::AddResult addResult = fontGlyphsCache().add(hash, PassOwnPtr<FontGlyphsCacheEntry>());
230 if (!addResult.isNewEntry && addResult.iterator->value->key == key)
231 return addResult.iterator->value->glyphs;
233 OwnPtr<FontGlyphsCacheEntry>& newEntry = addResult.iterator->value;
234 newEntry = adoptPtr(new FontGlyphsCacheEntry);
235 newEntry->glyphs = FontGlyphs::create(fontSelector);
237 RefPtr<FontGlyphs> glyphs = newEntry->glyphs;
239 static const unsigned unreferencedPruneInterval = 50;
240 static const int maximumEntries = 400;
241 static unsigned pruneCounter;
242 // Referenced FontGlyphs would exist anyway so pruning them saves little memory.
243 if (!(++pruneCounter % unreferencedPruneInterval))
244 pruneUnreferencedEntriesFromFontGlyphsCache();
245 // Prevent pathological growth.
246 if (fontGlyphsCache().size() > maximumEntries)
247 fontGlyphsCache().remove(fontGlyphsCache().begin());
251 void Font::update(PassRefPtr<FontSelector> fontSelector) const
253 m_glyphs = retrieveOrAddCachedFontGlyphs(m_fontDescription, fontSelector.get());
254 m_typesettingFeatures = computeTypesettingFeatures();
257 void Font::drawText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, int from, int to, CustomFontNotReadyAction customFontNotReadyAction) const
259 // Don't draw anything while we are using custom fonts that are in the process of loading,
260 // except if the 'force' argument is set to true (in which case it will use a fallback
262 if (loadingCustomFonts() && customFontNotReadyAction == DoNotPaintIfFontNotReady)
265 to = (to == -1 ? run.length() : to);
267 CodePath codePathToUse = codePath(run);
268 // FIXME: Use the fast code path once it handles partial runs with kerning and ligatures. See http://webkit.org/b/100050
269 if (codePathToUse != Complex && typesettingFeatures() && (from || to != run.length()))
270 codePathToUse = Complex;
272 if (codePathToUse != Complex)
273 return drawSimpleText(context, run, point, from, to);
275 return drawComplexText(context, run, point, from, to);
278 void Font::drawEmphasisMarks(GraphicsContext* context, const TextRun& run, const AtomicString& mark, const FloatPoint& point, int from, int to) const
280 if (loadingCustomFonts())
286 CodePath codePathToUse = codePath(run);
287 // FIXME: Use the fast code path once it handles partial runs with kerning and ligatures. See http://webkit.org/b/100050
288 if (codePathToUse != Complex && typesettingFeatures() && (from || to != run.length()))
289 codePathToUse = Complex;
291 if (codePathToUse != Complex)
292 drawEmphasisMarksForSimpleText(context, run, mark, point, from, to);
294 drawEmphasisMarksForComplexText(context, run, mark, point, from, to);
297 float Font::width(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const
299 CodePath codePathToUse = codePath(run);
300 if (codePathToUse != Complex) {
301 // 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.
302 if (!canReturnFallbackFontsForComplexText())
304 // The simple path can optimize the case where glyph overflow is not observable.
305 if (codePathToUse != SimpleWithGlyphOverflow && (glyphOverflow && !glyphOverflow->computeBounds))
309 bool hasKerningOrLigatures = typesettingFeatures() & (Kerning | Ligatures);
310 bool hasWordSpacingOrLetterSpacing = wordSpacing() | letterSpacing();
311 float* cacheEntry = m_glyphs->widthCache().add(run, std::numeric_limits<float>::quiet_NaN(), hasKerningOrLigatures, hasWordSpacingOrLetterSpacing, glyphOverflow);
312 if (cacheEntry && !std::isnan(*cacheEntry))
315 HashSet<const SimpleFontData*> localFallbackFonts;
317 fallbackFonts = &localFallbackFonts;
320 if (codePathToUse == Complex)
321 result = floatWidthForComplexText(run, fallbackFonts, glyphOverflow);
323 result = floatWidthForSimpleText(run, fallbackFonts, glyphOverflow);
325 if (cacheEntry && fallbackFonts->isEmpty())
326 *cacheEntry = result;
330 float Font::width(const TextRun& run, int& charsConsumed, String& glyphName) const
332 #if ENABLE(SVG_FONTS)
333 if (TextRun::RenderingContext* renderingContext = run.renderingContext())
334 return renderingContext->floatWidthUsingSVGFont(*this, run, charsConsumed, glyphName);
337 charsConsumed = run.length();
343 PassOwnPtr<TextLayout> Font::createLayout(RenderText*, float, bool) const
348 void Font::deleteLayout(TextLayout*)
352 float Font::width(TextLayout&, unsigned, unsigned, HashSet<const SimpleFontData*>*)
354 ASSERT_NOT_REACHED();
359 FloatRect Font::selectionRectForText(const TextRun& run, const FloatPoint& point, int h, int from, int to) const
361 to = (to == -1 ? run.length() : to);
363 CodePath codePathToUse = codePath(run);
364 // FIXME: Use the fast code path once it handles partial runs with kerning and ligatures. See http://webkit.org/b/100050
365 if (codePathToUse != Complex && typesettingFeatures() && (from || to != run.length()))
366 codePathToUse = Complex;
368 if (codePathToUse != Complex)
369 return selectionRectForSimpleText(run, point, h, from, to);
371 return selectionRectForComplexText(run, point, h, from, to);
374 int Font::offsetForPosition(const TextRun& run, float x, bool includePartialGlyphs) const
376 // FIXME: Use the fast code path once it handles partial runs with kerning and ligatures. See http://webkit.org/b/100050
377 if (codePath(run) != Complex && !typesettingFeatures())
378 return offsetForPositionForSimpleText(run, x, includePartialGlyphs);
380 return offsetForPositionForComplexText(run, x, includePartialGlyphs);
383 template <typename CharacterType>
384 static inline String normalizeSpacesInternal(const CharacterType* characters, unsigned length)
386 StringBuilder normalized;
387 normalized.reserveCapacity(length);
389 for (unsigned i = 0; i < length; ++i)
390 normalized.append(Font::normalizeSpaces(characters[i]));
392 return normalized.toString();
395 String Font::normalizeSpaces(const LChar* characters, unsigned length)
397 return normalizeSpacesInternal(characters, length);
400 String Font::normalizeSpaces(const UChar* characters, unsigned length)
402 return normalizeSpacesInternal(characters, length);
405 static bool shouldUseFontSmoothing = true;
407 void Font::setShouldUseSmoothing(bool shouldUseSmoothing)
409 ASSERT(isMainThread());
410 shouldUseFontSmoothing = shouldUseSmoothing;
413 bool Font::shouldUseSmoothing()
415 return shouldUseFontSmoothing;
418 void Font::setCodePath(CodePath p)
423 Font::CodePath Font::codePath()
428 void Font::setDefaultTypesettingFeatures(TypesettingFeatures typesettingFeatures)
430 s_defaultTypesettingFeatures = typesettingFeatures;
433 TypesettingFeatures Font::defaultTypesettingFeatures()
435 return s_defaultTypesettingFeatures;
438 Font::CodePath Font::codePath(const TextRun& run) const
440 if (s_codePath != Auto)
443 #if ENABLE(SVG_FONTS)
444 if (run.renderingContext())
448 if (m_fontDescription.featureSettings() && m_fontDescription.featureSettings()->size() > 0)
451 if (run.length() > 1 && !WidthIterator::supportsTypesettingFeatures(*this))
454 if (!run.characterScanForCodePath())
460 // Start from 0 since drawing and highlighting also measure the characters before run->from.
461 return characterRangeCodePath(run.characters16(), run.length());
464 Font::CodePath Font::characterRangeCodePath(const UChar* characters, unsigned len)
466 // FIXME: Should use a UnicodeSet in ports where ICU is used. Note that we
467 // can't simply use UnicodeCharacter Property/class because some characters
468 // are not 'combining', but still need to go to the complex path.
469 // Alternatively, we may as well consider binary search over a sorted
471 CodePath result = Simple;
472 for (unsigned i = 0; i < len; i++) {
473 const UChar c = characters[i];
474 if (c < 0x2E5) // U+02E5 through U+02E9 (Modifier Letters : Tone letters)
479 if (c < 0x300) // U+0300 through U+036F Combining diacritical marks
484 if (c < 0x0591 || c == 0x05BE) // U+0591 through U+05CF excluding U+05BE Hebrew combining marks, Hebrew punctuation Paseq, Sof Pasuq and Nun Hafukha
489 // U+0600 through U+109F Arabic, Syriac, Thaana, NKo, Samaritan, Mandaic,
490 // Devanagari, Bengali, Gurmukhi, Gujarati, Oriya, Tamil, Telugu, Kannada,
491 // Malayalam, Sinhala, Thai, Lao, Tibetan, Myanmar
497 // U+1100 through U+11FF Hangul Jamo (only Ancient Korean should be left here if you precompose;
498 // Modern Korean will be precomposed as a result of step A)
504 if (c < 0x135D) // U+135D through U+135F Ethiopic combining marks
509 if (c < 0x1700) // U+1780 through U+18AF Tagalog, Hanunoo, Buhid, Taghanwa,Khmer, Mongolian
514 if (c < 0x1900) // U+1900 through U+194F Limbu (Unicode 4.0)
519 if (c < 0x1980) // U+1980 through U+19DF New Tai Lue
524 if (c < 0x1A00) // U+1A00 through U+1CFF Buginese, Tai Tham, Balinese, Batak, Lepcha, Vedic
529 if (c < 0x1DC0) // U+1DC0 through U+1DFF Comining diacritical mark supplement
534 // U+1E00 through U+2000 characters with diacritics and stacked diacritics
536 result = SimpleWithGlyphOverflow;
540 if (c < 0x20D0) // U+20D0 through U+20FF Combining marks for symbols
545 if (c < 0x2CEF) // U+2CEF through U+2CF1 Combining marks for Coptic
550 if (c < 0x302A) // U+302A through U+302F Ideographic and Hangul Tone marks
555 if (c < 0xA67C) // U+A67C through U+A67D Combining marks for old Cyrillic
560 if (c < 0xA6F0) // U+A6F0 through U+A6F1 Combining mark for Bamum
565 // U+A800 through U+ABFF Nagri, Phags-pa, Saurashtra, Devanagari Extended,
566 // Hangul Jamo Ext. A, Javanese, Myanmar Extended A, Tai Viet, Meetei Mayek,
572 if (c < 0xD7B0) // U+D7B0 through U+D7FF Hangul Jamo Ext. B
583 UChar next = characters[++i];
584 if (!U16_IS_TRAIL(next))
587 UChar32 supplementaryCharacter = U16_GET_SUPPLEMENTARY(c, next);
589 if (supplementaryCharacter < 0x1F1E6) // U+1F1E6 through U+1F1FF Regional Indicator Symbols
591 if (supplementaryCharacter <= 0x1F1FF)
594 if (supplementaryCharacter < 0xE0100) // U+E0100 through U+E01EF Unicode variation selectors.
596 if (supplementaryCharacter <= 0xE01EF)
599 // FIXME: Check for Brahmi (U+11000 block), Kaithi (U+11080 block) and other complex scripts
600 // in plane 1 or higher.
605 if (c < 0xFE00) // U+FE00 through U+FE0F Unicode variation selectors
610 if (c < 0xFE20) // U+FE20 through U+FE2F Combining half marks
618 bool Font::isCJKIdeograph(UChar32 c)
620 // The basic CJK Unified Ideographs block.
621 if (c >= 0x4E00 && c <= 0x9FFF)
624 // CJK Unified Ideographs Extension A.
625 if (c >= 0x3400 && c <= 0x4DBF)
628 // CJK Radicals Supplement.
629 if (c >= 0x2E80 && c <= 0x2EFF)
633 if (c >= 0x2F00 && c <= 0x2FDF)
637 if (c >= 0x31C0 && c <= 0x31EF)
640 // CJK Compatibility Ideographs.
641 if (c >= 0xF900 && c <= 0xFAFF)
644 // CJK Unified Ideographs Extension B.
645 if (c >= 0x20000 && c <= 0x2A6DF)
648 // CJK Unified Ideographs Extension C.
649 if (c >= 0x2A700 && c <= 0x2B73F)
652 // CJK Unified Ideographs Extension D.
653 if (c >= 0x2B740 && c <= 0x2B81F)
656 // CJK Compatibility Ideographs Supplement.
657 if (c >= 0x2F800 && c <= 0x2FA1F)
663 bool Font::isCJKIdeographOrSymbol(UChar32 c)
665 // 0x2C7 Caron, Mandarin Chinese 3rd Tone
666 // 0x2CA Modifier Letter Acute Accent, Mandarin Chinese 2nd Tone
667 // 0x2CB Modifier Letter Grave Access, Mandarin Chinese 4th Tone
668 // 0x2D9 Dot Above, Mandarin Chinese 5th Tone
669 if ((c == 0x2C7) || (c == 0x2CA) || (c == 0x2CB) || (c == 0x2D9))
672 if ((c == 0x2020) || (c == 0x2021) || (c == 0x2030) || (c == 0x203B) || (c == 0x203C)
673 || (c == 0x2042) || (c == 0x2047) || (c == 0x2048) || (c == 0x2049) || (c == 0x2051)
674 || (c == 0x20DD) || (c == 0x20DE) || (c == 0x2100) || (c == 0x2103) || (c == 0x2105)
675 || (c == 0x2109) || (c == 0x210A) || (c == 0x2113) || (c == 0x2116) || (c == 0x2121)
676 || (c == 0x212B) || (c == 0x213B) || (c == 0x2150) || (c == 0x2151) || (c == 0x2152))
679 if (c >= 0x2156 && c <= 0x215A)
682 if (c >= 0x2160 && c <= 0x216B)
685 if (c >= 0x2170 && c <= 0x217B)
688 if ((c == 0x217F) || (c == 0x2189) || (c == 0x2307) || (c == 0x2312) || (c == 0x23BE) || (c == 0x23BF))
691 if (c >= 0x23C0 && c <= 0x23CC)
694 if ((c == 0x23CE) || (c == 0x2423))
697 if (c >= 0x2460 && c <= 0x2492)
700 if (c >= 0x249C && c <= 0x24FF)
703 if ((c == 0x25A0) || (c == 0x25A1) || (c == 0x25A2) || (c == 0x25AA) || (c == 0x25AB))
706 if ((c == 0x25B1) || (c == 0x25B2) || (c == 0x25B3) || (c == 0x25B6) || (c == 0x25B7) || (c == 0x25BC) || (c == 0x25BD))
709 if ((c == 0x25C0) || (c == 0x25C1) || (c == 0x25C6) || (c == 0x25C7) || (c == 0x25C9) || (c == 0x25CB) || (c == 0x25CC))
712 if (c >= 0x25CE && c <= 0x25D3)
715 if (c >= 0x25E2 && c <= 0x25E6)
721 if (c >= 0x2600 && c <= 0x2603)
724 if ((c == 0x2605) || (c == 0x2606) || (c == 0x260E) || (c == 0x2616) || (c == 0x2617) || (c == 0x2640) || (c == 0x2642))
727 if (c >= 0x2660 && c <= 0x266F)
730 if (c >= 0x2672 && c <= 0x267D)
733 if ((c == 0x26A0) || (c == 0x26BD) || (c == 0x26BE) || (c == 0x2713) || (c == 0x271A) || (c == 0x273F) || (c == 0x2740) || (c == 0x2756))
736 if (c >= 0x2776 && c <= 0x277F)
742 // Ideographic Description Characters.
743 if (c >= 0x2FF0 && c <= 0x2FFF)
746 // CJK Symbols and Punctuation, excluding 0x3030.
747 if (c >= 0x3000 && c < 0x3030)
750 if (c > 0x3030 && c <= 0x303F)
754 if (c >= 0x3040 && c <= 0x309F)
758 if (c >= 0x30A0 && c <= 0x30FF)
762 if (c >= 0x3100 && c <= 0x312F)
765 if (c >= 0x3190 && c <= 0x319F)
769 if (c >= 0x31A0 && c <= 0x31BF)
772 // Enclosed CJK Letters and Months.
773 if (c >= 0x3200 && c <= 0x32FF)
776 // CJK Compatibility.
777 if (c >= 0x3300 && c <= 0x33FF)
780 if (c >= 0xF860 && c <= 0xF862)
783 // CJK Compatibility Forms.
784 if (c >= 0xFE30 && c <= 0xFE4F)
787 if ((c == 0xFE10) || (c == 0xFE11) || (c == 0xFE12) || (c == 0xFE19))
790 if ((c == 0xFF0D) || (c == 0xFF1B) || (c == 0xFF1C) || (c == 0xFF1E))
793 // Halfwidth and Fullwidth Forms
794 // Usually only used in CJK
795 if (c >= 0xFF00 && c <= 0xFFEF)
802 if (c >= 0x1F110 && c <= 0x1F129)
805 if (c >= 0x1F130 && c <= 0x1F149)
808 if (c >= 0x1F150 && c <= 0x1F169)
811 if (c >= 0x1F170 && c <= 0x1F189)
814 if (c >= 0x1F200 && c <= 0x1F6F)
817 return isCJKIdeograph(c);
820 unsigned Font::expansionOpportunityCount(const LChar* characters, size_t length, TextDirection direction, bool& isAfterExpansion)
823 if (direction == LTR) {
824 for (size_t i = 0; i < length; ++i) {
825 if (treatAsSpace(characters[i])) {
827 isAfterExpansion = true;
829 isAfterExpansion = false;
832 for (size_t i = length; i > 0; --i) {
833 if (treatAsSpace(characters[i - 1])) {
835 isAfterExpansion = true;
837 isAfterExpansion = false;
843 unsigned Font::expansionOpportunityCount(const UChar* characters, size_t length, TextDirection direction, bool& isAfterExpansion)
845 static bool expandAroundIdeographs = canExpandAroundIdeographsInComplexText();
847 if (direction == LTR) {
848 for (size_t i = 0; i < length; ++i) {
849 UChar32 character = characters[i];
850 if (treatAsSpace(character)) {
852 isAfterExpansion = true;
855 if (U16_IS_LEAD(character) && i + 1 < length && U16_IS_TRAIL(characters[i + 1])) {
856 character = U16_GET_SUPPLEMENTARY(character, characters[i + 1]);
859 if (expandAroundIdeographs && isCJKIdeographOrSymbol(character)) {
860 if (!isAfterExpansion)
863 isAfterExpansion = true;
866 isAfterExpansion = false;
869 for (size_t i = length; i > 0; --i) {
870 UChar32 character = characters[i - 1];
871 if (treatAsSpace(character)) {
873 isAfterExpansion = true;
876 if (U16_IS_TRAIL(character) && i > 1 && U16_IS_LEAD(characters[i - 2])) {
877 character = U16_GET_SUPPLEMENTARY(characters[i - 2], character);
880 if (expandAroundIdeographs && isCJKIdeographOrSymbol(character)) {
881 if (!isAfterExpansion)
884 isAfterExpansion = true;
887 isAfterExpansion = false;
893 bool Font::canReceiveTextEmphasis(UChar32 c)
895 CharCategory category = Unicode::category(c);
896 if (category & (Separator_Space | Separator_Line | Separator_Paragraph | Other_NotAssigned | Other_Control | Other_Format))
899 // Additional word-separator characters listed in CSS Text Level 3 Editor's Draft 3 November 2010.
900 if (c == ethiopicWordspace || c == aegeanWordSeparatorLine || c == aegeanWordSeparatorDot
901 || c == ugariticWordDivider || c == tibetanMarkIntersyllabicTsheg || c == tibetanMarkDelimiterTshegBstar)