Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(185)

Side by Side Diff: Source/platform/fonts/Font.cpp

Issue 1192223002: Optimize Complex Text Shaping and Caching (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Addressing review comments Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698