| OLD | NEW |
| (Empty) |
| 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 "core/platform/graphics/Font.h" | |
| 26 | |
| 27 #include "core/platform/graphics/WidthIterator.h" | |
| 28 #include "platform/geometry/FloatRect.h" | |
| 29 #include "platform/graphics/TextRun.h" | |
| 30 #include "wtf/MainThread.h" | |
| 31 #include "wtf/StdLibExtras.h" | |
| 32 #include "wtf/UnusedParam.h" | |
| 33 #include "wtf/text/StringBuilder.h" | |
| 34 | |
| 35 using namespace WTF; | |
| 36 using namespace Unicode; | |
| 37 | |
| 38 namespace WTF { | |
| 39 | |
| 40 // allow compilation of OwnPtr<TextLayout> in source files that don't have acces
s to the TextLayout class definition | |
| 41 void OwnedPtrDeleter<WebCore::TextLayout>::deletePtr(WebCore::TextLayout* ptr) | |
| 42 { | |
| 43 WebCore::Font::deleteLayout(ptr); | |
| 44 } | |
| 45 | |
| 46 } | |
| 47 | |
| 48 namespace WebCore { | |
| 49 | |
| 50 const uint8_t Font::s_roundingHackCharacterTable[256] = { | |
| 51 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, | |
| 52 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 /*?*/, | |
| 53 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, | |
| 54 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, | |
| 55 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, | |
| 56 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, | |
| 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 }; | |
| 60 | |
| 61 static const UChar32 cjkIsolatedSymbolsArray[] = { | |
| 62 // 0x2C7 Caron, Mandarin Chinese 3rd Tone | |
| 63 0x2C7, | |
| 64 // 0x2CA Modifier Letter Acute Accent, Mandarin Chinese 2nd Tone | |
| 65 0x2CA, | |
| 66 // 0x2CB Modifier Letter Grave Access, Mandarin Chinese 4th Tone | |
| 67 0x2CB, | |
| 68 // 0x2D9 Dot Above, Mandarin Chinese 5th Tone | |
| 69 0x2D9, | |
| 70 0x2020, 0x2021, 0x2030, 0x203B, 0x203C, 0x2042, 0x2047, 0x2048, 0x2049, 0x20
51, | |
| 71 0x20DD, 0x20DE, 0x2100, 0x2103, 0x2105, 0x2109, 0x210A, 0x2113, 0x2116, 0x21
21, | |
| 72 0x212B, 0x213B, 0x2150, 0x2151, 0x2152, 0x217F, 0x2189, 0x2307, 0x2312, 0x23
CE, | |
| 73 0x2423, 0x25A0, 0x25A1, 0x25A2, 0x25AA, 0x25AB, 0x25B1, 0x25B2, 0x25B3, 0x25
B6, | |
| 74 0x25B7, 0x25BC, 0x25BD, 0x25C0, 0x25C1, 0x25C6, 0x25C7, 0x25C9, 0x25CB, 0x25
CC, | |
| 75 0x25EF, 0x2605, 0x2606, 0x260E, 0x2616, 0x2617, 0x2640, 0x2642, 0x26A0, 0x26
BD, | |
| 76 0x26BE, 0x2713, 0x271A, 0x273F, 0x2740, 0x2756, 0x2B1A, 0xFE10, 0xFE11, 0xFE
12, | |
| 77 0xFE19, 0xFF1D, | |
| 78 // Emoji. | |
| 79 0x1F100 | |
| 80 }; | |
| 81 | |
| 82 Font::CodePath Font::s_codePath = Auto; | |
| 83 | |
| 84 TypesettingFeatures Font::s_defaultTypesettingFeatures = 0; | |
| 85 | |
| 86 // =============================================================================
=============== | |
| 87 // Font Implementation (Cross-Platform Portion) | |
| 88 // =============================================================================
=============== | |
| 89 | |
| 90 Font::Font() | |
| 91 : m_letterSpacing(0) | |
| 92 , m_wordSpacing(0) | |
| 93 , m_isPlatformFont(false) | |
| 94 , m_typesettingFeatures(0) | |
| 95 { | |
| 96 } | |
| 97 | |
| 98 Font::Font(const FontDescription& fd, float letterSpacing, float wordSpacing) | |
| 99 : m_fontDescription(fd) | |
| 100 , m_letterSpacing(letterSpacing) | |
| 101 , m_wordSpacing(wordSpacing) | |
| 102 , m_isPlatformFont(false) | |
| 103 , m_typesettingFeatures(computeTypesettingFeatures()) | |
| 104 { | |
| 105 } | |
| 106 | |
| 107 Font::Font(const FontPlatformData& fontData, bool isPrinterFont, FontSmoothingMo
de fontSmoothingMode) | |
| 108 : m_fontFallbackList(FontFallbackList::create()) | |
| 109 , m_letterSpacing(0) | |
| 110 , m_wordSpacing(0) | |
| 111 , m_isPlatformFont(true) | |
| 112 , m_typesettingFeatures(computeTypesettingFeatures()) | |
| 113 { | |
| 114 m_fontDescription.setUsePrinterFont(isPrinterFont); | |
| 115 m_fontDescription.setFontSmoothing(fontSmoothingMode); | |
| 116 m_fontFallbackList->setPlatformFont(fontData); | |
| 117 } | |
| 118 | |
| 119 Font::Font(const Font& other) | |
| 120 : m_fontDescription(other.m_fontDescription) | |
| 121 , m_fontFallbackList(other.m_fontFallbackList) | |
| 122 , m_letterSpacing(other.m_letterSpacing) | |
| 123 , m_wordSpacing(other.m_wordSpacing) | |
| 124 , m_isPlatformFont(other.m_isPlatformFont) | |
| 125 , m_typesettingFeatures(computeTypesettingFeatures()) | |
| 126 { | |
| 127 } | |
| 128 | |
| 129 Font& Font::operator=(const Font& other) | |
| 130 { | |
| 131 m_fontDescription = other.m_fontDescription; | |
| 132 m_fontFallbackList = other.m_fontFallbackList; | |
| 133 m_letterSpacing = other.m_letterSpacing; | |
| 134 m_wordSpacing = other.m_wordSpacing; | |
| 135 m_isPlatformFont = other.m_isPlatformFont; | |
| 136 m_typesettingFeatures = other.m_typesettingFeatures; | |
| 137 return *this; | |
| 138 } | |
| 139 | |
| 140 bool Font::operator==(const Font& other) const | |
| 141 { | |
| 142 // Our FontData don't have to be checked, since checking the font descriptio
n will be fine. | |
| 143 // FIXME: This does not work if the font was made with the FontPlatformData
constructor. | |
| 144 if (loadingCustomFonts() || other.loadingCustomFonts()) | |
| 145 return false; | |
| 146 | |
| 147 FontSelector* first = m_fontFallbackList ? m_fontFallbackList->fontSelector(
) : 0; | |
| 148 FontSelector* second = other.m_fontFallbackList ? other.m_fontFallbackList->
fontSelector() : 0; | |
| 149 | |
| 150 return first == second | |
| 151 && m_fontDescription == other.m_fontDescription | |
| 152 && m_letterSpacing == other.m_letterSpacing | |
| 153 && m_wordSpacing == other.m_wordSpacing | |
| 154 && (m_fontFallbackList ? m_fontFallbackList->fontSelectorVersion() : 0)
== (other.m_fontFallbackList ? other.m_fontFallbackList->fontSelectorVersion() :
0) | |
| 155 && (m_fontFallbackList ? m_fontFallbackList->generation() : 0) == (other
.m_fontFallbackList ? other.m_fontFallbackList->generation() : 0); | |
| 156 } | |
| 157 | |
| 158 void Font::update(PassRefPtr<FontSelector> fontSelector) const | |
| 159 { | |
| 160 // FIXME: It is pretty crazy that we are willing to just poke into a RefPtr,
but it ends up | |
| 161 // being reasonably safe (because inherited fonts in the render tree pick up
the new | |
| 162 // style anyway. Other copies are transient, e.g., the state in the Graphics
Context, and | |
| 163 // won't stick around long enough to get you in trouble). Still, this is pre
tty disgusting, | |
| 164 // and could eventually be rectified by using RefPtrs for Fonts themselves. | |
| 165 if (!m_fontFallbackList) | |
| 166 m_fontFallbackList = FontFallbackList::create(); | |
| 167 m_fontFallbackList->invalidate(fontSelector); | |
| 168 m_typesettingFeatures = computeTypesettingFeatures(); | |
| 169 } | |
| 170 | |
| 171 void Font::drawText(GraphicsContext* context, const TextRunPaintInfo& runInfo, c
onst FloatPoint& point, CustomFontNotReadyAction customFontNotReadyAction) const | |
| 172 { | |
| 173 // Don't draw anything while we are using custom fonts that are in the proce
ss of loading, | |
| 174 // except if the 'force' argument is set to true (in which case it will use
a fallback | |
| 175 // font). | |
| 176 if (loadingCustomFonts() && customFontNotReadyAction == DoNotPaintIfFontNotR
eady) | |
| 177 return; | |
| 178 | |
| 179 CodePath codePathToUse = codePath(runInfo.run); | |
| 180 // FIXME: Use the fast code path once it handles partial runs with kerning a
nd ligatures. See http://webkit.org/b/100050 | |
| 181 if (codePathToUse != Complex && typesettingFeatures() && (runInfo.from || ru
nInfo.to != runInfo.run.length())) | |
| 182 codePathToUse = Complex; | |
| 183 | |
| 184 if (codePathToUse != Complex) | |
| 185 return drawSimpleText(context, runInfo, point); | |
| 186 | |
| 187 return drawComplexText(context, runInfo, point); | |
| 188 } | |
| 189 | |
| 190 void Font::drawEmphasisMarks(GraphicsContext* context, const TextRunPaintInfo& r
unInfo, const AtomicString& mark, const FloatPoint& point) const | |
| 191 { | |
| 192 if (loadingCustomFonts()) | |
| 193 return; | |
| 194 | |
| 195 CodePath codePathToUse = codePath(runInfo.run); | |
| 196 // FIXME: Use the fast code path once it handles partial runs with kerning a
nd ligatures. See http://webkit.org/b/100050 | |
| 197 if (codePathToUse != Complex && typesettingFeatures() && (runInfo.from || ru
nInfo.to != runInfo.run.length())) | |
| 198 codePathToUse = Complex; | |
| 199 | |
| 200 if (codePathToUse != Complex) | |
| 201 drawEmphasisMarksForSimpleText(context, runInfo, mark, point); | |
| 202 else | |
| 203 drawEmphasisMarksForComplexText(context, runInfo, mark, point); | |
| 204 } | |
| 205 | |
| 206 float Font::width(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFo
nts, GlyphOverflow* glyphOverflow) const | |
| 207 { | |
| 208 CodePath codePathToUse = codePath(run); | |
| 209 if (codePathToUse != Complex) { | |
| 210 // The complex path is more restrictive about returning fallback fonts t
han the simple path, so we need an explicit test to make their behaviors match. | |
| 211 if (!canReturnFallbackFontsForComplexText()) | |
| 212 fallbackFonts = 0; | |
| 213 // The simple path can optimize the case where glyph overflow is not obs
ervable. | |
| 214 if (codePathToUse != SimpleWithGlyphOverflow && (glyphOverflow && !glyph
Overflow->computeBounds)) | |
| 215 glyphOverflow = 0; | |
| 216 } | |
| 217 | |
| 218 bool hasKerningOrLigatures = typesettingFeatures() & (Kerning | Ligatures); | |
| 219 bool hasWordSpacingOrLetterSpacing = wordSpacing() || letterSpacing(); | |
| 220 float* cacheEntry = m_fontFallbackList->widthCache().add(run, std::numeric_l
imits<float>::quiet_NaN(), hasKerningOrLigatures, hasWordSpacingOrLetterSpacing,
glyphOverflow); | |
| 221 if (cacheEntry && !std::isnan(*cacheEntry)) | |
| 222 return *cacheEntry; | |
| 223 | |
| 224 float result; | |
| 225 if (codePathToUse == Complex) | |
| 226 result = floatWidthForComplexText(run, fallbackFonts, glyphOverflow); | |
| 227 else | |
| 228 result = floatWidthForSimpleText(run, fallbackFonts, glyphOverflow); | |
| 229 | |
| 230 if (cacheEntry && (!fallbackFonts || fallbackFonts->isEmpty())) | |
| 231 *cacheEntry = result; | |
| 232 return result; | |
| 233 } | |
| 234 | |
| 235 float Font::width(const TextRun& run, int& charsConsumed, String& glyphName) con
st | |
| 236 { | |
| 237 #if ENABLE(SVG_FONTS) | |
| 238 if (TextRun::RenderingContext* renderingContext = run.renderingContext()) | |
| 239 return renderingContext->floatWidthUsingSVGFont(*this, run, charsConsume
d, glyphName); | |
| 240 #endif | |
| 241 | |
| 242 charsConsumed = run.length(); | |
| 243 glyphName = ""; | |
| 244 return width(run); | |
| 245 } | |
| 246 | |
| 247 #if !OS(MACOSX) | |
| 248 | |
| 249 PassOwnPtr<TextLayout> Font::createLayoutForMacComplexText(const TextRun&, unsig
ned, float, bool) const | |
| 250 { | |
| 251 ASSERT_NOT_REACHED(); | |
| 252 return nullptr; | |
| 253 } | |
| 254 | |
| 255 void Font::deleteLayout(TextLayout*) | |
| 256 { | |
| 257 } | |
| 258 | |
| 259 float Font::width(TextLayout&, unsigned, unsigned, HashSet<const SimpleFontData*
>*) | |
| 260 { | |
| 261 ASSERT_NOT_REACHED(); | |
| 262 return 0; | |
| 263 } | |
| 264 | |
| 265 #endif | |
| 266 | |
| 267 FloatRect Font::selectionRectForText(const TextRun& run, const FloatPoint& point
, int h, int from, int to) const | |
| 268 { | |
| 269 to = (to == -1 ? run.length() : to); | |
| 270 | |
| 271 CodePath codePathToUse = codePath(run); | |
| 272 // FIXME: Use the fast code path once it handles partial runs with kerning a
nd ligatures. See http://webkit.org/b/100050 | |
| 273 if (codePathToUse != Complex && typesettingFeatures() && (from || to != run.
length())) | |
| 274 codePathToUse = Complex; | |
| 275 | |
| 276 if (codePathToUse != Complex) | |
| 277 return selectionRectForSimpleText(run, point, h, from, to); | |
| 278 | |
| 279 return selectionRectForComplexText(run, point, h, from, to); | |
| 280 } | |
| 281 | |
| 282 int Font::offsetForPosition(const TextRun& run, float x, bool includePartialGlyp
hs) const | |
| 283 { | |
| 284 // FIXME: Use the fast code path once it handles partial runs with kerning a
nd ligatures. See http://webkit.org/b/100050 | |
| 285 if (codePath(run) != Complex && !typesettingFeatures()) | |
| 286 return offsetForPositionForSimpleText(run, x, includePartialGlyphs); | |
| 287 | |
| 288 return offsetForPositionForComplexText(run, x, includePartialGlyphs); | |
| 289 } | |
| 290 | |
| 291 template <typename CharacterType> | |
| 292 static inline String normalizeSpacesInternal(const CharacterType* characters, un
signed length) | |
| 293 { | |
| 294 StringBuilder normalized; | |
| 295 normalized.reserveCapacity(length); | |
| 296 | |
| 297 for (unsigned i = 0; i < length; ++i) | |
| 298 normalized.append(Font::normalizeSpaces(characters[i])); | |
| 299 | |
| 300 return normalized.toString(); | |
| 301 } | |
| 302 | |
| 303 String Font::normalizeSpaces(const LChar* characters, unsigned length) | |
| 304 { | |
| 305 return normalizeSpacesInternal(characters, length); | |
| 306 } | |
| 307 | |
| 308 String Font::normalizeSpaces(const UChar* characters, unsigned length) | |
| 309 { | |
| 310 return normalizeSpacesInternal(characters, length); | |
| 311 } | |
| 312 | |
| 313 static bool shouldUseFontSmoothing = true; | |
| 314 | |
| 315 void Font::setShouldUseSmoothing(bool shouldUseSmoothing) | |
| 316 { | |
| 317 ASSERT(isMainThread()); | |
| 318 shouldUseFontSmoothing = shouldUseSmoothing; | |
| 319 } | |
| 320 | |
| 321 bool Font::shouldUseSmoothing() | |
| 322 { | |
| 323 return shouldUseFontSmoothing; | |
| 324 } | |
| 325 | |
| 326 void Font::setCodePath(CodePath p) | |
| 327 { | |
| 328 s_codePath = p; | |
| 329 } | |
| 330 | |
| 331 Font::CodePath Font::codePath() | |
| 332 { | |
| 333 return s_codePath; | |
| 334 } | |
| 335 | |
| 336 void Font::setDefaultTypesettingFeatures(TypesettingFeatures typesettingFeatures
) | |
| 337 { | |
| 338 s_defaultTypesettingFeatures = typesettingFeatures; | |
| 339 } | |
| 340 | |
| 341 TypesettingFeatures Font::defaultTypesettingFeatures() | |
| 342 { | |
| 343 return s_defaultTypesettingFeatures; | |
| 344 } | |
| 345 | |
| 346 Font::CodePath Font::codePath(const TextRun& run) const | |
| 347 { | |
| 348 if (s_codePath != Auto) | |
| 349 return s_codePath; | |
| 350 | |
| 351 #if ENABLE(SVG_FONTS) | |
| 352 if (run.renderingContext()) | |
| 353 return Simple; | |
| 354 #endif | |
| 355 | |
| 356 if (m_fontDescription.featureSettings() && m_fontDescription.featureSettings
()->size() > 0) | |
| 357 return Complex; | |
| 358 | |
| 359 if (run.length() > 1 && !WidthIterator::supportsTypesettingFeatures(*this)) | |
| 360 return Complex; | |
| 361 | |
| 362 if (!run.characterScanForCodePath()) | |
| 363 return Simple; | |
| 364 | |
| 365 if (run.is8Bit()) | |
| 366 return Simple; | |
| 367 | |
| 368 // Start from 0 since drawing and highlighting also measure the characters b
efore run->from. | |
| 369 return characterRangeCodePath(run.characters16(), run.length()); | |
| 370 } | |
| 371 | |
| 372 static inline UChar keyExtractorUChar(const UChar* value) | |
| 373 { | |
| 374 return *value; | |
| 375 } | |
| 376 | |
| 377 static inline UChar32 keyExtractorUChar32(const UChar32* value) | |
| 378 { | |
| 379 return *value; | |
| 380 } | |
| 381 | |
| 382 Font::CodePath Font::characterRangeCodePath(const UChar* characters, unsigned le
n) | |
| 383 { | |
| 384 static const UChar complexCodePathRanges[] = { | |
| 385 // U+02E5 through U+02E9 (Modifier Letters : Tone letters) | |
| 386 0x2E5, 0x2E9, | |
| 387 // U+0300 through U+036F Combining diacritical marks | |
| 388 0x300, 0x36F, | |
| 389 // U+0591 through U+05CF excluding U+05BE Hebrew combining marks, ... | |
| 390 0x0591, 0x05BD, | |
| 391 // ... Hebrew punctuation Paseq, Sof Pasuq and Nun Hafukha | |
| 392 0x05BF, 0x05CF, | |
| 393 // U+0600 through U+109F Arabic, Syriac, Thaana, NKo, Samaritan, Mandaic
, | |
| 394 // Devanagari, Bengali, Gurmukhi, Gujarati, Oriya, Tamil, Telugu, Kannad
a, | |
| 395 // Malayalam, Sinhala, Thai, Lao, Tibetan, Myanmar | |
| 396 0x0600, 0x109F, | |
| 397 // U+1100 through U+11FF Hangul Jamo (only Ancient Korean should be left | |
| 398 // here if you precompose; Modern Korean will be precomposed as a result
of step A) | |
| 399 0x1100, 0x11FF, | |
| 400 // U+135D through U+135F Ethiopic combining marks | |
| 401 0x135D, 0x135F, | |
| 402 // U+1780 through U+18AF Tagalog, Hanunoo, Buhid, Taghanwa,Khmer, Mongol
ian | |
| 403 0x1700, 0x18AF, | |
| 404 // U+1900 through U+194F Limbu (Unicode 4.0) | |
| 405 0x1900, 0x194F, | |
| 406 // U+1980 through U+19DF New Tai Lue | |
| 407 0x1980, 0x19DF, | |
| 408 // U+1A00 through U+1CFF Buginese, Tai Tham, Balinese, Batak, Lepcha, Ve
dic | |
| 409 0x1A00, 0x1CFF, | |
| 410 // U+1DC0 through U+1DFF Comining diacritical mark supplement | |
| 411 0x1DC0, 0x1DFF, | |
| 412 // U+20D0 through U+20FF Combining marks for symbols | |
| 413 0x20D0, 0x20FF, | |
| 414 // U+2CEF through U+2CF1 Combining marks for Coptic | |
| 415 0x2CEF, 0x2CF1, | |
| 416 // U+302A through U+302F Ideographic and Hangul Tone marks | |
| 417 0x302A, 0x302F, | |
| 418 // U+A67C through U+A67D Combining marks for old Cyrillic | |
| 419 0xA67C, 0xA67D, | |
| 420 // U+A6F0 through U+A6F1 Combining mark for Bamum | |
| 421 0xA6F0, 0xA6F1, | |
| 422 // U+A800 through U+ABFF Nagri, Phags-pa, Saurashtra, Devanagari Extende
d, | |
| 423 // Hangul Jamo Ext. A, Javanese, Myanmar Extended A, Tai Viet, Meetei Ma
yek | |
| 424 0xA800, 0xABFF, | |
| 425 // U+D7B0 through U+D7FF Hangul Jamo Ext. B | |
| 426 0xD7B0, 0xD7FF, | |
| 427 // U+FE00 through U+FE0F Unicode variation selectors | |
| 428 0xFE00, 0xFE0F, | |
| 429 // U+FE20 through U+FE2F Combining half marks | |
| 430 0xFE20, 0xFE2F | |
| 431 }; | |
| 432 static size_t complexCodePathRangesCount = WTF_ARRAY_LENGTH(complexCodePathR
anges); | |
| 433 | |
| 434 CodePath result = Simple; | |
| 435 for (unsigned i = 0; i < len; i++) { | |
| 436 const UChar c = characters[i]; | |
| 437 | |
| 438 // Shortcut for common case | |
| 439 if (c < 0x2E5) | |
| 440 continue; | |
| 441 | |
| 442 // U+1E00 through U+2000 characters with diacritics and stacked diacriti
cs | |
| 443 if (c >= 0x1E00 && c <= 0x2000) { | |
| 444 result = SimpleWithGlyphOverflow; | |
| 445 continue; | |
| 446 } | |
| 447 | |
| 448 // Surrogate pairs | |
| 449 if (c > 0xD7FF && c <= 0xDBFF) { | |
| 450 if (i == len - 1) | |
| 451 continue; | |
| 452 | |
| 453 UChar next = characters[++i]; | |
| 454 if (!U16_IS_TRAIL(next)) | |
| 455 continue; | |
| 456 | |
| 457 UChar32 supplementaryCharacter = U16_GET_SUPPLEMENTARY(c, next); | |
| 458 | |
| 459 if (supplementaryCharacter < 0x1F1E6) // U+1F1E6 through U+1F1FF Reg
ional Indicator Symbols | |
| 460 continue; | |
| 461 if (supplementaryCharacter <= 0x1F1FF) | |
| 462 return Complex; | |
| 463 | |
| 464 if (supplementaryCharacter < 0xE0100) // U+E0100 through U+E01EF Uni
code variation selectors. | |
| 465 continue; | |
| 466 if (supplementaryCharacter <= 0xE01EF) | |
| 467 return Complex; | |
| 468 | |
| 469 // FIXME: Check for Brahmi (U+11000 block), Kaithi (U+11080 block) a
nd other complex scripts | |
| 470 // in plane 1 or higher. | |
| 471 | |
| 472 continue; | |
| 473 } | |
| 474 | |
| 475 // Search for other Complex cases | |
| 476 UChar* boundingCharacter = approximateBinarySearch<UChar, UChar>( | |
| 477 (UChar*)complexCodePathRanges, complexCodePathRangesCount, c, keyExt
ractorUChar); | |
| 478 // Exact matches are complex | |
| 479 if (*boundingCharacter == c) | |
| 480 return Complex; | |
| 481 bool isEndOfRange = ((boundingCharacter - complexCodePathRanges) % 2); | |
| 482 if (*boundingCharacter < c) { | |
| 483 // Determine if we are in a range or out | |
| 484 if (!isEndOfRange) | |
| 485 return Complex; | |
| 486 continue; | |
| 487 } | |
| 488 ASSERT(*boundingCharacter > c); | |
| 489 // Determine if we are in a range or out - opposite condition to above | |
| 490 if (isEndOfRange) | |
| 491 return Complex; | |
| 492 } | |
| 493 | |
| 494 return result; | |
| 495 } | |
| 496 | |
| 497 bool Font::isCJKIdeograph(UChar32 c) | |
| 498 { | |
| 499 static const UChar32 cjkIdeographRanges[] = { | |
| 500 // CJK Radicals Supplement and Kangxi Radicals. | |
| 501 0x2E80, 0x2FDF, | |
| 502 // CJK Strokes. | |
| 503 0x31C0, 0x31EF, | |
| 504 // CJK Unified Ideographs Extension A. | |
| 505 0x3400, 0x4DBF, | |
| 506 // The basic CJK Unified Ideographs block. | |
| 507 0x4E00, 0x9FFF, | |
| 508 // CJK Compatibility Ideographs. | |
| 509 0xF900, 0xFAFF, | |
| 510 // CJK Unified Ideographs Extension B. | |
| 511 0x20000, 0x2A6DF, | |
| 512 // CJK Unified Ideographs Extension C. | |
| 513 // CJK Unified Ideographs Extension D. | |
| 514 0x2A700, 0x2B81F, | |
| 515 // CJK Compatibility Ideographs Supplement. | |
| 516 0x2F800, 0x2FA1F | |
| 517 }; | |
| 518 static size_t cjkIdeographRangesCount = WTF_ARRAY_LENGTH(cjkIdeographRanges)
; | |
| 519 | |
| 520 // Early out | |
| 521 if (c < cjkIdeographRanges[0] || c > cjkIdeographRanges[cjkIdeographRangesCo
unt - 1]) | |
| 522 return false; | |
| 523 | |
| 524 UChar32* boundingCharacter = approximateBinarySearch<UChar32, UChar32>( | |
| 525 (UChar32*)cjkIdeographRanges, cjkIdeographRangesCount, c, keyExtractorUC
har32); | |
| 526 // Exact matches are CJK | |
| 527 if (*boundingCharacter == c) | |
| 528 return true; | |
| 529 bool isEndOfRange = ((boundingCharacter - cjkIdeographRanges) % 2); | |
| 530 if (*boundingCharacter < c) | |
| 531 return !isEndOfRange; | |
| 532 return isEndOfRange; | |
| 533 } | |
| 534 | |
| 535 bool Font::isCJKIdeographOrSymbol(UChar32 c) | |
| 536 { | |
| 537 // Likely common case | |
| 538 if (c < 0x2C7) | |
| 539 return false; | |
| 540 | |
| 541 // Hash lookup for isolated symbols (those not part of a contiguous range) | |
| 542 static HashSet<UChar32>* cjkIsolatedSymbols = 0; | |
| 543 if (!cjkIsolatedSymbols) { | |
| 544 cjkIsolatedSymbols = new HashSet<UChar32>(); | |
| 545 for (size_t i = 0; i < WTF_ARRAY_LENGTH(cjkIsolatedSymbolsArray); ++i) | |
| 546 cjkIsolatedSymbols->add(cjkIsolatedSymbolsArray[i]); | |
| 547 } | |
| 548 if (cjkIsolatedSymbols->contains(c)) | |
| 549 return true; | |
| 550 | |
| 551 if (isCJKIdeograph(c)) | |
| 552 return true; | |
| 553 | |
| 554 static const UChar32 cjkSymbolRanges[] = { | |
| 555 0x2156, 0x215A, | |
| 556 0x2160, 0x216B, | |
| 557 0x2170, 0x217B, | |
| 558 0x23BE, 0x23CC, | |
| 559 0x2460, 0x2492, | |
| 560 0x249C, 0x24FF, | |
| 561 0x25CE, 0x25D3, | |
| 562 0x25E2, 0x25E6, | |
| 563 0x2600, 0x2603, | |
| 564 0x2660, 0x266F, | |
| 565 0x2672, 0x267D, | |
| 566 0x2776, 0x277F, | |
| 567 // Ideographic Description Characters, with CJK Symbols and Punctuation,
excluding 0x3030. | |
| 568 // Then Hiragana 0x3040 .. 0x309F, Katakana 0x30A0 .. 0x30FF, Bopomofo 0
x3100 .. 0x312F | |
| 569 0x2FF0, 0x302F, | |
| 570 0x3031, 0x312F, | |
| 571 // More Bopomofo and Bopomofo Extended 0x31A0 .. 0x31BF | |
| 572 0x3190, 0x31BF, | |
| 573 // Enclosed CJK Letters and Months (0x3200 .. 0x32FF). | |
| 574 // CJK Compatibility (0x3300 .. 0x33FF). | |
| 575 0x3200, 0x33FF, | |
| 576 0xF860, 0xF862, | |
| 577 // CJK Compatibility Forms. | |
| 578 0xFE30, 0xFE4F, | |
| 579 // Halfwidth and Fullwidth Forms | |
| 580 // Usually only used in CJK | |
| 581 0xFF00, 0xFF0C, | |
| 582 0xFF0E, 0xFF1A, | |
| 583 0xFF1F, 0xFFEF, | |
| 584 // Emoji. | |
| 585 0x1F110, 0x1F129, | |
| 586 0x1F130, 0x1F149, | |
| 587 0x1F150, 0x1F169, | |
| 588 0x1F170, 0x1F189, | |
| 589 0x1F200, 0x1F6FF | |
| 590 }; | |
| 591 static size_t cjkSymbolRangesCount = WTF_ARRAY_LENGTH(cjkSymbolRanges); | |
| 592 | |
| 593 UChar32* boundingCharacter = approximateBinarySearch<UChar32, UChar32>( | |
| 594 (UChar32*)cjkSymbolRanges, cjkSymbolRangesCount, c, keyExtractorUChar32)
; | |
| 595 // Exact matches are CJK Symbols | |
| 596 if (*boundingCharacter == c) | |
| 597 return true; | |
| 598 bool isEndOfRange = ((boundingCharacter - cjkSymbolRanges) % 2); | |
| 599 if (*boundingCharacter < c) | |
| 600 return !isEndOfRange; | |
| 601 return isEndOfRange; | |
| 602 } | |
| 603 | |
| 604 unsigned Font::expansionOpportunityCount(const LChar* characters, size_t length,
TextDirection direction, bool& isAfterExpansion) | |
| 605 { | |
| 606 unsigned count = 0; | |
| 607 if (direction == LTR) { | |
| 608 for (size_t i = 0; i < length; ++i) { | |
| 609 if (treatAsSpace(characters[i])) { | |
| 610 count++; | |
| 611 isAfterExpansion = true; | |
| 612 } else | |
| 613 isAfterExpansion = false; | |
| 614 } | |
| 615 } else { | |
| 616 for (size_t i = length; i > 0; --i) { | |
| 617 if (treatAsSpace(characters[i - 1])) { | |
| 618 count++; | |
| 619 isAfterExpansion = true; | |
| 620 } else | |
| 621 isAfterExpansion = false; | |
| 622 } | |
| 623 } | |
| 624 return count; | |
| 625 } | |
| 626 | |
| 627 unsigned Font::expansionOpportunityCount(const UChar* characters, size_t length,
TextDirection direction, bool& isAfterExpansion) | |
| 628 { | |
| 629 static bool expandAroundIdeographs = canExpandAroundIdeographsInComplexText(
); | |
| 630 unsigned count = 0; | |
| 631 if (direction == LTR) { | |
| 632 for (size_t i = 0; i < length; ++i) { | |
| 633 UChar32 character = characters[i]; | |
| 634 if (treatAsSpace(character)) { | |
| 635 count++; | |
| 636 isAfterExpansion = true; | |
| 637 continue; | |
| 638 } | |
| 639 if (U16_IS_LEAD(character) && i + 1 < length && U16_IS_TRAIL(charact
ers[i + 1])) { | |
| 640 character = U16_GET_SUPPLEMENTARY(character, characters[i + 1]); | |
| 641 i++; | |
| 642 } | |
| 643 if (expandAroundIdeographs && isCJKIdeographOrSymbol(character)) { | |
| 644 if (!isAfterExpansion) | |
| 645 count++; | |
| 646 count++; | |
| 647 isAfterExpansion = true; | |
| 648 continue; | |
| 649 } | |
| 650 isAfterExpansion = false; | |
| 651 } | |
| 652 } else { | |
| 653 for (size_t i = length; i > 0; --i) { | |
| 654 UChar32 character = characters[i - 1]; | |
| 655 if (treatAsSpace(character)) { | |
| 656 count++; | |
| 657 isAfterExpansion = true; | |
| 658 continue; | |
| 659 } | |
| 660 if (U16_IS_TRAIL(character) && i > 1 && U16_IS_LEAD(characters[i - 2
])) { | |
| 661 character = U16_GET_SUPPLEMENTARY(characters[i - 2], character); | |
| 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 } | |
| 674 return count; | |
| 675 } | |
| 676 | |
| 677 bool Font::canReceiveTextEmphasis(UChar32 c) | |
| 678 { | |
| 679 CharCategory category = Unicode::category(c); | |
| 680 if (category & (Separator_Space | Separator_Line | Separator_Paragraph | Oth
er_NotAssigned | Other_Control | Other_Format)) | |
| 681 return false; | |
| 682 | |
| 683 // Additional word-separator characters listed in CSS Text Level 3 Editor's
Draft 3 November 2010. | |
| 684 if (c == ethiopicWordspace || c == aegeanWordSeparatorLine || c == aegeanWor
dSeparatorDot | |
| 685 || c == ugariticWordDivider || c == tibetanMarkIntersyllabicTsheg || c =
= tibetanMarkDelimiterTshegBstar) | |
| 686 return false; | |
| 687 | |
| 688 return true; | |
| 689 } | |
| 690 | |
| 691 void Font::willUseFontData() const | |
| 692 { | |
| 693 const FontFamily& family = fontDescription().family(); | |
| 694 if (m_fontFallbackList && m_fontFallbackList->fontSelector() && !family.fami
lyIsEmpty()) | |
| 695 m_fontFallbackList->fontSelector()->willUseFontData(fontDescription(), f
amily.family()); | |
| 696 } | |
| 697 | |
| 698 } | |
| OLD | NEW |