Redo drawTextRSXForm for glyph runs

Change-Id: Iec9ad6a2c91b16c4e25150902b433fc7aae68a33
Reviewed-on: https://skia-review.googlesource.com/142171
Reviewed-by: Mike Reed <reed@google.com>
Commit-Queue: Herb Derby <herb@google.com>
This commit is contained in:
Herb Derby 2018-07-18 13:41:15 -04:00 committed by Skia Commit-Bot
parent 8364706c02
commit 2eacff02f1
5 changed files with 95 additions and 49 deletions

View File

@ -2478,7 +2478,7 @@ void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPat
LOOPER_END LOOPER_END
} }
void SkCanvas::onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[], void SkCanvas::onDrawTextRSXform(const void* text, size_t len, const SkRSXform xform[],
const SkRect* cullRect, const SkPaint& paint) { const SkRect* cullRect, const SkPaint& paint) {
if (cullRect && this->quickReject(*cullRect)) { if (cullRect && this->quickReject(*cullRect)) {
return; return;
@ -2487,7 +2487,12 @@ void SkCanvas::onDrawTextRSXform(const void* text, size_t byteLength, const SkRS
LOOPER_BEGIN(paint, nullptr) LOOPER_BEGIN(paint, nullptr)
while (iter.next()) { while (iter.next()) {
iter.fDevice->drawTextRSXform(text, byteLength, xform, looper.paint()); fScratchGlyphRunBuilder->drawTextAtOrigin(paint, text, len);
auto list = fScratchGlyphRunBuilder->useGlyphRunList();
if (!list->empty()) {
auto glyphRun = (*list)[0];
iter.fDevice->drawGlyphRunRSXform(&glyphRun, xform);
}
} }
LOOPER_END LOOPER_END

View File

@ -476,55 +476,34 @@ void SkBaseDevice::drawTextOnPath(const void* text, size_t byteLength,
#include "SkUtils.h" #include "SkUtils.h"
void SkBaseDevice::drawTextRSXform(const void* text, size_t len, void SkBaseDevice::drawGlyphRunRSXform(SkGlyphRun* run, const SkRSXform* xform) {
const SkRSXform xform[], const SkPaint& paint) { const SkMatrix originalCTM = this->ctm();
SkPaint::TextEncoding textEncoding = paint.getTextEncoding(); sk_sp<SkShader> shader = sk_ref_sp(run->mutablePaint()->getShader());
const char* end = (const char*)text + len; auto perGlyph = [this, &xform, &originalCTM, shader] (
SkPaint localPaint(paint); SkGlyphRun* glyphRun, SkPaint* runPaint) {
SkShader* shader = paint.getShader(); SkMatrix ctm;
SkScalar pos[2] = {0.0f, 0.0f}; ctm.setRSXform(*xform++);
SkPoint origin = SkPoint::Make(0, 0);
SkMatrix localM, currM;
const void* stopText = (const char*)text + len;
while ((const char*)text < (const char*)stopText) {
localM.setRSXform(*xform++);
currM.setConcat(this->ctm(), localM);
SkAutoDeviceCTMRestore adc(this, currM);
// We want to rotate each glyph by the rsxform, but we don't want to rotate "space" // We want to rotate each glyph by the rsxform, but we don't want to rotate "space"
// (i.e. the shader that cares about the ctm) so we have to undo our little ctm trick // (i.e. the shader that cares about the ctm) so we have to undo our little ctm trick
// with a localmatrixshader so that the shader draws as if there was no change to the ctm. // with a localmatrixshader so that the shader draws as if there was no change to the ctm.
if (shader) { if (shader) {
SkMatrix inverse; SkMatrix inverse;
if (localM.invert(&inverse)) { if (ctm.invert(&inverse)) {
localPaint.setShader(shader->makeWithLocalMatrix(inverse)); runPaint->setShader(shader->makeWithLocalMatrix(inverse));
} else { } else {
localPaint.setShader(nullptr); // can't handle this xform runPaint->setShader(nullptr); // can't handle this xform
} }
} }
int subLen = 0;
switch (textEncoding) { ctm.setConcat(originalCTM, ctm);
case SkPaint::kUTF8_TextEncoding: this->setCTM(ctm);
subLen = SkUTF8_CountUTF8Bytes((const char*)text); SkGlyphRunList glyphRunList{glyphRun};
break; this->drawGlyphRunList(&glyphRunList);
case SkPaint::kUTF16_TextEncoding:
{
const uint16_t* ptr = (const uint16_t*)text;
(void)SkUTF16_NextUnichar(&ptr, (const uint16_t*)end);
subLen = SkToInt((const char*)ptr - (const char*)text);
}; };
break; run->eachGlyphToGlyphRun(perGlyph);
case SkPaint::kUTF32_TextEncoding: run->mutablePaint()->setShader(shader);
subLen = 4; this->setCTM(originalCTM);
break;
case SkPaint::kGlyphID_TextEncoding:
subLen = 2;
break;
}
this->drawPosText(text, subLen, pos, 2, origin, localPaint);
text = (const char*)text + subLen;
}
} }
////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////

View File

@ -16,8 +16,8 @@
class SkBitmap; class SkBitmap;
struct SkDrawShadowRec; struct SkDrawShadowRec;
class SkGlyphRun;
class SkGlyphRunList; class SkGlyphRunList;
class SkGlyphRunBuilder;
class SkImageFilterCache; class SkImageFilterCache;
struct SkIRect; struct SkIRect;
class SkMatrix; class SkMatrix;
@ -242,8 +242,7 @@ protected:
virtual void drawTextOnPath(const void* text, size_t len, const SkPath&, virtual void drawTextOnPath(const void* text, size_t len, const SkPath&,
const SkMatrix*, const SkPaint&); const SkMatrix*, const SkPaint&);
virtual void drawTextRSXform(const void* text, size_t len, const SkRSXform[], void drawGlyphRunRSXform(SkGlyphRun* run, const SkRSXform* xform);
const SkPaint&);
virtual void drawSpecial(SkSpecialImage*, int x, int y, const SkPaint&, virtual void drawSpecial(SkSpecialImage*, int x, int y, const SkPaint&,
SkImage* clipImage, const SkMatrix& clipMatrix); SkImage* clipImage, const SkMatrix& clipMatrix);

View File

@ -51,6 +51,31 @@ SkGlyphRun::SkGlyphRun(SkPaint&& runPaint,
, fClusters{clusters} , fClusters{clusters}
, fRunPaint{std::move(runPaint)} {} , fRunPaint{std::move(runPaint)} {}
void SkGlyphRun::eachGlyphToGlyphRun(SkGlyphRun::PerGlyph perGlyph) {
SkPaint paint{fRunPaint};
SkPoint point;
SkGlyphID glyphID;
SkGlyphRun run{
std::move(paint),
SkSpan<const uint16_t>{}, // No dense indices for now.
SkSpan<const SkPoint>{&point, 1},
SkSpan<const SkGlyphID>{&glyphID, 1},
SkSpan<const SkGlyphID>{},
SkSpan<const char>{},
SkSpan<const uint32_t>{}
};
auto runSize = fTemporaryShuntGlyphIDs.size();
auto runPaint = run.mutablePaint();
for (size_t i = 0; i < runSize; i++) {
glyphID = fTemporaryShuntGlyphIDs[i];
point = fPositions[i];
perGlyph(&run, runPaint);
}
}
void SkGlyphRun::temporaryShuntToDrawPosText(SkBaseDevice* device, SkPoint origin) { void SkGlyphRun::temporaryShuntToDrawPosText(SkBaseDevice* device, SkPoint origin) {
auto pos = (const SkScalar*) this->positions().data(); auto pos = (const SkScalar*) this->positions().data();
@ -74,6 +99,7 @@ void SkGlyphRun::filloutGlyphsAndPositions(SkGlyphID* glyphIDs, SkPoint* positio
} }
// -- SkGlyphRunList ------------------------------------------------------------------------------- // -- SkGlyphRunList -------------------------------------------------------------------------------
SkGlyphRunList::SkGlyphRunList() = default;
SkGlyphRunList::SkGlyphRunList( SkGlyphRunList::SkGlyphRunList(
const SkPaint& paint, const SkPaint& paint,
const SkTextBlob* blob, const SkTextBlob* blob,
@ -84,6 +110,12 @@ SkGlyphRunList::SkGlyphRunList(
, fOrigin{origin} , fOrigin{origin}
, fGlyphRuns{glyphRunList} { } , fGlyphRuns{glyphRunList} { }
SkGlyphRunList::SkGlyphRunList(SkGlyphRun* glyphRun)
: fOriginalPaint{nullptr}
, fOriginalTextBlob{nullptr}
, fOrigin{SkPoint::Make(0, 0)}
, fGlyphRuns{SkSpan<SkGlyphRun>{glyphRun, 1}} {}
uint64_t SkGlyphRunList::uniqueID() const { uint64_t SkGlyphRunList::uniqueID() const {
return fOriginalTextBlob != nullptr ? fOriginalTextBlob->uniqueID() return fOriginalTextBlob != nullptr ? fOriginalTextBlob->uniqueID()
: SK_InvalidUniqueID; : SK_InvalidUniqueID;
@ -166,6 +198,29 @@ SkSpan<const SkGlyphID> SkGlyphIDSet::uniquifyGlyphIDs(
} }
// -- SkGlyphRunBuilder ---------------------------------------------------------------------------- // -- SkGlyphRunBuilder ----------------------------------------------------------------------------
void SkGlyphRunBuilder::drawTextAtOrigin(
const SkPaint& paint, const void* bytes, size_t byteLength) {
auto glyphIDs = textToGlyphIDs(paint, bytes, byteLength);
if (!glyphIDs.empty()) {
this->initialize(glyphIDs.size());
}
auto positions = SkSpan<const SkPoint>{fPositions, glyphIDs.size()};
// Every glyph is at the origin.
sk_bzero((void *)positions.data(), positions.size_bytes());
this->makeGlyphRun(
paint,
glyphIDs,
positions,
SkSpan<const uint16_t>{}, // no dense indices for now.,
SkSpan<const SkGlyphID>{},
SkSpan<const char>{},
SkSpan<const uint32_t>{});
this->makeGlyphRunList(paint, nullptr, SkPoint::Make(0, 0));
}
void SkGlyphRunBuilder::drawText( void SkGlyphRunBuilder::drawText(
const SkPaint& paint, const void* bytes, size_t byteLength, SkPoint origin) { const SkPaint& paint, const void* bytes, size_t byteLength, SkPoint origin) {
auto glyphIDs = textToGlyphIDs(paint, bytes, byteLength); auto glyphIDs = textToGlyphIDs(paint, bytes, byteLength);

View File

@ -19,6 +19,7 @@
#include "SkTypes.h" #include "SkTypes.h"
class SkBaseDevice; class SkBaseDevice;
class SkGlyphRunList;
template <typename T> template <typename T>
class SkSpan { class SkSpan {
@ -55,6 +56,10 @@ public:
SkSpan<const char> text, SkSpan<const char> text,
SkSpan<const uint32_t> clusters); SkSpan<const uint32_t> clusters);
// A function that turns an SkGlyphRun into an SkGlyphRun for each glyph.
using PerGlyph = std::function<void (SkGlyphRun*, SkPaint*)>;
void eachGlyphToGlyphRun(PerGlyph perGlyph);
// The temporaryShunt calls are to allow inter-operating with existing code while glyph runs // The temporaryShunt calls are to allow inter-operating with existing code while glyph runs
// are developed. // are developed.
void temporaryShuntToDrawPosText(SkBaseDevice* device, SkPoint origin); void temporaryShuntToDrawPosText(SkBaseDevice* device, SkPoint origin);
@ -65,6 +70,7 @@ public:
size_t runSize() const { return fTemporaryShuntGlyphIDs.size(); } size_t runSize() const { return fTemporaryShuntGlyphIDs.size(); }
SkSpan<const SkPoint> positions() const { return fPositions; } SkSpan<const SkPoint> positions() const { return fPositions; }
const SkPaint& paint() const { return fRunPaint; } const SkPaint& paint() const { return fRunPaint; }
SkPaint* mutablePaint() { return &fRunPaint; }
private: private:
// //
@ -80,11 +86,11 @@ private:
// Original clusters from SkTextBlob if present. Will be empty if not present. // Original clusters from SkTextBlob if present. Will be empty if not present.
const SkSpan<const uint32_t> fClusters; const SkSpan<const uint32_t> fClusters;
// Paint for this run modified to have glyph encoding and left alignment. // Paint for this run modified to have glyph encoding and left alignment.
const SkPaint fRunPaint; SkPaint fRunPaint;
}; };
class SkGlyphRunList { class SkGlyphRunList {
const SkPaint* fOriginalPaint{nullptr}; const SkPaint* fOriginalPaint{nullptr}; // This should be deleted soon.
// The text blob is needed to hookup the call back that the SkTextBlob destructor calls. It // The text blob is needed to hookup the call back that the SkTextBlob destructor calls. It
// should be used for nothing else // should be used for nothing else
const SkTextBlob* fOriginalTextBlob{nullptr}; const SkTextBlob* fOriginalTextBlob{nullptr};
@ -92,7 +98,7 @@ class SkGlyphRunList {
SkSpan<SkGlyphRun> fGlyphRuns; SkSpan<SkGlyphRun> fGlyphRuns;
public: public:
SkGlyphRunList() = default; SkGlyphRunList();
// Blob maybe null. // Blob maybe null.
SkGlyphRunList( SkGlyphRunList(
const SkPaint& paint, const SkPaint& paint,
@ -100,6 +106,8 @@ public:
SkPoint origin, SkPoint origin,
SkSpan<SkGlyphRun> glyphRunList); SkSpan<SkGlyphRun> glyphRunList);
SkGlyphRunList(SkGlyphRun* glyphRun);
uint64_t uniqueID() const; uint64_t uniqueID() const;
bool anyRunsLCD() const; bool anyRunsLCD() const;
void temporaryShuntBlobNotifyAddedToCache(uint32_t cacheID) const; void temporaryShuntBlobNotifyAddedToCache(uint32_t cacheID) const;
@ -143,6 +151,7 @@ private:
class SkGlyphRunBuilder { class SkGlyphRunBuilder {
public: public:
void drawTextAtOrigin(const SkPaint& paint, const void* bytes, size_t byteLength);
void drawText( void drawText(
const SkPaint& paint, const void* bytes, size_t byteLength, SkPoint origin); const SkPaint& paint, const void* bytes, size_t byteLength, SkPoint origin);
void drawPosTextH( void drawPosTextH(
@ -152,7 +161,6 @@ public:
const SkPaint& paint, const void* bytes, size_t byteLength, const SkPoint* pos); const SkPaint& paint, const void* bytes, size_t byteLength, const SkPoint* pos);
void drawTextBlob(const SkPaint& paint, const SkTextBlob& blob, SkPoint origin); void drawTextBlob(const SkPaint& paint, const SkTextBlob& blob, SkPoint origin);
SkGlyphRun* useGlyphRun();
SkGlyphRunList* useGlyphRunList(); SkGlyphRunList* useGlyphRunList();
private: private: