~ubuntu-branches/ubuntu/raring/qtwebkit-source/raring-proposed

« back to all changes in this revision

Viewing changes to Source/WebCore/platform/graphics/Font.cpp

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2013-02-18 14:24:18 UTC
  • Revision ID: package-import@ubuntu.com-20130218142418-eon0jmjg3nj438uy
Tags: upstream-2.3
ImportĀ upstreamĀ versionĀ 2.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
#include <wtf/UnusedParam.h>
 
38
 
 
39
using namespace WTF;
 
40
using namespace Unicode;
 
41
 
 
42
namespace WTF {
 
43
 
 
44
// allow compilation of OwnPtr<TextLayout> in source files that don't have access to the TextLayout class definition
 
45
template <> void deleteOwnedPtr<WebCore::TextLayout>(WebCore::TextLayout* ptr)
 
46
{
 
47
    WebCore::Font::deleteLayout(ptr);
 
48
}
 
49
 
 
50
}
 
51
 
 
52
namespace WebCore {
 
53
 
 
54
const uint8_t Font::s_roundingHackCharacterTable[256] = {
 
55
    0, 0, 0, 0, 0, 0, 0, 0, 0, 1 /*\t*/, 1 /*\n*/, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 
56
    1 /*space*/, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 /*-*/, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 /*?*/,
 
57
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 
58
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 
59
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 
60
    1 /*no-break space*/, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 
61
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 
62
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
 
63
};
 
64
 
 
65
Font::CodePath Font::s_codePath = Auto;
 
66
 
 
67
TypesettingFeatures Font::s_defaultTypesettingFeatures = 0;
 
68
 
 
69
// ============================================================================================
 
70
// Font Implementation (Cross-Platform Portion)
 
71
// ============================================================================================
 
72
 
 
73
Font::Font()
 
74
    : m_letterSpacing(0)
 
75
    , m_wordSpacing(0)
 
76
    , m_isPlatformFont(false)
 
77
    , m_needsTranscoding(false)
 
78
    , m_typesettingFeatures(0)
 
79
{
 
80
}
 
81
 
 
82
Font::Font(const FontDescription& fd, short letterSpacing, short wordSpacing) 
 
83
    : m_fontDescription(fd)
 
84
    , m_letterSpacing(letterSpacing)
 
85
    , m_wordSpacing(wordSpacing)
 
86
    , m_isPlatformFont(false)
 
87
    , m_needsTranscoding(fontTranscoder().needsTranscoding(fd))
 
88
    , m_typesettingFeatures(computeTypesettingFeatures())
 
89
{
 
90
}
 
91
 
 
92
Font::Font(const FontPlatformData& fontData, bool isPrinterFont, FontSmoothingMode fontSmoothingMode)
 
93
    : m_fontFallbackList(FontFallbackList::create())
 
94
    , m_letterSpacing(0)
 
95
    , m_wordSpacing(0)
 
96
    , m_isPlatformFont(true)
 
97
    , m_typesettingFeatures(computeTypesettingFeatures())
 
98
{
 
99
    m_fontDescription.setUsePrinterFont(isPrinterFont);
 
100
    m_fontDescription.setFontSmoothing(fontSmoothingMode);
 
101
    m_needsTranscoding = fontTranscoder().needsTranscoding(fontDescription());
 
102
    m_fontFallbackList->setPlatformFont(fontData);
 
103
}
 
104
 
 
105
Font::Font(const Font& other)
 
106
    : m_fontDescription(other.m_fontDescription)
 
107
    , m_fontFallbackList(other.m_fontFallbackList)
 
108
    , m_letterSpacing(other.m_letterSpacing)
 
109
    , m_wordSpacing(other.m_wordSpacing)
 
110
    , m_isPlatformFont(other.m_isPlatformFont)
 
111
    , m_needsTranscoding(other.m_needsTranscoding)
 
112
    , m_typesettingFeatures(computeTypesettingFeatures())
 
113
{
 
114
}
 
115
 
 
116
Font& Font::operator=(const Font& other)
 
117
{
 
118
    m_fontDescription = other.m_fontDescription;
 
119
    m_fontFallbackList = other.m_fontFallbackList;
 
120
    m_letterSpacing = other.m_letterSpacing;
 
121
    m_wordSpacing = other.m_wordSpacing;
 
122
    m_isPlatformFont = other.m_isPlatformFont;
 
123
    m_needsTranscoding = other.m_needsTranscoding;
 
124
    m_typesettingFeatures = other.m_typesettingFeatures;
 
125
    return *this;
 
126
}
 
127
 
 
128
bool Font::operator==(const Font& other) const
 
129
{
 
130
    // Our FontData don't have to be checked, since checking the font description will be fine.
 
131
    // FIXME: This does not work if the font was made with the FontPlatformData constructor.
 
132
    if (loadingCustomFonts() || other.loadingCustomFonts())
 
133
        return false;
 
134
    
 
135
    FontSelector* first = m_fontFallbackList ? m_fontFallbackList->fontSelector() : 0;
 
136
    FontSelector* second = other.m_fontFallbackList ? other.m_fontFallbackList->fontSelector() : 0;
 
137
 
 
138
    return first == second
 
139
        && m_fontDescription == other.m_fontDescription
 
140
        && m_letterSpacing == other.m_letterSpacing
 
141
        && m_wordSpacing == other.m_wordSpacing
 
142
        && (m_fontFallbackList ? m_fontFallbackList->fontSelectorVersion() : 0) == (other.m_fontFallbackList ? other.m_fontFallbackList->fontSelectorVersion() : 0)
 
143
        && (m_fontFallbackList ? m_fontFallbackList->generation() : 0) == (other.m_fontFallbackList ? other.m_fontFallbackList->generation() : 0);
 
144
}
 
145
 
 
146
void Font::update(PassRefPtr<FontSelector> fontSelector) const
 
147
{
 
148
    // FIXME: It is pretty crazy that we are willing to just poke into a RefPtr, but it ends up 
 
149
    // being reasonably safe (because inherited fonts in the render tree pick up the new
 
150
    // style anyway. Other copies are transient, e.g., the state in the GraphicsContext, and
 
151
    // won't stick around long enough to get you in trouble). Still, this is pretty disgusting,
 
152
    // and could eventually be rectified by using RefPtrs for Fonts themselves.
 
153
    if (!m_fontFallbackList)
 
154
        m_fontFallbackList = FontFallbackList::create();
 
155
    m_fontFallbackList->invalidate(fontSelector);
 
156
    m_typesettingFeatures = computeTypesettingFeatures();
 
157
}
 
158
 
 
159
void Font::drawText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, int from, int to, CustomFontNotReadyAction customFontNotReadyAction) const
 
