1 /** 2 * Copyright (C) 2003, 2006, 2010 Apple Inc. All rights reserved. 3 * Copyright (C) 2008 Holger Hans Peter Freyther 4 * Copyright (C) 2009 Torch Mobile, Inc. 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Library General Public 8 * License as published by the Free Software Foundation; either 9 * version 2 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Library General Public License for more details. 15 * 16 * You should have received a copy of the GNU Library General Public License 17 * along with this library; see the file COPYING.LIB. If not, write to 18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 19 * Boston, MA 02110-1301, USA. 20 * 21 */ 22 23 #include "config.h" 24 #include "Font.h" 25 26 #include "FloatRect.h" 27 #include "FontCache.h" 28 #include "FontFallbackList.h" 29 #include "GlyphBuffer.h" 30 #include "GlyphPageTreeNode.h" 31 #include "SimpleFontData.h" 32 #include "TextRun.h" 33 #include "WidthIterator.h" 34 #include <wtf/MathExtras.h> 35 #include <wtf/unicode/CharacterNames.h> 36 #include <wtf/unicode/Unicode.h> 37 38 using namespace WTF; 39 using namespace Unicode; 40 41 namespace WebCore { 42 43 GlyphData Font::glyphDataForCharacter(UChar32 c, bool mirror, FontDataVariant variant) const 44 { 45 ASSERT(isMainThread()); 46 47 if (variant == AutoVariant) { 48 if (m_fontDescription.smallCaps()) { 49 UChar32 upperC = toUpper(c); 50 if (upperC != c) { 51 c = upperC; 52 variant = SmallCapsVariant; 53 } else 54 variant = NormalVariant; 55 } else 56 variant = NormalVariant; 57 } 58 59 if (mirror) 60 c = mirroredChar(c); 61 62 unsigned pageNumber = (c / GlyphPage::size); 63 64 GlyphPageTreeNode* node = pageNumber ? m_fontList->m_pages.get(pageNumber) : m_fontList->m_pageZero; 65 if (!node) { 66 node = GlyphPageTreeNode::getRootChild(fontDataAt(0), pageNumber); 67 if (pageNumber) 68 m_fontList->m_pages.set(pageNumber, node); 69 else 70 m_fontList->m_pageZero = node; 71 } 72 73 GlyphPage* page; 74 if (variant == NormalVariant) { 75 // Fastest loop, for the common case (normal variant). 76 while (true) { 77 page = node->page(); 78 if (page) { 79 GlyphData data = page->glyphDataForCharacter(c); 80 if (data.fontData && (data.fontData->platformData().orientation() == Horizontal || data.fontData->isTextOrientationFallback())) 81 return data; 82 83 if (data.fontData) { 84 if (isCJKIdeographOrSymbol(c)) { 85 if (!data.fontData->hasVerticalGlyphs()) { 86 // Use the broken ideograph font data. The broken ideograph font will use the horizontal width of glyphs 87 // to make sure you get a square (even for broken glyphs like symbols used for punctuation). 88 const SimpleFontData* brokenIdeographFontData = data.fontData->brokenIdeographFontData(); 89 GlyphPageTreeNode* brokenIdeographNode = GlyphPageTreeNode::getRootChild(brokenIdeographFontData, pageNumber); 90 const GlyphPage* brokenIdeographPage = brokenIdeographNode->page(); 91 if (brokenIdeographPage) { 92 GlyphData brokenIdeographData = brokenIdeographPage->glyphDataForCharacter(c); 93 if (brokenIdeographData.fontData) 94 return brokenIdeographData; 95 } 96 97 // Shouldn't be possible to even reach this point. 98 ASSERT_NOT_REACHED(); 99 } 100 } else { 101 if (m_fontDescription.textOrientation() == TextOrientationVerticalRight) { 102 const SimpleFontData* verticalRightFontData = data.fontData->verticalRightOrientationFontData(); 103 GlyphPageTreeNode* verticalRightNode = GlyphPageTreeNode::getRootChild(verticalRightFontData, pageNumber); 104 const GlyphPage* verticalRightPage = verticalRightNode->page(); 105 if (verticalRightPage) { 106 GlyphData verticalRightData = verticalRightPage->glyphDataForCharacter(c); 107 // If the glyphs are distinct, we will make the assumption that the font has a vertical-right glyph baked 108 // into it. 109 if (data.glyph != verticalRightData.glyph) 110 return data; 111 // The glyphs are identical, meaning that we should just use the horizontal glyph. 112 if (verticalRightData.fontData) 113 return verticalRightData; 114 } 115 } else if (m_fontDescription.textOrientation() == TextOrientationUpright) { 116 const SimpleFontData* uprightFontData = data.fontData->uprightOrientationFontData(); 117 GlyphPageTreeNode* uprightNode = GlyphPageTreeNode::getRootChild(uprightFontData, pageNumber); 118 const GlyphPage* uprightPage = uprightNode->page(); 119 if (uprightPage) { 120 GlyphData uprightData = uprightPage->glyphDataForCharacter(c); 121 // If the glyphs are the same, then we know we can just use the horizontal glyph rotated vertically to be upright. 122 if (data.glyph == uprightData.glyph) 123 return data; 124 // The glyphs are distinct, meaning that the font has a vertical-right glyph baked into it. We can't use that 125 // glyph, so we fall back to the upright data and use the horizontal glyph. 126 if (uprightData.fontData) 127 return uprightData; 128 } 129 } 130 131 // Shouldn't be possible to even reach this point. 132 ASSERT_NOT_REACHED(); 133 } 134 return data; 135 } 136 137 if (node->isSystemFallback()) 138 break; 139 } 140 141 // Proceed with the fallback list. 142 node = node->getChild(fontDataAt(node->level()), pageNumber); 143 if (pageNumber) 144 m_fontList->m_pages.set(pageNumber, node); 145 else 146 m_fontList->m_pageZero = node; 147 } 148 } else { 149 while (true) { 150 page = node->page(); 151 if (page) { 152 GlyphData data = page->glyphDataForCharacter(c); 153 if (data.fontData) { 154 // The variantFontData function should not normally return 0. 155 // But if it does, we will just render the capital letter big. 156 const SimpleFontData* variantFontData = data.fontData->variantFontData(m_fontDescription, variant); 157 if (!variantFontData) 158 return data; 159 160 GlyphPageTreeNode* variantNode = GlyphPageTreeNode::getRootChild(variantFontData, pageNumber); 161 const GlyphPage* variantPage = variantNode->page(); 162 if (variantPage) { 163 GlyphData data = variantPage->glyphDataForCharacter(c); 164 if (data.fontData) 165 return data; 166 } 167 168 // Do not attempt system fallback off the variantFontData. This is the very unlikely case that 169 // a font has the lowercase character but the small caps font does not have its uppercase version. 170 return variantFontData->missingGlyphData(); 171 } 172 173 if (node->isSystemFallback()) 174 break; 175 } 176 177 // Proceed with the fallback list. 178 node = node->getChild(fontDataAt(node->level()), pageNumber); 179 if (pageNumber) 180 m_fontList->m_pages.set(pageNumber, node); 181 else 182 m_fontList->m_pageZero = node; 183 } 184 } 185 186 ASSERT(page); 187 ASSERT(node->isSystemFallback()); 188 189 // System fallback is character-dependent. When we get here, we 190 // know that the character in question isn't in the system fallback 191 // font's glyph page. Try to lazily create it here. 192 UChar codeUnits[2]; 193 int codeUnitsLength; 194 if (c <= 0xFFFF) { 195 codeUnits[0] = Font::normalizeSpaces(c); 196 codeUnitsLength = 1; 197 } else { 198 codeUnits[0] = U16_LEAD(c); 199 codeUnits[1] = U16_TRAIL(c); 200 codeUnitsLength = 2; 201 } 202 const SimpleFontData* characterFontData = fontCache()->getFontDataForCharacters(*this, codeUnits, codeUnitsLength); 203 if (variant != NormalVariant && characterFontData) 204 characterFontData = characterFontData->variantFontData(m_fontDescription, variant); 205 if (characterFontData) { 206 // Got the fallback glyph and font. 207 GlyphPage* fallbackPage = GlyphPageTreeNode::getRootChild(characterFontData, pageNumber)->page(); 208 GlyphData data = fallbackPage && fallbackPage->fontDataForCharacter(c) ? fallbackPage->glyphDataForCharacter(c) : characterFontData->missingGlyphData(); 209 // Cache it so we don't have to do system fallback again next time. 210 if (variant == NormalVariant) { 211 #if OS(WINCE) 212 // missingGlyphData returns a null character, which is not suitable for GDI to display. 213 // Also, sometimes we cannot map a font for the character on WINCE, but GDI can still 214 // display the character, probably because the font package is not installed correctly. 215 // So we just always set the glyph to be same as the character, and let GDI solve it. 216 page->setGlyphDataForCharacter(c, c, characterFontData); 217 return page->glyphDataForCharacter(c); 218 #else 219 page->setGlyphDataForCharacter(c, data.glyph, data.fontData); 220 #endif 221 } 222 return data; 223 } 224 225 // Even system fallback can fail; use the missing glyph in that case. 226 // FIXME: It would be nicer to use the missing glyph from the last resort font instead. 227 GlyphData data = primaryFont()->missingGlyphData(); 228 if (variant == NormalVariant) { 229 #if OS(WINCE) 230 // See comment about WINCE GDI handling near setGlyphDataForCharacter above. 231 page->setGlyphDataForCharacter(c, c, data.fontData); 232 return page->glyphDataForCharacter(c); 233 #else 234 page->setGlyphDataForCharacter(c, data.glyph, data.fontData); 235 #endif 236 } 237 return data; 238 } 239 240 bool Font::primaryFontHasGlyphForCharacter(UChar32 character) const 241 { 242 unsigned pageNumber = (character / GlyphPage::size); 243 244 GlyphPageTreeNode* node = GlyphPageTreeNode::getRootChild(primaryFont(), pageNumber); 245 GlyphPage* page = node->page(); 246 247 return page && page->fontDataForCharacter(character); 248 } 249 250 // FIXME: This function may not work if the emphasis mark uses a complex script, but none of the 251 // standard emphasis marks do so. 252 bool Font::getEmphasisMarkGlyphData(const AtomicString& mark, GlyphData& glyphData) const 253 { 254 if (mark.isEmpty()) 255 return false; 256 257 #if ENABLE(SVG_FONTS) 258 // FIXME: Implement for SVG fonts. 259 if (primaryFont()->isSVGFont()) 260 return false; 261 #endif 262 263 UChar32 character = mark[0]; 264 265 if (U16_IS_SURROGATE(character)) { 266 if (!U16_IS_SURROGATE_LEAD(character)) 267 return false; 268 269 if (mark.length() < 2) 270 return false; 271 272 UChar low = mark[1]; 273 if (!U16_IS_TRAIL(low)) 274 return false; 275 276 character = U16_GET_SUPPLEMENTARY(character, low); 277 } 278 279 glyphData = glyphDataForCharacter(character, false, EmphasisMarkVariant); 280 return true; 281 } 282 283 int Font::emphasisMarkAscent(const AtomicString& mark) const 284 { 285 GlyphData markGlyphData; 286 if (!getEmphasisMarkGlyphData(mark, markGlyphData)) 287 return 0; 288 289 const SimpleFontData* markFontData = markGlyphData.fontData; 290 ASSERT(markFontData); 291 if (!markFontData) 292 return 0; 293 294 return markFontData->fontMetrics().ascent(); 295 } 296 297 int Font::emphasisMarkDescent(const AtomicString& mark) const 298 { 299 GlyphData markGlyphData; 300 if (!getEmphasisMarkGlyphData(mark, markGlyphData)) 301 return 0; 302 303 const SimpleFontData* markFontData = markGlyphData.fontData; 304 ASSERT(markFontData); 305 if (!markFontData) 306 return 0; 307 308 return markFontData->fontMetrics().descent(); 309 } 310 311 int Font::emphasisMarkHeight(const AtomicString& mark) const 312 { 313 GlyphData markGlyphData; 314 if (!getEmphasisMarkGlyphData(mark, markGlyphData)) 315 return 0; 316 317 const SimpleFontData* markFontData = markGlyphData.fontData; 318 ASSERT(markFontData); 319 if (!markFontData) 320 return 0; 321 322 return markFontData->fontMetrics().height(); 323 } 324 325 float Font::getGlyphsAndAdvancesForSimpleText(const TextRun& run, int from, int to, GlyphBuffer& glyphBuffer, ForTextEmphasisOrNot forTextEmphasis) const 326 { 327 float initialAdvance; 328 329 WidthIterator it(this, run, 0, false, forTextEmphasis); 330 it.advance(from); 331 float beforeWidth = it.m_runWidthSoFar; 332 it.advance(to, &glyphBuffer); 333 334 if (glyphBuffer.isEmpty()) 335 return 0; 336 337 float afterWidth = it.m_runWidthSoFar; 338 339 if (run.rtl()) { 340 it.advance(run.length()); 341 initialAdvance = it.m_runWidthSoFar - afterWidth; 342 } else 343 initialAdvance = beforeWidth; 344 345 if (run.rtl()) { 346 for (int i = 0, end = glyphBuffer.size() - 1; i < glyphBuffer.size() / 2; ++i, --end) 347 glyphBuffer.swap(i, end); 348 } 349 350 return initialAdvance; 351 } 352 353 void Font::drawSimpleText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, int from, int to) const 354 { 355 // This glyph buffer holds our glyphs+advances+font data for each glyph. 356 GlyphBuffer glyphBuffer; 357 358 float startX = point.x() + getGlyphsAndAdvancesForSimpleText(run, from, to, glyphBuffer); 359 360 if (glyphBuffer.isEmpty()) 361 return; 362 363 FloatPoint startPoint(startX, point.y()); 364 drawGlyphBuffer(context, glyphBuffer, startPoint); 365 } 366 367 void Font::drawEmphasisMarksForSimpleText(GraphicsContext* context, const TextRun& run, const AtomicString& mark, const FloatPoint& point, int from, int to) const 368 { 369 GlyphBuffer glyphBuffer; 370 float initialAdvance = getGlyphsAndAdvancesForSimpleText(run, from, to, glyphBuffer, ForTextEmphasis); 371 372 if (glyphBuffer.isEmpty()) 373 return; 374 375 drawEmphasisMarks(context, glyphBuffer, mark, FloatPoint(point.x() + initialAdvance, point.y())); 376 } 377 378 void Font::drawGlyphBuffer(GraphicsContext* context, const GlyphBuffer& glyphBuffer, const FloatPoint& point) const 379 { 380 // Draw each contiguous run of glyphs that use the same font data. 381 const SimpleFontData* fontData = glyphBuffer.fontDataAt(0); 382 FloatSize offset = glyphBuffer.offsetAt(0); 383 FloatPoint startPoint(point); 384 float nextX = startPoint.x(); 385 int lastFrom = 0; 386 int nextGlyph = 0; 387 while (nextGlyph < glyphBuffer.size()) { 388 const SimpleFontData* nextFontData = glyphBuffer.fontDataAt(nextGlyph); 389 FloatSize nextOffset = glyphBuffer.offsetAt(nextGlyph); 390 if (nextFontData != fontData || nextOffset != offset) { 391 drawGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint); 392 393 lastFrom = nextGlyph; 394 fontData = nextFontData; 395 offset = nextOffset; 396 startPoint.setX(nextX); 397 } 398 nextX += glyphBuffer.advanceAt(nextGlyph); 399 nextGlyph++; 400 } 401 402 drawGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint); 403 } 404 405 inline static float offsetToMiddleOfGlyph(const SimpleFontData* fontData, Glyph glyph) 406 { 407 if (fontData->platformData().orientation() == Horizontal) { 408 FloatRect bounds = fontData->boundsForGlyph(glyph); 409 return bounds.x() + bounds.width() / 2; 410 } 411 // FIXME: Use glyph bounds once they make sense for vertical fonts. 412 return fontData->widthForGlyph(glyph) / 2; 413 } 414 415 inline static float offsetToMiddleOfGlyphAtIndex(const GlyphBuffer& glyphBuffer, size_t i) 416 { 417 return offsetToMiddleOfGlyph(glyphBuffer.fontDataAt(i), glyphBuffer.glyphAt(i)); 418 } 419 420 void Font::drawEmphasisMarks(GraphicsContext* context, const GlyphBuffer& glyphBuffer, const AtomicString& mark, const FloatPoint& point) const 421 { 422 GlyphData markGlyphData; 423 if (!getEmphasisMarkGlyphData(mark, markGlyphData)) 424 return; 425 426 const SimpleFontData* markFontData = markGlyphData.fontData; 427 ASSERT(markFontData); 428 if (!markFontData) 429 return; 430 431 Glyph markGlyph = markGlyphData.glyph; 432 Glyph spaceGlyph = markFontData->spaceGlyph(); 433 434 float middleOfLastGlyph = offsetToMiddleOfGlyphAtIndex(glyphBuffer, 0); 435 FloatPoint startPoint(point.x() + middleOfLastGlyph - offsetToMiddleOfGlyph(markFontData, markGlyph), point.y()); 436 437 GlyphBuffer markBuffer; 438 for (int i = 0; i + 1 < glyphBuffer.size(); ++i) { 439 float middleOfNextGlyph = offsetToMiddleOfGlyphAtIndex(glyphBuffer, i + 1); 440 float advance = glyphBuffer.advanceAt(i) - middleOfLastGlyph + middleOfNextGlyph; 441 markBuffer.add(glyphBuffer.glyphAt(i) ? markGlyph : spaceGlyph, markFontData, advance); 442 middleOfLastGlyph = middleOfNextGlyph; 443 } 444 markBuffer.add(glyphBuffer.glyphAt(glyphBuffer.size() - 1) ? markGlyph : spaceGlyph, markFontData, 0); 445 446 drawGlyphBuffer(context, markBuffer, startPoint); 447 } 448 449 float Font::floatWidthForSimpleText(const TextRun& run, GlyphBuffer* glyphBuffer, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const 450 { 451 WidthIterator it(this, run, fallbackFonts, glyphOverflow); 452 it.advance(run.length(), glyphBuffer); 453 454 if (glyphOverflow) { 455 glyphOverflow->top = max<int>(glyphOverflow->top, ceilf(-it.minGlyphBoundingBoxY()) - (glyphOverflow->computeBounds ? 0 : fontMetrics().ascent())); 456 glyphOverflow->bottom = max<int>(glyphOverflow->bottom, ceilf(it.maxGlyphBoundingBoxY()) - (glyphOverflow->computeBounds ? 0 : fontMetrics().descent())); 457 glyphOverflow->left = ceilf(it.firstGlyphOverflow()); 458 glyphOverflow->right = ceilf(it.lastGlyphOverflow()); 459 } 460 461 return it.m_runWidthSoFar; 462 } 463 464 FloatRect Font::selectionRectForSimpleText(const TextRun& run, const FloatPoint& point, int h, int from, int to) const 465 { 466 WidthIterator it(this, run); 467 it.advance(from); 468 float beforeWidth = it.m_runWidthSoFar; 469 it.advance(to); 470 float afterWidth = it.m_runWidthSoFar; 471 472 // Using roundf() rather than ceilf() for the right edge as a compromise to ensure correct caret positioning. 473 if (run.rtl()) { 474 it.advance(run.length()); 475 float totalWidth = it.m_runWidthSoFar; 476 return FloatRect(point.x() + floorf(totalWidth - afterWidth), point.y(), roundf(totalWidth - beforeWidth) - floorf(totalWidth - afterWidth), h); 477 } 478 479 return FloatRect(point.x() + floorf(beforeWidth), point.y(), roundf(afterWidth) - floorf(beforeWidth), h); 480 } 481 482 int Font::offsetForPositionForSimpleText(const TextRun& run, float x, bool includePartialGlyphs) const 483 { 484 float delta = x; 485 486 WidthIterator it(this, run); 487 GlyphBuffer localGlyphBuffer; 488 unsigned offset; 489 if (run.rtl()) { 490 delta -= floatWidthForSimpleText(run, 0); 491 while (1) { 492 offset = it.m_currentCharacter; 493 float w; 494 if (!it.advanceOneCharacter(w, &localGlyphBuffer)) 495 break; 496 delta += w; 497 if (includePartialGlyphs) { 498 if (delta - w / 2 >= 0) 499 break; 500 } else { 501 if (delta >= 0) 502 break; 503 } 504 } 505 } else { 506 while (1) { 507 offset = it.m_currentCharacter; 508 float w; 509 if (!it.advanceOneCharacter(w, &localGlyphBuffer)) 510 break; 511 delta -= w; 512 if (includePartialGlyphs) { 513 if (delta + w / 2 <= 0) 514 break; 515 } else { 516 if (delta <= 0) 517 break; 518 } 519 } 520 } 521 522 return offset; 523 } 524 525 } 526