Index: third_party/WebKit/Source/platform/fonts/Font.cpp |
diff --git a/third_party/WebKit/Source/platform/fonts/Font.cpp b/third_party/WebKit/Source/platform/fonts/Font.cpp |
index e858b6757e3a01b97499351bdf83ecc42631529b..131e11cdbfb94c15be4f44401d50df74666462cc 100644 |
--- a/third_party/WebKit/Source/platform/fonts/Font.cpp |
+++ b/third_party/WebKit/Source/platform/fonts/Font.cpp |
@@ -31,9 +31,9 @@ |
#include "platform/fonts/FontCache.h" |
#include "platform/fonts/FontFallbackIterator.h" |
#include "platform/fonts/FontFallbackList.h" |
-#include "platform/fonts/GlyphBuffer.h" |
#include "platform/fonts/SimpleFontData.h" |
#include "platform/fonts/shaping/CachingWordShaper.h" |
+#include "platform/fonts/shaping/ShapeResultBloberizer.h" |
#include "platform/geometry/FloatRect.h" |
#include "platform/graphics/paint/PaintCanvas.h" |
#include "platform/graphics/paint/PaintFlags.h" |
@@ -105,22 +105,29 @@ void Font::update(FontSelector* fontSelector) const { |
m_fontFallbackList->invalidate(fontSelector); |
} |
-float Font::buildGlyphBuffer(const TextRunPaintInfo& runInfo, |
- GlyphBuffer& glyphBuffer, |
- const GlyphData* emphasisData) const { |
- float width; |
- CachingWordShaper shaper(*this); |
- if (emphasisData) { |
- width = shaper.fillGlyphBufferForTextEmphasis(runInfo.run, |
- emphasisData, &glyphBuffer, |
- runInfo.from, runInfo.to); |
- } else { |
- width = shaper.fillGlyphBuffer(runInfo.run, &glyphBuffer, |
- runInfo.from, runInfo.to); |
+namespace { |
+ |
+void drawBlobs(PaintCanvas* canvas, |
+ const PaintFlags& flags, |
+ const ShapeResultBloberizer::BlobBuffer& blobs, |
+ const FloatPoint& point) { |
+ for (const auto& blobInfo : blobs) { |
+ DCHECK(blobInfo.blob); |
+ PaintCanvasAutoRestore autoRestore(canvas, false); |
+ if (blobInfo.rotation == ShapeResultBloberizer::BlobRotation::CCWRotation) { |
+ canvas->save(); |
+ |
+ SkMatrix m; |
+ m.setSinCos(-1, 0, point.x(), point.y()); |
+ canvas->concat(m); |
+ } |
+ |
+ canvas->drawTextBlob(blobInfo.blob, point.x(), point.y(), flags); |
} |
- return width; |
} |
+} // anonymous ns |
+ |
bool Font::drawText(PaintCanvas* canvas, |
const TextRunPaintInfo& runInfo, |
const FloatPoint& point, |
@@ -131,10 +138,9 @@ bool Font::drawText(PaintCanvas* canvas, |
if (shouldSkipDrawing()) |
return false; |
- GlyphBuffer glyphBuffer; |
- buildGlyphBuffer(runInfo, glyphBuffer); |
- |
- drawGlyphBuffer(canvas, flags, glyphBuffer, point, deviceScaleFactor); |
+ ShapeResultBloberizer bloberizer(*this, deviceScaleFactor); |
+ CachingWordShaper(*this).fillGlyphs(runInfo, bloberizer); |
+ drawBlobs(canvas, flags, bloberizer.blobs(), point); |
return true; |
} |
@@ -178,11 +184,10 @@ bool Font::drawBidiText(PaintCanvas* canvas, |
TextRunPaintInfo subrunInfo(subrun); |
subrunInfo.bounds = runInfo.bounds; |
- // TODO: investigate blob consolidation/caching (technically, |
- // all subruns could be part of the same blob). |
- GlyphBuffer glyphBuffer; |
- float runWidth = buildGlyphBuffer(subrunInfo, glyphBuffer); |
- drawGlyphBuffer(canvas, flags, glyphBuffer, currPoint, deviceScaleFactor); |
+ ShapeResultBloberizer bloberizer(*this, deviceScaleFactor); |
+ float runWidth = |
+ CachingWordShaper(*this).fillGlyphs(subrunInfo, bloberizer); |
+ drawBlobs(canvas, flags, bloberizer.blobs(), currPoint); |
bidiRun = bidiRun->next(); |
currPoint.move(runWidth, 0); |
@@ -207,13 +212,10 @@ void Font::drawEmphasisMarks(PaintCanvas* canvas, |
if (!emphasisGlyphData.fontData) |
return; |
- GlyphBuffer glyphBuffer; |
- buildGlyphBuffer(runInfo, glyphBuffer, &emphasisGlyphData); |
- |
- if (glyphBuffer.isEmpty()) |
- return; |
- |
- drawGlyphBuffer(canvas, flags, glyphBuffer, point, deviceScaleFactor); |
+ ShapeResultBloberizer bloberizer(*this, deviceScaleFactor); |
+ CachingWordShaper(*this).fillTextEmphasisGlyphs(runInfo, emphasisGlyphData, |
+ bloberizer); |
+ drawBlobs(canvas, flags, bloberizer.blobs(), point); |
} |
float Font::width(const TextRun& run, |
@@ -224,163 +226,29 @@ float Font::width(const TextRun& run, |
return shaper.width(run, fallbackFonts, glyphBounds); |
} |
-namespace { |
- |
-enum BlobRotation { |
- NoRotation, |
- CCWRotation, |
-}; |
- |
-class GlyphBufferBloberizer { |
- STACK_ALLOCATED() |
- public: |
- GlyphBufferBloberizer(const GlyphBuffer& buffer, |
- const Font* font, |
- float deviceScaleFactor) |
- : m_buffer(buffer), |
- m_font(font), |
- m_deviceScaleFactor(deviceScaleFactor), |
- m_hasVerticalOffsets(buffer.hasVerticalOffsets()), |
- m_index(0), |
- m_endIndex(m_buffer.size()), |
- m_rotation(buffer.isEmpty() ? NoRotation : computeBlobRotation( |
- buffer.fontDataAt(0))) {} |
- |
- bool done() const { return m_index >= m_endIndex; } |
- |
- std::pair<sk_sp<SkTextBlob>, BlobRotation> next() { |
- ASSERT(!done()); |
- const BlobRotation currentRotation = m_rotation; |
- |
- while (m_index < m_endIndex) { |
- const SimpleFontData* fontData = m_buffer.fontDataAt(m_index); |
- ASSERT(fontData); |
- |
- const BlobRotation newRotation = computeBlobRotation(fontData); |
- if (newRotation != m_rotation) { |
- // We're switching to an orientation which requires a different rotation |
- // => emit the pending blob (and start a new one with the new |
- // rotation). |
- m_rotation = newRotation; |
- break; |
- } |
- |
- const unsigned start = m_index++; |
- while (m_index < m_endIndex && m_buffer.fontDataAt(m_index) == fontData) |
- m_index++; |
- |
- appendRun(start, m_index - start, fontData); |
- } |
- |
- return std::make_pair(m_builder.make(), currentRotation); |
- } |
- |
- private: |
- static BlobRotation computeBlobRotation(const SimpleFontData* font) { |
- // For vertical upright text we need to compensate the inherited 90deg CW |
- // rotation (using a 90deg CCW rotation). |
- return (font->platformData().isVerticalAnyUpright() && font->verticalData()) |
- ? CCWRotation |
- : NoRotation; |
- } |
- |
- void appendRun(unsigned start, |
- unsigned count, |
- const SimpleFontData* fontData) { |
- SkPaint paint; |
- fontData->platformData().setupPaint(&paint, m_deviceScaleFactor, m_font); |
- paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); |
- |
- const SkTextBlobBuilder::RunBuffer& buffer = |
- m_hasVerticalOffsets ? m_builder.allocRunPos(paint, count) |
- : m_builder.allocRunPosH(paint, count, 0); |
- |
- const uint16_t* glyphs = m_buffer.glyphs(start); |
- const float* offsets = m_buffer.offsets(start); |
- std::copy(glyphs, glyphs + count, buffer.glyphs); |
- |
- if (m_rotation == NoRotation) { |
- std::copy(offsets, offsets + (m_hasVerticalOffsets ? 2 * count : count), |
- buffer.pos); |
- } else { |
- ASSERT(m_hasVerticalOffsets); |
- |
- const float verticalBaselineXOffset = |
- fontData->getFontMetrics().floatAscent() - |
- fontData->getFontMetrics().floatAscent(IdeographicBaseline); |
- |
- // TODO(fmalita): why don't we apply this adjustment when building the |
- // glyph buffer? |
- for (unsigned i = 0; i < 2 * count; i += 2) { |
- buffer.pos[i] = SkFloatToScalar(offsets[i] + verticalBaselineXOffset); |
- buffer.pos[i + 1] = SkFloatToScalar(offsets[i + 1]); |
- } |
- } |
- } |
- |
- const GlyphBuffer& m_buffer; |
- const Font* m_font; |
- const float m_deviceScaleFactor; |
- const bool m_hasVerticalOffsets; |
- |
- SkTextBlobBuilder m_builder; |
- unsigned m_index; |
- unsigned m_endIndex; |
- BlobRotation m_rotation; |
-}; |
- |
-} // anonymous namespace |
- |
-void Font::drawGlyphBuffer(PaintCanvas* canvas, |
- const PaintFlags& flags, |
- const GlyphBuffer& glyphBuffer, |
- const FloatPoint& point, |
- float deviceScaleFactor) const { |
- GlyphBufferBloberizer bloberizer(glyphBuffer, this, deviceScaleFactor); |
- |
- while (!bloberizer.done()) { |
- auto blob = bloberizer.next(); |
- ASSERT(blob.first); |
- |
- PaintCanvasAutoRestore autoRestore(canvas, false); |
- if (blob.second == CCWRotation) { |
- canvas->save(); |
- |
- SkMatrix m; |
- m.setSinCos(-1, 0, point.x(), point.y()); |
- canvas->concat(m); |
- } |
- |
- canvas->drawTextBlob(blob.first, point.x(), point.y(), flags); |
- } |
-} |
- |
-static int getInterceptsFromBloberizer(const GlyphBuffer& glyphBuffer, |
- const Font* font, |
- const SkPaint& paint, |
- float deviceScaleFactor, |
- const std::tuple<float, float>& bounds, |
- SkScalar* interceptsBuffer) { |
+static int getInterceptsFromBlobs( |
+ const ShapeResultBloberizer::BlobBuffer& blobs, |
+ const SkPaint& paint, |
+ const std::tuple<float, float>& bounds, |
+ SkScalar* interceptsBuffer) { |
SkScalar boundsArray[2] = {std::get<0>(bounds), std::get<1>(bounds)}; |
- GlyphBufferBloberizer bloberizer(glyphBuffer, font, deviceScaleFactor); |
int numIntervals = 0; |
- while (!bloberizer.done()) { |
- auto blob = bloberizer.next(); |
- DCHECK(blob.first); |
+ for (const auto& blobInfo : blobs) { |
+ DCHECK(blobInfo.blob); |
- // GlyphBufferBloberizer splits for a new blob rotation, but does not split |
+ // ShapeResultBloberizer splits for a new blob rotation, but does not split |
// for a change in font. A TextBlob can contain runs with differing fonts |
// and the getTextBlobIntercepts method handles multiple fonts for us. For |
// upright in vertical blobs we currently have to bail, see crbug.com/655154 |
- if (blob.second == BlobRotation::CCWRotation) |
+ if (blobInfo.rotation == ShapeResultBloberizer::BlobRotation::CCWRotation) |
continue; |
SkScalar* offsetInterceptsBuffer = nullptr; |
if (interceptsBuffer) |
offsetInterceptsBuffer = &interceptsBuffer[numIntervals]; |
- numIntervals += paint.getTextBlobIntercepts(blob.first.get(), boundsArray, |
- offsetInterceptsBuffer); |
+ numIntervals += paint.getTextBlobIntercepts( |
+ blobInfo.blob.get(), boundsArray, offsetInterceptsBuffer); |
} |
return numIntervals; |
} |
@@ -393,23 +261,23 @@ void Font::getTextIntercepts(const TextRunPaintInfo& runInfo, |
if (shouldSkipDrawing()) |
return; |
- GlyphBuffer glyphBuffer(GlyphBuffer::Type::TextIntercepts); |
- buildGlyphBuffer(runInfo, glyphBuffer); |
+ ShapeResultBloberizer bloberizer(*this, deviceScaleFactor, |
+ ShapeResultBloberizer::Type::TextIntercepts); |
+ CachingWordShaper(*this).fillGlyphs(runInfo, bloberizer); |
+ const auto& blobs = bloberizer.blobs(); |
// Get the number of intervals, without copying the actual values by |
// specifying nullptr for the buffer, following the Skia allocation model for |
// retrieving text intercepts. |
SkPaint paint(ToSkPaint(flags)); |
- int numIntervals = getInterceptsFromBloberizer( |
- glyphBuffer, this, paint, deviceScaleFactor, bounds, nullptr); |
+ int numIntervals = getInterceptsFromBlobs(blobs, paint, bounds, nullptr); |
if (!numIntervals) |
return; |
DCHECK_EQ(numIntervals % 2, 0); |
intercepts.resize(numIntervals / 2); |
- getInterceptsFromBloberizer(glyphBuffer, this, paint, deviceScaleFactor, |
- bounds, |
- reinterpret_cast<SkScalar*>(intercepts.data())); |
+ getInterceptsFromBlobs(blobs, paint, bounds, |
+ reinterpret_cast<SkScalar*>(intercepts.data())); |
} |
static inline FloatRect pixelSnappedSelectionRect(FloatRect rect) { |