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
}
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) {
if (cullRect && this->quickReject(*cullRect)) {
return;
@ -2487,7 +2487,12 @@ void SkCanvas::onDrawTextRSXform(const void* text, size_t byteLength, const SkRS
LOOPER_BEGIN(paint, nullptr)
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

View File

@ -476,55 +476,34 @@ void SkBaseDevice::drawTextOnPath(const void* text, size_t byteLength,
#include "SkUtils.h"
void SkBaseDevice::drawTextRSXform(const void* text, size_t len,
const SkRSXform xform[], const SkPaint& paint) {
SkPaint::TextEncoding textEncoding = paint.getTextEncoding();
const char* end = (const char*)text + 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;
while ((const char*)text < (const char*)stopText) {
localM.setRSXform(*xform++);
currM.setConcat(this->ctm(), localM);
SkAutoDeviceCTMRestore adc(this, currM);
void SkBaseDevice::drawGlyphRunRSXform(SkGlyphRun* run, const SkRSXform* xform) {
const SkMatrix originalCTM = this->ctm();
sk_sp<SkShader> shader = sk_ref_sp(run->mutablePaint()->getShader());
auto perGlyph = [this, &xform, &originalCTM, shader] (
SkGlyphRun* glyphRun, SkPaint* runPaint) {
SkMatrix ctm;
ctm.setRSXform(*xform++);
// 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
// with a localmatrixshader so that the shader draws as if there was no change to the ctm.
if (shader) {
SkMatrix inverse;
if (localM.invert(&inverse)) {
localPaint.setShader(shader->makeWithLocalMatrix(inverse));
if (ctm.invert(&inverse)) {
runPaint->setShader(shader->makeWithLocalMatrix(inverse));
} else {
localPaint.setShader(nullptr); // can't handle this xform
runPaint->setShader(nullptr); // can't handle this xform
}
}
int subLen = 0;
switch (textEncoding) {
case SkPaint::kUTF8_TextEncoding:
subLen = SkUTF8_CountUTF8Bytes((const char*)text);
break;
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;
case SkPaint::kUTF32_TextEncoding:
subLen = 4;
break;
case SkPaint::kGlyphID_TextEncoding:
subLen = 2;
break;
}
this->drawPosText(text, subLen, pos, 2, origin, localPaint);
text = (const char*)text + subLen;
}
ctm.setConcat(originalCTM, ctm);
this->setCTM(ctm);
SkGlyphRunList glyphRunList{glyphRun};
this->drawGlyphRunList(&glyphRunList);
};
run->eachGlyphToGlyphRun(perGlyph);
run->mutablePaint()->setShader(shader);
this->setCTM(originalCTM);
}
//////////////////////////////////////////////////////////////////////////////////////////

View File

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

View File

@ -51,6 +51,31 @@ SkGlyphRun::SkGlyphRun(SkPaint&& runPaint,
, fClusters{clusters}
, 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) {
auto pos = (const SkScalar*) this->positions().data();
@ -74,6 +99,7 @@ void SkGlyphRun::filloutGlyphsAndPositions(SkGlyphID* glyphIDs, SkPoint* positio
}
// -- SkGlyphRunList -------------------------------------------------------------------------------
SkGlyphRunList::SkGlyphRunList() = default;
SkGlyphRunList::SkGlyphRunList(
const SkPaint& paint,
const SkTextBlob* blob,
@ -84,6 +110,12 @@ SkGlyphRunList::SkGlyphRunList(
, fOrigin{origin}
, 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 {
return fOriginalTextBlob != nullptr ? fOriginalTextBlob->uniqueID()
: SK_InvalidUniqueID;
@ -166,6 +198,29 @@ SkSpan<const SkGlyphID> SkGlyphIDSet::uniquifyGlyphIDs(
}
// -- 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(
const SkPaint& paint, const void* bytes, size_t byteLength, SkPoint origin) {
auto glyphIDs = textToGlyphIDs(paint, bytes, byteLength);

View File

@ -19,6 +19,7 @@
#include "SkTypes.h"
class SkBaseDevice;
class SkGlyphRunList;
template <typename T>
class SkSpan {
@ -55,6 +56,10 @@ public:
SkSpan<const char> text,
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
// are developed.
void temporaryShuntToDrawPosText(SkBaseDevice* device, SkPoint origin);
@ -65,6 +70,7 @@ public:
size_t runSize() const { return fTemporaryShuntGlyphIDs.size(); }
SkSpan<const SkPoint> positions() const { return fPositions; }
const SkPaint& paint() const { return fRunPaint; }
SkPaint* mutablePaint() { return &fRunPaint; }
private:
//
@ -80,11 +86,11 @@ private:
// Original clusters from SkTextBlob if present. Will be empty if not present.
const SkSpan<const uint32_t> fClusters;
// Paint for this run modified to have glyph encoding and left alignment.
const SkPaint fRunPaint;
SkPaint fRunPaint;
};
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
// should be used for nothing else
const SkTextBlob* fOriginalTextBlob{nullptr};
@ -92,7 +98,7 @@ class SkGlyphRunList {
SkSpan<SkGlyphRun> fGlyphRuns;
public:
SkGlyphRunList() = default;
SkGlyphRunList();
// Blob maybe null.
SkGlyphRunList(
const SkPaint& paint,
@ -100,6 +106,8 @@ public:
SkPoint origin,
SkSpan<SkGlyphRun> glyphRunList);
SkGlyphRunList(SkGlyphRun* glyphRun);
uint64_t uniqueID() const;
bool anyRunsLCD() const;
void temporaryShuntBlobNotifyAddedToCache(uint32_t cacheID) const;
@ -143,6 +151,7 @@ private:
class SkGlyphRunBuilder {
public:
void drawTextAtOrigin(const SkPaint& paint, const void* bytes, size_t byteLength);
void drawText(
const SkPaint& paint, const void* bytes, size_t byteLength, SkPoint origin);
void drawPosTextH(
@ -152,7 +161,6 @@ public:
const SkPaint& paint, const void* bytes, size_t byteLength, const SkPoint* pos);
void drawTextBlob(const SkPaint& paint, const SkTextBlob& blob, SkPoint origin);
SkGlyphRun* useGlyphRun();
SkGlyphRunList* useGlyphRunList();
private: