1*c8dee2aaSAndroid Build Coastguard Worker // Copyright 2018 Google LLC.
2*c8dee2aaSAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
3*c8dee2aaSAndroid Build Coastguard Worker
4*c8dee2aaSAndroid Build Coastguard Worker #include "src/pdf/SkPDFSubsetFont.h"
5*c8dee2aaSAndroid Build Coastguard Worker
6*c8dee2aaSAndroid Build Coastguard Worker #if defined(SK_PDF_USE_HARFBUZZ_SUBSET)
7*c8dee2aaSAndroid Build Coastguard Worker
8*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkStream.h"
9*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTypeface.h"
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkAssert.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkMalloc.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTemplates.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTo.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "src/pdf/SkPDFGlyphUse.h"
15*c8dee2aaSAndroid Build Coastguard Worker
16*c8dee2aaSAndroid Build Coastguard Worker #include "hb.h" // NO_G3_REWRITE
17*c8dee2aaSAndroid Build Coastguard Worker #include "hb-subset.h" // NO_G3_REWRITE
18*c8dee2aaSAndroid Build Coastguard Worker
19*c8dee2aaSAndroid Build Coastguard Worker #include <cstddef>
20*c8dee2aaSAndroid Build Coastguard Worker #include <memory>
21*c8dee2aaSAndroid Build Coastguard Worker #include <utility>
22*c8dee2aaSAndroid Build Coastguard Worker
23*c8dee2aaSAndroid Build Coastguard Worker namespace {
24*c8dee2aaSAndroid Build Coastguard Worker
25*c8dee2aaSAndroid Build Coastguard Worker using HBBlob = std::unique_ptr<hb_blob_t, SkFunctionObject<hb_blob_destroy>>;
26*c8dee2aaSAndroid Build Coastguard Worker using HBFace = std::unique_ptr<hb_face_t, SkFunctionObject<hb_face_destroy>>;
27*c8dee2aaSAndroid Build Coastguard Worker using HBSubsetInput = std::unique_ptr<hb_subset_input_t, SkFunctionObject<hb_subset_input_destroy>>;
28*c8dee2aaSAndroid Build Coastguard Worker using HBSet = std::unique_ptr<hb_set_t, SkFunctionObject<hb_set_destroy>>;
29*c8dee2aaSAndroid Build Coastguard Worker
stream_to_blob(std::unique_ptr<SkStreamAsset> asset)30*c8dee2aaSAndroid Build Coastguard Worker HBBlob stream_to_blob(std::unique_ptr<SkStreamAsset> asset) {
31*c8dee2aaSAndroid Build Coastguard Worker size_t size = asset->getLength();
32*c8dee2aaSAndroid Build Coastguard Worker HBBlob blob;
33*c8dee2aaSAndroid Build Coastguard Worker if (const void* base = asset->getMemoryBase()) {
34*c8dee2aaSAndroid Build Coastguard Worker blob.reset(hb_blob_create(const_cast<char*>(static_cast<const char*>(base)), SkToUInt(size),
35*c8dee2aaSAndroid Build Coastguard Worker HB_MEMORY_MODE_READONLY, asset.release(),
36*c8dee2aaSAndroid Build Coastguard Worker [](void* p) { delete (SkStreamAsset*)p; }));
37*c8dee2aaSAndroid Build Coastguard Worker } else {
38*c8dee2aaSAndroid Build Coastguard Worker void* ptr = size ? sk_malloc_throw(size) : nullptr;
39*c8dee2aaSAndroid Build Coastguard Worker asset->read(ptr, size);
40*c8dee2aaSAndroid Build Coastguard Worker blob.reset(hb_blob_create((char*)ptr, SkToUInt(size),
41*c8dee2aaSAndroid Build Coastguard Worker HB_MEMORY_MODE_READONLY, ptr, sk_free));
42*c8dee2aaSAndroid Build Coastguard Worker }
43*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(blob);
44*c8dee2aaSAndroid Build Coastguard Worker hb_blob_make_immutable(blob.get());
45*c8dee2aaSAndroid Build Coastguard Worker return blob;
46*c8dee2aaSAndroid Build Coastguard Worker }
47*c8dee2aaSAndroid Build Coastguard Worker
to_data(HBBlob blob)48*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkData> to_data(HBBlob blob) {
49*c8dee2aaSAndroid Build Coastguard Worker if (!blob) {
50*c8dee2aaSAndroid Build Coastguard Worker return nullptr;
51*c8dee2aaSAndroid Build Coastguard Worker }
52*c8dee2aaSAndroid Build Coastguard Worker unsigned int length;
53*c8dee2aaSAndroid Build Coastguard Worker const char* data = hb_blob_get_data(blob.get(), &length);
54*c8dee2aaSAndroid Build Coastguard Worker if (!data || !length) {
55*c8dee2aaSAndroid Build Coastguard Worker return nullptr;
56*c8dee2aaSAndroid Build Coastguard Worker }
57*c8dee2aaSAndroid Build Coastguard Worker return SkData::MakeWithProc(data, SkToSizeT(length),
58*c8dee2aaSAndroid Build Coastguard Worker [](const void*, void* ctx) { hb_blob_destroy((hb_blob_t*)ctx); },
59*c8dee2aaSAndroid Build Coastguard Worker blob.release());
60*c8dee2aaSAndroid Build Coastguard Worker }
61*c8dee2aaSAndroid Build Coastguard Worker
make_subset(hb_subset_input_t * input,hb_face_t * face,bool retainZeroGlyph)62*c8dee2aaSAndroid Build Coastguard Worker HBFace make_subset(hb_subset_input_t* input, hb_face_t* face, bool retainZeroGlyph) {
63*c8dee2aaSAndroid Build Coastguard Worker // TODO: When possible, check if a font is 'tricky' with FT_IS_TRICKY.
64*c8dee2aaSAndroid Build Coastguard Worker // If it isn't known if a font is 'tricky', retain the hints.
65*c8dee2aaSAndroid Build Coastguard Worker unsigned int flags = HB_SUBSET_FLAGS_RETAIN_GIDS;
66*c8dee2aaSAndroid Build Coastguard Worker if (retainZeroGlyph) {
67*c8dee2aaSAndroid Build Coastguard Worker flags |= HB_SUBSET_FLAGS_NOTDEF_OUTLINE;
68*c8dee2aaSAndroid Build Coastguard Worker }
69*c8dee2aaSAndroid Build Coastguard Worker hb_subset_input_set_flags(input, flags);
70*c8dee2aaSAndroid Build Coastguard Worker return HBFace(hb_subset_or_fail(face, input));
71*c8dee2aaSAndroid Build Coastguard Worker }
72*c8dee2aaSAndroid Build Coastguard Worker
subset_harfbuzz(const SkTypeface & typeface,const SkPDFGlyphUse & glyphUsage)73*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkData> subset_harfbuzz(const SkTypeface& typeface, const SkPDFGlyphUse& glyphUsage) {
74*c8dee2aaSAndroid Build Coastguard Worker int index = 0;
75*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<SkStreamAsset> typefaceAsset = typeface.openStream(&index);
76*c8dee2aaSAndroid Build Coastguard Worker HBFace face;
77*c8dee2aaSAndroid Build Coastguard Worker HBBlob blob(stream_to_blob(std::move(typefaceAsset)));
78*c8dee2aaSAndroid Build Coastguard Worker // hb_face_create always succeeds. Check that the format is minimally recognized first.
79*c8dee2aaSAndroid Build Coastguard Worker // See https://github.com/harfbuzz/harfbuzz/issues/248
80*c8dee2aaSAndroid Build Coastguard Worker unsigned int num_hb_faces = hb_face_count(blob.get());
81*c8dee2aaSAndroid Build Coastguard Worker if (0 < num_hb_faces && (unsigned)index < num_hb_faces) {
82*c8dee2aaSAndroid Build Coastguard Worker face.reset(hb_face_create(blob.get(), (unsigned)index));
83*c8dee2aaSAndroid Build Coastguard Worker // Check the number of glyphs as a basic sanitization step.
84*c8dee2aaSAndroid Build Coastguard Worker if (face && hb_face_get_glyph_count(face.get()) == 0) {
85*c8dee2aaSAndroid Build Coastguard Worker face.reset();
86*c8dee2aaSAndroid Build Coastguard Worker }
87*c8dee2aaSAndroid Build Coastguard Worker }
88*c8dee2aaSAndroid Build Coastguard Worker
89*c8dee2aaSAndroid Build Coastguard Worker HBSubsetInput input(hb_subset_input_create_or_fail());
90*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(input);
91*c8dee2aaSAndroid Build Coastguard Worker if (!face || !input) {
92*c8dee2aaSAndroid Build Coastguard Worker return nullptr;
93*c8dee2aaSAndroid Build Coastguard Worker }
94*c8dee2aaSAndroid Build Coastguard Worker hb_set_t* glyphs = hb_subset_input_glyph_set(input.get());
95*c8dee2aaSAndroid Build Coastguard Worker glyphUsage.getSetValues([&glyphs](unsigned gid) { hb_set_add(glyphs, gid);});
96*c8dee2aaSAndroid Build Coastguard Worker
97*c8dee2aaSAndroid Build Coastguard Worker HBFace subset = make_subset(input.get(), face.get(), glyphUsage.has(0));
98*c8dee2aaSAndroid Build Coastguard Worker if (!subset) {
99*c8dee2aaSAndroid Build Coastguard Worker return nullptr;
100*c8dee2aaSAndroid Build Coastguard Worker }
101*c8dee2aaSAndroid Build Coastguard Worker
102*c8dee2aaSAndroid Build Coastguard Worker HBBlob result(hb_face_reference_blob(subset.get()));
103*c8dee2aaSAndroid Build Coastguard Worker return to_data(std::move(result));
104*c8dee2aaSAndroid Build Coastguard Worker }
105*c8dee2aaSAndroid Build Coastguard Worker
106*c8dee2aaSAndroid Build Coastguard Worker } // namespace
107*c8dee2aaSAndroid Build Coastguard Worker
SkPDFSubsetFont(const SkTypeface & typeface,const SkPDFGlyphUse & glyphUsage)108*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkData> SkPDFSubsetFont(const SkTypeface& typeface, const SkPDFGlyphUse& glyphUsage) {
109*c8dee2aaSAndroid Build Coastguard Worker return subset_harfbuzz(typeface, glyphUsage);
110*c8dee2aaSAndroid Build Coastguard Worker }
111*c8dee2aaSAndroid Build Coastguard Worker
112*c8dee2aaSAndroid Build Coastguard Worker #else
113*c8dee2aaSAndroid Build Coastguard Worker
SkPDFSubsetFont(const SkTypeface &,const SkPDFGlyphUse &)114*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkData> SkPDFSubsetFont(const SkTypeface&, const SkPDFGlyphUse&) {
115*c8dee2aaSAndroid Build Coastguard Worker return nullptr;
116*c8dee2aaSAndroid Build Coastguard Worker }
117*c8dee2aaSAndroid Build Coastguard Worker
118*c8dee2aaSAndroid Build Coastguard Worker #endif // defined(SK_PDF_USE_HARFBUZZ_SUBSET)
119