Font.cpp revision 1cbdecfa9fc428ac2d8aca0fa91c9580b3d57353
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 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 "CharacterNames.h" 28#include "FloatRect.h" 29#include "FontCache.h" 30#include "FontFallbackList.h" 31#include "IntPoint.h" 32#include "GlyphBuffer.h" 33#include "WidthIterator.h" 34#include <wtf/MathExtras.h> 35 36using namespace WTF; 37using namespace Unicode; 38 39namespace WebCore { 40 41const uint8_t Font::gRoundingHackCharacterTable[256] = { 42 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, 43 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 /*?*/, 44 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, 45 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, 46 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, 47 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, 48 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, 49 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 50}; 51 52Font::CodePath Font::s_codePath = Auto; 53 54// ============================================================================================ 55// Font Implementation (Cross-Platform Portion) 56// ============================================================================================ 57 58Font::Font() 59 : m_pageZero(0) 60 , m_cachedPrimaryFont(0) 61 , m_letterSpacing(0) 62 , m_wordSpacing(0) 63 , m_isPlatformFont(false) 64{ 65} 66 67Font::Font(const FontDescription& fd, short letterSpacing, short wordSpacing) 68 : m_fontDescription(fd) 69 , m_pageZero(0) 70 , m_cachedPrimaryFont(0) 71 , m_letterSpacing(letterSpacing) 72 , m_wordSpacing(wordSpacing) 73 , m_isPlatformFont(false) 74{ 75} 76 77Font::Font(const FontPlatformData& fontData, bool isPrinterFont) 78 : m_fontList(FontFallbackList::create()) 79 , m_pageZero(0) 80 , m_cachedPrimaryFont(0) 81 , m_letterSpacing(0) 82 , m_wordSpacing(0) 83 , m_isPlatformFont(true) 84{ 85 m_fontDescription.setUsePrinterFont(isPrinterFont); 86 m_fontList->setPlatformFont(fontData); 87} 88 89Font::Font(const Font& other) 90 : m_fontDescription(other.m_fontDescription) 91 , m_fontList(other.m_fontList) 92 , m_pages(other.m_pages) 93 , m_pageZero(other.m_pageZero) 94 , m_cachedPrimaryFont(other.m_cachedPrimaryFont) 95 , m_letterSpacing(other.m_letterSpacing) 96 , m_wordSpacing(other.m_wordSpacing) 97 , m_isPlatformFont(other.m_isPlatformFont) 98{ 99} 100 101Font& Font::operator=(const Font& other) 102{ 103 m_fontDescription = other.m_fontDescription; 104 m_fontList = other.m_fontList; 105 m_pages = other.m_pages; 106 m_pageZero = other.m_pageZero; 107 m_cachedPrimaryFont = other.m_cachedPrimaryFont; 108 m_letterSpacing = other.m_letterSpacing; 109 m_wordSpacing = other.m_wordSpacing; 110 m_isPlatformFont = other.m_isPlatformFont; 111 return *this; 112} 113 114Font::~Font() 115{ 116} 117 118bool Font::operator==(const Font& other) const 119{ 120 // Our FontData don't have to be checked, since checking the font description will be fine. 121 // FIXME: This does not work if the font was made with the FontPlatformData constructor. 122 if ((m_fontList && m_fontList->loadingCustomFonts()) || 123 (other.m_fontList && other.m_fontList->loadingCustomFonts())) 124 return false; 125 126 FontSelector* first = m_fontList ? m_fontList->fontSelector() : 0; 127 FontSelector* second = other.m_fontList ? other.m_fontList->fontSelector() : 0; 128 129 return first == second 130 && m_fontDescription == other.m_fontDescription 131 && m_letterSpacing == other.m_letterSpacing 132 && m_wordSpacing == other.m_wordSpacing 133 && (m_fontList ? m_fontList->generation() : 0) == (other.m_fontList ? other.m_fontList->generation() : 0); 134} 135 136const GlyphData& Font::glyphDataForCharacter(UChar32 c, bool mirror, bool forceSmallCaps) const 137{ 138 bool useSmallCapsFont = forceSmallCaps; 139 if (m_fontDescription.smallCaps()) { 140 UChar32 upperC = Unicode::toUpper(c); 141 if (upperC != c) { 142 c = upperC; 143 useSmallCapsFont = true; 144 } 145 } 146 147 if (mirror) 148 c = mirroredChar(c); 149 150 unsigned pageNumber = (c / GlyphPage::size); 151 152 GlyphPageTreeNode* node = pageNumber ? m_pages.get(pageNumber) : m_pageZero; 153 if (!node) { 154 node = GlyphPageTreeNode::getRootChild(fontDataAt(0), pageNumber); 155 if (pageNumber) 156 m_pages.set(pageNumber, node); 157 else 158 m_pageZero = node; 159 } 160 161 GlyphPage* page; 162 if (!useSmallCapsFont) { 163 // Fastest loop, for the common case (not small caps). 164 while (true) { 165 page = node->page(); 166 if (page) { 167 const GlyphData& data = page->glyphDataForCharacter(c); 168 if (data.fontData) 169 return data; 170 if (node->isSystemFallback()) 171 break; 172 } 173 174 // Proceed with the fallback list. 175 node = node->getChild(fontDataAt(node->level()), pageNumber); 176 if (pageNumber) 177 m_pages.set(pageNumber, node); 178 else 179 m_pageZero = node; 180 } 181 } else { 182 while (true) { 183 page = node->page(); 184 if (page) { 185 const GlyphData& data = page->glyphDataForCharacter(c); 186 if (data.fontData) { 187 // The smallCapsFontData function should not normally return 0. 188 // But if it does, we will just render the capital letter big. 189 const SimpleFontData* smallCapsFontData = data.fontData->smallCapsFontData(m_fontDescription); 190 if (!smallCapsFontData) 191 return data; 192 193 GlyphPageTreeNode* smallCapsNode = GlyphPageTreeNode::getRootChild(smallCapsFontData, pageNumber); 194 const GlyphPage* smallCapsPage = smallCapsNode->page(); 195 if (smallCapsPage) { 196 const GlyphData& data = smallCapsPage->glyphDataForCharacter(c); 197 if (data.fontData) 198 return data; 199 } 200 201 // Do not attempt system fallback off the smallCapsFontData. This is the very unlikely case that 202 // a font has the lowercase character but the small caps font does not have its uppercase version. 203 return smallCapsFontData->missingGlyphData(); 204 } 205 206 if (node->isSystemFallback()) 207 break; 208 } 209 210 // Proceed with the fallback list. 211 node = node->getChild(fontDataAt(node->level()), pageNumber); 212 if (pageNumber) 213 m_pages.set(pageNumber, node); 214 else 215 m_pageZero = node; 216 } 217 } 218 219 ASSERT(page); 220 ASSERT(node->isSystemFallback()); 221 222 // System fallback is character-dependent. When we get here, we 223 // know that the character in question isn't in the system fallback 224 // font's glyph page. Try to lazily create it here. 225 UChar codeUnits[2]; 226 int codeUnitsLength; 227 if (c <= 0xFFFF) { 228 UChar c16 = c; 229 if (Font::treatAsSpace(c16)) 230 codeUnits[0] = ' '; 231 else if (Font::treatAsZeroWidthSpace(c16)) 232 codeUnits[0] = zeroWidthSpace; 233 else 234 codeUnits[0] = c16; 235 codeUnitsLength = 1; 236 } else { 237 codeUnits[0] = U16_LEAD(c); 238 codeUnits[1] = U16_TRAIL(c); 239 codeUnitsLength = 2; 240 } 241 const SimpleFontData* characterFontData = FontCache::getFontDataForCharacters(*this, codeUnits, codeUnitsLength); 242 if (useSmallCapsFont) 243 characterFontData = characterFontData->smallCapsFontData(m_fontDescription); 244 if (characterFontData) { 245 // Got the fallback glyph and font. 246 GlyphPage* fallbackPage = GlyphPageTreeNode::getRootChild(characterFontData, pageNumber)->page(); 247 const GlyphData& data = fallbackPage && fallbackPage->glyphDataForCharacter(c).fontData ? fallbackPage->glyphDataForCharacter(c) : characterFontData->missingGlyphData(); 248 // Cache it so we don't have to do system fallback again next time. 249 if (!useSmallCapsFont) 250 page->setGlyphDataForCharacter(c, data.glyph, data.fontData); 251 return data; 252 } 253 254 // Even system fallback can fail; use the missing glyph in that case. 255 // FIXME: It would be nicer to use the missing glyph from the last resort font instead. 256 const GlyphData& data = primaryFont()->missingGlyphData(); 257 if (!useSmallCapsFont) 258 page->setGlyphDataForCharacter(c, data.glyph, data.fontData); 259 return data; 260} 261 262void Font::cachePrimaryFont() const 263{ 264 ASSERT(m_fontList); 265 ASSERT(!m_cachedPrimaryFont); 266 m_cachedPrimaryFont = m_fontList->primaryFont(this)->fontDataForCharacter(' '); 267} 268 269const FontData* Font::fontDataAt(unsigned index) const 270{ 271 ASSERT(m_fontList); 272 return m_fontList->fontDataAt(this, index); 273} 274 275const FontData* Font::fontDataForCharacters(const UChar* characters, int length) const 276{ 277 ASSERT(m_fontList); 278 return m_fontList->fontDataForCharacters(this, characters, length); 279} 280 281void Font::update(PassRefPtr<FontSelector> fontSelector) const 282{ 283 // FIXME: It is pretty crazy that we are willing to just poke into a RefPtr, but it ends up 284 // being reasonably safe (because inherited fonts in the render tree pick up the new 285 // style anyway. Other copies are transient, e.g., the state in the GraphicsContext, and 286 // won't stick around long enough to get you in trouble). Still, this is pretty disgusting, 287 // and could eventually be rectified by using RefPtrs for Fonts themselves. 288 if (!m_fontList) 289 m_fontList = FontFallbackList::create(); 290 m_fontList->invalidate(fontSelector); 291 m_cachedPrimaryFont = 0; 292 m_pageZero = 0; 293 m_pages.clear(); 294} 295 296int Font::width(const TextRun& run) const 297{ 298 return lroundf(floatWidth(run)); 299} 300 301int Font::ascent() const 302{ 303 return primaryFont()->ascent(); 304} 305 306int Font::descent() const 307{ 308 return primaryFont()->descent(); 309} 310 311int Font::lineSpacing() const 312{ 313 return primaryFont()->lineSpacing(); 314} 315 316int Font::lineGap() const 317{ 318 return primaryFont()->lineGap(); 319} 320 321float Font::xHeight() const 322{ 323 return primaryFont()->xHeight(); 324} 325 326unsigned Font::unitsPerEm() const 327{ 328 return primaryFont()->unitsPerEm(); 329} 330 331int Font::spaceWidth() const 332{ 333 return (int)ceilf(primaryFont()->m_adjustedSpaceWidth + m_letterSpacing); 334} 335 336bool Font::isFixedPitch() const 337{ 338 ASSERT(m_fontList); 339 return m_fontList->isFixedPitch(this); 340} 341 342void Font::setCodePath(CodePath p) 343{ 344 s_codePath = p; 345} 346 347Font::CodePath Font::codePath() 348{ 349 return s_codePath; 350} 351 352bool Font::canUseGlyphCache(const TextRun& run) const 353{ 354 switch (s_codePath) { 355 case Auto: 356 break; 357 case Simple: 358 return true; 359 case Complex: 360 return false; 361 } 362 363 // Start from 0 since drawing and highlighting also measure the characters before run->from 364 for (int i = 0; i < run.length(); i++) { 365 const UChar c = run[i]; 366 if (c < 0x300) // U+0300 through U+036F Combining diacritical marks 367 continue; 368 if (c <= 0x36F) 369 return false; 370 371 if (c < 0x0591 || c == 0x05BE) // U+0591 through U+05CF excluding U+05BE Hebrew combining marks, Hebrew punctuation Paseq, Sof Pasuq and Nun Hafukha 372 continue; 373 if (c <= 0x05CF) 374 return false; 375 376 if (c < 0x0600) // U+0600 through U+1059 Arabic, Syriac, Thaana, Devanagari, Bengali, Gurmukhi, Gujarati, Oriya, Tamil, Telugu, Kannada, Malayalam, Sinhala, Thai, Lao, Tibetan, Myanmar 377 continue; 378 if (c <= 0x1059) 379 return false; 380 381 if (c < 0x1100) // U+1100 through U+11FF Hangul Jamo (only Ancient Korean should be left here if you precompose; Modern Korean will be precomposed as a result of step A) 382 continue; 383 if (c <= 0x11FF) 384 return false; 385 386 if (c < 0x1780) // U+1780 through U+18AF Khmer, Mongolian 387 continue; 388 if (c <= 0x18AF) 389 return false; 390 391 if (c < 0x1900) // U+1900 through U+194F Limbu (Unicode 4.0) 392 continue; 393 if (c <= 0x194F) 394 return false; 395 396 if (c < 0x20D0) // U+20D0 through U+20FF Combining marks for symbols 397 continue; 398 if (c <= 0x20FF) 399 return false; 400 401 if (c < 0xFE20) // U+FE20 through U+FE2F Combining half marks 402 continue; 403 if (c <= 0xFE2F) 404 return false; 405 } 406 407 return true; 408 409} 410 411void Font::drawSimpleText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, int from, int to) const 412{ 413 // This glyph buffer holds our glyphs+advances+font data for each glyph. 414 GlyphBuffer glyphBuffer; 415 416 float startX = point.x(); 417 WidthIterator it(this, run); 418 it.advance(from); 419 float beforeWidth = it.m_runWidthSoFar; 420#ifdef ANDROID_GLYPHBUFFER_HAS_ADJUSTED_WIDTHS 421 bool adjustedWidths = 422#endif 423 it.advance(to, &glyphBuffer); 424 425 // We couldn't generate any glyphs for the run. Give up. 426 if (glyphBuffer.isEmpty()) 427 return; 428 429 float afterWidth = it.m_runWidthSoFar; 430 431 if (run.rtl()) { 432 float finalRoundingWidth = it.m_finalRoundingWidth; 433 it.advance(run.length()); 434 startX += finalRoundingWidth + it.m_runWidthSoFar - afterWidth; 435#ifdef ANDROID_GLYPHBUFFER_HAS_ADJUSTED_WIDTHS 436 adjustedWidths = true; // give up on simple/fast case 437#endif 438 } else 439 startX += beforeWidth; 440 441 // Swap the order of the glyphs if right-to-left. 442 if (run.rtl()) 443 for (int i = 0, end = glyphBuffer.size() - 1; i < glyphBuffer.size() / 2; ++i, --end) 444 glyphBuffer.swap(i, end); 445 446#ifdef ANDROID_GLYPHBUFFER_HAS_ADJUSTED_WIDTHS 447 // mark the GlyphBuffer as having adjusted widths or not 448 // used by drawGlyph as an optimization hint 449 glyphBuffer.setHasAdjustedWidths(adjustedWidths); 450#endif 451 // Calculate the starting point of the glyphs to be displayed by adding 452 // all the advances up to the first glyph. 453 FloatPoint startPoint(startX, point.y()); 454 drawGlyphBuffer(context, glyphBuffer, run, startPoint); 455} 456 457void Font::drawGlyphBuffer(GraphicsContext* context, const GlyphBuffer& glyphBuffer, 458 const TextRun& run, const FloatPoint& point) const 459{ 460 // Draw each contiguous run of glyphs that use the same font data. 461 const SimpleFontData* fontData = glyphBuffer.fontDataAt(0); 462 FloatSize offset = glyphBuffer.offsetAt(0); 463 FloatPoint startPoint(point); 464 float nextX = startPoint.x(); 465 int lastFrom = 0; 466 int nextGlyph = 0; 467 while (nextGlyph < glyphBuffer.size()) { 468 const SimpleFontData* nextFontData = glyphBuffer.fontDataAt(nextGlyph); 469 FloatSize nextOffset = glyphBuffer.offsetAt(nextGlyph); 470 if (nextFontData != fontData || nextOffset != offset) { 471 drawGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint); 472 473 lastFrom = nextGlyph; 474 fontData = nextFontData; 475 offset = nextOffset; 476 startPoint.setX(nextX); 477 } 478 nextX += glyphBuffer.advanceAt(nextGlyph); 479 nextGlyph++; 480 } 481 482 drawGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint); 483} 484 485void Font::drawText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, int from, int to) const 486{ 487 // Don't draw anything while we are using custom fonts that are in the process of loading. 488 if (m_fontList && m_fontList->loadingCustomFonts()) 489 return; 490 491 to = (to == -1 ? run.length() : to); 492 493#if ENABLE(SVG_FONTS) 494 if (primaryFont()->isSVGFont()) { 495 drawTextUsingSVGFont(context, run, point, from, to); 496 return; 497 } 498#endif 499 500 if (canUseGlyphCache(run)) 501 drawSimpleText(context, run, point, from, to); 502 else 503 drawComplexText(context, run, point, from, to); 504} 505 506float Font::floatWidth(const TextRun& run) const 507{ 508#if ENABLE(SVG_FONTS) 509 if (primaryFont()->isSVGFont()) 510 return floatWidthUsingSVGFont(run); 511#endif 512 513 if (canUseGlyphCache(run)) 514 return floatWidthForSimpleText(run, 0); 515 return floatWidthForComplexText(run); 516} 517 518float Font::floatWidth(const TextRun& run, int extraCharsAvailable, int& charsConsumed, String& glyphName) const 519{ 520#if ENABLE(SVG_FONTS) 521 if (primaryFont()->isSVGFont()) 522 return floatWidthUsingSVGFont(run, extraCharsAvailable, charsConsumed, glyphName); 523#endif 524 525 charsConsumed = run.length(); 526 glyphName = ""; 527 if (canUseGlyphCache(run)) 528 return floatWidthForSimpleText(run, 0); 529 return floatWidthForComplexText(run); 530} 531 532float Font::floatWidthForSimpleText(const TextRun& run, GlyphBuffer* glyphBuffer) const 533{ 534 WidthIterator it(this, run); 535 it.advance(run.length(), glyphBuffer); 536 return it.m_runWidthSoFar; 537} 538 539FloatRect Font::selectionRectForText(const TextRun& run, const IntPoint& point, int h, int from, int to) const 540{ 541#if ENABLE(SVG_FONTS) 542 if (primaryFont()->isSVGFont()) 543 return selectionRectForTextUsingSVGFont(run, point, h, from, to); 544#endif 545 546 to = (to == -1 ? run.length() : to); 547 if (canUseGlyphCache(run)) 548 return selectionRectForSimpleText(run, point, h, from, to); 549 return selectionRectForComplexText(run, point, h, from, to); 550} 551 552FloatRect Font::selectionRectForSimpleText(const TextRun& run, const IntPoint& point, int h, int from, int to) const 553{ 554 WidthIterator it(this, run); 555 it.advance(from); 556 float beforeWidth = it.m_runWidthSoFar; 557 it.advance(to); 558 float afterWidth = it.m_runWidthSoFar; 559 560 // Using roundf() rather than ceilf() for the right edge as a compromise to ensure correct caret positioning 561 if (run.rtl()) { 562 it.advance(run.length()); 563 float totalWidth = it.m_runWidthSoFar; 564 return FloatRect(point.x() + floorf(totalWidth - afterWidth), point.y(), roundf(totalWidth - beforeWidth) - floorf(totalWidth - afterWidth), h); 565 } else { 566 return FloatRect(point.x() + floorf(beforeWidth), point.y(), roundf(afterWidth) - floorf(beforeWidth), h); 567 } 568} 569 570int Font::offsetForPosition(const TextRun& run, int x, bool includePartialGlyphs) const 571{ 572#if ENABLE(SVG_FONTS) 573 if (primaryFont()->isSVGFont()) 574 return offsetForPositionForTextUsingSVGFont(run, x, includePartialGlyphs); 575#endif 576 577 if (canUseGlyphCache(run)) 578 return offsetForPositionForSimpleText(run, x, includePartialGlyphs); 579 return offsetForPositionForComplexText(run, x, includePartialGlyphs); 580} 581 582int Font::offsetForPositionForSimpleText(const TextRun& run, int x, bool includePartialGlyphs) const 583{ 584 float delta = (float)x; 585 586 WidthIterator it(this, run); 587 GlyphBuffer localGlyphBuffer; 588 unsigned offset; 589 if (run.rtl()) { 590 delta -= floatWidthForSimpleText(run, 0); 591 while (1) { 592 offset = it.m_currentCharacter; 593 float w; 594 if (!it.advanceOneCharacter(w, &localGlyphBuffer)) 595 break; 596 delta += w; 597 if (includePartialGlyphs) { 598 if (delta - w / 2 >= 0) 599 break; 600 } else { 601 if (delta >= 0) 602 break; 603 } 604 } 605 } else { 606 while (1) { 607 offset = it.m_currentCharacter; 608 float w; 609 if (!it.advanceOneCharacter(w, &localGlyphBuffer)) 610 break; 611 delta -= w; 612 if (includePartialGlyphs) { 613 if (delta + w / 2 <= 0) 614 break; 615 } else { 616 if (delta <= 0) 617 break; 618 } 619 } 620 } 621 622 return offset; 623} 624 625#if ENABLE(SVG_FONTS) 626bool Font::isSVGFont() const 627{ 628 return primaryFont()->isSVGFont(); 629} 630#endif 631 632FontSelector* Font::fontSelector() const 633{ 634 return m_fontList ? m_fontList->fontSelector() : 0; 635} 636 637} 638