Revert "Revert "custom typeface""
Fix: implement onComputeBounds() and generateFontMetrics()
This reverts commit 0066adefa9
.
Change-Id: Idb59336a3d201bb97e494ee0e0bb189e0a7186f1
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/288536
Commit-Queue: Mike Reed <reed@google.com>
Reviewed-by: Ben Wagner <bungeman@google.com>
This commit is contained in:
parent
8650d33f7a
commit
61642b3366
89
gm/userfont.cpp
Normal file
89
gm/userfont.cpp
Normal file
@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright 2020 Google LLC
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "gm/gm.h"
|
||||
#include "include/core/SkCanvas.h"
|
||||
#include "include/core/SkFont.h"
|
||||
#include "include/core/SkPaint.h"
|
||||
#include "include/core/SkPath.h"
|
||||
#include "include/core/SkSize.h"
|
||||
#include "include/core/SkString.h"
|
||||
#include "include/utils/SkCustomTypeface.h"
|
||||
#include "tools/Resources.h"
|
||||
|
||||
static sk_sp<SkTypeface> make_tf() {
|
||||
SkCustomTypefaceBuilder builder(128);
|
||||
SkFont font;
|
||||
font.setSize(1.0f);
|
||||
font.setHinting(SkFontHinting::kNone);
|
||||
|
||||
// Steal the first 128 chars from the default font
|
||||
for (SkGlyphID index = 0; index <= 127; ++index) {
|
||||
SkGlyphID glyph = font.unicharToGlyph(index);
|
||||
|
||||
SkScalar width;
|
||||
font.getWidths(&glyph, 1, &width);
|
||||
SkPath path;
|
||||
font.getPath(glyph, &path);
|
||||
|
||||
// we use the charcode to be our glyph index, since we have no cmap table
|
||||
builder.setGlyph(index, width, path);
|
||||
}
|
||||
|
||||
return builder.detach();
|
||||
}
|
||||
|
||||
#include "include/core/SkTextBlob.h"
|
||||
|
||||
class UserFontGM : public skiagm::GM {
|
||||
sk_sp<SkTypeface> fTF;
|
||||
sk_sp<SkTextBlob> fBlob;
|
||||
|
||||
SkPath fPath;
|
||||
public:
|
||||
UserFontGM() {}
|
||||
|
||||
void onOnceBeforeDraw() override {
|
||||
fTF = make_tf();
|
||||
|
||||
SkFont font(fTF);
|
||||
font.setSize(100);
|
||||
font.setEdging(SkFont::Edging::kAntiAlias);
|
||||
|
||||
std::vector<SkGlyphID> array;
|
||||
auto expand8to16 = [&](const char str[]) {
|
||||
for (int i = 0; str[i]; ++i) {
|
||||
array.push_back(str[i]);
|
||||
}
|
||||
};
|
||||
|
||||
expand8to16("User Typeface");
|
||||
fBlob = SkTextBlob::MakeFromText(array.data(), array.size() * sizeof(SkGlyphID),
|
||||
font, SkTextEncoding::kGlyphID);
|
||||
|
||||
}
|
||||
|
||||
bool runAsBench() const override { return true; }
|
||||
|
||||
SkString onShortName() override { return SkString("user_typeface"); }
|
||||
|
||||
SkISize onISize() override { return {512, 512}; }
|
||||
|
||||
void onDraw(SkCanvas* canvas) override {
|
||||
SkScalar x = 20,
|
||||
y = 250;
|
||||
|
||||
SkPaint paint;
|
||||
paint.setStyle(SkPaint::kStroke_Style);
|
||||
canvas->drawRect(fBlob->bounds().makeOffset(x, y), paint);
|
||||
|
||||
paint.setStyle(SkPaint::kFill_Style);
|
||||
paint.setColor(SK_ColorRED);
|
||||
canvas->drawTextBlob(fBlob, x, y, paint);
|
||||
}
|
||||
};
|
||||
DEF_GM(return new UserFontGM;)
|
@ -378,6 +378,7 @@ gm_sources = [
|
||||
"$_gm/trickycubicstrokes.cpp",
|
||||
"$_gm/typeface.cpp",
|
||||
"$_gm/unpremul.cpp",
|
||||
"$_gm/userfont.cpp",
|
||||
"$_gm/variedtext.cpp",
|
||||
"$_gm/verifiers/gmverifier.cpp",
|
||||
"$_gm/vertices.cpp",
|
||||
|
@ -12,6 +12,7 @@ skia_utils_public = [
|
||||
"$_include/utils/SkBase64.h",
|
||||
"$_include/utils/SkCamera.h",
|
||||
"$_include/utils/SkCanvasStateUtils.h",
|
||||
"$_include/utils/SkCustomTypeface.h",
|
||||
"$_include/utils/SkEventTracer.h",
|
||||
"$_include/utils/SkInterpolator.h",
|
||||
"$_include/utils/SkNWayCanvas.h",
|
||||
@ -40,6 +41,7 @@ skia_utils_sources = [
|
||||
"$_src/utils/SkCharToGlyphCache.h",
|
||||
"$_src/utils/SkClipStackUtils.cpp",
|
||||
"$_src/utils/SkClipStackUtils.h",
|
||||
"$_src/utils/SkCustomTypeface.cpp",
|
||||
"$_src/utils/SkDashPath.cpp",
|
||||
"$_src/utils/SkDashPathPriv.h",
|
||||
"$_src/utils/SkEventTracer.cpp",
|
||||
|
42
include/utils/SkCustomTypeface.h
Normal file
42
include/utils/SkCustomTypeface.h
Normal file
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2020 Google LLC
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef SkCustomTypeface_DEFINED
|
||||
#define SkCustomTypeface_DEFINED
|
||||
|
||||
#include "include/core/SkImage.h"
|
||||
#include "include/core/SkPaint.h"
|
||||
#include "include/core/SkPath.h"
|
||||
#include "include/core/SkPicture.h"
|
||||
#include "include/core/SkTypeface.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
class SkStream;
|
||||
|
||||
class SkCustomTypefaceBuilder {
|
||||
public:
|
||||
SkCustomTypefaceBuilder(int numGlyphs);
|
||||
|
||||
void setGlyph(SkGlyphID, float advance, const SkPath&);
|
||||
void setGlyph(SkGlyphID, float advance, const SkPath&, const SkPaint&);
|
||||
void setGlyph(SkGlyphID, float advance, sk_sp<SkImage>, float scale);
|
||||
void setGlyph(SkGlyphID, float advance, sk_sp<SkPicture>);
|
||||
|
||||
sk_sp<SkTypeface> detach();
|
||||
|
||||
private:
|
||||
int fGlyphCount;
|
||||
std::vector<SkPath> fPaths;
|
||||
std::vector<float> fAdvances;
|
||||
|
||||
static sk_sp<SkTypeface> Deserialize(SkStream*);
|
||||
|
||||
friend class SkTypeface;
|
||||
};
|
||||
|
||||
#endif
|
@ -296,6 +296,7 @@ private:
|
||||
friend class SkStrikeServer;
|
||||
friend class SkTestScalerContext;
|
||||
friend class SkTestSVGScalerContext;
|
||||
friend class SkUserScalerContext;
|
||||
friend class TestSVGTypeface;
|
||||
friend class TestTypeface;
|
||||
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "include/core/SkTypeface.h"
|
||||
#include "include/private/SkMutex.h"
|
||||
#include "include/private/SkOnce.h"
|
||||
#include "include/utils/SkCustomTypeface.h"
|
||||
#include "src/core/SkAdvancedTypefaceMetrics.h"
|
||||
#include "src/core/SkEndian.h"
|
||||
#include "src/core/SkFontDescriptor.h"
|
||||
@ -161,6 +162,12 @@ sk_sp<SkTypeface> SkTypeface::MakeFromData(sk_sp<SkData> data, int index) {
|
||||
}
|
||||
|
||||
sk_sp<SkTypeface> SkTypeface::MakeFromFontData(std::unique_ptr<SkFontData> data) {
|
||||
if (data->hasStream()) {
|
||||
if (auto tf = SkCustomTypefaceBuilder::Deserialize(data->getStream())) {
|
||||
return tf;
|
||||
}
|
||||
}
|
||||
|
||||
return SkFontMgr::RefDefault()->makeFromFontData(std::move(data));
|
||||
}
|
||||
|
||||
|
376
src/utils/SkCustomTypeface.cpp
Normal file
376
src/utils/SkCustomTypeface.cpp
Normal file
@ -0,0 +1,376 @@
|
||||
/*
|
||||
* Copyright 2020 Google LLC
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "include/core/SkCanvas.h"
|
||||
#include "include/core/SkData.h"
|
||||
#include "include/core/SkFontMetrics.h"
|
||||
#include "include/utils/SkCustomTypeface.h"
|
||||
#include "src/core/SkAdvancedTypefaceMetrics.h"
|
||||
|
||||
class SkUserTypeface : public SkTypeface {
|
||||
friend class SkCustomTypefaceBuilder;
|
||||
friend class SkUserScalerContext;
|
||||
|
||||
SkUserTypeface(int count)
|
||||
: SkTypeface(SkFontStyle())
|
||||
, fGlyphCount(count)
|
||||
{}
|
||||
|
||||
const int fGlyphCount;
|
||||
std::vector<SkPath> fPaths;
|
||||
std::vector<float> fAdvances;
|
||||
SkRect fBounds;
|
||||
|
||||
protected:
|
||||
SkScalerContext* onCreateScalerContext(const SkScalerContextEffects&,
|
||||
const SkDescriptor* desc) const override;
|
||||
void onFilterRec(SkScalerContextRec* rec) const override;
|
||||
void getGlyphToUnicodeMap(SkUnichar* glyphToUnicode) const override;
|
||||
std::unique_ptr<SkAdvancedTypefaceMetrics> onGetAdvancedMetrics() const override;
|
||||
|
||||
void onGetFontDescriptor(SkFontDescriptor* desc, bool* isLocal) const override;
|
||||
|
||||
void onCharsToGlyphs(const SkUnichar* chars, int count, SkGlyphID glyphs[]) const override;
|
||||
|
||||
void onGetFamilyName(SkString* familyName) const override;
|
||||
SkTypeface::LocalizedStrings* onCreateFamilyNameIterator() const override;
|
||||
|
||||
std::unique_ptr<SkStreamAsset> onOpenStream(int*) const override;
|
||||
|
||||
// trivial
|
||||
|
||||
sk_sp<SkTypeface> onMakeClone(const SkFontArguments& args) const override {
|
||||
return sk_ref_sp(this);
|
||||
}
|
||||
int onCountGlyphs() const override { return fGlyphCount; }
|
||||
int onGetUPEM() const override { return 2048; /* ?? */ }
|
||||
bool onComputeBounds(SkRect* bounds) const override { *bounds = fBounds; return true; }
|
||||
|
||||
// noops
|
||||
|
||||
void getPostScriptGlyphNames(SkString*) const override {}
|
||||
int onGetVariationDesignPosition(SkFontArguments::VariationPosition::Coordinate[],
|
||||
int) const override { return 0; }
|
||||
int onGetVariationDesignParameters(SkFontParameters::Variation::Axis[],
|
||||
int) const override { return 0; }
|
||||
int onGetTableTags(SkFontTableTag tags[]) const override { return 0; }
|
||||
size_t onGetTableData(SkFontTableTag, size_t, size_t, void*) const override { return 0; }
|
||||
};
|
||||
|
||||
SkCustomTypefaceBuilder::SkCustomTypefaceBuilder(int numGlyphs) : fGlyphCount(numGlyphs) {
|
||||
fAdvances.resize(numGlyphs);
|
||||
fPaths.resize(numGlyphs);
|
||||
}
|
||||
|
||||
void SkCustomTypefaceBuilder::setGlyph(SkGlyphID index, float advance, const SkPath& path) {
|
||||
if (index >= (unsigned)fGlyphCount) {
|
||||
return;
|
||||
}
|
||||
fAdvances[index] = advance;
|
||||
fPaths[index] = path;
|
||||
}
|
||||
|
||||
sk_sp<SkTypeface> SkCustomTypefaceBuilder::detach() {
|
||||
if (fGlyphCount <= 0) return nullptr;
|
||||
|
||||
SkUserTypeface* tf = new SkUserTypeface(fGlyphCount);
|
||||
tf->fAdvances = std::move(fAdvances);
|
||||
tf->fPaths = std::move(fPaths);
|
||||
|
||||
// initially inverted, so that any "union" will overwrite the first time
|
||||
SkRect bounds = {SK_ScalarMax, SK_ScalarMax, -SK_ScalarMax, -SK_ScalarMax};
|
||||
|
||||
for (const auto& path : tf->fPaths) {
|
||||
if (!path.isEmpty()) {
|
||||
bounds.join(path.getBounds());
|
||||
}
|
||||
}
|
||||
tf->fBounds = bounds;
|
||||
|
||||
return sk_sp<SkTypeface>(tf);
|
||||
}
|
||||
|
||||
/////////////
|
||||
|
||||
#include "src/core/SkScalerContext.h"
|
||||
|
||||
void SkUserTypeface::onFilterRec(SkScalerContextRec* rec) const {
|
||||
rec->setHinting(SkFontHinting::kNone);
|
||||
}
|
||||
|
||||
void SkUserTypeface::getGlyphToUnicodeMap(SkUnichar* glyphToUnicode) const {
|
||||
for (int gid = 0; gid < fGlyphCount; ++gid) {
|
||||
glyphToUnicode[gid] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<SkAdvancedTypefaceMetrics> SkUserTypeface::onGetAdvancedMetrics() const {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void SkUserTypeface::onGetFontDescriptor(SkFontDescriptor* desc, bool* isLocal) const {
|
||||
*isLocal = true;
|
||||
}
|
||||
|
||||
void SkUserTypeface::onCharsToGlyphs(const SkUnichar uni[], int count, SkGlyphID glyphs[]) const {
|
||||
for (int i = 0; i < count; ++i) {
|
||||
glyphs[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void SkUserTypeface::onGetFamilyName(SkString* familyName) const {
|
||||
*familyName = "";
|
||||
}
|
||||
|
||||
SkTypeface::LocalizedStrings* SkUserTypeface::onCreateFamilyNameIterator() const {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//////////////
|
||||
|
||||
#include "src/core/SkScalerContext.h"
|
||||
|
||||
class SkUserScalerContext : public SkScalerContext {
|
||||
public:
|
||||
SkUserScalerContext(sk_sp<SkUserTypeface> face,
|
||||
const SkScalerContextEffects& effects,
|
||||
const SkDescriptor* desc)
|
||||
: SkScalerContext(std::move(face), effects, desc) {
|
||||
fRec.getSingleMatrix(&fMatrix);
|
||||
this->forceGenerateImageFromPath();
|
||||
}
|
||||
|
||||
const SkUserTypeface* userTF() const {
|
||||
return static_cast<SkUserTypeface*>(this->getTypeface());
|
||||
}
|
||||
|
||||
protected:
|
||||
unsigned generateGlyphCount() override {
|
||||
return this->userTF()->fGlyphCount;
|
||||
}
|
||||
|
||||
bool generateAdvance(SkGlyph* glyph) override {
|
||||
const SkUserTypeface* tf = this->userTF();
|
||||
auto advance = fMatrix.mapXY(tf->fAdvances[glyph->getGlyphID()], 0);
|
||||
|
||||
glyph->fAdvanceX = advance.fX;
|
||||
glyph->fAdvanceY = advance.fY;
|
||||
return true;
|
||||
}
|
||||
|
||||
void generateMetrics(SkGlyph* glyph) override {
|
||||
glyph->zeroMetrics();
|
||||
this->generateAdvance(glyph);
|
||||
// Always generates from paths, so SkScalerContext::getMetrics will figure the bounds.
|
||||
}
|
||||
|
||||
void generateImage(const SkGlyph&) override { SK_ABORT("Should have generated from path."); }
|
||||
|
||||
bool generatePath(SkGlyphID glyph, SkPath* path) override {
|
||||
this->userTF()->fPaths[glyph].transform(fMatrix, path);
|
||||
return true;
|
||||
}
|
||||
|
||||
void generateFontMetrics(SkFontMetrics* metrics) override {
|
||||
const auto [_, sy] = fMatrix.mapXY(0, 1);
|
||||
|
||||
sk_bzero(metrics, sizeof(*metrics));
|
||||
metrics->fTop = this->userTF()->fBounds.fTop * sy;
|
||||
metrics->fBottom = this->userTF()->fBounds.fBottom * sy;
|
||||
|
||||
// todo: get these from the creator of the typeface?
|
||||
metrics->fAscent = metrics->fTop;
|
||||
metrics->fDescent = metrics->fBottom;
|
||||
}
|
||||
|
||||
private:
|
||||
SkMatrix fMatrix;
|
||||
};
|
||||
|
||||
SkScalerContext* SkUserTypeface::onCreateScalerContext(const SkScalerContextEffects& effects,
|
||||
const SkDescriptor* desc) const {
|
||||
return new SkUserScalerContext(sk_ref_sp(const_cast<SkUserTypeface*>(this)), effects, desc);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "include/private/SkFloatingPoint.h"
|
||||
#include "src/core/SkAutoMalloc.h"
|
||||
#include "src/core/SkPathPriv.h"
|
||||
|
||||
static void write_scaled_float_to_16(SkWStream* stream, float x, float scale) {
|
||||
stream->write16(SkToS16(sk_float_round2int(x * scale)) & 0xFFFF);
|
||||
}
|
||||
|
||||
enum PVerb {
|
||||
kMove,
|
||||
kLine,
|
||||
kCurve,
|
||||
kClose,
|
||||
};
|
||||
|
||||
static void compress_write(SkWStream* stream, const SkPath& path, int upem) {
|
||||
int pCount = 0;
|
||||
std::vector<PVerb> verbs;
|
||||
for (auto [v, p, w] : SkPathPriv::Iterate(path)) {
|
||||
switch (v) {
|
||||
default: SkASSERT(!"oops"); break;
|
||||
case SkPathVerb::kMove: verbs.push_back(kMove); pCount += 1; break;
|
||||
case SkPathVerb::kQuad: verbs.push_back(kCurve); pCount += 2; break;
|
||||
case SkPathVerb::kLine: verbs.push_back(kLine); pCount += 1; break;
|
||||
case SkPathVerb::kClose: verbs.push_back(kClose); break;
|
||||
}
|
||||
}
|
||||
|
||||
int vCount = verbs.size();
|
||||
|
||||
stream->write16(upem); // share w/ other paths?
|
||||
stream->write16(vCount);
|
||||
stream->write16(pCount);
|
||||
for (int i = 0; i < (vCount & ~3); i += 4) {
|
||||
stream->write8((verbs[i+0]<<6) | (verbs[i+1]<<4) | (verbs[i+2]<<2) | verbs[i+3]);
|
||||
}
|
||||
if (vCount & 3) {
|
||||
uint8_t b = 0;
|
||||
int shift = 6;
|
||||
for (int i = vCount & ~3; i < vCount; ++i) {
|
||||
b |= verbs[i] << shift;
|
||||
shift >>= 2;
|
||||
}
|
||||
stream->write8(b);
|
||||
}
|
||||
if (vCount & 1) {
|
||||
stream->write8(0);
|
||||
}
|
||||
|
||||
const float scale = (float)upem;
|
||||
auto write_pts = [&](const SkPoint pts[], int count) {
|
||||
for (int i = 0; i < count; ++i) {
|
||||
write_scaled_float_to_16(stream, pts[i].fX, scale);
|
||||
write_scaled_float_to_16(stream, pts[i].fY, scale);
|
||||
}
|
||||
};
|
||||
|
||||
for (auto [v, p, w] : SkPathPriv::Iterate(path)) {
|
||||
switch (v) {
|
||||
default: SkASSERT(!"oops"); break;
|
||||
case SkPathVerb::kMove: write_pts(&p[0], 1); break;
|
||||
case SkPathVerb::kQuad: write_pts(&p[1], 2); break;
|
||||
case SkPathVerb::kLine: write_pts(&p[1], 1); break;
|
||||
case SkPathVerb::kClose: break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static constexpr int kMaxGlyphCount = 65536;
|
||||
static constexpr size_t kHeaderSize = 16;
|
||||
static const char gHeaderString[] = "SkUserTypeface00";
|
||||
static_assert(sizeof(gHeaderString) == 1 + kHeaderSize, "need header to be 16 bytes");
|
||||
|
||||
std::unique_ptr<SkStreamAsset> SkUserTypeface::onOpenStream(int* ttcIndex) const {
|
||||
SkDynamicMemoryWStream wstream;
|
||||
|
||||
wstream.write(gHeaderString, kHeaderSize);
|
||||
|
||||
SkASSERT(fAdvances.size() == (unsigned)fGlyphCount);
|
||||
SkASSERT(fPaths.size() == (unsigned)fGlyphCount);
|
||||
|
||||
// just hacking around -- this makes the serialized font 1/2 size
|
||||
const bool use_compression = false;
|
||||
|
||||
wstream.write32(fGlyphCount);
|
||||
|
||||
if (use_compression) {
|
||||
for (float a : fAdvances) {
|
||||
write_scaled_float_to_16(&wstream, a, 2048);
|
||||
}
|
||||
} else {
|
||||
wstream.write(fAdvances.data(), fGlyphCount * sizeof(float));
|
||||
}
|
||||
|
||||
for (const auto& p : fPaths) {
|
||||
if (use_compression) {
|
||||
compress_write(&wstream, p, 2048);
|
||||
} else {
|
||||
auto data = p.serialize();
|
||||
SkASSERT(SkIsAlign4(data->size()));
|
||||
wstream.write(data->data(), data->size());
|
||||
}
|
||||
}
|
||||
// SkDebugf("%d glyphs, %d bytes\n", fGlyphCount, wstream.bytesWritten());
|
||||
*ttcIndex = 0;
|
||||
return wstream.detachAsStream();
|
||||
}
|
||||
|
||||
class AutoRestorePosition {
|
||||
SkStream* fStream;
|
||||
size_t fPosition;
|
||||
public:
|
||||
AutoRestorePosition(SkStream* stream) : fStream(stream) {
|
||||
fPosition = stream->getPosition();
|
||||
}
|
||||
|
||||
~AutoRestorePosition() {
|
||||
if (fStream) {
|
||||
fStream->seek(fPosition);
|
||||
}
|
||||
}
|
||||
|
||||
// So we don't restore the position
|
||||
void markDone() { fStream = nullptr; }
|
||||
};
|
||||
|
||||
sk_sp<SkTypeface> SkCustomTypefaceBuilder::Deserialize(SkStream* stream) {
|
||||
AutoRestorePosition arp(stream);
|
||||
|
||||
char header[kHeaderSize];
|
||||
if (stream->read(header, kHeaderSize) != kHeaderSize ||
|
||||
memcmp(header, gHeaderString, kHeaderSize) != 0)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int glyphCount;
|
||||
if (!stream->readS32(&glyphCount) || glyphCount < 0 || glyphCount > kMaxGlyphCount) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SkCustomTypefaceBuilder builder(glyphCount);
|
||||
|
||||
std::vector<float> advances(glyphCount);
|
||||
if (stream->read(advances.data(), glyphCount * sizeof(float)) != glyphCount * sizeof(float)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// SkPath can read from a stream, so we have to page the rest into ram
|
||||
const size_t offset = stream->getPosition();
|
||||
const size_t length = stream->getLength() - offset;
|
||||
SkAutoMalloc ram(length);
|
||||
char* buffer = (char*)ram.get();
|
||||
|
||||
if (stream->read(buffer, length) != length) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
size_t totalUsed = 0;
|
||||
for (int i = 0; i < glyphCount; ++i) {
|
||||
SkPath path;
|
||||
size_t used = path.readFromMemory(buffer + totalUsed, length - totalUsed);
|
||||
if (used == 0) {
|
||||
return nullptr;
|
||||
}
|
||||
builder.setGlyph(i, advances[i], path);
|
||||
totalUsed += used;
|
||||
SkASSERT(length >= totalUsed);
|
||||
}
|
||||
|
||||
// all done, update the stream to only reflect the bytes we needed
|
||||
stream->seek(offset + totalUsed);
|
||||
|
||||
arp.markDone();
|
||||
return builder.detach();
|
||||
}
|
Loading…
Reference in New Issue
Block a user