skia2/bench/PDFBench.cpp
halcanary 530032a18e SkPDF: in-place font subsetting
Motivation: gross code simplification, also no bitset lookups at draw time.

SkPDFFont owns its glyph useage bitset.

SkPDFSubstituteMap goes away.

SkPDFObject interface is simplified.

SkPDFDocument tracks font usage (as hash set), not glyph usage.

SkPDFFont gets a simpler constructor.

SkPDFFont has first and last glyph set in constructor, not adjusted later.

SkPDFFont implementations are simplified.

SkPDFGlyphSet is replaced with simple SkBitSet.

SkPDFFont sizes its SkBitSets based on glyph count.

SkPDFGlyphSetMap goes away.

SkBitSet is now non-copyable.

SkBitSet now how utility methods to match old SkPDFGlyphSet.

GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2253283004

CQ_INCLUDE_TRYBOTS=master.client.skia:Test-Win-MSVC-GCE-CPU-AVX2-x86_64-Release-GDI-Trybot,Test-Win-MSVC-GCE-CPU-AVX2-x86_64-Debug-GDI-Trybot

Review-Url: https://codereview.chromium.org/2253283004
2016-08-18 14:22:52 -07:00

254 lines
7.9 KiB
C++

/*
* Copyright 2016 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "Benchmark.h"
#include "Resources.h"
#include "SkAutoPixmapStorage.h"
#include "SkData.h"
#include "SkGradientShader.h"
#include "SkImage.h"
#include "SkPDFBitmap.h"
#include "SkPDFDocument.h"
#include "SkPDFShader.h"
#include "SkPDFUtils.h"
#include "SkPixmap.h"
#include "SkRandom.h"
#include "SkStream.h"
namespace {
struct NullWStream : public SkWStream {
NullWStream() : fN(0) {}
bool write(const void*, size_t n) override { fN += n; return true; }
size_t bytesWritten() const override { return fN; }
size_t fN;
};
static void test_pdf_object_serialization(const sk_sp<SkPDFObject> object) {
// SkDebugWStream wStream;
NullWStream wStream;
SkPDFObjNumMap objNumMap;
objNumMap.addObjectRecursively(object.get());
for (int i = 0; i < objNumMap.objects().count(); ++i) {
SkPDFObject* object = objNumMap.objects()[i].get();
wStream.writeDecAsText(i + 1);
wStream.writeText(" 0 obj\n");
object->emitObject(&wStream, objNumMap);
wStream.writeText("\nendobj\n");
}
}
class PDFImageBench : public Benchmark {
public:
PDFImageBench() {}
virtual ~PDFImageBench() {}
protected:
const char* onGetName() override { return "PDFImage"; }
bool isSuitableFor(Backend backend) override {
return backend == kNonRendering_Backend;
}
void onDelayedSetup() override {
sk_sp<SkImage> img(GetResourceAsImage("color_wheel.png"));
if (img) {
// force decoding, throw away reference to encoded data.
SkAutoPixmapStorage pixmap;
pixmap.alloc(SkImageInfo::MakeN32Premul(img->dimensions()));
if (img->readPixels(pixmap, 0, 0)) {
fImage = SkImage::MakeRasterCopy(pixmap);
}
}
}
void onDraw(int loops, SkCanvas*) override {
if (!fImage) {
return;
}
while (loops-- > 0) {
auto object = SkPDFCreateBitmapObject(fImage, nullptr);
SkASSERT(object);
if (!object) {
return;
}
test_pdf_object_serialization(object);
}
}
private:
sk_sp<SkImage> fImage;
};
class PDFJpegImageBench : public Benchmark {
public:
PDFJpegImageBench() {}
virtual ~PDFJpegImageBench() {}
protected:
const char* onGetName() override { return "PDFJpegImage"; }
bool isSuitableFor(Backend backend) override {
return backend == kNonRendering_Backend;
}
void onDelayedSetup() override {
sk_sp<SkImage> img(GetResourceAsImage("mandrill_512_q075.jpg"));
if (!img) { return; }
sk_sp<SkData> encoded(img->refEncoded());
SkASSERT(encoded);
if (!encoded) { return; }
fImage = img;
}
void onDraw(int loops, SkCanvas*) override {
if (!fImage) {
SkDEBUGFAIL("");
return;
}
while (loops-- > 0) {
auto object = SkPDFCreateBitmapObject(fImage, nullptr);
SkASSERT(object);
if (!object) {
return;
}
test_pdf_object_serialization(object);
}
}
private:
sk_sp<SkImage> fImage;
};
/** Test calling DEFLATE on a 78k PDF command stream. Used for measuring
alternate zlib settings, usage, and library versions. */
class PDFCompressionBench : public Benchmark {
public:
PDFCompressionBench() {}
virtual ~PDFCompressionBench() {}
protected:
const char* onGetName() override { return "PDFCompression"; }
bool isSuitableFor(Backend backend) override {
return backend == kNonRendering_Backend;
}
void onDelayedSetup() override {
fAsset.reset(GetResourceAsStream("pdf_command_stream.txt"));
}
void onDraw(int loops, SkCanvas*) override {
SkASSERT(fAsset);
if (!fAsset) { return; }
while (loops-- > 0) {
sk_sp<SkPDFObject> object =
sk_make_sp<SkPDFSharedStream>(
std::unique_ptr<SkStreamAsset>(fAsset->duplicate()));
test_pdf_object_serialization(object);
}
}
private:
SkAutoTDelete<SkStreamAsset> fAsset;
};
// Test speed of SkPDFUtils::FloatToDecimal for typical floats that
// might be found in a PDF document.
struct PDFScalarBench : public Benchmark {
bool isSuitableFor(Backend b) override {
return b == kNonRendering_Backend;
}
const char* onGetName() override { return "PDFScalar"; }
void onDraw(int loops, SkCanvas*) override {
SkRandom random;
char dst[SkPDFUtils::kMaximumFloatDecimalLength];
while (loops-- > 0) {
auto f = random.nextRangeF(-500.0f, 1500.0f);
(void)SkPDFUtils::FloatToDecimal(f, dst);
}
}
};
struct PDFColorComponentBench : public Benchmark {
bool isSuitableFor(Backend b) override {
return b == kNonRendering_Backend;
}
const char* onGetName() override { return "PDFColorComponent"; }
void onDraw(int loops, SkCanvas*) override {
char dst[5];
while (loops-- > 0) {
for (int i = 0; i < 256; ++i) {
(void)SkPDFUtils::ColorToDecimal(SkToU8(i), dst);
}
}
}
};
struct PDFShaderBench : public Benchmark {
sk_sp<SkShader> fShader;
const char* onGetName() final { return "PDFShader"; }
bool isSuitableFor(Backend b) final { return b == kNonRendering_Backend; }
void onDelayedSetup() final {
const SkPoint pts[2] = {{0.0f, 0.0f}, {100.0f, 100.0f}};
const SkColor colors[] = {
SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE,
SK_ColorWHITE, SK_ColorBLACK,
};
fShader = SkGradientShader::MakeLinear(
pts, colors, nullptr, SK_ARRAY_COUNT(colors),
SkShader::kClamp_TileMode);
}
void onDraw(int loops, SkCanvas*) final {
SkASSERT(fShader);
while (loops-- > 0) {
NullWStream nullStream;
SkPDFDocument doc(&nullStream, nullptr, 72,
SkDocument::PDFMetadata(), nullptr, false);
sk_sp<SkPDFObject> shader(
SkPDFShader::GetPDFShader(
&doc, 72, fShader.get(), SkMatrix::I(),
SkIRect::MakeWH(400,400), 72));
}
}
};
struct WStreamWriteTextBenchmark : public Benchmark {
std::unique_ptr<SkWStream> fWStream;
WStreamWriteTextBenchmark() : fWStream(new NullWStream) {}
const char* onGetName() override { return "WStreamWriteText"; }
bool isSuitableFor(Backend backend) override {
return backend == kNonRendering_Backend;
}
void onDraw(int loops, SkCanvas*) override {
while (loops-- > 0) {
for (int i = 1000; i-- > 0;) {
fWStream->writeText("HELLO SKIA!\n");
}
}
}
};
struct WritePDFTextBenchmark : public Benchmark {
std::unique_ptr<SkWStream> fWStream;
WritePDFTextBenchmark() : fWStream(new NullWStream) {}
const char* onGetName() override { return "WritePDFText"; }
bool isSuitableFor(Backend backend) override {
return backend == kNonRendering_Backend;
}
void onDraw(int loops, SkCanvas*) override {
static const char kHello[] = "HELLO SKIA!\n";
static const char kBinary[] = "\001\002\003\004\005\006";
while (loops-- > 0) {
for (int i = 1000; i-- > 0;) {
SkPDFUtils::WriteString(fWStream.get(), kHello, strlen(kHello));
SkPDFUtils::WriteString(fWStream.get(), kBinary, strlen(kBinary));
}
}
}
};
} // namespace
DEF_BENCH(return new PDFImageBench;)
DEF_BENCH(return new PDFJpegImageBench;)
DEF_BENCH(return new PDFCompressionBench;)
DEF_BENCH(return new PDFScalarBench;)
DEF_BENCH(return new PDFColorComponentBench;)
DEF_BENCH(return new PDFShaderBench;)
DEF_BENCH(return new WStreamWriteTextBenchmark;)
DEF_BENCH(return new WritePDFTextBenchmark;)