160
{
 
161
    // Don't draw anything while we are using custom fonts that are in the process of loading,
 
162
    // except if the 'force' argument is set to true (in which case it will use a fallback
 
163
    // font).
 
164
    if (loadingCustomFonts() && customFontNotReadyAction == DoNotPaintIfFontNotReady)
 
165
        return;
 
166
    
 
167
    to = (to == -1 ? run.length() : to);
 
168
 
 
169
    CodePath codePathToUse = codePath(run);
 
170
    // FIXME: Use the fast code path once it handles partial runs with kerning and ligatures. See http://webkit.org/b/100050
 
171
    if (codePathToUse != Complex && typesettingFeatures() && (from || to != run.length()))
 
172
        codePathToUse = Complex;
 
173
 
 
174
    if (codePathToUse != Complex)
 
175
        return drawSimpleText(context, run, point, from, to);
 
176
 
 
177
    return drawComplexText(context, run, point, from, to);
 
178
}
 
179
 
 
180
void Font::drawEmphasisMarks(GraphicsContext* context, const TextRun& run, const AtomicString& mark, const FloatPoint& point, int from, int to) const
 
181
{
 
182
    if (loadingCustomFonts())
 
183
        return;
 
184
 
 
185
    if (to < 0)
 
186
        to = run.length();
 
187
 
 
188
    CodePath codePathToUse = codePath(run);
 
189
    // FIXME: Use the fast code path once it handles partial runs with kerning and ligatures. See http://webkit.org/b/100050
 
190
    if (codePathToUse != Complex && typesettingFeatures() && (from || to != run.length()))
 
191
        codePathToUse = Complex;
 
192
 
 
193
    if (codePathToUse != Complex)
 
194
        drawEmphasisMarksForSimpleText(context, run, mark, point, from, to);
 
195
    else
 
196
        drawEmphasisMarksForComplexText(context, run, mark, point, from, to);
 
197
}
 
