Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) | 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) |
| 3 * (C) 1999 Antti Koivisto (koivisto@kde.org) | 3 * (C) 1999 Antti Koivisto (koivisto@kde.org) |
| 4 * (C) 2000 Dirk Mueller (mueller@kde.org) | 4 * (C) 2000 Dirk Mueller (mueller@kde.org) |
| 5 * Copyright (C) 2003, 2006, 2010, 2011 Apple Inc. All rights reserved. | 5 * Copyright (C) 2003, 2006, 2010, 2011 Apple Inc. All rights reserved. |
| 6 * Copyright (c) 2007, 2008, 2010 Google Inc. All rights reserved. | 6 * Copyright (c) 2007, 2008, 2010 Google Inc. All rights reserved. |
| 7 * | 7 * |
| 8 * This library is free software; you can redistribute it and/or | 8 * This library is free software; you can redistribute it and/or |
| 9 * modify it under the terms of the GNU Library General Public | 9 * modify it under the terms of the GNU Library General Public |
| 10 * License as published by the Free Software Foundation; either | 10 * License as published by the Free Software Foundation; either |
| 11 * version 2 of the License, or (at your option) any later version. | 11 * version 2 of the License, or (at your option) any later version. |
| 12 * | 12 * |
| 13 * This library is distributed in the hope that it will be useful, | 13 * This library is distributed in the hope that it will be useful, |
| 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of | 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 16 * Library General Public License for more details. | 16 * Library General Public License for more details. |
| 17 * | 17 * |
| 18 * You should have received a copy of the GNU Library General Public License | 18 * You should have received a copy of the GNU Library General Public License |
| 19 * along with this library; see the file COPYING.LIB. If not, write to | 19 * along with this library; see the file COPYING.LIB. If not, write to |
| 20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | 20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
| 21 * Boston, MA 02110-1301, USA. | 21 * Boston, MA 02110-1301, USA. |
| 22 * | 22 * |
| 23 */ | 23 */ |
| 24 | 24 |
| 25 #include "config.h" | 25 #include "config.h" |
| 26 #include "platform/fonts/Font.h" | 26 #include "platform/fonts/Font.h" |
| 27 | 27 |
| 28 #include "SkPaint.h" | 28 #include "SkPaint.h" |
| 29 #include "SkTemplates.h" | 29 #include "SkTemplates.h" |
| 30 #include "hb-ot.h" | |
| 31 #include "hb.h" | |
| 30 #include "platform/LayoutUnit.h" | 32 #include "platform/LayoutUnit.h" |
| 31 #include "platform/RuntimeEnabledFeatures.h" | 33 #include "platform/RuntimeEnabledFeatures.h" |
| 32 #include "platform/fonts/Character.h" | 34 #include "platform/fonts/Character.h" |
| 33 #include "platform/fonts/FontCache.h" | 35 #include "platform/fonts/FontCache.h" |
| 34 #include "platform/fonts/FontFallbackList.h" | 36 #include "platform/fonts/FontFallbackList.h" |
| 35 #include "platform/fonts/GlyphBuffer.h" | 37 #include "platform/fonts/GlyphBuffer.h" |
| 36 #include "platform/fonts/GlyphPageTreeNode.h" | 38 #include "platform/fonts/GlyphPageTreeNode.h" |
| 37 #include "platform/fonts/SimpleFontData.h" | 39 #include "platform/fonts/SimpleFontData.h" |
| 40 #include "platform/fonts/shaping/HarfBuzzFace.h" | |
| 38 #include "platform/fonts/shaping/HarfBuzzShaper.h" | 41 #include "platform/fonts/shaping/HarfBuzzShaper.h" |
| 39 #include "platform/fonts/shaping/SimpleShaper.h" | 42 #include "platform/fonts/shaping/SimpleShaper.h" |
| 40 #include "platform/geometry/FloatRect.h" | 43 #include "platform/geometry/FloatRect.h" |
| 41 #include "platform/graphics/skia/SkiaUtils.h" | 44 #include "platform/graphics/skia/SkiaUtils.h" |
| 42 #include "platform/text/BidiResolver.h" | 45 #include "platform/text/BidiResolver.h" |
| 43 #include "platform/text/TextRun.h" | 46 #include "platform/text/TextRun.h" |
| 44 #include "platform/text/TextRunIterator.h" | 47 #include "platform/text/TextRunIterator.h" |
| 45 #include "platform/transforms/AffineTransform.h" | 48 #include "platform/transforms/AffineTransform.h" |
| 46 #include "third_party/skia/include/core/SkCanvas.h" | 49 #include "third_party/skia/include/core/SkCanvas.h" |
| 47 #include "wtf/MainThread.h" | 50 #include "wtf/MainThread.h" |
| 48 #include "wtf/StdLibExtras.h" | 51 #include "wtf/StdLibExtras.h" |
| 49 #include "wtf/unicode/CharacterNames.h" | 52 #include "wtf/unicode/CharacterNames.h" |
| 50 #include "wtf/unicode/Unicode.h" | 53 #include "wtf/unicode/Unicode.h" |
| 51 | 54 |
| 52 using namespace WTF; | 55 using namespace WTF; |
| 53 using namespace Unicode; | 56 using namespace Unicode; |
| 54 | 57 |
| 55 namespace blink { | 58 namespace blink { |
| 56 | 59 |
| 57 Font::Font() | 60 Font::Font() |
| 58 { | 61 { |
| 59 } | 62 } |
| 60 | 63 |
| 61 Font::Font(const FontDescription& fd) | 64 Font::Font(const FontDescription& fd) |
| 62 : m_fontDescription(fd) | 65 : m_fontDescription(fd) |
| 66 , m_canShapeWordByWord(0) | |
| 67 , m_shapeWordByWordComputed(0) | |
| 63 { | 68 { |
| 64 } | 69 } |
| 65 | 70 |
| 66 Font::Font(const Font& other) | 71 Font::Font(const Font& other) |
| 67 : m_fontDescription(other.m_fontDescription) | 72 : m_fontDescription(other.m_fontDescription) |
| 68 , m_fontFallbackList(other.m_fontFallbackList) | 73 , m_fontFallbackList(other.m_fontFallbackList) |
| 74 , m_canShapeWordByWord(0) | |
| 75 , m_shapeWordByWordComputed(0) | |
| 69 { | 76 { |
| 70 } | 77 } |
| 71 | 78 |
| 72 Font& Font::operator=(const Font& other) | 79 Font& Font::operator=(const Font& other) |
| 73 { | 80 { |
| 74 m_fontDescription = other.m_fontDescription; | 81 m_fontDescription = other.m_fontDescription; |
| 75 m_fontFallbackList = other.m_fontFallbackList; | 82 m_fontFallbackList = other.m_fontFallbackList; |
| 83 m_canShapeWordByWord = other.m_canShapeWordByWord; | |
| 84 m_shapeWordByWordComputed = other.m_shapeWordByWordComputed; | |
| 76 return *this; | 85 return *this; |
| 77 } | 86 } |
| 78 | 87 |
| 79 bool Font::operator==(const Font& other) const | 88 bool Font::operator==(const Font& other) const |
| 80 { | 89 { |
| 81 FontSelector* first = m_fontFallbackList ? m_fontFallbackList->fontSelector( ) : 0; | 90 FontSelector* first = m_fontFallbackList ? m_fontFallbackList->fontSelector( ) : 0; |
| 82 FontSelector* second = other.m_fontFallbackList ? other.m_fontFallbackList-> fontSelector() : 0; | 91 FontSelector* second = other.m_fontFallbackList ? other.m_fontFallbackList-> fontSelector() : 0; |
| 83 | 92 |
| 84 return first == second | 93 return first == second |
| 85 && m_fontDescription == other.m_fontDescription | 94 && m_fontDescription == other.m_fontDescription |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 96 // and could eventually be rectified by using RefPtrs for Fonts themselves. | 105 // and could eventually be rectified by using RefPtrs for Fonts themselves. |
| 97 if (!m_fontFallbackList) | 106 if (!m_fontFallbackList) |
| 98 m_fontFallbackList = FontFallbackList::create(); | 107 m_fontFallbackList = FontFallbackList::create(); |
| 99 m_fontFallbackList->invalidate(fontSelector); | 108 m_fontFallbackList->invalidate(fontSelector); |
| 100 } | 109 } |
| 101 | 110 |
| 102 float Font::buildGlyphBuffer(const TextRunPaintInfo& runInfo, GlyphBuffer& glyph Buffer, | 111 float Font::buildGlyphBuffer(const TextRunPaintInfo& runInfo, GlyphBuffer& glyph Buffer, |
| 103 const GlyphData* emphasisData) const | 112 const GlyphData* emphasisData) const |
| 104 { | 113 { |
| 105 if (codePath(runInfo) == ComplexPath) { | 114 if (codePath(runInfo) == ComplexPath) { |
| 106 HarfBuzzShaper shaper(this, runInfo.run, emphasisData); | 115 float width; |
| 107 shaper.setDrawRange(runInfo.from, runInfo.to); | 116 if (emphasisData) { |
| 108 shaper.shape(&glyphBuffer); | 117 // FIXME: Populate using CachingWordShaper. |
|
drott
2015/06/23 12:45:51
IIRC, in a couple of reviews dpranke asked me to n
| |
| 109 return shaper.totalWidth(); | 118 HarfBuzzShaper shaper(this, runInfo.run); |
| 119 RefPtr<ShapeResult> shapeResult = shaper.shapeResult(); | |
| 120 shapeResult->fillGlyphBufferForTextEmphasis(&glyphBuffer, 0, | |
| 121 runInfo.run, emphasisData, runInfo.from, runInfo.to, 0); | |
| 122 width = shapeResult->width(); | |
| 123 } else { | |
| 124 CachingWordShaper& shaper = m_fontFallbackList->cachingWordShaper(); | |
| 125 width = shaper.fillGlyphBuffer(this, runInfo.run, nullptr, | |
| 126 &glyphBuffer, runInfo.from, runInfo.to); | |
| 127 } | |
| 128 | |
| 129 return width; | |
| 110 } | 130 } |
| 111 | 131 |
| 112 SimpleShaper shaper(this, runInfo.run, emphasisData, nullptr /* fallbackFont s */, nullptr); | 132 SimpleShaper shaper(this, runInfo.run, emphasisData, nullptr /* fallbackFont s */, nullptr); |
| 113 shaper.advance(runInfo.from); | 133 shaper.advance(runInfo.from); |
| 114 shaper.advance(runInfo.to, &glyphBuffer); | 134 shaper.advance(runInfo.to, &glyphBuffer); |
| 115 float width = shaper.runWidthSoFar(); | 135 float width = shaper.runWidthSoFar(); |
| 116 | 136 |
| 117 if (runInfo.run.rtl()) { | 137 if (runInfo.run.rtl()) { |
| 118 // Glyphs are shaped & stored in RTL advance order - reverse them for LT R drawing. | 138 // Glyphs are shaped & stored in RTL advance order - reverse them for LT R drawing. |
| 119 shaper.advance(runInfo.run.length()); | 139 shaper.advance(runInfo.run.length()); |
| (...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 327 if (run.codePath() == TextRun::ForceSimple) | 347 if (run.codePath() == TextRun::ForceSimple) |
| 328 return SimplePath; | 348 return SimplePath; |
| 329 | 349 |
| 330 if (run.is8Bit()) | 350 if (run.is8Bit()) |
| 331 return SimplePath; | 351 return SimplePath; |
| 332 | 352 |
| 333 // Start from 0 since drawing and highlighting also measure the characters b efore run->from. | 353 // Start from 0 since drawing and highlighting also measure the characters b efore run->from. |
| 334 return Character::characterRangeCodePath(run.characters16(), run.length()); | 354 return Character::characterRangeCodePath(run.characters16(), run.length()); |
| 335 } | 355 } |
| 336 | 356 |
| 357 static inline bool tableHasSpace(hb_face_t* face, hb_set_t* glyphs, | |
| 358 hb_tag_t tag, hb_codepoint_t space) | |
| 359 { | |
| 360 unsigned count = hb_ot_layout_table_get_lookup_count(face, tag); | |
| 361 for (unsigned i = 0; i < count; i++) { | |
| 362 hb_ot_layout_lookup_collect_glyphs(face, tag, i, glyphs, glyphs, glyphs, | |
| 363 0); | |
| 364 if (hb_set_has(glyphs, space)) | |
| 365 return true; | |
| 366 } | |
| 367 return false; | |
| 368 } | |
| 369 | |
| 370 bool Font::canShapeWordByWord() const | |
| 371 { | |
| 372 if (!m_shapeWordByWordComputed) { | |
| 373 m_canShapeWordByWord = computeCanShapeWordByWord(); | |
| 374 m_shapeWordByWordComputed = true; | |
| 375 } | |
| 376 return m_canShapeWordByWord; | |
| 377 }; | |
| 378 | |
| 379 bool Font::computeCanShapeWordByWord() const | |
| 380 { | |
| 381 if (!fontDescription().typesettingFeatures()) | |
| 382 return true; | |
| 383 | |
| 384 const FontPlatformData& platformData = primaryFont()->platformData(); | |
|
drott
2015/06/23 12:45:51
I'd suggest to move the code from below this line
| |
| 385 const HarfBuzzFace* hbFace = platformData.harfBuzzFace(); | |
| 386 if (!hbFace) | |
| 387 return true; | |
| 388 | |
| 389 hb_face_t* face = hbFace->face(); | |
| 390 ASSERT(face); | |
| 391 hb_font_t* font = hbFace->createFont(); | |
| 392 ASSERT(font); | |
| 393 | |
| 394 hb_codepoint_t space; | |
| 395 // If the space glyph isn't present in the font then each space character | |
| 396 // will be rendering using a fallback font, which grantees that it cannot | |
| 397 // affect the shape of the preceding word. | |
| 398 if (!hb_font_get_glyph(font, spaceCharacter, 0, &space)) | |
| 399 return true; | |
| 400 | |
| 401 if (!hb_ot_layout_has_substitution(face) | |
| 402 && !hb_ot_layout_has_positioning(face)) { | |
| 403 return true; | |
| 404 } | |
| 405 | |
| 406 hb_set_t* glyphs = hb_set_create(); | |
| 407 TypesettingFeatures features = fontDescription().typesettingFeatures(); | |
| 408 | |
| 409 bool foundSpaceInTable = false; | |
| 410 if (features & Kerning) | |
| 411 foundSpaceInTable = tableHasSpace(face, glyphs, HB_OT_TAG_GPOS, space); | |
| 412 if (!foundSpaceInTable && (features & Ligatures)) | |
| 413 foundSpaceInTable = tableHasSpace(face, glyphs, HB_OT_TAG_GSUB, space); | |
| 414 | |
| 415 hb_set_destroy(glyphs); | |
| 416 hb_font_destroy(font); | |
| 417 | |
| 418 return !foundSpaceInTable; | |
| 419 }; | |
| 420 | |
| 337 void Font::willUseFontData(UChar32 character) const | 421 void Font::willUseFontData(UChar32 character) const |
| 338 { | 422 { |
| 339 const FontFamily& family = fontDescription().family(); | 423 const FontFamily& family = fontDescription().family(); |
| 340 if (m_fontFallbackList && m_fontFallbackList->fontSelector() && !family.fami lyIsEmpty()) | 424 if (m_fontFallbackList && m_fontFallbackList->fontSelector() && !family.fami lyIsEmpty()) |
| 341 m_fontFallbackList->fontSelector()->willUseFontData(fontDescription(), f amily.family(), character); | 425 m_fontFallbackList->fontSelector()->willUseFontData(fontDescription(), f amily.family(), character); |
| 342 } | 426 } |
| 343 | 427 |
| 344 static inline GlyphData glyphDataForNonCJKCharacterWithGlyphOrientation(UChar32 character, FontOrientation orientation, GlyphData& data, unsigned pageNumber) | 428 static inline GlyphData glyphDataForNonCJKCharacterWithGlyphOrientation(UChar32 character, FontOrientation orientation, GlyphData& data, unsigned pageNumber) |
| 345 { | 429 { |
| 346 if (isVerticalNonCJKUpright(orientation) || Character::shouldIgnoreRotation( character)) { | 430 if (isVerticalNonCJKUpright(orientation) || Character::shouldIgnoreRotation( character)) { |
| (...skipping 316 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 663 canvas->restoreToCount(canvasStackLevel); | 747 canvas->restoreToCount(canvasStackLevel); |
| 664 } | 748 } |
| 665 | 749 |
| 666 void Font::drawTextBlob(SkCanvas* canvas, const SkPaint& paint, const SkTextBlob * blob, const SkPoint& origin) const | 750 void Font::drawTextBlob(SkCanvas* canvas, const SkPaint& paint, const SkTextBlob * blob, const SkPoint& origin) const |
| 667 { | 751 { |
| 668 ASSERT(RuntimeEnabledFeatures::textBlobEnabled()); | 752 ASSERT(RuntimeEnabledFeatures::textBlobEnabled()); |
| 669 | 753 |
| 670 canvas->drawTextBlob(blob, origin.x(), origin.y(), paint); | 754 canvas->drawTextBlob(blob, origin.x(), origin.y(), paint); |
| 671 } | 755 } |
| 672 | 756 |
| 673 float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFon tData*>* fallbackFonts, FloatRect* outGlyphBounds) const | 757 float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFon tData*>* fallbackFonts, FloatRect* glyphBounds) const |
| 674 { | 758 { |
| 675 bool hasWordSpacingOrLetterSpacing = fontDescription().wordSpacing() | 759 CachingWordShaper& shaper = m_fontFallbackList->cachingWordShaper(); |
| 676 || fontDescription().letterSpacing(); | 760 float width = shaper.width(this, run, fallbackFonts, glyphBounds); |
| 677 // Word spacing and letter spacing can change the width of a word. | 761 return width; |
| 678 // If a tab occurs inside a word, the width of the word varies based on its | |
| 679 // position on the line. | |
| 680 bool isCacheable = !hasWordSpacingOrLetterSpacing && !run.allowTabs(); | |
| 681 | |
| 682 WidthCacheEntry* cacheEntry = isCacheable | |
| 683 ? m_fontFallbackList->widthCache().add(run, WidthCacheEntry()) | |
| 684 : 0; | |
| 685 if (cacheEntry && cacheEntry->isValid()) { | |
| 686 if (outGlyphBounds) | |
| 687 *outGlyphBounds = cacheEntry->glyphBounds; | |
| 688 return cacheEntry->width; | |
| 689 } | |
| 690 | |
| 691 FloatRect glyphBounds; | |
| 692 HarfBuzzShaper shaper(this, run, nullptr, fallbackFonts, &glyphBounds); | |
| 693 if (!shaper.shape()) | |
| 694 return 0; | |
| 695 | |
| 696 float result = shaper.totalWidth(); | |
| 697 | |
| 698 if (cacheEntry && (!fallbackFonts || fallbackFonts->isEmpty())) { | |
| 699 cacheEntry->glyphBounds = glyphBounds; | |
| 700 cacheEntry->width = result; | |
| 701 } | |
| 702 | |
| 703 if (outGlyphBounds) | |
| 704 *outGlyphBounds = glyphBounds; | |
| 705 return result; | |
| 706 } | 762 } |
| 707 | 763 |
| 708 // Return the code point index for the given |x| offset into the text run. | 764 // Return the code point index for the given |x| offset into the text run. |
| 709 int Font::offsetForPositionForComplexText(const TextRun& run, float xFloat, | 765 int Font::offsetForPositionForComplexText(const TextRun& run, float xFloat, |
| 710 bool includePartialGlyphs) const | 766 bool includePartialGlyphs) const |
| 711 { | 767 { |
| 712 HarfBuzzShaper shaper(this, run); | 768 HarfBuzzShaper shaper(this, run); |
| 713 if (!shaper.shape()) | 769 RefPtr<ShapeResult> shapeResult = shaper.shapeResult(); |
| 770 if (!shapeResult) | |
| 714 return 0; | 771 return 0; |
| 715 return shaper.offsetForPosition(xFloat); | 772 return shapeResult->offsetForPosition(xFloat); |
| 716 } | 773 } |
| 717 | 774 |
| 718 // Return the rectangle for selecting the given range of code-points in the Text Run. | 775 // Return the rectangle for selecting the given range of code-points in the Text Run. |
| 719 FloatRect Font::selectionRectForComplexText(const TextRun& run, | 776 FloatRect Font::selectionRectForComplexText(const TextRun& run, |
| 720 const FloatPoint& point, int height, int from, int to) const | 777 const FloatPoint& point, int height, int from, int to) const |
| 721 { | 778 { |
| 722 HarfBuzzShaper shaper(this, run); | 779 HarfBuzzShaper shaper(this, run); |
| 723 if (!shaper.shape()) | 780 RefPtr<ShapeResult> shapeResult = shaper.shapeResult(); |
| 781 if (!shapeResult) | |
| 724 return FloatRect(); | 782 return FloatRect(); |
| 725 return shaper.selectionRect(point, height, from, to); | 783 return shapeResult->selectionRect(point, height, from, to); |
| 726 } | 784 } |
| 727 | 785 |
| 728 void Font::drawGlyphBuffer(SkCanvas* canvas, const SkPaint& paint, const TextRun PaintInfo& runInfo, const GlyphBuffer& glyphBuffer, const FloatPoint& point, flo at deviceScaleFactor) const | 786 void Font::drawGlyphBuffer(SkCanvas* canvas, const SkPaint& paint, const TextRun PaintInfo& runInfo, const GlyphBuffer& glyphBuffer, const FloatPoint& point, flo at deviceScaleFactor) const |
| 729 { | 787 { |
| 730 if (glyphBuffer.isEmpty()) | 788 if (glyphBuffer.isEmpty()) |
| 731 return; | 789 return; |
| 732 | 790 |
| 733 if (RuntimeEnabledFeatures::textBlobEnabled()) { | 791 if (RuntimeEnabledFeatures::textBlobEnabled()) { |
| 734 // Enabling text-blobs forces the blob rendering path even for uncacheab le blobs. | 792 // Enabling text-blobs forces the blob rendering path even for uncacheab le blobs. |
| 735 TextBlobPtr uncacheableTextBlob; | 793 TextBlobPtr uncacheableTextBlob; |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 837 { | 895 { |
| 838 return m_fontFallbackList && m_fontFallbackList->loadingCustomFonts(); | 896 return m_fontFallbackList && m_fontFallbackList->loadingCustomFonts(); |
| 839 } | 897 } |
| 840 | 898 |
| 841 bool Font::isFallbackValid() const | 899 bool Font::isFallbackValid() const |
| 842 { | 900 { |
| 843 return !m_fontFallbackList || m_fontFallbackList->isValid(); | 901 return !m_fontFallbackList || m_fontFallbackList->isValid(); |
| 844 } | 902 } |
| 845 | 903 |
| 846 } // namespace blink | 904 } // namespace blink |
| OLD | NEW |