Line data Source code
1 : /*
2 : * Copyright 2011 Google Inc.
3 : *
4 : * Use of this source code is governed by a BSD-style license that can be
5 : * found in the LICENSE file.
6 : */
7 :
8 : #include "SkData.h"
9 : #include "SkGlyphCache.h"
10 : #include "SkPaint.h"
11 : #include "SkPDFCanon.h"
12 : #include "SkPDFConvertType1FontStream.h"
13 : #include "SkPDFDevice.h"
14 : #include "SkPDFMakeCIDGlyphWidthsArray.h"
15 : #include "SkPDFMakeToUnicodeCmap.h"
16 : #include "SkPDFFont.h"
17 : #include "SkPDFUtils.h"
18 : #include "SkRefCnt.h"
19 : #include "SkScalar.h"
20 : #include "SkStream.h"
21 : #include "SkTypes.h"
22 : #include "SkUtils.h"
23 :
24 : #ifdef SK_PDF_USE_SFNTLY
25 : #include "sample/chromium/font_subsetter.h"
26 : #endif
27 :
28 0 : SkAutoGlyphCache SkPDFFont::MakeVectorCache(SkTypeface* face, int* size) {
29 0 : SkPaint tmpPaint;
30 0 : tmpPaint.setHinting(SkPaint::kNo_Hinting);
31 0 : tmpPaint.setTypeface(sk_ref_sp(face));
32 0 : int unitsPerEm = face->getUnitsPerEm();
33 0 : if (unitsPerEm <= 0) {
34 0 : unitsPerEm = 1024;
35 : }
36 0 : if (size) {
37 0 : *size = unitsPerEm;
38 : }
39 0 : tmpPaint.setTextSize((SkScalar)unitsPerEm);
40 0 : const SkSurfaceProps props(0, kUnknown_SkPixelGeometry);
41 0 : SkAutoGlyphCache glyphCache(tmpPaint, &props, nullptr);
42 0 : SkASSERT(glyphCache.get());
43 0 : return glyphCache;
44 : }
45 :
46 : namespace {
47 : // PDF's notion of symbolic vs non-symbolic is related to the character set, not
48 : // symbols vs. characters. Rarely is a font the right character set to call it
49 : // non-symbolic, so always call it symbolic. (PDF 1.4 spec, section 5.7.1)
50 : static const int32_t kPdfSymbolic = 4;
51 :
52 : struct SkPDFType0Font final : public SkPDFFont {
53 : SkPDFType0Font(SkPDFFont::Info, const SkAdvancedTypefaceMetrics&);
54 : ~SkPDFType0Font() override;
55 : void getFontSubset(SkPDFCanon*) override;
56 : #ifdef SK_DEBUG
57 : void emitObject(SkWStream*, const SkPDFObjNumMap&) const override;
58 : bool fPopulated;
59 : #endif
60 : typedef SkPDFDict INHERITED;
61 : };
62 :
63 : struct SkPDFType1Font final : public SkPDFFont {
64 : SkPDFType1Font(SkPDFFont::Info, const SkAdvancedTypefaceMetrics&, SkPDFCanon*);
65 0 : ~SkPDFType1Font() override {}
66 0 : void getFontSubset(SkPDFCanon*) override {} // TODO(halcanary): implement
67 : };
68 :
69 : struct SkPDFType3Font final : public SkPDFFont {
70 : SkPDFType3Font(SkPDFFont::Info, const SkAdvancedTypefaceMetrics&);
71 0 : ~SkPDFType3Font() override {}
72 : void getFontSubset(SkPDFCanon*) override;
73 : };
74 :
75 : ///////////////////////////////////////////////////////////////////////////////
76 : // File-Local Functions
77 : ///////////////////////////////////////////////////////////////////////////////
78 :
79 : // scale from em-units to base-1000, returning as a SkScalar
80 0 : SkScalar from_font_units(SkScalar scaled, uint16_t emSize) {
81 0 : if (emSize == 1000) {
82 0 : return scaled;
83 : } else {
84 0 : return scaled * 1000 / emSize;
85 : }
86 : }
87 :
88 0 : SkScalar scaleFromFontUnits(int16_t val, uint16_t emSize) {
89 0 : return from_font_units(SkIntToScalar(val), emSize);
90 : }
91 :
92 :
93 0 : void setGlyphWidthAndBoundingBox(SkScalar width, SkIRect box,
94 : SkDynamicMemoryWStream* content) {
95 : // Specify width and bounding box for the glyph.
96 0 : SkPDFUtils::AppendScalar(width, content);
97 0 : content->writeText(" 0 ");
98 0 : content->writeDecAsText(box.fLeft);
99 0 : content->writeText(" ");
100 0 : content->writeDecAsText(box.fTop);
101 0 : content->writeText(" ");
102 0 : content->writeDecAsText(box.fRight);
103 0 : content->writeText(" ");
104 0 : content->writeDecAsText(box.fBottom);
105 0 : content->writeText(" d1\n");
106 0 : }
107 :
108 0 : static sk_sp<SkPDFArray> makeFontBBox(SkIRect glyphBBox, uint16_t emSize) {
109 0 : auto bbox = sk_make_sp<SkPDFArray>();
110 0 : bbox->reserve(4);
111 0 : bbox->appendScalar(scaleFromFontUnits(glyphBBox.fLeft, emSize));
112 0 : bbox->appendScalar(scaleFromFontUnits(glyphBBox.fBottom, emSize));
113 0 : bbox->appendScalar(scaleFromFontUnits(glyphBBox.fRight, emSize));
114 0 : bbox->appendScalar(scaleFromFontUnits(glyphBBox.fTop, emSize));
115 0 : return bbox;
116 : }
117 : } // namespace
118 :
119 : ///////////////////////////////////////////////////////////////////////////////
120 : // class SkPDFFont
121 : ///////////////////////////////////////////////////////////////////////////////
122 :
123 : /* Font subset design: It would be nice to be able to subset fonts
124 : * (particularly type 3 fonts), but it's a lot of work and not a priority.
125 : *
126 : * Resources are canonicalized and uniqueified by pointer so there has to be
127 : * some additional state indicating which subset of the font is used. It
128 : * must be maintained at the page granularity and then combined at the document
129 : * granularity. a) change SkPDFFont to fill in its state on demand, kind of
130 : * like SkPDFGraphicState. b) maintain a per font glyph usage class in each
131 : * page/pdf device. c) in the document, retrieve the per font glyph usage
132 : * from each page and combine it and ask for a resource with that subset.
133 : */
134 :
135 0 : SkPDFFont::~SkPDFFont() {}
136 :
137 0 : static bool can_embed(const SkAdvancedTypefaceMetrics& metrics) {
138 0 : return !SkToBool(metrics.fFlags & SkAdvancedTypefaceMetrics::kNotEmbeddable_FontFlag);
139 : }
140 :
141 0 : const SkAdvancedTypefaceMetrics* SkPDFFont::GetMetrics(SkTypeface* typeface,
142 : SkPDFCanon* canon) {
143 0 : SkASSERT(typeface);
144 0 : SkFontID id = typeface->uniqueID();
145 0 : if (SkAdvancedTypefaceMetrics** ptr = canon->fTypefaceMetrics.find(id)) {
146 0 : return *ptr;
147 : }
148 0 : int count = typeface->countGlyphs();
149 0 : if (count <= 0 || count > 1 + SK_MaxU16) {
150 : // Cache nullptr to skip this check. Use SkSafeUnref().
151 0 : canon->fTypefaceMetrics.set(id, nullptr);
152 0 : return nullptr;
153 : }
154 : sk_sp<SkAdvancedTypefaceMetrics> metrics(
155 : typeface->getAdvancedTypefaceMetrics(
156 : SkTypeface::kGlyphNames_PerGlyphInfo | SkTypeface::kToUnicode_PerGlyphInfo,
157 0 : nullptr, 0));
158 0 : if (!metrics) {
159 0 : metrics = sk_make_sp<SkAdvancedTypefaceMetrics>();
160 : }
161 0 : return *canon->fTypefaceMetrics.set(id, metrics.release());
162 : }
163 :
164 0 : SkAdvancedTypefaceMetrics::FontType SkPDFFont::FontType(const SkAdvancedTypefaceMetrics& metrics) {
165 0 : if (SkToBool(metrics.fFlags & SkAdvancedTypefaceMetrics::kMultiMaster_FontFlag) ||
166 0 : SkToBool(metrics.fFlags & SkAdvancedTypefaceMetrics::kNotEmbeddable_FontFlag)) {
167 : // force Type3 fallback.
168 0 : return SkAdvancedTypefaceMetrics::kOther_Font;
169 : }
170 0 : return metrics.fType;
171 : }
172 :
173 0 : static SkGlyphID first_nonzero_glyph_for_single_byte_encoding(SkGlyphID gid) {
174 0 : return gid != 0 ? gid - (gid - 1) % 255 : 1;
175 : }
176 :
177 0 : SkPDFFont* SkPDFFont::GetFontResource(SkPDFCanon* canon,
178 : SkTypeface* face,
179 : SkGlyphID glyphID) {
180 0 : SkASSERT(canon);
181 0 : SkASSERT(face); // All SkPDFDevice::internalDrawText ensures this.
182 0 : const SkAdvancedTypefaceMetrics* fontMetrics = SkPDFFont::GetMetrics(face, canon);
183 0 : SkASSERT(fontMetrics); // SkPDFDevice::internalDrawText ensures the typeface is good.
184 : // GetMetrics only returns null to signify a bad typeface.
185 0 : const SkAdvancedTypefaceMetrics& metrics = *fontMetrics;
186 0 : SkAdvancedTypefaceMetrics::FontType type = SkPDFFont::FontType(metrics);
187 0 : bool multibyte = SkPDFFont::IsMultiByte(type);
188 0 : SkGlyphID subsetCode = multibyte ? 0 : first_nonzero_glyph_for_single_byte_encoding(glyphID);
189 0 : uint64_t fontID = (SkTypeface::UniqueID(face) << 16) | subsetCode;
190 :
191 0 : if (SkPDFFont** found = canon->fFontMap.find(fontID)) {
192 0 : SkPDFFont* foundFont = *found;
193 0 : SkASSERT(foundFont && multibyte == foundFont->multiByteGlyphs());
194 0 : return SkRef(foundFont);
195 : }
196 :
197 0 : sk_sp<SkTypeface> typeface(sk_ref_sp(face));
198 0 : SkASSERT(typeface);
199 :
200 0 : SkGlyphID lastGlyph = SkToU16(typeface->countGlyphs() - 1);
201 :
202 : // should be caught by SkPDFDevice::internalDrawText
203 0 : SkASSERT(glyphID <= lastGlyph);
204 :
205 : SkGlyphID firstNonZeroGlyph;
206 0 : if (multibyte) {
207 0 : firstNonZeroGlyph = 1;
208 : } else {
209 0 : firstNonZeroGlyph = subsetCode;
210 0 : lastGlyph = SkToU16(SkTMin<int>((int)lastGlyph, 254 + (int)subsetCode));
211 : }
212 0 : SkPDFFont::Info info = {std::move(typeface), firstNonZeroGlyph, lastGlyph, type};
213 0 : sk_sp<SkPDFFont> font;
214 0 : switch (type) {
215 : case SkAdvancedTypefaceMetrics::kType1CID_Font:
216 : case SkAdvancedTypefaceMetrics::kTrueType_Font:
217 0 : SkASSERT(multibyte);
218 0 : font = sk_make_sp<SkPDFType0Font>(std::move(info), metrics);
219 0 : break;
220 : case SkAdvancedTypefaceMetrics::kType1_Font:
221 0 : SkASSERT(!multibyte);
222 0 : font = sk_make_sp<SkPDFType1Font>(std::move(info), metrics, canon);
223 0 : break;
224 : default:
225 0 : SkASSERT(!multibyte);
226 : // Type3 is our fallback font.
227 0 : font = sk_make_sp<SkPDFType3Font>(std::move(info), metrics);
228 0 : break;
229 : }
230 0 : canon->fFontMap.set(fontID, SkRef(font.get()));
231 0 : return font.release(); // TODO(halcanary) return sk_sp<SkPDFFont>.
232 : }
233 :
234 0 : SkPDFFont::SkPDFFont(SkPDFFont::Info info)
235 : : SkPDFDict("Font")
236 0 : , fTypeface(std::move(info.fTypeface))
237 0 : , fGlyphUsage(info.fLastGlyphID + 1) // TODO(halcanary): Adjust mapping?
238 0 : , fFirstGlyphID(info.fFirstGlyphID)
239 0 : , fLastGlyphID(info.fLastGlyphID)
240 0 : , fFontType(info.fFontType) {
241 0 : SkASSERT(fTypeface);
242 0 : }
243 :
244 0 : static void add_common_font_descriptor_entries(SkPDFDict* descriptor,
245 : const SkAdvancedTypefaceMetrics& metrics,
246 : uint16_t emSize,
247 : int16_t defaultWidth) {
248 0 : descriptor->insertName("FontName", metrics.fFontName);
249 0 : descriptor->insertInt("Flags", (size_t)(metrics.fStyle | kPdfSymbolic));
250 0 : descriptor->insertScalar("Ascent",
251 0 : scaleFromFontUnits(metrics.fAscent, emSize));
252 0 : descriptor->insertScalar("Descent",
253 0 : scaleFromFontUnits(metrics.fDescent, emSize));
254 0 : descriptor->insertScalar("StemV",
255 0 : scaleFromFontUnits(metrics.fStemV, emSize));
256 0 : descriptor->insertScalar("CapHeight",
257 0 : scaleFromFontUnits(metrics.fCapHeight, emSize));
258 0 : descriptor->insertInt("ItalicAngle", metrics.fItalicAngle);
259 0 : descriptor->insertObject(
260 0 : "FontBBox", makeFontBBox(metrics.fBBox, emSize));
261 0 : if (defaultWidth > 0) {
262 0 : descriptor->insertScalar("MissingWidth",
263 0 : scaleFromFontUnits(defaultWidth, emSize));
264 : }
265 0 : }
266 :
267 : ///////////////////////////////////////////////////////////////////////////////
268 : // class SkPDFType0Font
269 : ///////////////////////////////////////////////////////////////////////////////
270 :
271 0 : SkPDFType0Font::SkPDFType0Font(
272 : SkPDFFont::Info info,
273 0 : const SkAdvancedTypefaceMetrics& metrics)
274 0 : : SkPDFFont(std::move(info)) {
275 0 : SkDEBUGCODE(fPopulated = false);
276 0 : }
277 :
278 0 : SkPDFType0Font::~SkPDFType0Font() {}
279 :
280 :
281 : #ifdef SK_DEBUG
282 0 : void SkPDFType0Font::emitObject(SkWStream* stream,
283 : const SkPDFObjNumMap& objNumMap) const {
284 0 : SkASSERT(fPopulated);
285 0 : return INHERITED::emitObject(stream, objNumMap);
286 : }
287 : #endif
288 :
289 : #ifdef SK_PDF_USE_SFNTLY
290 : // if possible, make no copy.
291 0 : static sk_sp<SkData> stream_to_data(std::unique_ptr<SkStreamAsset> stream) {
292 0 : SkASSERT(stream);
293 0 : (void)stream->rewind();
294 0 : SkASSERT(stream->hasLength());
295 0 : size_t size = stream->getLength();
296 0 : if (const void* base = stream->getMemoryBase()) {
297 : SkData::ReleaseProc proc =
298 0 : [](const void*, void* ctx) { delete (SkStreamAsset*)ctx; };
299 0 : return SkData::MakeWithProc(base, size, proc, stream.release());
300 : }
301 0 : return SkData::MakeFromStream(stream.get(), size);
302 : }
303 :
304 0 : static sk_sp<SkPDFStream> get_subset_font_stream(
305 : std::unique_ptr<SkStreamAsset> fontAsset,
306 : const SkBitSet& glyphUsage,
307 : const char* fontName,
308 : int ttcIndex) {
309 : // Generate glyph id array in format needed by sfntly.
310 : // TODO(halcanary): sfntly should take a more compact format.
311 0 : SkTDArray<unsigned> subset;
312 0 : if (!glyphUsage.has(0)) {
313 0 : subset.push(0); // Always include glyph 0.
314 : }
315 0 : glyphUsage.exportTo(&subset);
316 :
317 0 : unsigned char* subsetFont{nullptr};
318 0 : sk_sp<SkData> fontData(stream_to_data(std::move(fontAsset)));
319 : #if defined(GOOGLE3)
320 : // TODO(halcanary): update GOOGLE3 to newest version of Sfntly.
321 : (void)ttcIndex;
322 : int subsetFontSize = SfntlyWrapper::SubsetFont(fontName,
323 : fontData->bytes(),
324 : fontData->size(),
325 : subset.begin(),
326 : subset.count(),
327 : &subsetFont);
328 : #else
329 : (void)fontName;
330 0 : int subsetFontSize = SfntlyWrapper::SubsetFont(ttcIndex,
331 : fontData->bytes(),
332 : fontData->size(),
333 0 : subset.begin(),
334 0 : subset.count(),
335 0 : &subsetFont);
336 : #endif
337 0 : fontData.reset();
338 0 : subset.reset();
339 0 : SkASSERT(subsetFontSize > 0 || subsetFont == nullptr);
340 0 : if (subsetFontSize < 1) {
341 0 : return nullptr;
342 : }
343 0 : SkASSERT(subsetFont != nullptr);
344 : auto subsetStream = sk_make_sp<SkPDFStream>(
345 0 : SkData::MakeWithProc(
346 : subsetFont, subsetFontSize,
347 0 : [](const void* p, void*) { delete[] (unsigned char*)p; },
348 0 : nullptr));
349 0 : subsetStream->dict()->insertInt("Length1", subsetFontSize);
350 0 : return subsetStream;
351 : }
352 : #endif // SK_PDF_USE_SFNTLY
353 :
354 0 : void SkPDFType0Font::getFontSubset(SkPDFCanon* canon) {
355 : const SkAdvancedTypefaceMetrics* metricsPtr =
356 0 : SkPDFFont::GetMetrics(this->typeface(), canon);
357 0 : SkASSERT(metricsPtr);
358 0 : if (!metricsPtr) { return; }
359 0 : const SkAdvancedTypefaceMetrics& metrics = *metricsPtr;
360 0 : SkASSERT(can_embed(metrics));
361 0 : SkAdvancedTypefaceMetrics::FontType type = this->getType();
362 0 : SkTypeface* face = this->typeface();
363 0 : SkASSERT(face);
364 :
365 0 : auto descriptor = sk_make_sp<SkPDFDict>("FontDescriptor");
366 0 : uint16_t emSize = SkToU16(this->typeface()->getUnitsPerEm());
367 0 : add_common_font_descriptor_entries(descriptor.get(), metrics, emSize , 0);
368 :
369 : int ttcIndex;
370 0 : std::unique_ptr<SkStreamAsset> fontAsset(face->openStream(&ttcIndex));
371 0 : size_t fontSize = fontAsset ? fontAsset->getLength() : 0;
372 0 : if (0 == fontSize) {
373 0 : SkDebugf("Error: (SkTypeface)(%p)::openStream() returned "
374 : "empty stream (%p) when identified as kType1CID_Font "
375 0 : "or kTrueType_Font.\n", face, fontAsset.get());
376 : } else {
377 0 : switch (type) {
378 : case SkAdvancedTypefaceMetrics::kTrueType_Font: {
379 : #ifdef SK_PDF_USE_SFNTLY
380 0 : if (!SkToBool(metrics.fFlags &
381 : SkAdvancedTypefaceMetrics::kNotSubsettable_FontFlag)) {
382 : sk_sp<SkPDFStream> subsetStream = get_subset_font_stream(
383 0 : std::move(fontAsset), this->glyphUsage(),
384 0 : metrics.fFontName.c_str(), ttcIndex);
385 0 : if (subsetStream) {
386 0 : descriptor->insertObjRef("FontFile2", std::move(subsetStream));
387 0 : break;
388 : }
389 : // If subsetting fails, fall back to original font data.
390 0 : fontAsset.reset(face->openStream(&ttcIndex));
391 0 : SkASSERT(fontAsset);
392 0 : SkASSERT(fontAsset->getLength() == fontSize);
393 0 : if (!fontAsset || fontAsset->getLength() == 0) { break; }
394 : }
395 : #endif // SK_PDF_USE_SFNTLY
396 0 : auto fontStream = sk_make_sp<SkPDFSharedStream>(std::move(fontAsset));
397 0 : fontStream->dict()->insertInt("Length1", fontSize);
398 0 : descriptor->insertObjRef("FontFile2", std::move(fontStream));
399 0 : break;
400 : }
401 : case SkAdvancedTypefaceMetrics::kType1CID_Font: {
402 0 : auto fontStream = sk_make_sp<SkPDFSharedStream>(std::move(fontAsset));
403 0 : fontStream->dict()->insertName("Subtype", "CIDFontType0C");
404 0 : descriptor->insertObjRef("FontFile3", std::move(fontStream));
405 0 : break;
406 : }
407 : default:
408 0 : SkASSERT(false);
409 : }
410 : }
411 :
412 0 : auto newCIDFont = sk_make_sp<SkPDFDict>("Font");
413 0 : newCIDFont->insertObjRef("FontDescriptor", std::move(descriptor));
414 0 : newCIDFont->insertName("BaseFont", metrics.fFontName);
415 :
416 0 : switch (type) {
417 : case SkAdvancedTypefaceMetrics::kType1CID_Font:
418 0 : newCIDFont->insertName("Subtype", "CIDFontType0");
419 0 : break;
420 : case SkAdvancedTypefaceMetrics::kTrueType_Font:
421 0 : newCIDFont->insertName("Subtype", "CIDFontType2");
422 0 : newCIDFont->insertName("CIDToGIDMap", "Identity");
423 0 : break;
424 : default:
425 0 : SkASSERT(false);
426 : }
427 0 : auto sysInfo = sk_make_sp<SkPDFDict>();
428 0 : sysInfo->insertString("Registry", "Adobe");
429 0 : sysInfo->insertString("Ordering", "Identity");
430 0 : sysInfo->insertInt("Supplement", 0);
431 0 : newCIDFont->insertObject("CIDSystemInfo", std::move(sysInfo));
432 :
433 0 : int16_t defaultWidth = 0;
434 : {
435 : int emSize;
436 0 : SkAutoGlyphCache glyphCache = SkPDFFont::MakeVectorCache(face, &emSize);
437 : sk_sp<SkPDFArray> widths = SkPDFMakeCIDGlyphWidthsArray(
438 0 : glyphCache.get(), &this->glyphUsage(), SkToS16(emSize), &defaultWidth);
439 0 : if (widths && widths->size() > 0) {
440 0 : newCIDFont->insertObject("W", std::move(widths));
441 : }
442 0 : newCIDFont->insertScalar(
443 0 : "DW", scaleFromFontUnits(defaultWidth, SkToS16(emSize)));
444 : }
445 :
446 : ////////////////////////////////////////////////////////////////////////////
447 :
448 0 : this->insertName("Subtype", "Type0");
449 0 : this->insertName("BaseFont", metrics.fFontName);
450 0 : this->insertName("Encoding", "Identity-H");
451 0 : auto descendantFonts = sk_make_sp<SkPDFArray>();
452 0 : descendantFonts->appendObjRef(std::move(newCIDFont));
453 0 : this->insertObject("DescendantFonts", std::move(descendantFonts));
454 :
455 0 : if (metrics.fGlyphToUnicode.count() > 0) {
456 0 : this->insertObjRef("ToUnicode",
457 0 : SkPDFMakeToUnicodeCmap(metrics.fGlyphToUnicode,
458 0 : &this->glyphUsage(),
459 0 : multiByteGlyphs(),
460 0 : firstGlyphID(),
461 0 : lastGlyphID()));
462 : }
463 0 : SkDEBUGCODE(fPopulated = true);
464 0 : return;
465 : }
466 :
467 : ///////////////////////////////////////////////////////////////////////////////
468 : // class SkPDFType1Font
469 : ///////////////////////////////////////////////////////////////////////////////
470 :
471 0 : static sk_sp<SkPDFDict> make_type1_font_descriptor(
472 : SkTypeface* typeface,
473 : const SkAdvancedTypefaceMetrics& info) {
474 0 : auto descriptor = sk_make_sp<SkPDFDict>("FontDescriptor");
475 0 : uint16_t emSize = SkToU16(typeface->getUnitsPerEm());
476 0 : add_common_font_descriptor_entries(descriptor.get(), info, emSize, 0);
477 0 : if (!can_embed(info)) {
478 0 : return descriptor;
479 : }
480 : int ttcIndex;
481 0 : size_t header SK_INIT_TO_AVOID_WARNING;
482 0 : size_t data SK_INIT_TO_AVOID_WARNING;
483 0 : size_t trailer SK_INIT_TO_AVOID_WARNING;
484 0 : std::unique_ptr<SkStreamAsset> rawFontData(typeface->openStream(&ttcIndex));
485 0 : sk_sp<SkData> fontData = SkPDFConvertType1FontStream(std::move(rawFontData),
486 0 : &header, &data, &trailer);
487 0 : if (fontData) {
488 0 : auto fontStream = sk_make_sp<SkPDFStream>(std::move(fontData));
489 0 : fontStream->dict()->insertInt("Length1", header);
490 0 : fontStream->dict()->insertInt("Length2", data);
491 0 : fontStream->dict()->insertInt("Length3", trailer);
492 0 : descriptor->insertObjRef("FontFile", std::move(fontStream));
493 : }
494 0 : return descriptor;
495 : }
496 :
497 0 : static void populate_type_1_font(SkPDFDict* font,
498 : const SkAdvancedTypefaceMetrics& info,
499 : SkTypeface* typeface,
500 : SkGlyphID firstGlyphID,
501 : SkGlyphID lastGlyphID) {
502 0 : font->insertName("Subtype", "Type1");
503 0 : font->insertName("BaseFont", info.fFontName);
504 :
505 : // glyphCount not including glyph 0
506 0 : unsigned glyphCount = 1 + lastGlyphID - firstGlyphID;
507 0 : SkASSERT(glyphCount > 0 && glyphCount <= 255);
508 0 : font->insertInt("FirstChar", (size_t)0);
509 0 : font->insertInt("LastChar", (size_t)glyphCount);
510 : {
511 : int emSize;
512 0 : SkAutoGlyphCache glyphCache = SkPDFFont::MakeVectorCache(typeface, &emSize);
513 0 : auto widths = sk_make_sp<SkPDFArray>();
514 0 : SkScalar advance = glyphCache->getGlyphIDAdvance(0).fAdvanceX;
515 0 : widths->appendScalar(from_font_units(advance, SkToU16(emSize)));
516 0 : for (unsigned gID = firstGlyphID; gID <= lastGlyphID; gID++) {
517 0 : advance = glyphCache->getGlyphIDAdvance(gID).fAdvanceX;
518 0 : widths->appendScalar(from_font_units(advance, SkToU16(emSize)));
519 : }
520 0 : font->insertObject("Widths", std::move(widths));
521 : }
522 0 : auto encDiffs = sk_make_sp<SkPDFArray>();
523 0 : encDiffs->reserve(lastGlyphID - firstGlyphID + 3);
524 0 : encDiffs->appendInt(0);
525 0 : const SkTArray<SkString>& glyphNames = info.fGlyphNames;
526 0 : SkASSERT(glyphNames.count() > lastGlyphID);
527 0 : encDiffs->appendName(glyphNames[0].c_str());
528 0 : const SkString unknown("UNKNOWN");
529 0 : for (int gID = firstGlyphID; gID <= lastGlyphID; gID++) {
530 0 : const bool valid = gID < glyphNames.count() && !glyphNames[gID].isEmpty();
531 0 : const SkString& name = valid ? glyphNames[gID] : unknown;
532 0 : encDiffs->appendName(name);
533 : }
534 :
535 0 : auto encoding = sk_make_sp<SkPDFDict>("Encoding");
536 0 : encoding->insertObject("Differences", std::move(encDiffs));
537 0 : font->insertObject("Encoding", std::move(encoding));
538 0 : }
539 :
540 0 : SkPDFType1Font::SkPDFType1Font(SkPDFFont::Info info,
541 : const SkAdvancedTypefaceMetrics& metrics,
542 0 : SkPDFCanon* canon)
543 0 : : SkPDFFont(std::move(info))
544 : {
545 0 : SkFontID fontID = this->typeface()->uniqueID();
546 0 : sk_sp<SkPDFDict> fontDescriptor;
547 0 : if (SkPDFDict** ptr = canon->fFontDescriptors.find(fontID)) {
548 0 : fontDescriptor = sk_ref_sp(*ptr);
549 : } else {
550 0 : fontDescriptor = make_type1_font_descriptor(this->typeface(), metrics);
551 0 : canon->fFontDescriptors.set(fontID, SkRef(fontDescriptor.get()));
552 : }
553 0 : this->insertObjRef("FontDescriptor", std::move(fontDescriptor));
554 : // TODO(halcanary): subset this (advances and names).
555 0 : populate_type_1_font(this, metrics, this->typeface(),
556 0 : this->firstGlyphID(), this->lastGlyphID());
557 0 : }
558 :
559 : ///////////////////////////////////////////////////////////////////////////////
560 : // class SkPDFType3Font
561 : ///////////////////////////////////////////////////////////////////////////////
562 :
563 : namespace {
564 : // returns [0, first, first+1, ... last-1, last]
565 : struct SingleByteGlyphIdIterator {
566 0 : SingleByteGlyphIdIterator(SkGlyphID first, SkGlyphID last)
567 0 : : fFirst(first), fLast(last) {
568 0 : SkASSERT(fFirst > 0);
569 0 : SkASSERT(fLast >= first);
570 0 : }
571 : struct Iter {
572 0 : void operator++() {
573 0 : fCurrent = (0 == fCurrent) ? fFirst : fCurrent + 1;
574 0 : }
575 : // This is an input_iterator
576 0 : SkGlyphID operator*() const { return (SkGlyphID)fCurrent; }
577 0 : bool operator!=(const Iter& rhs) const {
578 0 : return fCurrent != rhs.fCurrent;
579 : }
580 0 : Iter(SkGlyphID f, int c) : fFirst(f), fCurrent(c) {}
581 : private:
582 : const SkGlyphID fFirst;
583 : int fCurrent; // must be int to make fLast+1 to fit
584 : };
585 0 : Iter begin() const { return Iter(fFirst, 0); }
586 0 : Iter end() const { return Iter(fFirst, (int)fLast + 1); }
587 : private:
588 : const SkGlyphID fFirst;
589 : const SkGlyphID fLast;
590 : };
591 : }
592 :
593 0 : static void add_type3_font_info(SkPDFCanon* canon,
594 : SkPDFDict* font,
595 : SkTypeface* typeface,
596 : const SkBitSet& subset,
597 : SkGlyphID firstGlyphID,
598 : SkGlyphID lastGlyphID) {
599 0 : const SkAdvancedTypefaceMetrics* metrics = SkPDFFont::GetMetrics(typeface, canon);
600 0 : SkASSERT(lastGlyphID >= firstGlyphID);
601 : // Remove unused glyphs at the end of the range.
602 : // Keep the lastGlyphID >= firstGlyphID invariant true.
603 0 : while (lastGlyphID > firstGlyphID && !subset.has(lastGlyphID)) {
604 0 : --lastGlyphID;
605 : }
606 : int unitsPerEm;
607 0 : SkAutoGlyphCache cache = SkPDFFont::MakeVectorCache(typeface, &unitsPerEm);
608 0 : SkScalar emSize = (SkScalar)unitsPerEm;
609 0 : font->insertName("Subtype", "Type3");
610 : // Flip about the x-axis and scale by 1/emSize.
611 : SkMatrix fontMatrix;
612 0 : fontMatrix.setScale(SkScalarInvert(emSize), -SkScalarInvert(emSize));
613 0 : font->insertObject("FontMatrix", SkPDFUtils::MatrixToArray(fontMatrix));
614 :
615 0 : auto charProcs = sk_make_sp<SkPDFDict>();
616 0 : auto encoding = sk_make_sp<SkPDFDict>("Encoding");
617 :
618 0 : auto encDiffs = sk_make_sp<SkPDFArray>();
619 : // length(firstGlyphID .. lastGlyphID) == lastGlyphID - firstGlyphID + 1
620 : // plus 1 for glyph 0;
621 0 : SkASSERT(firstGlyphID > 0);
622 0 : SkASSERT(lastGlyphID >= firstGlyphID);
623 0 : int glyphCount = lastGlyphID - firstGlyphID + 2;
624 : // one other entry for the index of first glyph.
625 0 : encDiffs->reserve(glyphCount + 1);
626 0 : encDiffs->appendInt(0); // index of first glyph
627 :
628 0 : auto widthArray = sk_make_sp<SkPDFArray>();
629 0 : widthArray->reserve(glyphCount);
630 :
631 0 : SkIRect bbox = SkIRect::MakeEmpty();
632 :
633 0 : sk_sp<SkPDFStream> emptyStream;
634 0 : for (SkGlyphID gID : SingleByteGlyphIdIterator(firstGlyphID, lastGlyphID)) {
635 0 : bool skipGlyph = gID != 0 && !subset.has(gID);
636 0 : SkString characterName;
637 0 : SkScalar advance = 0.0f;
638 : SkIRect glyphBBox;
639 0 : if (skipGlyph) {
640 0 : characterName.set("g0");
641 : } else {
642 0 : characterName.printf("g%X", gID);
643 0 : const SkGlyph& glyph = cache->getGlyphIDMetrics(gID);
644 0 : advance = SkFloatToScalar(glyph.fAdvanceX);
645 0 : glyphBBox = SkIRect::MakeXYWH(glyph.fLeft, glyph.fTop,
646 0 : glyph.fWidth, glyph.fHeight);
647 0 : bbox.join(glyphBBox);
648 0 : const SkPath* path = cache->findPath(glyph);
649 0 : if (path && !path->isEmpty()) {
650 0 : SkDynamicMemoryWStream content;
651 0 : setGlyphWidthAndBoundingBox(SkFloatToScalar(glyph.fAdvanceX), glyphBBox,
652 0 : &content);
653 0 : SkPDFUtils::EmitPath(*path, SkPaint::kFill_Style, &content);
654 0 : SkPDFUtils::PaintPath(SkPaint::kFill_Style, path->getFillType(),
655 0 : &content);
656 0 : charProcs->insertObjRef(
657 0 : characterName, sk_make_sp<SkPDFStream>(
658 0 : std::unique_ptr<SkStreamAsset>(content.detachAsStream())));
659 : } else {
660 0 : if (!emptyStream) {
661 0 : emptyStream = sk_make_sp<SkPDFStream>(
662 0 : std::unique_ptr<SkStreamAsset>(
663 0 : new SkMemoryStream((size_t)0)));
664 : }
665 0 : charProcs->insertObjRef(characterName, emptyStream);
666 : }
667 : }
668 0 : encDiffs->appendName(characterName.c_str());
669 0 : widthArray->appendScalar(advance);
670 : }
671 :
672 0 : encoding->insertObject("Differences", std::move(encDiffs));
673 0 : font->insertInt("FirstChar", 0);
674 0 : font->insertInt("LastChar", lastGlyphID - firstGlyphID + 1);
675 : /* FontBBox: "A rectangle expressed in the glyph coordinate
676 : system, specifying the font bounding box. This is the smallest
677 : rectangle enclosing the shape that would result if all of the
678 : glyphs of the font were placed with their origins coincident and
679 : then filled." */
680 0 : auto fontBBox = sk_make_sp<SkPDFArray>();
681 0 : fontBBox->reserve(4);
682 0 : fontBBox->appendInt(bbox.left());
683 0 : fontBBox->appendInt(bbox.bottom());
684 0 : fontBBox->appendInt(bbox.right());
685 0 : fontBBox->appendInt(bbox.top());
686 0 : font->insertObject("FontBBox", std::move(fontBBox));
687 0 : font->insertName("CIDToGIDMap", "Identity");
688 0 : if (metrics && metrics->fGlyphToUnicode.count() > 0) {
689 0 : font->insertObjRef("ToUnicode",
690 0 : SkPDFMakeToUnicodeCmap(metrics->fGlyphToUnicode,
691 : &subset,
692 : false,
693 : firstGlyphID,
694 0 : lastGlyphID));
695 : }
696 0 : auto descriptor = sk_make_sp<SkPDFDict>("FontDescriptor");
697 0 : int32_t fontDescriptorFlags = kPdfSymbolic;
698 0 : if (metrics) {
699 : // Type3 FontDescriptor does not require all the same fields.
700 0 : descriptor->insertName("FontName", metrics->fFontName);
701 0 : descriptor->insertInt("ItalicAngle", metrics->fItalicAngle);
702 0 : fontDescriptorFlags |= (int32_t)metrics->fStyle;
703 : }
704 0 : descriptor->insertInt("Flags", fontDescriptorFlags);
705 0 : font->insertObjRef("FontDescriptor", std::move(descriptor));
706 0 : font->insertObject("Widths", std::move(widthArray));
707 0 : font->insertObject("Encoding", std::move(encoding));
708 0 : font->insertObject("CharProcs", std::move(charProcs));
709 0 : }
710 :
711 0 : SkPDFType3Font::SkPDFType3Font(SkPDFFont::Info info,
712 0 : const SkAdvancedTypefaceMetrics& metrics)
713 0 : : SkPDFFont(std::move(info)) {}
714 :
715 0 : void SkPDFType3Font::getFontSubset(SkPDFCanon* canon) {
716 0 : add_type3_font_info(canon, this, this->typeface(), this->glyphUsage(),
717 0 : this->firstGlyphID(), this->lastGlyphID());
718 0 : }
719 :
720 : ////////////////////////////////////////////////////////////////////////////////
721 :
722 0 : bool SkPDFFont::CanEmbedTypeface(SkTypeface* typeface, SkPDFCanon* canon) {
723 0 : const SkAdvancedTypefaceMetrics* metrics = SkPDFFont::GetMetrics(typeface, canon);
724 0 : return metrics && can_embed(*metrics);
725 : }
726 :
727 0 : void SkPDFFont::drop() {
728 0 : fTypeface = nullptr;
729 0 : fGlyphUsage.~SkBitSet();
730 0 : new (&fGlyphUsage) SkBitSet(0);
731 0 : this->SkPDFDict::drop();
732 0 : }
|