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 "src/pdf/SkPDFFont.h"
9
10 #include "include/core/SkBitmap.h"
11 #include "include/core/SkCanvas.h"
12 #include "include/core/SkData.h"
13 #include "include/core/SkDrawable.h"
14 #include "include/core/SkFont.h"
15 #include "include/core/SkFontMetrics.h"
16 #include "include/core/SkFontStyle.h"
17 #include "include/core/SkFontTypes.h"
18 #include "include/core/SkImage.h"
19 #include "include/core/SkImageInfo.h"
20 #include "include/core/SkMatrix.h"
21 #include "include/core/SkPaint.h"
22 #include "include/core/SkPath.h"
23 #include "include/core/SkPoint.h"
24 #include "include/core/SkRect.h"
25 #include "include/core/SkRefCnt.h"
26 #include "include/core/SkScalar.h"
27 #include "include/core/SkStream.h"
28 #include "include/core/SkString.h"
29 #include "include/core/SkSurfaceProps.h"
30 #include "include/private/base/SkDebug.h"
31 #include "include/private/base/SkTPin.h"
32 #include "include/private/base/SkTo.h"
33 #include "src/base/SkBitmaskEnum.h"
34 #include "src/base/SkUTF.h"
35 #include "src/core/SkDevice.h"
36 #include "src/core/SkGlyph.h"
37 #include "src/core/SkMask.h"
38 #include "src/core/SkScalerContext.h"
39 #include "src/core/SkStrike.h"
40 #include "src/core/SkStrikeSpec.h"
41 #include "src/core/SkTHash.h"
42 #include "src/pdf/SkPDFBitmap.h"
43 #include "src/pdf/SkPDFDevice.h"
44 #include "src/pdf/SkPDFDocumentPriv.h"
45 #include "src/pdf/SkPDFFormXObject.h"
46 #include "src/pdf/SkPDFMakeCIDGlyphWidthsArray.h"
47 #include "src/pdf/SkPDFMakeToUnicodeCmap.h"
48 #include "src/pdf/SkPDFSubsetFont.h"
49 #include "src/pdf/SkPDFType1Font.h"
50 #include "src/pdf/SkPDFUtils.h"
51
52 #include <limits.h>
53 #include <algorithm>
54 #include <cstddef>
55 #include <initializer_list>
56 #include <memory>
57 #include <utility>
58
GetType1GlyphNames(const SkTypeface & face,SkString * dst)59 void SkPDFFont::GetType1GlyphNames(const SkTypeface& face, SkString* dst) {
60 face.getPostScriptGlyphNames(dst);
61 }
62
63 namespace {
64 // PDF's notion of symbolic vs non-symbolic is related to the character set, not
65 // symbols vs. characters. Rarely is a font the right character set to call it
66 // non-symbolic, so always call it symbolic. (PDF 1.4 spec, section 5.7.1)
67 static const int32_t kPdfSymbolic = 4;
68 static const SkFontTableTag kCOLRTableTag = SkSetFourByteTag('C', 'O', 'L', 'R');
69
70 // scale from em-units to base-1000, returning as a SkScalar
from_font_units(SkScalar scaled,uint16_t emSize)71 inline SkScalar from_font_units(SkScalar scaled, uint16_t emSize) {
72 return emSize == 1000 ? scaled : scaled * 1000 / emSize;
73 }
74
scaleFromFontUnits(int16_t val,uint16_t emSize)75 inline SkScalar scaleFromFontUnits(int16_t val, uint16_t emSize) {
76 return from_font_units(SkIntToScalar(val), emSize);
77 }
78
setGlyphWidthAndBoundingBox(SkScalar width,SkIRect box,SkDynamicMemoryWStream * content)79 void setGlyphWidthAndBoundingBox(SkScalar width, SkIRect box,
80 SkDynamicMemoryWStream* content) {
81 // Specify width and bounding box for the glyph.
82 SkPDFUtils::AppendScalar(width, content);
83 content->writeText(" 0 ");
84 content->writeDecAsText(box.fLeft);
85 content->writeText(" ");
86 content->writeDecAsText(box.fTop);
87 content->writeText(" ");
88 content->writeDecAsText(box.fRight);
89 content->writeText(" ");
90 content->writeDecAsText(box.fBottom);
91 content->writeText(" d1\n");
92 }
93 } // namespace
94
95 ///////////////////////////////////////////////////////////////////////////////
96 // class SkPDFFont
97 ///////////////////////////////////////////////////////////////////////////////
98
99 /* Resources are canonicalized and uniqueified by pointer so there has to be
100 * some additional state indicating which subset of the font is used. It
101 * must be maintained at the document granularity.
102 */
103
104 SkPDFFont::~SkPDFFont() = default;
105
106 SkPDFFont::SkPDFFont(SkPDFFont&&) = default;
107
108 SkPDFFont& SkPDFFont::operator=(SkPDFFont&&) = default;
109
can_embed(const SkAdvancedTypefaceMetrics & metrics)110 static bool can_embed(const SkAdvancedTypefaceMetrics& metrics) {
111 return !SkToBool(metrics.fFlags & SkAdvancedTypefaceMetrics::kNotEmbeddable_FontFlag);
112 }
113
GetMetrics(const SkTypeface * typeface,SkPDFDocument * canon)114 const SkAdvancedTypefaceMetrics* SkPDFFont::GetMetrics(const SkTypeface* typeface,
115 SkPDFDocument* canon) {
116 SkASSERT(typeface);
117 SkTypefaceID id = typeface->uniqueID();
118 if (std::unique_ptr<SkAdvancedTypefaceMetrics>* ptr = canon->fTypefaceMetrics.find(id)) {
119 return ptr->get(); // canon retains ownership.
120 }
121 int count = typeface->countGlyphs();
122 if (count <= 0 || count > 1 + SkTo<int>(UINT16_MAX)) {
123 // Cache nullptr to skip this check. Use SkSafeUnref().
124 canon->fTypefaceMetrics.set(id, nullptr);
125 return nullptr;
126 }
127 std::unique_ptr<SkAdvancedTypefaceMetrics> metrics = typeface->getAdvancedMetrics();
128 if (!metrics) {
129 metrics = std::make_unique<SkAdvancedTypefaceMetrics>();
130 }
131
132 if (0 == metrics->fStemV || 0 == metrics->fCapHeight) {
133 SkFont font;
134 font.setHinting(SkFontHinting::kNone);
135 font.setTypeface(sk_ref_sp(typeface));
136 font.setSize(1000); // glyph coordinate system
137 if (0 == metrics->fStemV) {
138 // Figure out a good guess for StemV - Min width of i, I, !, 1.
139 // This probably isn't very good with an italic font.
140 int16_t stemV = SHRT_MAX;
141 for (char c : {'i', 'I', '!', '1'}) {
142 uint16_t g = font.unicharToGlyph(c);
143 SkRect bounds;
144 font.getBounds(&g, 1, &bounds, nullptr);
145 stemV = std::min(stemV, SkToS16(SkScalarRoundToInt(bounds.width())));
146 }
147 metrics->fStemV = stemV;
148 }
149 if (0 == metrics->fCapHeight) {
150 // Figure out a good guess for CapHeight: average the height of M and X.
151 SkScalar capHeight = 0;
152 for (char c : {'M', 'X'}) {
153 uint16_t g = font.unicharToGlyph(c);
154 SkRect bounds;
155 font.getBounds(&g, 1, &bounds, nullptr);
156 capHeight += bounds.height();
157 }
158 metrics->fCapHeight = SkToS16(SkScalarRoundToInt(capHeight / 2));
159 }
160 }
161 // Fonts are always subset, so always prepend the subset tag.
162 metrics->fPostScriptName.prepend(canon->nextFontSubsetTag());
163 return canon->fTypefaceMetrics.set(id, std::move(metrics))->get();
164 }
165
GetUnicodeMap(const SkTypeface * typeface,SkPDFDocument * canon)166 const std::vector<SkUnichar>& SkPDFFont::GetUnicodeMap(const SkTypeface* typeface,
167 SkPDFDocument* canon) {
168 SkASSERT(typeface);
169 SkASSERT(canon);
170 SkTypefaceID id = typeface->uniqueID();
171 if (std::vector<SkUnichar>* ptr = canon->fToUnicodeMap.find(id)) {
172 return *ptr;
173 }
174 std::vector<SkUnichar> buffer(typeface->countGlyphs());
175 typeface->getGlyphToUnicodeMap(buffer.data());
176 return *canon->fToUnicodeMap.set(id, std::move(buffer));
177 }
178
FontType(const SkTypeface & typeface,const SkAdvancedTypefaceMetrics & metrics)179 SkAdvancedTypefaceMetrics::FontType SkPDFFont::FontType(const SkTypeface& typeface,
180 const SkAdvancedTypefaceMetrics& metrics) {
181 if (SkToBool(metrics.fFlags & SkAdvancedTypefaceMetrics::kVariable_FontFlag) ||
182 // PDF is actually interested in the encoding of the data, not just the logical format.
183 // If the TrueType is actually wOFF or wOF2 then it should not be directly embedded in PDF.
184 // For now export these as Type3 until the subsetter can handle table based fonts.
185 // See https://github.com/harfbuzz/harfbuzz/issues/3609 and
186 // https://skia-review.googlesource.com/c/skia/+/543485
187 SkToBool(metrics.fFlags & SkAdvancedTypefaceMetrics::kAltDataFormat_FontFlag) ||
188 SkToBool(metrics.fFlags & SkAdvancedTypefaceMetrics::kNotEmbeddable_FontFlag)) {
189 // force Type3 fallback.
190 return SkAdvancedTypefaceMetrics::kOther_Font;
191 }
192 if (typeface.getTableSize(kCOLRTableTag)) {
193 // https://bugs.chromium.org/p/skia/issues/detail?id=12650
194 // Don't embed COLRv0 / COLRv1 fonts, fall back to bitmaps.
195 return SkAdvancedTypefaceMetrics::kOther_Font;
196 }
197 return metrics.fType;
198 }
199
first_nonzero_glyph_for_single_byte_encoding(SkGlyphID gid)200 static SkGlyphID first_nonzero_glyph_for_single_byte_encoding(SkGlyphID gid) {
201 return gid != 0 ? gid - (gid - 1) % 255 : 1;
202 }
203
GetFontResource(SkPDFDocument * doc,const SkGlyph * glyph,SkTypeface * face)204 SkPDFFont* SkPDFFont::GetFontResource(SkPDFDocument* doc,
205 const SkGlyph* glyph,
206 SkTypeface* face) {
207 SkASSERT(doc);
208 SkASSERT(face); // All SkPDFDevice::internalDrawText ensures this.
209 const SkAdvancedTypefaceMetrics* fontMetrics = SkPDFFont::GetMetrics(face, doc);
210 SkASSERT(fontMetrics); // SkPDFDevice::internalDrawText ensures the typeface is good.
211 // GetMetrics only returns null to signify a bad typeface.
212 const SkAdvancedTypefaceMetrics& metrics = *fontMetrics;
213 SkAdvancedTypefaceMetrics::FontType type = SkPDFFont::FontType(*face, metrics);
214 if (!(glyph->isEmpty() || glyph->path())) {
215 type = SkAdvancedTypefaceMetrics::kOther_Font;
216 }
217 bool multibyte = SkPDFFont::IsMultiByte(type);
218 SkGlyphID subsetCode =
219 multibyte ? 0 : first_nonzero_glyph_for_single_byte_encoding(glyph->getGlyphID());
220 uint64_t typefaceID = (static_cast<uint64_t>(face->uniqueID()) << 16) | subsetCode;
221
222 if (SkPDFFont* found = doc->fFontMap.find(typefaceID)) {
223 SkASSERT(multibyte == found->multiByteGlyphs());
224 return found;
225 }
226
227 sk_sp<SkTypeface> typeface(sk_ref_sp(face));
228 SkASSERT(typeface);
229
230 SkGlyphID lastGlyph = SkToU16(typeface->countGlyphs() - 1);
231
232 // should be caught by SkPDFDevice::internalDrawText
233 SkASSERT(glyph->getGlyphID() <= lastGlyph);
234
235 SkGlyphID firstNonZeroGlyph;
236 if (multibyte) {
237 firstNonZeroGlyph = 1;
238 } else {
239 firstNonZeroGlyph = subsetCode;
240 lastGlyph = SkToU16(std::min<int>((int)lastGlyph, 254 + (int)subsetCode));
241 }
242 auto ref = doc->reserveRef();
243 return doc->fFontMap.set(
244 typefaceID, SkPDFFont(std::move(typeface), firstNonZeroGlyph, lastGlyph, type, ref));
245 }
246
SkPDFFont(sk_sp<SkTypeface> typeface,SkGlyphID firstGlyphID,SkGlyphID lastGlyphID,SkAdvancedTypefaceMetrics::FontType fontType,SkPDFIndirectReference indirectReference)247 SkPDFFont::SkPDFFont(sk_sp<SkTypeface> typeface,
248 SkGlyphID firstGlyphID,
249 SkGlyphID lastGlyphID,
250 SkAdvancedTypefaceMetrics::FontType fontType,
251 SkPDFIndirectReference indirectReference)
252 : fTypeface(std::move(typeface))
253 , fGlyphUsage(firstGlyphID, lastGlyphID)
254 , fIndirectReference(indirectReference)
255 , fFontType(fontType)
256 {
257 // Always include glyph 0
258 this->noteGlyphUsage(0);
259 }
260
PopulateCommonFontDescriptor(SkPDFDict * descriptor,const SkAdvancedTypefaceMetrics & metrics,uint16_t emSize,int16_t defaultWidth)261 void SkPDFFont::PopulateCommonFontDescriptor(SkPDFDict* descriptor,
262 const SkAdvancedTypefaceMetrics& metrics,
263 uint16_t emSize,
264 int16_t defaultWidth) {
265 descriptor->insertName("FontName", metrics.fPostScriptName);
266 descriptor->insertInt("Flags", (size_t)(metrics.fStyle | kPdfSymbolic));
267 descriptor->insertScalar("Ascent",
268 scaleFromFontUnits(metrics.fAscent, emSize));
269 descriptor->insertScalar("Descent",
270 scaleFromFontUnits(metrics.fDescent, emSize));
271 descriptor->insertScalar("StemV",
272 scaleFromFontUnits(metrics.fStemV, emSize));
273 descriptor->insertScalar("CapHeight",
274 scaleFromFontUnits(metrics.fCapHeight, emSize));
275 descriptor->insertInt("ItalicAngle", metrics.fItalicAngle);
276 descriptor->insertObject("FontBBox",
277 SkPDFMakeArray(scaleFromFontUnits(metrics.fBBox.left(), emSize),
278 scaleFromFontUnits(metrics.fBBox.bottom(), emSize),
279 scaleFromFontUnits(metrics.fBBox.right(), emSize),
280 scaleFromFontUnits(metrics.fBBox.top(), emSize)));
281 if (defaultWidth > 0) {
282 descriptor->insertScalar("MissingWidth",
283 scaleFromFontUnits(defaultWidth, emSize));
284 }
285 }
286
287 ///////////////////////////////////////////////////////////////////////////////
288 // Type0Font
289 ///////////////////////////////////////////////////////////////////////////////
290
emit_subset_type0(const SkPDFFont & font,SkPDFDocument * doc)291 static void emit_subset_type0(const SkPDFFont& font, SkPDFDocument* doc) {
292 const SkAdvancedTypefaceMetrics* metricsPtr =
293 SkPDFFont::GetMetrics(font.typeface(), doc);
294 SkASSERT(metricsPtr);
295 if (!metricsPtr) { return; }
296 const SkAdvancedTypefaceMetrics& metrics = *metricsPtr;
297 SkASSERT(can_embed(metrics));
298 SkAdvancedTypefaceMetrics::FontType type = font.getType();
299 SkTypeface* face = font.typeface();
300 SkASSERT(face);
301
302 auto descriptor = SkPDFMakeDict("FontDescriptor");
303 uint16_t emSize = SkToU16(font.typeface()->getUnitsPerEm());
304 SkPDFFont::PopulateCommonFontDescriptor(descriptor.get(), metrics, emSize, 0);
305
306 int ttcIndex;
307 std::unique_ptr<SkStreamAsset> fontAsset = face->openStream(&ttcIndex);
308 size_t fontSize = fontAsset ? fontAsset->getLength() : 0;
309 if (0 == fontSize) {
310 SkDebugf("Error: (SkTypeface)(%p)::openStream() returned "
311 "empty stream (%p) when identified as kType1CID_Font "
312 "or kTrueType_Font.\n", face, fontAsset.get());
313 } else {
314 switch (type) {
315 case SkAdvancedTypefaceMetrics::kTrueType_Font:
316 case SkAdvancedTypefaceMetrics::kCFF_Font: {
317 if (!SkToBool(metrics.fFlags &
318 SkAdvancedTypefaceMetrics::kNotSubsettable_FontFlag)) {
319 SkASSERT(font.firstGlyphID() == 1);
320 sk_sp<SkData> subsetFontData = SkPDFSubsetFont(*face, font.glyphUsage());
321 if (subsetFontData) {
322 std::unique_ptr<SkPDFDict> tmp = SkPDFMakeDict();
323 tmp->insertInt("Length1", SkToInt(subsetFontData->size()));
324 descriptor->insertRef(
325 "FontFile2",
326 SkPDFStreamOut(std::move(tmp),
327 SkMemoryStream::Make(std::move(subsetFontData)),
328 doc, SkPDFSteamCompressionEnabled::Yes));
329 break;
330 }
331 // If subsetting fails, fall back to original font data.
332 }
333 std::unique_ptr<SkPDFDict> tmp = SkPDFMakeDict();
334 tmp->insertInt("Length1", fontSize);
335 descriptor->insertRef("FontFile2",
336 SkPDFStreamOut(std::move(tmp), std::move(fontAsset),
337 doc, SkPDFSteamCompressionEnabled::Yes));
338 break;
339 }
340 case SkAdvancedTypefaceMetrics::kType1CID_Font: {
341 std::unique_ptr<SkPDFDict> tmp = SkPDFMakeDict();
342 tmp->insertName("Subtype", "CIDFontType0C");
343 descriptor->insertRef("FontFile3",
344 SkPDFStreamOut(std::move(tmp), std::move(fontAsset),
345 doc, SkPDFSteamCompressionEnabled::Yes));
346 break;
347 }
348 default:
349 SkASSERT(false);
350 }
351 }
352
353 auto newCIDFont = SkPDFMakeDict("Font");
354 newCIDFont->insertRef("FontDescriptor", doc->emit(*descriptor));
355 newCIDFont->insertName("BaseFont", metrics.fPostScriptName);
356
357 switch (type) {
358 case SkAdvancedTypefaceMetrics::kType1CID_Font:
359 newCIDFont->insertName("Subtype", "CIDFontType0");
360 break;
361 case SkAdvancedTypefaceMetrics::kTrueType_Font:
362 case SkAdvancedTypefaceMetrics::kCFF_Font:
363 newCIDFont->insertName("Subtype", "CIDFontType2");
364 newCIDFont->insertName("CIDToGIDMap", "Identity");
365 break;
366 default:
367 SkASSERT(false);
368 }
369 auto sysInfo = SkPDFMakeDict();
370 // These are actually ASCII strings.
371 sysInfo->insertByteString("Registry", "Adobe");
372 sysInfo->insertByteString("Ordering", "Identity");
373 sysInfo->insertInt("Supplement", 0);
374 newCIDFont->insertObject("CIDSystemInfo", std::move(sysInfo));
375
376 // Unfortunately, poppler enforces DW (default width) must be an integer.
377 int32_t defaultWidth = 0;
378 {
379 std::unique_ptr<SkPDFArray> widths = SkPDFMakeCIDGlyphWidthsArray(
380 *face, font.glyphUsage(), &defaultWidth);
381 if (widths && widths->size() > 0) {
382 newCIDFont->insertObject("W", std::move(widths));
383 }
384 newCIDFont->insertInt("DW", defaultWidth);
385 }
386
387 ////////////////////////////////////////////////////////////////////////////
388
389 SkPDFDict fontDict("Font");
390 fontDict.insertName("Subtype", "Type0");
391 fontDict.insertName("BaseFont", metrics.fPostScriptName);
392 fontDict.insertName("Encoding", "Identity-H");
393 auto descendantFonts = SkPDFMakeArray();
394 descendantFonts->appendRef(doc->emit(*newCIDFont));
395 fontDict.insertObject("DescendantFonts", std::move(descendantFonts));
396
397 const std::vector<SkUnichar>& glyphToUnicode =
398 SkPDFFont::GetUnicodeMap(font.typeface(), doc);
399 SkASSERT(SkToSizeT(font.typeface()->countGlyphs()) == glyphToUnicode.size());
400 std::unique_ptr<SkStreamAsset> toUnicode =
401 SkPDFMakeToUnicodeCmap(glyphToUnicode.data(),
402 &font.glyphUsage(),
403 font.multiByteGlyphs(),
404 font.firstGlyphID(),
405 font.lastGlyphID());
406 fontDict.insertRef("ToUnicode", SkPDFStreamOut(nullptr, std::move(toUnicode), doc));
407
408 doc->emit(fontDict, font.indirectReference());
409 }
410
411 ///////////////////////////////////////////////////////////////////////////////
412 // PDFType3Font
413 ///////////////////////////////////////////////////////////////////////////////
414
415 namespace {
416 // returns [0, first, first+1, ... last-1, last]
417 struct SingleByteGlyphIdIterator {
SingleByteGlyphIdIterator__anonc0ac3e7c0211::SingleByteGlyphIdIterator418 SingleByteGlyphIdIterator(SkGlyphID first, SkGlyphID last)
419 : fFirst(first), fLast(last) {
420 SkASSERT(fFirst > 0);
421 SkASSERT(fLast >= first);
422 }
423 struct Iter {
operator ++__anonc0ac3e7c0211::SingleByteGlyphIdIterator::Iter424 void operator++() {
425 fCurrent = (0 == fCurrent) ? fFirst : fCurrent + 1;
426 }
427 // This is an input_iterator
operator *__anonc0ac3e7c0211::SingleByteGlyphIdIterator::Iter428 SkGlyphID operator*() const { return (SkGlyphID)fCurrent; }
operator !=__anonc0ac3e7c0211::SingleByteGlyphIdIterator::Iter429 bool operator!=(const Iter& rhs) const {
430 return fCurrent != rhs.fCurrent;
431 }
Iter__anonc0ac3e7c0211::SingleByteGlyphIdIterator::Iter432 Iter(SkGlyphID f, int c) : fFirst(f), fCurrent(c) {}
433 private:
434 const SkGlyphID fFirst;
435 int fCurrent; // must be int to make fLast+1 to fit
436 };
begin__anonc0ac3e7c0211::SingleByteGlyphIdIterator437 Iter begin() const { return Iter(fFirst, 0); }
end__anonc0ac3e7c0211::SingleByteGlyphIdIterator438 Iter end() const { return Iter(fFirst, (int)fLast + 1); }
439 private:
440 const SkGlyphID fFirst;
441 const SkGlyphID fLast;
442 };
443 } // namespace
444
445 struct ImageAndOffset {
446 sk_sp<SkImage> fImage;
447 SkIPoint fOffset;
448 };
to_image(SkGlyphID gid,SkBulkGlyphMetricsAndImages * smallGlyphs)449 static ImageAndOffset to_image(SkGlyphID gid, SkBulkGlyphMetricsAndImages* smallGlyphs) {
450 const SkGlyph* glyph = smallGlyphs->glyph(SkPackedGlyphID{gid});
451 SkMask mask = glyph->mask();
452 if (!mask.fImage) {
453 return {nullptr, {0, 0}};
454 }
455 SkIRect bounds = mask.fBounds;
456 SkBitmap bm;
457 switch (mask.fFormat) {
458 case SkMask::kBW_Format:
459 bm.allocPixels(SkImageInfo::MakeA8(bounds.width(), bounds.height()));
460 for (int y = 0; y < bm.height(); ++y) {
461 for (int x8 = 0; x8 < bm.width(); x8 += 8) {
462 uint8_t v = *mask.getAddr1(x8 + bounds.x(), y + bounds.y());
463 int e = std::min(x8 + 8, bm.width());
464 for (int x = x8; x < e; ++x) {
465 *bm.getAddr8(x, y) = (v >> (x & 0x7)) & 0x1 ? 0xFF : 0x00;
466 }
467 }
468 }
469 bm.setImmutable();
470 return {bm.asImage(), {bounds.x(), bounds.y()}};
471 case SkMask::kA8_Format:
472 return {SkImages::RasterFromData(
473 SkImageInfo::MakeA8(bounds.width(), bounds.height()),
474 SkData::MakeWithCopy(mask.fImage, mask.computeTotalImageSize()),
475 mask.fRowBytes),
476 {bounds.x(), bounds.y()}};
477 case SkMask::kARGB32_Format:
478 return {SkImages::RasterFromData(
479 SkImageInfo::MakeN32Premul(bounds.width(), bounds.height()),
480 SkData::MakeWithCopy(mask.fImage, mask.computeTotalImageSize()),
481 mask.fRowBytes),
482 {bounds.x(), bounds.y()}};
483 case SkMask::k3D_Format:
484 case SkMask::kLCD16_Format:
485 default:
486 SkASSERT(false);
487 return {nullptr, {0, 0}};
488 }
489 }
490
type3_descriptor(SkPDFDocument * doc,const SkTypeface * typeface,SkScalar xHeight)491 static SkPDFIndirectReference type3_descriptor(SkPDFDocument* doc,
492 const SkTypeface* typeface,
493 SkScalar xHeight) {
494 if (SkPDFIndirectReference* ptr = doc->fType3FontDescriptors.find(typeface->uniqueID())) {
495 return *ptr;
496 }
497
498 SkPDFDict descriptor("FontDescriptor");
499 int32_t fontDescriptorFlags = kPdfSymbolic;
500
501 /** PDF32000_2008: FontFamily should be used for Type3 fonts in Tagged PDF documents. */
502 SkString familyName;
503 typeface->getFamilyName(&familyName);
504 if (!familyName.isEmpty()) {
505 descriptor.insertByteString("FontFamily", familyName);
506 }
507
508 /** PDF32000_2008: FontStretch should be used for Type3 fonts in Tagged PDF documents. */
509 static constexpr const char* stretchNames[9] = {
510 "UltraCondensed",
511 "ExtraCondensed",
512 "Condensed",
513 "SemiCondensed",
514 "Normal",
515 "SemiExpanded",
516 "Expanded",
517 "ExtraExpanded",
518 "UltraExpanded",
519 };
520 const char* stretchName = stretchNames[typeface->fontStyle().width() - 1];
521 descriptor.insertName("FontStretch", stretchName);
522
523 /** PDF32000_2008: FontWeight should be used for Type3 fonts in Tagged PDF documents. */
524 int weight = (typeface->fontStyle().weight() + 50) / 100;
525 descriptor.insertInt("FontWeight", SkTPin(weight, 1, 9) * 100);
526
527 if (const SkAdvancedTypefaceMetrics* metrics = SkPDFFont::GetMetrics(typeface, doc)) {
528 // Type3 FontDescriptor does not require all the same fields.
529 descriptor.insertName("FontName", metrics->fPostScriptName);
530 descriptor.insertInt("ItalicAngle", metrics->fItalicAngle);
531 fontDescriptorFlags |= (int32_t)metrics->fStyle;
532 // Adobe requests CapHeight, XHeight, and StemV be added
533 // to "greatly help our workflow downstream".
534 if (metrics->fCapHeight != 0) { descriptor.insertInt("CapHeight", metrics->fCapHeight); }
535 if (metrics->fStemV != 0) { descriptor.insertInt("StemV", metrics->fStemV); }
536 if (xHeight != 0) {
537 descriptor.insertScalar("XHeight", xHeight);
538 }
539 }
540 descriptor.insertInt("Flags", fontDescriptorFlags);
541 SkPDFIndirectReference ref = doc->emit(descriptor);
542 doc->fType3FontDescriptors.set(typeface->uniqueID(), ref);
543 return ref;
544 }
545
546 #ifdef SK_PDF_BITMAP_GLYPH_RASTER_SIZE
547 static constexpr float kBitmapFontSize = SK_PDF_BITMAP_GLYPH_RASTER_SIZE;
548 #else
549 static constexpr float kBitmapFontSize = 64;
550 #endif
551
make_small_strike(const SkTypeface & typeface)552 SkStrikeSpec make_small_strike(const SkTypeface& typeface) {
553 SkFont font(sk_ref_sp(&typeface), kBitmapFontSize);
554 font.setHinting(SkFontHinting::kNone);
555 font.setEdging(SkFont::Edging::kAlias);
556 return SkStrikeSpec::MakeMask(font,
557 SkPaint(),
558 SkSurfaceProps(),
559 SkScalerContextFlags::kFakeGammaAndBoostContrast,
560 SkMatrix::I());
561 }
562
emit_subset_type3(const SkPDFFont & pdfFont,SkPDFDocument * doc)563 static void emit_subset_type3(const SkPDFFont& pdfFont, SkPDFDocument* doc) {
564 SkTypeface* typeface = pdfFont.typeface();
565 SkGlyphID firstGlyphID = pdfFont.firstGlyphID();
566 SkGlyphID lastGlyphID = pdfFont.lastGlyphID();
567 const SkPDFGlyphUse& subset = pdfFont.glyphUsage();
568 SkASSERT(lastGlyphID >= firstGlyphID);
569 // Remove unused glyphs at the end of the range.
570 // Keep the lastGlyphID >= firstGlyphID invariant true.
571 while (lastGlyphID > firstGlyphID && !subset.has(lastGlyphID)) {
572 --lastGlyphID;
573 }
574 int unitsPerEm;
575 SkStrikeSpec strikeSpec = SkStrikeSpec::MakePDFVector(*typeface, &unitsPerEm);
576 auto strike = strikeSpec.findOrCreateStrike();
577 SkASSERT(strike);
578 SkScalar emSize = (SkScalar)unitsPerEm;
579 SkScalar xHeight = strike->getFontMetrics().fXHeight;
580 SkBulkGlyphMetricsAndPaths metricsAndPaths((sk_sp<SkStrike>(strike)));
581 SkBulkGlyphMetricsAndDrawables metricsAndDrawables(std::move(strike));
582
583 SkStrikeSpec strikeSpecSmall = kBitmapFontSize > 0 ? make_small_strike(*typeface)
584 : strikeSpec;
585
586 SkBulkGlyphMetricsAndImages smallGlyphs(strikeSpecSmall);
587 float bitmapScale = kBitmapFontSize > 0 ? emSize / kBitmapFontSize : 1.0f;
588
589 SkPDFDict font("Font");
590 font.insertName("Subtype", "Type3");
591 // Flip about the x-axis and scale by 1/emSize.
592 SkMatrix fontMatrix;
593 fontMatrix.setScale(SkScalarInvert(emSize), -SkScalarInvert(emSize));
594 font.insertObject("FontMatrix", SkPDFUtils::MatrixToArray(fontMatrix));
595
596 auto charProcs = SkPDFMakeDict();
597 auto encoding = SkPDFMakeDict("Encoding");
598
599 auto encDiffs = SkPDFMakeArray();
600 // length(firstGlyphID .. lastGlyphID) == lastGlyphID - firstGlyphID + 1
601 // plus 1 for glyph 0;
602 SkASSERT(firstGlyphID > 0);
603 SkASSERT(lastGlyphID >= firstGlyphID);
604 int glyphCount = lastGlyphID - firstGlyphID + 2;
605 // one other entry for the index of first glyph.
606 encDiffs->reserve(glyphCount + 1);
607 encDiffs->appendInt(0); // index of first glyph
608
609 auto widthArray = SkPDFMakeArray();
610 widthArray->reserve(glyphCount);
611
612 SkIRect bbox = SkIRect::MakeEmpty();
613
614 std::vector<std::pair<SkGlyphID, SkPDFIndirectReference>> imageGlyphs;
615 for (SkGlyphID gID : SingleByteGlyphIdIterator(firstGlyphID, lastGlyphID)) {
616 bool skipGlyph = gID != 0 && !subset.has(gID);
617 SkString characterName;
618 SkScalar advance = 0.0f;
619 SkIRect glyphBBox;
620 if (skipGlyph) {
621 characterName.set("g0");
622 } else {
623 characterName.printf("g%X", gID);
624 const SkGlyph* pathGlyph = metricsAndPaths.glyph(gID);
625 const SkGlyph* drawableGlyph = metricsAndDrawables.glyph(gID);
626 advance = pathGlyph->advanceX();
627 glyphBBox = pathGlyph->iRect();
628 bbox.join(glyphBBox);
629 const SkPath* path = pathGlyph->path();
630 SkDrawable* drawable = drawableGlyph->drawable();
631 SkDynamicMemoryWStream content;
632 if (drawable && !drawable->getBounds().isEmpty()) {
633 sk_sp<SkPDFDevice> glyphDevice = sk_make_sp<SkPDFDevice>(glyphBBox.size(), doc);
634 SkCanvas canvas(glyphDevice);
635 canvas.translate(-glyphBBox.fLeft, -glyphBBox.fTop);
636 canvas.drawDrawable(drawable);
637 SkPDFIndirectReference xobject = SkPDFMakeFormXObject(
638 doc, glyphDevice->content(),
639 SkPDFMakeArray(0, 0, glyphBBox.width(), glyphBBox.height()),
640 glyphDevice->makeResourceDict(),
641 SkMatrix::Translate(glyphBBox.fLeft, glyphBBox.fTop), nullptr);
642 imageGlyphs.emplace_back(gID, xobject);
643 SkPDFUtils::AppendScalar(drawableGlyph->advanceX(), &content);
644 content.writeText(" 0 d0\n1 0 0 1 0 0 cm\n/X");
645 content.write(characterName.c_str(), characterName.size());
646 content.writeText(" Do\n");
647 } else if (path && !path->isEmpty()) {
648 setGlyphWidthAndBoundingBox(pathGlyph->advanceX(), glyphBBox, &content);
649 SkPDFUtils::EmitPath(*path, SkPaint::kFill_Style, &content);
650 SkPDFUtils::PaintPath(SkPaint::kFill_Style, path->getFillType(), &content);
651 } else {
652 auto pimg = to_image(gID, &smallGlyphs);
653 if (!pimg.fImage) {
654 setGlyphWidthAndBoundingBox(pathGlyph->advanceX(), glyphBBox, &content);
655 } else {
656 using SkPDFUtils::AppendScalar;
657 imageGlyphs.emplace_back(gID, SkPDFSerializeImage(pimg.fImage.get(), doc));
658 AppendScalar(pathGlyph->advanceX(), &content);
659 content.writeText(" 0 d0\n");
660 AppendScalar(pimg.fImage->width() * bitmapScale, &content);
661 content.writeText(" 0 0 ");
662 AppendScalar(-pimg.fImage->height() * bitmapScale, &content);
663 content.writeText(" ");
664 AppendScalar(pimg.fOffset.x() * bitmapScale, &content);
665 content.writeText(" ");
666 AppendScalar((pimg.fImage->height() + pimg.fOffset.y()) * bitmapScale,
667 &content);
668 content.writeText(" cm\n/X");
669 content.write(characterName.c_str(), characterName.size());
670 content.writeText(" Do\n");
671 }
672 }
673 charProcs->insertRef(characterName, SkPDFStreamOut(nullptr,
674 content.detachAsStream(), doc));
675 }
676 encDiffs->appendName(std::move(characterName));
677 widthArray->appendScalar(advance);
678 }
679
680 if (!imageGlyphs.empty()) {
681 auto d0 = SkPDFMakeDict();
682 for (const auto& pair : imageGlyphs) {
683 d0->insertRef(SkStringPrintf("Xg%X", pair.first), pair.second);
684 }
685 auto d1 = SkPDFMakeDict();
686 d1->insertObject("XObject", std::move(d0));
687 font.insertObject("Resources", std::move(d1));
688 }
689
690 encoding->insertObject("Differences", std::move(encDiffs));
691 font.insertInt("FirstChar", 0);
692 font.insertInt("LastChar", lastGlyphID - firstGlyphID + 1);
693 /* FontBBox: "A rectangle expressed in the glyph coordinate
694 system, specifying the font bounding box. This is the smallest
695 rectangle enclosing the shape that would result if all of the
696 glyphs of the font were placed with their origins coincident and
697 then filled." */
698 font.insertObject("FontBBox", SkPDFMakeArray(bbox.left(),
699 bbox.bottom(),
700 bbox.right(),
701 bbox.top()));
702
703 font.insertName("CIDToGIDMap", "Identity");
704
705 const std::vector<SkUnichar>& glyphToUnicode = SkPDFFont::GetUnicodeMap(typeface, doc);
706 SkASSERT(glyphToUnicode.size() == SkToSizeT(typeface->countGlyphs()));
707 auto toUnicodeCmap = SkPDFMakeToUnicodeCmap(glyphToUnicode.data(),
708 &subset,
709 false,
710 firstGlyphID,
711 lastGlyphID);
712 font.insertRef("ToUnicode", SkPDFStreamOut(nullptr, std::move(toUnicodeCmap), doc));
713 font.insertRef("FontDescriptor", type3_descriptor(doc, typeface, xHeight));
714 font.insertObject("Widths", std::move(widthArray));
715 font.insertObject("Encoding", std::move(encoding));
716 font.insertObject("CharProcs", std::move(charProcs));
717
718 doc->emit(font, pdfFont.indirectReference());
719 }
720
emitSubset(SkPDFDocument * doc) const721 void SkPDFFont::emitSubset(SkPDFDocument* doc) const {
722 switch (fFontType) {
723 case SkAdvancedTypefaceMetrics::kType1CID_Font:
724 case SkAdvancedTypefaceMetrics::kTrueType_Font:
725 case SkAdvancedTypefaceMetrics::kCFF_Font:
726 return emit_subset_type0(*this, doc);
727 #ifndef SK_PDF_DO_NOT_SUPPORT_TYPE_1_FONTS
728 case SkAdvancedTypefaceMetrics::kType1_Font:
729 return SkPDFEmitType1Font(*this, doc);
730 #endif
731 default:
732 return emit_subset_type3(*this, doc);
733 }
734 }
735
736 ////////////////////////////////////////////////////////////////////////////////
737
CanEmbedTypeface(SkTypeface * typeface,SkPDFDocument * doc)738 bool SkPDFFont::CanEmbedTypeface(SkTypeface* typeface, SkPDFDocument* doc) {
739 const SkAdvancedTypefaceMetrics* metrics = SkPDFFont::GetMetrics(typeface, doc);
740 return metrics && can_embed(*metrics);
741 }
742
743