Flutter Engine
The Flutter Engine
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
8#include "src/pdf/SkPDFFont.h"
9
12#include "include/core/SkData.h"
14#include "include/core/SkFont.h"
22#include "include/core/SkPath.h"
24#include "include/core/SkRect.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"
39#include "src/core/SkStrike.h"
41#include "src/core/SkTHash.h"
42#include "src/pdf/SkPDFBitmap.h"
43#include "src/pdf/SkPDFDevice.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
61}
62
63namespace {
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)
67static const int32_t kPdfSymbolic = 4;
68static const SkFontTableTag kCOLRTableTag = SkSetFourByteTag('C', 'O', 'L', 'R');
69
70// scale from em-units to base-1000, returning as a SkScalar
71inline SkScalar from_font_units(SkScalar scaled, uint16_t emSize) {
72 return emSize == 1000 ? scaled : scaled * 1000 / emSize;
73}
74
75inline SkScalar scaleFromFontUnits(int16_t val, uint16_t emSize) {
76 return from_font_units(SkIntToScalar(val), emSize);
77}
78
79void setGlyphWidthAndBoundingBox(SkScalar width, SkIRect box,
81 // Specify width and bounding box for the glyph.
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
104SkPDFFont::~SkPDFFont() = default;
105
107
109
110static bool can_embed(const SkAdvancedTypefaceMetrics& metrics) {
112}
113
114static bool can_subset(const SkAdvancedTypefaceMetrics& metrics) {
116}
117
119 SkPDFDocument* canon) {
122 if (std::unique_ptr<SkAdvancedTypefaceMetrics>* ptr = canon->fTypefaceMetrics.find(id)) {
123 return ptr->get(); // canon retains ownership.
124 }
125 int count = typeface->countGlyphs();
126 if (count <= 0 || count > 1 + SkTo<int>(UINT16_MAX)) {
127 // Cache nullptr to skip this check. Use SkSafeUnref().
128 canon->fTypefaceMetrics.set(id, nullptr);
129 return nullptr;
130 }
131 std::unique_ptr<SkAdvancedTypefaceMetrics> metrics = typeface->getAdvancedMetrics();
132 if (!metrics) {
133 metrics = std::make_unique<SkAdvancedTypefaceMetrics>();
134 }
135
136 if (0 == metrics->fStemV || 0 == metrics->fCapHeight) {
137 SkFont font;
138 font.setHinting(SkFontHinting::kNone);
139 font.setTypeface(sk_ref_sp(typeface));
140 font.setSize(1000); // glyph coordinate system
141 if (0 == metrics->fStemV) {
142 // Figure out a good guess for StemV - Min width of i, I, !, 1.
143 // This probably isn't very good with an italic font.
144 int16_t stemV = SHRT_MAX;
145 for (char c : {'i', 'I', '!', '1'}) {
146 uint16_t g = font.unicharToGlyph(c);
148 font.getBounds(&g, 1, &bounds, nullptr);
149 stemV = std::min(stemV, SkToS16(SkScalarRoundToInt(bounds.width())));
150 }
151 metrics->fStemV = stemV;
152 }
153 if (0 == metrics->fCapHeight) {
154 // Figure out a good guess for CapHeight: average the height of M and X.
155 SkScalar capHeight = 0;
156 for (char c : {'M', 'X'}) {
157 uint16_t g = font.unicharToGlyph(c);
159 font.getBounds(&g, 1, &bounds, nullptr);
160 capHeight += bounds.height();
161 }
162 metrics->fCapHeight = SkToS16(SkScalarRoundToInt(capHeight / 2));
163 }
164 }
165 // Fonts are always subset, so always prepend the subset tag.
166 metrics->fPostScriptName.prepend(canon->nextFontSubsetTag());
167 return canon->fTypefaceMetrics.set(id, std::move(metrics))->get();
168}
169
170const std::vector<SkUnichar>& SkPDFFont::GetUnicodeMap(const SkTypeface* typeface,
171 SkPDFDocument* canon) {
173 SkASSERT(canon);
175 if (std::vector<SkUnichar>* ptr = canon->fToUnicodeMap.find(id)) {
176 return *ptr;
177 }
178 std::vector<SkUnichar> buffer(typeface->countGlyphs());
180 return *canon->fToUnicodeMap.set(id, std::move(buffer));
181}
182
184 const SkAdvancedTypefaceMetrics& metrics) {
186 // PDF is actually interested in the encoding of the data, not just the logical format.
187 // If the TrueType is actually wOFF or wOF2 then it should not be directly embedded in PDF.
188 // For now export these as Type3 until the subsetter can handle table based fonts.
189 // See https://github.com/harfbuzz/harfbuzz/issues/3609 and
190 // https://skia-review.googlesource.com/c/skia/+/543485
193 // force Type3 fallback.
195 }
196 if (typeface.getTableSize(kCOLRTableTag)) {
197 // https://bugs.chromium.org/p/skia/issues/detail?id=12650
198 // Don't embed COLRv0 / COLRv1 fonts, fall back to bitmaps.
200 }
201 return metrics.fType;
202}
203
205 return gid != 0 ? gid - (gid - 1) % 255 : 1;
206}
207
209 const SkGlyph* glyph,
210 SkTypeface* face) {
211 SkASSERT(doc);
212 SkASSERT(face); // All SkPDFDevice::internalDrawText ensures this.
213 const SkAdvancedTypefaceMetrics* fontMetrics = SkPDFFont::GetMetrics(face, doc);
214 SkASSERT(fontMetrics); // SkPDFDevice::internalDrawText ensures the typeface is good.
215 // GetMetrics only returns null to signify a bad typeface.
216 const SkAdvancedTypefaceMetrics& metrics = *fontMetrics;
218 if (!(glyph->isEmpty() || glyph->path())) {
220 }
221 bool multibyte = SkPDFFont::IsMultiByte(type);
222 SkGlyphID subsetCode =
224 uint64_t typefaceID = (static_cast<uint64_t>(face->uniqueID()) << 16) | subsetCode;
225
226 if (SkPDFFont* found = doc->fFontMap.find(typefaceID)) {
227 SkASSERT(multibyte == found->multiByteGlyphs());
228 return found;
229 }
230
233
234 SkGlyphID lastGlyph = SkToU16(typeface->countGlyphs() - 1);
235
236 // should be caught by SkPDFDevice::internalDrawText
237 SkASSERT(glyph->getGlyphID() <= lastGlyph);
238
239 SkGlyphID firstNonZeroGlyph;
240 if (multibyte) {
241 firstNonZeroGlyph = 1;
242 } else {
243 firstNonZeroGlyph = subsetCode;
244 lastGlyph = SkToU16(std::min<int>((int)lastGlyph, 254 + (int)subsetCode));
245 }
246 auto ref = doc->reserveRef();
247 return doc->fFontMap.set(
248 typefaceID, SkPDFFont(std::move(typeface), firstNonZeroGlyph, lastGlyph, type, ref));
249}
250
251SkPDFFont::SkPDFFont(sk_sp<SkTypeface> typeface,
252 SkGlyphID firstGlyphID,
253 SkGlyphID lastGlyphID,
255 SkPDFIndirectReference indirectReference)
256 : fTypeface(std::move(typeface))
257 , fGlyphUsage(firstGlyphID, lastGlyphID)
258 , fIndirectReference(indirectReference)
259 , fFontType(fontType)
260{
261 // Always include glyph 0
262 this->noteGlyphUsage(0);
263}
264
266 const SkAdvancedTypefaceMetrics& metrics,
267 uint16_t emSize,
268 int16_t defaultWidth) {
269 descriptor->insertName("FontName", metrics.fPostScriptName);
270 descriptor->insertInt("Flags", (size_t)(metrics.fStyle | kPdfSymbolic));
271 descriptor->insertScalar("Ascent",
272 scaleFromFontUnits(metrics.fAscent, emSize));
273 descriptor->insertScalar("Descent",
274 scaleFromFontUnits(metrics.fDescent, emSize));
275 descriptor->insertScalar("StemV",
276 scaleFromFontUnits(metrics.fStemV, emSize));
277 descriptor->insertScalar("CapHeight",
278 scaleFromFontUnits(metrics.fCapHeight, emSize));
279 descriptor->insertInt("ItalicAngle", metrics.fItalicAngle);
280 descriptor->insertObject("FontBBox",
281 SkPDFMakeArray(scaleFromFontUnits(metrics.fBBox.left(), emSize),
282 scaleFromFontUnits(metrics.fBBox.bottom(), emSize),
283 scaleFromFontUnits(metrics.fBBox.right(), emSize),
284 scaleFromFontUnits(metrics.fBBox.top(), emSize)));
285 if (defaultWidth > 0) {
286 descriptor->insertScalar("MissingWidth",
287 scaleFromFontUnits(defaultWidth, emSize));
288 }
289}
290
291///////////////////////////////////////////////////////////////////////////////
292// Type0Font
293///////////////////////////////////////////////////////////////////////////////
294
296 const SkAdvancedTypefaceMetrics* metricsPtr = SkPDFFont::GetMetrics(font.typeface(), doc);
297 SkASSERT(metricsPtr);
298 if (!metricsPtr) {
299 return;
300 }
301 const SkAdvancedTypefaceMetrics& metrics = *metricsPtr;
302 SkASSERT(can_embed(metrics));
304 SkTypeface* face = font.typeface();
305 SkASSERT(face);
306
307 auto descriptor = SkPDFMakeDict("FontDescriptor");
308 uint16_t emSize = SkToU16(font.typeface()->getUnitsPerEm());
309 SkPDFFont::PopulateCommonFontDescriptor(descriptor.get(), metrics, emSize, 0);
310
311 int ttcIndex;
312 std::unique_ptr<SkStreamAsset> fontAsset = face->openStream(&ttcIndex);
313 size_t fontSize = fontAsset ? fontAsset->getLength() : 0;
314 if (0 == fontSize) {
315 SkDebugf("Error: (SkTypeface)(%p)::openStream() returned "
316 "empty stream (%p) when identified as kType1CID_Font "
317 "or kTrueType_Font.\n", face, fontAsset.get());
320 {
321 sk_sp<SkData> subsetFontData;
322 if (can_subset(metrics)) {
323 SkASSERT(font.firstGlyphID() == 1);
324 subsetFontData = SkPDFSubsetFont(*face, font.glyphUsage());
325 }
326 std::unique_ptr<SkStreamAsset> subsetFontAsset;
327 if (subsetFontData) {
328 subsetFontAsset = SkMemoryStream::Make(std::move(subsetFontData));
329 } else {
330 // If subsetting fails, fall back to original font data.
331 subsetFontAsset = std::move(fontAsset);
332 }
333 std::unique_ptr<SkPDFDict> streamDict = SkPDFMakeDict();
334 streamDict->insertInt("Length1", subsetFontAsset->getLength());
335 const char* fontFileKey;
337 fontFileKey = "FontFile2";
338 } else {
339 streamDict->insertName("Subtype", "OpenType");
340 fontFileKey = "FontFile3";
341 }
342 descriptor->insertRef(fontFileKey,
343 SkPDFStreamOut(std::move(streamDict), std::move(subsetFontAsset),
346 std::unique_ptr<SkPDFDict> streamDict = SkPDFMakeDict();
347 streamDict->insertName("Subtype", "CIDFontType0C");
348 descriptor->insertRef("FontFile3",
349 SkPDFStreamOut(std::move(streamDict), std::move(fontAsset),
351 } else {
352 SkASSERT(false);
353 }
354
355 auto newCIDFont = SkPDFMakeDict("Font");
356 newCIDFont->insertRef("FontDescriptor", doc->emit(*descriptor));
357 newCIDFont->insertName("BaseFont", metrics.fPostScriptName);
358
359 switch (type) {
361 newCIDFont->insertName("Subtype", "CIDFontType0");
362 break;
364 newCIDFont->insertName("Subtype", "CIDFontType0");
365 newCIDFont->insertName("CIDToGIDMap", "Identity");
366 break;
368 newCIDFont->insertName("Subtype", "CIDFontType2");
369 newCIDFont->insertName("CIDToGIDMap", "Identity");
370 break;
371 default:
372 SkASSERT(false);
373 }
374 auto sysInfo = SkPDFMakeDict();
375 // These are actually ASCII strings.
376 sysInfo->insertByteString("Registry", "Adobe");
377 sysInfo->insertByteString("Ordering", "Identity");
378 sysInfo->insertInt("Supplement", 0);
379 newCIDFont->insertObject("CIDSystemInfo", std::move(sysInfo));
380
381 // Unfortunately, poppler enforces DW (default width) must be an integer.
382 int32_t defaultWidth = 0;
383 {
384 std::unique_ptr<SkPDFArray> widths = SkPDFMakeCIDGlyphWidthsArray(
385 *face, font.glyphUsage(), &defaultWidth);
386 if (widths && widths->size() > 0) {
387 newCIDFont->insertObject("W", std::move(widths));
388 }
389 newCIDFont->insertInt("DW", defaultWidth);
390 }
391
392 ////////////////////////////////////////////////////////////////////////////
393
394 SkPDFDict fontDict("Font");
395 fontDict.insertName("Subtype", "Type0");
396 fontDict.insertName("BaseFont", metrics.fPostScriptName);
397 fontDict.insertName("Encoding", "Identity-H");
398 auto descendantFonts = SkPDFMakeArray();
399 descendantFonts->appendRef(doc->emit(*newCIDFont));
400 fontDict.insertObject("DescendantFonts", std::move(descendantFonts));
401
402 const std::vector<SkUnichar>& glyphToUnicode =
403 SkPDFFont::GetUnicodeMap(font.typeface(), doc);
404 SkASSERT(SkToSizeT(font.typeface()->countGlyphs()) == glyphToUnicode.size());
405 std::unique_ptr<SkStreamAsset> toUnicode =
406 SkPDFMakeToUnicodeCmap(glyphToUnicode.data(),
407 &font.glyphUsage(),
408 font.multiByteGlyphs(),
409 font.firstGlyphID(),
410 font.lastGlyphID());
411 fontDict.insertRef("ToUnicode", SkPDFStreamOut(nullptr, std::move(toUnicode), doc));
412
413 doc->emit(fontDict, font.indirectReference());
414}
415
416///////////////////////////////////////////////////////////////////////////////
417// PDFType3Font
418///////////////////////////////////////////////////////////////////////////////
419
420namespace {
421// returns [0, first, first+1, ... last-1, last]
422struct SingleByteGlyphIdIterator {
423 SingleByteGlyphIdIterator(SkGlyphID first, SkGlyphID last)
424 : fFirst(first), fLast(last) {
425 SkASSERT(fFirst > 0);
426 SkASSERT(fLast >= first);
427 }
428 struct Iter {
429 void operator++() {
430 fCurrent = (0 == fCurrent) ? fFirst : fCurrent + 1;
431 }
432 // This is an input_iterator
433 SkGlyphID operator*() const { return (SkGlyphID)fCurrent; }
434 bool operator!=(const Iter& rhs) const {
435 return fCurrent != rhs.fCurrent;
436 }
437 Iter(SkGlyphID f, int c) : fFirst(f), fCurrent(c) {}
438 private:
439 const SkGlyphID fFirst;
440 int fCurrent; // must be int to make fLast+1 to fit
441 };
442 Iter begin() const { return Iter(fFirst, 0); }
443 Iter end() const { return Iter(fFirst, (int)fLast + 1); }
444private:
445 const SkGlyphID fFirst;
446 const SkGlyphID fLast;
447};
448} // namespace
449
453};
455 const SkGlyph* glyph = smallGlyphs->glyph(SkPackedGlyphID{gid});
456 SkMask mask = glyph->mask();
457 if (!mask.fImage) {
458 return {nullptr, {0, 0}};
459 }
460 SkIRect bounds = mask.fBounds;
461 SkBitmap bm;
462 switch (mask.fFormat) {
464 bm.allocPixels(SkImageInfo::MakeA8(bounds.width(), bounds.height()));
465 for (int y = 0; y < bm.height(); ++y) {
466 for (int x8 = 0; x8 < bm.width(); x8 += 8) {
467 uint8_t v = *mask.getAddr1(x8 + bounds.x(), y + bounds.y());
468 int e = std::min(x8 + 8, bm.width());
469 for (int x = x8; x < e; ++x) {
470 *bm.getAddr8(x, y) = (v >> (x & 0x7)) & 0x1 ? 0xFF : 0x00;
471 }
472 }
473 }
474 bm.setImmutable();
475 return {bm.asImage(), {bounds.x(), bounds.y()}};
478 SkImageInfo::MakeA8(bounds.width(), bounds.height()),
480 mask.fRowBytes),
481 {bounds.x(), bounds.y()}};
484 SkImageInfo::MakeN32Premul(bounds.width(), bounds.height()),
486 mask.fRowBytes),
487 {bounds.x(), bounds.y()}};
490 default:
491 SkASSERT(false);
492 return {nullptr, {0, 0}};
493 }
494}
495
497 const SkTypeface* typeface,
498 SkScalar xHeight) {
499 if (SkPDFIndirectReference* ptr = doc->fType3FontDescriptors.find(typeface->uniqueID())) {
500 return *ptr;
501 }
502
503 SkPDFDict descriptor("FontDescriptor");
504 int32_t fontDescriptorFlags = kPdfSymbolic;
505
506 /** PDF32000_2008: FontFamily should be used for Type3 fonts in Tagged PDF documents. */
507 SkString familyName;
508 typeface->getFamilyName(&familyName);
509 if (!familyName.isEmpty()) {
510 descriptor.insertByteString("FontFamily", familyName);
511 }
512
513 /** PDF32000_2008: FontStretch should be used for Type3 fonts in Tagged PDF documents. */
514 static constexpr const char* stretchNames[9] = {
515 "UltraCondensed",
516 "ExtraCondensed",
517 "Condensed",
518 "SemiCondensed",
519 "Normal",
520 "SemiExpanded",
521 "Expanded",
522 "ExtraExpanded",
523 "UltraExpanded",
524 };
525 const char* stretchName = stretchNames[typeface->fontStyle().width() - 1];
526 descriptor.insertName("FontStretch", stretchName);
527
528 /** PDF32000_2008: FontWeight should be used for Type3 fonts in Tagged PDF documents. */
529 int weight = (typeface->fontStyle().weight() + 50) / 100;
530 descriptor.insertInt("FontWeight", SkTPin(weight, 1, 9) * 100);
531
532 if (const SkAdvancedTypefaceMetrics* metrics = SkPDFFont::GetMetrics(typeface, doc)) {
533 // Type3 FontDescriptor does not require all the same fields.
534 descriptor.insertName("FontName", metrics->fPostScriptName);
535 descriptor.insertInt("ItalicAngle", metrics->fItalicAngle);
536 fontDescriptorFlags |= (int32_t)metrics->fStyle;
537 // Adobe requests CapHeight, XHeight, and StemV be added
538 // to "greatly help our workflow downstream".
539 if (metrics->fCapHeight != 0) { descriptor.insertInt("CapHeight", metrics->fCapHeight); }
540 if (metrics->fStemV != 0) { descriptor.insertInt("StemV", metrics->fStemV); }
541 if (xHeight != 0) {
542 descriptor.insertScalar("XHeight", xHeight);
543 }
544 }
545 descriptor.insertInt("Flags", fontDescriptorFlags);
546 SkPDFIndirectReference ref = doc->emit(descriptor);
547 doc->fType3FontDescriptors.set(typeface->uniqueID(), ref);
548 return ref;
549}
550
551#ifdef SK_PDF_BITMAP_GLYPH_RASTER_SIZE
552static constexpr float kBitmapFontSize = SK_PDF_BITMAP_GLYPH_RASTER_SIZE;
553#else
554static constexpr float kBitmapFontSize = 64;
555#endif
556
559 font.setHinting(SkFontHinting::kNone);
560 font.setEdging(SkFont::Edging::kAlias);
562 SkPaint(),
565 SkMatrix::I());
566}
567
568static void emit_subset_type3(const SkPDFFont& pdfFont, SkPDFDocument* doc) {
569 SkTypeface* typeface = pdfFont.typeface();
570 SkGlyphID firstGlyphID = pdfFont.firstGlyphID();
571 SkGlyphID lastGlyphID = pdfFont.lastGlyphID();
572 const SkPDFGlyphUse& subset = pdfFont.glyphUsage();
573 SkASSERT(lastGlyphID >= firstGlyphID);
574 // Remove unused glyphs at the end of the range.
575 // Keep the lastGlyphID >= firstGlyphID invariant true.
576 while (lastGlyphID > firstGlyphID && !subset.has(lastGlyphID)) {
577 --lastGlyphID;
578 }
579 int unitsPerEm;
580 SkStrikeSpec strikeSpec = SkStrikeSpec::MakePDFVector(*typeface, &unitsPerEm);
581 auto strike = strikeSpec.findOrCreateStrike();
582 SkASSERT(strike);
583 SkScalar emSize = (SkScalar)unitsPerEm;
584 SkScalar xHeight = strike->getFontMetrics().fXHeight;
585 SkBulkGlyphMetricsAndPaths metricsAndPaths((sk_sp<SkStrike>(strike)));
586 SkBulkGlyphMetricsAndDrawables metricsAndDrawables(std::move(strike));
587
588 SkStrikeSpec strikeSpecSmall = kBitmapFontSize > 0 ? make_small_strike(*typeface)
589 : strikeSpec;
590
591 SkBulkGlyphMetricsAndImages smallGlyphs(strikeSpecSmall);
592 float bitmapScale = kBitmapFontSize > 0 ? emSize / kBitmapFontSize : 1.0f;
593
594 SkPDFDict font("Font");
595 font.insertName("Subtype", "Type3");
596 // Flip about the x-axis and scale by 1/emSize.
597 SkMatrix fontMatrix;
598 fontMatrix.setScale(SkScalarInvert(emSize), -SkScalarInvert(emSize));
599 font.insertObject("FontMatrix", SkPDFUtils::MatrixToArray(fontMatrix));
600
601 auto charProcs = SkPDFMakeDict();
602 auto encoding = SkPDFMakeDict("Encoding");
603
604 auto encDiffs = SkPDFMakeArray();
605 // length(firstGlyphID .. lastGlyphID) == lastGlyphID - firstGlyphID + 1
606 // plus 1 for glyph 0;
607 SkASSERT(firstGlyphID > 0);
608 SkASSERT(lastGlyphID >= firstGlyphID);
609 int glyphCount = lastGlyphID - firstGlyphID + 2;
610 // one other entry for the index of first glyph.
611 encDiffs->reserve(glyphCount + 1);
612 encDiffs->appendInt(0); // index of first glyph
613
614 auto widthArray = SkPDFMakeArray();
615 widthArray->reserve(glyphCount);
616
618
619 std::vector<std::pair<SkGlyphID, SkPDFIndirectReference>> imageGlyphs;
620 for (SkGlyphID gID : SingleByteGlyphIdIterator(firstGlyphID, lastGlyphID)) {
621 bool skipGlyph = gID != 0 && !subset.has(gID);
622 SkString characterName;
623 SkScalar advance = 0.0f;
624 SkIRect glyphBBox;
625 if (skipGlyph) {
626 characterName.set("g0");
627 } else {
628 characterName.printf("g%X", gID);
629 const SkGlyph* pathGlyph = metricsAndPaths.glyph(gID);
630 const SkGlyph* drawableGlyph = metricsAndDrawables.glyph(gID);
631 advance = pathGlyph->advanceX();
632 glyphBBox = pathGlyph->iRect();
633 bbox.join(glyphBBox);
634 const SkPath* path = pathGlyph->path();
635 SkDrawable* drawable = drawableGlyph->drawable();
637 if (drawable && !drawable->getBounds().isEmpty()) {
638 sk_sp<SkPDFDevice> glyphDevice = sk_make_sp<SkPDFDevice>(glyphBBox.size(), doc);
639 SkCanvas canvas(glyphDevice);
640 canvas.translate(-glyphBBox.fLeft, -glyphBBox.fTop);
641 canvas.drawDrawable(drawable);
643 doc, glyphDevice->content(),
644 SkPDFMakeArray(0, 0, glyphBBox.width(), glyphBBox.height()),
645 glyphDevice->makeResourceDict(),
646 SkMatrix::Translate(glyphBBox.fLeft, glyphBBox.fTop), nullptr);
647 imageGlyphs.emplace_back(gID, xobject);
648 SkPDFUtils::AppendScalar(drawableGlyph->advanceX(), &content);
649 content.writeText(" 0 d0\n1 0 0 1 0 0 cm\n/X");
650 content.write(characterName.c_str(), characterName.size());
651 content.writeText(" Do\n");
652 } else if (path && !path->isEmpty()) {
653 setGlyphWidthAndBoundingBox(pathGlyph->advanceX(), glyphBBox, &content);
656 } else {
657 auto pimg = to_image(gID, &smallGlyphs);
658 if (!pimg.fImage) {
659 setGlyphWidthAndBoundingBox(pathGlyph->advanceX(), glyphBBox, &content);
660 } else {
662 imageGlyphs.emplace_back(gID, SkPDFSerializeImage(pimg.fImage.get(), doc));
663 AppendScalar(pathGlyph->advanceX(), &content);
664 content.writeText(" 0 d0\n");
665 AppendScalar(pimg.fImage->width() * bitmapScale, &content);
666 content.writeText(" 0 0 ");
667 AppendScalar(-pimg.fImage->height() * bitmapScale, &content);
668 content.writeText(" ");
669 AppendScalar(pimg.fOffset.x() * bitmapScale, &content);
670 content.writeText(" ");
671 AppendScalar((pimg.fImage->height() + pimg.fOffset.y()) * bitmapScale,
672 &content);
673 content.writeText(" cm\n/X");
674 content.write(characterName.c_str(), characterName.size());
675 content.writeText(" Do\n");
676 }
677 }
678 charProcs->insertRef(characterName, SkPDFStreamOut(nullptr,
679 content.detachAsStream(), doc));
680 }
681 encDiffs->appendName(std::move(characterName));
682 widthArray->appendScalar(advance);
683 }
684
685 if (!imageGlyphs.empty()) {
686 auto d0 = SkPDFMakeDict();
687 for (const auto& pair : imageGlyphs) {
688 d0->insertRef(SkStringPrintf("Xg%X", pair.first), pair.second);
689 }
690 auto d1 = SkPDFMakeDict();
691 d1->insertObject("XObject", std::move(d0));
692 font.insertObject("Resources", std::move(d1));
693 }
694
695 encoding->insertObject("Differences", std::move(encDiffs));
696 font.insertInt("FirstChar", 0);
697 font.insertInt("LastChar", lastGlyphID - firstGlyphID + 1);
698 /* FontBBox: "A rectangle expressed in the glyph coordinate
699 system, specifying the font bounding box. This is the smallest
700 rectangle enclosing the shape that would result if all of the
701 glyphs of the font were placed with their origins coincident and
702 then filled." */
703 font.insertObject("FontBBox", SkPDFMakeArray(bbox.left(),
704 bbox.bottom(),
705 bbox.right(),
706 bbox.top()));
707
708 font.insertName("CIDToGIDMap", "Identity");
709
710 const std::vector<SkUnichar>& glyphToUnicode = SkPDFFont::GetUnicodeMap(typeface, doc);
711 SkASSERT(glyphToUnicode.size() == SkToSizeT(typeface->countGlyphs()));
712 auto toUnicodeCmap = SkPDFMakeToUnicodeCmap(glyphToUnicode.data(),
713 &subset,
714 false,
715 firstGlyphID,
716 lastGlyphID);
717 font.insertRef("ToUnicode", SkPDFStreamOut(nullptr, std::move(toUnicodeCmap), doc));
718 font.insertRef("FontDescriptor", type3_descriptor(doc, typeface, xHeight));
719 font.insertObject("Widths", std::move(widthArray));
720 font.insertObject("Encoding", std::move(encoding));
721 font.insertObject("CharProcs", std::move(charProcs));
722
723 doc->emit(font, pdfFont.indirectReference());
724}
725
727 switch (fFontType) {
731 return emit_subset_type0(*this, doc);
732#ifndef SK_PDF_DO_NOT_SUPPORT_TYPE_1_FONTS
734 return SkPDFEmitType1Font(*this, doc);
735#endif
736 default:
737 return emit_subset_type3(*this, doc);
738 }
739}
740
741////////////////////////////////////////////////////////////////////////////////
742
745 return metrics && can_embed(*metrics);
746}
747
int count
Definition: FontMgrTest.cpp:50
#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)
SkStrikeSpec make_small_strike(const SkTypeface &typeface)
Definition: SkPDFFont.cpp:557
static SkPDFIndirectReference type3_descriptor(SkPDFDocument *doc, const SkTypeface *typeface, SkScalar xHeight)
Definition: SkPDFFont.cpp:496
static ImageAndOffset to_image(SkGlyphID gid, SkBulkGlyphMetricsAndImages *smallGlyphs)
Definition: SkPDFFont.cpp:454
static bool can_subset(const SkAdvancedTypefaceMetrics &metrics)
Definition: SkPDFFont.cpp:114
static void emit_subset_type3(const SkPDFFont &pdfFont, SkPDFDocument *doc)
Definition: SkPDFFont.cpp:568
static void emit_subset_type0(const SkPDFFont &font, SkPDFDocument *doc)
Definition: SkPDFFont.cpp:295
static constexpr float kBitmapFontSize
Definition: SkPDFFont.cpp:554
static SkGlyphID first_nonzero_glyph_for_single_byte_encoding(SkGlyphID gid)
Definition: SkPDFFont.cpp:204
static bool can_embed(const SkAdvancedTypefaceMetrics &metrics)
Definition: SkPDFFont.cpp:110
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(const SkTypeface &, const SkPDFGlyphUse &)
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)
Definition: SkPDFTypes.cpp:591
static std::unique_ptr< SkPDFDict > SkPDFMakeDict(const char *type=nullptr)
Definition: SkPDFTypes.h:185
static std::unique_ptr< SkPDFArray > SkPDFMakeArray(Args... args)
Definition: SkPDFTypes.h:125
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 SkStringPrintf(const char *format,...) SK_PRINTF_LIKE(1
Creates a new string and writes into it using a printf()-style format.
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
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[]
Definition: StrokerTest.cpp:39
GLenum type
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)
Definition: SkCanvas.cpp:1278
void drawDrawable(SkDrawable *drawable, const SkMatrix *matrix=nullptr)
Definition: SkCanvas.cpp:2574
static sk_sp< SkData > MakeWithCopy(const void *data, size_t length)
Definition: SkData.cpp:111
SkRect getBounds()
Definition: SkDrawable.cpp:71
int width() const
Definition: SkFontStyle.h:63
int weight() const
Definition: SkFontStyle.h:62
Definition: SkFont.h:35
@ 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()
Definition: SkMatrix.cpp:1544
static std::unique_ptr< SkMemoryStream > Make(sk_sp< SkData > data)
Definition: SkStream.cpp:314
std::unique_ptr< SkStreamAsset > content()
std::unique_ptr< SkPDFDict > makeResourceDict()
void insertName(const char key[], const char nameValue[])
Definition: SkPDFTypes.cpp:512
void insertObject(const char key[], std::unique_ptr< SkPDFObject > &&)
Definition: SkPDFTypes.cpp:484
void insertInt(const char key[], int32_t value)
Definition: SkPDFTypes.cpp:496
void insertRef(const char key[], SkPDFIndirectReference)
Definition: SkPDFTypes.cpp:476
void insertScalar(const char key[], SkScalar value)
Definition: SkPDFTypes.cpp:508
void insertByteString(const char key[], const char value[])
Definition: SkPDFTypes.cpp:520
SkPDFIndirectReference emit(const SkPDFObject &, SkPDFIndirectReference)
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:78
static const SkAdvancedTypefaceMetrics * GetMetrics(const SkTypeface *typeface, SkPDFDocument *canon)
Definition: SkPDFFont.cpp:118
static void PopulateCommonFontDescriptor(SkPDFDict *descriptor, const SkAdvancedTypefaceMetrics &, uint16_t emSize, int16_t defaultWidth)
Definition: SkPDFFont.cpp:265
static SkPDFFont * GetFontResource(SkPDFDocument *doc, const SkGlyph *glyphs, SkTypeface *typeface)
Definition: SkPDFFont.cpp:208
SkPDFIndirectReference indirectReference() const
Definition: SkPDFFont.h:83
static SkAdvancedTypefaceMetrics::FontType FontType(const SkTypeface &, const SkAdvancedTypefaceMetrics &)
Definition: SkPDFFont.cpp:183
static bool IsMultiByte(SkAdvancedTypefaceMetrics::FontType type)
Definition: SkPDFFont.h:52
static const std::vector< SkUnichar > & GetUnicodeMap(const SkTypeface *typeface, SkPDFDocument *canon)
Definition: SkPDFFont.cpp:170
SkPDFFont & operator=(SkPDFFont &&)
SkGlyphID lastGlyphID() const
Definition: SkPDFFont.h:121
SkGlyphID firstGlyphID() const
Definition: SkPDFFont.h:120
SkPDFFont(SkPDFFont &&)
void emitSubset(SkPDFDocument *) const
Definition: SkPDFFont.cpp:726
const SkPDFGlyphUse & glyphUsage() const
Definition: SkPDFFont.h:122
static void GetType1GlyphNames(const SkTypeface &, SkString *)
Definition: SkPDFFont.cpp:59
SkTypeface * typeface() const
Definition: SkPDFFont.h:41
static bool CanEmbedTypeface(SkTypeface *, SkPDFDocument *)
Definition: SkPDFFont.cpp:743
bool has(SkGlyphID gid) const
Definition: SkPDFGlyphUse.h:23
@ kFill_Style
set to fill geometry
Definition: SkPaint.h:193
Definition: SkPath.h:59
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
Definition: SkTypeface.cpp:432
virtual void getPostScriptGlyphNames(SkString *) const =0
SkTypefaceID uniqueID() const
Definition: SkTypeface.h:101
virtual void getGlyphToUnicodeMap(SkUnichar *dstArray) const =0
Definition: SkTypeface.cpp:468
void getFamilyName(SkString *name) const
Definition: SkTypeface.cpp:459
SkFontStyle fontStyle() const
Definition: SkTypeface.h:55
size_t getTableSize(SkFontTableTag) const
Definition: SkTypeface.cpp:309
std::unique_ptr< SkStreamAsset > openStream(int *ttcIndex) const
Definition: SkTypeface.cpp:332
V * find(const K &key) const
Definition: SkTHash.h:494
V * set(K key, V val)
Definition: SkTHash.h:487
static const char * begin(const StringSlice &s)
Definition: editor.cpp:252
float SkScalar
Definition: extension.cpp:12
if(end==-1)
glong glong end
static float min(float r, float g, float b)
Definition: hsl.cpp:48
union flutter::testing::@2836::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)
Definition: SkPDFUtils.cpp:67
void EmitPath(const SkPath &path, SkPaint::Style paintStyle, bool doConsumeDegerates, SkWStream *content, SkScalar tolerance=0.25f)
Definition: SkPDFUtils.cpp:132
void PaintPath(SkPaint::Style style, SkPathFillType fill, SkWStream *content)
Definition: SkPDFUtils.cpp:231
void AppendScalar(SkScalar value, SkWStream *stream)
Definition: SkPDFUtils.h:98
Optional< SkRect > bounds
Definition: SkRecords.h:189
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir path
Definition: switches.h:57
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace buffer
Definition: switches.h:126
bool operator!=(C p1, const scoped_nsprotocol< C > &p2)
font
Font Metadata and Metrics.
dst
Definition: cp.py:12
constexpr Color operator*(T value, const Color &c)
Definition: color.h:911
Definition: ref_ptr.h:256
int32_t width
sk_sp< SkImage > fImage
Definition: SkPDFFont.cpp:451
SkIPoint fOffset
Definition: SkPDFFont.cpp:452
@ 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.
Definition: SkRect.h:32
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)
Definition: SkMask.h:25
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
bool isEmpty() const
Definition: SkRect.h:693