From f9cf1aa2cab8d9455542e20aa2f878e4871b54ca Mon Sep 17 00:00:00 2001 From: Herb Derby Date: Wed, 21 Apr 2021 10:57:25 -0400 Subject: [PATCH] add drawGlyphs for SkRSXform Add a drawGlyphs to SkCanvas that takes SkRSXform instead of positions. Update buffer sizing calculations to take SkRSXform buffers into account. Change-Id: I14529088199dcd0b1ae78b4605e1ba77fec2000e Reviewed-on: https://skia-review.googlesource.com/c/skia/+/399096 Reviewed-by: Ben Wagner Reviewed-by: Mike Reed Commit-Queue: Herb Derby --- gm/drawglyphs.cpp | 26 +++++++++++++++++-- include/core/SkCanvas.h | 23 ++++++++++++++++- src/core/SkCanvas.cpp | 44 +++++++++++++++++++++++-------- src/core/SkGlyphRun.cpp | 57 ++++++++++++++++++++++++++--------------- src/core/SkGlyphRun.h | 6 ++++- 5 files changed, 121 insertions(+), 35 deletions(-) diff --git a/gm/drawglyphs.cpp b/gm/drawglyphs.cpp index 895dd039b1..b830164c9a 100644 --- a/gm/drawglyphs.cpp +++ b/gm/drawglyphs.cpp @@ -9,7 +9,10 @@ #include "include/core/SkCanvas.h" #include "include/core/SkFont.h" #include "include/core/SkPaint.h" +#include "include/core/SkRSXform.h" #include "include/private/SkTDArray.h" +#include "src/core/SkSpan.h" +#include "src/core/SkZip.h" #include "tools/ToolUtils.h" static const char gText[] = "Call me Ishmael. Some years ago—never mind how long precisely"; @@ -21,7 +24,7 @@ public: fFont = SkFont(fTypeface); fFont.setSubpixel(true); fFont.setSize(18); - size_t txtLen = strlen(gText); + const size_t txtLen = strlen(gText); fGlyphCount = fFont.countText(gText, txtLen, SkTextEncoding::kUTF8); fGlyphs.append(fGlyphCount); @@ -29,6 +32,19 @@ public: fPositions.append(fGlyphCount); fFont.getPos(fGlyphs.begin(), fGlyphCount, fPositions.begin()); + auto positions = SkSpan(fPositions.begin(), fGlyphCount); + + fLength = positions.back().x() - positions.front().x(); + fRadius = fLength / SK_FloatPI; + fXforms.append(fGlyphCount); + + for (auto [xform, pos] : SkMakeZip(fXforms.begin(), positions)) { + const SkScalar lengthToGlyph = pos.x() - positions.front().x(); + const SkScalar angle = SK_FloatPI * (fLength - lengthToGlyph) / fLength; + const SkScalar cos = std::cos(angle); + const SkScalar sin = std::sin(angle); + xform = SkRSXform::Make(sin, cos, fRadius*cos, -fRadius*sin); + } } SkString onShortName() override { @@ -53,6 +69,9 @@ public: canvas->drawGlyphs(fGlyphCount, fGlyphs.begin(), fPositions.begin(), {50, 640}, fFont, SkPaint{}); + canvas->drawGlyphs(fGlyphCount, fGlyphs.begin(), fXforms.begin(), + {50 + fLength / 2, 160 + fRadius}, fFont, SkPaint{}); + // TODO: add tests for cluster versions of drawGlyphs. } @@ -60,8 +79,11 @@ private: sk_sp fTypeface; SkFont fFont; SkTDArray fGlyphs; - SkTDArray fPositions; + SkTDArray fPositions; + SkTDArray fXforms; int fGlyphCount; + SkScalar fRadius; + SkScalar fLength; }; DEF_GM(return new DrawGlyphsGM{};) diff --git a/include/core/SkCanvas.h b/include/core/SkCanvas.h index 4043503dcc..2bfc2d00c1 100644 --- a/include/core/SkCanvas.h +++ b/include/core/SkCanvas.h @@ -1782,10 +1782,31 @@ public: @param font typeface, text size and so, used to describe the text @param paint blend, color, and so on, used to draw */ - void drawGlyphs(int count, const SkGlyphID glyphs[], const SkPoint positions[], SkPoint origin, const SkFont& font, const SkPaint& paint); + /** Draws count glyphs, at positions relative to origin styled with font and paint. + + This function draw glyphs using the given scaling and rotations. They are positioned + relative to the given origin. It does not perform typeface fallback for glyphs not found + in the SkTypeface in font. + + The drawing obeys the current transform matrix and clipping. + + All elements of paint: SkPathEffect, SkMaskFilter, SkShader, + SkColorFilter, and SkImageFilter; apply to text. By + default, draws filled black glyphs. + + @param count number of glyphs to draw + @param glyphs the array of glyphIDs to draw + @param xforms where to draw and orient each glyph + @param origin the origin of all the positions + @param font typeface, text size and so, used to describe the text + @param paint blend, color, and so on, used to draw + */ + void drawGlyphs(int count, const SkGlyphID glyphs[], const SkRSXform xforms[], + SkPoint origin, const SkFont& font, const SkPaint& paint); + /** Draws SkTextBlob blob at (x, y), using clip, SkMatrix, and SkPaint paint. blob contains glyphs, their positions, and paint attributes specific to text: diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp index 836b23ee0e..9ec49d08cb 100644 --- a/src/core/SkCanvas.cpp +++ b/src/core/SkCanvas.cpp @@ -2283,6 +2283,27 @@ void SkCanvas::drawSimpleText(const void* text, size_t byteLength, SkTextEncodin } } +void SkCanvas::drawGlyphs(int count, const SkGlyphID* glyphs, const SkPoint* positions, + const uint32_t* clusters, int textByteCount, const char* utf8text, + SkPoint origin, const SkFont& font, const SkPaint& paint) { + if (count <= 0) { return; } + + SkGlyphRun glyphRun { + font, + SkSpan(positions, count), + SkSpan(glyphs, count), + SkSpan(utf8text, textByteCount), + SkSpan(clusters, count), + SkSpan() + }; + SkGlyphRunList glyphRunList { + glyphRun, + glyphRun.sourceBounds(paint).makeOffset(origin), + origin + }; + this->onDrawGlyphRunList(glyphRunList, paint); +} + void SkCanvas::drawGlyphs(int count, const SkGlyphID glyphs[], const SkPoint positions[], SkPoint origin, const SkFont& font, const SkPaint& paint) { if (count <= 0) { return; } @@ -2303,23 +2324,24 @@ void SkCanvas::drawGlyphs(int count, const SkGlyphID glyphs[], const SkPoint pos this->onDrawGlyphRunList(glyphRunList, paint); } -void SkCanvas::drawGlyphs(int count, const SkGlyphID* glyphs, const SkPoint* positions, - const uint32_t* clusters, int textByteCount, const char* utf8text, +void SkCanvas::drawGlyphs(int count, const SkGlyphID glyphs[], const SkRSXform xforms[], SkPoint origin, const SkFont& font, const SkPaint& paint) { if (count <= 0) { return; } + auto [positions, rotateScales] = fScratchGlyphRunBuilder->convertRSXForm(SkSpan(xforms, count)); + SkGlyphRun glyphRun { - font, - SkSpan(positions, count), - SkSpan(glyphs, count), - SkSpan(utf8text, textByteCount), - SkSpan(clusters, count), - SkSpan() + font, + positions, + SkSpan(glyphs, count), + SkSpan(), + SkSpan(), + rotateScales }; SkGlyphRunList glyphRunList { - glyphRun, - glyphRun.sourceBounds(paint).makeOffset(origin), - origin + glyphRun, + glyphRun.sourceBounds(paint).makeOffset(origin), + origin }; this->onDrawGlyphRunList(glyphRunList, paint); } diff --git a/src/core/SkGlyphRun.cpp b/src/core/SkGlyphRun.cpp index 258d759a8d..1256f1962a 100644 --- a/src/core/SkGlyphRun.cpp +++ b/src/core/SkGlyphRun.cpp @@ -145,19 +145,28 @@ sk_sp SkGlyphRunList::makeBlob() const { SkTextBlobBuilder builder; for (auto& run : *this) { SkTextBlobBuilder::RunBuffer buffer; - if (run.text().empty()) { - buffer = builder.allocRunPos(run.font(), run.runSize(), nullptr); + if (run.scaledRotations().empty()) { + if (run.text().empty()) { + buffer = builder.allocRunPos(run.font(), run.runSize(), nullptr); + } else { + buffer = builder.allocRunTextPos(run.font(), run.runSize(), run.text().size(), nullptr); + auto text = run.text(); + memcpy(buffer.utf8text, text.data(), text.size_bytes()); + auto clusters = run.clusters(); + memcpy(buffer.clusters, clusters.data(), clusters.size_bytes()); + } + auto positions = run.positions(); + memcpy(buffer.points(), positions.data(), positions.size_bytes()); } else { - buffer = builder.allocRunTextPos(run.font(), run.runSize(), run.text().size(), nullptr); - auto text = run.text(); - memcpy(buffer.utf8text, text.data(), text.size_bytes()); - auto clusters = run.clusters(); - memcpy(buffer.clusters, clusters.data(), clusters.size_bytes()); + buffer = builder.allocRunRSXform(run.font(), run.runSize()); + for (auto [xform, pos, sr] : SkMakeZip(buffer.xforms(), + run.positions(), + run.scaledRotations())) { + xform = SkRSXform::Make(sr.x(), sr.y(), pos.x(), pos.y()); + } } auto glyphIDs = run.glyphsIDs(); memcpy(buffer.glyphs, glyphIDs.data(), glyphIDs.size_bytes()); - auto positions = run.positions(); - memcpy(buffer.points(), positions.data(), positions.size_bytes()); } return builder.make(); } @@ -185,7 +194,7 @@ const SkGlyphRunList& SkGlyphRunBuilder::textToGlyphRunList( auto glyphIDs = textToGlyphIDs(font, bytes, byteLength, encoding); SkRect bounds = SkRect::MakeEmpty(); if (!glyphIDs.empty()) { - this->initialize(glyphIDs.size()); + this->prepareBuffers(glyphIDs.size(), 0); SkSpan positions = draw_text_positions(font, glyphIDs, {0, 0}, fPositions); this->makeGlyphRun(font, glyphIDs, @@ -258,14 +267,18 @@ const SkGlyphRunList& SkGlyphRunBuilder::blobToGlyphRunList( return this->makeGlyphRunList(&blob, blob.bounds().makeOffset(origin), origin); } -void SkGlyphRunBuilder::initialize(int totalRunSize) { - - if (totalRunSize > fMaxTotalRunSize) { - fMaxTotalRunSize = totalRunSize; - fPositions.reset(fMaxTotalRunSize); +std::tuple, SkSpan> +SkGlyphRunBuilder::convertRSXForm(SkSpan xforms) { + const int count = xforms.count(); + this->prepareBuffers(count, count); + auto positions = SkSpan(fPositions.get(), count); + auto scaledRotations = SkSpan(fScaledRotations.get(), count); + for (auto [pos, sr, xform] : SkMakeZip(positions, scaledRotations, xforms)) { + auto [scos, ssin, tx, ty] = xform; + pos = {tx, ty}; + sr = {scos, ssin}; } - - fGlyphRunListStorage.clear(); + return {positions, scaledRotations}; } void SkGlyphRunBuilder::initialize(const SkTextBlob& blob) { @@ -280,14 +293,18 @@ void SkGlyphRunBuilder::initialize(const SkTextBlob& blob) { } } + prepareBuffers(positionCount, rsxFormCount); +} + +void SkGlyphRunBuilder::prepareBuffers(int positionCount, int RSXFormCount) { if (positionCount > fMaxTotalRunSize) { fMaxTotalRunSize = positionCount; fPositions.reset(fMaxTotalRunSize); } - if (rsxFormCount > fMaxScaledRotations) { - fMaxScaledRotations = rsxFormCount; - fScaledRotations.reset(rsxFormCount); + if (RSXFormCount > fMaxScaledRotations) { + fMaxScaledRotations = RSXFormCount; + fScaledRotations.reset(RSXFormCount); } fGlyphRunListStorage.clear(); diff --git a/src/core/SkGlyphRun.h b/src/core/SkGlyphRun.h index 65aeb9568c..848e0f9449 100644 --- a/src/core/SkGlyphRun.h +++ b/src/core/SkGlyphRun.h @@ -14,6 +14,7 @@ #include "include/core/SkFont.h" #include "include/core/SkPaint.h" #include "include/core/SkPoint.h" +#include "include/core/SkRSXform.h" #include "include/core/SkTypes.h" #include "include/private/SkTemplates.h" #include "src/core/SkSpan.h" @@ -127,12 +128,15 @@ public: SkPoint origin, SkTextEncoding encoding = SkTextEncoding::kUTF8); const SkGlyphRunList& blobToGlyphRunList(const SkTextBlob& blob, SkPoint origin); + std::tuple, SkSpan> + convertRSXForm(SkSpan xforms); bool empty() const { return fGlyphRunListStorage.empty(); } private: - void initialize(int totalRunSize); void initialize(const SkTextBlob& blob); + void prepareBuffers(int positionCount, int RSXFormCount); + SkSpan textToGlyphIDs( const SkFont& font, const void* bytes, size_t byteLength, SkTextEncoding);