Chromium Code Reviews| Index: Source/platform/fonts/Font.cpp |
| diff --git a/Source/platform/fonts/Font.cpp b/Source/platform/fonts/Font.cpp |
| index 0e37b836daa12fb56811319037cd8680a5ea3f53..b76e6ec50fbf4d6ef8a3d1cf037c16e438884a86 100644 |
| --- a/Source/platform/fonts/Font.cpp |
| +++ b/Source/platform/fonts/Font.cpp |
| @@ -27,6 +27,8 @@ |
| #include "SkPaint.h" |
| #include "SkTemplates.h" |
| +#include "hb-ot.h" |
| +#include "hb.h" |
| #include "platform/LayoutUnit.h" |
| #include "platform/RuntimeEnabledFeatures.h" |
| #include "platform/fonts/Character.h" |
| @@ -35,6 +37,7 @@ |
| #include "platform/fonts/GlyphBuffer.h" |
| #include "platform/fonts/GlyphPageTreeNode.h" |
| #include "platform/fonts/SimpleFontData.h" |
| +#include "platform/fonts/shaping/HarfBuzzFace.h" |
| #include "platform/fonts/shaping/HarfBuzzShaper.h" |
| #include "platform/fonts/shaping/SimpleShaper.h" |
| #include "platform/geometry/FloatRect.h" |
| @@ -60,12 +63,16 @@ Font::Font() |
| Font::Font(const FontDescription& fd) |
| : m_fontDescription(fd) |
| + , m_canShapeWordByWord(0) |
| + , m_shapeWordByWordComputed(0) |
| { |
| } |
| Font::Font(const Font& other) |
| : m_fontDescription(other.m_fontDescription) |
| , m_fontFallbackList(other.m_fontFallbackList) |
| + , m_canShapeWordByWord(0) |
| + , m_shapeWordByWordComputed(0) |
| { |
| } |
| @@ -73,6 +80,8 @@ Font& Font::operator=(const Font& other) |
| { |
| m_fontDescription = other.m_fontDescription; |
| m_fontFallbackList = other.m_fontFallbackList; |
| + m_canShapeWordByWord = other.m_canShapeWordByWord; |
| + m_shapeWordByWordComputed = other.m_shapeWordByWordComputed; |
| return *this; |
| } |
| @@ -103,10 +112,21 @@ float Font::buildGlyphBuffer(const TextRunPaintInfo& runInfo, GlyphBuffer& glyph |
| const GlyphData* emphasisData) const |
| { |
| if (codePath(runInfo) == ComplexPath) { |
| - HarfBuzzShaper shaper(this, runInfo.run, emphasisData); |
| - shaper.setDrawRange(runInfo.from, runInfo.to); |
| - shaper.shape(&glyphBuffer); |
| - return shaper.totalWidth(); |
| + float width; |
| + if (emphasisData) { |
| + // FIXME: Populate using CachingWordShaper. |
| + HarfBuzzShaper shaper(this, runInfo.run); |
| + RefPtr<ShapeResult> shapeResult = shaper.shapeResult(); |
| + shapeResult->fillGlyphBufferForTextEmphasis(&glyphBuffer, 0, |
| + runInfo.run, emphasisData, runInfo.from, runInfo.to, 0); |
| + width = shapeResult->width(); |
| + } else { |
| + CachingWordShaper& shaper = m_fontFallbackList->cachingWordShaper(); |
| + width = shaper.fillGlyphBuffer(this, runInfo.run, nullptr, |
| + &glyphBuffer, runInfo.from, runInfo.to); |
| + } |
| + |
| + return width; |
| } |
| SimpleShaper shaper(this, runInfo.run, emphasisData, nullptr /* fallbackFonts */, nullptr); |
| @@ -334,6 +354,67 @@ CodePath Font::codePath(const TextRunPaintInfo& runInfo) const |
| return Character::characterRangeCodePath(run.characters16(), run.length()); |
| } |
| +static inline bool tableHasSpace(hb_face_t* face, hb_set_t* glyphs, |
| + hb_tag_t tag, hb_codepoint_t space) |
| +{ |
| + unsigned count = hb_ot_layout_table_get_lookup_count(face, tag); |
| + for (unsigned i = 0; i < count; i++) { |
| + hb_ot_layout_lookup_collect_glyphs(face, tag, i, glyphs, glyphs, glyphs, |
| + 0); |
| + if (hb_set_has(glyphs, space)) |
| + return true; |
| + } |
| + return false; |
| +} |
| + |
| +bool Font::canShapeWordByWord() const |
| +{ |
| + if (!m_shapeWordByWordComputed) { |
| + m_canShapeWordByWord = computeCanShapeWordByWord(); |
| + m_shapeWordByWordComputed = true; |
| + } |
| + return m_canShapeWordByWord; |
| +}; |
| + |
| +bool Font::computeCanShapeWordByWord() const |
| +{ |
| + if (!fontDescription().typesettingFeatures()) |
| + return true; |
| + |
| + const FontPlatformData& platformData = primaryFont()->platformData(); |
| + const HarfBuzzFace* hbFace = platformData.harfBuzzFace(); |
| + if (!hbFace) |
| + return true; |
| + |
| + hb_face_t* face = hbFace->face(); |
| + ASSERT(face); |
| + hb_font_t* font = hbFace->createFont(); |
| + ASSERT(font); |
| + |
| + hb_codepoint_t space; |
| + if (!hb_font_get_glyph(font, spaceCharacter, 0, &space)) |
|
leviw_travelin_and_unemployed
2015/06/22 18:52:08
This seems worthy of a comment?
eae
2015/06/22 19:19:53
Done.
|
| + return true; |
| + |
| + if (!hb_ot_layout_has_substitution(face) |
| + && !hb_ot_layout_has_positioning(face)) { |
| + return true; |
| + } |
| + |
| + hb_set_t* glyphs = hb_set_create(); |
| + TypesettingFeatures features = fontDescription().typesettingFeatures(); |
| + |
| + bool foundSpaceInTable = false; |
| + if (features & Kerning) |
| + foundSpaceInTable = tableHasSpace(face, glyphs, HB_OT_TAG_GPOS, space); |
| + if (!foundSpaceInTable && (features & Ligatures)) |
| + foundSpaceInTable = tableHasSpace(face, glyphs, HB_OT_TAG_GSUB, space); |
| + |
| + hb_set_destroy(glyphs); |
| + hb_font_destroy(font); |
| + |
| + return !foundSpaceInTable; |
| +}; |
| + |
| void Font::willUseFontData(UChar32 character) const |
| { |
| const FontFamily& family = fontDescription().family(); |
| @@ -670,39 +751,11 @@ void Font::drawTextBlob(SkCanvas* canvas, const SkPaint& paint, const SkTextBlob |
| canvas->drawTextBlob(blob, origin.x(), origin.y(), paint); |
| } |
| -float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts, FloatRect* outGlyphBounds) const |
| +float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts, FloatRect* glyphBounds) const |
| { |
| - bool hasWordSpacingOrLetterSpacing = fontDescription().wordSpacing() |
| - || fontDescription().letterSpacing(); |
| - // Word spacing and letter spacing can change the width of a word. |
| - // If a tab occurs inside a word, the width of the word varies based on its |
| - // position on the line. |
| - bool isCacheable = !hasWordSpacingOrLetterSpacing && !run.allowTabs(); |
| - |
| - WidthCacheEntry* cacheEntry = isCacheable |
| - ? m_fontFallbackList->widthCache().add(run, WidthCacheEntry()) |
| - : 0; |
| - if (cacheEntry && cacheEntry->isValid()) { |
| - if (outGlyphBounds) |
| - *outGlyphBounds = cacheEntry->glyphBounds; |
| - return cacheEntry->width; |
| - } |
| - |
| - FloatRect glyphBounds; |
| - HarfBuzzShaper shaper(this, run, nullptr, fallbackFonts, &glyphBounds); |
| - if (!shaper.shape()) |
| - return 0; |
| - |
| - float result = shaper.totalWidth(); |
| - |
| - if (cacheEntry && (!fallbackFonts || fallbackFonts->isEmpty())) { |
| - cacheEntry->glyphBounds = glyphBounds; |
| - cacheEntry->width = result; |
| - } |
| - |
| - if (outGlyphBounds) |
| - *outGlyphBounds = glyphBounds; |
| - return result; |
| + CachingWordShaper& shaper = m_fontFallbackList->cachingWordShaper(); |
| + float width = shaper.width(this, run, fallbackFonts, glyphBounds); |
| + return width; |
| } |
| // Return the code point index for the given |x| offset into the text run. |
| @@ -710,9 +763,10 @@ int Font::offsetForPositionForComplexText(const TextRun& run, float xFloat, |
| bool includePartialGlyphs) const |
| { |
| HarfBuzzShaper shaper(this, run); |
| - if (!shaper.shape()) |
| + RefPtr<ShapeResult> shapeResult = shaper.shapeResult(); |
| + if (!shapeResult) |
| return 0; |
| - return shaper.offsetForPosition(xFloat); |
| + return shapeResult->offsetForPosition(xFloat); |
| } |
| // Return the rectangle for selecting the given range of code-points in the TextRun. |
| @@ -720,9 +774,10 @@ FloatRect Font::selectionRectForComplexText(const TextRun& run, |
| const FloatPoint& point, int height, int from, int to) const |
| { |
| HarfBuzzShaper shaper(this, run); |
| - if (!shaper.shape()) |
| + RefPtr<ShapeResult> shapeResult = shaper.shapeResult(); |
| + if (!shapeResult) |
| return FloatRect(); |
| - return shaper.selectionRect(point, height, from, to); |
| + return shapeResult->selectionRect(point, height, from, to); |
| } |
| void Font::drawGlyphBuffer(SkCanvas* canvas, const SkPaint& paint, const TextRunPaintInfo& runInfo, const GlyphBuffer& glyphBuffer, const FloatPoint& point, float deviceScaleFactor) const |