Plumbing for glyph drawable
The plumbing necessary to allow glyphs to have an associated drawable. The TestSVGTypeface is updated to produce drawables for testing. Bug: skia:12121 Change-Id: I475a1bfc27bf11e732e18bed3c1a9593e7c901cd Reviewed-on: https://skia-review.googlesource.com/c/skia/+/413438 Reviewed-by: Derek Sollenberger <djsollen@google.com> Reviewed-by: Herb Derby <herb@google.com> Commit-Queue: Ben Wagner <bungeman@google.com>
This commit is contained in:
parent
ada59c148e
commit
35d25ac79f
@ -103,6 +103,12 @@ public:
|
||||
*/
|
||||
SkRect getBounds();
|
||||
|
||||
/**
|
||||
* Return approximately how many bytes would be freed if this drawable is destroyed.
|
||||
* The base implementation returns 0 to indicate that this is unknown.
|
||||
*/
|
||||
size_t approximateBytesUsed();
|
||||
|
||||
/**
|
||||
* Calling this invalidates the previous generation ID, and causes a new one to be computed
|
||||
* the next time getGenerationID() is called. Typically this is called by the object itself,
|
||||
@ -132,6 +138,7 @@ protected:
|
||||
SkDrawable();
|
||||
|
||||
virtual SkRect onGetBounds() = 0;
|
||||
virtual size_t onApproximateBytesUsed();
|
||||
virtual void onDraw(SkCanvas*) = 0;
|
||||
|
||||
virtual std::unique_ptr<GpuDrawHandler> onSnapGpuDrawHandler(GrBackendApi, const SkMatrix&,
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
|
||||
#include "include/core/SkDrawable.h"
|
||||
#include "include/core/SkSpan.h"
|
||||
#include "include/core/SkTypeface.h"
|
||||
#include "include/private/SkChecksum.h"
|
||||
@ -171,7 +172,8 @@ private:
|
||||
};
|
||||
|
||||
// Paths use a SkWriter32 which requires 4 byte alignment.
|
||||
static const size_t kPathAlignment = 4u;
|
||||
static const size_t kPathAlignment = 4u;
|
||||
static const size_t kDrawableAlignment = 8u;
|
||||
|
||||
// -- StrikeSpec -----------------------------------------------------------------------------------
|
||||
struct StrikeSpec {
|
||||
@ -245,12 +247,15 @@ public:
|
||||
void prepareForPathDrawing(
|
||||
SkDrawableGlyphBuffer* accepted, SkSourceGlyphBuffer* rejected) override;
|
||||
|
||||
void prepareForDrawableDrawing(
|
||||
SkDrawableGlyphBuffer* accepted, SkSourceGlyphBuffer* rejected) override;
|
||||
|
||||
void onAboutToExitScope() override {}
|
||||
|
||||
sk_sp<SkStrike> getUnderlyingStrike() const override { return nullptr; }
|
||||
|
||||
bool hasPendingGlyphs() const {
|
||||
return !fMasksToSend.empty() || !fPathsToSend.empty();
|
||||
return !fMasksToSend.empty() || !fPathsToSend.empty() || !fDrawablesToSend.empty();
|
||||
}
|
||||
|
||||
void resetScalerContext();
|
||||
@ -279,7 +284,27 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
// Same thing as MaskSummary, but for drawables.
|
||||
struct DrawableSummary {
|
||||
constexpr static uint16_t kIsDrawable = 0;
|
||||
SkGlyphID glyphID;
|
||||
// If drawing glyphID can be done with a drawable, this is 0, otherwise it is the max
|
||||
// dimension of the glyph.
|
||||
uint16_t maxDimensionOrDrawable;
|
||||
};
|
||||
|
||||
struct DrawableSummaryTraits {
|
||||
static SkGlyphID GetKey(DrawableSummary summary) {
|
||||
return summary.glyphID;
|
||||
}
|
||||
|
||||
static uint32_t Hash(SkGlyphID packedID) {
|
||||
return SkChecksum::CheapMix(packedID);
|
||||
}
|
||||
};
|
||||
|
||||
void writeGlyphPath(const SkGlyph& glyph, Serializer* serializer) const;
|
||||
void writeGlyphDrawable(const SkGlyph& glyph, Serializer* serializer) const;
|
||||
void ensureScalerContext();
|
||||
|
||||
const SkAutoDescriptor fDescriptor;
|
||||
@ -302,14 +327,16 @@ private:
|
||||
// The masks and paths that currently reside in the GPU process.
|
||||
SkTHashTable<SkGlyphDigest, uint32_t, SkGlyphDigest> fSentGlyphs;
|
||||
SkTHashTable<PathSummary, SkPackedGlyphID, PathSummaryTraits> fSentPaths;
|
||||
SkTHashTable<DrawableSummary, SkGlyphID, DrawableSummaryTraits> fSentDrawables;
|
||||
|
||||
// The Masks, SDFT Mask, and Paths that need to be sent to the GPU task for the processed
|
||||
// TextBlobs. Cleared after diffs are serialized.
|
||||
std::vector<SkGlyph> fMasksToSend;
|
||||
std::vector<SkGlyph> fPathsToSend;
|
||||
std::vector<SkGlyph> fDrawablesToSend;
|
||||
|
||||
// Alloc for storing bits and pieces of paths, Cleared after diffs are serialized.
|
||||
SkArenaAllocWithReset fPathAlloc{256};
|
||||
// Alloc for storing bits and pieces of paths and drawables, Cleared after diffs are serialized.
|
||||
SkArenaAllocWithReset fAlloc{256};
|
||||
};
|
||||
|
||||
RemoteStrike::RemoteStrike(
|
||||
@ -378,7 +405,17 @@ void RemoteStrike::writePendingGlyphs(Serializer* serializer) {
|
||||
this->writeGlyphPath(glyph, serializer);
|
||||
}
|
||||
fPathsToSend.clear();
|
||||
fPathAlloc.reset();
|
||||
|
||||
// Write glyphs drawables.
|
||||
serializer->emplace<uint64_t>(fDrawablesToSend.size());
|
||||
for (SkGlyph& glyph : fDrawablesToSend) {
|
||||
SkASSERT(SkMask::IsValidFormat(glyph.maskFormat()));
|
||||
|
||||
write_glyph(glyph, serializer);
|
||||
writeGlyphDrawable(glyph, serializer);
|
||||
}
|
||||
fDrawablesToSend.clear();
|
||||
fAlloc.reset();
|
||||
}
|
||||
|
||||
void RemoteStrike::ensureScalerContext() {
|
||||
@ -396,8 +433,7 @@ void RemoteStrike::setStrikeSpec(const SkStrikeSpec& strikeSpec) {
|
||||
fStrikeSpec = &strikeSpec;
|
||||
}
|
||||
|
||||
void RemoteStrike::writeGlyphPath(
|
||||
const SkGlyph& glyph, Serializer* serializer) const {
|
||||
void RemoteStrike::writeGlyphPath(const SkGlyph& glyph, Serializer* serializer) const {
|
||||
const SkPath* path = glyph.path();
|
||||
|
||||
if (path == nullptr) {
|
||||
@ -412,6 +448,25 @@ void RemoteStrike::writeGlyphPath(
|
||||
serializer->write<bool>(glyph.pathIsHairline());
|
||||
}
|
||||
|
||||
void RemoteStrike::writeGlyphDrawable(const SkGlyph& glyph, Serializer* serializer) const {
|
||||
if (glyph.isEmpty()) {
|
||||
serializer->write<uint64_t>(0u);
|
||||
return;
|
||||
}
|
||||
|
||||
SkDrawable* drawable = glyph.drawable();
|
||||
|
||||
if (drawable == nullptr) {
|
||||
serializer->write<uint64_t>(0u);
|
||||
return;
|
||||
}
|
||||
|
||||
sk_sp<SkPicture> picture(drawable->newPictureSnapshot());
|
||||
sk_sp<SkData> data = picture->serialize();
|
||||
serializer->write<uint64_t>(data->size());
|
||||
memcpy(serializer->allocate(data->size(), kDrawableAlignment), data->data(), data->size());
|
||||
}
|
||||
|
||||
template <typename Rejector>
|
||||
void RemoteStrike::commonMaskLoop(
|
||||
SkDrawableGlyphBuffer* accepted, SkSourceGlyphBuffer* rejected, Rejector&& reject) {
|
||||
@ -421,7 +476,7 @@ void RemoteStrike::commonMaskLoop(
|
||||
if (digest == nullptr) {
|
||||
// Put the new SkGlyph in the glyphs to send.
|
||||
this->ensureScalerContext();
|
||||
fMasksToSend.emplace_back(fContext->makeGlyph(packedID, &fPathAlloc));
|
||||
fMasksToSend.emplace_back(fContext->makeGlyph(packedID, &fAlloc));
|
||||
SkGlyph* glyph = &fMasksToSend.back();
|
||||
|
||||
SkGlyphDigest newDigest{0, *glyph};
|
||||
@ -453,7 +508,7 @@ void RemoteStrike::prepareForMaskDrawing(
|
||||
|
||||
// Put the new SkGlyph in the glyphs to send.
|
||||
this->ensureScalerContext();
|
||||
fMasksToSend.emplace_back(fContext->makeGlyph(packedID, &fPathAlloc));
|
||||
fMasksToSend.emplace_back(fContext->makeGlyph(packedID, &fAlloc));
|
||||
SkGlyph* glyph = &fMasksToSend.back();
|
||||
|
||||
SkGlyphDigest newDigest{0, *glyph};
|
||||
@ -488,11 +543,11 @@ void RemoteStrike::prepareForPathDrawing(
|
||||
|
||||
// Put the new SkGlyph in the glyphs to send.
|
||||
this->ensureScalerContext();
|
||||
fPathsToSend.emplace_back(fContext->makeGlyph(packedID, &fPathAlloc));
|
||||
fPathsToSend.emplace_back(fContext->makeGlyph(packedID, &fAlloc));
|
||||
SkGlyph* glyph = &fPathsToSend.back();
|
||||
|
||||
uint16_t maxDimensionOrPath = glyph->maxDimension();
|
||||
glyph->setPath(&fPathAlloc, fContext.get());
|
||||
glyph->setPath(&fAlloc, fContext.get());
|
||||
if (glyph->path() != nullptr) {
|
||||
maxDimensionOrPath = PathSummary::kIsPath;
|
||||
}
|
||||
@ -507,6 +562,35 @@ void RemoteStrike::prepareForPathDrawing(
|
||||
});
|
||||
}
|
||||
|
||||
void RemoteStrike::prepareForDrawableDrawing(
|
||||
SkDrawableGlyphBuffer* accepted, SkSourceGlyphBuffer* rejected) {
|
||||
accepted->forEachInput(
|
||||
[&](size_t i, SkPackedGlyphID packedID, SkPoint position) {
|
||||
SkGlyphID glyphID = packedID.glyphID();
|
||||
DrawableSummary* summary = fSentDrawables.find(glyphID);
|
||||
if (summary == nullptr) {
|
||||
|
||||
// Put the new SkGlyph in the glyphs to send.
|
||||
this->ensureScalerContext();
|
||||
fDrawablesToSend.emplace_back(fContext->makeGlyph(packedID, &fAlloc));
|
||||
SkGlyph* glyph = &fDrawablesToSend.back();
|
||||
|
||||
uint16_t maxDimensionOrDrawable = glyph->maxDimension();
|
||||
glyph->setDrawable(&fAlloc, fContext.get());
|
||||
if (glyph->drawable() != nullptr) {
|
||||
maxDimensionOrDrawable = DrawableSummary::kIsDrawable;
|
||||
}
|
||||
|
||||
DrawableSummary newSummary = {glyph->getGlyphID(), maxDimensionOrDrawable};
|
||||
summary = fSentDrawables.set(newSummary);
|
||||
}
|
||||
|
||||
if (summary->maxDimensionOrDrawable != DrawableSummary::kIsDrawable) {
|
||||
rejected->reject(i, (int)summary->maxDimensionOrDrawable);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// -- WireTypeface ---------------------------------------------------------------------------------
|
||||
struct WireTypeface {
|
||||
WireTypeface() = default;
|
||||
@ -866,6 +950,18 @@ public:
|
||||
bool readStrikeData(const volatile void* memory, size_t memorySize);
|
||||
|
||||
private:
|
||||
class PictureBackedGlyphDrawable final : public SkDrawable {
|
||||
public:
|
||||
PictureBackedGlyphDrawable(sk_sp<SkPicture> self) : fSelf(std::move(self)) {}
|
||||
private:
|
||||
sk_sp<SkPicture> fSelf;
|
||||
SkRect onGetBounds() override { return fSelf->cullRect(); }
|
||||
size_t onApproximateBytesUsed() override {
|
||||
return sizeof(PictureBackedGlyphDrawable) + fSelf->approximateBytesUsed();
|
||||
}
|
||||
void onDraw(SkCanvas* canvas) override { canvas->drawPicture(fSelf); }
|
||||
};
|
||||
|
||||
static bool ReadGlyph(SkTLazy<SkGlyph>& glyph, Deserializer* deserializer);
|
||||
sk_sp<SkTypeface> addTypeface(const WireTypeface& wire);
|
||||
|
||||
@ -923,6 +1019,7 @@ bool SkStrikeClientImpl::readStrikeData(const volatile void* memory, size_t memo
|
||||
uint64_t strikeCount = 0;
|
||||
uint64_t glyphImagesCount = 0;
|
||||
uint64_t glyphPathsCount = 0;
|
||||
uint64_t glyphDrawablesCount = 0;
|
||||
|
||||
if (!deserializer.read<uint64_t>(&typefaceSize)) READ_FAILURE
|
||||
for (size_t i = 0; i < typefaceSize; ++i) {
|
||||
@ -1028,6 +1125,30 @@ bool SkStrikeClientImpl::readStrikeData(const volatile void* memory, size_t memo
|
||||
|
||||
strike->mergePath(allocatedGlyph, pathPtr, hairline);
|
||||
}
|
||||
|
||||
if (!deserializer.read<uint64_t>(&glyphDrawablesCount)) READ_FAILURE
|
||||
for (size_t j = 0; j < glyphDrawablesCount; j++) {
|
||||
SkTLazy<SkGlyph> glyph;
|
||||
if (!ReadGlyph(glyph, &deserializer)) READ_FAILURE
|
||||
|
||||
SkGlyph* allocatedGlyph = strike->mergeGlyphAndImage(glyph->getPackedID(), *glyph);
|
||||
|
||||
sk_sp<SkDrawable> drawable;
|
||||
uint64_t drawableSize = 0u;
|
||||
if (!deserializer.read<uint64_t>(&drawableSize)) READ_FAILURE
|
||||
|
||||
if (drawableSize > 0) {
|
||||
auto* drawableData = deserializer.read(drawableSize, kDrawableAlignment);
|
||||
if (!drawableData) READ_FAILURE
|
||||
sk_sp<SkPicture> picture(SkPicture::MakeFromData(
|
||||
const_cast<const void*>(drawableData), drawableSize));
|
||||
if (!picture) READ_FAILURE
|
||||
|
||||
drawable = sk_make_sp<PictureBackedGlyphDrawable>(std::move(picture));
|
||||
}
|
||||
|
||||
strike->mergeDrawable(allocatedGlyph, std::move(drawable));
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(SK_TRACE_GLYPH_RUN_PROCESS)
|
||||
|
@ -62,6 +62,13 @@ SkRect SkDrawable::getBounds() {
|
||||
return this->onGetBounds();
|
||||
}
|
||||
|
||||
size_t SkDrawable::approximateBytesUsed() {
|
||||
return this->onApproximateBytesUsed();
|
||||
}
|
||||
size_t SkDrawable::onApproximateBytesUsed() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void SkDrawable::notifyDrawingChanged() {
|
||||
fGenerationID = 0;
|
||||
}
|
||||
|
@ -7,11 +7,18 @@
|
||||
|
||||
#include "src/core/SkGlyph.h"
|
||||
|
||||
#include "include/core/SkDrawable.h"
|
||||
#include "src/core/SkArenaAlloc.h"
|
||||
#include "src/core/SkScalerContext.h"
|
||||
#include "src/pathops/SkPathOpsCubic.h"
|
||||
#include "src/pathops/SkPathOpsQuad.h"
|
||||
|
||||
SkGlyph::SkGlyph(const SkGlyph&) = default;
|
||||
SkGlyph& SkGlyph::operator=(const SkGlyph&) = default;
|
||||
SkGlyph::SkGlyph(SkGlyph&&) = default;
|
||||
SkGlyph& SkGlyph::operator=(SkGlyph&&) = default;
|
||||
SkGlyph::~SkGlyph() = default;
|
||||
|
||||
SkMask SkGlyph::mask() const {
|
||||
SkMask mask;
|
||||
mask.fImage = (uint8_t*)fImage;
|
||||
@ -189,6 +196,43 @@ bool SkGlyph::pathIsHairline() const {
|
||||
return fPathData->fHairline;
|
||||
}
|
||||
|
||||
void SkGlyph::installDrawable(SkArenaAlloc* alloc, sk_sp<SkDrawable> drawable) {
|
||||
SkASSERT(fDrawableData == nullptr);
|
||||
SkASSERT(!this->setDrawableHasBeenCalled());
|
||||
fDrawableData = alloc->make<SkGlyph::DrawableData>();
|
||||
if (drawable != nullptr) {
|
||||
fDrawableData->fDrawable = std::move(drawable);
|
||||
fDrawableData->fDrawable->getGenerationID();
|
||||
fDrawableData->fHasDrawable = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool SkGlyph::setDrawable(SkArenaAlloc* alloc, SkScalerContext* scalerContext) {
|
||||
if (!this->setDrawableHasBeenCalled()) {
|
||||
sk_sp<SkDrawable> drawable = scalerContext->getDrawable(*this);
|
||||
this->installDrawable(alloc, std::move(drawable));
|
||||
return this->drawable() != nullptr;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SkGlyph::setDrawable(SkArenaAlloc* alloc, sk_sp<SkDrawable> drawable) {
|
||||
if (!this->setDrawableHasBeenCalled()) {
|
||||
this->installDrawable(alloc, std::move(drawable));
|
||||
return this->drawable() != nullptr;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
SkDrawable* SkGlyph::drawable() const {
|
||||
// setDrawable must have been called previously.
|
||||
SkASSERT(this->setDrawableHasBeenCalled());
|
||||
if (fDrawableData->fHasDrawable) {
|
||||
return fDrawableData->fDrawable.get();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static std::tuple<SkScalar, SkScalar> calculate_path_gap(
|
||||
SkScalar topOffset, SkScalar bottomOffset, const SkPath& path) {
|
||||
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "src/core/SkStrikeForGPU.h"
|
||||
|
||||
class SkArenaAlloc;
|
||||
class SkDrawable;
|
||||
class SkScalerContext;
|
||||
|
||||
// A combination of SkGlyphID and sub-pixel position information.
|
||||
@ -280,6 +281,11 @@ class SkGlyph {
|
||||
public:
|
||||
// SkGlyph() is used for testing.
|
||||
constexpr SkGlyph() : SkGlyph{SkPackedGlyphID()} { }
|
||||
SkGlyph(const SkGlyph&);
|
||||
SkGlyph& operator=(const SkGlyph&);
|
||||
SkGlyph(SkGlyph&&);
|
||||
SkGlyph& operator=(SkGlyph&&);
|
||||
~SkGlyph();
|
||||
constexpr explicit SkGlyph(SkPackedGlyphID id) : fID{id} { }
|
||||
|
||||
SkVector advanceVector() const { return SkVector{fAdvanceX, fAdvanceY}; }
|
||||
@ -349,6 +355,11 @@ public:
|
||||
const SkPath* path() const;
|
||||
bool pathIsHairline() const;
|
||||
|
||||
bool setDrawable(SkArenaAlloc* alloc, SkScalerContext* scalerContext);
|
||||
bool setDrawable(SkArenaAlloc* alloc, sk_sp<SkDrawable> drawable);
|
||||
bool setDrawableHasBeenCalled() const { return fDrawableData != nullptr; }
|
||||
SkDrawable* drawable() const;
|
||||
|
||||
// Format
|
||||
bool isColor() const { return fMaskFormat == SkMask::kARGB32_Format; }
|
||||
SkMask::Format maskFormat() const { return fMaskFormat; }
|
||||
@ -428,11 +439,20 @@ private:
|
||||
bool fHairline{false};
|
||||
};
|
||||
|
||||
struct DrawableData {
|
||||
Intercept* fIntercept{nullptr};
|
||||
sk_sp<SkDrawable> fDrawable;
|
||||
bool fHasDrawable{false};
|
||||
};
|
||||
|
||||
size_t allocImage(SkArenaAlloc* alloc);
|
||||
|
||||
// path == nullptr indicates that there is no path.
|
||||
void installPath(SkArenaAlloc* alloc, const SkPath* path, bool hairline);
|
||||
|
||||
// drawable == nullptr indicates that there is no path.
|
||||
void installDrawable(SkArenaAlloc* alloc, sk_sp<SkDrawable> drawable);
|
||||
|
||||
// The width and height of the glyph mask.
|
||||
uint16_t fWidth = 0,
|
||||
fHeight = 0;
|
||||
@ -448,6 +468,7 @@ private:
|
||||
// else if fPathData is not null, then a path has been requested. The fPath field of fPathData
|
||||
// may still be null after the request meaning that there is no path for this glyph.
|
||||
PathData* fPathData = nullptr;
|
||||
DrawableData* fDrawableData = nullptr;
|
||||
|
||||
// The advance for this glyph.
|
||||
float fAdvanceX = 0,
|
||||
|
@ -16,6 +16,8 @@
|
||||
|
||||
class SkStrikeForGPU;
|
||||
struct SkGlyphPositionRoundingSpec;
|
||||
class SkPath;
|
||||
class SkDrawable;
|
||||
|
||||
// SkSourceGlyphBuffer is the source of glyphs between the different stages of glyph drawing.
|
||||
// It starts with the glyphs and positions from the SkGlyphRun as the first source. When glyphs
|
||||
@ -110,6 +112,11 @@ public:
|
||||
SkDEBUGCODE(fTag = kPath);
|
||||
return *this;
|
||||
}
|
||||
SkGlyphVariant& operator= (SkDrawable* drawable) {
|
||||
fV.drawable = drawable;
|
||||
SkDEBUGCODE(fTag = kDrawable);
|
||||
return *this;
|
||||
}
|
||||
|
||||
SkGlyph* glyph() const {
|
||||
SkASSERT(fTag == kGlyph);
|
||||
@ -119,19 +126,25 @@ public:
|
||||
SkASSERT(fTag == kPath);
|
||||
return fV.path;
|
||||
}
|
||||
SkDrawable* drawable() const {
|
||||
SkASSERT(fTag == kDrawable);
|
||||
return fV.drawable;
|
||||
}
|
||||
SkPackedGlyphID packedID() const {
|
||||
SkASSERT(fTag == kPackedID);
|
||||
return fV.packedID;
|
||||
}
|
||||
|
||||
operator SkPackedGlyphID() const { return this->packedID(); }
|
||||
operator SkGlyph*() const { return this->glyph(); }
|
||||
operator const SkPath*() const { return this->path(); }
|
||||
operator SkPackedGlyphID() const { return this->packedID(); }
|
||||
operator SkGlyph*() const { return this->glyph(); }
|
||||
operator const SkPath*() const { return this->path(); }
|
||||
operator const SkDrawable*()const { return this->drawable(); }
|
||||
|
||||
private:
|
||||
union {
|
||||
SkGlyph* glyph;
|
||||
const SkPath* path;
|
||||
SkDrawable* drawable;
|
||||
SkPackedGlyphID packedID;
|
||||
} fV;
|
||||
|
||||
@ -140,7 +153,8 @@ private:
|
||||
kEmpty,
|
||||
kPackedID,
|
||||
kGlyph,
|
||||
kPath
|
||||
kPath,
|
||||
kDrawable,
|
||||
} fTag{kEmpty};
|
||||
#endif
|
||||
};
|
||||
@ -208,6 +222,15 @@ public:
|
||||
fAcceptedSize++;
|
||||
}
|
||||
|
||||
// Store drawable in the next slot, using the position information located at index from.
|
||||
void accept(SkDrawable* drawable, size_t from) {
|
||||
SkASSERT(fPhase == kProcess);
|
||||
SkASSERT(fAcceptedSize <= from);
|
||||
fPositions[fAcceptedSize] = fPositions[from];
|
||||
fMultiBuffer[fAcceptedSize] = drawable;
|
||||
fAcceptedSize++;
|
||||
}
|
||||
|
||||
// The result after a series of `accept` of accepted SkGlyph* or SkPath*.
|
||||
SkZip<SkGlyphVariant, SkPoint> accepted() {
|
||||
SkASSERT(fPhase == kProcess);
|
||||
|
@ -146,6 +146,23 @@ void SkGlyphRunListPainter::drawForBitmapDevice(
|
||||
canvas->drawPath(deviceOutline, pathPaint);
|
||||
}
|
||||
}
|
||||
|
||||
fAccepted.startSource(fRejected.source());
|
||||
strike->prepareForDrawableDrawing(&fAccepted, &fRejected);
|
||||
fRejected.flipRejectsToSource();
|
||||
|
||||
for (auto [variant, pos] : fAccepted.accepted()) {
|
||||
SkDrawable* drawable = variant.drawable();
|
||||
SkMatrix m;
|
||||
SkPoint translate = drawOrigin + pos;
|
||||
m.setScaleTranslate(strikeToSourceScale, strikeToSourceScale,
|
||||
translate.x(), translate.y());
|
||||
SkAutoCanvasRestore acr(canvas, false);
|
||||
SkRect drawableBounds = drawable->getBounds();
|
||||
m.mapRect(&drawableBounds);
|
||||
canvas->saveLayer(&drawableBounds, &paint);
|
||||
drawable->draw(canvas, &m);
|
||||
}
|
||||
}
|
||||
if (!fRejected.source().empty() && !deviceMatrix.hasPerspective()) {
|
||||
SkStrikeSpec strikeSpec = SkStrikeSpec::MakeMask(
|
||||
@ -349,6 +366,34 @@ void SkGlyphRunListPainter::processGlyphRun(SkGlyphRunPainterInterface* process,
|
||||
// maxDimensionInSourceSpace is used to calculate the factor from strike space to source
|
||||
// space.
|
||||
SkScalar maxDimensionInSourceSpace = 0.0;
|
||||
if (!fRejected.source().empty()) {
|
||||
// Drawable case - handle big things with that have a drawable.
|
||||
auto [strikeSpec, strikeToSourceScale] =
|
||||
SkStrikeSpec::MakePath(runFont, runPaint, fDeviceProps, fScalerContextFlags);
|
||||
|
||||
#if defined(SK_TRACE_GLYPH_RUN_PROCESS)
|
||||
msg.appendf(" Drawable case:\n%s", strikeSpec.dump().c_str());
|
||||
#endif
|
||||
|
||||
if (!SkScalarNearlyZero(strikeToSourceScale)) {
|
||||
SkScopedStrikeForGPU strike = strikeSpec.findOrCreateScopedStrike(fStrikeCache);
|
||||
|
||||
fAccepted.startSource(fRejected.source());
|
||||
#if defined(SK_TRACE_GLYPH_RUN_PROCESS)
|
||||
msg.appendf(" glyphs:(x,y):\n %s\n", fAccepted.dumpInput().c_str());
|
||||
#endif
|
||||
strike->prepareForDrawableDrawing(&fAccepted, &fRejected);
|
||||
fRejected.flipRejectsToSource();
|
||||
auto [minHint, maxHint] = fRejected.maxDimensionHint();
|
||||
maxDimensionInSourceSpace = SkScalarCeilToScalar(maxHint * strikeToSourceScale);
|
||||
|
||||
if (process && !fAccepted.empty()) {
|
||||
// processSourceDrawables must be called even if there are no glyphs to make sure
|
||||
// runs are set correctly.
|
||||
process->processSourceDrawables(fAccepted.accepted(), runFont, strikeToSourceScale);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!fRejected.source().empty()) {
|
||||
// Path case - handle big things without color and that have a path.
|
||||
auto [strikeSpec, strikeToSourceScale] =
|
||||
|
@ -146,6 +146,10 @@ public:
|
||||
const SkFont& runFont,
|
||||
SkScalar strikeToSourceScale) = 0;
|
||||
|
||||
virtual void processSourceDrawables(const SkZip<SkGlyphVariant, SkPoint>& accepted,
|
||||
const SkFont& runFont,
|
||||
SkScalar strikeToSourceScale) = 0;
|
||||
|
||||
virtual void processSourceSDFT(const SkZip<SkGlyphVariant, SkPoint>& accepted,
|
||||
sk_sp<SkStrike>&& strike,
|
||||
SkScalar strikeToSourceScale,
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
#include "src/core/SkScalerCache.h"
|
||||
|
||||
#include "include/core/SkDrawable.h"
|
||||
#include "include/core/SkGraphics.h"
|
||||
#include "include/core/SkPath.h"
|
||||
#include "include/core/SkTypeface.h"
|
||||
@ -79,6 +80,28 @@ std::tuple<const SkPath*, size_t> SkScalerCache::mergePath(
|
||||
return {glyph->path(), pathDelta};
|
||||
}
|
||||
|
||||
std::tuple<SkDrawable*, size_t> SkScalerCache::prepareDrawable(SkGlyph* glyph) {
|
||||
size_t delta = 0;
|
||||
if (glyph->setDrawable(&fAlloc, fScalerContext.get())) {
|
||||
delta = glyph->drawable()->approximateBytesUsed();
|
||||
}
|
||||
return {glyph->drawable(), delta};
|
||||
}
|
||||
|
||||
std::tuple<SkDrawable*, size_t> SkScalerCache::mergeDrawable(SkGlyph* glyph,
|
||||
sk_sp<SkDrawable> drawable) {
|
||||
SkAutoMutexExclusive lock{fMu};
|
||||
size_t drawableDelta = 0;
|
||||
if (glyph->setDrawableHasBeenCalled()) {
|
||||
SkDEBUGFAIL("Re-adding drawable to existing glyph. This should not happen.");
|
||||
}
|
||||
if (glyph->setDrawable(&fAlloc, std::move(drawable))) {
|
||||
drawableDelta = glyph->drawable()->approximateBytesUsed();
|
||||
SkASSERT(drawableDelta > 0);
|
||||
}
|
||||
return {glyph->drawable(), drawableDelta};
|
||||
}
|
||||
|
||||
int SkScalerCache::countCachedGlyphs() const {
|
||||
SkAutoMutexExclusive lock(fMu);
|
||||
return fDigestForPackedGlyphID.count();
|
||||
@ -249,6 +272,27 @@ size_t SkScalerCache::prepareForPathDrawing(
|
||||
return delta + pathDelta;
|
||||
}
|
||||
|
||||
size_t SkScalerCache::prepareForDrawableDrawing(
|
||||
SkDrawableGlyphBuffer* accepted, SkSourceGlyphBuffer* rejected) {
|
||||
SkAutoMutexExclusive lock{fMu};
|
||||
size_t drawableDelta = 0;
|
||||
size_t delta = this->commonFilterLoop(accepted,
|
||||
[&](size_t i, SkGlyphDigest digest, SkPoint pos) SK_REQUIRES(fMu) {
|
||||
SkGlyph* glyph = fGlyphForIndex[digest.index()];
|
||||
auto [drawable, drawableSize] = this->prepareDrawable(glyph);
|
||||
drawableDelta += drawableSize;
|
||||
if (drawable != nullptr) {
|
||||
// Save off the drawable to draw later.
|
||||
accepted->accept(drawable, i);
|
||||
} else {
|
||||
// Glyph does not have a drawable.
|
||||
rejected->reject(i, glyph->maxDimension());
|
||||
}
|
||||
});
|
||||
|
||||
return delta + drawableDelta;
|
||||
}
|
||||
|
||||
void SkScalerCache::findIntercepts(const SkScalar bounds[2], SkScalar scale, SkScalar xPos,
|
||||
SkGlyph* glyph, SkScalar* array, int* count) {
|
||||
SkAutoMutexExclusive lock{fMu};
|
||||
|
@ -39,6 +39,10 @@ public:
|
||||
std::tuple<const SkPath*, size_t> mergePath(
|
||||
SkGlyph* glyph, const SkPath* path, bool hairline) SK_EXCLUDES(fMu);
|
||||
|
||||
// If the drawable has never been set, then add a drawble to glyph.
|
||||
std::tuple<SkDrawable*, size_t> mergeDrawable(
|
||||
SkGlyph* glyph, sk_sp<SkDrawable> drawable) SK_EXCLUDES(fMu);
|
||||
|
||||
/** Return the number of glyphs currently cached. */
|
||||
int countCachedGlyphs() const SK_EXCLUDES(fMu);
|
||||
|
||||
@ -77,6 +81,9 @@ public:
|
||||
size_t prepareForPathDrawing(
|
||||
SkDrawableGlyphBuffer* accepted, SkSourceGlyphBuffer* rejected) SK_EXCLUDES(fMu);
|
||||
|
||||
size_t prepareForDrawableDrawing(
|
||||
SkDrawableGlyphBuffer* accepted, SkSourceGlyphBuffer* rejected) SK_EXCLUDES(fMu);
|
||||
|
||||
void dump() const SK_EXCLUDES(fMu);
|
||||
|
||||
SkScalerContext* getScalerContext() const { return fScalerContext.get(); }
|
||||
@ -99,6 +106,9 @@ private:
|
||||
// If the path has never been set, then use the scaler context to add the glyph.
|
||||
std::tuple<const SkPath*, size_t> preparePath(SkGlyph*) SK_REQUIRES(fMu);
|
||||
|
||||
// If the drawable has never been set, then use the scaler context to add the glyph.
|
||||
std::tuple<SkDrawable*, size_t> prepareDrawable(SkGlyph*) SK_REQUIRES(fMu);
|
||||
|
||||
enum PathDetail {
|
||||
kMetricsOnly,
|
||||
kMetricsAndPath
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "include/core/SkPaint.h"
|
||||
#include "src/core/SkScalerContext.h"
|
||||
|
||||
#include "include/core/SkDrawable.h"
|
||||
#include "include/core/SkFontMetrics.h"
|
||||
#include "include/core/SkMaskFilter.h"
|
||||
#include "include/core/SkPathEffect.h"
|
||||
@ -695,6 +696,14 @@ void SkScalerContext::getPath(SkGlyph& glyph, SkArenaAlloc* alloc) {
|
||||
this->internalGetPath(glyph, alloc);
|
||||
}
|
||||
|
||||
sk_sp<SkDrawable> SkScalerContext::getDrawable(SkGlyph& glyph) {
|
||||
return this->generateDrawable(glyph);
|
||||
}
|
||||
//TODO: make pure virtual
|
||||
sk_sp<SkDrawable> SkScalerContext::generateDrawable(const SkGlyph&) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void SkScalerContext::getFontMetrics(SkFontMetrics* fm) {
|
||||
SkASSERT(fm);
|
||||
this->generateFontMetrics(fm);
|
||||
|
@ -295,6 +295,7 @@ public:
|
||||
SkGlyph makeGlyph(SkPackedGlyphID, SkArenaAlloc*);
|
||||
void getImage(const SkGlyph&);
|
||||
void getPath(SkGlyph&, SkArenaAlloc*);
|
||||
sk_sp<SkDrawable> getDrawable(SkGlyph&);
|
||||
void getFontMetrics(SkFontMetrics*);
|
||||
|
||||
/** Return the size in bytes of the associated gamma lookup table
|
||||
@ -396,6 +397,16 @@ protected:
|
||||
*/
|
||||
virtual bool SK_WARN_UNUSED_RESULT generatePath(const SkGlyph&, SkPath*) = 0;
|
||||
|
||||
/** Returns the drawable for the glyph (if any).
|
||||
*
|
||||
* The generated drawable will be lifetime scoped to the lifetime of this scaler context.
|
||||
* This means the drawable may refer to the scaler context and associated font data.
|
||||
*
|
||||
* The drawable does not need to be flattenable (e.g. implement getFactory and getTypeName).
|
||||
* Any necessary serialization will be done with newPictureSnapshot.
|
||||
*/
|
||||
virtual sk_sp<SkDrawable> generateDrawable(const SkGlyph&); // TODO: = 0
|
||||
|
||||
/** Retrieves font metrics. */
|
||||
virtual void generateFontMetrics(SkFontMetrics*) = 0;
|
||||
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
#include "include/core/SkDrawable.h"
|
||||
#include "include/private/SkSpinlock.h"
|
||||
#include "include/private/SkTemplates.h"
|
||||
#include "src/core/SkDescriptor.h"
|
||||
@ -61,6 +62,12 @@ public:
|
||||
return glyphPath;
|
||||
}
|
||||
|
||||
const SkDrawable* mergeDrawable(SkGlyph* glyph, sk_sp<SkDrawable> drawable) {
|
||||
auto [glyphDrawable, increase] = fScalerCache.mergeDrawable(glyph, std::move(drawable));
|
||||
this->updateDelta(increase);
|
||||
return glyphDrawable;
|
||||
}
|
||||
|
||||
// [[deprecated]]
|
||||
SkScalerContext* getScalerContext() const {
|
||||
return fScalerCache.getScalerContext();
|
||||
@ -135,6 +142,12 @@ public:
|
||||
this->updateDelta(increase);
|
||||
}
|
||||
|
||||
void prepareForDrawableDrawing(
|
||||
SkDrawableGlyphBuffer* accepted, SkSourceGlyphBuffer* rejected) override {
|
||||
size_t increase = fScalerCache.prepareForDrawableDrawing(accepted, rejected);
|
||||
this->updateDelta(increase);
|
||||
}
|
||||
|
||||
void onAboutToExitScope() override {
|
||||
this->unref();
|
||||
}
|
||||
|
@ -41,6 +41,9 @@ public:
|
||||
virtual void prepareForPathDrawing(
|
||||
SkDrawableGlyphBuffer* accepted, SkSourceGlyphBuffer* rejected) = 0;
|
||||
|
||||
virtual void prepareForDrawableDrawing(
|
||||
SkDrawableGlyphBuffer* accepted, SkSourceGlyphBuffer* rejected) = 0;
|
||||
|
||||
virtual const SkGlyphPositionRoundingSpec& roundingSpec() const = 0;
|
||||
|
||||
// Used with SkScopedStrikeForGPU to take action at the end of a scope.
|
||||
|
@ -510,6 +510,142 @@ private:
|
||||
PathOpSubmitter fPathDrawing;
|
||||
};
|
||||
|
||||
// -- DrawableOpSubmitter --------------------------------------------------------------------------
|
||||
// Shared code for submitting GPU ops for drawing glyphs as drawables.
|
||||
class DrawableOpSubmitter {
|
||||
struct DrawableAndPosition;
|
||||
public:
|
||||
DrawableOpSubmitter(bool isAntiAliased,
|
||||
SkScalar strikeToSourceScale,
|
||||
SkSpan<DrawableAndPosition> drawables,
|
||||
std::unique_ptr<DrawableAndPosition[],
|
||||
GrSubRunAllocator::ArrayDestroyer> drawableData);
|
||||
|
||||
DrawableOpSubmitter(DrawableOpSubmitter&& that);
|
||||
|
||||
static DrawableOpSubmitter Make(const SkZip<SkGlyphVariant, SkPoint>& accepted,
|
||||
bool isAntiAliased,
|
||||
SkScalar strikeToSourceScale,
|
||||
GrSubRunAllocator* alloc);
|
||||
|
||||
void submitOps(SkCanvas*,
|
||||
const GrClip* clip,
|
||||
const SkMatrixProvider& viewMatrix,
|
||||
SkPoint drawOrigin,
|
||||
const SkPaint& paint,
|
||||
skgpu::v1::SurfaceDrawContext* sdc) const;
|
||||
|
||||
private:
|
||||
struct DrawableAndPosition {
|
||||
sk_sp<SkDrawable> fDrawable;
|
||||
SkPoint fPosition;
|
||||
};
|
||||
const bool fIsAntiAliased;
|
||||
const SkScalar fStrikeToSourceScale;
|
||||
const SkSpan<const DrawableAndPosition> fDrawables;
|
||||
std::unique_ptr<DrawableAndPosition[], GrSubRunAllocator::ArrayDestroyer> fDrawableData;
|
||||
};
|
||||
|
||||
DrawableOpSubmitter::DrawableOpSubmitter(
|
||||
bool isAntiAliased,
|
||||
SkScalar strikeToSourceScale,
|
||||
SkSpan<DrawableAndPosition> drawables,
|
||||
std::unique_ptr<DrawableAndPosition[], GrSubRunAllocator::ArrayDestroyer> drawableData)
|
||||
: fIsAntiAliased{isAntiAliased}
|
||||
, fStrikeToSourceScale{strikeToSourceScale}
|
||||
, fDrawables{drawables}
|
||||
, fDrawableData{std::move(drawableData)} {
|
||||
SkASSERT(!fDrawables.empty());
|
||||
}
|
||||
|
||||
DrawableOpSubmitter::DrawableOpSubmitter(DrawableOpSubmitter&& that)
|
||||
: fIsAntiAliased{that.fIsAntiAliased}
|
||||
, fStrikeToSourceScale{that.fStrikeToSourceScale}
|
||||
, fDrawables{that.fDrawables}
|
||||
, fDrawableData{std::move(that.fDrawableData)} {}
|
||||
|
||||
DrawableOpSubmitter DrawableOpSubmitter::Make(const SkZip<SkGlyphVariant, SkPoint>& accepted,
|
||||
bool isAntiAliased,
|
||||
SkScalar strikeToSourceScale,
|
||||
GrSubRunAllocator* alloc) {
|
||||
auto drawableData = alloc->makeUniqueArray<DrawableAndPosition>(
|
||||
accepted.size(),
|
||||
[&](int i){
|
||||
auto [variant, pos] = accepted[i];
|
||||
return DrawableAndPosition{sk_ref_sp(variant.drawable()), pos};
|
||||
});
|
||||
SkSpan<DrawableAndPosition> drawables{drawableData.get(), accepted.size()};
|
||||
|
||||
return DrawableOpSubmitter{isAntiAliased, strikeToSourceScale,
|
||||
drawables, std::move(drawableData)};
|
||||
}
|
||||
|
||||
void DrawableOpSubmitter::submitOps(SkCanvas* canvas,
|
||||
const GrClip* clip,
|
||||
const SkMatrixProvider& viewMatrix,
|
||||
SkPoint drawOrigin,
|
||||
const SkPaint& paint,
|
||||
skgpu::v1::SurfaceDrawContext* sdc) const {
|
||||
// Calculate the matrix that maps the path glyphs from their size in the strike to
|
||||
// the graphics source space.
|
||||
SkMatrix strikeToSource = SkMatrix::Scale(fStrikeToSourceScale, fStrikeToSourceScale);
|
||||
strikeToSource.postTranslate(drawOrigin.x(), drawOrigin.y());
|
||||
|
||||
// Transform the path to device because the deviceMatrix must be unchanged to
|
||||
// draw effect, filter or shader paths.
|
||||
for (const auto& pathPos : fDrawables) {
|
||||
const sk_sp<SkDrawable>& drawable = pathPos.fDrawable;
|
||||
const SkPoint pos = pathPos.fPosition;
|
||||
// Transform the glyph to source space.
|
||||
SkMatrix pathMatrix = strikeToSource;
|
||||
pathMatrix.postTranslate(pos.x(), pos.y());
|
||||
|
||||
SkAutoCanvasRestore acr(canvas, false);
|
||||
SkRect drawableBounds = drawable->getBounds();
|
||||
pathMatrix.mapRect(&drawableBounds);
|
||||
canvas->saveLayer(&drawableBounds, &paint);
|
||||
drawable->draw(canvas, &pathMatrix);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename SubRun>
|
||||
GrSubRunOwner make_drawable_sub_run(const SkZip<SkGlyphVariant, SkPoint>& drawables,
|
||||
bool isAntiAliased,
|
||||
SkScalar strikeToSourceScale,
|
||||
GrSubRunAllocator* alloc) {
|
||||
return alloc->makeUnique<SubRun>(
|
||||
DrawableOpSubmitter::Make(drawables, isAntiAliased, strikeToSourceScale, alloc));
|
||||
}
|
||||
|
||||
// -- DrawableSubRunSlug ---------------------------------------------------------------------------
|
||||
class DrawableSubRunSlug : public GrSubRun {
|
||||
public:
|
||||
DrawableSubRunSlug(DrawableOpSubmitter&& drawingDrawing) : fDrawingDrawing(std::move(drawingDrawing)) {}
|
||||
|
||||
void draw(SkCanvas* canvas,
|
||||
const GrClip* clip,
|
||||
const SkMatrixProvider& viewMatrix,
|
||||
SkPoint drawOrigin,
|
||||
const SkPaint& paint,
|
||||
skgpu::v1::SurfaceDrawContext* sdc) const override {
|
||||
fDrawingDrawing.submitOps(canvas, clip, viewMatrix, drawOrigin, paint, sdc);
|
||||
}
|
||||
|
||||
private:
|
||||
DrawableOpSubmitter fDrawingDrawing;
|
||||
};
|
||||
|
||||
// -- DrawableSubRun -------------------------------------------------------------------------------
|
||||
class DrawableSubRun final : public DrawableSubRunSlug, public GrBlobSubRun {
|
||||
public:
|
||||
using DrawableSubRunSlug::DrawableSubRunSlug;
|
||||
const GrBlobSubRun* blobCast() const override { return this; }
|
||||
bool canReuse(const SkPaint& paint, const SkMatrix& positionMatrix) const override {
|
||||
return true;
|
||||
}
|
||||
const GrAtlasSubRun* testingOnly_atlasSubRun() const override { return nullptr; }
|
||||
};
|
||||
|
||||
// -- GlyphVector ----------------------------------------------------------------------------------
|
||||
// GlyphVector provides a way to delay the lookup of GrGlyphs until the code is running on the
|
||||
// GPU in single threaded mode. The GlyphVector is created in a multi-threaded environment, but
|
||||
@ -1825,6 +1961,13 @@ void GrTextBlob::processSourcePaths(const SkZip<SkGlyphVariant, SkPoint>& accept
|
||||
accepted, has_some_antialiasing(runFont), strikeToSourceScale, &fAlloc));
|
||||
}
|
||||
|
||||
void GrTextBlob::processSourceDrawables(const SkZip<SkGlyphVariant, SkPoint>& accepted,
|
||||
const SkFont& runFont,
|
||||
SkScalar strikeToSourceScale) {
|
||||
fSubRunList.append(make_drawable_sub_run<DrawableSubRun>(
|
||||
accepted, has_some_antialiasing(runFont), strikeToSourceScale, &fAlloc));
|
||||
}
|
||||
|
||||
void GrTextBlob::processSourceSDFT(const SkZip<SkGlyphVariant, SkPoint>& accepted,
|
||||
sk_sp<SkStrike>&& strike,
|
||||
SkScalar strikeToSourceScale,
|
||||
@ -2533,6 +2676,18 @@ void GrSubRunNoCachePainter::processSourcePaths(const SkZip<SkGlyphVariant, SkPo
|
||||
pathDrawing.submitOps(fCanvas, fClip, fViewMatrix, fGlyphRunList.origin(), fPaint, fSDC);
|
||||
}
|
||||
|
||||
void GrSubRunNoCachePainter::processSourceDrawables(const SkZip<SkGlyphVariant, SkPoint>& accepted,
|
||||
const SkFont& runFont,
|
||||
SkScalar strikeToSourceScale) {
|
||||
DrawableOpSubmitter drawableDrawing =
|
||||
DrawableOpSubmitter::Make(accepted,
|
||||
has_some_antialiasing(runFont),
|
||||
strikeToSourceScale,
|
||||
fAlloc);
|
||||
|
||||
drawableDrawing.submitOps(fCanvas, fClip, fViewMatrix, fGlyphRunList.origin(), fPaint, fSDC);
|
||||
}
|
||||
|
||||
void GrSubRunNoCachePainter::processSourceSDFT(const SkZip<SkGlyphVariant, SkPoint>& accepted,
|
||||
sk_sp<SkStrike>&& strike,
|
||||
SkScalar strikeToSourceScale,
|
||||
@ -2590,6 +2745,9 @@ public:
|
||||
void processSourcePaths(
|
||||
const SkZip<SkGlyphVariant, SkPoint>& accepted, const SkFont& runFont,
|
||||
SkScalar strikeToSourceScale) override;
|
||||
void processSourceDrawables(
|
||||
const SkZip<SkGlyphVariant, SkPoint>& drawables, const SkFont& runFont,
|
||||
SkScalar strikeToSourceScale) override;
|
||||
void processSourceSDFT(
|
||||
const SkZip<SkGlyphVariant, SkPoint>& accepted, sk_sp<SkStrike>&& strike,
|
||||
SkScalar strikeToSourceScale, const SkFont& runFont,
|
||||
@ -3072,6 +3230,13 @@ void Slug::processSourcePaths(const SkZip<SkGlyphVariant,
|
||||
accepted, has_some_antialiasing(runFont), strikeToSourceScale, &fAlloc));
|
||||
}
|
||||
|
||||
void Slug::processSourceDrawables(const SkZip<SkGlyphVariant, SkPoint>& accepted,
|
||||
const SkFont& runFont,
|
||||
SkScalar strikeToSourceScale) {
|
||||
fSubRuns.append(make_drawable_sub_run<DrawableSubRunSlug>(
|
||||
accepted, has_some_antialiasing(runFont), strikeToSourceScale, &fAlloc));
|
||||
}
|
||||
|
||||
void Slug::processSourceSDFT(const SkZip<SkGlyphVariant, SkPoint>& accepted,
|
||||
sk_sp<SkStrike>&& strike,
|
||||
SkScalar strikeToSourceScale,
|
||||
|
@ -249,6 +249,9 @@ private:
|
||||
void processSourcePaths(const SkZip<SkGlyphVariant, SkPoint>& accepted,
|
||||
const SkFont& runFont,
|
||||
SkScalar strikeToSourceScale) override;
|
||||
void processSourceDrawables(const SkZip<SkGlyphVariant, SkPoint>& accepted,
|
||||
const SkFont& runFont,
|
||||
SkScalar strikeToSourceScale) override;
|
||||
void processSourceSDFT(const SkZip<SkGlyphVariant, SkPoint>& accepted,
|
||||
sk_sp<SkStrike>&& strike,
|
||||
SkScalar strikeToSourceScale,
|
||||
@ -299,6 +302,9 @@ public:
|
||||
void processSourcePaths(const SkZip<SkGlyphVariant, SkPoint>& accepted,
|
||||
const SkFont& runFont,
|
||||
SkScalar strikeToSourceScale) override;
|
||||
void processSourceDrawables(const SkZip<SkGlyphVariant, SkPoint>& accepted,
|
||||
const SkFont& runFont,
|
||||
SkScalar strikeToSourceScale) override;
|
||||
void processSourceSDFT(const SkZip<SkGlyphVariant, SkPoint>& accepted,
|
||||
sk_sp<SkStrike>&& strike,
|
||||
SkScalar strikeToSourceScale,
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "include/core/SkCanvas.h"
|
||||
#include "include/core/SkColor.h"
|
||||
#include "include/core/SkData.h"
|
||||
#include "include/core/SkDrawable.h"
|
||||
#include "include/core/SkEncodedImageFormat.h"
|
||||
#include "include/core/SkFontStyle.h"
|
||||
#include "include/core/SkImage.h"
|
||||
@ -255,6 +256,34 @@ protected:
|
||||
return false;
|
||||
}
|
||||
|
||||
struct SVGGlyphDrawable : public SkDrawable {
|
||||
SkTestSVGScalerContext* fSelf;
|
||||
SkGlyph fGlyph;
|
||||
SVGGlyphDrawable(SkTestSVGScalerContext* self, const SkGlyph& glyph)
|
||||
: fSelf(self), fGlyph(glyph) {}
|
||||
SkRect onGetBounds() override { return fGlyph.rect(); }
|
||||
size_t onApproximateBytesUsed() override { return sizeof(SVGGlyphDrawable); }
|
||||
|
||||
void onDraw(SkCanvas* canvas) override {
|
||||
SkGlyphID glyphID = fGlyph.getGlyphID();
|
||||
glyphID = glyphID < fSelf->getTestSVGTypeface()->fGlyphCount ? glyphID : 0;
|
||||
|
||||
TestSVGTypeface::Glyph& glyphData = fSelf->getTestSVGTypeface()->fGlyphs[glyphID];
|
||||
|
||||
SkScalar dx = SkFixedToScalar(fGlyph.getSubXFixed());
|
||||
SkScalar dy = SkFixedToScalar(fGlyph.getSubYFixed());
|
||||
|
||||
canvas->translate(dx, dy);
|
||||
canvas->concat(fSelf->fMatrix);
|
||||
canvas->translate(glyphData.fOrigin.fX, -glyphData.fOrigin.fY);
|
||||
|
||||
glyphData.render(canvas);
|
||||
}
|
||||
};
|
||||
sk_sp<SkDrawable> generateDrawable(const SkGlyph& glyph) override {
|
||||
return sk_sp<SVGGlyphDrawable>(new SVGGlyphDrawable(this, glyph));
|
||||
}
|
||||
|
||||
void generateFontMetrics(SkFontMetrics* metrics) override {
|
||||
this->getTestSVGTypeface()->getFontMetrics(metrics);
|
||||
SkFontPriv::ScaleFontMetrics(metrics, fMatrix.getScaleY());
|
||||
|
Loading…
Reference in New Issue
Block a user