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
|
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
|
||||||
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
@ -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:
|
||||||
|
Loading…
Reference in New Issue
Block a user