SkPDF: maybe save some RAM by making the bitsets smaller
Wrap SkBitSet in a thin SkPDFGlyphUse class that manages new mapping.
Change-Id: Id97d42b8961f49c93fd45fdefad69d0aa9e273c5
Reviewed-on: https://skia-review.googlesource.com/c/163882
Auto-Submit: Hal Canary <halcanary@google.com>
Reviewed-by: Ben Wagner <bungeman@google.com>
Commit-Queue: Ben Wagner <bungeman@google.com>
diff --git a/src/pdf/SkPDFFont.cpp b/src/pdf/SkPDFFont.cpp
index a7b3662..d797338 100644
--- a/src/pdf/SkPDFFont.cpp
+++ b/src/pdf/SkPDFFont.cpp
@@ -277,9 +277,7 @@
SkPDFFont::SkPDFFont(SkPDFFont::Info info)
: SkPDFDict("Font")
, fTypeface(std::move(info.fTypeface))
- , fGlyphUsage(info.fLastGlyphID + 1) // TODO(halcanary): Adjust mapping?
- , fFirstGlyphID(info.fFirstGlyphID)
- , fLastGlyphID(info.fLastGlyphID)
+ , fGlyphUsage(info.fFirstGlyphID, info.fLastGlyphID)
, fFontType(info.fFontType) {
SkASSERT(fTypeface);
}
@@ -349,7 +347,7 @@
static sk_sp<SkPDFStream> get_subset_font_stream(
std::unique_ptr<SkStreamAsset> fontAsset,
- const SkBitSet& glyphUsage,
+ const SkPDFGlyphUse& glyphUsage,
const char* fontName,
int ttcIndex) {
// Generate glyph id array in format needed by sfntly.
@@ -425,6 +423,7 @@
#ifdef SK_PDF_USE_SFNTLY
if (!SkToBool(metrics.fFlags &
SkAdvancedTypefaceMetrics::kNotSubsettable_FontFlag)) {
+ SkASSERT(this->firstGlyphID() == 1);
sk_sp<SkPDFStream> subsetStream = get_subset_font_stream(
std::move(fontAsset), this->glyphUsage(),
metrics.fFontName.c_str(), ttcIndex);
@@ -696,7 +695,7 @@
static void add_type3_font_info(SkPDFCanon* canon,
SkPDFDict* font,
SkTypeface* typeface,
- const SkBitSet& subset,
+ const SkPDFGlyphUse& subset,
SkGlyphID firstGlyphID,
SkGlyphID lastGlyphID) {
const SkAdvancedTypefaceMetrics* metrics = SkPDFFont::GetMetrics(typeface, canon);
@@ -860,6 +859,6 @@
void SkPDFFont::drop() {
fTypeface = nullptr;
- fGlyphUsage = SkBitSet(0);
+ fGlyphUsage = SkPDFGlyphUse();
this->SkPDFDict::drop();
}
diff --git a/src/pdf/SkPDFFont.h b/src/pdf/SkPDFFont.h
index 5efcdaf..28957b0 100644
--- a/src/pdf/SkPDFFont.h
+++ b/src/pdf/SkPDFFont.h
@@ -10,8 +10,8 @@
#define SkPDFFont_DEFINED
#include "SkAdvancedTypefaceMetrics.h"
-#include "SkBitSet.h"
#include "SkPDFCanon.h"
+#include "SkPDFGlyphUse.h"
#include "SkPDFTypes.h"
#include "SkStrikeCache.h"
#include "SkTypeface.h"
@@ -55,7 +55,7 @@
/** Return true if this font has an encoding for the passed glyph id.
*/
bool hasGlyph(SkGlyphID gid) {
- return (gid >= fFirstGlyphID && gid <= fLastGlyphID) || gid == 0;
+ return (gid >= this->firstGlyphID() && gid <= this->lastGlyphID()) || gid == 0;
}
/** Convert the input glyph ID into the font encoding. */
@@ -63,9 +63,9 @@
if (this->multiByteGlyphs() || gid == 0) {
return gid;
}
- SkASSERT(gid >= fFirstGlyphID && gid <= fLastGlyphID);
- SkASSERT(fFirstGlyphID > 0);
- return gid - fFirstGlyphID + 1;
+ SkASSERT(gid >= this->firstGlyphID() && gid <= this->lastGlyphID());
+ SkASSERT(this->firstGlyphID() > 0);
+ return gid - this->firstGlyphID() + 1;
}
void noteGlyphUsage(SkGlyphID glyph) {
@@ -117,21 +117,19 @@
};
SkPDFFont(Info);
- SkGlyphID firstGlyphID() const { return fFirstGlyphID; }
- SkGlyphID lastGlyphID() const { return fLastGlyphID; }
- const SkBitSet& glyphUsage() const { return fGlyphUsage; }
+ SkGlyphID firstGlyphID() const { return fGlyphUsage.firstNonZero(); }
+ SkGlyphID lastGlyphID() const { return fGlyphUsage.lastGlyph(); }
+ const SkPDFGlyphUse& glyphUsage() const { return fGlyphUsage; }
sk_sp<SkTypeface> refTypeface() const { return fTypeface; }
void drop() override;
private:
sk_sp<SkTypeface> fTypeface;
- SkBitSet fGlyphUsage;
+ SkPDFGlyphUse fGlyphUsage;
// The glyph IDs accessible with this font. For Type1 (non CID) fonts,
// this will be a subset if the font has more than 255 glyphs.
- const SkGlyphID fFirstGlyphID;
- const SkGlyphID fLastGlyphID;
const SkAdvancedTypefaceMetrics::FontType fFontType;
typedef SkPDFDict INHERITED;
diff --git a/src/pdf/SkPDFGlyphUse.h b/src/pdf/SkPDFGlyphUse.h
new file mode 100644
index 0000000..5ee76e8
--- /dev/null
+++ b/src/pdf/SkPDFGlyphUse.h
@@ -0,0 +1,49 @@
+// Copyright 2018 Google LLC.
+// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
+#ifndef SkPDFGlyphUse_DEFINED
+#define SkPDFGlyphUse_DEFINED
+
+#include "SkBitSet.h"
+#include "SkTypes.h"
+
+class SkPDFGlyphUse {
+public:
+ SkPDFGlyphUse() : fBitSet(0) {}
+ SkPDFGlyphUse(SkGlyphID firstNonZero, SkGlyphID lastGlyph)
+ : fBitSet((int)lastGlyph - firstNonZero + 2)
+ , fFirstNonZero(firstNonZero)
+ , fLastGlyph(lastGlyph) { SkASSERT(firstNonZero >= 1); }
+ ~SkPDFGlyphUse() = default;
+ SkPDFGlyphUse(SkPDFGlyphUse&&) = default;
+ SkPDFGlyphUse& operator=(SkPDFGlyphUse&&) = default;
+
+ SkGlyphID firstNonZero() const { return fFirstNonZero; }
+ SkGlyphID lastGlyph() const { return fLastGlyph; }
+ void set(SkGlyphID gid) { fBitSet.set(this->toCode(gid)); }
+ bool has(SkGlyphID gid) const { return fBitSet.has(this->toCode(gid)); }
+
+ template<typename FN>
+ void getSetValues(FN f) const {
+ if (fFirstNonZero == 1) {
+ return fBitSet.getSetValues(std::move(f));
+ }
+ uint16_t offset = fFirstNonZero - 1;
+ fBitSet.getSetValues([&f, offset](unsigned v) { f(v == 0 ? v : v + offset); });
+ }
+
+private:
+ SkBitSet fBitSet;
+ SkGlyphID fFirstNonZero = 0;
+ SkGlyphID fLastGlyph = 0;
+
+ uint16_t toCode(SkGlyphID gid) const {
+ if (gid == 0 || fFirstNonZero == 1) {
+ return gid;
+ }
+ SkASSERT(gid >= fFirstNonZero && gid <= fLastGlyph);
+ return gid - fFirstNonZero + 1;
+ }
+ SkPDFGlyphUse(const SkPDFGlyphUse&) = delete;
+ SkPDFGlyphUse& operator=(const SkPDFGlyphUse&) = delete;
+};
+#endif // SkPDFGlyphUse_DEFINED
diff --git a/src/pdf/SkPDFMakeCIDGlyphWidthsArray.cpp b/src/pdf/SkPDFMakeCIDGlyphWidthsArray.cpp
index d5785d3..1090e36 100644
--- a/src/pdf/SkPDFMakeCIDGlyphWidthsArray.cpp
+++ b/src/pdf/SkPDFMakeCIDGlyphWidthsArray.cpp
@@ -7,7 +7,7 @@
#include "SkPDFMakeCIDGlyphWidthsArray.h"
-#include "SkBitSet.h"
+#include "SkPDFGlyphUse.h"
#include "SkGlyphCache.h"
#include "SkPaint.h"
#include "SkTo.h"
@@ -144,7 +144,7 @@
// TODO(halcanary): this function is complex enough to need its logic
// tested with unit tests.
sk_sp<SkPDFArray> SkPDFMakeCIDGlyphWidthsArray(SkGlyphCache* cache,
- const SkBitSet* subset,
+ const SkPDFGlyphUse* subset,
uint16_t emSize,
int16_t* defaultAdvance) {
// Assuming that on average, the ASCII representation of an advance plus
diff --git a/src/pdf/SkPDFMakeCIDGlyphWidthsArray.h b/src/pdf/SkPDFMakeCIDGlyphWidthsArray.h
index 4fc0072..bfa4a38 100644
--- a/src/pdf/SkPDFMakeCIDGlyphWidthsArray.h
+++ b/src/pdf/SkPDFMakeCIDGlyphWidthsArray.h
@@ -9,14 +9,14 @@
#include "SkPDFTypes.h"
-class SkBitSet;
class SkGlyphCache;
+class SkPDFGlyphUse;
/* PDF 32000-1:2008, page 270: "The array's elements have a variable
format that can specify individual widths for consecutive CIDs or
one width for a range of CIDs". */
sk_sp<SkPDFArray> SkPDFMakeCIDGlyphWidthsArray(SkGlyphCache* cache,
- const SkBitSet* subset,
+ const SkPDFGlyphUse* subset,
uint16_t emSize,
int16_t* defaultWidth);
diff --git a/src/pdf/SkPDFMakeToUnicodeCmap.cpp b/src/pdf/SkPDFMakeToUnicodeCmap.cpp
index f4789a8..a329547 100644
--- a/src/pdf/SkPDFMakeToUnicodeCmap.cpp
+++ b/src/pdf/SkPDFMakeToUnicodeCmap.cpp
@@ -150,7 +150,7 @@
// one of them), the possible savings by aggressive optimization is 416KB
// pre-compressed and does not provide enough motivation for implementation.
void SkPDFAppendCmapSections(const SkUnichar* glyphToUnicode,
- const SkBitSet* subset,
+ const SkPDFGlyphUse* subset,
SkDynamicMemoryWStream* cmap,
bool multiByteGlyphs,
SkGlyphID firstGlyphID,
@@ -168,8 +168,8 @@
const int limit = (int)lastGlyphID + 1 - glyphOffset;
for (int i = firstGlyphID - glyphOffset; i < limit + 1; ++i) {
- bool inSubset = i < limit &&
- (subset == nullptr || subset->has(i + glyphOffset));
+ SkGlyphID gid = i + glyphOffset;
+ bool inSubset = i < limit && (subset == nullptr || subset->has(gid));
if (!rangeEmpty) {
// PDF spec requires bfrange not changing the higher byte,
// e.g. <1035> <10FF> <2222> is ok, but
@@ -178,7 +178,7 @@
i == currentRangeEntry.fEnd + 1 &&
i >> 8 == currentRangeEntry.fStart >> 8 &&
i < limit &&
- glyphToUnicode[i + glyphOffset] ==
+ glyphToUnicode[gid] ==
currentRangeEntry.fUnicode + i - currentRangeEntry.fStart;
if (!inSubset || !inRange) {
if (currentRangeEntry.fEnd > currentRangeEntry.fStart) {
@@ -193,7 +193,7 @@
currentRangeEntry.fEnd = i;
if (rangeEmpty) {
currentRangeEntry.fStart = i;
- currentRangeEntry.fUnicode = glyphToUnicode[i + glyphOffset];
+ currentRangeEntry.fUnicode = glyphToUnicode[gid];
rangeEmpty = false;
}
}
@@ -207,7 +207,7 @@
sk_sp<SkPDFStream> SkPDFMakeToUnicodeCmap(
const SkUnichar* glyphToUnicode,
- const SkBitSet* subset,
+ const SkPDFGlyphUse* subset,
bool multiByteGlyphs,
SkGlyphID firstGlyphID,
SkGlyphID lastGlyphID) {
diff --git a/src/pdf/SkPDFMakeToUnicodeCmap.h b/src/pdf/SkPDFMakeToUnicodeCmap.h
index c7eaed9..f52862f 100644
--- a/src/pdf/SkPDFMakeToUnicodeCmap.h
+++ b/src/pdf/SkPDFMakeToUnicodeCmap.h
@@ -12,14 +12,14 @@
sk_sp<SkPDFStream> SkPDFMakeToUnicodeCmap(
const SkUnichar* glyphToUnicode,
- const SkBitSet* subset,
+ const SkPDFGlyphUse* subset,
bool multiByteGlyphs,
SkGlyphID firstGlyphID,
SkGlyphID lastGlyphID);
// Exposed for unit testing.
void SkPDFAppendCmapSections(const SkUnichar* glyphToUnicode,
- const SkBitSet* subset,
+ const SkPDFGlyphUse* subset,
SkDynamicMemoryWStream* cmap,
bool multiByteGlyphs,
SkGlyphID firstGlyphID,
diff --git a/tests/PDFGlyphsToUnicodeTest.cpp b/tests/PDFGlyphsToUnicodeTest.cpp
index 2aa52f8..71d75dd 100644
--- a/tests/PDFGlyphsToUnicodeTest.cpp
+++ b/tests/PDFGlyphsToUnicodeTest.cpp
@@ -15,7 +15,7 @@
#include "SkStream.h"
#include "SkTo.h"
-static const int kMaximumGlyphCount = UINT16_MAX + 1;
+static constexpr SkGlyphID kMaximumGlyphIndex = UINT16_MAX;
static bool stream_equals(const SkDynamicMemoryWStream& stream, size_t offset,
const char* buffer, size_t len) {
@@ -37,7 +37,7 @@
DEF_TEST(SkPDF_ToUnicode, reporter) {
SkTDArray<SkUnichar> glyphToUnicode;
SkTDArray<uint16_t> glyphsInSubset;
- SkBitSet subset(kMaximumGlyphCount);
+ SkPDFGlyphUse subset(1, kMaximumGlyphIndex);
glyphToUnicode.push_back(0); // 0
glyphToUnicode.push_back(0); // 1
@@ -155,7 +155,7 @@
glyphToUnicode.reset();
glyphsInSubset.reset();
- SkBitSet subset2(kMaximumGlyphCount);
+ SkPDFGlyphUse subset2(1, kMaximumGlyphIndex);
// Test mapping:
// I n s t a l