Merge Blink code to cache SkTextBlob
This CL merges the following CLs from Blink to implement SkTextBlobs:
https://codereview.chromium.org/554613004
https://codereview.chromium.org/645363003
https://codereview.chromium.org/667573008
https://codereview.chromium.org/672713002
https://codereview.chromium.org/778233002
https://codereview.chromium.org/820093005
https://codereview.chromium.org/856613002
R=esprehn@chromium.org
Review URL: https://codereview.chromium.org/859203002
diff --git a/sky/engine/core/rendering/InlineTextBox.cpp b/sky/engine/core/rendering/InlineTextBox.cpp
index cb54daf..a026235 100644
--- a/sky/engine/core/rendering/InlineTextBox.cpp
+++ b/sky/engine/core/rendering/InlineTextBox.cpp
@@ -56,7 +56,7 @@
struct SameSizeAsInlineTextBox : public InlineBox {
unsigned variables[1];
unsigned short variables2[2];
- void* pointers[2];
+ void* pointers[3];
};
COMPILE_ASSERT(sizeof(InlineTextBox) == sizeof(SameSizeAsInlineTextBox), InlineTextBox_should_stay_small);
@@ -416,13 +416,16 @@
const Font& font, const TextRun& textRun,
const AtomicString& emphasisMark, int emphasisMarkOffset,
int startOffset, int endOffset, int truncationPoint,
- const FloatPoint& textOrigin, const FloatRect& boxRect)
+ const FloatPoint& textOrigin, const FloatRect& boxRect,
+ TextBlobPtr* cachedTextBlob = 0)
{
TextRunPaintInfo textRunPaintInfo(textRun);
textRunPaintInfo.bounds = boxRect;
if (startOffset <= endOffset) {
textRunPaintInfo.from = startOffset;
textRunPaintInfo.to = endOffset;
+ // FIXME: We should be able to use cachedTextBlob in more cases.
+ textRunPaintInfo.cachedTextBlob = cachedTextBlob;
if (emphasisMark.isEmpty())
context->drawText(font, textRunPaintInfo, textOrigin);
else
@@ -460,11 +463,11 @@
void paintTextWithEmphasisMark(
GraphicsContext* context, const Font& font, const TextPaintingStyle& textStyle, const TextRun& textRun,
const AtomicString& emphasisMark, int emphasisMarkOffset, int startOffset, int endOffset, int length,
- const FloatPoint& textOrigin, const FloatRect& boxRect)
+ const FloatPoint& textOrigin, const FloatRect& boxRect, TextBlobPtr* cachedTextBlob = 0)
{
GraphicsContextStateSaver stateSaver(*context, false);
updateGraphicsContext(context, textStyle, stateSaver);
- paintText(context, font, textRun, nullAtom, 0, startOffset, endOffset, length, textOrigin, boxRect);
+ paintText(context, font, textRun, nullAtom, 0, startOffset, endOffset, length, textOrigin, boxRect, cachedTextBlob);
if (!emphasisMark.isEmpty()) {
if (textStyle.emphasisMarkColor != textStyle.fillColor)
@@ -603,12 +606,19 @@
startOffset = ePos;
endOffset = sPos;
}
- paintTextWithEmphasisMark(context, font, textStyle, textRun, emphasisMark, emphasisMarkOffset, startOffset, endOffset, length, textOrigin, boxRect);
+ // FIXME: This cache should probably ultimately be held somewhere else.
+ // A hashmap is convenient to avoid a memory hit when the
+ // RuntimeEnabledFeature is off.
+ bool textBlobIsCacheable = RuntimeEnabledFeatures::textBlobEnabled() && startOffset == 0 && endOffset == length;
+ TextBlobPtr* cachedTextBlob = textBlobIsCacheable ? &m_cachedTextBlob : nullptr;
+ paintTextWithEmphasisMark(context, font, textStyle, textRun, emphasisMark, emphasisMarkOffset, startOffset, endOffset, length, textOrigin, boxRect, cachedTextBlob);
}
if ((paintSelectedTextOnly || paintSelectedTextSeparately) && sPos < ePos) {
// paint only the text that is selected
- paintTextWithEmphasisMark(context, font, selectionStyle, textRun, emphasisMark, emphasisMarkOffset, sPos, ePos, length, textOrigin, boxRect);
+ bool textBlobIsCacheable = RuntimeEnabledFeatures::textBlobEnabled() && sPos == 0 && ePos == length;
+ TextBlobPtr* cachedTextBlob = textBlobIsCacheable ? &m_cachedTextBlob : nullptr;
+ paintTextWithEmphasisMark(context, font, selectionStyle, textRun, emphasisMark, emphasisMarkOffset, sPos, ePos, length, textOrigin, boxRect, cachedTextBlob);
}
// Paint decorations
diff --git a/sky/engine/core/rendering/InlineTextBox.h b/sky/engine/core/rendering/InlineTextBox.h
index ab67eee..76696f9 100644
--- a/sky/engine/core/rendering/InlineTextBox.h
+++ b/sky/engine/core/rendering/InlineTextBox.h
@@ -161,6 +161,7 @@
private:
InlineTextBox* m_prevTextBox; // The previous box that also uses our RenderObject
InlineTextBox* m_nextTextBox; // The next box that also uses our RenderObject
+ TextBlobPtr m_cachedTextBlob;
int m_start;
unsigned short m_len;
diff --git a/sky/engine/platform/BUILD.gn b/sky/engine/platform/BUILD.gn
index 63bf93c..20e644b 100644
--- a/sky/engine/platform/BUILD.gn
+++ b/sky/engine/platform/BUILD.gn
@@ -699,7 +699,6 @@
"fonts/FontCacheTest.cpp",
"fonts/FontDescriptionTest.cpp",
"fonts/FontTest.cpp",
- "fonts/GlyphBufferTest.cpp",
"fonts/GlyphPageTreeNodeTest.cpp",
"fonts/android/FontCacheAndroidTest.cpp",
"geometry/FloatBoxTest.cpp",
diff --git a/sky/engine/platform/fonts/Font.cpp b/sky/engine/platform/fonts/Font.cpp
index 3167834..b0c2975 100644
--- a/sky/engine/platform/fonts/Font.cpp
+++ b/sky/engine/platform/fonts/Font.cpp
@@ -34,6 +34,7 @@
#include "sky/engine/platform/fonts/GlyphPageTreeNode.h"
#include "sky/engine/platform/fonts/SimpleFontData.h"
#include "sky/engine/platform/fonts/WidthIterator.h"
+#include "sky/engine/platform/fonts/harfbuzz/HarfBuzzShaper.h"
#include "sky/engine/platform/geometry/FloatRect.h"
#include "sky/engine/platform/graphics/GraphicsContext.h"
#include "sky/engine/platform/text/TextRun.h"
@@ -103,24 +104,95 @@
m_fontFallbackList->invalidate(fontSelector);
}
-void Font::drawText(GraphicsContext* context, const TextRunPaintInfo& runInfo, const FloatPoint& point, CustomFontNotReadyAction customFontNotReadyAction) const
+float Font::buildGlyphBuffer(const TextRunPaintInfo& runInfo, GlyphBuffer& glyphBuffer,
+ ForTextEmphasisOrNot forTextEmphasis) const
+{
+ if (codePath(runInfo.run) == ComplexPath) {
+ HarfBuzzShaper shaper(this, runInfo.run, (forTextEmphasis == ForTextEmphasis)
+ ? HarfBuzzShaper::ForTextEmphasis : HarfBuzzShaper::NotForTextEmphasis);
+ shaper.setDrawRange(runInfo.from, runInfo.to);
+ shaper.shape(&glyphBuffer);
+
+ return 0;
+ }
+
+ WidthIterator it(this, runInfo.run, nullptr, false, forTextEmphasis);
+ it.advance(runInfo.from);
+ float beforeWidth = it.runWidthSoFar();
+ it.advance(runInfo.to, &glyphBuffer);
+
+ if (runInfo.run.ltr())
+ return beforeWidth;
+
+ // RTL
+ float afterWidth = it.runWidthSoFar();
+ it.advance(runInfo.run.length());
+ glyphBuffer.reverse();
+
+ return it.runWidthSoFar() - afterWidth;
+}
+
+void Font::drawText(GraphicsContext* context, const TextRunPaintInfo& runInfo,
+ const FloatPoint& point) const
+{
+ // Don't draw anything while we are using custom fonts that are in the process of loading.
+ if (shouldSkipDrawing())
+ return;
+
+ TextDrawingModeFlags textMode = context->textDrawingMode();
+ if (!(textMode & TextModeFill) && !((textMode & TextModeStroke) && context->hasStroke()))
+ return;
+
+ if (runInfo.cachedTextBlob && runInfo.cachedTextBlob->get()) {
+ ASSERT(RuntimeEnabledFeatures::textBlobEnabled());
+ // we have a pre-cached blob -- happy joy!
+ drawTextBlob(context, runInfo.cachedTextBlob->get(), point.data());
+ return;
+ }
+
+ GlyphBuffer glyphBuffer;
+ float initialAdvance = buildGlyphBuffer(runInfo, glyphBuffer);
+
+ if (glyphBuffer.isEmpty())
+ return;
+
+ if (RuntimeEnabledFeatures::textBlobEnabled()) {
+ // Enabling text-blobs forces the blob rendering path even for uncacheable blobs.
+ TextBlobPtr uncacheableTextBlob;
+ TextBlobPtr& textBlob = runInfo.cachedTextBlob ? *runInfo.cachedTextBlob : uncacheableTextBlob;
+ FloatRect blobBounds = runInfo.bounds;
+ blobBounds.moveBy(-point);
+
+ textBlob = buildTextBlob(glyphBuffer, initialAdvance, blobBounds);
+ if (textBlob) {
+ drawTextBlob(context, textBlob.get(), point.data());
+ return;
+ }
+ }
+
+ drawGlyphBuffer(context, runInfo, glyphBuffer, FloatPoint(point.x() + initialAdvance, point.y()));
+}
+
+float Font::drawUncachedText(GraphicsContext* context, const TextRunPaintInfo& runInfo,
+ const FloatPoint& point, CustomFontNotReadyAction customFontNotReadyAction) const
{
// Don't draw anything while we are using custom fonts that are in the process of loading,
// except if the 'force' argument is set to true (in which case it will use a fallback
// font).
if (shouldSkipDrawing() && customFontNotReadyAction == DoNotPaintIfFontNotReady)
- return;
+ return 0;
- CodePath codePathToUse = codePath(runInfo.run);
- // FIXME: Use the fast code path once it handles partial runs with kerning and ligatures. See http://webkit.org/b/100050
- if (codePathToUse != ComplexPath && fontDescription().typesettingFeatures() && (runInfo.from || runInfo.to != runInfo.run.length()))
- codePathToUse = ComplexPath;
+ TextDrawingModeFlags textMode = context->textDrawingMode();
+ if (!(textMode & TextModeFill) && !((textMode & TextModeStroke) && context->hasStroke()))
+ return 0;
- if (codePathToUse != ComplexPath) {
- drawSimpleText(context, runInfo, point);
- } else {
- drawComplexText(context, runInfo, point);
- }
+ GlyphBuffer glyphBuffer;
+ float initialAdvance = buildGlyphBuffer(runInfo, glyphBuffer);
+
+ if (glyphBuffer.isEmpty())
+ return 0;
+
+ return drawGlyphBuffer(context, runInfo, glyphBuffer, FloatPoint(point.x() + initialAdvance, point.y()));
}
void Font::drawEmphasisMarks(GraphicsContext* context, const TextRunPaintInfo& runInfo, const AtomicString& mark, const FloatPoint& point) const
@@ -128,15 +200,13 @@
if (shouldSkipDrawing())
return;
- CodePath codePathToUse = codePath(runInfo.run);
- // FIXME: Use the fast code path once it handles partial runs with kerning and ligatures. See http://webkit.org/b/100050
- if (codePathToUse != ComplexPath && fontDescription().typesettingFeatures() && (runInfo.from || runInfo.to != runInfo.run.length()))
- codePathToUse = ComplexPath;
+ GlyphBuffer glyphBuffer;
+ float initialAdvance = buildGlyphBuffer(runInfo, glyphBuffer, ForTextEmphasis);
- if (codePathToUse != ComplexPath)
- drawEmphasisMarksForSimpleText(context, runInfo, mark, point);
- else
- drawEmphasisMarksForComplexText(context, runInfo, mark, point);
+ if (glyphBuffer.isEmpty())
+ return;
+
+ drawEmphasisMarks(context, runInfo, glyphBuffer, mark, FloatPoint(point.x() + initialAdvance, point.y()));
}
static inline void updateGlyphOverflowFromBounds(const IntRectExtent& glyphBounds,
@@ -609,97 +679,32 @@
return markFontData->fontMetrics().height();
}
-float Font::getGlyphsAndAdvancesForSimpleText(const TextRunPaintInfo& runInfo, GlyphBuffer& glyphBuffer, ForTextEmphasisOrNot forTextEmphasis) const
-{
- float initialAdvance;
-
- WidthIterator it(this, runInfo.run, 0, false, forTextEmphasis);
- it.advance(runInfo.from);
- float beforeWidth = it.m_runWidthSoFar;
- it.advance(runInfo.to, &glyphBuffer);
-
- if (glyphBuffer.isEmpty())
- return 0;
-
- float afterWidth = it.m_runWidthSoFar;
-
- if (runInfo.run.rtl()) {
- it.advance(runInfo.run.length());
- initialAdvance = it.m_runWidthSoFar - afterWidth;
- glyphBuffer.reverse();
- } else {
- initialAdvance = beforeWidth;
- }
-
- return initialAdvance;
-}
-
-void Font::drawSimpleText(GraphicsContext* context, const TextRunPaintInfo& runInfo, const FloatPoint& point) const
-{
- // This glyph buffer holds our glyphs+advances+font data for each glyph.
- GlyphBuffer glyphBuffer;
- float initialAdvance = getGlyphsAndAdvancesForSimpleText(runInfo, glyphBuffer);
- ASSERT(!glyphBuffer.hasVerticalAdvances());
-
- if (glyphBuffer.isEmpty())
- return;
-
- TextBlobPtr textBlob;
- if (RuntimeEnabledFeatures::textBlobEnabled()) {
- // Using text blob causes a small difference in how gradients and
- // patterns are rendered.
- // FIXME: Fix this, most likely in Skia.
- if (!context->strokeGradient() && !context->strokePattern() && !context->fillGradient() && !context->fillPattern()) {
- FloatRect blobBounds = runInfo.bounds;
- blobBounds.moveBy(-point);
- textBlob = buildTextBlob(glyphBuffer, initialAdvance, blobBounds);
- }
- }
-
- if (textBlob) {
- drawTextBlob(context, textBlob.get(), point.data());
- } else {
- FloatPoint startPoint(point.x() + initialAdvance, point.y());
- drawGlyphBuffer(context, runInfo, glyphBuffer, startPoint);
- }
-}
-
-void Font::drawEmphasisMarksForSimpleText(GraphicsContext* context, const TextRunPaintInfo& runInfo, const AtomicString& mark, const FloatPoint& point) const
-{
- GlyphBuffer glyphBuffer;
- float initialAdvance = getGlyphsAndAdvancesForSimpleText(runInfo, glyphBuffer, ForTextEmphasis);
-
- if (glyphBuffer.isEmpty())
- return;
-
- drawEmphasisMarks(context, runInfo, glyphBuffer, mark, FloatPoint(point.x() + initialAdvance, point.y()));
-}
-
-void Font::drawGlyphBuffer(GraphicsContext* context, const TextRunPaintInfo& runInfo, const GlyphBuffer& glyphBuffer, const FloatPoint& point) const
+float Font::drawGlyphBuffer(GraphicsContext* context, const TextRunPaintInfo& runInfo, const GlyphBuffer& glyphBuffer, const FloatPoint& point) const
{
// Draw each contiguous run of glyphs that use the same font data.
const SimpleFontData* fontData = glyphBuffer.fontDataAt(0);
FloatPoint startPoint(point);
- FloatPoint nextPoint = startPoint + glyphBuffer.advanceAt(0);
+ float advanceSoFar = 0;
unsigned lastFrom = 0;
- unsigned nextGlyph = 1;
+ unsigned nextGlyph = 0;
while (nextGlyph < glyphBuffer.size()) {
const SimpleFontData* nextFontData = glyphBuffer.fontDataAt(nextGlyph);
-
if (nextFontData != fontData) {
drawGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint, runInfo.bounds);
-
lastFrom = nextGlyph;
fontData = nextFontData;
- startPoint = nextPoint;
+ startPoint += FloatSize(advanceSoFar, 0);
+ advanceSoFar = 0;
}
- nextPoint += glyphBuffer.advanceAt(nextGlyph);
+ advanceSoFar += glyphBuffer.advanceAt(nextGlyph);
nextGlyph++;
}
-
drawGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint, runInfo.bounds);
+ startPoint += FloatSize(advanceSoFar, 0);
+ return startPoint.x() - point.x();
}
+
inline static float offsetToMiddleOfGlyph(const SimpleFontData* fontData, Glyph glyph)
{
if (fontData->platformData().orientation() == Horizontal) {
@@ -712,7 +717,7 @@
inline static float offsetToMiddleOfAdvanceAtIndex(const GlyphBuffer& glyphBuffer, size_t i)
{
- return glyphBuffer.advanceAt(i).width() / 2;
+ return glyphBuffer.advanceAt(i) / 2;
}
void Font::drawEmphasisMarks(GraphicsContext* context, const TextRunPaintInfo& runInfo, const GlyphBuffer& glyphBuffer, const AtomicString& mark, const FloatPoint& point) const
@@ -737,7 +742,7 @@
GlyphBuffer markBuffer;
for (unsigned i = 0; i + 1 < glyphBuffer.size(); ++i) {
float middleOfNextGlyph = offsetToMiddleOfAdvanceAtIndex(glyphBuffer, i + 1);
- float advance = glyphBuffer.advanceAt(i).width() - middleOfLastGlyph + middleOfNextGlyph;
+ float advance = glyphBuffer.advanceAt(i) - middleOfLastGlyph + middleOfNextGlyph;
markBuffer.add(glyphBuffer.glyphAt(i) ? markGlyph : spaceGlyph, markFontData, advance);
middleOfLastGlyph = middleOfNextGlyph;
}
diff --git a/sky/engine/platform/fonts/Font.h b/sky/engine/platform/fonts/Font.h
index 213915f..f57afd0 100644
--- a/sky/engine/platform/fonts/Font.h
+++ b/sky/engine/platform/fonts/Font.h
@@ -100,7 +100,8 @@
void update(PassRefPtr<FontSelector>) const;
enum CustomFontNotReadyAction { DoNotPaintIfFontNotReady, UseFallbackIfFontNotReady };
- void drawText(GraphicsContext*, const TextRunPaintInfo&, const FloatPoint&, CustomFontNotReadyAction = DoNotPaintIfFontNotReady) const;
+ void drawText(GraphicsContext*, const TextRunPaintInfo&, const FloatPoint&) const;
+ float drawUncachedText(GraphicsContext*, const TextRunPaintInfo&, const FloatPoint&, CustomFontNotReadyAction) const;
void drawEmphasisMarks(GraphicsContext*, const TextRunPaintInfo&, const AtomicString& mark, const FloatPoint&) const;
float width(const TextRun&, HashSet<const SimpleFontData*>* fallbackFonts = 0, GlyphOverflow* = 0) const;
@@ -136,12 +137,11 @@
enum ForTextEmphasisOrNot { NotForTextEmphasis, ForTextEmphasis };
// Returns the initial in-stream advance.
- float getGlyphsAndAdvancesForSimpleText(const TextRunPaintInfo&, GlyphBuffer&, ForTextEmphasisOrNot = NotForTextEmphasis) const;
- void drawSimpleText(GraphicsContext*, const TextRunPaintInfo&, const FloatPoint&) const;
- void drawEmphasisMarksForSimpleText(GraphicsContext*, const TextRunPaintInfo&, const AtomicString& mark, const FloatPoint&) const;
+ float buildGlyphBuffer(const TextRunPaintInfo&, GlyphBuffer&, ForTextEmphasisOrNot = NotForTextEmphasis) const;
+ PassTextBlobPtr buildTextBlob(const GlyphBuffer&, float initialAdvance, const FloatRect& bounds) const;
void drawGlyphs(GraphicsContext*, const SimpleFontData*, const GlyphBuffer&, unsigned from, unsigned numGlyphs, const FloatPoint&, const FloatRect& textRect) const;
- void drawGlyphBuffer(GraphicsContext*, const TextRunPaintInfo&, const GlyphBuffer&, const FloatPoint&) const;
void drawTextBlob(GraphicsContext*, const SkTextBlob*, const SkPoint& origin) const;
+ float drawGlyphBuffer(GraphicsContext*, const TextRunPaintInfo&, const GlyphBuffer&, const FloatPoint&) const;
void drawEmphasisMarks(GraphicsContext*, const TextRunPaintInfo&, const GlyphBuffer&, const AtomicString&, const FloatPoint&) const;
float floatWidthForSimpleText(const TextRun&, HashSet<const SimpleFontData*>* fallbackFonts = 0, IntRectExtent* glyphBounds = 0) const;
int offsetForPositionForSimpleText(const TextRun&, float position, bool includePartialGlyphs) const;
@@ -149,10 +149,6 @@
bool getEmphasisMarkGlyphData(const AtomicString&, GlyphData&) const;
- // Returns the initial in-stream advance.
- float getGlyphsAndAdvancesForComplexText(const TextRunPaintInfo&, GlyphBuffer&, ForTextEmphasisOrNot = NotForTextEmphasis) const;
- void drawComplexText(GraphicsContext*, const TextRunPaintInfo&, const FloatPoint&) const;
- void drawEmphasisMarksForComplexText(GraphicsContext*, const TextRunPaintInfo&, const AtomicString& mark, const FloatPoint&) const;
float floatWidthForComplexText(const TextRun&, HashSet<const SimpleFontData*>* fallbackFonts, IntRectExtent* glyphBounds) const;
int offsetForPositionForComplexText(const TextRun&, float position, bool includePartialGlyphs) const;
FloatRect selectionRectForComplexText(const TextRun&, const FloatPoint&, int h, int from, int to) const;
@@ -183,8 +179,6 @@
return m_fontFallbackList && m_fontFallbackList->shouldSkipDrawing();
}
- PassTextBlobPtr buildTextBlob(const GlyphBuffer&, float initialAdvance, const FloatRect& bounds) const;
-
FontDescription m_fontDescription;
mutable RefPtr<FontFallbackList> m_fontFallbackList;
};
diff --git a/sky/engine/platform/fonts/GlyphBuffer.h b/sky/engine/platform/fonts/GlyphBuffer.h
index 7249213..c9e8a42 100644
--- a/sky/engine/platform/fonts/GlyphBuffer.h
+++ b/sky/engine/platform/fonts/GlyphBuffer.h
@@ -40,22 +40,23 @@
class GlyphBuffer {
public:
- GlyphBuffer() : m_hasVerticalAdvances(false) { }
+ GlyphBuffer() { }
bool isEmpty() const { return m_fontData.isEmpty(); }
+ bool hasOffsets() const { return !m_offsets.isEmpty(); }
unsigned size() const { return m_fontData.size(); }
- bool hasVerticalAdvances() const { return m_hasVerticalAdvances; }
void clear()
{
m_fontData.clear();
m_glyphs.clear();
m_advances.clear();
- m_hasVerticalAdvances = false;
+ m_offsets.clear();
}
const Glyph* glyphs(unsigned from) const { return m_glyphs.data() + from; }
- const FloatSize* advances(unsigned from) const { return m_advances.data() + from; }
+ const float* advances(unsigned from) const { return m_advances.data() + from; }
+ const FloatSize* offsets(unsigned from) const { return m_offsets.data() + from; }
const SimpleFontData* fontDataAt(unsigned index) const { return m_fontData[index]; }
@@ -64,25 +65,30 @@
return m_glyphs[index];
}
- FloatSize advanceAt(unsigned index) const
+ float advanceAt(unsigned index) const
{
return m_advances[index];
}
void add(Glyph glyph, const SimpleFontData* font, float width)
{
+ // should not mix offset/advance-only glyphs
+ ASSERT(!hasOffsets());
+
m_fontData.append(font);
m_glyphs.append(glyph);
- m_advances.append(FloatSize(width, 0));
+ m_advances.append(width);
}
- void add(Glyph glyph, const SimpleFontData* font, const FloatSize& advance)
+ void add(Glyph glyph, const SimpleFontData* font, const FloatSize& offset, float advance)
{
+ // should not mix offset/advance-only glyphs
+ ASSERT(size() == m_offsets.size());
+
m_fontData.append(font);
m_glyphs.append(glyph);
+ m_offsets.append(offset);
m_advances.append(advance);
- if (advance.height())
- m_hasVerticalAdvances = true;
}
void reverse()
@@ -92,23 +98,18 @@
m_advances.reverse();
}
- void setAdvanceWidth(unsigned index, float newWidth)
- {
- m_advances[index].setWidth(newWidth);
- }
-
void expandLastAdvance(float width)
{
ASSERT(!isEmpty());
- FloatSize& lastAdvance = m_advances.last();
- lastAdvance.setWidth(lastAdvance.width() + width);
+ float& lastAdvance = m_advances.last();
+ lastAdvance += width;
}
private:
Vector<const SimpleFontData*, 2048> m_fontData;
Vector<Glyph, 2048> m_glyphs;
- Vector<FloatSize, 2048> m_advances;
- bool m_hasVerticalAdvances;
+ Vector<float, 2048> m_advances;
+ Vector<FloatSize, 1024> m_offsets;
};
} // namespace blink
diff --git a/sky/engine/platform/fonts/GlyphBufferTest.cpp b/sky/engine/platform/fonts/GlyphBufferTest.cpp
deleted file mode 100644
index 37d3d45..0000000
--- a/sky/engine/platform/fonts/GlyphBufferTest.cpp
+++ /dev/null
@@ -1,237 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "sky/engine/config.h"
-#include "sky/engine/platform/fonts/GlyphBuffer.h"
-
-#include <gtest/gtest.h>
-#include "sky/engine/platform/fonts/SimpleFontData.h"
-#include "sky/engine/wtf/PassRefPtr.h"
-#include "sky/engine/wtf/RefPtr.h"
-
-using namespace blink;
-
-namespace {
-
-// Minimal TestSimpleFontData implementation.
-// Font has no glyphs, but that's okay.
-class TestSimpleFontData : public SimpleFontData {
-public:
- static PassRefPtr<TestSimpleFontData> create()
- {
- return adoptRef(new TestSimpleFontData);
- }
-
-private:
- TestSimpleFontData() : SimpleFontData(nullptr, 10, false, false) { }
-
- bool fillGlyphPage(GlyphPage* pageToFill, unsigned offset, unsigned length, UChar* buffer, unsigned bufferLength) const override
- {
- return false;
- }
-};
-
-TEST(GlyphBufferTest, StartsEmpty)
-{
- GlyphBuffer glyphBuffer;
- EXPECT_TRUE(glyphBuffer.isEmpty());
- EXPECT_EQ(0u, glyphBuffer.size());
-}
-
-TEST(GlyphBufferTest, StoresGlyphs)
-{
- RefPtr<SimpleFontData> font1 = TestSimpleFontData::create();
- RefPtr<SimpleFontData> font2 = TestSimpleFontData::create();
-
- GlyphBuffer glyphBuffer;
- glyphBuffer.add(42, font1.get(), 10);
- glyphBuffer.add(43, font1.get(), 15);
- glyphBuffer.add(44, font2.get(), FloatSize(12, 2));
-
- EXPECT_FALSE(glyphBuffer.isEmpty());
- EXPECT_EQ(3u, glyphBuffer.size());
-
- EXPECT_EQ(42, glyphBuffer.glyphAt(0));
- EXPECT_EQ(43, glyphBuffer.glyphAt(1));
- EXPECT_EQ(44, glyphBuffer.glyphAt(2));
-
- const Glyph* glyphs = glyphBuffer.glyphs(0);
- EXPECT_EQ(42, glyphs[0]);
- EXPECT_EQ(43, glyphs[1]);
- EXPECT_EQ(44, glyphs[2]);
-}
-
-TEST(GlyphBufferTest, StoresAdvances)
-{
- RefPtr<SimpleFontData> font1 = TestSimpleFontData::create();
- RefPtr<SimpleFontData> font2 = TestSimpleFontData::create();
-
- GlyphBuffer glyphBuffer;
- glyphBuffer.add(42, font1.get(), 10);
- glyphBuffer.add(43, font1.get(), 15);
- glyphBuffer.add(44, font2.get(), FloatSize(12, 2));
-
- EXPECT_FALSE(glyphBuffer.isEmpty());
- EXPECT_EQ(3u, glyphBuffer.size());
-
- EXPECT_EQ(FloatSize(10, 0), glyphBuffer.advanceAt(0));
- EXPECT_EQ(FloatSize(15, 0), glyphBuffer.advanceAt(1));
- EXPECT_EQ(FloatSize(12, 2), glyphBuffer.advanceAt(2));
-
- const FloatSize* advances = glyphBuffer.advances(0);
- EXPECT_EQ(FloatSize(10, 0), advances[0]);
- EXPECT_EQ(FloatSize(15, 0), advances[1]);
- EXPECT_EQ(FloatSize(12, 2), advances[2]);
-}
-
-TEST(GlyphBufferTest, StoresSimpleFontData)
-{
- RefPtr<SimpleFontData> font1 = TestSimpleFontData::create();
- RefPtr<SimpleFontData> font2 = TestSimpleFontData::create();
-
- GlyphBuffer glyphBuffer;
- glyphBuffer.add(42, font1.get(), 10);
- glyphBuffer.add(43, font1.get(), 15);
- glyphBuffer.add(44, font2.get(), FloatSize(12, 2));
-
- EXPECT_FALSE(glyphBuffer.isEmpty());
- EXPECT_EQ(3u, glyphBuffer.size());
-
- EXPECT_EQ(font1.get(), glyphBuffer.fontDataAt(0));
- EXPECT_EQ(font1.get(), glyphBuffer.fontDataAt(1));
- EXPECT_EQ(font2.get(), glyphBuffer.fontDataAt(2));
-}
-
-TEST(GlyphBufferTest, GlyphArrayWithOffset)
-{
- RefPtr<SimpleFontData> font1 = TestSimpleFontData::create();
- RefPtr<SimpleFontData> font2 = TestSimpleFontData::create();
-
- GlyphBuffer glyphBuffer;
- glyphBuffer.add(42, font1.get(), 10);
- glyphBuffer.add(43, font1.get(), 15);
- glyphBuffer.add(44, font2.get(), FloatSize(12, 2));
-
- EXPECT_FALSE(glyphBuffer.isEmpty());
- EXPECT_EQ(3u, glyphBuffer.size());
-
- const Glyph* glyphs = glyphBuffer.glyphs(1);
- EXPECT_EQ(43, glyphs[0]);
- EXPECT_EQ(44, glyphs[1]);
-}
-
-TEST(GlyphBufferTest, AdvanceArrayWithOffset)
-{
- RefPtr<SimpleFontData> font1 = TestSimpleFontData::create();
- RefPtr<SimpleFontData> font2 = TestSimpleFontData::create();
-
- GlyphBuffer glyphBuffer;
- glyphBuffer.add(42, font1.get(), 10);
- glyphBuffer.add(43, font1.get(), 15);
- glyphBuffer.add(44, font2.get(), FloatSize(12, 2));
-
- EXPECT_FALSE(glyphBuffer.isEmpty());
- EXPECT_EQ(3u, glyphBuffer.size());
-
- const FloatSize* advances = glyphBuffer.advances(1);
- EXPECT_EQ(FloatSize(15, 0), advances[0]);
- EXPECT_EQ(FloatSize(12, 2), advances[1]);
-}
-
-TEST(GlyphBufferTest, Clear)
-{
- RefPtr<SimpleFontData> font1 = TestSimpleFontData::create();
- RefPtr<SimpleFontData> font2 = TestSimpleFontData::create();
-
- GlyphBuffer glyphBuffer;
- glyphBuffer.add(42, font1.get(), 10);
- glyphBuffer.add(43, font1.get(), 15);
- glyphBuffer.add(44, font2.get(), FloatSize(12, 2));
-
- EXPECT_FALSE(glyphBuffer.isEmpty());
- EXPECT_EQ(3u, glyphBuffer.size());
-
- glyphBuffer.clear();
-
- EXPECT_TRUE(glyphBuffer.isEmpty());
- EXPECT_EQ(0u, glyphBuffer.size());
-}
-
-TEST(GlyphBufferTest, TracksVerticalAdvances)
-{
- RefPtr<SimpleFontData> font = TestSimpleFontData::create();
- GlyphBuffer glyphBuffer;
- EXPECT_FALSE(glyphBuffer.hasVerticalAdvances());
- glyphBuffer.add(42, font.get(), 10);
- EXPECT_FALSE(glyphBuffer.hasVerticalAdvances());
- glyphBuffer.add(43, font.get(), FloatSize(15, 0));
- EXPECT_FALSE(glyphBuffer.hasVerticalAdvances());
- glyphBuffer.add(44, font.get(), FloatSize(10, 5));
- EXPECT_TRUE(glyphBuffer.hasVerticalAdvances());
- glyphBuffer.clear();
- EXPECT_FALSE(glyphBuffer.hasVerticalAdvances());
-}
-
-TEST(GlyphBufferTest, Reverse)
-{
- RefPtr<SimpleFontData> font1 = TestSimpleFontData::create();
- RefPtr<SimpleFontData> font2 = TestSimpleFontData::create();
-
- GlyphBuffer glyphBuffer;
- glyphBuffer.add(42, font1.get(), 10);
- glyphBuffer.add(43, font1.get(), 15);
- glyphBuffer.add(44, font2.get(), FloatSize(12, 2));
-
- EXPECT_FALSE(glyphBuffer.isEmpty());
- EXPECT_EQ(3u, glyphBuffer.size());
- EXPECT_TRUE(glyphBuffer.hasVerticalAdvances());
-
- glyphBuffer.reverse();
-
- EXPECT_FALSE(glyphBuffer.isEmpty());
- EXPECT_EQ(3u, glyphBuffer.size());
- EXPECT_TRUE(glyphBuffer.hasVerticalAdvances());
- EXPECT_EQ(44, glyphBuffer.glyphAt(0));
- EXPECT_EQ(43, glyphBuffer.glyphAt(1));
- EXPECT_EQ(42, glyphBuffer.glyphAt(2));
- EXPECT_EQ(FloatSize(12, 2), glyphBuffer.advanceAt(0));
- EXPECT_EQ(FloatSize(15, 0), glyphBuffer.advanceAt(1));
- EXPECT_EQ(FloatSize(10, 0), glyphBuffer.advanceAt(2));
- EXPECT_EQ(font2.get(), glyphBuffer.fontDataAt(0));
- EXPECT_EQ(font1.get(), glyphBuffer.fontDataAt(1));
- EXPECT_EQ(font1.get(), glyphBuffer.fontDataAt(2));
-}
-
-TEST(GlyphBufferTest, SetAdvanceWidth)
-{
- RefPtr<SimpleFontData> font1 = TestSimpleFontData::create();
- RefPtr<SimpleFontData> font2 = TestSimpleFontData::create();
-
- GlyphBuffer glyphBuffer;
- glyphBuffer.add(42, font1.get(), 10);
- glyphBuffer.add(43, font1.get(), 15);
- glyphBuffer.add(44, font2.get(), FloatSize(12, 2));
-
- glyphBuffer.setAdvanceWidth(1, 20);
- EXPECT_EQ(FloatSize(20, 0), glyphBuffer.advanceAt(1));
-
- glyphBuffer.setAdvanceWidth(2, 10);
- EXPECT_EQ(FloatSize(10, 2), glyphBuffer.advanceAt(2));
-}
-
-TEST(GlyphBufferTest, ExpandLastAdvance)
-{
- RefPtr<SimpleFontData> font1 = TestSimpleFontData::create();
- RefPtr<SimpleFontData> font2 = TestSimpleFontData::create();
-
- GlyphBuffer glyphBuffer;
- glyphBuffer.add(42, font1.get(), 10);
- glyphBuffer.add(43, font1.get(), 15);
- glyphBuffer.add(44, font2.get(), FloatSize(12, 2));
-
- glyphBuffer.expandLastAdvance(20);
- EXPECT_EQ(FloatSize(32, 2), glyphBuffer.advanceAt(2));
-}
-
-} // namespace
diff --git a/sky/engine/platform/fonts/harfbuzz/FontHarfBuzz.cpp b/sky/engine/platform/fonts/harfbuzz/FontHarfBuzz.cpp
index 998b38b..af34cba 100644
--- a/sky/engine/platform/fonts/harfbuzz/FontHarfBuzz.cpp
+++ b/sky/engine/platform/fonts/harfbuzz/FontHarfBuzz.cpp
@@ -31,7 +31,7 @@
#include "sky/engine/config.h"
#include "sky/engine/platform/fonts/Font.h"
-#include "sky/engine/platform/NotImplemented.h"
+#include "gen/sky/platform/RuntimeEnabledFeatures.h"
#include "sky/engine/platform/fonts/FontPlatformFeatures.h"
#include "sky/engine/platform/fonts/GlyphBuffer.h"
#include "sky/engine/platform/fonts/SimpleFontData.h"
@@ -157,7 +157,7 @@
pos[i].set(
x + SkIntToScalar(lroundf(translations[i].x())),
y + -SkIntToScalar(-lroundf(currentWidth - translations[i].y())));
- currentWidth += glyphBuffer.advanceAt(from + glyphIndex).width();
+ currentWidth += glyphBuffer.advanceAt(from + glyphIndex);
}
horizontalOffset += currentWidth;
paintGlyphs(gc, font, glyphs, chunkLength, pos, textRect);
@@ -167,13 +167,13 @@
return;
}
- if (!glyphBuffer.hasVerticalAdvances()) {
+ if (!glyphBuffer.hasOffsets()) {
SkAutoSTMalloc<64, SkScalar> storage(numGlyphs);
SkScalar* xpos = storage.get();
- const FloatSize* adv = glyphBuffer.advances(from);
+ const float* adv = glyphBuffer.advances(from);
for (unsigned i = 0; i < numGlyphs; i++) {
xpos[i] = x;
- x += SkFloatToScalar(adv[i].width());
+ x += SkFloatToScalar(adv[i]);
}
const Glyph* glyphs = glyphBuffer.glyphs(from);
paintGlyphsHorizontal(gc, font, glyphs, numGlyphs, xpos, SkFloatToScalar(y), textRect);
@@ -188,11 +188,14 @@
// here.
SkAutoSTMalloc<32, SkPoint> storage(numGlyphs);
SkPoint* pos = storage.get();
- const FloatSize* adv = glyphBuffer.advances(from);
+ const FloatSize* offsets = glyphBuffer.offsets(from);
+ const float* advances = glyphBuffer.advances(from);
+ SkScalar advanceSoFar = SkFloatToScalar(0);
for (unsigned i = 0; i < numGlyphs; i++) {
- pos[i].set(x, y);
- x += SkFloatToScalar(adv[i].width());
- y += SkFloatToScalar(adv[i].height());
+ pos[i].set(
+ x + SkFloatToScalar(offsets[i].width()) + advanceSoFar,
+ y + SkFloatToScalar(offsets[i].height()));
+ advanceSoFar += SkFloatToScalar(advances[i]);
}
const Glyph* glyphs = glyphBuffer.glyphs(from);
@@ -201,69 +204,24 @@
void Font::drawTextBlob(GraphicsContext* gc, const SkTextBlob* blob, const SkPoint& origin) const
{
+ ASSERT(RuntimeEnabledFeatures::textBlobEnabled());
+
// FIXME: It would be good to move this to Font.cpp, if we're sure that none
// of the things in FontMac's setupPaint need to apply here.
// See also paintGlyphs.
TextDrawingModeFlags textMode = gc->textDrawingMode();
- if (textMode & TextModeFill) {
- SkPaint paint = gc->fillPaint();
- gc->adjustTextRenderMode(&paint);
- paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
- gc->drawTextBlob(blob, origin, paint);
- }
+ if (textMode & TextModeFill)
+ gc->drawTextBlob(blob, origin, gc->fillPaint());
if ((textMode & TextModeStroke) && gc->hasStroke()) {
SkPaint paint = gc->strokePaint();
- gc->adjustTextRenderMode(&paint);
- paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
if (textMode & TextModeFill)
paint.setLooper(0);
gc->drawTextBlob(blob, origin, paint);
}
}
-void Font::drawComplexText(GraphicsContext* gc, const TextRunPaintInfo& runInfo, const FloatPoint& point) const
-{
- if (!runInfo.run.length())
- return;
-
- TextDrawingModeFlags textMode = gc->textDrawingMode();
- bool fill = textMode & TextModeFill;
- bool stroke = (textMode & TextModeStroke) && gc->hasStroke();
-
- if (!fill && !stroke)
- return;
-
- GlyphBuffer glyphBuffer;
- HarfBuzzShaper shaper(this, runInfo.run);
- shaper.setDrawRange(runInfo.from, runInfo.to);
- if (!shaper.shape(&glyphBuffer) || glyphBuffer.isEmpty())
- return;
- FloatPoint adjustedPoint = shaper.adjustStartPoint(point);
- drawGlyphBuffer(gc, runInfo, glyphBuffer, adjustedPoint);
-}
-
-void Font::drawEmphasisMarksForComplexText(GraphicsContext* context, const TextRunPaintInfo& runInfo, const AtomicString& mark, const FloatPoint& point) const
-{
- GlyphBuffer glyphBuffer;
-
- float initialAdvance = getGlyphsAndAdvancesForComplexText(runInfo, glyphBuffer, ForTextEmphasis);
-
- if (glyphBuffer.isEmpty())
- return;
-
- drawEmphasisMarks(context, runInfo, glyphBuffer, mark, FloatPoint(point.x() + initialAdvance, point.y()));
-}
-
-float Font::getGlyphsAndAdvancesForComplexText(const TextRunPaintInfo& runInfo, GlyphBuffer& glyphBuffer, ForTextEmphasisOrNot forTextEmphasis) const
-{
- HarfBuzzShaper shaper(this, runInfo.run, HarfBuzzShaper::ForTextEmphasis);
- shaper.setDrawRange(runInfo.from, runInfo.to);
- shaper.shape(&glyphBuffer);
- return 0;
-}
-
float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts, IntRectExtent* glyphBounds) const
{
HarfBuzzShaper shaper(this, run, HarfBuzzShaper::NotForTextEmphasis, fallbackFonts);
@@ -299,27 +257,23 @@
return shaper.selectionRect(point, height, from, to);
}
-PassTextBlobPtr Font::buildTextBlob(const GlyphBuffer& glyphBuffer, float initialAdvance, const FloatRect& bounds) const
+namespace {
+
+template <bool hasOffsets>
+bool buildTextBlobInternal(const GlyphBuffer& glyphBuffer, SkScalar initialAdvance, SkTextBlobBuilder& builder)
{
- // FIXME: Except for setupPaint, this is not specific to FontHarfBuzz.
- // FIXME: Also implement the more general full-positioning path.
- ASSERT(!glyphBuffer.hasVerticalAdvances());
-
- SkTextBlobBuilder builder;
- SkScalar x = SkFloatToScalar(initialAdvance);
- SkRect skBounds = bounds;
-
+ SkScalar x = initialAdvance;
unsigned i = 0;
while (i < glyphBuffer.size()) {
const SimpleFontData* fontData = glyphBuffer.fontDataAt(i);
// FIXME: Handle vertical text.
if (fontData->platformData().orientation() == Vertical)
- return nullptr;
+ return false;
// FIXME: Handle SVG fonts.
if (fontData->isSVGFont())
- return nullptr;
+ return false;
// FIXME: FontPlatformData makes some decisions on the device scale
// factor, which is found via the GraphicsContext. This should be fixed
@@ -333,19 +287,43 @@
i++;
unsigned count = i - start;
- const SkTextBlobBuilder::RunBuffer& buffer = builder.allocRunPosH(paint, count, 0, &skBounds);
+ const SkTextBlobBuilder::RunBuffer& buffer = hasOffsets ?
+ builder.allocRunPos(paint, count) :
+ builder.allocRunPosH(paint, count, 0);
const uint16_t* glyphs = glyphBuffer.glyphs(start);
std::copy(glyphs, glyphs + count, buffer.glyphs);
- const FloatSize* advances = glyphBuffer.advances(start);
+ const float* advances = glyphBuffer.advances(start);
+ const FloatSize* offsets = glyphBuffer.offsets(start);
for (unsigned j = 0; j < count; j++) {
- buffer.pos[j] = x;
- x += SkFloatToScalar(advances[j].width());
+ if (hasOffsets) {
+ const FloatSize& offset = offsets[j];
+ buffer.pos[2 * j] = x + offset.width();
+ buffer.pos[2 * j + 1] = offset.height();
+ } else {
+ buffer.pos[j] = x;
+ }
+ x += SkFloatToScalar(advances[j]);
}
}
-
- return adoptRef(builder.build());
+ return true;
}
+} // namespace
+
+PassTextBlobPtr Font::buildTextBlob(const GlyphBuffer& glyphBuffer, float initialAdvance, const FloatRect& bounds) const
+{
+ ASSERT(RuntimeEnabledFeatures::textBlobEnabled());
+
+ SkTextBlobBuilder builder;
+ SkScalar advance = SkFloatToScalar(initialAdvance);
+
+ bool success = glyphBuffer.hasOffsets() ?
+ buildTextBlobInternal<true>(glyphBuffer, advance, builder) :
+ buildTextBlobInternal<false>(glyphBuffer, advance, builder);
+ return success ? adoptRef(builder.build()) : nullptr;
+}
+
+
} // namespace blink
diff --git a/sky/engine/platform/fonts/harfbuzz/HarfBuzzShaper.cpp b/sky/engine/platform/fonts/harfbuzz/HarfBuzzShaper.cpp
index 34fc737..1a3da20 100644
--- a/sky/engine/platform/fonts/harfbuzz/HarfBuzzShaper.cpp
+++ b/sky/engine/platform/fonts/harfbuzz/HarfBuzzShaper.cpp
@@ -278,7 +278,7 @@
{
m_glyphs[index] = glyphId;
m_advances[index] = advance;
- m_offsets[index] = FloatPoint(offsetX, offsetY);
+ m_offsets[index] = FloatSize(offsetX, offsetY);
}
int HarfBuzzShaper::HarfBuzzRun::characterIndexForXPosition(float targetX)
@@ -571,11 +571,6 @@
return true;
}
-FloatPoint HarfBuzzShaper::adjustStartPoint(const FloatPoint& point)
-{
- return point + m_startOffset;
-}
-
static inline int handleMultipleUChar(
UChar32 character,
unsigned clusterLength,
@@ -950,29 +945,35 @@
m_totalWidth += currentRun->width();
}
-void HarfBuzzShaper::fillGlyphBufferFromHarfBuzzRun(GlyphBuffer* glyphBuffer, HarfBuzzRun* currentRun, FloatPoint& firstOffsetOfNextRun)
+void HarfBuzzShaper::fillGlyphBufferFromHarfBuzzRun(GlyphBuffer* glyphBuffer, HarfBuzzRun* currentRun, float& carryAdvance)
{
- FloatPoint* offsets = currentRun->offsets();
+ FloatSize* offsets = currentRun->offsets();
uint16_t* glyphs = currentRun->glyphs();
float* advances = currentRun->advances();
unsigned numGlyphs = currentRun->numGlyphs();
uint16_t* glyphToCharacterIndexes = currentRun->glyphToCharacterIndexes();
- for (unsigned i = 0; i < numGlyphs; ++i) {
- uint16_t currentCharacterIndex = currentRun->startIndex() + glyphToCharacterIndexes[i];
- FloatPoint& currentOffset = offsets[i];
- FloatPoint& nextOffset = (i == numGlyphs - 1) ? firstOffsetOfNextRun : offsets[i + 1];
- float glyphAdvanceX = advances[i] + nextOffset.x() - currentOffset.x();
- float glyphAdvanceY = nextOffset.y() - currentOffset.y();
- if (m_run.rtl()) {
- if (currentCharacterIndex >= m_toIndex)
- m_startOffset.move(glyphAdvanceX, glyphAdvanceY);
- else if (currentCharacterIndex >= m_fromIndex)
- glyphBuffer->add(glyphs[i], currentRun->fontData(), FloatSize(glyphAdvanceX, glyphAdvanceY));
- } else {
- if (currentCharacterIndex < m_fromIndex)
- m_startOffset.move(glyphAdvanceX, glyphAdvanceY);
- else if (currentCharacterIndex < m_toIndex)
- glyphBuffer->add(glyphs[i], currentRun->fontData(), FloatSize(glyphAdvanceX, glyphAdvanceY));
+ FloatSize runStartOffset = FloatSize();
+ if (m_run.rtl()) {
+ for (unsigned i = 0; i < numGlyphs; ++i) {
+ uint16_t currentCharacterIndex = currentRun->startIndex() + glyphToCharacterIndexes[i];
+ if (currentCharacterIndex >= m_toIndex) {
+ carryAdvance += advances[i];
+ } else if (currentCharacterIndex >= m_fromIndex) {
+ runStartOffset = HB_DIRECTION_IS_HORIZONTAL(currentRun->direction()) ? FloatSize(carryAdvance, 0) : FloatSize(0, carryAdvance);
+ glyphBuffer->add(glyphs[i], currentRun->fontData(), runStartOffset + offsets[i], carryAdvance + advances[i]);
+ carryAdvance = 0;
+ }
+ }
+ } else {
+ for (unsigned i = 0; i < numGlyphs; ++i) {
+ uint16_t currentCharacterIndex = currentRun->startIndex() + glyphToCharacterIndexes[i];
+ if (currentCharacterIndex < m_fromIndex) {
+ carryAdvance += advances[i];
+ } else if (currentCharacterIndex < m_toIndex) {
+ runStartOffset = HB_DIRECTION_IS_HORIZONTAL(currentRun->direction()) ? FloatSize(carryAdvance, 0) : FloatSize(0, carryAdvance);
+ glyphBuffer->add(glyphs[i], currentRun->fontData(), runStartOffset + offsets[i], carryAdvance + advances[i]);
+ carryAdvance = 0;
+ }
}
}
}
@@ -1034,33 +1035,30 @@
bool HarfBuzzShaper::fillGlyphBuffer(GlyphBuffer* glyphBuffer)
{
unsigned numRuns = m_harfBuzzRuns.size();
+ float carryAdvance = 0;
if (m_run.rtl()) {
- m_startOffset = m_harfBuzzRuns.last()->offsets()[0];
for (int runIndex = numRuns - 1; runIndex >= 0; --runIndex) {
HarfBuzzRun* currentRun = m_harfBuzzRuns[runIndex].get();
if (!currentRun->hasGlyphToCharacterIndexes()) {
// FIXME: bug 337886, 359664
continue;
}
- FloatPoint firstOffsetOfNextRun = !runIndex ? FloatPoint() : m_harfBuzzRuns[runIndex - 1]->offsets()[0];
if (m_forTextEmphasis == ForTextEmphasis)
fillGlyphBufferForTextEmphasis(glyphBuffer, currentRun);
else
- fillGlyphBufferFromHarfBuzzRun(glyphBuffer, currentRun, firstOffsetOfNextRun);
+ fillGlyphBufferFromHarfBuzzRun(glyphBuffer, currentRun, carryAdvance);
}
} else {
- m_startOffset = m_harfBuzzRuns.first()->offsets()[0];
for (unsigned runIndex = 0; runIndex < numRuns; ++runIndex) {
HarfBuzzRun* currentRun = m_harfBuzzRuns[runIndex].get();
if (!currentRun->hasGlyphToCharacterIndexes()) {
// FIXME: bug 337886, 359664
continue;
}
- FloatPoint firstOffsetOfNextRun = runIndex == numRuns - 1 ? FloatPoint() : m_harfBuzzRuns[runIndex + 1]->offsets()[0];
if (m_forTextEmphasis == ForTextEmphasis)
fillGlyphBufferForTextEmphasis(glyphBuffer, currentRun);
else
- fillGlyphBufferFromHarfBuzzRun(glyphBuffer, currentRun, firstOffsetOfNextRun);
+ fillGlyphBufferFromHarfBuzzRun(glyphBuffer, currentRun, carryAdvance);
}
}
return glyphBuffer->size();
diff --git a/sky/engine/platform/fonts/harfbuzz/HarfBuzzShaper.h b/sky/engine/platform/fonts/harfbuzz/HarfBuzzShaper.h
index 8e968a6..581737c 100644
--- a/sky/engine/platform/fonts/harfbuzz/HarfBuzzShaper.h
+++ b/sky/engine/platform/fonts/harfbuzz/HarfBuzzShaper.h
@@ -60,7 +60,6 @@
void setDrawRange(int from, int to);
bool shape(GlyphBuffer* = 0);
- FloatPoint adjustStartPoint(const FloatPoint&);
float totalWidth() { return m_totalWidth; }
int offsetForPosition(float targetX);
FloatRect selectionRect(const FloatPoint&, int height, int from, int to);
@@ -90,7 +89,7 @@
unsigned numGlyphs() const { return m_numGlyphs; }
uint16_t* glyphs() { return &m_glyphs[0]; }
float* advances() { return &m_advances[0]; }
- FloatPoint* offsets() { return &m_offsets[0]; }
+ FloatSize* offsets() { return &m_offsets[0]; }
bool hasGlyphToCharacterIndexes() const
{
return m_glyphToCharacterIndexes.size() > 0;
@@ -116,7 +115,7 @@
Vector<uint16_t, 256> m_glyphs;
Vector<float, 256> m_advances;
Vector<uint16_t, 256> m_glyphToCharacterIndexes;
- Vector<FloatPoint, 256> m_offsets;
+ Vector<FloatSize, 256> m_offsets;
float m_width;
};
@@ -130,7 +129,7 @@
bool createHarfBuzzRuns();
bool shapeHarfBuzzRuns();
bool fillGlyphBuffer(GlyphBuffer*);
- void fillGlyphBufferFromHarfBuzzRun(GlyphBuffer*, HarfBuzzRun*, FloatPoint& firstOffsetOfNextRun);
+ void fillGlyphBufferFromHarfBuzzRun(GlyphBuffer*, HarfBuzzRun*, float& carryAdvance);
void fillGlyphBufferForTextEmphasis(GlyphBuffer*, HarfBuzzRun* currentRun);
void setGlyphPositionsForHarfBuzzRun(HarfBuzzRun*, hb_buffer_t*);
void addHarfBuzzRun(unsigned startCharacter, unsigned endCharacter, const SimpleFontData*, UScriptCode);
@@ -149,8 +148,6 @@
Vector<hb_feature_t, 4> m_features;
Vector<OwnPtr<HarfBuzzRun>, 16> m_harfBuzzRuns;
- FloatPoint m_startOffset;
-
int m_fromIndex;
int m_toIndex;
diff --git a/sky/engine/platform/graphics/GraphicsContext.cpp b/sky/engine/platform/graphics/GraphicsContext.cpp
index a0a8870..8323246 100644
--- a/sky/engine/platform/graphics/GraphicsContext.cpp
+++ b/sky/engine/platform/graphics/GraphicsContext.cpp
@@ -918,12 +918,10 @@
TextRunPaintInfo subrunInfo(subrun);
subrunInfo.bounds = runInfo.bounds;
- font.drawText(this, subrunInfo, currPoint, customFontNotReadyAction);
+ float runWidth = font.drawUncachedText(this, subrunInfo, currPoint, customFontNotReadyAction);
bidiRun = bidiRun->next();
- // FIXME: Have Font::drawText return the width of what it drew so that we don't have to re-measure here.
- if (bidiRun)
- currPoint.move(font.width(subrun), 0);
+ currPoint.move(runWidth, 0);
}
bidiRuns.deleteRuns();
diff --git a/sky/engine/platform/text/TextRun.h b/sky/engine/platform/text/TextRun.h
index f6329ad..285ba5b 100644
--- a/sky/engine/platform/text/TextRun.h
+++ b/sky/engine/platform/text/TextRun.h
@@ -32,6 +32,8 @@
#include "sky/engine/wtf/RefCounted.h"
#include "sky/engine/wtf/text/WTFString.h"
+class SkTextBlob;
+
namespace blink {
class FloatPoint;
@@ -245,6 +247,7 @@
: run(r)
, from(0)
, to(r.length())
+ , cachedTextBlob(nullptr)
{
}
@@ -252,6 +255,7 @@
int from;
int to;
FloatRect bounds;
+ RefPtr<const SkTextBlob>* cachedTextBlob;
};
}