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 "core/platform/graphics/Font.h" 25 26 #include "core/platform/graphics/FloatRect.h" 27 #include "core/platform/graphics/FontCache.h" 28 #include "core/platform/graphics/FontFallbackList.h" 29 #include "core/platform/graphics/GlyphBuffer.h" 30 #include "core/platform/graphics/GlyphPageTreeNode.h" 31 #include "core/platform/graphics/SimpleFontData.h" 32 #include "core/platform/graphics/TextRun.h" 33 #include "core/platform/graphics/WidthIterator.h" 34 #include "wtf/MainThread.h" 35 #include "wtf/MathExtras.h" 36 #include "wtf/unicode/CharacterNames.h" 37 #include "wtf/unicode/Unicode.h" 38 39 using namespace WTF; 40 using namespace Unicode; 41 using namespace std; 42 43 namespace WebCore { 44 45 static inline bool isInRange(UChar32 character, UChar32 lowerBound, UChar32 upperBound) 46 { 47 return character >= lowerBound && character <= upperBound; 48 } 49 50 static bool shouldIgnoreRotation(UChar32 character) 51 { 52 if (character == 0x000A7 || character == 0x000A9 || character == 0x000AE) 53 return true; 54 55 if (character == 0x000B6 || character == 0x000BC || character == 0x000BD || character == 0x000BE) 56 return true; 57 58 if (isInRange(character, 0x002E5, 0x002EB)) 59 return true; 60 61 if (isInRange(character, 0x01100, 0x011FF) || isInRange(character, 0x01401, 0x0167F) || isInRange(character, 0x01800, 0x018FF)) 62 return true; 63 64 if (character == 0x02016 || character == 0x02018 || character == 0x02019 || character == 0x02020 || character == 0x02021 65 || character == 0x2030 || character == 0x02031) 66 return true; 67 68 if (isInRange(character, 0x0203B, 0x0203D) || character == 0x02042 || character == 0x02044 || character == 0x02047 69 || character == 0x02048 || character == 0x02049 || character == 0x2051) 70 return true; 71 72 if (isInRange(character, 0x02065, 0x02069) || isInRange(character, 0x020DD, 0x020E0) 73 || isInRange(character, 0x020E2, 0x020E4) || isInRange(character, 0x02100, 0x02117) 74 || isInRange(character, 0x02119, 0x02131) || isInRange(character, 0x02133, 0x0213F)) 75 return true; 76 77 if (isInRange(character, 0x02145, 0x0214A) || character == 0x0214C || character == 0x0214D 78 || isInRange(character, 0x0214F, 0x0218F)) 79 return true; 80 81 if (isInRange(character, 0x02300, 0x02307) || isInRange(character, 0x0230C, 0x0231F) 82 || isInRange(character, 0x02322, 0x0232B) || isInRange(character, 0x0237D, 0x0239A) 83 || isInRange(character, 0x023B4, 0x023B6) || isInRange(character, 0x023BA, 0x023CF) 84 || isInRange(character, 0x023D1, 0x023DB) || isInRange(character, 0x023E2, 0x024FF)) 85 return true; 86 87 if (isInRange(character, 0x025A0, 0x02619) || isInRange(character, 0x02620, 0x02767) 88 || isInRange(character, 0x02776, 0x02793) || isInRange(character, 0x02B12, 0x02B2F) 89 || isInRange(character, 0x02B4D, 0x02BFF) || isInRange(character, 0x02E80, 0x03007)) 90 return true; 91 92 if (character == 0x03012 || character == 0x03013 || isInRange(character, 0x03020, 0x0302F) 93 || isInRange(character, 0x03031, 0x0309F) || isInRange(character, 0x030A1, 0x030FB) 94 || isInRange(character, 0x030FD, 0x0A4CF)) 95 return true; 96 97 if (isInRange(character, 0x0A840, 0x0A87F) || isInRange(character, 0x0A960, 0x0A97F) 98 || isInRange(character, 0x0AC00, 0x0D7FF) || isInRange(character, 0x0E000, 0x0FAFF)) 99 return true; 100 101 if (isInRange(character, 0x0FE10, 0x0FE1F) || isInRange(character, 0x0FE30, 0x0FE48) 102 || isInRange(character, 0x0FE50, 0x0FE57) || isInRange(character, 0x0FE5F, 0x0FE62) 103 || isInRange(character, 0x0FE67, 0x0FE6F)) 104 return true; 105 106 if (isInRange(character, 0x0FF01, 0x0FF07) || isInRange(character, 0x0FF0A, 0x0FF0C) 107 || isInRange(character, 0x0FF0E, 0x0FF19) ||isInRange (character, 0x0FF1F, 0x0FF3A)) 108 return true; 109 110 if (character == 0x0FF3C || character == 0x0FF3E) 111 return true; 112 113 if (isInRange(character, 0x0FF40, 0x0FF5A) || isInRange(character, 0x0FFE0, 0x0FFE2) 114 || isInRange(character, 0x0FFE4, 0x0FFE7) || isInRange(character, 0x0FFF0, 0x0FFF8) 115 || character == 0x0FFFD) 116 return true; 117 118 if (isInRange(character, 0x13000, 0x1342F) || isInRange(character, 0x1B000, 0x1B0FF) 119 || isInRange(character, 0x1D000, 0x1D1FF) || isInRange(character, 0x1D300, 0x1D37F) 120 || isInRange(character, 0x1F000, 0x1F64F) || isInRange(character, 0x1F680, 0x1F77F)) 121 return true; 122 123 if (isInRange(character, 0x20000, 0x2FFFD) || isInRange(character, 0x30000, 0x3FFFD)) 124 return true; 125 126 return false; 127 } 128 129 static inline std::pair<GlyphData, GlyphPage*> glyphDataAndPageForNonCJKCharacterWithGlyphOrientation(UChar32 character, NonCJKGlyphOrientation orientation, GlyphData& data, GlyphPage* page, unsigned pageNumber) 130 { 131 if (orientation == NonCJKGlyphOrientationUpright || shouldIgnoreRotation(character)) { 132 RefPtr<SimpleFontData> uprightFontData = data.fontData->uprightOrientationFontData(); 133 GlyphPageTreeNode* uprightNode = GlyphPageTreeNode::getRootChild(uprightFontData.get(), pageNumber); 134 GlyphPage* uprightPage = uprightNode->page(); 135 if (uprightPage) { 136 GlyphData uprightData = uprightPage->glyphDataForCharacter(character); 137 // If the glyphs are the same, then we know we can just use the horizontal glyph rotated vertically to be upright. 138 if (data.glyph == uprightData.glyph) 139 return make_pair(data, page); 140 // The glyphs are distinct, meaning that the font has a vertical-right glyph baked into it. We can't use that 141 // glyph, so we fall back to the upright data and use the horizontal glyph. 142 if (uprightData.fontData) 143 return make_pair(uprightData, uprightPage); 144 } 145 } else if (orientation == NonCJKGlyphOrientationVerticalRight) { 146 RefPtr<SimpleFontData> verticalRightFontData = data.fontData->verticalRightOrientationFontData(); 147 GlyphPageTreeNode* verticalRightNode = GlyphPageTreeNode::getRootChild(verticalRightFontData.get(), pageNumber); 148 GlyphPage* verticalRightPage = verticalRightNode->page(); 149 if (verticalRightPage) { 150 GlyphData verticalRightData = verticalRightPage->glyphDataForCharacter(character); 151 // If the glyphs are distinct, we will make the assumption that the font has a vertical-right glyph baked 152 // into it. 153 if (data.glyph != verticalRightData.glyph) 154 return make_pair(data, page); 155 // The glyphs are identical, meaning that we should just use the horizontal glyph. 156 if (verticalRightData.fontData) 157 return make_pair(verticalRightData, verticalRightPage); 158 } 159 } 160 return make_pair(data, page); 161 } 162 163 std::pair<GlyphData, GlyphPage*> Font::glyphDataAndPageForCharacter(UChar32 c, bool mirror, FontDataVariant variant) const 164 { 165 ASSERT(isMainThread()); 166 167 if (variant == AutoVariant) { 168 if (m_fontDescription.smallCaps() && !primaryFont()->isSVGFont()) { 169 UChar32 upperC = toUpper(c); 170 if (upperC != c) { 171 c = upperC; 172 variant = SmallCapsVariant; 173 } else 174 variant = NormalVariant; 175 } else 176 variant = NormalVariant; 177 } 178 179 if (mirror) 180 c = mirroredChar(c); 181 182 unsigned pageNumber = (c / GlyphPage::size); 183 184 GlyphPageTreeNode* node = pageNumber ? m_fontFallbackList->m_pages.get(pageNumber) : m_fontFallbackList->m_pageZero; 185 if (!node) { 186 node = GlyphPageTreeNode::getRootChild(fontDataAt(0), pageNumber); 187 if (pageNumber) 188 m_fontFallbackList->m_pages.set(pageNumber, node); 189 else 190 m_fontFallbackList->m_pageZero = node; 191 } 192 193 GlyphPage* page = 0; 194 if (variant == NormalVariant) { 195 // Fastest loop, for the common case (normal variant). 196 while (true) { 197 page = node->page(); 198 if (page) { 199 GlyphData data = page->glyphDataForCharacter(c); 200 if (data.fontData && (data.fontData->platformData().orientation() == Horizontal || data.fontData->isTextOrientationFallback())) 201 return make_pair(data, page); 202 203 if (data.fontData) { 204 if (isCJKIdeographOrSymbol(c)) { 205 if (!data.fontData->hasVerticalGlyphs()) { 206 // Use the broken ideograph font data. The broken ideograph font will use the horizontal width of glyphs 207 // to make sure you get a square (even for broken glyphs like symbols used for punctuation). 208 variant = BrokenIdeographVariant; 209 break; 210 } 211 } else 212 return glyphDataAndPageForNonCJKCharacterWithGlyphOrientation(c, m_fontDescription.nonCJKGlyphOrientation(), data, page, pageNumber); 213 214 return make_pair(data, page); 215 } 216 217 if (node->isSystemFallback()) 218 break; 219 } 220 221 // Proceed with the fallback list. 222 node = node->getChild(fontDataAt(node->level()), pageNumber); 223 if (pageNumber) 224 m_fontFallbackList->m_pages.set(pageNumber, node); 225 else 226 m_fontFallbackList->m_pageZero = node; 227 } 228 } 229 if (variant != NormalVariant) { 230 while (true) { 231 page = node->page(); 232 if (page) { 233 GlyphData data = page->glyphDataForCharacter(c); 234 if (data.fontData) { 235 // The variantFontData function should not normally return 0. 236 // But if it does, we will just render the capital letter big. 237 RefPtr<SimpleFontData> variantFontData = data.fontData->variantFontData(m_fontDescription, variant); 238 if (!variantFontData) 239 return make_pair(data, page); 240 241 GlyphPageTreeNode* variantNode = GlyphPageTreeNode::getRootChild(variantFontData.get(), pageNumber); 242 GlyphPage* variantPage = variantNode->page(); 243 if (variantPage) { 244 GlyphData data = variantPage->glyphDataForCharacter(c); 245 if (data.fontData) 246 return make_pair(data, variantPage); 247 } 248 249 // Do not attempt system fallback off the variantFontData. This is the very unlikely case that 250 // a font has the lowercase character but the small caps font does not have its uppercase version. 251 return make_pair(variantFontData->missingGlyphData(), page); 252 } 253 254 if (node->isSystemFallback()) 255 break; 256 } 257 258 // Proceed with the fallback list. 259 node = node->getChild(fontDataAt(node->level()), pageNumber); 260 if (pageNumber) 261 m_fontFallbackList->m_pages.set(pageNumber, node); 262 else 263 m_fontFallbackList->m_pageZero = node; 264 } 265 } 266 267 ASSERT(page); 268 ASSERT(node->isSystemFallback()); 269 270 // System fallback is character-dependent. When we get here, we 271 // know that the character in question isn't in the system fallback 272 // font's glyph page. Try to lazily create it here. 273 274 // FIXME: Unclear if this should normalizeSpaces above 0xFFFF. 275 // Doing so changes fast/text/international/plane2-diffs.html 276 UChar32 characterToRender = c; 277 if (characterToRender <= 0xFFFF) 278 characterToRender = Font::normalizeSpaces(characterToRender); 279 RefPtr<SimpleFontData> characterFontData = fontCache()->getFontDataForCharacter(*this, characterToRender); 280 if (characterFontData) { 281 if (characterFontData->platformData().orientation() == Vertical && !characterFontData->hasVerticalGlyphs() && isCJKIdeographOrSymbol(c)) 282 variant = BrokenIdeographVariant; 283 if (variant != NormalVariant) 284 characterFontData = characterFontData->variantFontData(m_fontDescription, variant); 285 } 286 if (characterFontData) { 287 // Got the fallback glyph and font. 288 GlyphPage* fallbackPage = GlyphPageTreeNode::getRootChild(characterFontData.get(), pageNumber)->page(); 289 GlyphData data = fallbackPage && fallbackPage->fontDataForCharacter(c) ? fallbackPage->glyphDataForCharacter(c) : characterFontData->missingGlyphData(); 290 // Cache it so we don't have to do system fallback again next time. 291 if (variant == NormalVariant) { 292 page->setGlyphDataForCharacter(c, data.glyph, data.fontData); 293 data.fontData->setMaxGlyphPageTreeLevel(max(data.fontData->maxGlyphPageTreeLevel(), node->level())); 294 if (!isCJKIdeographOrSymbol(c) && data.fontData->platformData().orientation() != Horizontal && !data.fontData->isTextOrientationFallback()) 295 return glyphDataAndPageForNonCJKCharacterWithGlyphOrientation(c, m_fontDescription.nonCJKGlyphOrientation(), data, fallbackPage, pageNumber); 296 } 297 return make_pair(data, page); 298 } 299 300 // Even system fallback can fail; use the missing glyph in that case. 301 // FIXME: It would be nicer to use the missing glyph from the last resort font instead. 302 GlyphData data = primaryFont()->missingGlyphData(); 303 if (variant == NormalVariant) { 304 page->setGlyphDataForCharacter(c, data.glyph, data.fontData); 305 data.fontData->setMaxGlyphPageTreeLevel(max(data.fontData->maxGlyphPageTreeLevel(), node->level())); 306 } 307 return make_pair(data, page); 308 } 309 310 bool Font::primaryFontHasGlyphForCharacter(UChar32 character) const 311 { 312 unsigned pageNumber = (character / GlyphPage::size); 313 314 GlyphPageTreeNode* node = GlyphPageTreeNode::getRootChild(primaryFont(), pageNumber); 315 GlyphPage* page = node->page(); 316 317 return page && page->fontDataForCharacter(character); 318 } 319 320 // FIXME: This function may not work if the emphasis mark uses a complex script, but none of the 321 // standard emphasis marks do so. 322 bool Font::getEmphasisMarkGlyphData(const AtomicString& mark, GlyphData& glyphData) const 323 { 324 if (mark.isEmpty()) 325 return false; 326 327 UChar32 character = mark[0]; 328 329 if (U16_IS_SURROGATE(character)) { 330 if (!U16_IS_SURROGATE_LEAD(character)) 331 return false; 332 333 if (mark.length() < 2) 334 return false; 335 336 UChar low = mark[1]; 337 if (!U16_IS_TRAIL(low)) 338 return false; 339 340 character = U16_GET_SUPPLEMENTARY(character, low); 341 } 342 343 glyphData = glyphDataForCharacter(character, false, EmphasisMarkVariant); 344 return true; 345 } 346 347 int Font::emphasisMarkAscent(const AtomicString& mark) const 348 { 349 FontCachePurgePreventer purgePreventer; 350 351 GlyphData markGlyphData; 352 if (!getEmphasisMarkGlyphData(mark, markGlyphData)) 353 return 0; 354 355 const SimpleFontData* markFontData = markGlyphData.fontData; 356 ASSERT(markFontData); 357 if (!markFontData) 358 return 0; 359 360 return markFontData->fontMetrics().ascent(); 361 } 362 363 int Font::emphasisMarkDescent(const AtomicString& mark) const 364 { 365 FontCachePurgePreventer purgePreventer; 366 367 GlyphData markGlyphData; 368 if (!getEmphasisMarkGlyphData(mark, markGlyphData)) 369 return 0; 370 371 const SimpleFontData* markFontData = markGlyphData.fontData; 372 ASSERT(markFontData); 373 if (!markFontData) 374 return 0; 375 376 return markFontData->fontMetrics().descent(); 377 } 378 379 int Font::emphasisMarkHeight(const AtomicString& mark) const 380 { 381 FontCachePurgePreventer purgePreventer; 382 383 GlyphData markGlyphData; 384 if (!getEmphasisMarkGlyphData(mark, markGlyphData)) 385 return 0; 386 387 const SimpleFontData* markFontData = markGlyphData.fontData; 388 ASSERT(markFontData); 389 if (!markFontData) 390 return 0; 391 392 return markFontData->fontMetrics().height(); 393 } 394 395 float Font::getGlyphsAndAdvancesForSimpleText(const TextRun& run, int from, int to, GlyphBuffer& glyphBuffer, ForTextEmphasisOrNot forTextEmphasis) const 396 { 397 float initialAdvance; 398 399 WidthIterator it(this, run, 0, false, forTextEmphasis); 400 // FIXME: Using separate glyph buffers for the prefix and the suffix is incorrect when kerning or 401 // ligatures are enabled. 402 GlyphBuffer localGlyphBuffer; 403 it.advance(from, &localGlyphBuffer); 404 float beforeWidth = it.m_runWidthSoFar; 405 it.advance(to, &glyphBuffer); 406 407 if (glyphBuffer.isEmpty()) 408 return 0; 409 410 float afterWidth = it.m_runWidthSoFar; 411 412 if (run.rtl()) { 413 float finalRoundingWidth = it.m_finalRoundingWidth; 414 it.advance(run.length(), &localGlyphBuffer); 415 initialAdvance = finalRoundingWidth + it.m_runWidthSoFar - afterWidth; 416 } else 417 initialAdvance = beforeWidth; 418 419 if (run.rtl()) 420 glyphBuffer.reverse(0, glyphBuffer.size()); 421 422 return initialAdvance; 423 } 424 425 void Font::drawSimpleText(GraphicsContext* context, const TextRunPaintInfo& runInfo, const FloatPoint& point) const 426 { 427 // This glyph buffer holds our glyphs+advances+font data for each glyph. 428 GlyphBuffer glyphBuffer; 429 430 float startX = point.x() + getGlyphsAndAdvancesForSimpleText(runInfo.run, runInfo.from, runInfo.to, glyphBuffer); 431 432 if (glyphBuffer.isEmpty()) 433 return; 434 435 FloatPoint startPoint(startX, point.y()); 436 drawGlyphBuffer(context, runInfo, glyphBuffer, startPoint); 437 } 438 439 void Font::drawEmphasisMarksForSimpleText(GraphicsContext* context, const TextRunPaintInfo& runInfo, const AtomicString& mark, const FloatPoint& point) const 440 { 441 GlyphBuffer glyphBuffer; 442 float initialAdvance = getGlyphsAndAdvancesForSimpleText(runInfo.run, runInfo.from, runInfo.to, glyphBuffer, ForTextEmphasis); 443 444 if (glyphBuffer.isEmpty()) 445 return; 446 447 drawEmphasisMarks(context, runInfo, glyphBuffer, mark, FloatPoint(point.x() + initialAdvance, point.y())); 448 } 449 450 void Font::drawGlyphBuffer(GraphicsContext* context, const TextRunPaintInfo& runInfo, const GlyphBuffer& glyphBuffer, const FloatPoint& point) const 451 { 452 // Draw each contiguous run of glyphs that use the same font data. 453 const SimpleFontData* fontData = glyphBuffer.fontDataAt(0); 454 FloatPoint startPoint(point); 455 float nextX = startPoint.x() + glyphBuffer.advanceAt(0); 456 int lastFrom = 0; 457 int nextGlyph = 1; 458 #if ENABLE(SVG_FONTS) 459 TextRun::RenderingContext* renderingContext = runInfo.run.renderingContext(); 460 #endif 461 while (nextGlyph < glyphBuffer.size()) { 462 const SimpleFontData* nextFontData = glyphBuffer.fontDataAt(nextGlyph); 463 464 if (nextFontData != fontData) { 465 #if ENABLE(SVG_FONTS) 466 if (renderingContext && fontData->isSVGFont()) 467 renderingContext->drawSVGGlyphs(context, runInfo.run, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint); 468 else 469 #endif 470 drawGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint, runInfo.bounds); 471 472 lastFrom = nextGlyph; 473 fontData = nextFontData; 474 startPoint.setX(nextX); 475 } 476 nextX += glyphBuffer.advanceAt(nextGlyph); 477 nextGlyph++; 478 } 479 480 #if ENABLE(SVG_FONTS) 481 if (renderingContext && fontData->isSVGFont()) 482 renderingContext->drawSVGGlyphs(context, runInfo.run, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint); 483 else 484 #endif 485 drawGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint, runInfo.bounds); 486 } 487 488 inline static float offsetToMiddleOfGlyph(const SimpleFontData* fontData, Glyph glyph) 489 { 490 if (fontData->platformData().orientation() == Horizontal) { 491 FloatRect bounds = fontData->boundsForGlyph(glyph); 492 return bounds.x() + bounds.width() / 2; 493 } 494 // FIXME: Use glyph bounds once they make sense for vertical fonts. 495 return fontData->widthForGlyph(glyph) / 2; 496 } 497 498 inline static float offsetToMiddleOfGlyphAtIndex(const GlyphBuffer& glyphBuffer, size_t i) 499 { 500 return offsetToMiddleOfGlyph(glyphBuffer.fontDataAt(i), glyphBuffer.glyphAt(i)); 501 } 502 503 void Font::drawEmphasisMarks(GraphicsContext* context, const TextRunPaintInfo& runInfo, const GlyphBuffer& glyphBuffer, const AtomicString& mark, const FloatPoint& point) const 504 { 505 FontCachePurgePreventer purgePreventer; 506 507 GlyphData markGlyphData; 508 if (!getEmphasisMarkGlyphData(mark, markGlyphData)) 509 return; 510 511 const SimpleFontData* markFontData = markGlyphData.fontData; 512 ASSERT(markFontData); 513 if (!markFontData) 514 return; 515 516 Glyph markGlyph = markGlyphData.glyph; 517 Glyph spaceGlyph = markFontData->spaceGlyph(); 518 519 float middleOfLastGlyph = offsetToMiddleOfGlyphAtIndex(glyphBuffer, 0); 520 FloatPoint startPoint(point.x() + middleOfLastGlyph - offsetToMiddleOfGlyph(markFontData, markGlyph), point.y()); 521 522 GlyphBuffer markBuffer; 523 for (int i = 0; i + 1 < glyphBuffer.size(); ++i) { 524 float middleOfNextGlyph = offsetToMiddleOfGlyphAtIndex(glyphBuffer, i + 1); 525 float advance = glyphBuffer.advanceAt(i) - middleOfLastGlyph + middleOfNextGlyph; 526 markBuffer.add(glyphBuffer.glyphAt(i) ? markGlyph : spaceGlyph, markFontData, advance); 527 middleOfLastGlyph = middleOfNextGlyph; 528 } 529 markBuffer.add(glyphBuffer.glyphAt(glyphBuffer.size() - 1) ? markGlyph : spaceGlyph, markFontData, 0); 530 531 drawGlyphBuffer(context, runInfo, markBuffer, startPoint); 532 } 533 534 float Font::floatWidthForSimpleText(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const 535 { 536 WidthIterator it(this, run, fallbackFonts, glyphOverflow); 537 GlyphBuffer glyphBuffer; 538 it.advance(run.length(), (typesettingFeatures() & (Kerning | Ligatures)) ? &glyphBuffer : 0); 539 540 if (glyphOverflow) { 541 glyphOverflow->top = max<int>(glyphOverflow->top, ceilf(-it.minGlyphBoundingBoxY()) - (glyphOverflow->computeBounds ? 0 : fontMetrics().ascent())); 542 glyphOverflow->bottom = max<int>(glyphOverflow->bottom, ceilf(it.maxGlyphBoundingBoxY()) - (glyphOverflow->computeBounds ? 0 : fontMetrics().descent())); 543 glyphOverflow->left = ceilf(it.firstGlyphOverflow()); 544 glyphOverflow->right = ceilf(it.lastGlyphOverflow()); 545 } 546 547 return it.m_runWidthSoFar; 548 } 549 550 FloatRect Font::selectionRectForSimpleText(const TextRun& run, const FloatPoint& point, int h, int from, int to) const 551 { 552 GlyphBuffer glyphBuffer; 553 WidthIterator it(this, run); 554 it.advance(from, &glyphBuffer); 555 float beforeWidth = it.m_runWidthSoFar; 556 it.advance(to, &glyphBuffer); 557 float afterWidth = it.m_runWidthSoFar; 558 559 // Using roundf() rather than ceilf() for the right edge as a compromise to ensure correct caret positioning. 560 if (run.rtl()) { 561 it.advance(run.length(), &glyphBuffer); 562 float totalWidth = it.m_runWidthSoFar; 563 return FloatRect(floorf(point.x() + totalWidth - afterWidth), point.y(), roundf(point.x() + totalWidth - beforeWidth) - floorf(point.x() + totalWidth - afterWidth), h); 564 } 565 566 return FloatRect(floorf(point.x() + beforeWidth), point.y(), roundf(point.x() + afterWidth) - floorf(point.x() + beforeWidth), h); 567 } 568 569 int Font::offsetForPositionForSimpleText(const TextRun& run, float x, bool includePartialGlyphs) const 570 { 571 float delta = x; 572 573 WidthIterator it(this, run); 574 GlyphBuffer localGlyphBuffer; 575 unsigned offset; 576 if (run.rtl()) { 577 delta -= floatWidthForSimpleText(run); 578 while (1) { 579 offset = it.m_currentCharacter; 580 float w; 581 if (!it.advanceOneCharacter(w, localGlyphBuffer)) 582 break; 583 delta += w; 584 if (includePartialGlyphs) { 585 if (delta - w / 2 >= 0) 586 break; 587 } else { 588 if (delta >= 0) 589 break; 590 } 591 } 592 } else { 593 while (1) { 594 offset = it.m_currentCharacter; 595 float w; 596 if (!it.advanceOneCharacter(w, localGlyphBuffer)) 597 break; 598 delta -= w; 599 if (includePartialGlyphs) { 600 if (delta + w / 2 <= 0) 601 break; 602 } else { 603 if (delta <= 0) 604 break; 605 } 606 } 607 } 608 609 return offset; 610 } 611 612 } 613