• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2018 Google LLC.
2 // Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
3 
4 #include "src/pdf/SkPDFSubsetFont.h"
5 
6 #if defined(SK_USING_THIRD_PARTY_ICU)
7 #include "SkLoadICU.h"
8 #endif
9 
10 #if defined(SK_PDF_USE_HARFBUZZ_SUBSET)
11 
12 #include "include/private/SkTemplates.h"
13 #include "include/private/SkTo.h"
14 #include "src/utils/SkCallableTraits.h"
15 
16 #include "hb.h"
17 #include "hb-subset.h"
18 
19 template <class T, void(*P)(T*)> using resource = std::unique_ptr<T, SkFunctionWrapper<void, T, P>>;
20 using HBBlob = resource<hb_blob_t, hb_blob_destroy>;
21 using HBFace = resource<hb_face_t, hb_face_destroy>;
22 using HBSubsetInput = resource<hb_subset_input_t, hb_subset_input_destroy>;
23 using HBSet = resource<hb_set_t, hb_set_destroy>;
24 
to_blob(sk_sp<SkData> data)25 static HBBlob to_blob(sk_sp<SkData> data) {
26     using blob_size_t = SkCallableTraits<decltype(hb_blob_create)>::argument<1>::type;
27     if (!SkTFitsIn<blob_size_t>(data->size())) {
28         return nullptr;
29     }
30     const char* blobData = static_cast<const char*>(data->data());
31     blob_size_t blobSize = SkTo<blob_size_t>(data->size());
32     return HBBlob(hb_blob_create(blobData, blobSize,
33                                  HB_MEMORY_MODE_READONLY,
34                                  data.release(), [](void* p){ ((SkData*)p)->unref(); }));
35 }
36 
to_data(HBBlob blob)37 static sk_sp<SkData> to_data(HBBlob blob) {
38     if (!blob) {
39         return nullptr;
40     }
41     unsigned int length;
42     const char* data = hb_blob_get_data(blob.get(), &length);
43     if (!data || !length) {
44         return nullptr;
45     }
46     return SkData::MakeWithProc(data, SkToSizeT(length),
47                                 [](const void*, void* ctx) { hb_blob_destroy((hb_blob_t*)ctx); },
48                                 blob.release());
49 }
50 
subset_harfbuzz(sk_sp<SkData> fontData,const SkPDFGlyphUse & glyphUsage,int ttcIndex)51 static sk_sp<SkData> subset_harfbuzz(sk_sp<SkData> fontData,
52                                      const SkPDFGlyphUse& glyphUsage,
53                                      int ttcIndex) {
54 #if defined(SK_USING_THIRD_PARTY_ICU)
55     if (!SkLoadICU()) {
56         return nullptr;
57     }
58 #endif
59     if (!fontData) {
60         return nullptr;
61     }
62     HBFace face(hb_face_create(to_blob(std::move(fontData)).get(), ttcIndex));
63     SkASSERT(face);
64 
65     HBSubsetInput input(hb_subset_input_create_or_fail());
66     SkASSERT(input);
67     if (!face || !input) {
68         return nullptr;
69     }
70     hb_set_t* glyphs = hb_subset_input_glyph_set(input.get());
71     hb_set_add(glyphs, 0);
72     glyphUsage.getSetValues([&glyphs](unsigned gid) { hb_set_add(glyphs, gid);});
73 
74     hb_subset_input_set_retain_gids(input.get(), true);
75     hb_subset_input_set_drop_hints(input.get(), true);
76     HBFace subset(hb_subset(face.get(), input.get()));
77     HBBlob result(hb_face_reference_blob(subset.get()));
78     return to_data(std::move(result));
79 }
80 
81 #endif  // defined(SK_PDF_USE_HARFBUZZ_SUBSET)
82 
83 ////////////////////////////////////////////////////////////////////////////////
84 
85 #if defined(SK_PDF_USE_SFNTLY)
86 
87 #include "sample/chromium/font_subsetter.h"
88 #include <vector>
89 
subset_sfntly(sk_sp<SkData> fontData,const SkPDFGlyphUse & glyphUsage,const char * fontName,int ttcIndex)90 static sk_sp<SkData> subset_sfntly(sk_sp<SkData> fontData,
91                                    const SkPDFGlyphUse& glyphUsage,
92                                    const char* fontName,
93                                    int ttcIndex) {
94 #if defined(SK_USING_THIRD_PARTY_ICU)
95     if (!SkLoadICU()) {
96         return nullptr;
97     }
98 #endif
99     // Generate glyph id array in format needed by sfntly.
100     // TODO(halcanary): sfntly should take a more compact format.
101     std::vector<unsigned> subset;
102     if (!glyphUsage.has(0)) {
103         subset.push_back(0);  // Always include glyph 0.
104     }
105     glyphUsage.getSetValues([&subset](unsigned v) { subset.push_back(v); });
106 
107     unsigned char* subsetFont{nullptr};
108 #if defined(SK_BUILD_FOR_GOOGLE3)
109     // TODO(halcanary): update SK_BUILD_FOR_GOOGLE3 to newest version of Sfntly.
110     (void)ttcIndex;
111     int subsetFontSize = SfntlyWrapper::SubsetFont(fontName,
112                                                    fontData->bytes(),
113                                                    fontData->size(),
114                                                    subset.data(),
115                                                    subset.size(),
116                                                    &subsetFont);
117 #else  // defined(SK_BUILD_FOR_GOOGLE3)
118     (void)fontName;
119     int subsetFontSize = SfntlyWrapper::SubsetFont(ttcIndex,
120                                                    fontData->bytes(),
121                                                    fontData->size(),
122                                                    subset.data(),
123                                                    subset.size(),
124                                                    &subsetFont);
125 #endif  // defined(SK_BUILD_FOR_GOOGLE3)
126     SkASSERT(subsetFontSize > 0 || subsetFont == nullptr);
127     if (subsetFontSize < 1 || subsetFont == nullptr) {
128         return nullptr;
129     }
130     return SkData::MakeWithProc(subsetFont, subsetFontSize,
131                                 [](const void* p, void*) { delete[] (unsigned char*)p; },
132                                 nullptr);
133 }
134 
135 #endif  // defined(SK_PDF_USE_SFNTLY)
136 
137 ////////////////////////////////////////////////////////////////////////////////
138 
139 #if defined(SK_PDF_USE_SFNTLY) && defined(SK_PDF_USE_HARFBUZZ_SUBSET)
140 
SkPDFSubsetFont(sk_sp<SkData> fontData,const SkPDFGlyphUse & glyphUsage,SkPDF::Metadata::Subsetter subsetter,const char * fontName,int ttcIndex)141 sk_sp<SkData> SkPDFSubsetFont(sk_sp<SkData> fontData,
142                               const SkPDFGlyphUse& glyphUsage,
143                               SkPDF::Metadata::Subsetter subsetter,
144                               const char* fontName,
145                               int ttcIndex) {
146     switch (subsetter) {
147         case SkPDF::Metadata::kHarfbuzz_Subsetter:
148             return subset_harfbuzz(std::move(fontData), glyphUsage, ttcIndex);
149         case SkPDF::Metadata::kSfntly_Subsetter:
150             return subset_sfntly(std::move(fontData), glyphUsage, fontName, ttcIndex);
151     }
152     return nullptr;
153 }
154 
155 #elif defined(SK_PDF_USE_SFNTLY)
156 
SkPDFSubsetFont(sk_sp<SkData> fontData,const SkPDFGlyphUse & glyphUsage,SkPDF::Metadata::Subsetter,const char * fontName,int ttcIndex)157 sk_sp<SkData> SkPDFSubsetFont(sk_sp<SkData> fontData,
158                               const SkPDFGlyphUse& glyphUsage,
159                               SkPDF::Metadata::Subsetter,
160                               const char* fontName,
161                               int ttcIndex) {
162     return subset_sfntly(std::move(fontData), glyphUsage, fontName, ttcIndex);
163 }
164 
165 #elif defined(SK_PDF_USE_HARFBUZZ_SUBSET)
166 
SkPDFSubsetFont(sk_sp<SkData> fontData,const SkPDFGlyphUse & glyphUsage,SkPDF::Metadata::Subsetter,const char *,int ttcIndex)167 sk_sp<SkData> SkPDFSubsetFont(sk_sp<SkData> fontData,
168                               const SkPDFGlyphUse& glyphUsage,
169                               SkPDF::Metadata::Subsetter,
170                               const char*,
171                               int ttcIndex) {
172     return subset_harfbuzz(std::move(fontData), glyphUsage, ttcIndex);
173 }
174 
175 #else
176 
SkPDFSubsetFont(sk_sp<SkData>,const SkPDFGlyphUse &,SkPDF::Metadata::Subsetter,const char *,int)177 sk_sp<SkData> SkPDFSubsetFont(sk_sp<SkData>, const SkPDFGlyphUse&, SkPDF::Metadata::Subsetter,
178                               const char*, int) {
179     return nullptr;
180 }
181 #endif  // defined(SK_PDF_USE_SFNTLY)
182 
183