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