From 74b390d6b136a60f1df15ac5ecd19bd8ad5a394b Mon Sep 17 00:00:00 2001 From: Hal Canary Date: Wed, 6 Jun 2018 13:29:51 +0000 Subject: [PATCH] Revert "Have draw(Text|PosText|PosTextH) use a single entry on the device" This reverts commit 4225b3220ef4bf50f0d9403f812ea94d50c4ee59. Reason for revert: made valgrind unhappy. Original change's description: > Have draw(Text|PosText|PosTextH) use a single entry on the device > > Handle the positioning of drawText at the canvas layer. Simplify > the code by removing similar implementations. > > Change-Id: I8b711783435072f560e29fca1dd934fa2e345ed2 > Reviewed-on: https://skia-review.googlesource.com/127131 > Reviewed-by: Ben Wagner > Commit-Queue: Herb Derby TBR=jvanverth@google.com,bungeman@google.com,herb@google.com Change-Id: I65c9d30ae6ecb1f87e8660e56d8f8ce5daab7551 No-Presubmit: true No-Tree-Checks: true No-Try: true Reviewed-on: https://skia-review.googlesource.com/132403 Reviewed-by: Hal Canary Commit-Queue: Hal Canary --- gn/core.gni | 2 - gn/tests.gni | 1 - src/core/SkBitmapDevice.cpp | 6 + src/core/SkBitmapDevice.h | 2 + src/core/SkCanvas.cpp | 21 +-- src/core/SkDevice.cpp | 30 +--- src/core/SkDevice.h | 12 +- src/core/SkDraw.cpp | 31 ++++ src/core/SkDraw.h | 2 + src/core/SkGlyphCache.cpp | 7 - src/core/SkGlyphCache.h | 3 - src/core/SkGlyphRun.cpp | 236 ------------------------------ src/core/SkGlyphRun.h | 72 --------- src/core/SkThreadedBMPDevice.cpp | 10 ++ src/core/SkThreadedBMPDevice.h | 3 + src/gpu/GrRenderTargetContext.cpp | 14 ++ src/gpu/GrRenderTargetContext.h | 3 + src/gpu/SkGpuDevice.cpp | 11 ++ src/gpu/SkGpuDevice.h | 2 + src/gpu/text/GrTextContext.cpp | 227 ++++++++++++++++++++++++---- src/gpu/text/GrTextContext.h | 28 ++++ src/pdf/SkPDFDevice.cpp | 6 + src/pdf/SkPDFDevice.h | 2 + src/svg/SkSVGDevice.cpp | 11 ++ src/svg/SkSVGDevice.h | 2 + src/xps/SkXPSDevice.cpp | 57 ++++++++ src/xps/SkXPSDevice.h | 2 + tests/GlyphRunTest.cpp | 20 --- tests/SVGDeviceTest.cpp | 15 +- 29 files changed, 412 insertions(+), 426 deletions(-) delete mode 100644 src/core/SkGlyphRun.cpp delete mode 100644 src/core/SkGlyphRun.h delete mode 100644 tests/GlyphRunTest.cpp diff --git a/gn/core.gni b/gn/core.gni index 99da62fe4a..123c6aa022 100644 --- a/gn/core.gni +++ b/gn/core.gni @@ -153,8 +153,6 @@ skia_core_sources = [ "$_src/core/SkGlyph.cpp", "$_src/core/SkGlyphCache.cpp", "$_src/core/SkGlyphCache.h", - "$_src/core/SkGlyphRun.cpp", - "$_src/core/SkGlyphRun.h", "$_src/core/SkGpuBlurUtils.h", "$_src/core/SkGpuBlurUtils.cpp", "$_src/core/SkGraphics.cpp", diff --git a/gn/tests.gni b/gn/tests.gni index 2655834d7b..a67b4f4e34 100644 --- a/gn/tests.gni +++ b/gn/tests.gni @@ -85,7 +85,6 @@ tests_sources = [ "$_tests/GeometryTest.cpp", "$_tests/GifTest.cpp", "$_tests/GLProgramsTest.cpp", - "$_tests/GlyphRunTest.cpp", "$_tests/GpuDrawPathTest.cpp", "$_tests/GpuLayerCacheTest.cpp", "$_tests/GpuRectanizerTest.cpp", diff --git a/src/core/SkBitmapDevice.cpp b/src/core/SkBitmapDevice.cpp index cbd9a7cc40..71b85af268 100644 --- a/src/core/SkBitmapDevice.cpp +++ b/src/core/SkBitmapDevice.cpp @@ -565,6 +565,12 @@ void SkBitmapDevice::drawSprite(const SkBitmap& bitmap, int x, int y, const SkPa BDDraw(this).drawSprite(bitmap, x, y, paint); } +void SkBitmapDevice::drawText(const void* text, size_t len, + SkScalar x, SkScalar y, const SkPaint& paint) { + SkBitmapDeviceFilteredSurfaceProps props(fBitmap, paint, fSurfaceProps); + LOOP_TILER( drawText((const char*)text, len, x, y, paint, &props()), nullptr) +} + void SkBitmapDevice::drawPosText(const void* text, size_t len, const SkScalar xpos[], int scalarsPerPos, const SkPoint& offset, const SkPaint& paint) { SkBitmapDeviceFilteredSurfaceProps props(fBitmap, paint, fSurfaceProps); diff --git a/src/core/SkBitmapDevice.h b/src/core/SkBitmapDevice.h index ba7846ca43..c36bc28713 100644 --- a/src/core/SkBitmapDevice.h +++ b/src/core/SkBitmapDevice.h @@ -111,6 +111,8 @@ protected: * Does not handle text decoration. * Decorations (underline and stike-thru) will be handled by SkCanvas. */ + void drawText(const void* text, size_t len, SkScalar x, SkScalar y, + const SkPaint&) override; void drawPosText(const void* text, size_t len, const SkScalar pos[], int scalarsPerPos, const SkPoint& offset, const SkPaint& paint) override; void drawVertices(const SkVertices*, SkBlendMode, const SkPaint&) override; diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp index dcff1b0cc3..8230fb3928 100644 --- a/src/core/SkCanvas.cpp +++ b/src/core/SkCanvas.cpp @@ -15,8 +15,6 @@ #include "SkDrawable.h" #include "SkDrawFilter.h" #include "SkDrawLooper.h" -#include "SkGlyphCache.h" -#include "SkGlyphRun.h" #include "SkImage.h" #include "SkImage_Base.h" #include "SkImageFilter.h" @@ -36,7 +34,6 @@ #include "SkRasterHandleAllocator.h" #include "SkRRect.h" #include "SkSpecialImage.h" -#include "SkStrikeCache.h" #include "SkString.h" #include "SkSurface_Base.h" #include "SkTextBlob.h" @@ -1078,8 +1075,7 @@ void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy stra const bool preserveLCDText = kOpaque_SkAlphaType == info.alphaType() || (saveLayerFlags & kPreserveLCDText_SaveLayerFlag); const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage; - const bool trackCoverage = - SkToBool(saveLayerFlags & kMaskAgainstCoverage_EXPERIMENTAL_DONT_USE_SaveLayerFlag); + const bool trackCoverage = SkToBool(saveLayerFlags & kMaskAgainstCoverage_EXPERIMENTAL_DONT_USE_SaveLayerFlag); const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo, preserveLCDText, trackCoverage, @@ -2443,13 +2439,10 @@ void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattic void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y, const SkPaint& paint) { - LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr) while (iter.next()) { - auto glyphRun = SkGlyphRun::MakeFromDrawText( - looper.paint(), text, byteLength, SkPoint::Make(x, y)); - iter.fDevice->drawGlyphRun(looper.paint(), &glyphRun); + iter.fDevice->drawText(text, byteLength, x, y, looper.paint()); } LOOPER_END @@ -2457,12 +2450,12 @@ void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkSca void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[], const SkPaint& paint) { + SkPoint textOffset = SkPoint::Make(0, 0); LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr) while (iter.next()) { - auto glyphRun = SkGlyphRun::MakeFromDrawPosText(looper.paint(), text, byteLength, pos); - iter.fDevice->drawGlyphRun(looper.paint(), &glyphRun); + iter.fDevice->drawPosText(text, byteLength, &pos->fX, 2, textOffset, looper.paint()); } LOOPER_END @@ -2471,12 +2464,12 @@ void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[], SkScalar constY, const SkPaint& paint) { + SkPoint textOffset = SkPoint::Make(0, constY); + LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr) while (iter.next()) { - auto glyphRun = - SkGlyphRun::MakeFromDrawPosTextH(looper.paint(), text, byteLength, xpos, constY); - iter.fDevice->drawGlyphRun(looper.paint(), &glyphRun); + iter.fDevice->drawPosText(text, byteLength, xpos, 1, textOffset, looper.paint()); } LOOPER_END diff --git a/src/core/SkDevice.cpp b/src/core/SkDevice.cpp index 1bad6dba6e..35cfc9ab71 100644 --- a/src/core/SkDevice.cpp +++ b/src/core/SkDevice.cpp @@ -9,14 +9,12 @@ #include "SkColorFilter.h" #include "SkDraw.h" #include "SkDrawFilter.h" -#include "SkGlyphRun.h" #include "SkImageFilter.h" #include "SkImageFilterCache.h" #include "SkImagePriv.h" #include "SkImage_Base.h" #include "SkLatticeIter.h" #include "SkLocalMatrixShader.h" -#include "SkMakeUnique.h" #include "SkMatrixPriv.h" #include "SkPatchUtils.h" #include "SkPathMeasure.h" @@ -159,16 +157,9 @@ void SkBaseDevice::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, } switch (it.positioning()) { - case SkTextBlob::kDefault_Positioning: { - auto origin = SkPoint::Make(x + offset.x(), y + offset.y()); - auto glyphRun = - SkGlyphRun::MakeFromDrawText(runPaint, - (const char*) it.glyphs(), textLen, origin); - this->drawPosText( - it.glyphs(), textLen, glyphRun.getPositions(), 2, - SkPoint::Make(0, 0), runPaint); - } - break; + case SkTextBlob::kDefault_Positioning: + this->drawText(it.glyphs(), textLen, x + offset.x(), y + offset.y(), runPaint); + break; case SkTextBlob::kHorizontal_Positioning: this->drawPosText(it.glyphs(), textLen, it.pos(), 1, SkPoint::Make(x, y + offset.y()), runPaint); @@ -252,17 +243,6 @@ void SkBaseDevice::drawImageLattice(const SkImage* image, } } -void SkBaseDevice::drawGlyphRun(const SkPaint& paint, SkGlyphRun* info) { - SkPaint glyphPaint(paint); - glyphPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); - - auto glyphs = info->copyGlyphIDs(); - - this->drawPosText( - glyphs.get(), info->runSize() * 2, - info->getPositions(), 2, SkPoint::Make(0, 0), glyphPaint); -} - void SkBaseDevice::drawBitmapLattice(const SkBitmap& bitmap, const SkCanvas::Lattice& lattice, const SkRect& dst, const SkPaint& paint) { @@ -516,8 +496,6 @@ void SkBaseDevice::drawTextRSXform(const void* text, size_t len, SkPaint localPaint(paint); SkShader* shader = paint.getShader(); - SkScalar pos[2] = {0.0f, 0.0f}; - SkPoint origin = SkPoint::Make(0, 0); SkMatrix localM, currM; const void* stopText = (const char*)text + len; @@ -539,7 +517,7 @@ void SkBaseDevice::drawTextRSXform(const void* text, size_t len, } int subLen = proc((const char*)text); - this->drawPosText(text, subLen, pos, 2, origin, localPaint); + this->drawText(text, subLen, 0, 0, localPaint); text = (const char*)text + subLen; } } diff --git a/src/core/SkDevice.h b/src/core/SkDevice.h index d36dc4d6ab..40b9589ce5 100644 --- a/src/core/SkDevice.h +++ b/src/core/SkDevice.h @@ -17,7 +17,6 @@ class SkBitmap; class SkDrawFilter; struct SkDrawShadowRec; -class SkGlyphRun; class SkImageFilterCache; struct SkIRect; class SkMatrix; @@ -223,7 +222,11 @@ protected: * Does not handle text decoration. * Decorations (underline and stike-thru) will be handled by SkCanvas. */ - virtual void drawGlyphRun(const SkPaint& paint, SkGlyphRun* info); + virtual void drawText(const void* text, size_t len, + SkScalar x, SkScalar y, const SkPaint& paint) = 0; + virtual void drawPosText(const void* text, size_t len, + const SkScalar pos[], int scalarsPerPos, + const SkPoint& offset, const SkPaint& paint) = 0; virtual void drawVertices(const SkVertices*, SkBlendMode, const SkPaint&) = 0; virtual void drawShadow(const SkPath&, const SkDrawShadowRec&); @@ -346,10 +349,6 @@ private: friend class SkSurface_Raster; friend class DeviceTestingAccess; - virtual void drawPosText(const void* text, size_t len, - const SkScalar pos[], int scalarsPerPos, - const SkPoint& offset, const SkPaint& paint) = 0; - // used to change the backend's pixels (and possibly config/rowbytes) // but cannot change the width/height, so there should be no change to // any clip information. @@ -428,6 +427,7 @@ protected: void drawSprite(const SkBitmap&, int, int, const SkPaint&) override {} void drawBitmapRect(const SkBitmap&, const SkRect*, const SkRect&, const SkPaint&, SkCanvas::SrcRectConstraint) override {} + void drawText(const void*, size_t, SkScalar, SkScalar, const SkPaint&) override {} void drawPosText(const void*, size_t, const SkScalar[], int, const SkPoint&, const SkPaint&) override {} void drawDevice(SkBaseDevice*, int, int, const SkPaint&) override {} diff --git a/src/core/SkDraw.cpp b/src/core/SkDraw.cpp index e975ea2a4b..b7150f85f8 100644 --- a/src/core/SkDraw.cpp +++ b/src/core/SkDraw.cpp @@ -1537,6 +1537,37 @@ SkScalerContextFlags SkDraw::scalerContextFlags() const { return flags; } +void SkDraw::drawText(const char text[], size_t byteLength, SkScalar x, SkScalar y, + const SkPaint& paint, const SkSurfaceProps* props) const { + SkASSERT(byteLength == 0 || text != nullptr); + + SkDEBUGCODE(this->validate();) + + // nothing to draw + if (text == nullptr || byteLength == 0 || fRC->isEmpty()) { + return; + } + + // SkScalarRec doesn't currently have a way of representing hairline stroke and + // will fill if its frame-width is 0. + if (ShouldDrawTextAsPaths(paint, *fMatrix)) { + this->drawText_asPaths(text, byteLength, x, y, paint); + return; + } + + auto cache = SkStrikeCache::FindOrCreateStrikeExclusive( + paint, props, this->scalerContextFlags(), fMatrix); + + // The Blitter Choose needs to be live while using the blitter below. + SkAutoBlitterChoose blitterChooser(*this, nullptr, paint); + SkAAClipBlitterWrapper wrapper(*fRC, blitterChooser.get()); + DrawOneGlyph drawOneGlyph(*this, paint, cache.get(), wrapper.getBlitter()); + + SkFindAndPlaceGlyph::ProcessText( + paint.getTextEncoding(), text, byteLength, + {x, y}, *fMatrix, paint.getTextAlign(), cache.get(), drawOneGlyph); +} + ////////////////////////////////////////////////////////////////////////////// void SkDraw::drawPosText_asPaths(const char text[], size_t byteLength, const SkScalar pos[], diff --git a/src/core/SkDraw.h b/src/core/SkDraw.h index 266960eedd..eabccf0d8d 100644 --- a/src/core/SkDraw.h +++ b/src/core/SkDraw.h @@ -62,6 +62,8 @@ public: void drawBitmap(const SkBitmap&, const SkMatrix&, const SkRect* dstOrNull, const SkPaint&) const; void drawSprite(const SkBitmap&, int x, int y, const SkPaint&) const; + void drawText(const char text[], size_t byteLength, SkScalar x, + SkScalar y, const SkPaint& paint, const SkSurfaceProps*) const; void drawPosText(const char text[], size_t byteLength, const SkScalar pos[], int scalarsPerPosition, const SkPoint& offset, const SkPaint&, const SkSurfaceProps*) const; diff --git a/src/core/SkGlyphCache.cpp b/src/core/SkGlyphCache.cpp index 3734b96ee2..bf5f77c817 100644 --- a/src/core/SkGlyphCache.cpp +++ b/src/core/SkGlyphCache.cpp @@ -130,13 +130,6 @@ const SkGlyph& SkGlyphCache::getGlyphIDMetrics(uint16_t glyphID, SkFixed x, SkFi return *this->lookupByPackedGlyphID(packedGlyphID, kFull_MetricsType); } -void SkGlyphCache::getAdvances(SkSpan glyphIDs, SkPoint advances[]) { - for (ptrdiff_t i = 0; i < glyphIDs.size(); i++) { - auto glyph = this->getGlyphIDAdvance(glyphIDs[i]); - advances[i] = SkPoint::Make(glyph.fAdvanceX, glyph.fAdvanceY); - } -} - SkGlyph* SkGlyphCache::lookupByChar(SkUnichar charCode, MetricsType type, SkFixed x, SkFixed y) { SkPackedUnicharID id(charCode, x, y); CharGlyphRec* rec = this->getCharGlyphRec(id); diff --git a/src/core/SkGlyphCache.h b/src/core/SkGlyphCache.h index e904c6e5c7..2e7355779a 100644 --- a/src/core/SkGlyphCache.h +++ b/src/core/SkGlyphCache.h @@ -10,7 +10,6 @@ #include "SkArenaAlloc.h" #include "SkDescriptor.h" #include "SkGlyph.h" -#include "SkGlyphRun.h" #include "SkPaint.h" #include "SkTHash.h" #include "SkScalerContext.h" @@ -68,8 +67,6 @@ public: const SkGlyph& getUnicharMetrics(SkUnichar, SkFixed x, SkFixed y); const SkGlyph& getGlyphIDMetrics(uint16_t, SkFixed x, SkFixed y); - void getAdvances(SkSpan, SkPoint[]); - /** Return the glyphID for the specified Unichar. If the char has already been seen, use the existing cache entry. If not, ask the scalercontext to compute it for us. */ diff --git a/src/core/SkGlyphRun.cpp b/src/core/SkGlyphRun.cpp deleted file mode 100644 index a25b9afa8e..0000000000 --- a/src/core/SkGlyphRun.cpp +++ /dev/null @@ -1,236 +0,0 @@ -/* - * Copyright 2018 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "SkGlyphRun.h" - -#include -#include - -#include "SkDraw.h" -#include "SkGlyphCache.h" -#include "SkMakeUnique.h" -#include "SkMSAN.h" -#include "SkPaint.h" -#include "SkPaintPriv.h" -#include "SkStrikeCache.h" -#include "SkUtils.h" - -namespace { - -// A faster set implementation that does not need any initialization, and reading the set items -// is order the number of items, and not the size of the universe. -// This implementation is based on the paper by Briggs and Torczon, "An Efficient Representation -// for Sparse Sets" -class GlyphSet { -public: - GlyphSet(uint32_t glyphUniverseSize) - : fUniverseSize{glyphUniverseSize} - , fIndexes{skstd::make_unique_default(2 * glyphUniverseSize)} - , fUniqueGlyphIDs{&fIndexes[glyphUniverseSize]} { - SkASSERT(glyphUniverseSize <= (1 << 16)); - sk_msan_mark_initialized(fIndexes.get(), &fIndexes[glyphUniverseSize], "works with uninited"); - } - - uint16_t add(SkGlyphID glyphID) { - if (glyphID >= fUniverseSize) { - glyphID = kUndefGlyph; - } - auto index = fIndexes[glyphID]; - if (index < fUniqueCount && fUniqueGlyphIDs[index] == glyphID) { - return index; - } - - fUniqueGlyphIDs[fUniqueCount] = glyphID; - fIndexes[glyphID] = fUniqueCount; - fUniqueCount += 1; - return fUniqueCount - 1; - } - - std::tuple> uniqueGlyphIDs() const { - auto uniqueGlyphs = skstd::make_unique_default(fUniqueCount); - memcpy(uniqueGlyphs.get(), fUniqueGlyphIDs, fUniqueCount * sizeof(SkGlyphID)); - return std::make_tuple(fUniqueCount, std::move(uniqueGlyphs)); - } - -private: - static constexpr SkGlyphID kUndefGlyph{0}; - const uint32_t fUniverseSize; - uint16_t fUniqueCount{0}; - std::unique_ptr fIndexes; - SkGlyphID* fUniqueGlyphIDs; - }; - -template -bool is_aligned(const void* ptr) { - uintptr_t bits = reinterpret_cast(ptr); - return (bits & (alignof(T) - 1)) == 0; -} - -template -bool is_aligned_size(size_t size) { - return size % sizeof(T) == 0; -} - -SkTypeface::Encoding convert_encoding(SkPaint::TextEncoding encoding) { - switch (encoding) { - case SkPaint::kUTF8_TextEncoding: return SkTypeface::kUTF8_Encoding; - case SkPaint::kUTF16_TextEncoding: return SkTypeface::kUTF16_Encoding; - case SkPaint::kUTF32_TextEncoding: return SkTypeface::kUTF32_Encoding; - default: return SkTypeface::kUTF32_Encoding; - } -} - -using Core = std::tuple, - uint16_t, std::unique_ptr>; - -Core make_from_glyphids(size_t glyphCount, const SkGlyphID* glyphs, SkGlyphID maxGlyphID) { - if (glyphCount == 0) { return Core(0, nullptr, 0, nullptr); } - - GlyphSet glyphSet{maxGlyphID}; - - auto denseIndex = skstd::make_unique_default(glyphCount); - for (size_t i = 0; i < glyphCount; i++) { - denseIndex[i] = glyphSet.add(glyphs[i]); - } - - std::unique_ptr uniqueGlyphIDs; - uint16_t uniqueCount; - std::tie(uniqueCount, uniqueGlyphIDs) = glyphSet.uniqueGlyphIDs(); - - return Core(glyphCount, std::move(denseIndex), uniqueCount, std::move(uniqueGlyphIDs)); -} - -Core make_from_utfn(size_t byteLength, const void* utfN, const SkTypeface& typeface, - SkTypeface::Encoding encoding) { - auto count = SkUTFN_CountUnichars(encoding, utfN, byteLength); - - if (count <= 0) { - return Core(0, nullptr, 0, nullptr); - } - - auto glyphs = skstd::make_unique_default(count); - - // TODO: move to using cached version. - typeface.charsToGlyphs(utfN, encoding, glyphs.get(), count); - - return make_from_glyphids(count, glyphs.get(), typeface.countGlyphs()); -} - -Core make_core(const SkPaint& paint, const void* bytes, size_t byteLength) { - auto encoding = paint.getTextEncoding(); - auto typeface = SkPaintPriv::GetTypefaceOrDefault(paint); - if (encoding == SkPaint::kGlyphID_TextEncoding) { - return make_from_glyphids( - byteLength / 2, reinterpret_cast(bytes), typeface->countGlyphs()); - } else { - return make_from_utfn(byteLength, bytes, *typeface, convert_encoding(encoding)); - } -} - -} // namespace - -SkGlyphRun SkGlyphRun::MakeFromDrawText( - const SkPaint& paint, const void* bytes, size_t byteLength, - const SkPoint origin) { - size_t runSize; - std::unique_ptr denseIndex; - uint16_t uniqueSize; - std::unique_ptr uniqueGlyphIDs; - std::tie(runSize, denseIndex, uniqueSize, uniqueGlyphIDs) = make_core(paint, bytes, byteLength); - - if (runSize == 0) { return SkGlyphRun{}; } - - auto advances = skstd::make_unique_default(uniqueSize); - - { - auto cache = SkStrikeCache::FindOrCreateStrikeExclusive(paint); - cache->getAdvances(SkSpan{uniqueGlyphIDs.get(), uniqueSize}, advances.get()); - } - - auto positions = skstd::make_unique_default(runSize); - - SkPoint endOfLastGlyph = origin; - - for (size_t i = 0; i < runSize; i++) { - positions[i] = endOfLastGlyph; - endOfLastGlyph += advances[denseIndex[i]]; - } - - if (paint.getTextAlign() != SkPaint::kLeft_Align) { - SkVector len = endOfLastGlyph - origin; - if (paint.getTextAlign() == SkPaint::kCenter_Align) { - len.scale(SK_ScalarHalf); - } - for (size_t i = 0; i < runSize; i++) { - positions[i] -= len; - } - } - - return SkGlyphRun{ - runSize, std::move(denseIndex), std::move(positions), uniqueSize, std::move(uniqueGlyphIDs)}; -} - -SkGlyphRun SkGlyphRun::MakeFromDrawPosTextH( - const SkPaint& paint, const void* bytes, size_t byteLength, - const SkScalar xpos[], SkScalar constY) { - size_t runSize; - std::unique_ptr denseIndex; - uint16_t uniqueSize; - std::unique_ptr uniqueGlyphIDs; - std::tie(runSize, denseIndex, uniqueSize, uniqueGlyphIDs) = make_core(paint, bytes, byteLength); - - if (runSize == 0) { return SkGlyphRun{}; } - - auto positions = skstd::make_unique_default(runSize); - - for (size_t i = 0; i < runSize; i++) { - positions[i] = SkPoint::Make(xpos[i], constY); - } - - return SkGlyphRun{ - runSize, std::move(denseIndex), std::move(positions), uniqueSize, std::move(uniqueGlyphIDs)}; -} - -SkGlyphRun SkGlyphRun::MakeFromDrawPosText( - const SkPaint& paint, const void* bytes, size_t byteLength, - const SkPoint pos[]) { - size_t runSize; - std::unique_ptr denseIndex; - uint16_t uniqueSize; - std::unique_ptr uniqueGlyphIDs; - std::tie(runSize, denseIndex, uniqueSize, uniqueGlyphIDs) = make_core(paint, bytes, byteLength); - - if (runSize == 0) { return SkGlyphRun{}; } - - auto positions = skstd::make_unique_default(runSize); - - memcpy(positions.get(), pos, sizeof(SkPoint) * runSize); - - return SkGlyphRun{ - runSize, std::move(denseIndex), std::move(positions), uniqueSize, std::move(uniqueGlyphIDs)}; -} - -std::unique_ptr SkGlyphRun::copyGlyphIDs() const { - auto glyphs = skstd::make_unique_default(fRunSize); - - for (size_t i = 0; i < fRunSize; i++) { - glyphs[i] = fUniqueGlyphs[fDenseIndex[i]]; - } - - return glyphs; -} - -SkGlyphRun::SkGlyphRun(size_t runSize, - std::unique_ptr&& denseIndex, - std::unique_ptr&& positions, - uint16_t uniqueSize, - std::unique_ptr&& uniqueGlyphIDs) - : fDenseIndex{std::move(denseIndex)} - , fPositions{std::move(positions)} - , fUniqueGlyphs{std::move(uniqueGlyphIDs)} - , fRunSize{runSize} - , fUniqueSize{uniqueSize} { } diff --git a/src/core/SkGlyphRun.h b/src/core/SkGlyphRun.h deleted file mode 100644 index 17b4297208..0000000000 --- a/src/core/SkGlyphRun.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2018 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef SkGlyphRunInfo_DEFINED -#define SkGlyphRunInfo_DEFINED - -#include -#include - -#include "SkDescriptor.h" -#include "SkMask.h" -#include "SkPath.h" -#include "SkPoint.h" -#include "SkTypes.h" - -class SkGlyphRun { -public: - SkGlyphRun() = default; - SkGlyphRun(SkGlyphRun&&) = default; - static SkGlyphRun MakeFromDrawText( - const SkPaint& paint, const void* bytes, size_t byteLength, - SkPoint origin); - static SkGlyphRun MakeFromDrawPosTextH( - const SkPaint& paint, const void* bytes, size_t byteLength, - const SkScalar xpos[], SkScalar constY); - static SkGlyphRun MakeFromDrawPosText( - const SkPaint& paint, const void* bytes, size_t byteLength, - const SkPoint pos[]); - - size_t runSize() const { return fRunSize; } - uint16_t uniqueSize() const { return fUniqueSize; } - - // copyGlyphIDs is temporary glue to work with the existing system. Don't use with new code. - std::unique_ptr copyGlyphIDs() const; - const SkScalar* getPositions() const { - return reinterpret_cast(fPositions.get()); - } - -private: - SkGlyphRun(size_t runSize, - std::unique_ptr&& denseIndex, - std::unique_ptr&& positions, - uint16_t uniqueSize, - std::unique_ptr&& uniqueGlyphIDs); - - std::unique_ptr fDenseIndex; - std::unique_ptr fPositions; - std::unique_ptr fUniqueGlyphs; - const size_t fRunSize{0}; - const uint16_t fUniqueSize{0}; -}; - -template -class SkSpan { -public: - SkSpan(const T* ptr, size_t size) : fPtr{ptr}, fSize{size} {} - SkSpan(const std::vector& v) : fPtr{v.data()}, fSize{v.size()} {} - const T& operator [] (ptrdiff_t i) const { return fPtr[i]; } - const T* begin() const { return fPtr; } - const T* end() const { return fPtr + fSize; } - ptrdiff_t size() const { return fSize; } - -private: - const T* fPtr; - size_t fSize; -}; - -#endif // SkGlyphRunInfo_DEFINED diff --git a/src/core/SkThreadedBMPDevice.cpp b/src/core/SkThreadedBMPDevice.cpp index 10cd824205..b75e90d5e4 100644 --- a/src/core/SkThreadedBMPDevice.cpp +++ b/src/core/SkThreadedBMPDevice.cpp @@ -210,6 +210,16 @@ void SkThreadedBMPDevice::drawSprite(const SkBitmap& bitmap, int x, int y, const }); } +void SkThreadedBMPDevice::drawText(const void* text, size_t len, SkScalar x, SkScalar y, + const SkPaint& paint) { + char* clonedText = this->cloneArray((const char*)text, len); + SkRect drawBounds = SkRectPriv::MakeLargest(); // TODO tighter drawBounds + SkSurfaceProps prop(SkBitmapDeviceFilteredSurfaceProps(fBitmap, paint, this->surfaceProps())()); + fQueue.push(drawBounds, [=](SkArenaAlloc*, const DrawState& ds, const SkIRect& tileBounds){ + TileDraw(ds, tileBounds).drawText(clonedText, len, x, y, paint, &prop); + }); +} + void SkThreadedBMPDevice::drawPosText(const void* text, size_t len, const SkScalar xpos[], int scalarsPerPos, const SkPoint& offset, const SkPaint& paint) { char* clonedText = this->cloneArray((const char*)text, len); diff --git a/src/core/SkThreadedBMPDevice.h b/src/core/SkThreadedBMPDevice.h index 6defce5d8c..d9e27b449c 100644 --- a/src/core/SkThreadedBMPDevice.h +++ b/src/core/SkThreadedBMPDevice.h @@ -32,6 +32,9 @@ protected: void drawPath(const SkPath&, const SkPaint&, const SkMatrix* prePathMatrix, bool pathIsMutable) override; void drawSprite(const SkBitmap&, int x, int y, const SkPaint&) override; + + void drawText(const void* text, size_t len, SkScalar x, SkScalar y, + const SkPaint&) override; void drawPosText(const void* text, size_t len, const SkScalar pos[], int scalarsPerPos, const SkPoint& offset, const SkPaint& paint) override; void drawVertices(const SkVertices*, SkBlendMode, const SkPaint&) override; diff --git a/src/gpu/GrRenderTargetContext.cpp b/src/gpu/GrRenderTargetContext.cpp index a79f9d113d..e5bda32354 100644 --- a/src/gpu/GrRenderTargetContext.cpp +++ b/src/gpu/GrRenderTargetContext.cpp @@ -217,6 +217,20 @@ GrOpList* GrRenderTargetContext::getOpList() { return this->getRTOpList(); } +void GrRenderTargetContext::drawText(const GrClip& clip, const SkPaint& skPaint, + const SkMatrix& viewMatrix, const char text[], + size_t byteLength, SkScalar x, SkScalar y, + const SkIRect& clipBounds) { + ASSERT_SINGLE_OWNER + RETURN_IF_ABANDONED + SkDEBUGCODE(this->validate();) + GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawText", fContext); + + GrTextContext* atlasTextContext = this->drawingManager()->getTextContext(); + atlasTextContext->drawText(fContext, fTextTarget.get(), clip, skPaint, viewMatrix, + fSurfaceProps, text, byteLength, x, y, clipBounds); +} + void GrRenderTargetContext::drawPosText(const GrClip& clip, const SkPaint& paint, const SkMatrix& viewMatrix, const char text[], size_t byteLength, const SkScalar pos[], diff --git a/src/gpu/GrRenderTargetContext.h b/src/gpu/GrRenderTargetContext.h index d605314385..acbf963c06 100644 --- a/src/gpu/GrRenderTargetContext.h +++ b/src/gpu/GrRenderTargetContext.h @@ -63,6 +63,9 @@ public: // we could use GrPaint except that // * SkPaint->GrPaint conversion depends upon whether the glyphs are color or grayscale and // this can vary within a text run. + virtual void drawText(const GrClip&, const SkPaint&, const SkMatrix& viewMatrix, + const char text[], size_t byteLength, SkScalar x, SkScalar y, + const SkIRect& clipBounds); virtual void drawPosText(const GrClip&, const SkPaint&, const SkMatrix& viewMatrix, const char text[], size_t byteLength, const SkScalar pos[], int scalarsPerPosition, const SkPoint& offset, diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp index 210cefc7a7..06307a1af2 100644 --- a/src/gpu/SkGpuDevice.cpp +++ b/src/gpu/SkGpuDevice.cpp @@ -1611,6 +1611,17 @@ void SkGpuDevice::drawAtlas(const SkImage* atlas, const SkRSXform xform[], /////////////////////////////////////////////////////////////////////////////// +void SkGpuDevice::drawText(const void* text, + size_t byteLength, SkScalar x, SkScalar y, + const SkPaint& paint) { + ASSERT_SINGLE_OWNER + GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawText", fContext.get()); + SkDEBUGCODE(this->validate();) + + fRenderTargetContext->drawText(this->clip(), paint, this->ctm(), (const char*)text, byteLength, + x, y, this->devClipBounds()); +} + void SkGpuDevice::drawPosText(const void* text, size_t byteLength, const SkScalar pos[], int scalarsPerPos, const SkPoint& offset, const SkPaint& paint) { diff --git a/src/gpu/SkGpuDevice.h b/src/gpu/SkGpuDevice.h index 7c7030e1ab..d98dbffe1d 100644 --- a/src/gpu/SkGpuDevice.h +++ b/src/gpu/SkGpuDevice.h @@ -87,6 +87,8 @@ public: const SkPaint& paint, SkCanvas::SrcRectConstraint) override; void drawSprite(const SkBitmap& bitmap, int x, int y, const SkPaint& paint) override; + void drawText(const void* text, size_t len, SkScalar x, SkScalar y, + const SkPaint&) override; void drawPosText(const void* text, size_t len, const SkScalar pos[], int scalarsPerPos, const SkPoint& offset, const SkPaint&) override; void drawTextBlob(const SkTextBlob*, SkScalar x, SkScalar y, diff --git a/src/gpu/text/GrTextContext.cpp b/src/gpu/text/GrTextContext.cpp index 72926fe280..f662fa9c12 100644 --- a/src/gpu/text/GrTextContext.cpp +++ b/src/gpu/text/GrTextContext.cpp @@ -17,7 +17,6 @@ #include "SkFindAndPlaceGlyph.h" #include "SkGr.h" #include "SkGraphics.h" -#include "SkGlyphRun.h" #include "SkMakeUnique.h" #include "SkMaskFilterBase.h" #include "SkPaintPriv.h" @@ -210,17 +209,11 @@ void GrTextContext::regenerateTextBlob(GrTextBlob* cacheBlob, shaderCaps.supportsDistanceFieldText(), fOptions)) { switch (it.positioning()) { case SkTextBlob::kDefault_Positioning: { - auto origin = SkPoint::Make(x + offset.x(), y + offset.y()); - auto glyphRun = - SkGlyphRun::MakeFromDrawText(runPaint.skPaint(), - (const char*)it.glyphs(), textLen, origin); - - this->drawDFPosText(cacheBlob, run, glyphCache, props, runPaint, - scalerContextFlags, viewMatrix, (const char*)it.glyphs(), - textLen, glyphRun.getPositions(), 2, SkPoint::Make(0,0)); + this->drawDFText(cacheBlob, run, glyphCache, props, runPaint, scalerContextFlags, + viewMatrix, (const char*)it.glyphs(), textLen, x + offset.x(), + y + offset.y()); break; } - case SkTextBlob::kHorizontal_Positioning: { SkPoint dfOffset = SkPoint::Make(x, y + offset.y()); this->drawDFPosText(cacheBlob, run, glyphCache, props, runPaint, @@ -238,17 +231,11 @@ void GrTextContext::regenerateTextBlob(GrTextBlob* cacheBlob, } } else { switch (it.positioning()) { - case SkTextBlob::kDefault_Positioning: { - auto origin = SkPoint::Make(x + offset.x(), y + offset.y()); - auto glyphRun = - SkGlyphRun::MakeFromDrawText( - runPaint.skPaint(), (const char*) it.glyphs(), textLen, origin); - - this->DrawBmpPosText(cacheBlob, run, glyphCache, props, runPaint, - scalerContextFlags, viewMatrix, (const char*) it.glyphs(), - textLen, glyphRun.getPositions(), 2, SkPoint::Make(0, 0)); + case SkTextBlob::kDefault_Positioning: + DrawBmpText(cacheBlob, run, glyphCache, props, runPaint, scalerContextFlags, + viewMatrix, (const char*)it.glyphs(), textLen, x + offset.x(), + y + offset.y()); break; - } case SkTextBlob::kHorizontal_Positioning: DrawBmpPosText(cacheBlob, run, glyphCache, props, runPaint, scalerContextFlags, viewMatrix, (const char*)it.glyphs(), textLen, it.pos(), 1, @@ -264,6 +251,35 @@ void GrTextContext::regenerateTextBlob(GrTextBlob* cacheBlob, } } +inline sk_sp +GrTextContext::makeDrawTextBlob(GrTextBlobCache* blobCache, + GrGlyphCache* glyphCache, + const GrShaderCaps& shaderCaps, + const GrTextUtils::Paint& paint, + SkScalerContextFlags scalerContextFlags, + const SkMatrix& viewMatrix, + const SkSurfaceProps& props, + const char text[], size_t byteLength, + SkScalar x, SkScalar y) const { + int glyphCount = paint.skPaint().countText(text, byteLength); + if (!glyphCount) { + return nullptr; + } + sk_sp blob = blobCache->makeBlob(glyphCount, 1); + blob->initThrowawayBlob(viewMatrix, x, y); + blob->setRunPaintFlags(0, paint.skPaint().getFlags()); + + if (CanDrawAsDistanceFields(paint, viewMatrix, props, shaderCaps.supportsDistanceFieldText(), + fOptions)) { + this->drawDFText(blob.get(), 0, glyphCache, props, paint, scalerContextFlags, viewMatrix, + text, byteLength, x, y); + } else { + DrawBmpText(blob.get(), 0, glyphCache, props, paint, scalerContextFlags, viewMatrix, text, + byteLength, x, y); + } + return blob; +} + inline sk_sp GrTextContext::makeDrawPosTextBlob(GrTextBlobCache* blobCache, GrGlyphCache* glyphCache, @@ -295,6 +311,29 @@ GrTextContext::makeDrawPosTextBlob(GrTextBlobCache* blobCache, return blob; } +void GrTextContext::drawText(GrContext* context, GrTextUtils::Target* target, + const GrClip& clip, const SkPaint& skPaint, + const SkMatrix& viewMatrix, const SkSurfaceProps& props, + const char text[], size_t byteLength, SkScalar x, SkScalar y, + const SkIRect& regionClipBounds) { + if (context->contextPriv().abandoned()) { + return; + } + + auto glyphCache = context->contextPriv().getGlyphCache(); + auto textBlobCache = context->contextPriv().getTextBlobCache(); + + GrTextUtils::Paint paint(&skPaint, &target->colorSpaceInfo()); + sk_sp blob(this->makeDrawTextBlob( + textBlobCache, glyphCache, *context->contextPriv().caps()->shaderCaps(), paint, + ComputeScalerContextFlags(target->colorSpaceInfo()), viewMatrix, props, text, + byteLength, x, y)); + if (blob) { + blob->flush(target, props, fDistanceAdjustTable.get(), paint, + clip, viewMatrix, regionClipBounds, x, y); + } +} + void GrTextContext::drawPosText(GrContext* context, GrTextUtils::Target* target, const GrClip& clip, const SkPaint& skPaint, const SkMatrix& viewMatrix, const SkSurfaceProps& props, @@ -319,6 +358,41 @@ void GrTextContext::drawPosText(GrContext* context, GrTextUtils::Target* target, } } +void GrTextContext::DrawBmpText(GrTextBlob* blob, int runIndex, + GrGlyphCache* glyphCache, const SkSurfaceProps& props, + const GrTextUtils::Paint& paint, + SkScalerContextFlags scalerContextFlags, + const SkMatrix& viewMatrix, const char text[], + size_t byteLength, SkScalar x, SkScalar y) { + SkASSERT(byteLength == 0 || text != nullptr); + + // nothing to draw + if (text == nullptr || byteLength == 0) { + return; + } + + // Ensure the blob is set for bitmaptext + blob->setHasBitmap(); + + if (SkDraw::ShouldDrawTextAsPaths(paint, viewMatrix)) { + DrawBmpTextAsPaths(blob, runIndex, glyphCache, props, paint, scalerContextFlags, viewMatrix, + text, byteLength, x, y); + return; + } + + sk_sp currStrike; + auto cache = blob->setupCache(runIndex, props, scalerContextFlags, paint, &viewMatrix); + SkFindAndPlaceGlyph::ProcessText(paint.skPaint().getTextEncoding(), text, byteLength, {x, y}, + viewMatrix, paint.skPaint().getTextAlign(), cache.get(), + [&](const SkGlyph& glyph, SkPoint position, SkPoint rounding) { + position += rounding; + BmpAppendGlyph(blob, runIndex, glyphCache, &currStrike, + glyph, SkScalarFloorToScalar(position.fX), + SkScalarFloorToScalar(position.fY), + paint.filteredPremulColor(), cache.get(), + SK_Scalar1, false); + }); +} void GrTextContext::DrawBmpPosText(GrTextBlob* blob, int runIndex, GrGlyphCache* glyphCache, const SkSurfaceProps& props, @@ -358,6 +432,43 @@ void GrTextContext::DrawBmpPosText(GrTextBlob* blob, int runIndex, }); } +void GrTextContext::DrawBmpTextAsPaths(GrTextBlob* blob, int runIndex, + GrGlyphCache* glyphCache, + const SkSurfaceProps& props, + const GrTextUtils::Paint& origPaint, + SkScalerContextFlags scalerContextFlags, + const SkMatrix& viewMatrix, const char text[], + size_t byteLength, SkScalar x, SkScalar y) { + // nothing to draw + if (text == nullptr || byteLength == 0) { + return; + } + + // Temporarily jam in kFill, so we only ever ask for the raw outline from the cache. + SkPaint pathPaint(origPaint); + pathPaint.setStyle(SkPaint::kFill_Style); + pathPaint.setPathEffect(nullptr); + + GrTextUtils::PathTextIter iter(text, byteLength, pathPaint, true); + FallbackTextHelper fallbackTextHelper(viewMatrix, pathPaint, glyphCache, iter.getPathScale()); + + const SkGlyph* iterGlyph; + const SkPath* iterPath; + SkScalar xpos = 0; + const char* lastText = text; + while (iter.next(&iterGlyph, &iterPath, &xpos)) { + if (iterGlyph) { + SkPoint pos = SkPoint::Make(xpos + x, y); + fallbackTextHelper.appendText(*iterGlyph, iter.getText() - lastText, lastText, pos); + } else if (iterPath) { + blob->appendPathGlyph(runIndex, *iterPath, xpos + x, y, iter.getPathScale(), false); + } + lastText = iter.getText(); + } + + fallbackTextHelper.drawText(blob, runIndex, glyphCache, props, origPaint, scalerContextFlags); +} + void GrTextContext::DrawBmpPosTextAsPaths(GrTextBlob* blob, int runIndex, GrGlyphCache* glyphCache, const SkSurfaceProps& props, @@ -567,6 +678,74 @@ void GrTextContext::InitDistanceFieldPaint(GrTextBlob* blob, *flags = SkScalerContextFlags::kNone; } +void GrTextContext::drawDFText(GrTextBlob* blob, int runIndex, + GrGlyphCache* glyphCache, const SkSurfaceProps& props, + const GrTextUtils::Paint& paint, + SkScalerContextFlags scalerContextFlags, + const SkMatrix& viewMatrix, const char text[], + size_t byteLength, SkScalar x, SkScalar y) const { + SkASSERT(byteLength == 0 || text != nullptr); + + // nothing to draw + if (text == nullptr || byteLength == 0) { + return; + } + + const SkPaint& skPaint = paint.skPaint(); + SkPaint::GlyphCacheProc glyphCacheProc = + SkPaint::GetGlyphCacheProc(skPaint.getTextEncoding(), true); + + SkTArray positions; + + const char* textPtr = text; + SkScalar stopX = 0; + SkScalar stopY = 0; + + SkAutoDescriptor desc; + SkScalerContextEffects effects; + // We apply the fake-gamma by altering the distance in the shader, so we ignore the + // passed-in scaler context flags. (It's only used when we fall-back to bitmap text). + SkScalerContext::CreateDescriptorAndEffectsUsingPaint( + skPaint, &props, SkScalerContextFlags::kNone, nullptr, &desc, &effects); + auto typeface = SkPaintPriv::GetTypefaceOrDefault(skPaint); + + { + auto origPaintCache = + SkStrikeCache::FindOrCreateStrikeExclusive(*desc.getDesc(), effects, *typeface); + + const char* stop = text + byteLength; + while (textPtr < stop) { + // don't need x, y here, since all subpixel variants will have the + // same advance + const SkGlyph& glyph = glyphCacheProc(origPaintCache.get(), &textPtr); + + positions.push_back(stopX); + positions.push_back(stopY); + + stopX += SkFloatToScalar(glyph.fAdvanceX); + stopY += SkFloatToScalar(glyph.fAdvanceY); + } + SkASSERT(textPtr == stop); + } + + // now adjust starting point depending on alignment + SkScalar alignX = stopX; + SkScalar alignY = stopY; + if (skPaint.getTextAlign() == SkPaint::kCenter_Align) { + alignX = SkScalarHalf(alignX); + alignY = SkScalarHalf(alignY); + } else if (skPaint.getTextAlign() == SkPaint::kLeft_Align) { + alignX = 0; + alignY = 0; + } + x -= alignX; + y -= alignY; + SkPoint offset = SkPoint::Make(x, y); + + this->drawDFPosText(blob, runIndex, glyphCache, props, paint, scalerContextFlags, + viewMatrix, text, byteLength, positions.begin(), 2, offset); +} + void GrTextContext::drawDFPosText(GrTextBlob* blob, int runIndex, GrGlyphCache* glyphCache, const SkSurfaceProps& props, const GrTextUtils::Paint& paint, @@ -757,15 +936,11 @@ std::unique_ptr GrTextContext::createOp_TestingOnly(GrContext* context // right now we don't handle textblobs, nor do we handle drawPosText. Since we only intend to // test the text op with this unit test, that is okay. - - auto origin = SkPoint::Make(x, y); - auto glyphRun = SkGlyphRun::MakeFromDrawText(skPaint, text, textLen, origin); - - sk_sp blob(textContext->makeDrawPosTextBlob( + sk_sp blob(textContext->makeDrawTextBlob( context->contextPriv().getTextBlobCache(), glyphCache, *context->contextPriv().caps()->shaderCaps(), utilsPaint, GrTextContext::kTextBlobOpScalerContextFlags, viewMatrix, surfaceProps, text, - static_cast(textLen), glyphRun.getPositions(), 2, origin)); + static_cast(textLen), SkIntToScalar(x), SkIntToScalar(y))); return blob->test_makeOp(textLen, 0, 0, viewMatrix, x, y, utilsPaint, surfaceProps, textContext->dfAdjustTable(), rtc->textTarget()); diff --git a/src/gpu/text/GrTextContext.h b/src/gpu/text/GrTextContext.h index 7d31d84a05..3dab70ba9b 100644 --- a/src/gpu/text/GrTextContext.h +++ b/src/gpu/text/GrTextContext.h @@ -44,6 +44,9 @@ public: static std::unique_ptr Make(const Options& options); + void drawText(GrContext*, GrTextUtils::Target*, const GrClip&, const SkPaint&, + const SkMatrix& viewMatrix, const SkSurfaceProps&, const char text[], + size_t byteLength, SkScalar x, SkScalar y, const SkIRect& regionClipBounds); void drawPosText(GrContext*, GrTextUtils::Target*, const GrClip&, const SkPaint&, const SkMatrix& viewMatrix, const SkSurfaceProps&, const char text[], size_t byteLength, const SkScalar pos[], int scalarsPerPosition, @@ -120,6 +123,15 @@ private: static bool HasLCD(const SkTextBlob*); + sk_sp makeDrawTextBlob(GrTextBlobCache*, GrGlyphCache*, + const GrShaderCaps&, + const GrTextUtils::Paint&, + SkScalerContextFlags scalerContextFlags, + const SkMatrix& viewMatrix, + const SkSurfaceProps&, + const char text[], size_t byteLength, + SkScalar x, SkScalar y) const; + sk_sp makeDrawPosTextBlob(GrTextBlobCache*, GrGlyphCache*, const GrShaderCaps&, const GrTextUtils::Paint&, @@ -132,12 +144,23 @@ private: const SkPoint& offset) const; // Functions for appending BMP text to GrTextBlob + static void DrawBmpText(GrTextBlob*, int runIndex, GrGlyphCache*, + const SkSurfaceProps&, const GrTextUtils::Paint& paint, + SkScalerContextFlags scalerContextFlags, const SkMatrix& viewMatrix, + const char text[], size_t byteLength, SkScalar x, SkScalar y); + static void DrawBmpPosText(GrTextBlob*, int runIndex, GrGlyphCache*, const SkSurfaceProps&, const GrTextUtils::Paint& paint, SkScalerContextFlags scalerContextFlags, const SkMatrix& viewMatrix, const char text[], size_t byteLength, const SkScalar pos[], int scalarsPerPosition, const SkPoint& offset); + static void DrawBmpTextAsPaths(GrTextBlob*, int runIndex, GrGlyphCache*, + const SkSurfaceProps&, const GrTextUtils::Paint& paint, + SkScalerContextFlags scalerContextFlags, + const SkMatrix& viewMatrix, const char text[], + size_t byteLength, SkScalar x, SkScalar y); + static void DrawBmpPosTextAsPaths(GrTextBlob*, int runIndex, GrGlyphCache*, const SkSurfaceProps&, const GrTextUtils::Paint& paint, SkScalerContextFlags scalerContextFlags, @@ -147,6 +170,11 @@ private: const SkPoint& offset); // functions for appending distance field text + void drawDFText(GrTextBlob* blob, int runIndex, GrGlyphCache*, const SkSurfaceProps&, + const GrTextUtils::Paint& paint, SkScalerContextFlags scalerContextFlags, + const SkMatrix& viewMatrix, const char text[], size_t byteLength, SkScalar x, + SkScalar y) const; + void drawDFPosText(GrTextBlob* blob, int runIndex, GrGlyphCache*, const SkSurfaceProps&, const GrTextUtils::Paint& paint, SkScalerContextFlags scalerContextFlags, diff --git a/src/pdf/SkPDFDevice.cpp b/src/pdf/SkPDFDevice.cpp index f4c034e1ef..1cf649c1a1 100644 --- a/src/pdf/SkPDFDevice.cpp +++ b/src/pdf/SkPDFDevice.cpp @@ -1450,6 +1450,12 @@ void SkPDFDevice::internalDrawText( } } +void SkPDFDevice::drawText(const void* text, size_t len, + SkScalar x, SkScalar y, const SkPaint& paint) { + this->internalDrawText(text, len, nullptr, SkTextBlob::kDefault_Positioning, + SkPoint{x, y}, paint, nullptr, 0, nullptr); +} + void SkPDFDevice::drawPosText(const void* text, size_t len, const SkScalar pos[], int scalarsPerPos, const SkPoint& offset, const SkPaint& paint) { diff --git a/src/pdf/SkPDFDevice.h b/src/pdf/SkPDFDevice.h index 33d0e70e67..a9c0590bed 100644 --- a/src/pdf/SkPDFDevice.h +++ b/src/pdf/SkPDFDevice.h @@ -95,6 +95,8 @@ public: const SkRect& dst, const SkPaint&, SkCanvas::SrcRectConstraint) override; + void drawText(const void* text, size_t len, + SkScalar x, SkScalar y, const SkPaint&) override; void drawPosText(const void* text, size_t len, const SkScalar pos[], int scalarsPerPos, const SkPoint& offset, const SkPaint&) override; diff --git a/src/svg/SkSVGDevice.cpp b/src/svg/SkSVGDevice.cpp index 3462f7cd6b..e777f60e9f 100644 --- a/src/svg/SkSVGDevice.cpp +++ b/src/svg/SkSVGDevice.cpp @@ -936,6 +936,17 @@ void SkSVGDevice::drawBitmapRect(const SkBitmap& bm, const SkRect* srcOrNull, drawBitmapCommon(MxCp(&adjustedMatrix, cs), bm, paint); } +void SkSVGDevice::drawText(const void* text, size_t len, + SkScalar x, SkScalar y, const SkPaint& paint) { + AutoElement elem("text", fWriter, fResourceBucket.get(), MxCp(this), paint); + elem.addTextAttributes(paint); + + SVGTextBuilder builder(text, len, paint, SkPoint::Make(x, y), 0); + elem.addAttribute("x", builder.posX()); + elem.addAttribute("y", builder.posY()); + elem.addText(builder.text()); +} + void SkSVGDevice::drawPosText(const void* text, size_t len, const SkScalar pos[], int scalarsPerPos, const SkPoint& offset, const SkPaint& paint) { diff --git a/src/svg/SkSVGDevice.h b/src/svg/SkSVGDevice.h index 4784c7e238..222e55d83c 100644 --- a/src/svg/SkSVGDevice.h +++ b/src/svg/SkSVGDevice.h @@ -37,6 +37,8 @@ protected: const SkRect* srcOrNull, const SkRect& dst, const SkPaint& paint, SkCanvas::SrcRectConstraint) override; + void drawText(const void* text, size_t len, + SkScalar x, SkScalar y, const SkPaint& paint) override; void drawPosText(const void* text, size_t len, const SkScalar pos[], int scalarsPerPos, const SkPoint& offset, const SkPaint& paint) override; diff --git a/src/xps/SkXPSDevice.cpp b/src/xps/SkXPSDevice.cpp index ef5f48881d..29ee8f3eca 100644 --- a/src/xps/SkXPSDevice.cpp +++ b/src/xps/SkXPSDevice.cpp @@ -2047,6 +2047,63 @@ private: GlyphRun* const fXpsGlyphs; }; +void SkXPSDevice::drawText(const void* text, size_t byteLen, + SkScalar x, SkScalar y, + const SkPaint& paint) { + if (byteLen < 1) return; + + if (text_must_be_pathed(paint, this->ctm())) { + SkPath path; + paint.getTextPath(text, byteLen, x, y, &path); + this->drawPath(path, paint, nullptr, true); + //TODO: add automation "text" + return; + } + + TypefaceUse* typeface; + HRV(CreateTypefaceUse(paint, &typeface)); + + auto cache = + SkStrikeCache::FindOrCreateStrikeExclusive( + paint, &this->surfaceProps(), + SkScalerContextFlags::kNone, nullptr); + + // Advance width and offsets for glyphs measured in hundredths of the font em size + // (XPS Spec 5.1.3). + FLOAT centemPerUnit = 100.0f / SkScalarToFLOAT(paint.getTextSize()); + GlyphRun xpsGlyphs; + xpsGlyphs.setReserve(num_glyph_guess(paint.getTextEncoding(), + static_cast(text), byteLen)); + + ProcessOneGlyph processOneGlyph(centemPerUnit, typeface->glyphsUsed, &xpsGlyphs); + + SkFindAndPlaceGlyph::ProcessText( + paint.getTextEncoding(), static_cast(text), byteLen, + SkPoint{ x, y }, SkMatrix::I(), paint.getTextAlign(), cache.get(), processOneGlyph); + + if (xpsGlyphs.count() == 0) { + return; + } + + XPS_POINT origin = { + xpsGlyphs[0].horizontalOffset / centemPerUnit, + xpsGlyphs[0].verticalOffset / -centemPerUnit, + }; + xpsGlyphs[0].horizontalOffset = 0.0f; + xpsGlyphs[0].verticalOffset = 0.0f; + + HRV(AddGlyphs(this->fXpsFactory.get(), + this->fCurrentXpsCanvas.get(), + typeface, + nullptr, + xpsGlyphs.begin(), xpsGlyphs.count(), + &origin, + SkScalarToFLOAT(paint.getTextSize()), + XPS_STYLE_SIMULATION_NONE, + this->ctm(), + paint)); +} + void SkXPSDevice::drawPosText(const void* text, size_t byteLen, const SkScalar pos[], int scalarsPerPos, const SkPoint& offset, const SkPaint& paint) { diff --git a/src/xps/SkXPSDevice.h b/src/xps/SkXPSDevice.h index 81e881ea82..a5ee07634c 100644 --- a/src/xps/SkXPSDevice.h +++ b/src/xps/SkXPSDevice.h @@ -97,6 +97,8 @@ protected: const SkRect* srcOrNull, const SkRect& dst, const SkPaint& paint, SkCanvas::SrcRectConstraint) override; + void drawText(const void* text, size_t len, + SkScalar x, SkScalar y, const SkPaint& paint) override; void drawPosText(const void* text, size_t len, const SkScalar pos[], int scalarsPerPos, const SkPoint& offset, const SkPaint& paint) override; diff --git a/tests/GlyphRunTest.cpp b/tests/GlyphRunTest.cpp deleted file mode 100644 index cad01acef7..0000000000 --- a/tests/GlyphRunTest.cpp +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright 2018 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "SkGlyphRun.h" - -#include "Test.h" - -DEF_TEST(GlyphRunInfo, reporter) { - SkGlyphID glyphs[] = {100, 3, 240, 3, 234, 111, 3, 4, 10, 11}; - uint16_t count = SK_ARRAY_COUNT(glyphs); - - SkPaint paint; - paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); - - SkGlyphRun::MakeFromDrawText(paint, glyphs, count, SkPoint::Make(0, 0)); -} \ No newline at end of file diff --git a/tests/SVGDeviceTest.cpp b/tests/SVGDeviceTest.cpp index 6cf533fa1b..b55a35fc56 100644 --- a/tests/SVGDeviceTest.cpp +++ b/tests/SVGDeviceTest.cpp @@ -24,9 +24,6 @@ #include "SkSVGCanvas.h" #include "SkXMLWriter.h" -#if 0 -Using the new system where devices only gets glyphs causes this to fail because the font has no -glyph to unichar data. namespace { @@ -52,9 +49,6 @@ void check_text_node(skiatest::Reporter* reporter, REPORTER_ASSERT(reporter, textNode != nullptr); if (textNode != nullptr) { REPORTER_ASSERT(reporter, dom.getType(textNode) == SkDOM::kText_Type); - if (strcmp(expected, dom.getName(textNode)) != 0) { - SkDebugf("string fail %s == %s\n", expected, dom.getName(textNode)); - } REPORTER_ASSERT(reporter, strcmp(expected, dom.getName(textNode)) == 0); } @@ -72,9 +66,6 @@ void check_text_node(skiatest::Reporter* reporter, REPORTER_ASSERT(reporter, xpos[0] == offset.x()); } else { for (int i = 0; i < xposCount; ++i) { - if (xpos[i] != SkIntToScalar(expected[i])) { - SkDebugf("Bad xs %g == %g\n", xpos[i], SkIntToScalar(expected[i])); - } REPORTER_ASSERT(reporter, xpos[i] == SkIntToScalar(expected[i])); } } @@ -112,7 +103,7 @@ void test_whitespace_pos(skiatest::Reporter* reporter, std::unique_ptr svgCanvas = SkSVGCanvas::Make(SkRect::MakeWH(100, 100), &writer); svgCanvas->drawText(txt, len, offset.x(), offset.y(), paint); } - check_text_node(reporter, dom, dom.finishParsing(), offset, 2, expected); + check_text_node(reporter, dom, dom.finishParsing(), offset, 0, expected); { SkAutoTMalloc xpos(len); @@ -124,7 +115,7 @@ void test_whitespace_pos(skiatest::Reporter* reporter, std::unique_ptr svgCanvas = SkSVGCanvas::Make(SkRect::MakeWH(100, 100), &writer); svgCanvas->drawPosTextH(txt, len, xpos, offset.y(), paint); } - check_text_node(reporter, dom, dom.finishParsing(), offset, 2, expected); + check_text_node(reporter, dom, dom.finishParsing(), offset, 1, expected); { SkAutoTMalloc pos(len); @@ -141,7 +132,6 @@ void test_whitespace_pos(skiatest::Reporter* reporter, } - DEF_TEST(SVGDevice_whitespace_pos, reporter) { static const struct { const char* tst_in; @@ -163,7 +153,6 @@ DEF_TEST(SVGDevice_whitespace_pos, reporter) { test_whitespace_pos(reporter, tests[i].tst_in, tests[i].tst_out); } } -#endif void SetImageShader(SkPaint* paint, int imageWidth, int imageHeight, SkShader::TileMode xTile,