REGRESSION: Lines jump up and down while typing Chinese or Japanese
[WebKit-https.git] / Source / WebCore / platform / graphics / Font.cpp
1 /*
2  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
4  *           (C) 2000 Dirk Mueller (mueller@kde.org)
5  * Copyright (C) 2003, 2006, 2010, 2011 Apple Inc. All rights reserved.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public License
18  * along with this library; see the file COPYING.LIB.  If not, write to
19  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20  * Boston, MA 02110-1301, USA.
21  *
22  */
23
24 #include "config.h"
25 #include "Font.h"
26
27 #include "FloatRect.h"
28 #include "FontCache.h"
29 #include "FontTranscoder.h"
30 #include "IntPoint.h"
31 #include "GlyphBuffer.h"
32 #include "TextRun.h"
33 #include "WidthIterator.h"
34 #include <wtf/MainThread.h>
35 #include <wtf/MathExtras.h>
36 #include <wtf/text/StringBuilder.h>
37
38 using namespace WTF;
39 using namespace Unicode;
40
41 namespace WTF {
42
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)
45 {
46     WebCore::Font::deleteLayout(ptr);
47 }
48
49 }
50
51 namespace WebCore {
52
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
62 };
63
64 Font::CodePath Font::s_codePath = Auto;
65
66 TypesettingFeatures Font::s_defaultTypesettingFeatures = 0;
67
68 // ============================================================================================
69 // Font Implementation (Cross-Platform Portion)
70 // ============================================================================================
71
72 Font::Font()
73     : m_letterSpacing(0)
74     , m_wordSpacing(0)
75     , m_needsTranscoding(false)
76     , m_typesettingFeatures(0)
77 {
78 }
79
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())
86 {
87 }
88
89 Font::Font(const FontPlatformData& fontData, bool isPrinterFont, FontSmoothingMode fontSmoothingMode)
90     : m_glyphs(FontGlyphs::createForPlatformFont(fontData))
91     , m_letterSpacing(0)
92     , m_wordSpacing(0)
93     , m_typesettingFeatures(computeTypesettingFeatures())
94 {
95     m_fontDescription.setUsePrinterFont(isPrinterFont);
96     m_fontDescription.setFontSmoothing(fontSmoothingMode);
97     m_needsTranscoding = fontTranscoder().needsTranscoding(fontDescription());
98 }
99
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())
107 {
108 }
109
110 Font& Font::operator=(const Font& other)
111 {
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;
118     return *this;
119 }
120
121 bool Font::operator==(const Font& other) const
122 {
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())
126         return false;
127
128     if (m_fontDescription != other.m_fontDescription || m_letterSpacing != other.m_letterSpacing || m_wordSpacing != other.m_wordSpacing)
129         return false;
130     if (m_glyphs == other.m_glyphs)
131         return true;
132     if (!m_glyphs || !other.m_glyphs)
133         return false;
134     if (m_glyphs->fontSelector() != other.m_glyphs->fontSelector())
135         return false;
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())
138         return false;
139     if (m_glyphs->generation() != other.m_glyphs->generation())
140         return false;
141     return true;
142 }
143
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;
151 };
152
153 struct FontGlyphsCacheEntry {
154     WTF_MAKE_FAST_ALLOCATED;
155 public:
156     FontGlyphsCacheKey key;
157     RefPtr<FontGlyphs> glyphs;
158 };
159
160 typedef HashMap<unsigned, OwnPtr<FontGlyphsCacheEntry>, AlreadyHashed> FontGlyphsCache;
161
162 static bool operator==(const FontGlyphsCacheKey& a, const FontGlyphsCacheKey& b)
163 {
164     if (a.fontDescriptionCacheKey != b.fontDescriptionCacheKey)
165         return false;
166     if (a.families != b.families)
167         return false;
168     if (a.fontSelectorId != b.fontSelectorId || a.fontSelectorVersion != b.fontSelectorVersion || a.fontSelectorFlags != b.fontSelectorFlags)
169         return false;
170     return true;
171 }
172
173 static FontGlyphsCache& fontGlyphsCache()
174 {
175     DEFINE_STATIC_LOCAL(FontGlyphsCache, cache, ());
176     return cache;
177 }
178
179 void invalidateFontGlyphsCache()
180 {
181     fontGlyphsCache().clear();
182 }
183
184 static unsigned makeFontSelectorFlags(const FontDescription& description)
185 {
186     return static_cast<unsigned>(description.script()) << 1 | static_cast<unsigned>(description.smallCaps());
187 }
188
189 static void makeFontGlyphsCacheKey(FontGlyphsCacheKey& key, const FontDescription& description, FontSelector* fontSelector)
190 {
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;
197 }
198
199 static unsigned computeFontGlyphsCacheHash(const FontGlyphsCacheKey& key)
200 {
201     unsigned hashCodes[5] = {
202         StringHasher::hashMemory(key.families.data(), key.families.size() * sizeof(key.families[0])),
203         key.fontDescriptionCacheKey.computeHash(),
204         key.fontSelectorId,
205         key.fontSelectorVersion,
206         key.fontSelectorFlags
207     };
208     return StringHasher::hashMemory<sizeof(hashCodes)>(hashCodes);
209 }
210
211 void pruneUnreferencedEntriesFromFontGlyphsCache()
212 {
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);
218     }
219     for (unsigned i = 0; i < toRemove.size(); ++i)
220         fontGlyphsCache().remove(toRemove[i]);
221 }
222
223 static PassRefPtr<FontGlyphs> retrieveOrAddCachedFontGlyphs(const FontDescription& fontDescription, PassRefPtr<FontSelector> fontSelector)
224 {
225     FontGlyphsCacheKey key;
226     makeFontGlyphsCacheKey(key, fontDescription, fontSelector.get());
227
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;
232
233     OwnPtr<FontGlyphsCacheEntry>& newEntry = addResult.iterator->value;
234     newEntry = adoptPtr(new FontGlyphsCacheEntry);
235     newEntry->glyphs = FontGlyphs::create(fontSelector);
236     newEntry->key = key;
237     RefPtr<FontGlyphs> glyphs = newEntry->glyphs;
238
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());
248     return glyphs;
249 }
250
251 void Font::update(PassRefPtr<FontSelector> fontSelector) const
252 {
253     m_glyphs = retrieveOrAddCachedFontGlyphs(m_fontDescription, fontSelector.get());
254     m_typesettingFeatures = computeTypesettingFeatures();
255 }
256
257 void Font::drawText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, int from, int to, CustomFontNotReadyAction customFontNotReadyAction) const
258 {
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
261     // font).
262     if (loadingCustomFonts() && customFontNotReadyAction == DoNotPaintIfFontNotReady)
263         return;
264     
265     to = (to == -1 ? run.length() : to);
266
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;
271
272     if (codePathToUse != Complex)
273         return drawSimpleText(context, run, point, from, to);
274
275     return drawComplexText(context, run, point, from, to);
276 }
277
278 void Font::drawEmphasisMarks(GraphicsContext* context, const TextRun& run, const AtomicString& mark, const FloatPoint& point, int from, int to) const
279 {
280     if (loadingCustomFonts())
281         return;
282
283     if (to < 0)
284         to = run.length();
285
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;
290
291     if (codePathToUse != Complex)
292         drawEmphasisMarksForSimpleText(context, run, mark, point, from, to);
293     else
294         drawEmphasisMarksForComplexText(context, run, mark, point, from, to);
295 }
296
297 float Font::width(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const
298 {
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())
303             fallbackFonts = 0;
304         // The simple path can optimize the case where glyph overflow is not observable.
305         if (codePathToUse != SimpleWithGlyphOverflow && (glyphOverflow && !glyphOverflow->computeBounds))
306             glyphOverflow = 0;
307     }
308
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))
313         return *cacheEntry;
314
315     HashSet<const SimpleFontData*> localFallbackFonts;
316     if (!fallbackFonts)
317         fallbackFonts = &localFallbackFonts;
318
319     float result;
320     if (codePathToUse == Complex)
321         result = floatWidthForComplexText(run, fallbackFonts, glyphOverflow);
322     else
323         result = floatWidthForSimpleText(run, fallbackFonts, glyphOverflow);
324
325     if (cacheEntry && fallbackFonts->isEmpty())
326         *cacheEntry = result;
327     return result;
328 }
329
330 float Font::width(const TextRun& run, int& charsConsumed, String& glyphName) const
331 {
332 #if ENABLE(SVG_FONTS)
333     if (TextRun::RenderingContext* renderingContext = run.renderingContext())
334         return renderingContext->floatWidthUsingSVGFont(*this, run, charsConsumed, glyphName);
335 #endif
336
337     charsConsumed = run.length();
338     glyphName = "";
339     return width(run);
340 }
341
342 #if !PLATFORM(MAC)
343 PassOwnPtr<TextLayout> Font::createLayout(RenderText*, float, bool) const
344 {
345     return nullptr;
346 }
347
348 void Font::deleteLayout(TextLayout*)
349 {
350 }
351
352 float Font::width(TextLayout&, unsigned, unsigned, HashSet<const SimpleFontData*>*)
353 {
354     ASSERT_NOT_REACHED();
355     return 0;
356 }
357 #endif
358
359 FloatRect Font::selectionRectForText(const TextRun& run, const FloatPoint& point, int h, int from, int to) const
360 {
361     to = (to == -1 ? run.length() : to);
362
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;
367
368     if (codePathToUse != Complex)
369         return selectionRectForSimpleText(run, point, h, from, to);
370
371     return selectionRectForComplexText(run, point, h, from, to);
372 }
373
374 int Font::offsetForPosition(const TextRun& run, float x, bool includePartialGlyphs) const
375 {
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);
379
380     return offsetForPositionForComplexText(run, x, includePartialGlyphs);
381 }
382
383 template <typename CharacterType>
384 static inline String normalizeSpacesInternal(const CharacterType* characters, unsigned length)
385 {
386     StringBuilder normalized;
387     normalized.reserveCapacity(length);
388
389     for (unsigned i = 0; i < length; ++i)
390         normalized.append(Font::normalizeSpaces(characters[i]));
391
392     return normalized.toString();
393 }
394
395 String Font::normalizeSpaces(const LChar* characters, unsigned length)
396 {
397     return normalizeSpacesInternal(characters, length);
398 }
399
400 String Font::normalizeSpaces(const UChar* characters, unsigned length)
401 {
402     return normalizeSpacesInternal(characters, length);
403 }
404
405 static bool shouldUseFontSmoothing = true;
406
407 void Font::setShouldUseSmoothing(bool shouldUseSmoothing)
408 {
409     ASSERT(isMainThread());
410     shouldUseFontSmoothing = shouldUseSmoothing;
411 }
412
413 bool Font::shouldUseSmoothing()
414 {
415     return shouldUseFontSmoothing;
416 }
417
418 void Font::setCodePath(CodePath p)
419 {
420     s_codePath = p;
421 }
422
423 Font::CodePath Font::codePath()
424 {
425     return s_codePath;
426 }
427
428 void Font::setDefaultTypesettingFeatures(TypesettingFeatures typesettingFeatures)
429 {
430     s_defaultTypesettingFeatures = typesettingFeatures;
431 }
432
433 TypesettingFeatures Font::defaultTypesettingFeatures()
434 {
435     return s_defaultTypesettingFeatures;
436 }
437
438 Font::CodePath Font::codePath(const TextRun& run) const
439 {
440     if (s_codePath != Auto)
441         return s_codePath;
442
443 #if ENABLE(SVG_FONTS)
444     if (run.renderingContext())
445         return Simple;
446 #endif
447
448     if (m_fontDescription.featureSettings() && m_fontDescription.featureSettings()->size() > 0)
449         return Complex;
450     
451     if (run.length() > 1 && !WidthIterator::supportsTypesettingFeatures(*this))
452         return Complex;
453
454     if (!run.characterScanForCodePath())
455         return Simple;
456
457     if (run.is8Bit())
458         return Simple;
459
460     // Start from 0 since drawing and highlighting also measure the characters before run->from.
461     return characterRangeCodePath(run.characters16(), run.length());
462 }
463
464 Font::CodePath Font::characterRangeCodePath(const UChar* characters, unsigned len)
465 {
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
470     // list of ranges.
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)  
475             continue;
476         if (c <= 0x2E9) 
477             return Complex;
478
479         if (c < 0x300) // U+0300 through U+036F Combining diacritical marks
480             continue;
481         if (c <= 0x36F)
482             return Complex;
483
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
485             continue;
486         if (c <= 0x05CF)
487             return Complex;
488
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
492         if (c < 0x0600) 
493             continue;
494         if (c <= 0x109F)
495             return Complex;
496
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)
499         if (c < 0x1100)
500             continue;
501         if (c <= 0x11FF)
502             return Complex;
503
504         if (c < 0x135D) // U+135D through U+135F Ethiopic combining marks
505             continue;
506         if (c <= 0x135F)
507             return Complex;
508
509         if (c < 0x1700) // U+1780 through U+18AF Tagalog, Hanunoo, Buhid, Taghanwa,Khmer, Mongolian
510             continue;
511         if (c <= 0x18AF)
512             return Complex;
513
514         if (c < 0x1900) // U+1900 through U+194F Limbu (Unicode 4.0)
515             continue;
516         if (c <= 0x194F)
517             return Complex;
518
519         if (c < 0x1980) // U+1980 through U+19DF New Tai Lue
520             continue;
521         if (c <= 0x19DF)
522             return Complex;
523
524         if (c < 0x1A00) // U+1A00 through U+1CFF Buginese, Tai Tham, Balinese, Batak, Lepcha, Vedic
525             continue;
526         if (c <= 0x1CFF)
527             return Complex;
528
529         if (c < 0x1DC0) // U+1DC0 through U+1DFF Comining diacritical mark supplement
530             continue;
531         if (c <= 0x1DFF)
532             return Complex;
533
534         // U+1E00 through U+2000 characters with diacritics and stacked diacritics
535         if (c <= 0x2000) {
536             result = SimpleWithGlyphOverflow;
537             continue;
538         }
539
540         if (c < 0x20D0) // U+20D0 through U+20FF Combining marks for symbols
541             continue;
542         if (c <= 0x20FF)
543             return Complex;
544
545         if (c < 0x2CEF) // U+2CEF through U+2CF1 Combining marks for Coptic
546             continue;
547         if (c <= 0x2CF1)
548             return Complex;
549
550         if (c < 0x302A) // U+302A through U+302F Ideographic and Hangul Tone marks
551             continue;
552         if (c <= 0x302F)
553             return Complex;
554
555         if (c < 0xA67C) // U+A67C through U+A67D Combining marks for old Cyrillic
556             continue;
557         if (c <= 0xA67D)
558             return Complex;
559
560         if (c < 0xA6F0) // U+A6F0 through U+A6F1 Combining mark for Bamum
561             continue;
562         if (c <= 0xA6F1)
563             return Complex;
564
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,
567         if (c < 0xA800) 
568             continue;
569         if (c <= 0xABFF)
570             return Complex;
571
572         if (c < 0xD7B0) // U+D7B0 through U+D7FF Hangul Jamo Ext. B
573             continue;
574         if (c <= 0xD7FF)
575             return Complex;
576
577         if (c <= 0xDBFF) {
578             // High surrogate
579
580             if (i == len - 1)
581                 continue;
582
583             UChar next = characters[++i];
584             if (!U16_IS_TRAIL(next))
585                 continue;
586
587             UChar32 supplementaryCharacter = U16_GET_SUPPLEMENTARY(c, next);
588
589             if (supplementaryCharacter < 0x1F1E6) // U+1F1E6 through U+1F1FF Regional Indicator Symbols
590                 continue;
591             if (supplementaryCharacter <= 0x1F1FF)
592                 return Complex;
593
594             if (supplementaryCharacter < 0xE0100) // U+E0100 through U+E01EF Unicode variation selectors.
595                 continue;
596             if (supplementaryCharacter <= 0xE01EF)
597                 return Complex;
598
599             // FIXME: Check for Brahmi (U+11000 block), Kaithi (U+11080 block) and other complex scripts
600             // in plane 1 or higher.
601
602             continue;
603         }
604
605         if (c < 0xFE00) // U+FE00 through U+FE0F Unicode variation selectors
606             continue;
607         if (c <= 0xFE0F)
608             return Complex;
609
610         if (c < 0xFE20) // U+FE20 through U+FE2F Combining half marks
611             continue;
612         if (c <= 0xFE2F)
613             return Complex;
614     }
615     return result;
616 }
617
618 bool Font::isCJKIdeograph(UChar32 c)
619 {
620     // The basic CJK Unified Ideographs block.
621     if (c >= 0x4E00 && c <= 0x9FFF)
622         return true;
623     
624     // CJK Unified Ideographs Extension A.
625     if (c >= 0x3400 && c <= 0x4DBF)
626         return true;
627     
628     // CJK Radicals Supplement.
629     if (c >= 0x2E80 && c <= 0x2EFF)
630         return true;
631     
632     // Kangxi Radicals.
633     if (c >= 0x2F00 && c <= 0x2FDF)
634         return true;
635     
636     // CJK Strokes.
637     if (c >= 0x31C0 && c <= 0x31EF)
638         return true;
639     
640     // CJK Compatibility Ideographs.
641     if (c >= 0xF900 && c <= 0xFAFF)
642         return true;
643     
644     // CJK Unified Ideographs Extension B.
645     if (c >= 0x20000 && c <= 0x2A6DF)
646         return true;
647         
648     // CJK Unified Ideographs Extension C.
649     if (c >= 0x2A700 && c <= 0x2B73F)
650         return true;
651     
652     // CJK Unified Ideographs Extension D.
653     if (c >= 0x2B740 && c <= 0x2B81F)
654         return true;
655     
656     // CJK Compatibility Ideographs Supplement.
657     if (c >= 0x2F800 && c <= 0x2FA1F)
658         return true;
659
660     return false;
661 }
662
663 bool Font::isCJKIdeographOrSymbol(UChar32 c)
664 {
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))
670         return true;
671
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))
677         return true;
678
679     if (c >= 0x2156 && c <= 0x215A)
680         return true;
681
682     if (c >= 0x2160 && c <= 0x216B)
683         return true;
684
685     if (c >= 0x2170 && c <= 0x217B)
686         return true;
687
688     if ((c == 0x217F) || (c == 0x2189) || (c == 0x2307) || (c == 0x2312) || (c == 0x23BE) || (c == 0x23BF))
689         return true;
690
691     if (c >= 0x23C0 && c <= 0x23CC)
692         return true;
693
694     if ((c == 0x23CE) || (c == 0x2423))
695         return true;
696
697     if (c >= 0x2460 && c <= 0x2492)
698         return true;
699
700     if (c >= 0x249C && c <= 0x24FF)
701         return true;
702
703     if ((c == 0x25A0) || (c == 0x25A1) || (c == 0x25A2) || (c == 0x25AA) || (c == 0x25AB))
704         return true;
705
706     if ((c == 0x25B1) || (c == 0x25B2) || (c == 0x25B3) || (c == 0x25B6) || (c == 0x25B7) || (c == 0x25BC) || (c == 0x25BD))
707         return true;
708     
709     if ((c == 0x25C0) || (c == 0x25C1) || (c == 0x25C6) || (c == 0x25C7) || (c == 0x25C9) || (c == 0x25CB) || (c == 0x25CC))
710         return true;
711
712     if (c >= 0x25CE && c <= 0x25D3)
713         return true;
714
715     if (c >= 0x25E2 && c <= 0x25E6)
716         return true;
717
718     if (c == 0x25EF)
719         return true;
720
721     if (c >= 0x2600 && c <= 0x2603)
722         return true;
723
724     if ((c == 0x2605) || (c == 0x2606) || (c == 0x260E) || (c == 0x2616) || (c == 0x2617) || (c == 0x2640) || (c == 0x2642))
725         return true;
726
727     if (c >= 0x2660 && c <= 0x266F)
728         return true;
729
730     if (c >= 0x2672 && c <= 0x267D)
731         return true;
732
733     if ((c == 0x26A0) || (c == 0x26BD) || (c == 0x26BE) || (c == 0x2713) || (c == 0x271A) || (c == 0x273F) || (c == 0x2740) || (c == 0x2756))
734         return true;
735
736     if (c >= 0x2776 && c <= 0x277F)
737         return true;
738
739     if (c == 0x2B1A)
740         return true;
741
742     // Ideographic Description Characters.
743     if (c >= 0x2FF0 && c <= 0x2FFF)
744         return true;
745     
746     // CJK Symbols and Punctuation, excluding 0x3030.
747     if (c >= 0x3000 && c < 0x3030)
748         return true;
749
750     if (c > 0x3030 && c <= 0x303F)
751         return true;
752
753     // Hiragana
754     if (c >= 0x3040 && c <= 0x309F)
755         return true;
756
757     // Katakana 
758     if (c >= 0x30A0 && c <= 0x30FF)
759         return true;
760
761     // Bopomofo
762     if (c >= 0x3100 && c <= 0x312F)
763         return true;
764
765     if (c >= 0x3190 && c <= 0x319F)
766         return true;
767
768     // Bopomofo Extended
769     if (c >= 0x31A0 && c <= 0x31BF)
770         return true;
771  
772     // Enclosed CJK Letters and Months.
773     if (c >= 0x3200 && c <= 0x32FF)
774         return true;
775     
776     // CJK Compatibility.
777     if (c >= 0x3300 && c <= 0x33FF)
778         return true;
779
780     if (c >= 0xF860 && c <= 0xF862)
781         return true;
782
783     // CJK Compatibility Forms.
784     if (c >= 0xFE30 && c <= 0xFE4F)
785         return true;
786
787     if ((c == 0xFE10) || (c == 0xFE11) || (c == 0xFE12) || (c == 0xFE19))
788         return true;
789
790     if ((c == 0xFF0D) || (c == 0xFF1B) || (c == 0xFF1C) || (c == 0xFF1E))
791         return false;
792
793     // Halfwidth and Fullwidth Forms
794     // Usually only used in CJK
795     if (c >= 0xFF00 && c <= 0xFFEF)
796         return true;
797
798     // Emoji.
799     if (c == 0x1F100)
800         return true;
801
802     if (c >= 0x1F110 && c <= 0x1F129)
803         return true;
804
805     if (c >= 0x1F130 && c <= 0x1F149)
806         return true;
807
808     if (c >= 0x1F150 && c <= 0x1F169)
809         return true;
810
811     if (c >= 0x1F170 && c <= 0x1F189)
812         return true;
813
814     if (c >= 0x1F200 && c <= 0x1F6F)
815         return true;
816
817     return isCJKIdeograph(c);
818 }
819
820 unsigned Font::expansionOpportunityCount(const LChar* characters, size_t length, TextDirection direction, bool& isAfterExpansion)
821 {
822     unsigned count = 0;
823     if (direction == LTR) {
824         for (size_t i = 0; i < length; ++i) {
825             if (treatAsSpace(characters[i])) {
826                 count++;
827                 isAfterExpansion = true;
828             } else
829                 isAfterExpansion = false;
830         }
831     } else {
832         for (size_t i = length; i > 0; --i) {
833             if (treatAsSpace(characters[i - 1])) {
834                 count++;
835                 isAfterExpansion = true;
836             } else
837                 isAfterExpansion = false;
838         }
839     }
840     return count;
841 }
842
843 unsigned Font::expansionOpportunityCount(const UChar* characters, size_t length, TextDirection direction, bool& isAfterExpansion)
844 {
845     static bool expandAroundIdeographs = canExpandAroundIdeographsInComplexText();
846     unsigned count = 0;
847     if (direction == LTR) {
848         for (size_t i = 0; i < length; ++i) {
849             UChar32 character = characters[i];
850             if (treatAsSpace(character)) {
851                 count++;
852                 isAfterExpansion = true;
853                 continue;
854             }
855             if (U16_IS_LEAD(character) && i + 1 < length && U16_IS_TRAIL(characters[i + 1])) {
856                 character = U16_GET_SUPPLEMENTARY(character, characters[i + 1]);
857                 i++;
858             }
859             if (expandAroundIdeographs && isCJKIdeographOrSymbol(character)) {
860                 if (!isAfterExpansion)
861                     count++;
862                 count++;
863                 isAfterExpansion = true;
864                 continue;
865             }
866             isAfterExpansion = false;
867         }
868     } else {
869         for (size_t i = length; i > 0; --i) {
870             UChar32 character = characters[i - 1];
871             if (treatAsSpace(character)) {
872                 count++;
873                 isAfterExpansion = true;
874                 continue;
875             }
876             if (U16_IS_TRAIL(character) && i > 1 && U16_IS_LEAD(characters[i - 2])) {
877                 character = U16_GET_SUPPLEMENTARY(characters[i - 2], character);
878                 i--;
879             }
880             if (expandAroundIdeographs && isCJKIdeographOrSymbol(character)) {
881                 if (!isAfterExpansion)
882                     count++;
883                 count++;
884                 isAfterExpansion = true;
885                 continue;
886             }
887             isAfterExpansion = false;
888         }
889     }
890     return count;
891 }
892
893 bool Font::canReceiveTextEmphasis(UChar32 c)
894 {
895     CharCategory category = Unicode::category(c);
896     if (category & (Separator_Space | Separator_Line | Separator_Paragraph | Other_NotAssigned | Other_Control | Other_Format))
897         return false;
898
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)
902         return false;
903
904     return true;
905 }
906
907 }