198
 
 
199
float Font::width(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const
 
200
{
 
201
    CodePath codePathToUse = codePath(run);
 
202
    if (codePathToUse != Complex) {
 
203
        // The complex path is more restrictive about returning fallback fonts than the simple path, so we need an explicit test to make their behaviors match.
 
204
        if (!canReturnFallbackFontsForComplexText())
 
205
            fallbackFonts = 0;
 
206
        // The simple path can optimize the case where glyph overflow is not observable.
 
207
        if (codePathToUse != SimpleWithGlyphOverflow && (glyphOverflow && !glyphOverflow->computeBounds))
 
208
            glyphOverflow = 0;
 
209
    }
 
210
 
 
211
    bool hasKerningOrLigatures = typesettingFeatures() & (Kerning | Ligatures);
 
212
    bool hasWordSpacingOrLetterSpacing = wordSpacing() | letterSpacing();
 
213
    float* cacheEntry = m_fontFallbackList->widthCache().add(run, std::numeric_limits<float>::quiet_NaN(), hasKerningOrLigatures, hasWordSpacingOrLetterSpacing, glyphOverflow);
 
214
    if (cacheEntry && !isnan(*cacheEntry))
 
215
        return *cacheEntry;
 
216
 
 
217
    float result;
 
218
    if (codePathToUse == Complex)
 
219
        result = floatWidthForComplexText(run, fallbackFonts, glyphOverflow);
 
220
    else
 
221
        result = floatWidthForSimpleText(run, fallbackFonts, glyphOverflow);
 
222
 
 
223
    if (cacheEntry && (!fallbackFonts || fallbackFonts->isEmpty()))
 
224
        *cacheEntry = result;
 
225
    return result;
 
226
}
 
227
 
 
228
float Font::width(const TextRun& run, int& charsConsumed, String& glyphName) const
 
229
{
 
230
#if ENABLE(SVG_FONTS)
 
231
    if (TextRun::RenderingContext* renderingContext = run.renderingContext())
 
232
        return renderingContext->floatWidthUsingSVGFont(*this, run, charsConsumed, glyphName);
 
233
#endif
 
234
 
 
235
    charsConsumed = run.length();
 
236
    glyphName = "";
 
237
    return width(run);
 
238
}
 
239
 
 
240
#if !(PLATFORM(MAC) || (PLATFORM(CHROMIUM) && OS(DARWIN)))
 
241
 
 
242
PassOwnPtr<TextLayout> Font::createLayout(RenderText*, float, bool) const
 
243
{
 
244
    return nullptr;
 
245
}
 
246
 
 
247
void Font::deleteLayout(TextLayout*)
 
248
{
 
249
}
 
250
 
 
251
float Font::width(TextLayout&, unsigned, unsigned, HashSet<const SimpleFontData*>*)
 
252
{
 
253
    ASSERT_NOT_REACHED();
 
254
    return 0;
 
255
}
 
256
 
 
257
#endif
 
258
 
 
259
FloatRect Font::selectionRectForText(const TextRun& run, const FloatPoint& point, int h, int from, int to) const
 
260
{
 
261
    to = (to == -1 ? run.length() : to);
 
262
 
 
263
    CodePath codePathToUse = codePath(run);
 
264
    // FIXME: Use the fast code path once it handles partial runs with kerning and ligatures. See http://webkit.org/b/100050
 
265
    if (codePathToUse != Complex && typesettingFeatures() && (from || to != run.length()))
 
266
        codePathToUse = Complex;
 
267
 
 
268
    if (codePathToUse != Complex)
 
269
        return selectionRectForSimpleText(run, point, h, from, to);
 
270
 
 
271
    return selectionRectForComplexText(run, point, h, from, to);
 
272
}
 
273
 
 
274
int Font::offsetForPosition(const TextRun& run, float x, bool includePartialGlyphs) const
 
275
{
 
276
    // FIXME: Use the fast code path once it handles partial runs with kerning and ligatures. See http://webkit.org/b/100050
 
277
    if (codePath(run) != Complex && !typesettingFeatures())
 
278
        return offsetForPositionForSimpleText(run, x, includePartialGlyphs);
 
279
 
 
280
    return offsetForPositionForComplexText(run, x, includePartialGlyphs);
 
281
}
 
282
 
 
283
template <typename CharacterType>
 
284
static inline String normalizeSpacesInternal(const CharacterType* characters, unsigned length)
 
285
{
 
286
    StringBuilder normalized;
 
287
    normalized.reserveCapacity(length);
 
288
 
 
289
    for (unsigned i = 0; i < length; ++i)
 
290
        normalized.append(Font::normalizeSpaces(characters[i]));
 
291
 
 
292
    return normalized.toString();
 
293
}
 
294
 
 
295
String Font::normalizeSpaces(const LChar* characters, unsigned length)
 
296
{
 
297
    return normalizeSpacesInternal(characters, length);
 
298
}
 
299
 
 
300
String Font::normalizeSpaces(const UChar* characters, unsigned length)
 
301
{
 
302
    return normalizeSpacesInternal(characters, length);
 
303
}
 
304
 
 
305
static bool shouldUseFontSmoothing = true;
 
306
 
 
307
void Font::setShouldUseSmoothing(bool shouldUseSmoothing)
 
308
{
 
309
    ASSERT(isMainThread());
 
310
    shouldUseFontSmoothing = shouldUseSmoothing;
 
311
}
 
312
 
 
313
bool Font::shouldUseSmoothing()
 
314
{
 
315
    return shouldUseFontSmoothing;
 
316
}
 
317
 
 
318
void Font::setCodePath(CodePath p)
 
319
{
 
320
    s_codePath = p;
 
321
}
 
322
 
 
323
Font::CodePath Font::codePath()
 
324
{
 
325
    return s_codePath;
 
326
}
 
327
 
 
328
void Font::setDefaultTypesettingFeatures(TypesettingFeatures typesettingFeatures)
 
329
{
 
330
    s_defaultTypesettingFeatures = typesettingFeatures;
 
331
}
 
332
 
 
333
TypesettingFeatures Font::defaultTypesettingFeatures()
 
334
{
 
335
    return s_defaultTypesettingFeatures;
 
336
}
 
337
 
 
338
Font::CodePath Font::codePath(const TextRun& run) const
 
339
{
 
340
    if (s_codePath != Auto)
 
341
        return s_codePath;
 
342
 
 
343
#if ENABLE(SVG_FONTS)
 
344
    if (run.renderingContext())
 
345
        return Simple;
 
346
#endif
 
347
 
 
348
#if PLATFORM(QT) && !HAVE(QRAWFONT)
 
349
    if (run.expansion() || run.rtl() || isSmallCaps() || wordSpacing() || letterSpacing())
 
350
        return Complex;
 
351
#endif
 
352
 
 
353
    if (m_fontDescription.featureSettings() && m_fontDescription.featureSettings()->size() > 0)
 
354
        return Complex;
 
355
    
 
356
    if (run.length() > 1 && !WidthIterator::supportsTypesettingFeatures(*this))
 
357
        return Complex;
 
358
 
 
359
    if (!run.characterScanForCodePath())
 
360
        return Simple;
 
361
 
 
362
    if (run.is8Bit())
 
363
        return Simple;
 
364
 
 
365
    // Start from 0 since drawing and highlighting also measure the characters before run->from.
 
366
    return characterRangeCodePath(run.characters16(), run.length());
 
367
}
 
368
 
 
369
Font::CodePath Font::characterRangeCodePath(const UChar* characters, unsigned len)
 
370
{
 
371
    // FIXME: Should use a UnicodeSet in ports where ICU is used. Note that we 
 
372
    // can't simply use UnicodeCharacter Property/class because some characters
 
373
    // are not 'combining', but still need to go to the complex path.
 
374
    // Alternatively, we may as well consider binary search over a sorted
 
375
    // list of ranges.
 
376
    CodePath result = Simple;
 
377
    for (unsigned i = 0; i < len; i++) {
 
378
        const UChar c = characters[i];
 
379
        if (c < 0x2E5) // U+02E5 through U+02E9 (Modifier Letters : Tone letters)  
 
380
            continue;
 
381
        if (c <= 0x2E9) 
 
382
            return Complex;
 
383
 
 
384
        if (c < 0x300) // U+0300 through U+036F Combining diacritical marks
 
385
            continue;
 
386
        if (c <= 0x36F)
 
387
            return Complex;
 
388
 
 
389
        if (c < 0x0591 || c == 0x05BE) // U+0591 through U+05CF excluding U+05BE Hebrew combining marks, Hebrew punctuation Paseq, Sof Pasuq and Nun Hafukha
 
390
            continue;
 
391
        if (c <= 0x05CF)
 
392
            return Complex;
 
393
 
 
394
        // U+0600 through U+109F Arabic, Syriac, Thaana, NKo, Samaritan, Mandaic,
 
395
        // Devanagari, Bengali, Gurmukhi, Gujarati, Oriya, Tamil, Telugu, Kannada, 
 
396
        // Malayalam, Sinhala, Thai, Lao, Tibetan, Myanmar
 
397
        if (c < 0x0600) 
 
398
            continue;
 
399
        if (c <= 0x109F)
 
400
            return Complex;
 
401
 
 
402
        // U+1100 through U+11FF Hangul Jamo (only Ancient Korean should be left here if you precompose;
 
403
        // Modern Korean will be precomposed as a result of step A)
 
404
        if (c < 0x1100)
 
405
            continue;
 
406
        if (c <= 0x11FF)
 
407
            return Complex;
 
408
 
 
409
        if (c < 0x135D) // U+135D through U+135F Ethiopic combining marks
 
410
            continue;
 
411
        if (c <= 0x135F)
 
412
            return Complex;
 
413
 
 
414
        if (c < 0x1700) // U+1780 through U+18AF Tagalog, Hanunoo, Buhid, Taghanwa,Khmer, Mongolian
 
415
            continue;
 
416
        if (c <= 0x18AF)
 
417
            return Complex;
 
418
 
 
419
        if (c < 0x1900) // U+1900 through U+194F Limbu (Unicode 4.0)
 
420
            continue;
 
421
        if (c <= 0x194F)
 
422
            return Complex;
 
423
 
 
424
        if (c < 0x1980) // U+1980 through U+19DF New Tai Lue
 
425
            continue;
 
426
        if (c <= 0x19DF)
 
427
            return Complex;
 
428
 
 
429
        if (c < 0x1A00) // U+1A00 through U+1CFF Buginese, Tai Tham, Balinese, Batak, Lepcha, Vedic
 
430
            continue;
 
431
        if (c <= 0x1CFF)
 
432
            return Complex;
 
433
 
 
434
        if (c < 0x1DC0) // U+1DC0 through U+1DFF Comining diacritical mark supplement
 
435
            continue;
 
436
        if (c <= 0x1DFF)
 
437
            return Complex;
 
438
 
 
439
        // U+1E00 through U+2000 characters with diacritics and stacked diacritics
 
440
        if (c <= 0x2000) {
 
441
            result = SimpleWithGlyphOverflow;
 
442
            continue;
 
443
        }
 
444
 
 
445
        if (c < 0x20D0) // U+20D0 through U+20FF Combining marks for symbols
 
446
            continue;
 
447
        if (c <= 0x20FF)
 
448
            return Complex;
 
449
 
 
450
        if (c < 0x2CEF) // U+2CEF through U+2CF1 Combining marks for Coptic
 
451
            continue;
 
452
        if (c <= 0x2CF1)
 
453
            return Complex;
 
454
 
 
455
        if (c < 0x302A) // U+302A through U+302F Ideographic and Hangul Tone marks
 
456
            continue;
 
457
        if (c <= 0x302F)
 
458
            return Complex;
 
459
 
 
460
        if (c < 0xA67C) // U+A67C through U+A67D Combining marks for old Cyrillic
 
461
            continue;
 
462
        if (c <= 0xA67D)
 
463
            return Complex;
 
464
 
 
465
        if (c < 0xA6F0) // U+A6F0 through U+A6F1 Combining mark for Bamum
 
466
            continue;
 
467
        if (c <= 0xA6F1)
 
468
            return Complex;
 
469
 
 
470
       // U+A800 through U+ABFF Nagri, Phags-pa, Saurashtra, Devanagari Extended,
 
471
       // Hangul Jamo Ext. A, Javanese, Myanmar Extended A, Tai Viet, Meetei Mayek,
 
472
        if (c < 0xA800) 
 
473
            continue;
 
474
        if (c <= 0xABFF)
 
475
            return Complex;
 
476
 
 
477
        if (c < 0xD7B0) // U+D7B0 through U+D7FF Hangul Jamo Ext. B
 
478
            continue;
 
479
        if (c <= 0xD7FF)
 
480
            return Complex;
 
481
 
 
482
        if (c <= 0xDBFF) {
 
483
            // High surrogate
 
484
 
 
485
            if (i == len - 1)
 
486
                continue;
 
487
 
 
488
            UChar next = characters[++i];
 
489
            if (!U16_IS_TRAIL(next))
 
490
                continue;
 
491
 
 
492
            UChar32 supplementaryCharacter = U16_GET_SUPPLEMENTARY(c, next);
 
493
 
 
494
            if (supplementaryCharacter < 0x1F1E6) // U+1F1E6 through U+1F1FF Regional Indicator Symbols
 
495
                continue;
 
496
            if (supplementaryCharacter <= 0x1F1FF)
 
497
                return Complex;
 
498
 
 
499
            if (supplementaryCharacter < 0xE0100) // U+E0100 through U+E01EF Unicode variation selectors.
 
500
                continue;
 
501
            if (supplementaryCharacter <= 0xE01EF)
 
502
                return Complex;
 
503
 
 
504
            // FIXME: Check for Brahmi (U+11000 block), Kaithi (U+11080 block) and other complex scripts
 
505
            // in plane 1 or higher.
 
506
 
 
507
            continue;
 
508
        }
 
509
 
 
510
        if (c < 0xFE00) // U+FE00 through U+FE0F Unicode variation selectors
 
511
            continue;
 
512
        if (c <= 0xFE0F)
 
513
            return Complex;
 
514
 
 
515
        if (c < 0xFE20) // U+FE20 through U+FE2F Combining half marks
 
516
            continue;
 
517
        if (c <= 0xFE2F)
 
518
            return Complex;
 
519
    }
 
520
    return result;
 
521
}
 
522
 
 
523
bool Font::isCJKIdeograph(UChar32 c)
 
524
{
 
525
    // The basic CJK Unified Ideographs block.
 
526
    if (c >= 0x4E00 && c <= 0x9FFF)
 
527
        return true;
 
528
    
 
529
    // CJK Unified Ideographs Extension A.
 
530
    if (c >= 0x3400 && c <= 0x4DBF)
 
531
        return true;
 
532
    
 
533
    // CJK Radicals Supplement.
 
534
    if (c >= 0x2E80 && c <= 0x2EFF)
 
535
        return true;
 
536
    
 
537
    // Kangxi Radicals.
 
538
    if (c >= 0x2F00 && c <= 0x2FDF)
 
539
        return true;
 
540
    
 
541
    // CJK Strokes.
 
542
    if (c >= 0x31C0 && c <= 0x31EF)
 
543
        return true;
 
544
    
 
545
    // CJK Compatibility Ideographs.
 
546
    if (c >= 0xF900 && c <= 0xFAFF)
 
547
        return true;
 
548
    
 
549
    // CJK Unified Ideographs Extension B.
 
550
    if (c >= 0x20000 && c <= 0x2A6DF)
 
551
        return true;
 
552
        
 
553
    // CJK Unified Ideographs Extension C.
 
554
    if (c >= 0x2A700 && c <= 0x2B73F)
 
555
        return true;
 
556
    
 
557
    // CJK Unified Ideographs Extension D.
 
558
    if (c >= 0x2B740 && c <= 0x2B81F)
 
559
        return true;
 
560
    
 
561
    // CJK Compatibility Ideographs Supplement.
 
562
    if (c >= 0x2F800 && c <= 0x2FA1F)
 
563
        return true;
 
564
 
 
565
    return false;
 
566
}
 
567
 
 
568
bool Font::isCJKIdeographOrSymbol(UChar32 c)
 
569
{
 
570
    // 0x2C7 Caron, Mandarin Chinese 3rd Tone
 
571
    // 0x2CA Modifier Letter Acute Accent, Mandarin Chinese 2nd Tone
 
572
    // 0x2CB Modifier Letter Grave Access, Mandarin Chinese 4th Tone 
 
573
    // 0x2D9 Dot Above, Mandarin Chinese 5th Tone 
 
574
    if ((c == 0x2C7) || (c == 0x2CA) || (c == 0x2CB) || (c == 0x2D9))
 
575
        return true;
 
576
 
 
577
    // Ideographic Description Characters.
 
578
    if (c >= 0x2FF0 && c <= 0x2FFF)
 
579
        return true;
 
580
    
 
581
    // CJK Symbols and Punctuation.
 
582
    if (c >= 0x3000 && c <= 0x303F)
 
583
        return true;
 
584
   
 
585
    // Hiragana 
 
586
    if (c >= 0x3040 && c <= 0x309F)
 
587
        return true;
 
588
 
 
589
    // Katakana 
 
590
    if (c >= 0x30A0 && c <= 0x30FF)
 
591
        return true;
 
592
 
 
593
    // Bopomofo
 
594
    if (c >= 0x3100 && c <= 0x312F)
 
595
        return true;
 
596
    
 
597
    // Bopomofo Extended
 
598
    if (c >= 0x31A0 && c <= 0x31BF)
 
599
        return true;
 
600
 
 
601
    // Enclosed CJK Letters and Months.
 
602
    if (c >= 0x3200 && c <= 0x32FF)
 
603
        return true;
 
604
    
 
605
    // CJK Compatibility.
 
606
    if (c >= 0x3300 && c <= 0x33FF)
 
607
        return true;
 
608
    
 
609
    // CJK Compatibility Forms.
 
610
    if (c >= 0xFE30 && c <= 0xFE4F)
 
611
        return true;
 
612
 
 
613
    // Halfwidth and Fullwidth Forms
 
614
    // Usually only used in CJK
 
615
    if (c >= 0xFF00 && c <= 0xFFEF)
 
616
        return true;
 
617
 
 
618
    // Emoji.
 
619
    if (c >= 0x1F200 && c <= 0x1F6F)
 
620
        return true;
 
621
 
 
622
    return isCJKIdeograph(c);
 
623
}
 
624
 
 
625
unsigned Font::expansionOpportunityCount(const LChar* characters, size_t length, TextDirection direction, bool& isAfterExpansion)
 
626
{
 
627
    unsigned count = 0;
 
628
    if (direction == LTR) {
 
629
        for (size_t i = 0; i < length; ++i) {
 
630
            if (treatAsSpace(characters[i])) {
 
631
                count++;
 
632
                isAfterExpansion = true;
 
633
            } else
 
634
                isAfterExpansion = false;
 
635
        }
 
636
    } else {
 
637
        for (size_t i = length; i > 0; --i) {
 
638
            if (treatAsSpace(characters[i - 1])) {
 
639
                count++;
 
640
                isAfterExpansion = true;
 
641
            } else
 
642
                isAfterExpansion = false;
 
643
        }
 
644
    }
 
645
    return count;
 
646
}
 
647
 
 
648
unsigned Font::expansionOpportunityCount(const UChar* characters, size_t length, TextDirection direction, bool& isAfterExpansion)
 
649
{
 
650
    static bool expandAroundIdeographs = canExpandAroundIdeographsInComplexText();
 
651
    unsigned count = 0;
 
652
    if (direction == LTR) {
 
653
        for (size_t i = 0; i < length; ++i) {
 
654
            UChar32 character = characters[i];
 
655
            if (treatAsSpace(character)) {
 
656
                count++;
 
657
                isAfterExpansion = true;
 
658
                continue;
 
659
            }
 
660
            if (U16_IS_LEAD(character) && i + 1 < length && U16_IS_TRAIL(characters[i + 1])) {
 
661
                character = U16_GET_SUPPLEMENTARY(character, characters[i + 1]);
 
662
                i++;
 
663
            }
 
664
            if (expandAroundIdeographs && isCJKIdeographOrSymbol(character)) {
 
665
                if (!isAfterExpansion)
 
666
                    count++;
 
667
                count++;
 
668
                isAfterExpansion = true;
 
669
                continue;
 
670
            }
 
671
            isAfterExpansion = false;
 
672
        }
 
673
    } else {
 
674
        for (size_t i = length; i > 0; --i) {
 
675
            UChar32 character = characters[i - 1];
 
676
            if (treatAsSpace(character)) {
 
677
                count++;
 
678
                isAfterExpansion = true;
 
679
                continue;
 
680
            }
 
681
            if (U16_IS_TRAIL(character) && i > 1 && U16_IS_LEAD(characters[i - 2])) {
 
682
                character = U16_GET_SUPPLEMENTARY(characters[i - 2], character);
 
683
                i--;
 
684
            }
 
685
            if (expandAroundIdeographs && isCJKIdeographOrSymbol(character)) {
 
686
                if (!isAfterExpansion)
 
687
                    count++;
 
688
                count++;
 
689
                isAfterExpansion = true;
 
690
                continue;
 
691
            }
 
692
            isAfterExpansion = false;
 
693
        }
 
694
    }
 
695
    return count;
 
696
}
 
697
 
 
698
bool Font::canReceiveTextEmphasis(UChar32 c)
 
699
{
 
700
    CharCategory category = Unicode::category(c);
 
701
    if (category & (Separator_Space | Separator_Line | Separator_Paragraph | Other_NotAssigned | Other_Control | Other_Format))
 
702
        return false;
 
703
 
 
704
    // Additional word-separator characters listed in CSS Text Level 3 Editor's Draft 3 November 2010.
 
705
    if (c == ethiopicWordspace || c == aegeanWordSeparatorLine || c == aegeanWordSeparatorDot
 
706
        || c == ugariticWordDivider || c == tibetanMarkIntersyllabicTsheg || c == tibetanMarkDelimiterTshegBstar)
 
707
        return false;
 
708
 
 
709
    return true;
 
710
}
 
711
 
 
712
}