Split out SkRunFont and SkPaint
Coping paints take significant time. The ApplyFontToPaint idiom requires a copy and a dtor. This CL keeps the paint and font in parallel through the code until a paint is actually needed, then a special ctor is used to create it. Also, inline a bunch of text blob calls that were showing up in perf. Change-Id: I7da746a287e4d3942e45e9536ef9acdc64f084d4 Reviewed-on: https://skia-review.googlesource.com/c/159222 Reviewed-by: Mike Klein <mtklein@google.com> Reviewed-by: Herb Derby <herb@google.com> Commit-Queue: Herb Derby <herb@google.com>
This commit is contained in:
parent
2c06e14697
commit
434377abfb
@ -63,7 +63,8 @@ class TextBlobCachedBench : public SkTextBlobBench {
|
||||
SkPaint paint;
|
||||
|
||||
auto blob = this->makeBlob();
|
||||
for (int i = 0; i < loops; i++) {
|
||||
auto bigLoops = loops * 1000;
|
||||
for (int i = 0; i < bigLoops; i++) {
|
||||
// To ensure maximum caching, we just redraw the blob at the same place everytime
|
||||
canvas->drawTextBlob(blob, 0, 0, paint);
|
||||
}
|
||||
@ -78,7 +79,8 @@ class TextBlobFirstTimeBench : public SkTextBlobBench {
|
||||
void onDraw(int loops, SkCanvas* canvas) override {
|
||||
SkPaint paint;
|
||||
|
||||
for (int i = 0; i < loops; i++) {
|
||||
auto bigLoops = loops * 1000;
|
||||
for (int i = 0; i < bigLoops; i++) {
|
||||
canvas->drawTextBlob(this->makeBlob(), 0, 0, paint);
|
||||
}
|
||||
}
|
||||
|
@ -33,6 +33,8 @@ class SkData;
|
||||
class SkDescriptor;
|
||||
class SkDrawLooper;
|
||||
class SkGlyph;
|
||||
class SkGlyphRunBuilder;
|
||||
class SkGlyphRun;
|
||||
class SkGlyphRunListPainter;
|
||||
struct SkRect;
|
||||
class SkGlyphCache;
|
||||
@ -41,9 +43,11 @@ class SkMaskFilter;
|
||||
class SkPath;
|
||||
class SkPathEffect;
|
||||
struct SkPoint;
|
||||
class SkRunFont;
|
||||
class SkShader;
|
||||
class SkSurfaceProps;
|
||||
class SkTextBlob;
|
||||
class SkTextBlobRunIterator;
|
||||
class SkTypeface;
|
||||
|
||||
/** \class SkPaint
|
||||
@ -1474,6 +1478,9 @@ public:
|
||||
Style style) const;
|
||||
|
||||
private:
|
||||
friend class SkGlyphRun;
|
||||
friend class SkGlyphRunBuilder;
|
||||
SkPaint(const SkPaint&, const SkRunFont&);
|
||||
typedef const SkGlyph& (*GlyphCacheProc)(SkGlyphCache*, const char**, const char*);
|
||||
|
||||
sk_sp<SkTypeface> fTypeface;
|
||||
|
@ -28,7 +28,8 @@ static SkTypeface::Encoding convert_encoding(SkPaint::TextEncoding encoding) {
|
||||
} // namespace
|
||||
|
||||
// -- SkGlyphRun -----------------------------------------------------------------------------------
|
||||
SkGlyphRun::SkGlyphRun(const SkPaint& runPaint,
|
||||
SkGlyphRun::SkGlyphRun(const SkPaint& basePaint,
|
||||
const SkRunFont& runFont,
|
||||
SkSpan<const uint16_t> denseIndices,
|
||||
SkSpan<const SkPoint> positions,
|
||||
SkSpan<const SkGlyphID> glyphIDs,
|
||||
@ -41,14 +42,14 @@ SkGlyphRun::SkGlyphRun(const SkPaint& runPaint,
|
||||
, fUniqueGlyphIDs{uniqueGlyphIDs}
|
||||
, fText{text}
|
||||
, fClusters{clusters}
|
||||
, fRunPaint{runPaint} {}
|
||||
, fRunPaint{basePaint, runFont} {}
|
||||
|
||||
void SkGlyphRun::eachGlyphToGlyphRun(SkGlyphRun::PerGlyph perGlyph) {
|
||||
SkPaint paint{fRunPaint};
|
||||
SkPoint point;
|
||||
SkGlyphID glyphID;
|
||||
SkGlyphRun run{
|
||||
std::move(paint),
|
||||
fRunPaint,
|
||||
SkRunFont{fRunPaint},
|
||||
SkSpan<const uint16_t>{}, // No dense indices for now.
|
||||
SkSpan<const SkPoint>{&point, 1},
|
||||
SkSpan<const SkGlyphID>{&glyphID, 1},
|
||||
@ -185,6 +186,7 @@ void SkGlyphRunBuilder::drawTextAtOrigin(
|
||||
|
||||
this->makeGlyphRun(
|
||||
paint,
|
||||
SkRunFont{paint},
|
||||
glyphIDs,
|
||||
positions,
|
||||
SkSpan<const uint16_t>{}, // no dense indices for now.,
|
||||
@ -199,8 +201,8 @@ void SkGlyphRunBuilder::drawText(
|
||||
auto glyphIDs = textToGlyphIDs(paint, bytes, byteLength);
|
||||
if (!glyphIDs.empty()) {
|
||||
this->initialize(glyphIDs.size());
|
||||
this->simplifyDrawText(
|
||||
paint, glyphIDs, origin, fUniqueGlyphIDIndices, fUniqueGlyphIDs, fPositions);
|
||||
this->simplifyDrawText(paint, SkRunFont{paint}, glyphIDs, origin,
|
||||
fUniqueGlyphIDIndices, fUniqueGlyphIDs, fPositions);
|
||||
}
|
||||
|
||||
this->makeGlyphRunList(paint, nullptr, SkPoint::Make(0, 0));
|
||||
@ -213,7 +215,8 @@ void SkGlyphRunBuilder::drawPosTextH(const SkPaint& paint, const void* bytes,
|
||||
if (!glyphIDs.empty()) {
|
||||
this->initialize(glyphIDs.size());
|
||||
this->simplifyDrawPosTextH(
|
||||
paint, glyphIDs, xpos, constY, fUniqueGlyphIDIndices, fUniqueGlyphIDs, fPositions);
|
||||
paint, SkRunFont{paint}, glyphIDs, xpos, constY,
|
||||
fUniqueGlyphIDIndices, fUniqueGlyphIDs, fPositions);
|
||||
}
|
||||
|
||||
this->makeGlyphRunList(paint, nullptr, SkPoint::Make(0, 0));
|
||||
@ -224,7 +227,7 @@ void SkGlyphRunBuilder::drawPosText(const SkPaint& paint, const void* bytes,
|
||||
auto glyphIDs = textToGlyphIDs(paint, bytes, byteLength);
|
||||
if (!glyphIDs.empty()) {
|
||||
this->initialize(glyphIDs.size());
|
||||
this->simplifyDrawPosText(paint, glyphIDs, pos,
|
||||
this->simplifyDrawPosText(paint, SkRunFont{paint}, glyphIDs, pos,
|
||||
fUniqueGlyphIDIndices, fUniqueGlyphIDs);
|
||||
}
|
||||
|
||||
@ -232,8 +235,6 @@ void SkGlyphRunBuilder::drawPosText(const SkPaint& paint, const void* bytes,
|
||||
}
|
||||
|
||||
void SkGlyphRunBuilder::drawTextBlob(const SkPaint& paint, const SkTextBlob& blob, SkPoint origin) {
|
||||
SkPaint runPaint = paint;
|
||||
|
||||
// Figure out all the storage needed to pre-size everything below.
|
||||
size_t totalGlyphs = 0;
|
||||
for (SkTextBlobRunIterator it(&blob); !it.done(); it.next()) {
|
||||
@ -250,12 +251,8 @@ void SkGlyphRunBuilder::drawTextBlob(const SkPaint& paint, const SkTextBlob& blo
|
||||
for (SkTextBlobRunIterator it(&blob); !it.done(); it.next()) {
|
||||
// applyFontToPaint() always overwrites the exact same attributes,
|
||||
// so it is safe to not re-seed the paint for this reason.
|
||||
it.applyFontToPaint(&runPaint);
|
||||
size_t runSize = it.glyphCount();
|
||||
|
||||
// These better be glyphs
|
||||
SkASSERT(runPaint.getTextEncoding() == SkPaint::kGlyphID_TextEncoding);
|
||||
|
||||
auto text = SkSpan<const char>(it.text(), it.textSize());
|
||||
auto clusters = SkSpan<const uint32_t>(it.clusters(), runSize);
|
||||
const SkPoint& offset = it.offset();
|
||||
@ -265,7 +262,7 @@ void SkGlyphRunBuilder::drawTextBlob(const SkPaint& paint, const SkTextBlob& blo
|
||||
switch (it.positioning()) {
|
||||
case SkTextBlobRunIterator::kDefault_Positioning: {
|
||||
uniqueGlyphIDsSize = this->simplifyDrawText(
|
||||
runPaint, glyphIDs, offset,
|
||||
paint, it.runFont(), glyphIDs, offset,
|
||||
currentDenseIndices, currentUniqueGlyphIDs, currentPositions,
|
||||
text, clusters);
|
||||
}
|
||||
@ -273,14 +270,14 @@ void SkGlyphRunBuilder::drawTextBlob(const SkPaint& paint, const SkTextBlob& blo
|
||||
case SkTextBlobRunIterator::kHorizontal_Positioning: {
|
||||
auto constY = offset.y();
|
||||
uniqueGlyphIDsSize = this->simplifyDrawPosTextH(
|
||||
runPaint, glyphIDs, it.pos(), constY,
|
||||
paint, it.runFont(), glyphIDs, it.pos(), constY,
|
||||
currentDenseIndices, currentUniqueGlyphIDs, currentPositions,
|
||||
text, clusters);
|
||||
}
|
||||
break;
|
||||
case SkTextBlobRunIterator::kFull_Positioning:
|
||||
uniqueGlyphIDsSize = this->simplifyDrawPosText(
|
||||
runPaint, glyphIDs, (const SkPoint*)it.pos(),
|
||||
paint, it.runFont(), glyphIDs, (const SkPoint*)it.pos(),
|
||||
currentDenseIndices, currentUniqueGlyphIDs,
|
||||
text, clusters);
|
||||
break;
|
||||
@ -298,8 +295,8 @@ void SkGlyphRunBuilder::drawGlyphPos(
|
||||
const SkPaint& paint, SkSpan<const SkGlyphID> glyphIDs, const SkPoint* pos) {
|
||||
if (!glyphIDs.empty()) {
|
||||
this->initialize(glyphIDs.size());
|
||||
this->simplifyDrawPosText(paint, glyphIDs, pos,
|
||||
fUniqueGlyphIDIndices, fUniqueGlyphIDs);
|
||||
this->simplifyDrawPosText(paint, SkRunFont{paint}, glyphIDs, pos,
|
||||
fUniqueGlyphIDIndices, fUniqueGlyphIDs);
|
||||
this->makeGlyphRunList(paint, nullptr, SkPoint::Make(0, 0));
|
||||
}
|
||||
}
|
||||
@ -361,7 +358,8 @@ SkSpan<const SkGlyphID> SkGlyphRunBuilder::addDenseAndUnique(
|
||||
}
|
||||
|
||||
void SkGlyphRunBuilder::makeGlyphRun(
|
||||
const SkPaint& runPaint,
|
||||
const SkPaint& basePaint,
|
||||
const SkRunFont& runFont,
|
||||
SkSpan<const SkGlyphID> glyphIDs,
|
||||
SkSpan<const SkPoint> positions,
|
||||
SkSpan<const uint16_t> uniqueGlyphIDIndices,
|
||||
@ -372,7 +370,8 @@ void SkGlyphRunBuilder::makeGlyphRun(
|
||||
// Ignore empty runs.
|
||||
if (!glyphIDs.empty()) {
|
||||
fGlyphRunListStorage.emplace_back(
|
||||
runPaint,
|
||||
basePaint,
|
||||
runFont,
|
||||
uniqueGlyphIDIndices,
|
||||
positions,
|
||||
glyphIDs,
|
||||
@ -391,20 +390,22 @@ void SkGlyphRunBuilder::makeGlyphRunList(
|
||||
}
|
||||
|
||||
size_t SkGlyphRunBuilder::simplifyDrawText(
|
||||
const SkPaint& paint, SkSpan<const SkGlyphID> glyphIDs, SkPoint origin,
|
||||
uint16_t* uniqueGlyphIDIndicesBuffer, SkGlyphID* uniqueGlyphIDsBuffer, SkPoint* positions,
|
||||
SkSpan<const char> text, SkSpan<const uint32_t> clusters) {
|
||||
const SkPaint& paint, const SkRunFont& runFont, SkSpan<const SkGlyphID> glyphIDs,
|
||||
SkPoint origin, uint16_t* uniqueGlyphIDIndicesBuffer, SkGlyphID* uniqueGlyphIDsBuffer,
|
||||
SkPoint* positions, SkSpan<const char> text, SkSpan<const uint32_t> clusters) {
|
||||
SkASSERT(!glyphIDs.empty());
|
||||
|
||||
auto runSize = glyphIDs.size();
|
||||
|
||||
SkPaint runPaint{paint, runFont};
|
||||
|
||||
auto unqiueGlyphIDs = this->addDenseAndUnique(
|
||||
paint, glyphIDs, uniqueGlyphIDIndicesBuffer, uniqueGlyphIDsBuffer);
|
||||
runPaint, glyphIDs, uniqueGlyphIDIndicesBuffer, uniqueGlyphIDsBuffer);
|
||||
|
||||
if (!unqiueGlyphIDs.empty()) {
|
||||
fScratchAdvances.resize(runSize);
|
||||
{
|
||||
auto cache = SkStrikeCache::FindOrCreateStrikeExclusive(paint);
|
||||
auto cache = SkStrikeCache::FindOrCreateStrikeExclusive(runPaint);
|
||||
cache->getAdvances(unqiueGlyphIDs, fScratchAdvances.data());
|
||||
}
|
||||
|
||||
@ -428,6 +429,7 @@ size_t SkGlyphRunBuilder::simplifyDrawText(
|
||||
|
||||
this->makeGlyphRun(
|
||||
paint,
|
||||
runFont,
|
||||
glyphIDs,
|
||||
SkSpan<const SkPoint>{positions, runSize},
|
||||
SkSpan<const uint16_t>{uniqueGlyphIDIndicesBuffer, runSize},
|
||||
@ -440,7 +442,7 @@ size_t SkGlyphRunBuilder::simplifyDrawText(
|
||||
}
|
||||
|
||||
size_t SkGlyphRunBuilder::simplifyDrawPosTextH(
|
||||
const SkPaint& paint, SkSpan<const SkGlyphID> glyphIDs,
|
||||
const SkPaint& paint, const SkRunFont& runFont, SkSpan<const SkGlyphID> glyphIDs,
|
||||
const SkScalar* xpos, SkScalar constY,
|
||||
uint16_t* uniqueGlyphIDIndicesBuffer, SkGlyphID* uniqueGlyphIDsBuffer, SkPoint* positions,
|
||||
SkSpan<const char> text, SkSpan<const uint32_t> clusters) {
|
||||
@ -450,14 +452,14 @@ size_t SkGlyphRunBuilder::simplifyDrawPosTextH(
|
||||
*posCursor++ = SkPoint::Make(x, constY);
|
||||
}
|
||||
|
||||
return simplifyDrawPosText(paint, glyphIDs, positions,
|
||||
return simplifyDrawPosText(paint, runFont, glyphIDs, positions,
|
||||
uniqueGlyphIDIndicesBuffer, uniqueGlyphIDsBuffer,
|
||||
text, clusters);
|
||||
}
|
||||
|
||||
size_t SkGlyphRunBuilder::simplifyDrawPosText(
|
||||
const SkPaint& paint, SkSpan<const SkGlyphID> glyphIDs, const SkPoint* pos,
|
||||
uint16_t* uniqueGlyphIDIndicesBuffer, SkGlyphID* uniqueGlyphIDsBuffer,
|
||||
const SkPaint& paint, const SkRunFont& runFont, SkSpan<const SkGlyphID> glyphIDs,
|
||||
const SkPoint* pos, uint16_t* uniqueGlyphIDIndicesBuffer, SkGlyphID* uniqueGlyphIDsBuffer,
|
||||
SkSpan<const char> text, SkSpan<const uint32_t> clusters) {
|
||||
auto runSize = glyphIDs.size();
|
||||
|
||||
@ -472,6 +474,7 @@ size_t SkGlyphRunBuilder::simplifyDrawPosText(
|
||||
// drawText above.
|
||||
this->makeGlyphRun(
|
||||
paint,
|
||||
runFont,
|
||||
glyphIDs,
|
||||
SkSpan<const SkPoint>{pos, runSize},
|
||||
SkSpan<const SkGlyphID>{uniqueGlyphIDIndicesBuffer, runSize},
|
||||
|
@ -85,7 +85,8 @@ public:
|
||||
class SkGlyphRun {
|
||||
public:
|
||||
SkGlyphRun() = default;
|
||||
SkGlyphRun(const SkPaint& runPaint,
|
||||
SkGlyphRun(const SkPaint& basePaint,
|
||||
const SkRunFont& runFont,
|
||||
SkSpan<const uint16_t> denseIndices,
|
||||
SkSpan<const SkPoint> positions,
|
||||
SkSpan<const SkGlyphID> glyphIDs,
|
||||
@ -214,7 +215,8 @@ private:
|
||||
SkGlyphID* uniqueGlyphIDs);
|
||||
|
||||
void makeGlyphRun(
|
||||
const SkPaint& runPaint,
|
||||
const SkPaint& basePaint,
|
||||
const SkRunFont& runFont,
|
||||
SkSpan<const SkGlyphID> glyphIDs,
|
||||
SkSpan<const SkPoint> positions,
|
||||
SkSpan<const uint16_t> uniqueGlyphIDIndices,
|
||||
@ -225,19 +227,20 @@ private:
|
||||
void makeGlyphRunList(const SkPaint& paint, const SkTextBlob* blob, SkPoint origin);
|
||||
|
||||
size_t simplifyDrawText(
|
||||
const SkPaint& paint, SkSpan<const SkGlyphID> glyphIDs, SkPoint origin,
|
||||
uint16_t* uniqueGlyphIDIndices, SkGlyphID* uniqueGlyphIDs, SkPoint* positions,
|
||||
const SkPaint& paint, const SkRunFont& runFont, SkSpan<const SkGlyphID> glyphIDs,
|
||||
SkPoint origin,uint16_t* uniqueGlyphIDIndices, SkGlyphID* uniqueGlyphIDs,
|
||||
SkPoint* positions,
|
||||
SkSpan<const char> text = SkSpan<const char>{},
|
||||
SkSpan<const uint32_t> clusters = SkSpan<const uint32_t>{});
|
||||
size_t simplifyDrawPosTextH(
|
||||
const SkPaint& paint, SkSpan<const SkGlyphID> glyphIDs,
|
||||
const SkPaint& paint, const SkRunFont& runFont, SkSpan<const SkGlyphID> glyphIDs,
|
||||
const SkScalar* xpos, SkScalar constY,
|
||||
uint16_t* uniqueGlyphIDIndices, SkGlyphID* uniqueGlyphIDs, SkPoint* positions,
|
||||
SkSpan<const char> text = SkSpan<const char>{},
|
||||
SkSpan<const uint32_t> clusters = SkSpan<const uint32_t>{});
|
||||
size_t simplifyDrawPosText(
|
||||
const SkPaint& paint, SkSpan<const SkGlyphID> glyphIDs, const SkPoint* pos,
|
||||
uint16_t* uniqueGlyphIDIndices, SkGlyphID* uniqueGlyphIDs,
|
||||
const SkPaint& paint, const SkRunFont& runFont, SkSpan<const SkGlyphID> glyphIDs,
|
||||
const SkPoint* pos, uint16_t* uniqueGlyphIDIndices, SkGlyphID* uniqueGlyphIDs,
|
||||
SkSpan<const char> text = SkSpan<const char>{},
|
||||
SkSpan<const uint32_t> clusters = SkSpan<const uint32_t>{});
|
||||
|
||||
|
@ -22,12 +22,7 @@
|
||||
#include "text/GrTextBlobCache.h"
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
|
||||
// TODO(fmalita): replace with SkFont.
|
||||
class RunFont : SkNoncopyable {
|
||||
public:
|
||||
RunFont(const SkPaint& paint)
|
||||
SkRunFont::SkRunFont(const SkPaint& paint)
|
||||
: fSize(paint.getTextSize())
|
||||
, fScaleX(paint.getTextScaleX())
|
||||
, fTypeface(SkPaintPriv::RefTypefaceOrDefault(paint))
|
||||
@ -36,98 +31,73 @@ public:
|
||||
, fHinting(paint.getHinting())
|
||||
, fFlags(paint.getFlags() & kFlagsMask) { }
|
||||
|
||||
void applyToPaint(SkPaint* paint) const {
|
||||
paint->setTextEncoding(SkPaint::kGlyphID_TextEncoding);
|
||||
paint->setTypeface(fTypeface);
|
||||
paint->setTextSize(fSize);
|
||||
paint->setTextScaleX(fScaleX);
|
||||
paint->setTextSkewX(fSkewX);
|
||||
paint->setTextAlign(static_cast<SkPaint::Align>(fAlign));
|
||||
paint->setHinting(static_cast<SkPaint::Hinting>(fHinting));
|
||||
void SkRunFont::applyToPaint(SkPaint* paint) const {
|
||||
paint->setTextEncoding(SkPaint::kGlyphID_TextEncoding);
|
||||
paint->setTypeface(fTypeface);
|
||||
paint->setTextSize(fSize);
|
||||
paint->setTextScaleX(fScaleX);
|
||||
paint->setTextSkewX(fSkewX);
|
||||
paint->setTextAlign(static_cast<SkPaint::Align>(fAlign));
|
||||
paint->setHinting(static_cast<SkPaint::Hinting>(fHinting));
|
||||
|
||||
paint->setFlags((paint->getFlags() & ~kFlagsMask) | fFlags);
|
||||
}
|
||||
paint->setFlags((paint->getFlags() & ~kFlagsMask) | fFlags);
|
||||
}
|
||||
|
||||
bool operator==(const RunFont& other) const {
|
||||
return fTypeface == other.fTypeface
|
||||
&& fSize == other.fSize
|
||||
&& fScaleX == other.fScaleX
|
||||
&& fSkewX == other.fSkewX
|
||||
&& fAlign == other.fAlign
|
||||
&& fHinting == other.fHinting
|
||||
&& fFlags == other.fFlags;
|
||||
}
|
||||
|
||||
bool operator!=(const RunFont& other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
uint32_t flags() const { return fFlags; }
|
||||
|
||||
private:
|
||||
const static uint32_t kFlagsMask =
|
||||
SkPaint::kAntiAlias_Flag |
|
||||
SkPaint::kFakeBoldText_Flag |
|
||||
SkPaint::kLinearText_Flag |
|
||||
SkPaint::kSubpixelText_Flag |
|
||||
SkPaint::kLCDRenderText_Flag |
|
||||
SkPaint::kEmbeddedBitmapText_Flag |
|
||||
SkPaint::kAutoHinting_Flag |
|
||||
SkPaint::kVerticalText_Flag ;
|
||||
|
||||
SkScalar fSize;
|
||||
SkScalar fScaleX;
|
||||
|
||||
// Keep this sk_sp off the first position, to avoid interfering with SkNoncopyable
|
||||
// empty baseclass optimization (http://code.google.com/p/skia/issues/detail?id=3694).
|
||||
sk_sp<SkTypeface> fTypeface;
|
||||
SkScalar fSkewX;
|
||||
|
||||
static_assert(SkPaint::kAlignCount < 4, "insufficient_align_bits");
|
||||
uint32_t fAlign : 2;
|
||||
static_assert(SkPaint::kFull_Hinting < 4, "insufficient_hinting_bits");
|
||||
uint32_t fHinting : 2;
|
||||
static_assert((kFlagsMask & 0xffff) == kFlagsMask, "insufficient_flags_bits");
|
||||
uint32_t fFlags : 16;
|
||||
|
||||
typedef SkNoncopyable INHERITED;
|
||||
};
|
||||
bool SkRunFont::operator==(const SkRunFont& other) const {
|
||||
return fTypeface == other.fTypeface
|
||||
&& fSize == other.fSize
|
||||
&& fScaleX == other.fScaleX
|
||||
&& fSkewX == other.fSkewX
|
||||
&& fAlign == other.fAlign
|
||||
&& fHinting == other.fHinting
|
||||
&& fFlags == other.fFlags;
|
||||
}
|
||||
|
||||
namespace {
|
||||
struct RunFontStorageEquivalent {
|
||||
SkScalar fSize, fScaleX;
|
||||
void* fTypeface;
|
||||
SkScalar fSkewX;
|
||||
uint32_t fFlags;
|
||||
};
|
||||
static_assert(sizeof(RunFont) == sizeof(RunFontStorageEquivalent), "runfont_should_stay_packed");
|
||||
static_assert(sizeof(SkRunFont) == sizeof(RunFontStorageEquivalent), "runfont_should_stay_packed");
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
size_t SkTextBlob::RunRecord::StorageSize(uint32_t glyphCount, uint32_t textSize,
|
||||
SkTextBlob::GlyphPositioning positioning,
|
||||
SkSafeMath* safe) {
|
||||
static_assert(SkIsAlign4(sizeof(SkScalar)), "SkScalar size alignment");
|
||||
|
||||
//
|
||||
// Textblob data is laid out into externally-managed storage as follows:
|
||||
//
|
||||
// -----------------------------------------------------------------------------
|
||||
// | SkTextBlob | RunRecord | Glyphs[] | Pos[] | RunRecord | Glyphs[] | Pos[] | ...
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// Each run record describes a text blob run, and can be used to determine the (implicit)
|
||||
// location of the following record.
|
||||
//
|
||||
// Extended Textblob runs have more data after the Pos[] array:
|
||||
//
|
||||
// -------------------------------------------------------------------------
|
||||
// ... | RunRecord | Glyphs[] | Pos[] | TextSize | Clusters[] | Text[] | ...
|
||||
// -------------------------------------------------------------------------
|
||||
//
|
||||
// To determine the length of the extended run data, the TextSize must be read.
|
||||
//
|
||||
// Extended Textblob runs may be mixed with non-extended runs.
|
||||
auto glyphSize = safe->mul(glyphCount, sizeof(uint16_t)),
|
||||
posSize = safe->mul(PosCount(glyphCount, positioning, safe), sizeof(SkScalar));
|
||||
|
||||
SkDEBUGCODE(static const unsigned kRunRecordMagic = 0xb10bcafe;)
|
||||
// RunRecord object + (aligned) glyph buffer + position buffer
|
||||
auto size = sizeof(SkTextBlob::RunRecord);
|
||||
size = safe->add(size, safe->alignUp(glyphSize, 4));
|
||||
size = safe->add(size, posSize);
|
||||
|
||||
if (textSize) { // Extended run.
|
||||
size = safe->add(size, sizeof(uint32_t));
|
||||
size = safe->add(size, safe->mul(glyphCount, sizeof(uint32_t)));
|
||||
size = safe->add(size, textSize);
|
||||
}
|
||||
|
||||
return safe->alignUp(size, sizeof(void*));
|
||||
}
|
||||
|
||||
const SkTextBlob::RunRecord* SkTextBlob::RunRecord::First(const SkTextBlob* blob) {
|
||||
// The first record (if present) is stored following the blob object.
|
||||
// (aligned up to make the RunRecord aligned too)
|
||||
return reinterpret_cast<const RunRecord*>(SkAlignPtr((uintptr_t)(blob + 1)));
|
||||
}
|
||||
|
||||
const SkTextBlob::RunRecord* SkTextBlob::RunRecord::Next(const RunRecord* run) {
|
||||
return SkToBool(run->fFlags & kLast_Flag) ? nullptr : NextUnchecked(run);
|
||||
}
|
||||
|
||||
namespace {
|
||||
struct RunRecordStorageEquivalent {
|
||||
RunFont fFont;
|
||||
SkRunFont fFont;
|
||||
SkPoint fOffset;
|
||||
uint32_t fCount;
|
||||
uint32_t fFlags;
|
||||
@ -135,169 +105,59 @@ struct RunRecordStorageEquivalent {
|
||||
};
|
||||
}
|
||||
|
||||
class SkTextBlob::RunRecord {
|
||||
public:
|
||||
RunRecord(uint32_t count, uint32_t textSize, const SkPoint& offset, const SkPaint& font, GlyphPositioning pos)
|
||||
: fFont(font)
|
||||
, fCount(count)
|
||||
, fOffset(offset)
|
||||
, fFlags(pos) {
|
||||
SkASSERT(static_cast<unsigned>(pos) <= Flags::kPositioning_Mask);
|
||||
void SkTextBlob::RunRecord::validate(const uint8_t* storageTop) const {
|
||||
SkASSERT(kRunRecordMagic == fMagic);
|
||||
SkASSERT((uint8_t*)NextUnchecked(this) <= storageTop);
|
||||
|
||||
SkDEBUGCODE(fMagic = kRunRecordMagic);
|
||||
if (textSize > 0) {
|
||||
fFlags |= kExtended_Flag;
|
||||
*this->textSizePtr() = textSize;
|
||||
}
|
||||
SkASSERT(glyphBuffer() + fCount <= (uint16_t*)posBuffer());
|
||||
SkASSERT(posBuffer() + fCount * ScalarsPerGlyph(positioning())
|
||||
<= (SkScalar*)NextUnchecked(this));
|
||||
if (isExtended()) {
|
||||
SkASSERT(textSize() > 0);
|
||||
SkASSERT(textSizePtr() < (uint32_t*)NextUnchecked(this));
|
||||
SkASSERT(clusterBuffer() < (uint32_t*)NextUnchecked(this));
|
||||
SkASSERT(textBuffer() + textSize() <= (char*)NextUnchecked(this));
|
||||
}
|
||||
static_assert(sizeof(SkTextBlob::RunRecord) == sizeof(RunRecordStorageEquivalent),
|
||||
"runrecord_should_stay_packed");
|
||||
}
|
||||
|
||||
uint32_t glyphCount() const {
|
||||
return fCount;
|
||||
}
|
||||
const SkTextBlob::RunRecord* SkTextBlob::RunRecord::NextUnchecked(const RunRecord* run) {
|
||||
SkSafeMath safe;
|
||||
auto res = reinterpret_cast<const RunRecord*>(
|
||||
reinterpret_cast<const uint8_t*>(run)
|
||||
+ StorageSize(run->glyphCount(), run->textSize(), run->positioning(), &safe));
|
||||
SkASSERT(safe);
|
||||
return res;
|
||||
}
|
||||
|
||||
const SkPoint& offset() const {
|
||||
return fOffset;
|
||||
}
|
||||
size_t SkTextBlob::RunRecord::PosCount(uint32_t glyphCount,
|
||||
SkTextBlob::GlyphPositioning positioning,
|
||||
SkSafeMath* safe) {
|
||||
return safe->mul(glyphCount, ScalarsPerGlyph(positioning));
|
||||
}
|
||||
|
||||
const RunFont& font() const {
|
||||
return fFont;
|
||||
}
|
||||
uint32_t* SkTextBlob::RunRecord::textSizePtr() const {
|
||||
// textSize follows the position buffer.
|
||||
SkASSERT(isExtended());
|
||||
SkSafeMath safe;
|
||||
auto res = (uint32_t*)(&this->posBuffer()[PosCount(fCount, positioning(), &safe)]);
|
||||
SkASSERT(safe);
|
||||
return res;
|
||||
}
|
||||
|
||||
GlyphPositioning positioning() const {
|
||||
return static_cast<GlyphPositioning>(fFlags & kPositioning_Mask);
|
||||
}
|
||||
void SkTextBlob::RunRecord::grow(uint32_t count) {
|
||||
SkScalar* initialPosBuffer = posBuffer();
|
||||
uint32_t initialCount = fCount;
|
||||
fCount += count;
|
||||
|
||||
uint16_t* glyphBuffer() const {
|
||||
static_assert(SkIsAlignPtr(sizeof(RunRecord)), "");
|
||||
// Glyphs are stored immediately following the record.
|
||||
return reinterpret_cast<uint16_t*>(const_cast<RunRecord*>(this) + 1);
|
||||
}
|
||||
// Move the initial pos scalars to their new location.
|
||||
size_t copySize = initialCount * sizeof(SkScalar) * ScalarsPerGlyph(positioning());
|
||||
SkASSERT((uint8_t*)posBuffer() + copySize <= (uint8_t*)NextUnchecked(this));
|
||||
|
||||
SkScalar* posBuffer() const {
|
||||
// Position scalars follow the (aligned) glyph buffer.
|
||||
return reinterpret_cast<SkScalar*>(reinterpret_cast<uint8_t*>(this->glyphBuffer()) +
|
||||
SkAlign4(fCount * sizeof(uint16_t)));
|
||||
}
|
||||
|
||||
uint32_t textSize() const { return isExtended() ? *this->textSizePtr() : 0; }
|
||||
|
||||
uint32_t* clusterBuffer() const {
|
||||
// clusters follow the textSize.
|
||||
return isExtended() ? 1 + this->textSizePtr() : nullptr;
|
||||
}
|
||||
|
||||
char* textBuffer() const {
|
||||
return isExtended()
|
||||
? reinterpret_cast<char*>(this->clusterBuffer() + fCount)
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
static size_t StorageSize(uint32_t glyphCount, uint32_t textSize,
|
||||
SkTextBlob::GlyphPositioning positioning,
|
||||
SkSafeMath* safe) {
|
||||
static_assert(SkIsAlign4(sizeof(SkScalar)), "SkScalar size alignment");
|
||||
|
||||
auto glyphSize = safe->mul(glyphCount, sizeof(uint16_t)),
|
||||
posSize = safe->mul(PosCount(glyphCount, positioning, safe), sizeof(SkScalar));
|
||||
|
||||
// RunRecord object + (aligned) glyph buffer + position buffer
|
||||
auto size = sizeof(SkTextBlob::RunRecord);
|
||||
size = safe->add(size, safe->alignUp(glyphSize, 4));
|
||||
size = safe->add(size, posSize);
|
||||
|
||||
if (textSize) { // Extended run.
|
||||
size = safe->add(size, sizeof(uint32_t));
|
||||
size = safe->add(size, safe->mul(glyphCount, sizeof(uint32_t)));
|
||||
size = safe->add(size, textSize);
|
||||
}
|
||||
|
||||
return safe->alignUp(size, sizeof(void*));
|
||||
}
|
||||
|
||||
static const RunRecord* First(const SkTextBlob* blob) {
|
||||
// The first record (if present) is stored following the blob object.
|
||||
// (aligned up to make the RunRecord aligned too)
|
||||
return reinterpret_cast<const RunRecord*>(SkAlignPtr((uintptr_t)(blob + 1)));
|
||||
}
|
||||
|
||||
static const RunRecord* Next(const RunRecord* run) {
|
||||
return SkToBool(run->fFlags & kLast_Flag) ? nullptr : NextUnchecked(run);
|
||||
}
|
||||
|
||||
void validate(const uint8_t* storageTop) const {
|
||||
SkASSERT(kRunRecordMagic == fMagic);
|
||||
SkASSERT((uint8_t*)NextUnchecked(this) <= storageTop);
|
||||
|
||||
SkASSERT(glyphBuffer() + fCount <= (uint16_t*)posBuffer());
|
||||
SkASSERT(posBuffer() + fCount * ScalarsPerGlyph(positioning())
|
||||
<= (SkScalar*)NextUnchecked(this));
|
||||
if (isExtended()) {
|
||||
SkASSERT(textSize() > 0);
|
||||
SkASSERT(textSizePtr() < (uint32_t*)NextUnchecked(this));
|
||||
SkASSERT(clusterBuffer() < (uint32_t*)NextUnchecked(this));
|
||||
SkASSERT(textBuffer() + textSize() <= (char*)NextUnchecked(this));
|
||||
}
|
||||
static_assert(sizeof(SkTextBlob::RunRecord) == sizeof(RunRecordStorageEquivalent),
|
||||
"runrecord_should_stay_packed");
|
||||
}
|
||||
|
||||
private:
|
||||
friend class SkTextBlobBuilder;
|
||||
|
||||
enum Flags {
|
||||
kPositioning_Mask = 0x03, // bits 0-1 reserved for positioning
|
||||
kLast_Flag = 0x04, // set for the last blob run
|
||||
kExtended_Flag = 0x08, // set for runs with text/cluster info
|
||||
};
|
||||
|
||||
static const RunRecord* NextUnchecked(const RunRecord* run) {
|
||||
SkSafeMath safe;
|
||||
auto res = reinterpret_cast<const RunRecord*>(
|
||||
reinterpret_cast<const uint8_t*>(run)
|
||||
+ StorageSize(run->glyphCount(), run->textSize(), run->positioning(), &safe));
|
||||
SkASSERT(safe);
|
||||
return res;
|
||||
}
|
||||
|
||||
static size_t PosCount(uint32_t glyphCount,
|
||||
SkTextBlob::GlyphPositioning positioning,
|
||||
SkSafeMath* safe) {
|
||||
return safe->mul(glyphCount, ScalarsPerGlyph(positioning));
|
||||
}
|
||||
|
||||
uint32_t* textSizePtr() const {
|
||||
// textSize follows the position buffer.
|
||||
SkASSERT(isExtended());
|
||||
SkSafeMath safe;
|
||||
auto res = (uint32_t*)(&this->posBuffer()[PosCount(fCount, positioning(), &safe)]);
|
||||
SkASSERT(safe);
|
||||
return res;
|
||||
}
|
||||
|
||||
void grow(uint32_t count) {
|
||||
SkScalar* initialPosBuffer = posBuffer();
|
||||
uint32_t initialCount = fCount;
|
||||
fCount += count;
|
||||
|
||||
// Move the initial pos scalars to their new location.
|
||||
size_t copySize = initialCount * sizeof(SkScalar) * ScalarsPerGlyph(positioning());
|
||||
SkASSERT((uint8_t*)posBuffer() + copySize <= (uint8_t*)NextUnchecked(this));
|
||||
|
||||
// memmove, as the buffers may overlap
|
||||
memmove(posBuffer(), initialPosBuffer, copySize);
|
||||
}
|
||||
|
||||
bool isExtended() const {
|
||||
return fFlags & kExtended_Flag;
|
||||
}
|
||||
|
||||
RunFont fFont;
|
||||
uint32_t fCount;
|
||||
SkPoint fOffset;
|
||||
uint32_t fFlags;
|
||||
|
||||
SkDEBUGCODE(unsigned fMagic;)
|
||||
};
|
||||
// memmove, as the buffers may overlap
|
||||
memmove(posBuffer(), initialPosBuffer, copySize);
|
||||
}
|
||||
|
||||
static int32_t gNextID = 1;
|
||||
static int32_t next_id() {
|
||||
@ -374,10 +234,6 @@ SkTextBlobRunIterator::SkTextBlobRunIterator(const SkTextBlob* blob)
|
||||
SkDEBUGCODE(fStorageTop = (uint8_t*)blob + blob->fStorageSize;)
|
||||
}
|
||||
|
||||
bool SkTextBlobRunIterator::done() const {
|
||||
return !fCurrentRun;
|
||||
}
|
||||
|
||||
void SkTextBlobRunIterator::next() {
|
||||
SkASSERT(!this->done());
|
||||
|
||||
@ -387,26 +243,6 @@ void SkTextBlobRunIterator::next() {
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t SkTextBlobRunIterator::glyphCount() const {
|
||||
SkASSERT(!this->done());
|
||||
return fCurrentRun->glyphCount();
|
||||
}
|
||||
|
||||
const uint16_t* SkTextBlobRunIterator::glyphs() const {
|
||||
SkASSERT(!this->done());
|
||||
return fCurrentRun->glyphBuffer();
|
||||
}
|
||||
|
||||
const SkScalar* SkTextBlobRunIterator::pos() const {
|
||||
SkASSERT(!this->done());
|
||||
return fCurrentRun->posBuffer();
|
||||
}
|
||||
|
||||
const SkPoint& SkTextBlobRunIterator::offset() const {
|
||||
SkASSERT(!this->done());
|
||||
return fCurrentRun->offset();
|
||||
}
|
||||
|
||||
SkTextBlobRunIterator::GlyphPositioning SkTextBlobRunIterator::positioning() const {
|
||||
SkASSERT(!this->done());
|
||||
static_assert(static_cast<GlyphPositioning>(SkTextBlob::kDefault_Positioning) ==
|
||||
@ -425,20 +261,6 @@ void SkTextBlobRunIterator::applyFontToPaint(SkPaint* paint) const {
|
||||
fCurrentRun->font().applyToPaint(paint);
|
||||
}
|
||||
|
||||
uint32_t* SkTextBlobRunIterator::clusters() const {
|
||||
SkASSERT(!this->done());
|
||||
return fCurrentRun->clusterBuffer();
|
||||
}
|
||||
uint32_t SkTextBlobRunIterator::textSize() const {
|
||||
SkASSERT(!this->done());
|
||||
return fCurrentRun->textSize();
|
||||
}
|
||||
char* SkTextBlobRunIterator::text() const {
|
||||
SkASSERT(!this->done());
|
||||
return fCurrentRun->textBuffer();
|
||||
}
|
||||
|
||||
|
||||
bool SkTextBlobRunIterator::isLCD() const {
|
||||
return SkToBool(fCurrentRun->font().flags() & SkPaint::kLCDRenderText_Flag);
|
||||
}
|
||||
|
@ -8,7 +8,16 @@
|
||||
#ifndef SkTextBlobPriv_DEFINED
|
||||
#define SkTextBlobPriv_DEFINED
|
||||
|
||||
#include "SkColorFilter.h"
|
||||
#include "SkDrawLooper.h"
|
||||
#include "SkImageFilter.h"
|
||||
#include "SkMaskFilter.h"
|
||||
#include "SkPaintPriv.h"
|
||||
#include "SkPathEffect.h"
|
||||
#include "SkSafeMath.h"
|
||||
#include "SkShader.h"
|
||||
#include "SkTextBlob.h"
|
||||
#include "SkTypeface.h"
|
||||
|
||||
class SkReadBuffer;
|
||||
class SkWriteBuffer;
|
||||
@ -49,6 +58,193 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
// TODO(fmalita): replace with SkFont.
|
||||
class SkRunFont : SkNoncopyable {
|
||||
public:
|
||||
SkRunFont(const SkPaint& paint);
|
||||
|
||||
void applyToPaint(SkPaint* paint) const;
|
||||
|
||||
bool operator==(const SkRunFont& other) const;
|
||||
|
||||
bool operator!=(const SkRunFont& other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
uint32_t flags() const { return fFlags; }
|
||||
|
||||
private:
|
||||
friend SkPaint;
|
||||
const static uint32_t kFlagsMask =
|
||||
SkPaint::kAntiAlias_Flag |
|
||||
SkPaint::kFakeBoldText_Flag |
|
||||
SkPaint::kLinearText_Flag |
|
||||
SkPaint::kSubpixelText_Flag |
|
||||
SkPaint::kLCDRenderText_Flag |
|
||||
SkPaint::kEmbeddedBitmapText_Flag |
|
||||
SkPaint::kAutoHinting_Flag |
|
||||
SkPaint::kVerticalText_Flag ;
|
||||
|
||||
SkScalar fSize;
|
||||
SkScalar fScaleX;
|
||||
|
||||
// Keep this sk_sp off the first position, to avoid interfering with SkNoncopyable
|
||||
// empty baseclass optimization (http://code.google.com/p/skia/issues/detail?id=3694).
|
||||
sk_sp<SkTypeface> fTypeface;
|
||||
SkScalar fSkewX;
|
||||
|
||||
static_assert(SkPaint::kAlignCount < 4, "insufficient_align_bits");
|
||||
uint32_t fAlign : 2;
|
||||
static_assert(SkPaint::kFull_Hinting < 4, "insufficient_hinting_bits");
|
||||
uint32_t fHinting : 2;
|
||||
static_assert((kFlagsMask & 0xffff) == kFlagsMask, "insufficient_flags_bits");
|
||||
uint32_t fFlags : 16;
|
||||
|
||||
typedef SkNoncopyable INHERITED;
|
||||
};
|
||||
|
||||
//
|
||||
// Textblob data is laid out into externally-managed storage as follows:
|
||||
//
|
||||
// -----------------------------------------------------------------------------
|
||||
// | SkTextBlob | RunRecord | Glyphs[] | Pos[] | RunRecord | Glyphs[] | Pos[] | ...
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// Each run record describes a text blob run, and can be used to determine the (implicit)
|
||||
// location of the following record.
|
||||
//
|
||||
// Extended Textblob runs have more data after the Pos[] array:
|
||||
//
|
||||
// -------------------------------------------------------------------------
|
||||
// ... | RunRecord | Glyphs[] | Pos[] | TextSize | Clusters[] | Text[] | ...
|
||||
// -------------------------------------------------------------------------
|
||||
//
|
||||
// To determine the length of the extended run data, the TextSize must be read.
|
||||
//
|
||||
// Extended Textblob runs may be mixed with non-extended runs.
|
||||
|
||||
SkDEBUGCODE(static const unsigned kRunRecordMagic = 0xb10bcafe;)
|
||||
|
||||
class SkTextBlob::RunRecord {
|
||||
public:
|
||||
RunRecord(uint32_t count, uint32_t textSize, const SkPoint& offset, const SkPaint& font, GlyphPositioning pos)
|
||||
: fFont(font)
|
||||
, fCount(count)
|
||||
, fOffset(offset)
|
||||
, fFlags(pos) {
|
||||
SkASSERT(static_cast<unsigned>(pos) <= Flags::kPositioning_Mask);
|
||||
|
||||
SkDEBUGCODE(fMagic = kRunRecordMagic);
|
||||
if (textSize > 0) {
|
||||
fFlags |= kExtended_Flag;
|
||||
*this->textSizePtr() = textSize;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t glyphCount() const {
|
||||
return fCount;
|
||||
}
|
||||
|
||||
const SkPoint& offset() const {
|
||||
return fOffset;
|
||||
}
|
||||
|
||||
const SkRunFont& font() const {
|
||||
return fFont;
|
||||
}
|
||||
|
||||
GlyphPositioning positioning() const {
|
||||
return static_cast<GlyphPositioning>(fFlags & kPositioning_Mask);
|
||||
}
|
||||
|
||||
uint16_t* glyphBuffer() const {
|
||||
static_assert(SkIsAlignPtr(sizeof(RunRecord)), "");
|
||||
// Glyphs are stored immediately following the record.
|
||||
return reinterpret_cast<uint16_t*>(const_cast<RunRecord*>(this) + 1);
|
||||
}
|
||||
|
||||
SkScalar* posBuffer() const {
|
||||
// Position scalars follow the (aligned) glyph buffer.
|
||||
return reinterpret_cast<SkScalar*>(reinterpret_cast<uint8_t*>(this->glyphBuffer()) +
|
||||
SkAlign4(fCount * sizeof(uint16_t)));
|
||||
}
|
||||
|
||||
uint32_t textSize() const { return isExtended() ? *this->textSizePtr() : 0; }
|
||||
|
||||
uint32_t* clusterBuffer() const {
|
||||
// clusters follow the textSize.
|
||||
return isExtended() ? 1 + this->textSizePtr() : nullptr;
|
||||
}
|
||||
|
||||
char* textBuffer() const {
|
||||
return isExtended()
|
||||
? reinterpret_cast<char*>(this->clusterBuffer() + fCount)
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
static size_t StorageSize(uint32_t glyphCount, uint32_t textSize,
|
||||
SkTextBlob::GlyphPositioning positioning,
|
||||
SkSafeMath* safe);
|
||||
|
||||
static const RunRecord* First(const SkTextBlob* blob);
|
||||
|
||||
static const RunRecord* Next(const RunRecord* run);
|
||||
|
||||
void validate(const uint8_t* storageTop) const;
|
||||
|
||||
private:
|
||||
friend class SkTextBlobBuilder;
|
||||
|
||||
enum Flags {
|
||||
kPositioning_Mask = 0x03, // bits 0-1 reserved for positioning
|
||||
kLast_Flag = 0x04, // set for the last blob run
|
||||
kExtended_Flag = 0x08, // set for runs with text/cluster info
|
||||
};
|
||||
|
||||
static const RunRecord* NextUnchecked(const RunRecord* run);
|
||||
|
||||
static size_t PosCount(uint32_t glyphCount,
|
||||
SkTextBlob::GlyphPositioning positioning,
|
||||
SkSafeMath* safe);
|
||||
|
||||
uint32_t* textSizePtr() const;
|
||||
|
||||
void grow(uint32_t count);
|
||||
|
||||
bool isExtended() const {
|
||||
return fFlags & kExtended_Flag;
|
||||
}
|
||||
|
||||
SkRunFont fFont;
|
||||
uint32_t fCount;
|
||||
SkPoint fOffset;
|
||||
uint32_t fFlags;
|
||||
|
||||
SkDEBUGCODE(unsigned fMagic;)
|
||||
};
|
||||
|
||||
// (paint->getFlags() & ~kFlagsMask) | fFlags
|
||||
inline SkPaint::SkPaint(const SkPaint& basePaint, const SkRunFont& runFont)
|
||||
: fTypeface{runFont.fTypeface}
|
||||
, fPathEffect{basePaint.fPathEffect}
|
||||
, fShader{basePaint.fShader}
|
||||
, fMaskFilter{basePaint.fMaskFilter}
|
||||
, fColorFilter{basePaint.fColorFilter}
|
||||
, fDrawLooper{basePaint.fDrawLooper}
|
||||
, fImageFilter{basePaint.fImageFilter}
|
||||
, fTextSize{runFont.fSize}
|
||||
, fTextScaleX{runFont.fScaleX}
|
||||
, fTextSkewX{runFont.fSkewX}
|
||||
, fColor4f{basePaint.fColor4f}
|
||||
, fWidth{basePaint.fWidth}
|
||||
, fMiterLimit{basePaint.fMiterLimit}
|
||||
, fBlendMode{basePaint.fBlendMode}
|
||||
, fBitfieldsUInt{(basePaint.fBitfieldsUInt & ~SkRunFont::kFlagsMask) | runFont.fFlags} {
|
||||
fBitfields.fTextEncoding = kGlyphID_TextEncoding;
|
||||
fBitfields.fHinting = runFont.fHinting;
|
||||
fBitfields.fTextAlign = runFont.fAlign;
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterate through all of the text runs of the text blob. For example:
|
||||
* for (SkTextBlobRunIterator it(blob); !it.done(); it.next()) {
|
||||
@ -65,18 +261,45 @@ public:
|
||||
kFull_Positioning = 2 // Point positioning -- two scalars per glyph.
|
||||
};
|
||||
|
||||
bool done() const;
|
||||
bool done() const {
|
||||
return !fCurrentRun;
|
||||
}
|
||||
void next();
|
||||
|
||||
uint32_t glyphCount() const;
|
||||
const uint16_t* glyphs() const;
|
||||
const SkScalar* pos() const;
|
||||
const SkPoint& offset() const;
|
||||
uint32_t glyphCount() const {
|
||||
SkASSERT(!this->done());
|
||||
return fCurrentRun->glyphCount();
|
||||
}
|
||||
const uint16_t* glyphs() const {
|
||||
SkASSERT(!this->done());
|
||||
return fCurrentRun->glyphBuffer();
|
||||
}
|
||||
const SkScalar* pos() const {
|
||||
SkASSERT(!this->done());
|
||||
return fCurrentRun->posBuffer();
|
||||
}
|
||||
const SkPoint& offset() const {
|
||||
SkASSERT(!this->done());
|
||||
return fCurrentRun->offset();
|
||||
}
|
||||
const SkRunFont& runFont() const {
|
||||
SkASSERT(!this->done());
|
||||
return fCurrentRun->font();
|
||||
}
|
||||
void applyFontToPaint(SkPaint*) const;
|
||||
GlyphPositioning positioning() const;
|
||||
uint32_t* clusters() const;
|
||||
uint32_t textSize() const;
|
||||
char* text() const;
|
||||
uint32_t* clusters() const {
|
||||
SkASSERT(!this->done());
|
||||
return fCurrentRun->clusterBuffer();
|
||||
}
|
||||
uint32_t textSize() const {
|
||||
SkASSERT(!this->done());
|
||||
return fCurrentRun->textSize();
|
||||
}
|
||||
char* text() const {
|
||||
SkASSERT(!this->done());
|
||||
return fCurrentRun->textBuffer();
|
||||
}
|
||||
|
||||
bool isLCD() const;
|
||||
|
||||
|
@ -492,7 +492,7 @@ DEF_TEST(SkPDF_Primitives_Color, reporter) {
|
||||
static SkGlyphRun make_run(size_t len, const SkGlyphID* glyphs, SkPoint* pos,
|
||||
SkPaint paint, const uint32_t* clusters,
|
||||
size_t utf8TextByteLength, const char* utf8Text) {
|
||||
return SkGlyphRun(std::move(paint),
|
||||
return SkGlyphRun(paint, SkRunFont{paint},
|
||||
SkSpan<const uint16_t>{}, // No dense indices for now.
|
||||
SkSpan<const SkPoint>{pos, len},
|
||||
SkSpan<const SkGlyphID>{glyphs, len},
|
||||
|
Loading…
Reference in New Issue
Block a user