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:
parent
8364706c02
commit
2eacff02f1
@ -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
|
||||
|
@ -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);
|
||||
|
||||
ctm.setConcat(originalCTM, ctm);
|
||||
this->setCTM(ctm);
|
||||
SkGlyphRunList glyphRunList{glyphRun};
|
||||
this->drawGlyphRunList(&glyphRunList);
|
||||
};
|
||||
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;
|
||||
}
|
||||
run->eachGlyphToGlyphRun(perGlyph);
|
||||
run->mutablePaint()->setShader(shader);
|
||||
this->setCTM(originalCTM);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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:
|
||||
|
Loading…
Reference in New Issue
Block a user