summaryrefslogtreecommitdiffstats
path: root/gfx/skia/skia/src/pdf/SkPDFSubsetFont.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/skia/skia/src/pdf/SkPDFSubsetFont.cpp')
-rw-r--r--gfx/skia/skia/src/pdf/SkPDFSubsetFont.cpp208
1 files changed, 208 insertions, 0 deletions
diff --git a/gfx/skia/skia/src/pdf/SkPDFSubsetFont.cpp b/gfx/skia/skia/src/pdf/SkPDFSubsetFont.cpp
new file mode 100644
index 0000000000..0a729bef50
--- /dev/null
+++ b/gfx/skia/skia/src/pdf/SkPDFSubsetFont.cpp
@@ -0,0 +1,208 @@
+// Copyright 2018 Google LLC.
+// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
+
+#include "src/pdf/SkPDFSubsetFont.h"
+
+#if defined(SK_PDF_USE_HARFBUZZ_SUBSET)
+
+#include "include/private/base/SkTemplates.h"
+#include "include/private/base/SkTo.h"
+#include "src/utils/SkCallableTraits.h"
+
+#include "hb.h"
+#include "hb-subset.h"
+
+using HBBlob = std::unique_ptr<hb_blob_t, SkFunctionObject<hb_blob_destroy>>;
+using HBFace = std::unique_ptr<hb_face_t, SkFunctionObject<hb_face_destroy>>;
+using HBSubsetInput = std::unique_ptr<hb_subset_input_t, SkFunctionObject<hb_subset_input_destroy>>;
+using HBSet = std::unique_ptr<hb_set_t, SkFunctionObject<hb_set_destroy>>;
+
+static HBBlob to_blob(sk_sp<SkData> data) {
+ using blob_size_t = SkCallableTraits<decltype(hb_blob_create)>::argument<1>::type;
+ if (!SkTFitsIn<blob_size_t>(data->size())) {
+ return nullptr;
+ }
+ const char* blobData = static_cast<const char*>(data->data());
+ blob_size_t blobSize = SkTo<blob_size_t>(data->size());
+ return HBBlob(hb_blob_create(blobData, blobSize,
+ HB_MEMORY_MODE_READONLY,
+ data.release(), [](void* p){ ((SkData*)p)->unref(); }));
+}
+
+static sk_sp<SkData> to_data(HBBlob blob) {
+ if (!blob) {
+ return nullptr;
+ }
+ unsigned int length;
+ const char* data = hb_blob_get_data(blob.get(), &length);
+ if (!data || !length) {
+ return nullptr;
+ }
+ return SkData::MakeWithProc(data, SkToSizeT(length),
+ [](const void*, void* ctx) { hb_blob_destroy((hb_blob_t*)ctx); },
+ blob.release());
+}
+
+template<typename...> using void_t = void;
+template<typename T, typename = void>
+struct SkPDFHarfBuzzSubset {
+ // This is the HarfBuzz 3.0 interface.
+ // hb_subset_flags_t does not exist in 2.0. It isn't dependent on T, so inline the value of
+ // HB_SUBSET_FLAGS_RETAIN_GIDS until 2.0 is no longer supported.
+ static HBFace Make(T input, hb_face_t* face, bool retainZeroGlyph) {
+ // TODO: When possible, check if a font is 'tricky' with FT_IS_TRICKY.
+ // If it isn't known if a font is 'tricky', retain the hints.
+ unsigned int flags = 0x2u/*HB_SUBSET_FLAGS_RETAIN_GIDS*/;
+ if (retainZeroGlyph) {
+ flags |= 0x40u/*HB_SUBSET_FLAGS_NOTDEF_OUTLINE*/;
+ }
+ hb_subset_input_set_flags(input, flags);
+ return HBFace(hb_subset_or_fail(face, input));
+ }
+};
+template<typename T>
+struct SkPDFHarfBuzzSubset<T, void_t<
+ decltype(hb_subset_input_set_retain_gids(std::declval<T>(), std::declval<bool>())),
+ decltype(hb_subset_input_set_drop_hints(std::declval<T>(), std::declval<bool>())),
+ decltype(hb_subset(std::declval<hb_face_t*>(), std::declval<T>()))
+ >>
+{
+ // This is the HarfBuzz 2.0 (non-public) interface, used if it exists.
+ // This code should be removed as soon as all users are migrated to the newer API.
+ static HBFace Make(T input, hb_face_t* face, bool) {
+ hb_subset_input_set_retain_gids(input, true);
+ // TODO: When possible, check if a font is 'tricky' with FT_IS_TRICKY.
+ // If it isn't known if a font is 'tricky', retain the hints.
+ hb_subset_input_set_drop_hints(input, false);
+ return HBFace(hb_subset(face, input));
+ }
+};
+
+static sk_sp<SkData> subset_harfbuzz(sk_sp<SkData> fontData,
+ const SkPDFGlyphUse& glyphUsage,
+ int ttcIndex) {
+ if (!fontData) {
+ return nullptr;
+ }
+ HBFace face(hb_face_create(to_blob(std::move(fontData)).get(), ttcIndex));
+ SkASSERT(face);
+
+ HBSubsetInput input(hb_subset_input_create_or_fail());
+ SkASSERT(input);
+ if (!face || !input) {
+ return nullptr;
+ }
+ hb_set_t* glyphs = hb_subset_input_glyph_set(input.get());
+ glyphUsage.getSetValues([&glyphs](unsigned gid) { hb_set_add(glyphs, gid);});
+
+ HBFace subset = SkPDFHarfBuzzSubset<hb_subset_input_t*>::Make(input.get(), face.get(),
+ glyphUsage.has(0));
+ if (!subset) {
+ return nullptr;
+ }
+ HBBlob result(hb_face_reference_blob(subset.get()));
+ return to_data(std::move(result));
+}
+
+#endif // defined(SK_PDF_USE_HARFBUZZ_SUBSET)
+
+////////////////////////////////////////////////////////////////////////////////
+
+#if defined(SK_PDF_USE_SFNTLY)
+
+#include "sample/chromium/font_subsetter.h"
+#include <vector>
+
+#if defined(SK_USING_THIRD_PARTY_ICU)
+#include "third_party/icu/SkLoadICU.h"
+#endif
+
+static sk_sp<SkData> subset_sfntly(sk_sp<SkData> fontData,
+ const SkPDFGlyphUse& glyphUsage,
+ const char* fontName,
+ int ttcIndex) {
+#if defined(SK_USING_THIRD_PARTY_ICU)
+ if (!SkLoadICU()) {
+ return nullptr;
+ }
+#endif
+ // Generate glyph id array in format needed by sfntly.
+ // TODO(halcanary): sfntly should take a more compact format.
+ std::vector<unsigned> subset;
+ glyphUsage.getSetValues([&subset](unsigned v) { subset.push_back(v); });
+
+ unsigned char* subsetFont{nullptr};
+#if defined(SK_BUILD_FOR_GOOGLE3)
+ // TODO(halcanary): update SK_BUILD_FOR_GOOGLE3 to newest version of Sfntly.
+ (void)ttcIndex;
+ int subsetFontSize = SfntlyWrapper::SubsetFont(fontName,
+ fontData->bytes(),
+ fontData->size(),
+ subset.data(),
+ subset.size(),
+ &subsetFont);
+#else // defined(SK_BUILD_FOR_GOOGLE3)
+ (void)fontName;
+ int subsetFontSize = SfntlyWrapper::SubsetFont(ttcIndex,
+ fontData->bytes(),
+ fontData->size(),
+ subset.data(),
+ subset.size(),
+ &subsetFont);
+#endif // defined(SK_BUILD_FOR_GOOGLE3)
+ SkASSERT(subsetFontSize > 0 || subsetFont == nullptr);
+ if (subsetFontSize < 1 || subsetFont == nullptr) {
+ return nullptr;
+ }
+ return SkData::MakeWithProc(subsetFont, subsetFontSize,
+ [](const void* p, void*) { delete[] (unsigned char*)p; },
+ nullptr);
+}
+
+#endif // defined(SK_PDF_USE_SFNTLY)
+
+////////////////////////////////////////////////////////////////////////////////
+
+#if defined(SK_PDF_USE_SFNTLY) && defined(SK_PDF_USE_HARFBUZZ_SUBSET)
+
+sk_sp<SkData> SkPDFSubsetFont(sk_sp<SkData> fontData,
+ const SkPDFGlyphUse& glyphUsage,
+ SkPDF::Metadata::Subsetter subsetter,
+ const char* fontName,
+ int ttcIndex) {
+ switch (subsetter) {
+ case SkPDF::Metadata::kHarfbuzz_Subsetter:
+ return subset_harfbuzz(std::move(fontData), glyphUsage, ttcIndex);
+ case SkPDF::Metadata::kSfntly_Subsetter:
+ return subset_sfntly(std::move(fontData), glyphUsage, fontName, ttcIndex);
+ }
+ return nullptr;
+}
+
+#elif defined(SK_PDF_USE_SFNTLY)
+
+sk_sp<SkData> SkPDFSubsetFont(sk_sp<SkData> fontData,
+ const SkPDFGlyphUse& glyphUsage,
+ SkPDF::Metadata::Subsetter,
+ const char* fontName,
+ int ttcIndex) {
+ return subset_sfntly(std::move(fontData), glyphUsage, fontName, ttcIndex);
+}
+
+#elif defined(SK_PDF_USE_HARFBUZZ_SUBSET)
+
+sk_sp<SkData> SkPDFSubsetFont(sk_sp<SkData> fontData,
+ const SkPDFGlyphUse& glyphUsage,
+ SkPDF::Metadata::Subsetter,
+ const char*,
+ int ttcIndex) {
+ return subset_harfbuzz(std::move(fontData), glyphUsage, ttcIndex);
+}
+
+#else
+
+sk_sp<SkData> SkPDFSubsetFont(sk_sp<SkData>, const SkPDFGlyphUse&, SkPDF::Metadata::Subsetter,
+ const char*, int) {
+ return nullptr;
+}
+#endif // defined(SK_PDF_USE_SFNTLY)