1 /* 2 * Copyright 2009, The Android Open Source Project 3 * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY 15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27 #include "config.h" 28 29 #define LOG_TAG "FontAndroid" 30 31 #include "AndroidLog.h" 32 #include "EmojiFont.h" 33 #include "GraphicsOperation.h" 34 #include "Font.h" 35 #include "FontData.h" 36 #include "FontFallbackList.h" 37 #include "GraphicsContext.h" 38 #include "GlyphBuffer.h" 39 #include "IntRect.h" 40 #include "NotImplemented.h" 41 #include "PlatformGraphicsContext.h" 42 #include "SkCanvas.h" 43 #include "SkColorFilter.h" 44 #include "SkLayerDrawLooper.h" 45 #include "SkPaint.h" 46 #include "SkTemplates.h" 47 #include "SkTypeface.h" 48 #include "SkUtils.h" 49 #include "TextRun.h" 50 #include "SkTypeface_android.h" 51 52 #ifdef SUPPORT_COMPLEX_SCRIPTS 53 #include "HarfbuzzSkia.h" 54 #include <unicode/normlzr.h> 55 #include <unicode/uchar.h> 56 #include <wtf/OwnArrayPtr.h> 57 #include <wtf/OwnPtr.h> 58 #include <wtf/PassOwnArrayPtr.h> 59 #include <wtf/PassOwnPtr.h> 60 #include <wtf/unicode/CharacterNames.h> 61 #include <wtf/unicode/Unicode.h> 62 #endif 63 64 using namespace android; 65 66 namespace WebCore { 67 68 typedef std::pair<int, float> FallbackFontKey; 69 70 typedef HashMap<FallbackFontKey, FontPlatformData*> FallbackHash; 71 72 static void updateForFont(SkPaint* paint, const SimpleFontData* font) { 73 font->platformData().setupPaint(paint); 74 paint->setTextEncoding(SkPaint::kGlyphID_TextEncoding); 75 } 76 77 static SkPaint* setupFill(SkPaint* paint, GraphicsContext* gc, 78 const SimpleFontData* font) { 79 gc->setupFillPaint(paint); 80 updateForFont(paint, font); 81 return paint; 82 } 83 84 static SkPaint* setupStroke(SkPaint* paint, GraphicsContext* gc, 85 const SimpleFontData* font) { 86 gc->setupStrokePaint(paint); 87 updateForFont(paint, font); 88 return paint; 89 } 90 91 static bool setupForText(SkPaint* paint, GraphicsContext* gc, 92 const SimpleFontData* font) { 93 int mode = gc->textDrawingMode() & (TextModeFill | TextModeStroke); 94 if (!mode) 95 return false; 96 97 paint->setVerticalText(font->platformData().orientation() == Vertical); 98 99 FloatSize shadowOffset; 100 float shadowBlur; 101 Color shadowColor; 102 ColorSpace shadowColorSpace; 103 104 if (RenderSkinAndroid::DrawableResolution() >= RenderSkinAndroid::HighRes) 105 paint->setAutohinted(false); 106 107 bool hasShadow = gc->getShadow(shadowOffset, shadowBlur, shadowColor, shadowColorSpace); 108 bool hasBothStrokeAndFill = 109 (mode & (TextModeStroke | TextModeFill)) == (TextModeStroke | TextModeFill); 110 if (hasShadow || hasBothStrokeAndFill) { 111 SkLayerDrawLooper* looper = new SkLayerDrawLooper; 112 paint->setLooper(looper)->unref(); 113 114 // The layerDrawLooper uses at the root paint to determine the text 115 // encoding so we need to make sure it is properly configured. 116 updateForFont(paint, font); 117 118 // Specify the behavior of the looper 119 SkLayerDrawLooper::LayerInfo info; 120 info.fPaintBits = SkLayerDrawLooper::kEntirePaint_Bits; 121 info.fColorMode = SkXfermode::kSrc_Mode; 122 info.fFlagsMask = SkPaint::kAllFlags; 123 124 // The paint is only valid until the looper receives another call to 125 // addLayer(). Therefore, we must cache certain state for later use. 126 bool hasFillPaint = false; 127 bool hasStrokePaint = false; 128 SkScalar strokeWidth; 129 130 if ((mode & TextModeStroke) && gc->willStroke()) { 131 strokeWidth = setupStroke(looper->addLayer(info), gc, font)->getStrokeWidth(); 132 hasStrokePaint = true; 133 } 134 if ((mode & TextModeFill) && gc->willFill()) { 135 setupFill(looper->addLayer(info), gc, font); 136 hasFillPaint = true; 137 } 138 139 if (hasShadow) { 140 SkPaint shadowPaint; 141 SkPoint offset; 142 if (gc->setupShadowPaint(&shadowPaint, &offset)) { 143 144 // add an offset to the looper when creating a shadow layer 145 info.fOffset.set(offset.fX, offset.fY); 146 147 SkPaint* p = looper->addLayer(info); 148 *p = shadowPaint; 149 150 // Currently, only GraphicsContexts associated with the 151 // HTMLCanvasElement have shadows ignore transforms set. This 152 // allows us to distinguish between CSS and Canvas shadows which 153 // have different rendering specifications. 154 if (gc->shadowsIgnoreTransforms()) { 155 SkColorFilter* cf = SkColorFilter::CreateModeFilter(p->getColor(), 156 SkXfermode::kSrcIn_Mode); 157 p->setColorFilter(cf)->unref(); 158 } else { // in CSS 159 p->setShader(NULL); 160 } 161 162 if (hasStrokePaint && !hasFillPaint) { 163 // stroke the shadow if we have stroke but no fill 164 p->setStyle(SkPaint::kStroke_Style); 165 p->setStrokeWidth(strokeWidth); 166 } 167 updateForFont(p, font); 168 } 169 } 170 } else if (mode & TextModeFill) { 171 (void)setupFill(paint, gc, font); 172 } else if (mode & TextModeStroke) { 173 (void)setupStroke(paint, gc, font); 174 } else { 175 return false; 176 } 177 return true; 178 } 179 180 bool Font::canReturnFallbackFontsForComplexText() 181 { 182 return false; 183 } 184 185 bool Font::canExpandAroundIdeographsInComplexText() 186 { 187 return false; 188 } 189 190 void Font::drawGlyphs(GraphicsContext* gc, const SimpleFontData* font, 191 const GlyphBuffer& glyphBuffer, int from, int numGlyphs, 192 const FloatPoint& point) const 193 { 194 // compile-time assert 195 SkASSERT(sizeof(GlyphBufferGlyph) == sizeof(uint16_t)); 196 197 if (numGlyphs == 1 && glyphBuffer.glyphAt(from) == 0x3) { 198 // Webkit likes to draw end text control command for some reason 199 // Just ignore it 200 return; 201 } 202 203 SkPaint paint; 204 if (!setupForText(&paint, gc, font)) { 205 return; 206 } 207 208 SkScalar x = SkFloatToScalar(point.x()); 209 SkScalar y = SkFloatToScalar(point.y()); 210 const GlyphBufferGlyph* glyphs = glyphBuffer.glyphs(from); 211 const GlyphBufferAdvance* adv = glyphBuffer.advances(from); 212 SkAutoSTMalloc<32, SkPoint> storage(numGlyphs), storage2(numGlyphs), storage3(numGlyphs); 213 SkPoint* pos = storage.get(); 214 215 SkCanvas* canvas = gc->platformContext()->recordingCanvas(); 216 217 /* We need an array of [x,y,x,y,x,y,...], but webkit is giving us 218 point.xy + [width, height, width, height, ...], so we have to convert 219 */ 220 221 if (font->platformData().orientation() == Vertical) { 222 float yOffset = SkFloatToScalar(font->fontMetrics().floatAscent(IdeographicBaseline) - font->fontMetrics().floatAscent()); 223 gc->platformContext()->setTextOffset(FloatSize(0.0f, -yOffset)); // compensate for offset in bounds calculation 224 y += yOffset; 225 } 226 227 if (EmojiFont::IsAvailable()) { 228 // set filtering, to make scaled images look nice(r) 229 paint.setFilterBitmap(true); 230 231 SkMatrix rotator; 232 rotator.reset(); 233 if (font->platformData().orientation() == Vertical) { 234 canvas->save(); 235 canvas->rotate(-90); 236 rotator.setRotate(90); 237 } 238 239 int localIndex = 0; 240 int localCount = 0; 241 for (int i = 0; i < numGlyphs; i++) { 242 if (EmojiFont::IsEmojiGlyph(glyphs[i])) { 243 if (localCount) { 244 rotator.mapPoints(&pos[localIndex], localCount); 245 canvas->drawPosText(&glyphs[localIndex], 246 localCount * sizeof(uint16_t), 247 &pos[localIndex], paint); 248 } 249 EmojiFont::Draw(canvas, glyphs[i], x, y, paint); 250 // reset local index/count track for "real" glyphs 251 localCount = 0; 252 localIndex = i + 1; 253 } else { 254 pos[i].set(x, y); 255 localCount += 1; 256 } 257 x += SkFloatToScalar(adv[i].width()); 258 y += SkFloatToScalar(adv[i].height()); 259 } 260 261 // draw the last run of glyphs (if any) 262 if (localCount) { 263 rotator.mapPoints(&pos[localIndex], localCount); 264 canvas->drawPosText(&glyphs[localIndex], 265 localCount * sizeof(uint16_t), 266 &pos[localIndex], paint); 267 268 } 269 270 if (font->platformData().orientation() == Vertical) 271 canvas->restore(); 272 } else { 273 for (int i = 0; i < numGlyphs; i++) { 274 pos[i].set(x, y); 275 y += SkFloatToScalar(adv[i].height()); 276 x += SkFloatToScalar(adv[i].width()); 277 } 278 279 if (font->platformData().orientation() == Vertical) { 280 canvas->save(); 281 canvas->rotate(-90); 282 SkMatrix rotator; 283 rotator.reset(); 284 rotator.setRotate(90); 285 rotator.mapPoints(pos, numGlyphs); 286 } 287 canvas->drawPosText(glyphs, 288 numGlyphs * sizeof(uint16_t), pos, paint); 289 290 if (font->platformData().orientation() == Vertical) 291 canvas->restore(); 292 } 293 294 if (font->platformData().orientation() == Vertical) 295 gc->platformContext()->setTextOffset(FloatSize()); // reset to undo above 296 } 297 298 void Font::drawEmphasisMarksForComplexText(WebCore::GraphicsContext*, WebCore::TextRun const&, WTF::AtomicString const&, WebCore::FloatPoint const&, int, int) const 299 { 300 notImplemented(); 301 } 302 303 #ifndef SUPPORT_COMPLEX_SCRIPTS 304 305 FloatRect Font::selectionRectForComplexText(const TextRun& run, 306 const FloatPoint& point, int h, int, int) const 307 { 308 SkPaint paint; 309 SkScalar width, left; 310 SkPaint::FontMetrics metrics; 311 312 primaryFont()->platformData().setupPaint(&paint); 313 314 width = paint.measureText(run.characters(), run.length() << 1); 315 SkScalar spacing = paint.getFontMetrics(&metrics); 316 317 return FloatRect(point.x(), 318 point.y(), 319 roundf(SkScalarToFloat(width)), 320 roundf(SkScalarToFloat(spacing))); 321 } 322 323 void Font::drawComplexText(GraphicsContext* gc, TextRun const& run, 324 FloatPoint const& point, int, int) const 325 { 326 SkCanvas* canvas = gc->platformContext()->mCanvas; 327 SkPaint paint; 328 329 if (!setupForText(&paint, gc, primaryFont())) { 330 return; 331 } 332 333 // go to chars, instead of glyphs, which was set by setupForText() 334 paint.setTextEncoding(SkPaint::kUTF16_TextEncoding); 335 336 canvas->drawText(run.characters(), run.length() << 1, 337 SkFloatToScalar(point.x()), SkFloatToScalar(point.y()), 338 paint); 339 } 340 341 float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>*, GlyphOverflow*) const 342 { 343 SkPaint paint; 344 345 primaryFont()->platformData().setupPaint(&paint); 346 347 //printf("--------- complext measure %d chars\n", run.to() - run.from()); 348 349 SkScalar width = paint.measureText(run.characters(), run.length() << 1); 350 return SkScalarToFloat(width); 351 } 352 353 int Font::offsetForPositionForComplexText(const TextRun& run, float x, 354 bool includePartialGlyphs) const 355 { 356 SkPaint paint; 357 int count = run.length(); 358 SkAutoSTMalloc<64, SkScalar> storage(count); 359 SkScalar* widths = storage.get(); 360 361 primaryFont()->platformData().setupPaint(&paint); 362 363 count = paint.getTextWidths(run.characters(), count << 1, widths); 364 365 if (count > 0) 366 { 367 SkScalar pos = 0; 368 for (int i = 0; i < count; i++) 369 { 370 if (x < SkScalarRound(pos + SkScalarHalf(widths[i]))) 371 return i; 372 pos += widths[i]; 373 } 374 } 375 return count; 376 } 377 378 #else 379 380 // TODO Should we remove the multilayer support? 381 // If yes. remove isCanvasMultiLayered() and adjustTextRenderMode(). 382 static bool isCanvasMultiLayered(SkCanvas* canvas) 383 { 384 SkCanvas::LayerIter layerIterator(canvas, false); 385 layerIterator.next(); 386 return !layerIterator.done(); 387 } 388 389 static void adjustTextRenderMode(SkPaint* paint, bool isCanvasMultiLayered) 390 { 391 // Our layers only have a single alpha channel. This means that subpixel 392 // rendered text cannot be compositied correctly when the layer is 393 // collapsed. Therefore, subpixel text is disabled when we are drawing 394 // onto a layer. 395 if (isCanvasMultiLayered) 396 paint->setLCDRenderText(false); 397 } 398 399 // Harfbuzz uses 26.6 fixed point values for pixel offsets. However, we don't 400 // handle subpixel positioning so this function is used to truncate Harfbuzz 401 // values to a number of pixels. 402 static int truncateFixedPointToInteger(HB_Fixed value) 403 { 404 return value >> 6; 405 } 406 407 // TextRunWalker walks a TextRun and presents each script run in sequence. A 408 // TextRun is a sequence of code-points with the same embedding level (i.e. they 409 // are all left-to-right or right-to-left). A script run is a subsequence where 410 // all the characters have the same script (e.g. Arabic, Thai etc). Shaping is 411 // only ever done with script runs since the shapers only know how to deal with 412 // a single script. 413 // 414 // After creating it, the script runs are either iterated backwards or forwards. 415 // It defaults to backwards for RTL and forwards otherwise (which matches the 416 // presentation order), however you can set it with |setBackwardsIteration|. 417 // 418 // Once you have setup the object, call |nextScriptRun| to get the first script 419 // run. This will return false when the iteration is complete. At any time you 420 // can call |reset| to start over again. 421 class TextRunWalker { 422 public: 423 TextRunWalker(const TextRun&, int, int, const Font*); 424 ~TextRunWalker(); 425 426 bool isWordBreak(unsigned, bool); 427 // setPadding sets a number of pixels to be distributed across the TextRun. 428 // WebKit uses this to justify text. 429 void setPadding(int); 430 void reset(); 431 void setBackwardsIteration(bool); 432 // Advance to the next script run, returning false when the end of the 433 // TextRun has been reached. 434 bool nextScriptRun(); 435 float widthOfFullRun(); 436 437 // setWordSpacingAdjustment sets a delta (in pixels) which is applied at 438 // each word break in the TextRun. 439 void setWordSpacingAdjustment(int wordSpacingAdjustment) 440 { 441 m_wordSpacingAdjustment = wordSpacingAdjustment; 442 } 443 444 // setLetterSpacingAdjustment sets an additional number of pixels that is 445 // added to the advance after each output cluster. This matches the behaviour 446 // of WidthIterator::advance. 447 // 448 // (NOTE: currently does nothing because I don't know how to get the 449 // cluster information from Harfbuzz.) 450 void setLetterSpacingAdjustment(int letterSpacingAdjustment) 451 { 452 m_letterSpacing = letterSpacingAdjustment; 453 } 454 455 // setWordAndLetterSpacing calls setWordSpacingAdjustment() and 456 // setLetterSpacingAdjustment() to override m_wordSpacingAdjustment 457 // and m_letterSpacing. 458 void setWordAndLetterSpacing(int wordSpacingAdjustment, int letterSpacingAdjustment); 459 460 // Set the x offset for the next script run. This affects the values in 461 // |xPositions| 462 void setXOffsetToZero() { m_offsetX = 0; } 463 bool rtl() const { return m_run.rtl(); } 464 const uint16_t* glyphs() const { return m_glyphs16; } 465 466 // Return the length of the array returned by |glyphs| 467 unsigned length() const { return m_item.num_glyphs; } 468 469 // Return the offset for each of the glyphs. Note that this is translated 470 // by the current x offset and that the x offset is updated for each script 471 // run. 472 const SkPoint* positions() const { return m_positions; } 473 474 // Get the advances (widths) for each glyph. 475 const HB_Fixed* advances() const { return m_item.advances; } 476 477 // Return the width (in px) of the current script run. 478 unsigned width() const { return m_pixelWidth; } 479 480 // Return the cluster log for the current script run. For example: 481 // script run: f i a n c (fi gets ligatured) 482 // log clutrs: 0 0 1 2 3 4 483 // So, for each input code point, the log tells you which output glyph was 484 // generated for it. 485 const unsigned short* logClusters() const { return m_item.log_clusters; } 486 487 // return the number of code points in the current script run 488 unsigned numCodePoints() const { return m_numCodePoints; } 489 490 const FontPlatformData* fontPlatformDataForScriptRun() { 491 return reinterpret_cast<FontPlatformData*>(m_item.font->userData); 492 } 493 494 private: 495 void setupFontForScriptRun(); 496 const FontPlatformData* setupComplexFont(HB_Script script, const FontPlatformData& platformData); 497 HB_FontRec* allocHarfbuzzFont(); 498 void deleteGlyphArrays(); 499 void createGlyphArrays(int); 500 void resetGlyphArrays(); 501 void shapeGlyphs(); 502 void setGlyphPositions(bool); 503 504 static void normalizeSpacesAndMirrorChars(const UChar* source, bool rtl, 505 UChar* destination, int length); 506 static const TextRun& getNormalizedTextRun(const TextRun& originalRun, 507 OwnPtr<TextRun>& normalizedRun, OwnArrayPtr<UChar>& normalizedBuffer); 508 509 // This matches the logic in RenderBlock::findNextLineBreak 510 static bool isCodepointSpace(HB_UChar16 c) { return c == ' ' || c == '\t'; } 511 512 const Font* const m_font; 513 HB_ShaperItem m_item; 514 uint16_t* m_glyphs16; // A vector of 16-bit glyph ids. 515 SkPoint* m_positions; // A vector of positions for each glyph. 516 ssize_t m_indexOfNextScriptRun; // Indexes the script run in |m_run|. 517 const int m_startingX; // Offset in pixels of the first script run. 518 const int m_startingY; // Offset in pixels of the first script run. 519 int m_offsetX; // Offset in pixels to the start of the next script run. 520 unsigned m_pixelWidth; // Width (in px) of the current script run. 521 unsigned m_numCodePoints; // Code points in current script run. 522 unsigned m_glyphsArrayCapacity; // Current size of all the Harfbuzz arrays. 523 524 OwnPtr<TextRun> m_normalizedRun; 525 OwnArrayPtr<UChar> m_normalizedBuffer; // A buffer for normalized run. 526 const TextRun& m_run; 527 bool m_iterateBackwards; 528 int m_wordSpacingAdjustment; // delta adjustment (pixels) for each word break. 529 float m_padding; // pixels to be distributed over the line at word breaks. 530 float m_padPerWordBreak; // pixels to be added to each word break. 531 float m_padError; // |m_padPerWordBreak| might have a fractional component. 532 // Since we only add a whole number of padding pixels at 533 // each word break we accumulate error. This is the 534 // number of pixels that we are behind so far. 535 unsigned m_letterSpacing; // pixels to be added after each glyph. 536 }; 537 538 TextRunWalker::TextRunWalker(const TextRun& run, int startingX, int startingY, const Font* font) 539 : m_font(font) 540 , m_startingX(startingX) 541 , m_startingY(startingY) 542 , m_offsetX(m_startingX) 543 , m_run(getNormalizedTextRun(run, m_normalizedRun, m_normalizedBuffer)) 544 , m_iterateBackwards(m_run.rtl()) 545 , m_wordSpacingAdjustment(0) 546 , m_padding(0) 547 , m_padPerWordBreak(0) 548 , m_padError(0) 549 , m_letterSpacing(0) 550 { 551 // Do not use |run| inside this constructor. Use |m_run| instead. 552 553 memset(&m_item, 0, sizeof(m_item)); 554 // We cannot know, ahead of time, how many glyphs a given script run 555 // will produce. We take a guess that script runs will not produce more 556 // than twice as many glyphs as there are code points plus a bit of 557 // padding and fallback if we find that we are wrong. 558 createGlyphArrays((m_run.length() + 2) * 2); 559 560 m_item.log_clusters = new unsigned short[m_run.length()]; 561 562 m_item.face = 0; 563 m_item.font = allocHarfbuzzFont(); 564 565 m_item.item.bidiLevel = m_run.rtl(); 566 567 m_item.string = m_run.characters(); 568 m_item.stringLength = m_run.length(); 569 570 reset(); 571 } 572 573 TextRunWalker::~TextRunWalker() 574 { 575 fastFree(m_item.font); 576 deleteGlyphArrays(); 577 delete[] m_item.log_clusters; 578 } 579 580 bool TextRunWalker::isWordBreak(unsigned index, bool isRTL) 581 { 582 if (!isRTL) 583 return index && isCodepointSpace(m_item.string[index]) 584 && !isCodepointSpace(m_item.string[index - 1]); 585 return index != m_item.stringLength - 1 && isCodepointSpace(m_item.string[index]) 586 && !isCodepointSpace(m_item.string[index + 1]); 587 } 588 589 // setPadding sets a number of pixels to be distributed across the TextRun. 590 // WebKit uses this to justify text. 591 void TextRunWalker::setPadding(int padding) 592 { 593 m_padding = padding; 594 if (!m_padding) 595 return; 596 597 // If we have padding to distribute, then we try to give an equal 598 // amount to each space. The last space gets the smaller amount, if 599 // any. 600 unsigned numWordBreaks = 0; 601 bool isRTL = m_iterateBackwards; 602 603 for (unsigned i = 0; i < m_item.stringLength; i++) { 604 if (isWordBreak(i, isRTL)) 605 numWordBreaks++; 606 } 607 608 if (numWordBreaks) 609 m_padPerWordBreak = m_padding / numWordBreaks; 610 else 611 m_padPerWordBreak = 0; 612 } 613 614 void TextRunWalker::reset() 615 { 616 if (m_iterateBackwards) 617 m_indexOfNextScriptRun = m_run.length() - 1; 618 else 619 m_indexOfNextScriptRun = 0; 620 m_offsetX = m_startingX; 621 } 622 623 void TextRunWalker::setBackwardsIteration(bool isBackwards) 624 { 625 m_iterateBackwards = isBackwards; 626 reset(); 627 } 628 629 // Advance to the next script run, returning false when the end of the 630 // TextRun has been reached. 631 bool TextRunWalker::nextScriptRun() 632 { 633 if (m_iterateBackwards) { 634 // In right-to-left mode we need to render the shaped glyph backwards and 635 // also render the script runs themselves backwards. So given a TextRun: 636 // AAAAAAACTTTTTTT (A = Arabic, C = Common, T = Thai) 637 // we render: 638 // TTTTTTCAAAAAAA 639 // (and the glyphs in each A, C and T section are backwards too) 640 if (!hb_utf16_script_run_prev(&m_numCodePoints, &m_item.item, m_run.characters(), 641 m_run.length(), &m_indexOfNextScriptRun)) 642 return false; 643 } else { 644 if (!hb_utf16_script_run_next(&m_numCodePoints, &m_item.item, m_run.characters(), 645 m_run.length(), &m_indexOfNextScriptRun)) 646 return false; 647 648 // It is actually wrong to consider script runs at all in this code. 649 // Other WebKit code (e.g. Mac) segments complex text just by finding 650 // the longest span of text covered by a single font. 651 // But we currently need to call hb_utf16_script_run_next anyway to fill 652 // in the harfbuzz data structures to e.g. pick the correct script's shaper. 653 // So we allow that to run first, then do a second pass over the range it 654 // found and take the largest subregion that stays within a single font. 655 const FontData* glyphData = m_font->glyphDataForCharacter( 656 m_item.string[m_item.item.pos], false).fontData; 657 unsigned endOfRun; 658 for (endOfRun = 1; endOfRun < m_item.item.length; ++endOfRun) { 659 const FontData* nextGlyphData = m_font->glyphDataForCharacter( 660 m_item.string[m_item.item.pos + endOfRun], false).fontData; 661 if (nextGlyphData != glyphData) 662 break; 663 } 664 m_item.item.length = endOfRun; 665 m_indexOfNextScriptRun = m_item.item.pos + endOfRun; 666 } 667 668 setupFontForScriptRun(); 669 shapeGlyphs(); 670 setGlyphPositions(rtl()); 671 672 return true; 673 } 674 675 float TextRunWalker::widthOfFullRun() 676 { 677 float widthSum = 0; 678 while (nextScriptRun()) 679 widthSum += width(); 680 681 return widthSum; 682 } 683 684 void TextRunWalker::setWordAndLetterSpacing(int wordSpacingAdjustment, 685 int letterSpacingAdjustment) 686 { 687 setWordSpacingAdjustment(wordSpacingAdjustment); 688 setLetterSpacingAdjustment(letterSpacingAdjustment); 689 } 690 691 const FontPlatformData* TextRunWalker::setupComplexFont( 692 HB_Script script, const FontPlatformData& platformData) 693 { 694 static FallbackHash fallbackPlatformData; 695 696 // generate scriptStyleIndex - we need unique hash IDs for each style 697 // of each script - normal, bold, italic, bolditalic. the first set of 698 // NUM_SCRIPTS are the normal style version, followed by bold, then 699 // italic, then bold italic. additional fake style bits can be added. 700 int scriptStyleIndex = script; 701 if (platformData.isFakeBold()) 702 scriptStyleIndex += HB_ScriptCount; 703 if (platformData.isFakeItalic()) 704 scriptStyleIndex += HB_ScriptCount << 1; 705 706 FallbackFontKey key(scriptStyleIndex, platformData.size()); 707 FontPlatformData* newPlatformData = 0; 708 709 if (!fallbackPlatformData.contains(key)) { 710 SkTypeface::Style currentStyle = SkTypeface::kNormal; 711 if (platformData.typeface()) 712 currentStyle = platformData.typeface()->style(); 713 SkTypeface* typeface = SkCreateTypefaceForScript(script, currentStyle, 714 SkPaint::kElegant_Variant); 715 newPlatformData = new FontPlatformData(platformData, typeface); 716 SkSafeUnref(typeface); 717 fallbackPlatformData.set(key, newPlatformData); 718 } 719 720 if (!newPlatformData) 721 newPlatformData = fallbackPlatformData.get(key); 722 723 // If we couldn't allocate a new FontPlatformData, revert to the one passed 724 return newPlatformData ? newPlatformData : &platformData; 725 } 726 727 void TextRunWalker::setupFontForScriptRun() 728 { 729 const FontData* fontData = m_font->glyphDataForCharacter(m_run[0], false).fontData; 730 const FontPlatformData& platformData = 731 fontData->fontDataForCharacter(' ')->platformData(); 732 const FontPlatformData* complexPlatformData = setupComplexFont(m_item.item.script, platformData); 733 734 m_item.face = complexPlatformData->harfbuzzFace(); 735 m_item.font->userData = const_cast<FontPlatformData*>(complexPlatformData); 736 737 int size = complexPlatformData->size(); 738 m_item.font->x_ppem = size; 739 m_item.font->y_ppem = size; 740 // x_ and y_scale are the conversion factors from font design space (fEmSize) to 1/64th of device pixels in 16.16 format. 741 const int devicePixelFraction = 64; 742 const int multiplyFor16Dot16 = 1 << 16; 743 int scale = devicePixelFraction * size * multiplyFor16Dot16 / complexPlatformData->emSizeInFontUnits(); 744 m_item.font->x_scale = scale; 745 m_item.font->y_scale = scale; 746 } 747 748 HB_FontRec* TextRunWalker::allocHarfbuzzFont() 749 { 750 HB_FontRec* font = reinterpret_cast<HB_FontRec*>(fastMalloc(sizeof(HB_FontRec))); 751 memset(font, 0, sizeof(HB_FontRec)); 752 font->klass = &harfbuzzSkiaClass; 753 font->userData = 0; 754 755 return font; 756 } 757 758 void TextRunWalker::deleteGlyphArrays() 759 { 760 delete[] m_item.glyphs; 761 delete[] m_item.attributes; 762 delete[] m_item.advances; 763 delete[] m_item.offsets; 764 delete[] m_glyphs16; 765 delete[] m_positions; 766 } 767 768 void TextRunWalker::createGlyphArrays(int size) 769 { 770 m_item.glyphs = new HB_Glyph[size]; 771 m_item.attributes = new HB_GlyphAttributes[size]; 772 m_item.advances = new HB_Fixed[size]; 773 m_item.offsets = new HB_FixedPoint[size]; 774 775 m_glyphs16 = new uint16_t[size]; 776 m_positions = new SkPoint[size]; 777 778 m_item.num_glyphs = size; 779 m_glyphsArrayCapacity = size; // Save the GlyphArrays size. 780 } 781 782 void TextRunWalker::resetGlyphArrays() 783 { 784 int size = m_item.num_glyphs; 785 // All the types here don't have pointers. It is safe to reset to 786 // zero unless Harfbuzz breaks the compatibility in the future. 787 memset(m_item.glyphs, 0, size * sizeof(m_item.glyphs[0])); 788 memset(m_item.attributes, 0, size * sizeof(m_item.attributes[0])); 789 memset(m_item.advances, 0, size * sizeof(m_item.advances[0])); 790 memset(m_item.offsets, 0, size * sizeof(m_item.offsets[0])); 791 memset(m_glyphs16, 0, size * sizeof(m_glyphs16[0])); 792 memset(m_positions, 0, size * sizeof(m_positions[0])); 793 } 794 795 void TextRunWalker::shapeGlyphs() 796 { 797 // HB_ShapeItem() resets m_item.num_glyphs. If the previous call to 798 // HB_ShapeItem() used less space than was available, the capacity of 799 // the array may be larger than the current value of m_item.num_glyphs. 800 // So, we need to reset the num_glyphs to the capacity of the array. 801 m_item.num_glyphs = m_glyphsArrayCapacity; 802 resetGlyphArrays(); 803 while (!HB_ShapeItem(&m_item)) { 804 // We overflowed our arrays. Resize and retry. 805 // HB_ShapeItem fills in m_item.num_glyphs with the needed size. 806 deleteGlyphArrays(); 807 createGlyphArrays(m_item.num_glyphs << 1); 808 resetGlyphArrays(); 809 } 810 } 811 812 void TextRunWalker::setGlyphPositions(bool isRTL) 813 { 814 int position = 0; 815 // logClustersIndex indexes logClusters for the first (or last when 816 // RTL) codepoint of the current glyph. Each time we advance a glyph, 817 // we skip over all the codepoints that contributed to the current 818 // glyph. 819 unsigned logClustersIndex = isRTL && m_item.num_glyphs ? m_item.num_glyphs - 1 : 0; 820 821 for (unsigned iter = 0; iter < m_item.num_glyphs; ++iter) { 822 // Glyphs are stored in logical order, but for layout purposes we 823 // always go left to right. 824 int i = isRTL ? m_item.num_glyphs - iter - 1 : iter; 825 826 m_glyphs16[i] = m_item.glyphs[i]; 827 int offsetX = truncateFixedPointToInteger(m_item.offsets[i].x); 828 int offsetY = truncateFixedPointToInteger(m_item.offsets[i].y); 829 m_positions[i].set(SkIntToScalar(m_offsetX + position) + offsetX, m_startingY + offsetY); 830 831 int advance = truncateFixedPointToInteger(m_item.advances[i]); 832 // The first half of the conjunction works around the case where 833 // output glyphs aren't associated with any codepoints by the 834 // clusters log. 835 if (logClustersIndex < m_item.item.length 836 && isWordBreak(m_item.item.pos + logClustersIndex, isRTL)) { 837 advance += m_wordSpacingAdjustment; 838 839 if (m_padding > 0) { 840 int toPad = roundf(m_padPerWordBreak + m_padError); 841 m_padError += m_padPerWordBreak - toPad; 842 843 if (m_padding < toPad) 844 toPad = m_padding; 845 m_padding -= toPad; 846 advance += toPad; 847 } 848 } 849 850 // ZeroWidthJoiners and ZeroWidthNonJoiners should be stripped by 851 // Harfbuzz, but aren't. Check for zwj and zwnj and replace with a 852 // zero width space. We get the glyph data for space instead of 853 // zeroWidthSpace because the latter was seen to render with an 854 // unexpected code point (the symbol for a cloud). Since the standard 855 // space is in page zero and since we've also confirmed that there is 856 // no advance on this glyph, that should be ok. 857 if (0 == m_item.advances[i]) { 858 const HB_UChar16 c = m_item.string[m_item.item.pos + logClustersIndex]; 859 if ((c == zeroWidthJoiner) || (c == zeroWidthNonJoiner)) { 860 static Glyph spaceGlyph = m_font->glyphDataForCharacter(space, false).glyph; 861 m_glyphs16[i] = spaceGlyph; 862 } 863 } 864 865 // TODO We would like to add m_letterSpacing after each cluster, but I 866 // don't know where the cluster information is. This is typically 867 // fine for Roman languages, but breaks more complex languages 868 // terribly. 869 // advance += m_letterSpacing; 870 871 if (isRTL) { 872 while (logClustersIndex > 0 && logClusters()[logClustersIndex] == i) 873 logClustersIndex--; 874 } else { 875 while (logClustersIndex < m_item.item.length 876 && logClusters()[logClustersIndex] == i) 877 logClustersIndex++; 878 } 879 880 position += advance; 881 } 882 883 m_pixelWidth = position; 884 m_offsetX += m_pixelWidth; 885 } 886 887 void TextRunWalker::normalizeSpacesAndMirrorChars(const UChar* source, bool rtl, 888 UChar* destination, int length) 889 { 890 int position = 0; 891 bool error = false; 892 // Iterate characters in source and mirror character if needed. 893 while (position < length) { 894 UChar32 character; 895 int nextPosition = position; 896 U16_NEXT(source, nextPosition, length, character); 897 898 if (Font::treatAsSpace(character)) 899 character = space; 900 else if (Font::treatAsZeroWidthSpaceInComplexScript(character)) 901 character = zeroWidthSpace; 902 else if (rtl) 903 character = u_charMirror(character); 904 905 U16_APPEND(destination, position, length, character, error); 906 ASSERT(!error); 907 position = nextPosition; 908 } 909 } 910 911 const TextRun& TextRunWalker::getNormalizedTextRun(const TextRun& originalRun, 912 OwnPtr<TextRun>& normalizedRun, OwnArrayPtr<UChar>& normalizedBuffer) 913 { 914 // Normalize the text run in three ways: 915 // 1) Convert the |originalRun| to NFC normalized form if combining diacritical marks 916 // (U+0300..) are used in the run. This conversion is necessary since most OpenType 917 // fonts (e.g., Arial) don't have substitution rules for the diacritical marks in 918 // their GSUB tables. 919 // 920 // Note that we don't use the icu::Normalizer::isNormalized(UNORM_NFC) API here since 921 // the API returns FALSE (= not normalized) for complex runs that don't require NFC 922 // normalization (e.g., Arabic text). Unless the run contains the diacritical marks, 923 // Harfbuzz will do the same thing for us using the GSUB table. 924 // 2) Convert spacing characters into plain spaces, as some fonts will provide glyphs 925 // for characters like '\n' otherwise. 926 // 3) Convert mirrored characters such as parenthesis for rtl text. 927 928 // Convert to NFC form if the text has diacritical marks. 929 icu::UnicodeString normalizedString; 930 UErrorCode error = U_ZERO_ERROR; 931 932 for (int16_t i = 0; i < originalRun.length(); ++i) { 933 UChar ch = originalRun[i]; 934 if (::ublock_getCode(ch) == UBLOCK_COMBINING_DIACRITICAL_MARKS) { 935 icu::Normalizer::normalize(icu::UnicodeString(originalRun.characters(), 936 originalRun.length()), UNORM_NFC, 0 /* no options */, 937 normalizedString, error); 938 if (U_FAILURE(error)) 939 return originalRun; 940 break; 941 } 942 } 943 944 // Normalize space and mirror parenthesis for rtl text. 945 int normalizedBufferLength; 946 const UChar* sourceText; 947 if (normalizedString.isEmpty()) { 948 normalizedBufferLength = originalRun.length(); 949 sourceText = originalRun.characters(); 950 } else { 951 normalizedBufferLength = normalizedString.length(); 952 sourceText = normalizedString.getBuffer(); 953 } 954 955 normalizedBuffer = adoptArrayPtr(new UChar[normalizedBufferLength + 1]); 956 957 normalizeSpacesAndMirrorChars(sourceText, originalRun.rtl(), normalizedBuffer.get(), 958 normalizedBufferLength); 959 960 normalizedRun = adoptPtr(new TextRun(originalRun)); 961 normalizedRun->setText(normalizedBuffer.get(), normalizedBufferLength); 962 return *normalizedRun; 963 } 964 965 FloatRect Font::selectionRectForComplexText(const TextRun& run, 966 const FloatPoint& point, int height, int from, int to) const 967 { 968 int fromX = -1; 969 int toX = -1; 970 TextRunWalker walker(run, 0, 0, this); 971 walker.setWordAndLetterSpacing(wordSpacing(), letterSpacing()); 972 973 // Base will point to the x offset for the current script run. Note that, in 974 // the LTR case, width will be 0. 975 int base = walker.rtl() ? walker.widthOfFullRun() : 0; 976 const int leftEdge = base; 977 978 // We want to enumerate the script runs in code point order in the following 979 // code. This call also resets |walker|. 980 walker.setBackwardsIteration(false); 981 if (!from) 982 fromX = leftEdge; 983 if (!to) 984 toX = leftEdge; 985 986 while (walker.nextScriptRun() && (fromX == -1 || toX == -1)) { 987 // TextRunWalker will helpfully accumulate the x offsets for different 988 // script runs for us. For this code, however, we always want the x 989 // offsets to start from zero so we call this before each script run. 990 walker.setXOffsetToZero(); 991 992 if (walker.rtl()) 993 base -= walker.width(); 994 995 int numCodePoints = static_cast<int>(walker.numCodePoints()); 996 if (fromX == -1 && from < numCodePoints) { 997 // |from| is within this script run. So we index the clusters log to 998 // find which glyph this code-point contributed to and find its x 999 // position. 1000 int glyph = walker.logClusters()[from]; 1001 fromX = base + walker.positions()[glyph].x(); 1002 if (walker.rtl()) 1003 fromX += truncateFixedPointToInteger(walker.advances()[glyph]); 1004 } else 1005 from -= numCodePoints; 1006 1007 if (toX == -1 && to < numCodePoints) { 1008 int glyph = walker.logClusters()[to]; 1009 toX = base + walker.positions()[glyph].x(); 1010 if (walker.rtl()) 1011 toX += truncateFixedPointToInteger(walker.advances()[glyph]); 1012 } else 1013 to -= numCodePoints; 1014 1015 if (!walker.rtl()) 1016 base += walker.width(); 1017 } 1018 1019 // The position in question might be just after the text. 1020 const int rightEdge = base; 1021 if (fromX == -1 && !from) 1022 fromX = rightEdge; 1023 if (toX == -1 && !to) 1024 toX = rightEdge; 1025 1026 ASSERT(fromX != -1 && toX != -1); 1027 1028 if (fromX < toX) 1029 return FloatRect(point.x() + fromX, point.y(), toX - fromX, height); 1030 1031 return FloatRect(point.x() + toX, point.y(), fromX - toX, height); 1032 } 1033 1034 void Font::drawComplexText(GraphicsContext* gc, TextRun const& run, 1035 FloatPoint const& point, int, int) const 1036 { 1037 if (!run.length()) 1038 return; 1039 1040 int mode = gc->textDrawingMode(); 1041 bool fill = mode & TextModeFill; 1042 bool stroke = mode & TextModeStroke; 1043 if (!fill && !stroke) 1044 return; 1045 1046 SkPaint fillPaint, strokePaint; 1047 if (fill) 1048 setupFill(&fillPaint, gc, primaryFont()); 1049 if (stroke) 1050 setupStroke(&strokePaint, gc, primaryFont()); 1051 1052 SkCanvas* canvas = gc->platformContext()->recordingCanvas(); 1053 1054 bool haveMultipleLayers = isCanvasMultiLayered(canvas); 1055 TextRunWalker walker(run, point.x(), point.y(), this); 1056 walker.setWordAndLetterSpacing(wordSpacing(), letterSpacing()); 1057 walker.setPadding(run.expansion()); 1058 1059 while (walker.nextScriptRun()) { 1060 if (fill) { 1061 walker.fontPlatformDataForScriptRun()->setupPaint(&fillPaint); 1062 adjustTextRenderMode(&fillPaint, haveMultipleLayers); 1063 canvas->drawPosText(walker.glyphs(), 1064 walker.length() << 1, walker.positions(), fillPaint); 1065 } 1066 if (stroke) { 1067 walker.fontPlatformDataForScriptRun()->setupPaint(&strokePaint); 1068 adjustTextRenderMode(&strokePaint, haveMultipleLayers); 1069 canvas->drawPosText(walker.glyphs(), 1070 walker.length() << 1, walker.positions(), strokePaint); 1071 } 1072 } 1073 1074 } 1075 1076 float Font::floatWidthForComplexText(const TextRun& run, 1077 HashSet<const SimpleFontData*>*, GlyphOverflow*) const 1078 { 1079 TextRunWalker walker(run, 0, 0, this); 1080 walker.setWordAndLetterSpacing(wordSpacing(), letterSpacing()); 1081 return walker.widthOfFullRun(); 1082 } 1083 1084 static int glyphIndexForXPositionInScriptRun(const TextRunWalker& walker, int x) 1085 { 1086 const HB_Fixed* advances = walker.advances(); 1087 int glyphIndex; 1088 if (walker.rtl()) { 1089 for (glyphIndex = walker.length() - 1; glyphIndex >= 0; --glyphIndex) { 1090 if (x < truncateFixedPointToInteger(advances[glyphIndex])) 1091 break; 1092 x -= truncateFixedPointToInteger(advances[glyphIndex]); 1093 } 1094 } else { 1095 for (glyphIndex = 0; glyphIndex < static_cast<int>(walker.length()); 1096 ++glyphIndex) { 1097 if (x < truncateFixedPointToInteger(advances[glyphIndex])) 1098 break; 1099 x -= truncateFixedPointToInteger(advances[glyphIndex]); 1100 } 1101 } 1102 1103 return glyphIndex; 1104 } 1105 1106 int Font::offsetForPositionForComplexText(const TextRun& run, float x, 1107 bool includePartialGlyphs) const 1108 { 1109 // (Mac code ignores includePartialGlyphs, and they don't know what it's 1110 // supposed to do, so we just ignore it as well.) 1111 TextRunWalker walker(run, 0, 0, this); 1112 walker.setWordAndLetterSpacing(wordSpacing(), letterSpacing()); 1113 1114 // If this is RTL text, the first glyph from the left is actually the last 1115 // code point. So we need to know how many code points there are total in 1116 // order to subtract. This is different from the length of the TextRun 1117 // because UTF-16 surrogate pairs are a single code point, but 32-bits long. 1118 // In LTR we leave this as 0 so that we get the correct value for 1119 // |basePosition|, below. 1120 unsigned totalCodePoints = 0; 1121 if (walker.rtl()) { 1122 ssize_t offset = 0; 1123 while (offset < run.length()) { 1124 utf16_to_code_point(run.characters(), run.length(), &offset); 1125 totalCodePoints++; 1126 } 1127 } 1128 1129 unsigned basePosition = totalCodePoints; 1130 1131 // For RTL: 1132 // code-point order: abcd efg hijkl 1133 // on screen: lkjih gfe dcba 1134 // ^ ^ 1135 // | | 1136 // basePosition--| | 1137 // totalCodePoints----| 1138 // Since basePosition is currently the total number of code-points, the 1139 // first thing we do is decrement it so that it's pointing to the start of 1140 // the current script-run. 1141 // 1142 // For LTR, basePosition is zero so it already points to the start of the 1143 // first script run. 1144 while (walker.nextScriptRun()) { 1145 if (walker.rtl()) 1146 basePosition -= walker.numCodePoints(); 1147 1148 if (x >= 0 && x < static_cast<int>(walker.width())) { 1149 // The x value in question is within this script run. We consider 1150 // each glyph in presentation order and stop when we find the one 1151 // covering this position. 1152 const int glyphIndex = glyphIndexForXPositionInScriptRun(walker, x); 1153 1154 // Now that we have a glyph index, we have to turn that into a 1155 // code-point index. Because of ligatures, several code-points may 1156 // have gone into a single glyph. We iterate over the clusters log 1157 // and find the first code-point which contributed to the glyph. 1158 1159 // Some shapers (i.e. Khmer) will produce cluster logs which report 1160 // that /no/ code points contributed to certain glyphs. Because of 1161 // this, we take any code point which contributed to the glyph in 1162 // question, or any subsequent glyph. If we run off the end, then 1163 // we take the last code point. 1164 const unsigned short* log = walker.logClusters(); 1165 for (unsigned j = 0; j < walker.numCodePoints(); ++j) { 1166 if (log[j] >= glyphIndex) 1167 return basePosition + j; 1168 } 1169 1170 return basePosition + walker.numCodePoints() - 1; 1171 } 1172 1173 x -= walker.width(); 1174 1175 if (!walker.rtl()) 1176 basePosition += walker.numCodePoints(); 1177 } 1178 1179 return basePosition; 1180 } 1181 #endif 1182 1183 } 1184