Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
SkPDFFont.cpp
Go to the documentation of this file.
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
10#include "include/core/SkFont.h"
17#include "include/core/SkPath.h"
19#include "include/core/SkRect.h"
29#include "src/base/SkUTF.h"
30#include "src/core/SkGlyph.h"
32#include "src/core/SkMask.h"
34#include "src/core/SkStrike.h"
36#include "src/core/SkTHash.h"
37#include "src/pdf/SkPDFBitmap.h"
38#include "src/pdf/SkPDFDevice.h"
40#include "src/pdf/SkPDFFont.h"
46#include "src/pdf/SkPDFUtils.h"
47
48#include <limits.h>
49#include <initializer_list>
50#include <memory>
51#include <utility>
52
56
57namespace {
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)
61static const int32_t kPdfSymbolic = 4;
62static const SkFontTableTag kCOLRTableTag = SkSetFourByteTag('C', 'O', 'L', 'R');
63
64// scale from em-units to base-1000, returning as a SkScalar
65inline SkScalar from_font_units(SkScalar scaled, uint16_t emSize) {
66 return emSize == 1000 ? scaled : scaled * 1000 / emSize;
67}
68
69inline SkScalar scaleFromFontUnits(int16_t val, uint16_t emSize) {
70 return from_font_units(SkIntToScalar(val), emSize);
71}
72
73void setGlyphWidthAndBoundingBox(SkScalar width, SkIRect box,
75 // Specify width and bounding box for the glyph.
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
98SkPDFFont::~SkPDFFont() = default;
99
101
103
107
109 SkPDFDocument* canon) {
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
160const std::vector<SkUnichar>& SkPDFFont::GetUnicodeMap(const SkTypeface* typeface,
161 SkPDFDocument* canon) {
163 SkASSERT(canon);
165 if (std::vector<SkUnichar>* ptr = canon->fToUnicodeMap.find(id)) {
166 return *ptr;
167 }
168 std::vector<SkUnichar> buffer(typeface->countGlyphs());
170 return *canon->fToUnicodeMap.set(id, std::move(buffer));
171}
172
174 const SkAdvancedTypefaceMetrics& metrics) {
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
183 // force Type3 fallback.
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.
190 }
191 return metrics.fType;
192}
193
195 return gid != 0 ? gid - (gid - 1) % 255 : 1;
196}
197
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;
208 if (!(glyph->isEmpty() || glyph->path())) {
210 }
211 bool multibyte = SkPDFFont::IsMultiByte(type);
212 SkGlyphID subsetCode =
214 uint64_t typefaceID = (static_cast<uint64_t>(face->uniqueID()) << 16) | subsetCode;
215
216 if (SkPDFFont* found = doc->fFontMap.find(typefaceID)) {
217 SkASSERT(multibyte == found->multiByteGlyphs());
218 return found;
219 }
220
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
241SkPDFFont::SkPDFFont(sk_sp<SkTypeface> typeface,
242 SkGlyphID firstGlyphID,
243 SkGlyphID lastGlyphID,
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
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.
286static 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()) {
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
299static 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));
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) {
325 if (!SkToBool(metrics.fFlags &
327 SkASSERT(font.firstGlyphID() == 1);
328 sk_sp<SkData> subsetFontData = SkPDFSubsetFont(
329 stream_to_data(std::move(fontAsset)), font.glyphUsage(),
330 doc->metadata().fSubsetter,
331 ttcIndex);
332 if (subsetFontData) {
333 std::unique_ptr<SkPDFDict> tmp = SkPDFMakeDict();
334 tmp->insertInt("Length1", SkToInt(subsetFontData->size()));
335 descriptor->insertRef(
336 "FontFile2",
337 SkPDFStreamOut(std::move(tmp),
338 SkMemoryStream::Make(std::move(subsetFontData)),
340 break;
341 }
342 // If subsetting fails, fall back to original font data.
343 fontAsset = face->openStream(&ttcIndex);
344 SkASSERT(fontAsset);
345 SkASSERT(fontAsset->getLength() == fontSize);
346 if (!fontAsset || fontAsset->getLength() == 0) { break; }
347 }
348 std::unique_ptr<SkPDFDict> tmp = SkPDFMakeDict();
349 tmp->insertInt("Length1", fontSize);
350 descriptor->insertRef("FontFile2",
351 SkPDFStreamOut(std::move(tmp), std::move(fontAsset),
353 break;
354 }
356 std::unique_ptr<SkPDFDict> tmp = SkPDFMakeDict();
357 tmp->insertName("Subtype", "CIDFontType0C");
358 descriptor->insertRef("FontFile3",
359 SkPDFStreamOut(std::move(tmp), std::move(fontAsset),
361 break;
362 }
363 default:
364 SkASSERT(false);
365 }
366 }
367
368 auto newCIDFont = SkPDFMakeDict("Font");
369 newCIDFont->insertRef("FontDescriptor", doc->emit(*descriptor));
370 newCIDFont->insertName("BaseFont", metrics.fPostScriptName);
371
372 switch (type) {
374 newCIDFont->insertName("Subtype", "CIDFontType0");
375 break;
378 newCIDFont->insertName("Subtype", "CIDFontType2");
379 newCIDFont->insertName("CIDToGIDMap", "Identity");
380 break;
381 default:
382 SkASSERT(false);
383 }
384 auto sysInfo = SkPDFMakeDict();
385 // These are actually ASCII strings.
386 sysInfo->insertByteString("Registry", "Adobe");
387 sysInfo->insertByteString("Ordering", "Identity");
388 sysInfo->insertInt("Supplement", 0);
389 newCIDFont->insertObject("CIDSystemInfo", std::move(sysInfo));
390
391 // Unfortunately, poppler enforces DW (default width) must be an integer.
392 int32_t defaultWidth = 0;
393 {
394 std::unique_ptr<SkPDFArray> widths = SkPDFMakeCIDGlyphWidthsArray(
395 *face, font.glyphUsage(), &defaultWidth);
396 if (widths && widths->size() > 0) {
397 newCIDFont->insertObject("W", std::move(widths));
398 }
399 newCIDFont->insertInt("DW", defaultWidth);
400 }
401
402 ////////////////////////////////////////////////////////////////////////////
403
404 SkPDFDict fontDict("Font");
405 fontDict.insertName("Subtype", "Type0");
406 fontDict.insertName("BaseFont", metrics.fPostScriptName);
407 fontDict.insertName("Encoding", "Identity-H");
408 auto descendantFonts = SkPDFMakeArray();
409 descendantFonts->appendRef(doc->emit(*newCIDFont));
410 fontDict.insertObject("DescendantFonts", std::move(descendantFonts));
411
412 const std::vector<SkUnichar>& glyphToUnicode =
413 SkPDFFont::GetUnicodeMap(font.typeface(), doc);
414 SkASSERT(SkToSizeT(font.typeface()->countGlyphs()) == glyphToUnicode.size());
415 std::unique_ptr<SkStreamAsset> toUnicode =
416 SkPDFMakeToUnicodeCmap(glyphToUnicode.data(),
417 &font.glyphUsage(),
418 font.multiByteGlyphs(),
419 font.firstGlyphID(),
420 font.lastGlyphID());
421 fontDict.insertRef("ToUnicode", SkPDFStreamOut(nullptr, std::move(toUnicode), doc));
422
423 doc->emit(fontDict, font.indirectReference());
424}
425
426///////////////////////////////////////////////////////////////////////////////
427// PDFType3Font
428///////////////////////////////////////////////////////////////////////////////
429
430namespace {
431// returns [0, first, first+1, ... last-1, last]
432struct SingleByteGlyphIdIterator {
433 SingleByteGlyphIdIterator(SkGlyphID first, SkGlyphID last)
434 : fFirst(first), fLast(last) {
435 SkASSERT(fFirst > 0);
436 SkASSERT(fLast >= first);
437 }
438 struct Iter {
439 void operator++() {
440 fCurrent = (0 == fCurrent) ? fFirst : fCurrent + 1;
441 }
442 // This is an input_iterator
443 SkGlyphID operator*() const { return (SkGlyphID)fCurrent; }
444 bool operator!=(const Iter& rhs) const {
445 return fCurrent != rhs.fCurrent;
446 }
447 Iter(SkGlyphID f, int c) : fFirst(f), fCurrent(c) {}
448 private:
449 const SkGlyphID fFirst;
450 int fCurrent; // must be int to make fLast+1 to fit
451 };
452 Iter begin() const { return Iter(fFirst, 0); }
453 Iter end() const { return Iter(fFirst, (int)fLast + 1); }
454private:
455 const SkGlyphID fFirst;
456 const SkGlyphID fLast;
457};
458} // namespace
459
465 const SkGlyph* glyph = smallGlyphs->glyph(SkPackedGlyphID{gid});
466 SkMask mask = glyph->mask();
467 if (!mask.fImage) {
468 return {nullptr, {0, 0}};
469 }
470 SkIRect bounds = mask.fBounds;
471 SkBitmap bm;
472 switch (mask.fFormat) {
474 bm.allocPixels(SkImageInfo::MakeA8(bounds.width(), bounds.height()));
475 for (int y = 0; y < bm.height(); ++y) {
476 for (int x8 = 0; x8 < bm.width(); x8 += 8) {
477 uint8_t v = *mask.getAddr1(x8 + bounds.x(), y + bounds.y());
478 int e = std::min(x8 + 8, bm.width());
479 for (int x = x8; x < e; ++x) {
480 *bm.getAddr8(x, y) = (v >> (x & 0x7)) & 0x1 ? 0xFF : 0x00;
481 }
482 }
483 }
484 bm.setImmutable();
485 return {bm.asImage(), {bounds.x(), bounds.y()}};
488 SkImageInfo::MakeA8(bounds.width(), bounds.height()),
490 mask.fRowBytes),
491 {bounds.x(), bounds.y()}};
494 SkImageInfo::MakeN32Premul(bounds.width(), bounds.height()),
496 mask.fRowBytes),
497 {bounds.x(), bounds.y()}};
500 default:
501 SkASSERT(false);
502 return {nullptr, {0, 0}};
503 }
504}
505
507 const SkTypeface* typeface,
508 SkScalar xHeight) {
509 if (SkPDFIndirectReference* ptr = doc->fType3FontDescriptors.find(typeface->uniqueID())) {
510 return *ptr;
511 }
512
513 SkPDFDict descriptor("FontDescriptor");
514 int32_t fontDescriptorFlags = kPdfSymbolic;
515
516 /** PDF32000_2008: FontFamily should be used for Type3 fonts in Tagged PDF documents. */
517 SkString familyName;
518 typeface->getFamilyName(&familyName);
519 if (!familyName.isEmpty()) {
520 descriptor.insertByteString("FontFamily", familyName);
521 }
522
523 /** PDF32000_2008: FontStretch should be used for Type3 fonts in Tagged PDF documents. */
524 static constexpr const char* stretchNames[9] = {
525 "UltraCondensed",
526 "ExtraCondensed",
527 "Condensed",
528 "SemiCondensed",
529 "Normal",
530 "SemiExpanded",
531 "Expanded",
532 "ExtraExpanded",
533 "UltraExpanded",
534 };
535 const char* stretchName = stretchNames[typeface->fontStyle().width() - 1];
536 descriptor.insertName("FontStretch", stretchName);
537
538 /** PDF32000_2008: FontWeight should be used for Type3 fonts in Tagged PDF documents. */
539 int weight = (typeface->fontStyle().weight() + 50) / 100;
540 descriptor.insertInt("FontWeight", SkTPin(weight, 1, 9) * 100);
541
542 if (const SkAdvancedTypefaceMetrics* metrics = SkPDFFont::GetMetrics(typeface, doc)) {
543 // Type3 FontDescriptor does not require all the same fields.
544 descriptor.insertName("FontName", metrics->fPostScriptName);
545 descriptor.insertInt("ItalicAngle", metrics->fItalicAngle);
546 fontDescriptorFlags |= (int32_t)metrics->fStyle;
547 // Adobe requests CapHeight, XHeight, and StemV be added
548 // to "greatly help our workflow downstream".
549 if (metrics->fCapHeight != 0) { descriptor.insertInt("CapHeight", metrics->fCapHeight); }
550 if (metrics->fStemV != 0) { descriptor.insertInt("StemV", metrics->fStemV); }
551 if (xHeight != 0) {
552 descriptor.insertScalar("XHeight", xHeight);
553 }
554 }
555 descriptor.insertInt("Flags", fontDescriptorFlags);
556 SkPDFIndirectReference ref = doc->emit(descriptor);
557 doc->fType3FontDescriptors.set(typeface->uniqueID(), ref);
558 return ref;
559}
560
561#ifdef SK_PDF_BITMAP_GLYPH_RASTER_SIZE
562static constexpr float kBitmapFontSize = SK_PDF_BITMAP_GLYPH_RASTER_SIZE;
563#else
564static constexpr float kBitmapFontSize = 64;
565#endif
566
568 SkFont font(sk_ref_sp(&typeface), kBitmapFontSize);
569 font.setHinting(SkFontHinting::kNone);
570 font.setEdging(SkFont::Edging::kAlias);
571 return SkStrikeSpec::MakeMask(font,
572 SkPaint(),
575 SkMatrix::I());
576}
577
578static void emit_subset_type3(const SkPDFFont& pdfFont, SkPDFDocument* doc) {
579 SkTypeface* typeface = pdfFont.typeface();
580 SkGlyphID firstGlyphID = pdfFont.firstGlyphID();
581 SkGlyphID lastGlyphID = pdfFont.lastGlyphID();
582 const SkPDFGlyphUse& subset = pdfFont.glyphUsage();
583 SkASSERT(lastGlyphID >= firstGlyphID);
584 // Remove unused glyphs at the end of the range.
585 // Keep the lastGlyphID >= firstGlyphID invariant true.
586 while (lastGlyphID > firstGlyphID && !subset.has(lastGlyphID)) {
587 --lastGlyphID;
588 }
589 int unitsPerEm;
590 SkStrikeSpec strikeSpec = SkStrikeSpec::MakePDFVector(*typeface, &unitsPerEm);
591 auto strike = strikeSpec.findOrCreateStrike();
592 SkASSERT(strike);
593 SkScalar emSize = (SkScalar)unitsPerEm;
594 SkScalar xHeight = strike->getFontMetrics().fXHeight;
595 SkBulkGlyphMetricsAndPaths metricsAndPaths((sk_sp<SkStrike>(strike)));
596 SkBulkGlyphMetricsAndDrawables metricsAndDrawables(std::move(strike));
597
598 SkStrikeSpec strikeSpecSmall = kBitmapFontSize > 0 ? make_small_strike(*typeface)
599 : strikeSpec;
600
601 SkBulkGlyphMetricsAndImages smallGlyphs(strikeSpecSmall);
602 float bitmapScale = kBitmapFontSize > 0 ? emSize / kBitmapFontSize : 1.0f;
603
604 SkPDFDict font("Font");
605 font.insertName("Subtype", "Type3");
606 // Flip about the x-axis and scale by 1/emSize.
607 SkMatrix fontMatrix;
608 fontMatrix.setScale(SkScalarInvert(emSize), -SkScalarInvert(emSize));
609 font.insertObject("FontMatrix", SkPDFUtils::MatrixToArray(fontMatrix));
610
611 auto charProcs = SkPDFMakeDict();
612 auto encoding = SkPDFMakeDict("Encoding");
613
614 auto encDiffs = SkPDFMakeArray();
615 // length(firstGlyphID .. lastGlyphID) == lastGlyphID - firstGlyphID + 1
616 // plus 1 for glyph 0;
617 SkASSERT(firstGlyphID > 0);
618 SkASSERT(lastGlyphID >= firstGlyphID);
619 int glyphCount = lastGlyphID - firstGlyphID + 2;
620 // one other entry for the index of first glyph.
621 encDiffs->reserve(glyphCount + 1);
622 encDiffs->appendInt(0); // index of first glyph
623
624 auto widthArray = SkPDFMakeArray();
625 widthArray->reserve(glyphCount);
626
628
629 std::vector<std::pair<SkGlyphID, SkPDFIndirectReference>> imageGlyphs;
630 for (SkGlyphID gID : SingleByteGlyphIdIterator(firstGlyphID, lastGlyphID)) {
631 bool skipGlyph = gID != 0 && !subset.has(gID);
632 SkString characterName;
633 SkScalar advance = 0.0f;
634 SkIRect glyphBBox;
635 if (skipGlyph) {
636 characterName.set("g0");
637 } else {
638 characterName.printf("g%X", gID);
639 const SkGlyph* pathGlyph = metricsAndPaths.glyph(gID);
640 const SkGlyph* drawableGlyph = metricsAndDrawables.glyph(gID);
641 advance = pathGlyph->advanceX();
642 glyphBBox = pathGlyph->iRect();
643 bbox.join(glyphBBox);
644 const SkPath* path = pathGlyph->path();
645 SkDrawable* drawable = drawableGlyph->drawable();
647 if (drawable && !drawable->getBounds().isEmpty()) {
648 sk_sp<SkPDFDevice> glyphDevice = sk_make_sp<SkPDFDevice>(glyphBBox.size(), doc);
649 SkCanvas canvas(glyphDevice);
650 canvas.translate(-glyphBBox.fLeft, -glyphBBox.fTop);
651 canvas.drawDrawable(drawable);
653 doc, glyphDevice->content(),
654 SkPDFMakeArray(0, 0, glyphBBox.width(), glyphBBox.height()),
655 glyphDevice->makeResourceDict(),
656 SkMatrix::Translate(glyphBBox.fLeft, glyphBBox.fTop), nullptr);
657 imageGlyphs.emplace_back(gID, xobject);
658 SkPDFUtils::AppendScalar(drawableGlyph->advanceX(), &content);
659 content.writeText(" 0 d0\n1 0 0 1 0 0 cm\n/X");
660 content.write(characterName.c_str(), characterName.size());
661 content.writeText(" Do\n");
662 } else if (path && !path->isEmpty()) {
663 setGlyphWidthAndBoundingBox(pathGlyph->advanceX(), glyphBBox, &content);
665 SkPDFUtils::PaintPath(SkPaint::kFill_Style, path->getFillType(), &content);
666 } else {
667 auto pimg = to_image(gID, &smallGlyphs);
668 if (!pimg.fImage) {
669 setGlyphWidthAndBoundingBox(pathGlyph->advanceX(), glyphBBox, &content);
670 } else {
672 imageGlyphs.emplace_back(gID, SkPDFSerializeImage(pimg.fImage.get(), doc));
673 AppendScalar(pathGlyph->advanceX(), &content);
674 content.writeText(" 0 d0\n");
675 AppendScalar(pimg.fImage->width() * bitmapScale, &content);
676 content.writeText(" 0 0 ");
677 AppendScalar(-pimg.fImage->height() * bitmapScale, &content);
678 content.writeText(" ");
679 AppendScalar(pimg.fOffset.x() * bitmapScale, &content);
680 content.writeText(" ");
681 AppendScalar((pimg.fImage->height() + pimg.fOffset.y()) * bitmapScale,
682 &content);
683 content.writeText(" cm\n/X");
684 content.write(characterName.c_str(), characterName.size());
685 content.writeText(" Do\n");
686 }
687 }
688 charProcs->insertRef(characterName, SkPDFStreamOut(nullptr,
689 content.detachAsStream(), doc));
690 }
691 encDiffs->appendName(std::move(characterName));
692 widthArray->appendScalar(advance);
693 }
694
695 if (!imageGlyphs.empty()) {
696 auto d0 = SkPDFMakeDict();
697 for (const auto& pair : imageGlyphs) {
698 d0->insertRef(SkStringPrintf("Xg%X", pair.first), pair.second);
699 }
700 auto d1 = SkPDFMakeDict();
701 d1->insertObject("XObject", std::move(d0));
702 font.insertObject("Resources", std::move(d1));
703 }
704
705 encoding->insertObject("Differences", std::move(encDiffs));
706 font.insertInt("FirstChar", 0);
707 font.insertInt("LastChar", lastGlyphID - firstGlyphID + 1);
708 /* FontBBox: "A rectangle expressed in the glyph coordinate
709 system, specifying the font bounding box. This is the smallest
710 rectangle enclosing the shape that would result if all of the
711 glyphs of the font were placed with their origins coincident and
712 then filled." */
713 font.insertObject("FontBBox", SkPDFMakeArray(bbox.left(),
714 bbox.bottom(),
715 bbox.right(),
716 bbox.top()));
717
718 font.insertName("CIDToGIDMap", "Identity");
719
720 const std::vector<SkUnichar>& glyphToUnicode = SkPDFFont::GetUnicodeMap(typeface, doc);
721 SkASSERT(glyphToUnicode.size() == SkToSizeT(typeface->countGlyphs()));
722 auto toUnicodeCmap = SkPDFMakeToUnicodeCmap(glyphToUnicode.data(),
723 &subset,
724 false,
725 firstGlyphID,
726 lastGlyphID);
727 font.insertRef("ToUnicode", SkPDFStreamOut(nullptr, std::move(toUnicodeCmap), doc));
728 font.insertRef("FontDescriptor", type3_descriptor(doc, typeface, xHeight));
729 font.insertObject("Widths", std::move(widthArray));
730 font.insertObject("Encoding", std::move(encoding));
731 font.insertObject("CharProcs", std::move(charProcs));
732
733 doc->emit(font, pdfFont.indirectReference());
734}
735
737 switch (fFontType) {
741 return emit_subset_type0(*this, doc);
742#ifndef SK_PDF_DO_NOT_SUPPORT_TYPE_1_FONTS
744 return SkPDFEmitType1Font(*this, doc);
745#endif
746 default:
747 return emit_subset_type3(*this, doc);
748 }
749}
750
751////////////////////////////////////////////////////////////////////////////////
752
755 return metrics && can_embed(*metrics);
756}
757
int count
#define SkASSERT(cond)
Definition SkAssert.h:116
void SK_SPI SkDebugf(const char format[],...) SK_PRINTF_LIKE(1
@ kNone
glyph outlines unchanged
SkPDFIndirectReference SkPDFSerializeImage(const SkImage *img, SkPDFDocument *doc, int encodingQuality)
static SkSize operator*(SkISize u, SkScalar s)
SkStrikeSpec make_small_strike(const SkTypeface &typeface)
static SkPDFIndirectReference type3_descriptor(SkPDFDocument *doc, const SkTypeface *typeface, SkScalar xHeight)
static ImageAndOffset to_image(SkGlyphID gid, SkBulkGlyphMetricsAndImages *smallGlyphs)
static void emit_subset_type3(const SkPDFFont &pdfFont, SkPDFDocument *doc)
static void emit_subset_type0(const SkPDFFont &font, SkPDFDocument *doc)
static constexpr float kBitmapFontSize
static SkGlyphID first_nonzero_glyph_for_single_byte_encoding(SkGlyphID gid)
static bool can_embed(const SkAdvancedTypefaceMetrics &metrics)
static sk_sp< SkData > stream_to_data(std::unique_ptr< SkStreamAsset > stream)
SkPDFIndirectReference SkPDFMakeFormXObject(SkPDFDocument *doc, std::unique_ptr< SkStreamAsset > content, std::unique_ptr< SkPDFArray > mediaBox, std::unique_ptr< SkPDFDict > resourceDict, const SkMatrix &inverseTransform, const char *colorSpace)
std::unique_ptr< SkPDFArray > SkPDFMakeCIDGlyphWidthsArray(const SkTypeface &typeface, const SkPDFGlyphUse &subset, int32_t *defaultAdvance)
std::unique_ptr< SkStreamAsset > SkPDFMakeToUnicodeCmap(const SkUnichar *glyphToUnicode, const SkPDFGlyphUse *subset, bool multiByteGlyphs, SkGlyphID firstGlyphID, SkGlyphID lastGlyphID)
sk_sp< SkData > SkPDFSubsetFont(sk_sp< SkData >, const SkPDFGlyphUse &, SkPDF::Metadata::Subsetter, int)
void SkPDFEmitType1Font(const SkPDFFont &pdfFont, SkPDFDocument *doc)
static SkScalar from_font_units(SkScalar scaled, uint16_t emSize)
SkPDFIndirectReference SkPDFStreamOut(std::unique_ptr< SkPDFDict > dict, std::unique_ptr< SkStreamAsset > content, SkPDFDocument *doc, SkPDFSteamCompressionEnabled compress)
static std::unique_ptr< SkPDFDict > SkPDFMakeDict(const char *type=nullptr)
Definition SkPDFTypes.h:195
static std::unique_ptr< SkPDFArray > SkPDFMakeArray(Args... args)
Definition SkPDFTypes.h:135
bool operator!=(const sk_sp< T > &a, const sk_sp< U > &b)
Definition SkRefCnt.h:355
sk_sp< T > sk_ref_sp(T *obj)
Definition SkRefCnt.h:381
#define SkScalarInvert(x)
Definition SkScalar.h:73
#define SkScalarRoundToInt(x)
Definition SkScalar.h:37
#define SkIntToScalar(x)
Definition SkScalar.h:57
SK_API SkString static SkString SkStringPrintf()
Definition SkString.h:287
static constexpr const T & SkTPin(const T &x, const T &lo, const T &hi)
Definition SkTPin.h:19
constexpr size_t SkToSizeT(S x)
Definition SkTo.h:31
constexpr uint16_t SkToU16(S x)
Definition SkTo.h:24
constexpr int SkToInt(S x)
Definition SkTo.h:29
static constexpr bool SkToBool(const T &x)
Definition SkTo.h:35
constexpr int16_t SkToS16(S x)
Definition SkTo.h:23
uint32_t SkFontTableTag
Definition SkTypeface.h:41
uint32_t SkTypefaceID
Definition SkTypeface.h:38
uint16_t SkGlyphID
Definition SkTypes.h:179
static constexpr SkFourByteTag SkSetFourByteTag(char a, char b, char c, char d)
Definition SkTypes.h:167
const SkScalar widths[]
void allocPixels(const SkImageInfo &info, size_t rowBytes)
Definition SkBitmap.cpp:258
sk_sp< SkImage > asImage() const
Definition SkBitmap.cpp:645
void setImmutable()
Definition SkBitmap.cpp:400
uint8_t * getAddr8(int x, int y) const
Definition SkBitmap.h:1270
int width() const
Definition SkBitmap.h:149
int height() const
Definition SkBitmap.h:158
const SkGlyph * glyph(SkGlyphID glyphID)
const SkGlyph * glyph(SkPackedGlyphID packedID)
const SkGlyph * glyph(SkGlyphID glyphID)
void translate(SkScalar dx, SkScalar dy)
void drawDrawable(SkDrawable *drawable, const SkMatrix *matrix=nullptr)
void(* ReleaseProc)(const void *ptr, void *context)
Definition SkData.h:78
static sk_sp< SkData > MakeWithProc(const void *ptr, size_t length, ReleaseProc proc, void *ctx)
Definition SkData.cpp:128
static sk_sp< SkData > MakeWithCopy(const void *data, size_t length)
Definition SkData.cpp:111
static sk_sp< SkData > MakeFromStream(SkStream *, size_t size)
Definition SkData.cpp:208
SkRect getBounds()
int width() const
Definition SkFontStyle.h:63
int weight() const
Definition SkFontStyle.h:62
@ kAlias
no transparent pixels on glyph edges
bool isEmpty() const
Definition SkGlyph.h:514
SkGlyphID getGlyphID() const
Definition SkGlyph.h:429
SkMask mask() const
Definition SkGlyph.cpp:125
const SkPath * path() const
Definition SkGlyph.cpp:284
SkScalar advanceX() const
Definition SkGlyph.h:426
SkIRect iRect() const
Definition SkGlyph.h:505
SkDrawable * drawable() const
Definition SkGlyph.cpp:327
static SkMatrix Translate(SkScalar dx, SkScalar dy)
Definition SkMatrix.h:91
SkMatrix & setScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py)
Definition SkMatrix.cpp:296
static const SkMatrix & I()
static std::unique_ptr< SkMemoryStream > Make(sk_sp< SkData > data)
Definition SkStream.cpp:314
void insertName(const char key[], const char nameValue[])
void insertObject(const char key[], std::unique_ptr< SkPDFObject > &&)
void insertInt(const char key[], int32_t value)
void insertRef(const char key[], SkPDFIndirectReference)
void insertScalar(const char key[], SkScalar value)
void insertByteString(const char key[], const char value[])
SkPDFIndirectReference emit(const SkPDFObject &, SkPDFIndirectReference)
const SkPDF::Metadata & metadata() const
skia_private::THashMap< uint64_t, SkPDFFont > fFontMap
skia_private::THashMap< uint32_t, std::vector< SkUnichar > > fToUnicodeMap
SkString nextFontSubsetTag()
skia_private::THashMap< uint32_t, SkPDFIndirectReference > fType3FontDescriptors
SkPDFIndirectReference reserveRef()
skia_private::THashMap< uint32_t, std::unique_ptr< SkAdvancedTypefaceMetrics > > fTypefaceMetrics
void noteGlyphUsage(SkGlyphID glyph)
Definition SkPDFFont.h:76
static const SkAdvancedTypefaceMetrics * GetMetrics(const SkTypeface *typeface, SkPDFDocument *canon)
static void PopulateCommonFontDescriptor(SkPDFDict *descriptor, const SkAdvancedTypefaceMetrics &, uint16_t emSize, int16_t defaultWidth)
static SkPDFFont * GetFontResource(SkPDFDocument *doc, const SkGlyph *glyphs, SkTypeface *typeface)
SkPDFIndirectReference indirectReference() const
Definition SkPDFFont.h:81
static SkAdvancedTypefaceMetrics::FontType FontType(const SkTypeface &, const SkAdvancedTypefaceMetrics &)
static bool IsMultiByte(SkAdvancedTypefaceMetrics::FontType type)
Definition SkPDFFont.h:50
static const std::vector< SkUnichar > & GetUnicodeMap(const SkTypeface *typeface, SkPDFDocument *canon)
SkPDFFont & operator=(SkPDFFont &&)
SkGlyphID lastGlyphID() const
Definition SkPDFFont.h:119
SkGlyphID firstGlyphID() const
Definition SkPDFFont.h:118
SkPDFFont(SkPDFFont &&)
void emitSubset(SkPDFDocument *) const
const SkPDFGlyphUse & glyphUsage() const
Definition SkPDFFont.h:120
static void GetType1GlyphNames(const SkTypeface &, SkString *)
Definition SkPDFFont.cpp:53
SkTypeface * typeface() const
Definition SkPDFFont.h:39
static bool CanEmbedTypeface(SkTypeface *, SkPDFDocument *)
bool has(SkGlyphID gid) const
@ kFill_Style
set to fill geometry
Definition SkPaint.h:193
static SkStrikeSpec MakeMask(const SkFont &font, const SkPaint &paint, const SkSurfaceProps &surfaceProps, SkScalerContextFlags scalerContextFlags, const SkMatrix &deviceMatrix)
sk_sp< SkStrike > findOrCreateStrike() const
static SkStrikeSpec MakePDFVector(const SkTypeface &typeface, int *size)
void printf(const char format[],...) SK_PRINTF_LIKE(2
Definition SkString.cpp:534
size_t size() const
Definition SkString.h:131
void set(const SkString &src)
Definition SkString.h:186
bool isEmpty() const
Definition SkString.h:130
const char * c_str() const
Definition SkString.h:133
int countGlyphs() const
virtual void getPostScriptGlyphNames(SkString *) const =0
SkTypefaceID uniqueID() const
Definition SkTypeface.h:101
virtual void getGlyphToUnicodeMap(SkUnichar *dstArray) const =0
void getFamilyName(SkString *name) const
SkFontStyle fontStyle() const
Definition SkTypeface.h:55
size_t getTableSize(SkFontTableTag) const
std::unique_ptr< SkStreamAsset > openStream(int *ttcIndex) const
V * find(const K &key) const
Definition SkTHash.h:479
V * set(K key, V val)
Definition SkTHash.h:472
static const char * begin(const StringSlice &s)
Definition editor.cpp:252
float SkScalar
Definition extension.cpp:12
glong glong end
static const uint8_t buffer[]
union flutter::testing::@2838::KeyboardChange::@76 content
double y
double x
SK_API sk_sp< SkImage > RasterFromData(const SkImageInfo &info, sk_sp< SkData > pixels, size_t rowBytes)
std::unique_ptr< SkPDFArray > MatrixToArray(const SkMatrix &matrix)
void EmitPath(const SkPath &path, SkPaint::Style paintStyle, bool doConsumeDegerates, SkWStream *content, SkScalar tolerance=0.25f)
void PaintPath(SkPaint::Style style, SkPathFillType fill, SkWStream *content)
void AppendScalar(SkScalar value, SkWStream *stream)
Definition SkPDFUtils.h:86
Definition ref_ptr.h:256
int32_t width
sk_sp< SkImage > fImage
SkIPoint fOffset
@ kNotEmbeddable_FontFlag
May not be embedded.
@ kAltDataFormat_FontFlag
Data compressed. Table access may still work.
@ kNotSubsettable_FontFlag
May not be subset.
@ kVariable_FontFlag
May be true for Type1, CFF, or TrueType fonts.
int32_t fBottom
larger y-axis bounds
Definition SkRect.h:36
constexpr int32_t top() const
Definition SkRect.h:120
constexpr SkISize size() const
Definition SkRect.h:172
constexpr int32_t bottom() const
Definition SkRect.h:134
constexpr int32_t height() const
Definition SkRect.h:165
constexpr int32_t right() const
Definition SkRect.h:127
int32_t fTop
smaller y-axis bounds
Definition SkRect.h:34
void join(const SkIRect &r)
Definition SkRect.cpp:31
static constexpr SkIRect MakeEmpty()
Definition SkRect.h:45
constexpr int32_t width() const
Definition SkRect.h:158
int32_t fLeft
smaller x-axis bounds
Definition SkRect.h:33
constexpr int32_t left() const
Definition SkRect.h:113
int32_t fRight
larger x-axis bounds
Definition SkRect.h:35
static SkImageInfo MakeN32Premul(int width, int height)
static SkImageInfo MakeA8(int width, int height)
const uint32_t fRowBytes
Definition SkMask.h:43
@ k3D_Format
3 8bit per pixl planes: alpha, mul, add
Definition SkMask.h:29
@ kA8_Format
8bits per pixel mask (e.g. antialiasing)
Definition SkMask.h:28
@ kLCD16_Format
565 alpha for r/g/b
Definition SkMask.h:31
@ kARGB32_Format
SkPMColor.
Definition SkMask.h:30
@ kBW_Format
1bit per pixel mask (e.g. monochrome)
Definition SkMask.h:27
const uint8_t * getAddr1(int x, int y) const
Definition SkMask.h:68
uint8_t const *const fImage
Definition SkMask.h:41
const SkIRect fBounds
Definition SkMask.h:42
size_t computeTotalImageSize() const
Definition SkMask.cpp:34
const Format fFormat
Definition SkMask.h:44
enum SkPDF::Metadata::Subsetter fSubsetter
bool isEmpty() const
Definition SkRect.h:693