blob: a70ebf7c4199c983eb7b4a3992c876c6e9a09d7a [file] [log] [blame]
vandebo@chromium.org28be72b2010-11-11 21:37:00 +00001/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00002 * Copyright 2011 Google Inc.
vandebo@chromium.org28be72b2010-11-11 21:37:00 +00003 *
epoger@google.comec3ed6a2011-07-28 14:26:00 +00004 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
vandebo@chromium.org28be72b2010-11-11 21:37:00 +00006 */
7
Kaylee Lubickbea38402024-05-03 18:11:24 -04008#include "src/pdf/SkPDFFont.h"
9
Ben Wagner0b9b1f12019-04-04 18:00:05 -040010#include "include/core/SkBitmap.h"
Kaylee Lubickbea38402024-05-03 18:11:24 -040011#include "include/core/SkCanvas.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050012#include "include/core/SkData.h"
Kaylee Lubickbea38402024-05-03 18:11:24 -040013#include "include/core/SkDrawable.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050014#include "include/core/SkFont.h"
Ben Wagner0b9b1f12019-04-04 18:00:05 -040015#include "include/core/SkFontMetrics.h"
Kaylee Lubickbea38402024-05-03 18:11:24 -040016#include "include/core/SkFontStyle.h"
Ben Wagner0b9b1f12019-04-04 18:00:05 -040017#include "include/core/SkFontTypes.h"
18#include "include/core/SkImage.h"
19#include "include/core/SkImageInfo.h"
20#include "include/core/SkMatrix.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050021#include "include/core/SkPaint.h"
Ben Wagner0b9b1f12019-04-04 18:00:05 -040022#include "include/core/SkPath.h"
23#include "include/core/SkPoint.h"
24#include "include/core/SkRect.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050025#include "include/core/SkRefCnt.h"
26#include "include/core/SkScalar.h"
27#include "include/core/SkStream.h"
Ben Wagner0b9b1f12019-04-04 18:00:05 -040028#include "include/core/SkString.h"
29#include "include/core/SkSurfaceProps.h"
Kaylee Lubickbea38402024-05-03 18:11:24 -040030#include "include/private/base/SkDebug.h"
31#include "include/private/base/SkTPin.h"
Kevin Lubick19936eb2023-01-05 09:00:37 -050032#include "include/private/base/SkTo.h"
John Stiles99e8dc52023-07-24 11:56:16 -040033#include "src/base/SkBitmaskEnum.h"
Kevin Lubick1b3aa8b2023-01-19 14:03:31 -050034#include "src/base/SkUTF.h"
Kaylee Lubickbea38402024-05-03 18:11:24 -040035#include "src/core/SkDevice.h"
Ben Wagner0b9b1f12019-04-04 18:00:05 -040036#include "src/core/SkGlyph.h"
Ben Wagner0b9b1f12019-04-04 18:00:05 -040037#include "src/core/SkMask.h"
38#include "src/core/SkScalerContext.h"
Herb Derby14c62c62023-01-20 10:32:02 -050039#include "src/core/SkStrike.h"
Herb Derby2b35b7d2019-05-22 16:11:13 -040040#include "src/core/SkStrikeSpec.h"
Kevin Lubick1b3aa8b2023-01-19 14:03:31 -050041#include "src/core/SkTHash.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050042#include "src/pdf/SkPDFBitmap.h"
Ben Wagner4e8b2352023-01-31 17:00:56 -050043#include "src/pdf/SkPDFDevice.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050044#include "src/pdf/SkPDFDocumentPriv.h"
Ben Wagner4e8b2352023-01-31 17:00:56 -050045#include "src/pdf/SkPDFFormXObject.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050046#include "src/pdf/SkPDFMakeCIDGlyphWidthsArray.h"
47#include "src/pdf/SkPDFMakeToUnicodeCmap.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050048#include "src/pdf/SkPDFSubsetFont.h"
Ben Wagner0b9b1f12019-04-04 18:00:05 -040049#include "src/pdf/SkPDFType1Font.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050050#include "src/pdf/SkPDFUtils.h"
vandebo@chromium.org28be72b2010-11-11 21:37:00 +000051
Ben Wagner0b9b1f12019-04-04 18:00:05 -040052#include <limits.h>
Kaylee Lubickbea38402024-05-03 18:11:24 -040053#include <algorithm>
54#include <cstddef>
Ben Wagner0b9b1f12019-04-04 18:00:05 -040055#include <initializer_list>
56#include <memory>
57#include <utility>
58
Hal Canary2e904bc2019-04-18 15:40:27 -040059void SkPDFFont::GetType1GlyphNames(const SkTypeface& face, SkString* dst) {
60 face.getPostScriptGlyphNames(dst);
61}
62
halcanary8eccc302016-08-09 13:04:34 -070063namespace {
vandebo@chromium.orgdcf9c192013-03-13 20:01:51 +000064// 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)
halcanary3d01c622016-08-31 12:52:35 -070067static const int32_t kPdfSymbolic = 4;
Dominik Röttsches2ed0bae2021-11-15 15:14:03 +020068static const SkFontTableTag kCOLRTableTag = SkSetFourByteTag('C', 'O', 'L', 'R');
vandebo@chromium.org98594282011-07-25 22:34:12 +000069
reed@google.com3f0dcf92011-03-18 21:23:45 +000070// scale from em-units to base-1000, returning as a SkScalar
Hal Canary2e904bc2019-04-18 15:40:27 -040071inline SkScalar from_font_units(SkScalar scaled, uint16_t emSize) {
72 return emSize == 1000 ? scaled : scaled * 1000 / emSize;
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +000073}
74
Hal Canary2e904bc2019-04-18 15:40:27 -040075inline SkScalar scaleFromFontUnits(int16_t val, uint16_t emSize) {
halcanary8eccc302016-08-09 13:04:34 -070076 return from_font_units(SkIntToScalar(val), emSize);
77}
78
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +000079void setGlyphWidthAndBoundingBox(SkScalar width, SkIRect box,
halcanary7e8d5d32016-08-12 07:59:38 -070080 SkDynamicMemoryWStream* content) {
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +000081 // Specify width and bounding box for the glyph.
halcanarybc4696b2015-05-06 10:56:04 -070082 SkPDFUtils::AppendScalar(width, content);
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +000083 content->writeText(" 0 ");
Cary Clark60ebf142018-09-06 12:22:33 +000084 content->writeDecAsText(box.fLeft);
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +000085 content->writeText(" ");
Cary Clark60ebf142018-09-06 12:22:33 +000086 content->writeDecAsText(box.fTop);
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +000087 content->writeText(" ");
Cary Clark60ebf142018-09-06 12:22:33 +000088 content->writeDecAsText(box.fRight);
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +000089 content->writeText(" ");
Cary Clark60ebf142018-09-06 12:22:33 +000090 content->writeDecAsText(box.fBottom);
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +000091 content->writeText(" d1\n");
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +000092}
vandebo@chromium.org2a22e102011-01-25 21:01:34 +000093} // namespace
94
vandebo@chromium.org98594282011-07-25 22:34:12 +000095///////////////////////////////////////////////////////////////////////////////
96// class SkPDFFont
97///////////////////////////////////////////////////////////////////////////////
98
Hal Canaryb10f92e2018-11-16 17:01:50 -050099/* Resources are canonicalized and uniqueified by pointer so there has to be
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000100 * some additional state indicating which subset of the font is used. It
Hal Canaryb10f92e2018-11-16 17:01:50 -0500101 * must be maintained at the document granularity.
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000102 */
103
Hal Canaryb10f92e2018-11-16 17:01:50 -0500104SkPDFFont::~SkPDFFont() = default;
105
106SkPDFFont::SkPDFFont(SkPDFFont&&) = default;
107
108SkPDFFont& SkPDFFont::operator=(SkPDFFont&&) = default;
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000109
halcanarycee13422016-08-18 09:52:48 -0700110static bool can_embed(const SkAdvancedTypefaceMetrics& metrics) {
111 return !SkToBool(metrics.fFlags & SkAdvancedTypefaceMetrics::kNotEmbeddable_FontFlag);
vandebo0f9bad02014-06-19 11:05:39 -0700112}
113
Hal Canaryb10f92e2018-11-16 17:01:50 -0500114const SkAdvancedTypefaceMetrics* SkPDFFont::GetMetrics(const SkTypeface* typeface,
Hal Canary4ca9fa32018-12-21 16:15:01 -0500115 SkPDFDocument* canon) {
halcanary4871f222016-08-26 13:17:44 -0700116 SkASSERT(typeface);
Herb Derby25621442022-02-07 12:12:45 -0500117 SkTypefaceID id = typeface->uniqueID();
Hal Canary209e4b12017-05-04 14:23:55 -0400118 if (std::unique_ptr<SkAdvancedTypefaceMetrics>* ptr = canon->fTypefaceMetrics.find(id)) {
Hal Canary5c1b3602017-04-17 16:30:06 -0400119 return ptr->get(); // canon retains ownership.
halcanarycee13422016-08-18 09:52:48 -0700120 }
halcanary4871f222016-08-26 13:17:44 -0700121 int count = typeface->countGlyphs();
Ben Wagner1adfbd52018-06-15 17:10:25 -0400122 if (count <= 0 || count > 1 + SkTo<int>(UINT16_MAX)) {
halcanary4871f222016-08-26 13:17:44 -0700123 // Cache nullptr to skip this check. Use SkSafeUnref().
124 canon->fTypefaceMetrics.set(id, nullptr);
125 return nullptr;
halcanarycee13422016-08-18 09:52:48 -0700126 }
Hal Canary209e4b12017-05-04 14:23:55 -0400127 std::unique_ptr<SkAdvancedTypefaceMetrics> metrics = typeface->getAdvancedMetrics();
halcanarycee13422016-08-18 09:52:48 -0700128 if (!metrics) {
Mike Kleinf46d5ca2019-12-11 10:45:01 -0500129 metrics = std::make_unique<SkAdvancedTypefaceMetrics>();
halcanary17484322016-08-29 09:47:48 -0700130 }
Hal Canary3223e272017-07-05 16:47:59 -0400131
132 if (0 == metrics->fStemV || 0 == metrics->fCapHeight) {
Mike Reedab8f2972018-12-05 13:20:29 -0500133 SkFont font;
Ben Wagner5785e4a2019-05-07 16:50:29 -0400134 font.setHinting(SkFontHinting::kNone);
Mike Reedab8f2972018-12-05 13:20:29 -0500135 font.setTypeface(sk_ref_sp(typeface));
136 font.setSize(1000); // glyph coordinate system
Hal Canary3223e272017-07-05 16:47:59 -0400137 if (0 == metrics->fStemV) {
138 // Figure out a good guess for StemV - Min width of i, I, !, 1.
139 // This probably isn't very good with an italic font.
140 int16_t stemV = SHRT_MAX;
141 for (char c : {'i', 'I', '!', '1'}) {
Mike Reedab8f2972018-12-05 13:20:29 -0500142 uint16_t g = font.unicharToGlyph(c);
Hal Canary3223e272017-07-05 16:47:59 -0400143 SkRect bounds;
Mike Reedab8f2972018-12-05 13:20:29 -0500144 font.getBounds(&g, 1, &bounds, nullptr);
Brian Osman788b9162020-02-07 10:36:46 -0500145 stemV = std::min(stemV, SkToS16(SkScalarRoundToInt(bounds.width())));
Hal Canary3223e272017-07-05 16:47:59 -0400146 }
147 metrics->fStemV = stemV;
148 }
149 if (0 == metrics->fCapHeight) {
150 // Figure out a good guess for CapHeight: average the height of M and X.
151 SkScalar capHeight = 0;
152 for (char c : {'M', 'X'}) {
Mike Reedab8f2972018-12-05 13:20:29 -0500153 uint16_t g = font.unicharToGlyph(c);
Hal Canary3223e272017-07-05 16:47:59 -0400154 SkRect bounds;
Mike Reedab8f2972018-12-05 13:20:29 -0500155 font.getBounds(&g, 1, &bounds, nullptr);
Hal Canary3223e272017-07-05 16:47:59 -0400156 capHeight += bounds.height();
157 }
158 metrics->fCapHeight = SkToS16(SkScalarRoundToInt(capHeight / 2));
159 }
160 }
Ben Wagner17667b02021-11-24 14:52:12 -0500161 // Fonts are always subset, so always prepend the subset tag.
162 metrics->fPostScriptName.prepend(canon->nextFontSubsetTag());
Hal Canary5c1b3602017-04-17 16:30:06 -0400163 return canon->fTypefaceMetrics.set(id, std::move(metrics))->get();
halcanarycee13422016-08-18 09:52:48 -0700164}
165
Hal Canary46cc3da2018-05-09 11:50:34 -0400166const std::vector<SkUnichar>& SkPDFFont::GetUnicodeMap(const SkTypeface* typeface,
Hal Canary4ca9fa32018-12-21 16:15:01 -0500167 SkPDFDocument* canon) {
Hal Canary46cc3da2018-05-09 11:50:34 -0400168 SkASSERT(typeface);
169 SkASSERT(canon);
Herb Derby25621442022-02-07 12:12:45 -0500170 SkTypefaceID id = typeface->uniqueID();
Hal Canary46cc3da2018-05-09 11:50:34 -0400171 if (std::vector<SkUnichar>* ptr = canon->fToUnicodeMap.find(id)) {
172 return *ptr;
173 }
174 std::vector<SkUnichar> buffer(typeface->countGlyphs());
175 typeface->getGlyphToUnicodeMap(buffer.data());
176 return *canon->fToUnicodeMap.set(id, std::move(buffer));
177}
178
Dominik Röttsches2ed0bae2021-11-15 15:14:03 +0200179SkAdvancedTypefaceMetrics::FontType SkPDFFont::FontType(const SkTypeface& typeface,
180 const SkAdvancedTypefaceMetrics& metrics) {
Ben Wagner997c9072020-08-04 13:36:52 -0400181 if (SkToBool(metrics.fFlags & SkAdvancedTypefaceMetrics::kVariable_FontFlag) ||
Ben Wagner2bc54472022-05-25 14:00:11 -0400182 // PDF is actually interested in the encoding of the data, not just the logical format.
183 // If the TrueType is actually wOFF or wOF2 then it should not be directly embedded in PDF.
184 // For now export these as Type3 until the subsetter can handle table based fonts.
185 // See https://github.com/harfbuzz/harfbuzz/issues/3609 and
186 // https://skia-review.googlesource.com/c/skia/+/543485
187 SkToBool(metrics.fFlags & SkAdvancedTypefaceMetrics::kAltDataFormat_FontFlag) ||
Hal Canaryb3480e12016-09-30 14:53:15 -0400188 SkToBool(metrics.fFlags & SkAdvancedTypefaceMetrics::kNotEmbeddable_FontFlag)) {
halcanarycee13422016-08-18 09:52:48 -0700189 // force Type3 fallback.
190 return SkAdvancedTypefaceMetrics::kOther_Font;
191 }
Dominik Röttsches2ed0bae2021-11-15 15:14:03 +0200192 if (typeface.getTableSize(kCOLRTableTag)) {
193 // https://bugs.chromium.org/p/skia/issues/detail?id=12650
194 // Don't embed COLRv0 / COLRv1 fonts, fall back to bitmaps.
195 return SkAdvancedTypefaceMetrics::kOther_Font;
196 }
halcanarycee13422016-08-18 09:52:48 -0700197 return metrics.fType;
198}
199
halcanary4871f222016-08-26 13:17:44 -0700200static SkGlyphID first_nonzero_glyph_for_single_byte_encoding(SkGlyphID gid) {
halcanarycee13422016-08-18 09:52:48 -0700201 return gid != 0 ? gid - (gid - 1) % 255 : 1;
202}
203
Hal Canaryb10f92e2018-11-16 17:01:50 -0500204SkPDFFont* SkPDFFont::GetFontResource(SkPDFDocument* doc,
Herb Derby02e91502019-07-03 10:57:33 -0400205 const SkGlyph* glyph,
206 SkTypeface* face) {
Hal Canaryb10f92e2018-11-16 17:01:50 -0500207 SkASSERT(doc);
halcanary4871f222016-08-26 13:17:44 -0700208 SkASSERT(face); // All SkPDFDevice::internalDrawText ensures this.
Hal Canary4ca9fa32018-12-21 16:15:01 -0500209 const SkAdvancedTypefaceMetrics* fontMetrics = SkPDFFont::GetMetrics(face, doc);
halcanary4871f222016-08-26 13:17:44 -0700210 SkASSERT(fontMetrics); // SkPDFDevice::internalDrawText ensures the typeface is good.
211 // GetMetrics only returns null to signify a bad typeface.
halcanarycee13422016-08-18 09:52:48 -0700212 const SkAdvancedTypefaceMetrics& metrics = *fontMetrics;
Dominik Röttsches2ed0bae2021-11-15 15:14:03 +0200213 SkAdvancedTypefaceMetrics::FontType type = SkPDFFont::FontType(*face, metrics);
Herb Derby02e91502019-07-03 10:57:33 -0400214 if (!(glyph->isEmpty() || glyph->path())) {
Hal Canary8ef78ea2018-10-01 13:38:30 -0400215 type = SkAdvancedTypefaceMetrics::kOther_Font;
216 }
halcanarycee13422016-08-18 09:52:48 -0700217 bool multibyte = SkPDFFont::IsMultiByte(type);
Herb Derby02e91502019-07-03 10:57:33 -0400218 SkGlyphID subsetCode =
219 multibyte ? 0 : first_nonzero_glyph_for_single_byte_encoding(glyph->getGlyphID());
Kevin Lubick04449cd2023-10-19 09:37:19 -0400220 uint64_t typefaceID = (static_cast<uint64_t>(face->uniqueID()) << 16) | subsetCode;
halcanarycee13422016-08-18 09:52:48 -0700221
Herb Derby25621442022-02-07 12:12:45 -0500222 if (SkPDFFont* found = doc->fFontMap.find(typefaceID)) {
Hal Canaryb10f92e2018-11-16 17:01:50 -0500223 SkASSERT(multibyte == found->multiByteGlyphs());
224 return found;
halcanarycee13422016-08-18 09:52:48 -0700225 }
226
halcanary4871f222016-08-26 13:17:44 -0700227 sk_sp<SkTypeface> typeface(sk_ref_sp(face));
halcanary7e8d5d32016-08-12 07:59:38 -0700228 SkASSERT(typeface);
halcanary4871f222016-08-26 13:17:44 -0700229
Hal Canaryaa3af7b2017-03-06 16:18:49 -0500230 SkGlyphID lastGlyph = SkToU16(typeface->countGlyphs() - 1);
halcanary4871f222016-08-26 13:17:44 -0700231
232 // should be caught by SkPDFDevice::internalDrawText
Herb Derby02e91502019-07-03 10:57:33 -0400233 SkASSERT(glyph->getGlyphID() <= lastGlyph);
halcanary32875882016-08-16 09:36:23 -0700234
halcanary530032a2016-08-18 14:22:52 -0700235 SkGlyphID firstNonZeroGlyph;
halcanary530032a2016-08-18 14:22:52 -0700236 if (multibyte) {
237 firstNonZeroGlyph = 1;
halcanary530032a2016-08-18 14:22:52 -0700238 } else {
halcanary4871f222016-08-26 13:17:44 -0700239 firstNonZeroGlyph = subsetCode;
Brian Osman788b9162020-02-07 10:36:46 -0500240 lastGlyph = SkToU16(std::min<int>((int)lastGlyph, 254 + (int)subsetCode));
halcanary530032a2016-08-18 14:22:52 -0700241 }
Hal Canary9a3f5542018-12-10 19:59:07 -0500242 auto ref = doc->reserveRef();
Hal Canary4ca9fa32018-12-21 16:15:01 -0500243 return doc->fFontMap.set(
Herb Derby25621442022-02-07 12:12:45 -0500244 typefaceID, SkPDFFont(std::move(typeface), firstNonZeroGlyph, lastGlyph, type, ref));
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000245}
246
Hal Canaryb10f92e2018-11-16 17:01:50 -0500247SkPDFFont::SkPDFFont(sk_sp<SkTypeface> typeface,
248 SkGlyphID firstGlyphID,
249 SkGlyphID lastGlyphID,
250 SkAdvancedTypefaceMetrics::FontType fontType,
251 SkPDFIndirectReference indirectReference)
252 : fTypeface(std::move(typeface))
253 , fGlyphUsage(firstGlyphID, lastGlyphID)
254 , fIndirectReference(indirectReference)
Ben Wagnere91f22352019-08-30 19:28:09 -0400255 , fFontType(fontType)
256{
257 // Always include glyph 0
258 this->noteGlyphUsage(0);
259}
vandebo@chromium.org98594282011-07-25 22:34:12 +0000260
Hal Canary2e904bc2019-04-18 15:40:27 -0400261void SkPDFFont::PopulateCommonFontDescriptor(SkPDFDict* descriptor,
262 const SkAdvancedTypefaceMetrics& metrics,
263 uint16_t emSize,
264 int16_t defaultWidth) {
Hal Canarye1fec192018-03-29 10:59:02 -0700265 descriptor->insertName("FontName", metrics.fPostScriptName);
halcanary28c6d832016-08-16 10:29:38 -0700266 descriptor->insertInt("Flags", (size_t)(metrics.fStyle | kPdfSymbolic));
267 descriptor->insertScalar("Ascent",
268 scaleFromFontUnits(metrics.fAscent, emSize));
269 descriptor->insertScalar("Descent",
270 scaleFromFontUnits(metrics.fDescent, emSize));
271 descriptor->insertScalar("StemV",
272 scaleFromFontUnits(metrics.fStemV, emSize));
273 descriptor->insertScalar("CapHeight",
274 scaleFromFontUnits(metrics.fCapHeight, emSize));
275 descriptor->insertInt("ItalicAngle", metrics.fItalicAngle);
Hal Canarye650b852018-09-12 09:12:36 -0400276 descriptor->insertObject("FontBBox",
277 SkPDFMakeArray(scaleFromFontUnits(metrics.fBBox.left(), emSize),
278 scaleFromFontUnits(metrics.fBBox.bottom(), emSize),
279 scaleFromFontUnits(metrics.fBBox.right(), emSize),
280 scaleFromFontUnits(metrics.fBBox.top(), emSize)));
vandebo@chromium.org98594282011-07-25 22:34:12 +0000281 if (defaultWidth > 0) {
halcanary28c6d832016-08-16 10:29:38 -0700282 descriptor->insertScalar("MissingWidth",
vandebo@chromium.org98594282011-07-25 22:34:12 +0000283 scaleFromFontUnits(defaultWidth, emSize));
284 }
vandebo@chromium.org98594282011-07-25 22:34:12 +0000285}
286
vandebo@chromium.org98594282011-07-25 22:34:12 +0000287///////////////////////////////////////////////////////////////////////////////
Hal Canaryb10f92e2018-11-16 17:01:50 -0500288// Type0Font
vandebo@chromium.org98594282011-07-25 22:34:12 +0000289///////////////////////////////////////////////////////////////////////////////
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000290
Hal Canaryb10f92e2018-11-16 17:01:50 -0500291static void emit_subset_type0(const SkPDFFont& font, SkPDFDocument* doc) {
halcanary530032a2016-08-18 14:22:52 -0700292 const SkAdvancedTypefaceMetrics* metricsPtr =
Hal Canary4ca9fa32018-12-21 16:15:01 -0500293 SkPDFFont::GetMetrics(font.typeface(), doc);
halcanary530032a2016-08-18 14:22:52 -0700294 SkASSERT(metricsPtr);
295 if (!metricsPtr) { return; }
296 const SkAdvancedTypefaceMetrics& metrics = *metricsPtr;
halcanarycee13422016-08-18 09:52:48 -0700297 SkASSERT(can_embed(metrics));
Hal Canaryb10f92e2018-11-16 17:01:50 -0500298 SkAdvancedTypefaceMetrics::FontType type = font.getType();
299 SkTypeface* face = font.typeface();
halcanary28c6d832016-08-16 10:29:38 -0700300 SkASSERT(face);
vandebo@chromium.org98594282011-07-25 22:34:12 +0000301
Hal Canary74801582018-12-18 16:30:41 -0500302 auto descriptor = SkPDFMakeDict("FontDescriptor");
Hal Canaryb10f92e2018-11-16 17:01:50 -0500303 uint16_t emSize = SkToU16(font.typeface()->getUnitsPerEm());
Ben Wagnere91f22352019-08-30 19:28:09 -0400304 SkPDFFont::PopulateCommonFontDescriptor(descriptor.get(), metrics, emSize, 0);
halcanaryfe8f0e02016-07-27 14:14:04 -0700305
halcanary426a2452016-09-08 15:04:38 -0700306 int ttcIndex;
Ben Wagnerff84d8a2019-02-26 15:39:41 -0500307 std::unique_ptr<SkStreamAsset> fontAsset = face->openStream(&ttcIndex);
halcanary426a2452016-09-08 15:04:38 -0700308 size_t fontSize = fontAsset ? fontAsset->getLength() : 0;
halcanary2a4d1e12016-09-22 14:13:16 -0700309 if (0 == fontSize) {
310 SkDebugf("Error: (SkTypeface)(%p)::openStream() returned "
311 "empty stream (%p) when identified as kType1CID_Font "
312 "or kTrueType_Font.\n", face, fontAsset.get());
313 } else {
halcanary426a2452016-09-08 15:04:38 -0700314 switch (type) {
Ben Wagner45eeedd2024-04-08 15:59:43 -0400315 case SkAdvancedTypefaceMetrics::kTrueType_Font:
316 case SkAdvancedTypefaceMetrics::kCFF_Font: {
halcanary426a2452016-09-08 15:04:38 -0700317 if (!SkToBool(metrics.fFlags &
318 SkAdvancedTypefaceMetrics::kNotSubsettable_FontFlag)) {
Hal Canaryb10f92e2018-11-16 17:01:50 -0500319 SkASSERT(font.firstGlyphID() == 1);
Ben Wagner84acad62022-05-25 09:41:01 -0400320 sk_sp<SkData> subsetFontData = SkPDFSubsetFont(*face, font.glyphUsage());
Hal Canary42d6c592018-11-15 14:01:49 -0500321 if (subsetFontData) {
Hal Canary74801582018-12-18 16:30:41 -0500322 std::unique_ptr<SkPDFDict> tmp = SkPDFMakeDict();
Hal Canary9a3f5542018-12-10 19:59:07 -0500323 tmp->insertInt("Length1", SkToInt(subsetFontData->size()));
324 descriptor->insertRef(
325 "FontFile2",
326 SkPDFStreamOut(std::move(tmp),
327 SkMemoryStream::Make(std::move(subsetFontData)),
Ben Wagner64560572022-11-17 17:18:33 -0500328 doc, SkPDFSteamCompressionEnabled::Yes));
halcanary426a2452016-09-08 15:04:38 -0700329 break;
330 }
331 // If subsetting fails, fall back to original font data.
halcanary28c6d832016-08-16 10:29:38 -0700332 }
Hal Canary74801582018-12-18 16:30:41 -0500333 std::unique_ptr<SkPDFDict> tmp = SkPDFMakeDict();
Hal Canary9a3f5542018-12-10 19:59:07 -0500334 tmp->insertInt("Length1", fontSize);
335 descriptor->insertRef("FontFile2",
336 SkPDFStreamOut(std::move(tmp), std::move(fontAsset),
Ben Wagner64560572022-11-17 17:18:33 -0500337 doc, SkPDFSteamCompressionEnabled::Yes));
halcanary426a2452016-09-08 15:04:38 -0700338 break;
halcanaryfe8f0e02016-07-27 14:14:04 -0700339 }
halcanary426a2452016-09-08 15:04:38 -0700340 case SkAdvancedTypefaceMetrics::kType1CID_Font: {
Hal Canary74801582018-12-18 16:30:41 -0500341 std::unique_ptr<SkPDFDict> tmp = SkPDFMakeDict();
Hal Canary9a3f5542018-12-10 19:59:07 -0500342 tmp->insertName("Subtype", "CIDFontType0C");
343 descriptor->insertRef("FontFile3",
344 SkPDFStreamOut(std::move(tmp), std::move(fontAsset),
Ben Wagner64560572022-11-17 17:18:33 -0500345 doc, SkPDFSteamCompressionEnabled::Yes));
halcanary426a2452016-09-08 15:04:38 -0700346 break;
halcanary8e3f54d2016-08-30 11:58:52 -0700347 }
halcanary426a2452016-09-08 15:04:38 -0700348 default:
349 SkASSERT(false);
halcanary8e3f54d2016-08-30 11:58:52 -0700350 }
vandebo@chromium.org98594282011-07-25 22:34:12 +0000351 }
vandebo@chromium.org98594282011-07-25 22:34:12 +0000352
Hal Canary74801582018-12-18 16:30:41 -0500353 auto newCIDFont = SkPDFMakeDict("Font");
Hal Canaryf34131a2018-12-18 15:11:03 -0500354 newCIDFont->insertRef("FontDescriptor", doc->emit(*descriptor));
Hal Canarye1fec192018-03-29 10:59:02 -0700355 newCIDFont->insertName("BaseFont", metrics.fPostScriptName);
halcanary28c6d832016-08-16 10:29:38 -0700356
halcanary426a2452016-09-08 15:04:38 -0700357 switch (type) {
358 case SkAdvancedTypefaceMetrics::kType1CID_Font:
359 newCIDFont->insertName("Subtype", "CIDFontType0");
360 break;
361 case SkAdvancedTypefaceMetrics::kTrueType_Font:
Ben Wagner45eeedd2024-04-08 15:59:43 -0400362 case SkAdvancedTypefaceMetrics::kCFF_Font:
halcanary426a2452016-09-08 15:04:38 -0700363 newCIDFont->insertName("Subtype", "CIDFontType2");
364 newCIDFont->insertName("CIDToGIDMap", "Identity");
365 break;
366 default:
367 SkASSERT(false);
halcanary462d0142016-08-05 13:51:46 -0700368 }
Hal Canary74801582018-12-18 16:30:41 -0500369 auto sysInfo = SkPDFMakeDict();
Ben Wagner225c8862022-05-23 17:45:13 -0400370 // These are actually ASCII strings.
371 sysInfo->insertByteString("Registry", "Adobe");
372 sysInfo->insertByteString("Ordering", "Identity");
halcanary28c6d832016-08-16 10:29:38 -0700373 sysInfo->insertInt("Supplement", 0);
374 newCIDFont->insertObject("CIDSystemInfo", std::move(sysInfo));
375
Ben Wagner53da9c52023-06-08 13:57:11 -0400376 // Unfortunately, poppler enforces DW (default width) must be an integer.
377 int32_t defaultWidth = 0;
halcanary86b6eab2016-08-17 07:57:27 -0700378 {
Hal Canary74801582018-12-18 16:30:41 -0500379 std::unique_ptr<SkPDFArray> widths = SkPDFMakeCIDGlyphWidthsArray(
Ben Wagnere91f22352019-08-30 19:28:09 -0400380 *face, font.glyphUsage(), &defaultWidth);
halcanary86b6eab2016-08-17 07:57:27 -0700381 if (widths && widths->size() > 0) {
382 newCIDFont->insertObject("W", std::move(widths));
383 }
Ben Wagner53da9c52023-06-08 13:57:11 -0400384 newCIDFont->insertInt("DW", defaultWidth);
halcanary28c6d832016-08-16 10:29:38 -0700385 }
386
halcanary28c6d832016-08-16 10:29:38 -0700387 ////////////////////////////////////////////////////////////////////////////
388
Hal Canaryb10f92e2018-11-16 17:01:50 -0500389 SkPDFDict fontDict("Font");
390 fontDict.insertName("Subtype", "Type0");
391 fontDict.insertName("BaseFont", metrics.fPostScriptName);
392 fontDict.insertName("Encoding", "Identity-H");
Hal Canary74801582018-12-18 16:30:41 -0500393 auto descendantFonts = SkPDFMakeArray();
Hal Canaryf34131a2018-12-18 15:11:03 -0500394 descendantFonts->appendRef(doc->emit(*newCIDFont));
Hal Canaryb10f92e2018-11-16 17:01:50 -0500395 fontDict.insertObject("DescendantFonts", std::move(descendantFonts));
halcanarycee13422016-08-18 09:52:48 -0700396
Hal Canary46cc3da2018-05-09 11:50:34 -0400397 const std::vector<SkUnichar>& glyphToUnicode =
Hal Canary4ca9fa32018-12-21 16:15:01 -0500398 SkPDFFont::GetUnicodeMap(font.typeface(), doc);
Hal Canaryb10f92e2018-11-16 17:01:50 -0500399 SkASSERT(SkToSizeT(font.typeface()->countGlyphs()) == glyphToUnicode.size());
Hal Canary9a3f5542018-12-10 19:59:07 -0500400 std::unique_ptr<SkStreamAsset> toUnicode =
401 SkPDFMakeToUnicodeCmap(glyphToUnicode.data(),
402 &font.glyphUsage(),
403 font.multiByteGlyphs(),
404 font.firstGlyphID(),
405 font.lastGlyphID());
406 fontDict.insertRef("ToUnicode", SkPDFStreamOut(nullptr, std::move(toUnicode), doc));
Hal Canaryb10f92e2018-11-16 17:01:50 -0500407
Hal Canary9a3f5542018-12-10 19:59:07 -0500408 doc->emit(fontDict, font.indirectReference());
halcanary8eccc302016-08-09 13:04:34 -0700409}
410
vandebo@chromium.org98594282011-07-25 22:34:12 +0000411///////////////////////////////////////////////////////////////////////////////
Hal Canaryb10f92e2018-11-16 17:01:50 -0500412// PDFType3Font
vandebo@chromium.org98594282011-07-25 22:34:12 +0000413///////////////////////////////////////////////////////////////////////////////
414
halcanary7e8d5d32016-08-12 07:59:38 -0700415namespace {
416// returns [0, first, first+1, ... last-1, last]
417struct SingleByteGlyphIdIterator {
418 SingleByteGlyphIdIterator(SkGlyphID first, SkGlyphID last)
419 : fFirst(first), fLast(last) {
420 SkASSERT(fFirst > 0);
421 SkASSERT(fLast >= first);
422 }
423 struct Iter {
424 void operator++() {
425 fCurrent = (0 == fCurrent) ? fFirst : fCurrent + 1;
426 }
427 // This is an input_iterator
428 SkGlyphID operator*() const { return (SkGlyphID)fCurrent; }
429 bool operator!=(const Iter& rhs) const {
430 return fCurrent != rhs.fCurrent;
431 }
432 Iter(SkGlyphID f, int c) : fFirst(f), fCurrent(c) {}
433 private:
434 const SkGlyphID fFirst;
435 int fCurrent; // must be int to make fLast+1 to fit
436 };
437 Iter begin() const { return Iter(fFirst, 0); }
438 Iter end() const { return Iter(fFirst, (int)fLast + 1); }
439private:
440 const SkGlyphID fFirst;
441 const SkGlyphID fLast;
442};
John Stilesa6841be2020-08-06 14:11:56 -0400443} // namespace
vandebo@chromium.org98594282011-07-25 22:34:12 +0000444
Hal Canary8ef78ea2018-10-01 13:38:30 -0400445struct ImageAndOffset {
446 sk_sp<SkImage> fImage;
447 SkIPoint fOffset;
448};
Herb Derbycb443a52019-11-11 18:01:36 -0500449static ImageAndOffset to_image(SkGlyphID gid, SkBulkGlyphMetricsAndImages* smallGlyphs) {
450 const SkGlyph* glyph = smallGlyphs->glyph(SkPackedGlyphID{gid});
herb252cdb72019-11-07 12:20:10 -0500451 SkMask mask = glyph->mask();
Hal Canary8ef78ea2018-10-01 13:38:30 -0400452 if (!mask.fImage) {
453 return {nullptr, {0, 0}};
454 }
455 SkIRect bounds = mask.fBounds;
456 SkBitmap bm;
457 switch (mask.fFormat) {
458 case SkMask::kBW_Format:
459 bm.allocPixels(SkImageInfo::MakeA8(bounds.width(), bounds.height()));
460 for (int y = 0; y < bm.height(); ++y) {
461 for (int x8 = 0; x8 < bm.width(); x8 += 8) {
462 uint8_t v = *mask.getAddr1(x8 + bounds.x(), y + bounds.y());
Brian Osman788b9162020-02-07 10:36:46 -0500463 int e = std::min(x8 + 8, bm.width());
Hal Canary8ef78ea2018-10-01 13:38:30 -0400464 for (int x = x8; x < e; ++x) {
465 *bm.getAddr8(x, y) = (v >> (x & 0x7)) & 0x1 ? 0xFF : 0x00;
466 }
467 }
468 }
469 bm.setImmutable();
Mike Reeddc607e32020-12-23 11:50:36 -0500470 return {bm.asImage(), {bounds.x(), bounds.y()}};
Hal Canary8ef78ea2018-10-01 13:38:30 -0400471 case SkMask::kA8_Format:
Ben Wagner6cf423f2023-08-01 16:05:08 -0400472 return {SkImages::RasterFromData(
473 SkImageInfo::MakeA8(bounds.width(), bounds.height()),
474 SkData::MakeWithCopy(mask.fImage, mask.computeTotalImageSize()),
475 mask.fRowBytes),
Hal Canary8ef78ea2018-10-01 13:38:30 -0400476 {bounds.x(), bounds.y()}};
477 case SkMask::kARGB32_Format:
Ben Wagner6cf423f2023-08-01 16:05:08 -0400478 return {SkImages::RasterFromData(
479 SkImageInfo::MakeN32Premul(bounds.width(), bounds.height()),
480 SkData::MakeWithCopy(mask.fImage, mask.computeTotalImageSize()),
481 mask.fRowBytes),
Hal Canary8ef78ea2018-10-01 13:38:30 -0400482 {bounds.x(), bounds.y()}};
483 case SkMask::k3D_Format:
484 case SkMask::kLCD16_Format:
485 default:
486 SkASSERT(false);
487 return {nullptr, {0, 0}};
488 }
489}
Hal Canaryb3907a82018-12-17 09:53:30 -0500490
Hal Canaryb10f92e2018-11-16 17:01:50 -0500491static SkPDFIndirectReference type3_descriptor(SkPDFDocument* doc,
492 const SkTypeface* typeface,
Herb Derbycb443a52019-11-11 18:01:36 -0500493 SkScalar xHeight) {
Hal Canary4ca9fa32018-12-21 16:15:01 -0500494 if (SkPDFIndirectReference* ptr = doc->fType3FontDescriptors.find(typeface->uniqueID())) {
Hal Canaryb10f92e2018-11-16 17:01:50 -0500495 return *ptr;
496 }
497
498 SkPDFDict descriptor("FontDescriptor");
499 int32_t fontDescriptorFlags = kPdfSymbolic;
Ben Wagner4f6bdf82024-04-08 17:08:27 -0400500
501 /** PDF32000_2008: FontFamily should be used for Type3 fonts in Tagged PDF documents. */
502 SkString familyName;
503 typeface->getFamilyName(&familyName);
504 if (!familyName.isEmpty()) {
505 descriptor.insertByteString("FontFamily", familyName);
506 }
507
508 /** PDF32000_2008: FontStretch should be used for Type3 fonts in Tagged PDF documents. */
509 static constexpr const char* stretchNames[9] = {
510 "UltraCondensed",
511 "ExtraCondensed",
512 "Condensed",
513 "SemiCondensed",
514 "Normal",
515 "SemiExpanded",
516 "Expanded",
517 "ExtraExpanded",
518 "UltraExpanded",
519 };
520 const char* stretchName = stretchNames[typeface->fontStyle().width() - 1];
521 descriptor.insertName("FontStretch", stretchName);
522
523 /** PDF32000_2008: FontWeight should be used for Type3 fonts in Tagged PDF documents. */
524 int weight = (typeface->fontStyle().weight() + 50) / 100;
525 descriptor.insertInt("FontWeight", SkTPin(weight, 1, 9) * 100);
526
Hal Canary4ca9fa32018-12-21 16:15:01 -0500527 if (const SkAdvancedTypefaceMetrics* metrics = SkPDFFont::GetMetrics(typeface, doc)) {
Hal Canaryb10f92e2018-11-16 17:01:50 -0500528 // Type3 FontDescriptor does not require all the same fields.
529 descriptor.insertName("FontName", metrics->fPostScriptName);
530 descriptor.insertInt("ItalicAngle", metrics->fItalicAngle);
531 fontDescriptorFlags |= (int32_t)metrics->fStyle;
532 // Adobe requests CapHeight, XHeight, and StemV be added
533 // to "greatly help our workflow downstream".
534 if (metrics->fCapHeight != 0) { descriptor.insertInt("CapHeight", metrics->fCapHeight); }
535 if (metrics->fStemV != 0) { descriptor.insertInt("StemV", metrics->fStemV); }
Hal Canaryb10f92e2018-11-16 17:01:50 -0500536 if (xHeight != 0) {
537 descriptor.insertScalar("XHeight", xHeight);
538 }
539 }
540 descriptor.insertInt("Flags", fontDescriptorFlags);
541 SkPDFIndirectReference ref = doc->emit(descriptor);
Hal Canary4ca9fa32018-12-21 16:15:01 -0500542 doc->fType3FontDescriptors.set(typeface->uniqueID(), ref);
Hal Canaryb10f92e2018-11-16 17:01:50 -0500543 return ref;
544}
545
Hal Canary5c41f362019-09-30 10:54:54 -0400546#ifdef SK_PDF_BITMAP_GLYPH_RASTER_SIZE
547static constexpr float kBitmapFontSize = SK_PDF_BITMAP_GLYPH_RASTER_SIZE;
548#else
549static constexpr float kBitmapFontSize = 64;
550#endif
551
552SkStrikeSpec make_small_strike(const SkTypeface& typeface) {
553 SkFont font(sk_ref_sp(&typeface), kBitmapFontSize);
554 font.setHinting(SkFontHinting::kNone);
555 font.setEdging(SkFont::Edging::kAlias);
556 return SkStrikeSpec::MakeMask(font,
557 SkPaint(),
Kurt Catti-Schmidt (SCHMIDT)0e0e00e2023-12-12 16:46:43 -0800558 SkSurfaceProps(),
Ben Wagner6c630f22022-03-07 23:06:02 -0500559 SkScalerContextFlags::kFakeGammaAndBoostContrast,
Hal Canary5c41f362019-09-30 10:54:54 -0400560 SkMatrix::I());
561}
Hal Canaryb10f92e2018-11-16 17:01:50 -0500562
563static void emit_subset_type3(const SkPDFFont& pdfFont, SkPDFDocument* doc) {
564 SkTypeface* typeface = pdfFont.typeface();
565 SkGlyphID firstGlyphID = pdfFont.firstGlyphID();
566 SkGlyphID lastGlyphID = pdfFont.lastGlyphID();
567 const SkPDFGlyphUse& subset = pdfFont.glyphUsage();
halcanary7e8d5d32016-08-12 07:59:38 -0700568 SkASSERT(lastGlyphID >= firstGlyphID);
halcanary17484322016-08-29 09:47:48 -0700569 // Remove unused glyphs at the end of the range.
570 // Keep the lastGlyphID >= firstGlyphID invariant true.
571 while (lastGlyphID > firstGlyphID && !subset.has(lastGlyphID)) {
572 --lastGlyphID;
573 }
Hal Canaryaa3af7b2017-03-06 16:18:49 -0500574 int unitsPerEm;
Herb Derby36a54c12019-06-06 10:50:56 -0400575 SkStrikeSpec strikeSpec = SkStrikeSpec::MakePDFVector(*typeface, &unitsPerEm);
Herb Derbya64f5b22020-02-24 14:35:51 -0500576 auto strike = strikeSpec.findOrCreateStrike();
577 SkASSERT(strike);
Hal Canaryaa3af7b2017-03-06 16:18:49 -0500578 SkScalar emSize = (SkScalar)unitsPerEm;
Herb Derbya64f5b22020-02-24 14:35:51 -0500579 SkScalar xHeight = strike->getFontMetrics().fXHeight;
Ben Wagner4e8b2352023-01-31 17:00:56 -0500580 SkBulkGlyphMetricsAndPaths metricsAndPaths((sk_sp<SkStrike>(strike)));
581 SkBulkGlyphMetricsAndDrawables metricsAndDrawables(std::move(strike));
Hal Canaryb10f92e2018-11-16 17:01:50 -0500582
Hal Canary5c41f362019-09-30 10:54:54 -0400583 SkStrikeSpec strikeSpecSmall = kBitmapFontSize > 0 ? make_small_strike(*typeface)
584 : strikeSpec;
Herb Derbycb443a52019-11-11 18:01:36 -0500585
586 SkBulkGlyphMetricsAndImages smallGlyphs(strikeSpecSmall);
Hal Canary5c41f362019-09-30 10:54:54 -0400587 float bitmapScale = kBitmapFontSize > 0 ? emSize / kBitmapFontSize : 1.0f;
588
Hal Canaryb10f92e2018-11-16 17:01:50 -0500589 SkPDFDict font("Font");
590 font.insertName("Subtype", "Type3");
halcanary7e8d5d32016-08-12 07:59:38 -0700591 // Flip about the x-axis and scale by 1/emSize.
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000592 SkMatrix fontMatrix;
halcanary7e8d5d32016-08-12 07:59:38 -0700593 fontMatrix.setScale(SkScalarInvert(emSize), -SkScalarInvert(emSize));
Hal Canaryb10f92e2018-11-16 17:01:50 -0500594 font.insertObject("FontMatrix", SkPDFUtils::MatrixToArray(fontMatrix));
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000595
Hal Canary74801582018-12-18 16:30:41 -0500596 auto charProcs = SkPDFMakeDict();
597 auto encoding = SkPDFMakeDict("Encoding");
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000598
Hal Canary74801582018-12-18 16:30:41 -0500599 auto encDiffs = SkPDFMakeArray();
halcanary7e8d5d32016-08-12 07:59:38 -0700600 // length(firstGlyphID .. lastGlyphID) == lastGlyphID - firstGlyphID + 1
601 // plus 1 for glyph 0;
602 SkASSERT(firstGlyphID > 0);
603 SkASSERT(lastGlyphID >= firstGlyphID);
604 int glyphCount = lastGlyphID - firstGlyphID + 2;
605 // one other entry for the index of first glyph.
606 encDiffs->reserve(glyphCount + 1);
607 encDiffs->appendInt(0); // index of first glyph
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000608
Hal Canary74801582018-12-18 16:30:41 -0500609 auto widthArray = SkPDFMakeArray();
halcanary7e8d5d32016-08-12 07:59:38 -0700610 widthArray->reserve(glyphCount);
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000611
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000612 SkIRect bbox = SkIRect::MakeEmpty();
halcanary7e8d5d32016-08-12 07:59:38 -0700613
Hal Canaryb3907a82018-12-17 09:53:30 -0500614 std::vector<std::pair<SkGlyphID, SkPDFIndirectReference>> imageGlyphs;
halcanary7e8d5d32016-08-12 07:59:38 -0700615 for (SkGlyphID gID : SingleByteGlyphIdIterator(firstGlyphID, lastGlyphID)) {
halcanary530032a2016-08-18 14:22:52 -0700616 bool skipGlyph = gID != 0 && !subset.has(gID);
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000617 SkString characterName;
halcanary7e8d5d32016-08-12 07:59:38 -0700618 SkScalar advance = 0.0f;
619 SkIRect glyphBBox;
620 if (skipGlyph) {
621 characterName.set("g0");
622 } else {
623 characterName.printf("g%X", gID);
Ben Wagner4e8b2352023-01-31 17:00:56 -0500624 const SkGlyph* pathGlyph = metricsAndPaths.glyph(gID);
625 const SkGlyph* drawableGlyph = metricsAndDrawables.glyph(gID);
626 advance = pathGlyph->advanceX();
627 glyphBBox = pathGlyph->iRect();
halcanary7e8d5d32016-08-12 07:59:38 -0700628 bbox.join(glyphBBox);
Ben Wagner4e8b2352023-01-31 17:00:56 -0500629 const SkPath* path = pathGlyph->path();
630 SkDrawable* drawable = drawableGlyph->drawable();
Hal Canaryb3907a82018-12-17 09:53:30 -0500631 SkDynamicMemoryWStream content;
Ben Wagner4e8b2352023-01-31 17:00:56 -0500632 if (drawable && !drawable->getBounds().isEmpty()) {
633 sk_sp<SkPDFDevice> glyphDevice = sk_make_sp<SkPDFDevice>(glyphBBox.size(), doc);
634 SkCanvas canvas(glyphDevice);
635 canvas.translate(-glyphBBox.fLeft, -glyphBBox.fTop);
636 canvas.drawDrawable(drawable);
637 SkPDFIndirectReference xobject = SkPDFMakeFormXObject(
638 doc, glyphDevice->content(),
639 SkPDFMakeArray(0, 0, glyphBBox.width(), glyphBBox.height()),
640 glyphDevice->makeResourceDict(),
641 SkMatrix::Translate(glyphBBox.fLeft, glyphBBox.fTop), nullptr);
642 imageGlyphs.emplace_back(gID, xobject);
643 SkPDFUtils::AppendScalar(drawableGlyph->advanceX(), &content);
644 content.writeText(" 0 d0\n1 0 0 1 0 0 cm\n/X");
645 content.write(characterName.c_str(), characterName.size());
646 content.writeText(" Do\n");
647 } else if (path && !path->isEmpty()) {
648 setGlyphWidthAndBoundingBox(pathGlyph->advanceX(), glyphBBox, &content);
halcanary7e8d5d32016-08-12 07:59:38 -0700649 SkPDFUtils::EmitPath(*path, SkPaint::kFill_Style, &content);
Mike Reedcf0e3c62019-12-03 16:26:15 -0500650 SkPDFUtils::PaintPath(SkPaint::kFill_Style, path->getFillType(), &content);
halcanary7e8d5d32016-08-12 07:59:38 -0700651 } else {
Herb Derbycb443a52019-11-11 18:01:36 -0500652 auto pimg = to_image(gID, &smallGlyphs);
Hal Canary8ef78ea2018-10-01 13:38:30 -0400653 if (!pimg.fImage) {
Ben Wagner4e8b2352023-01-31 17:00:56 -0500654 setGlyphWidthAndBoundingBox(pathGlyph->advanceX(), glyphBBox, &content);
Hal Canary8ef78ea2018-10-01 13:38:30 -0400655 } else {
Hal Canary5c41f362019-09-30 10:54:54 -0400656 using SkPDFUtils::AppendScalar;
Hal Canaryb3907a82018-12-17 09:53:30 -0500657 imageGlyphs.emplace_back(gID, SkPDFSerializeImage(pimg.fImage.get(), doc));
Ben Wagner4e8b2352023-01-31 17:00:56 -0500658 AppendScalar(pathGlyph->advanceX(), &content);
Hal Canary8ef78ea2018-10-01 13:38:30 -0400659 content.writeText(" 0 d0\n");
Hal Canary5c41f362019-09-30 10:54:54 -0400660 AppendScalar(pimg.fImage->width() * bitmapScale, &content);
Hal Canary8ef78ea2018-10-01 13:38:30 -0400661 content.writeText(" 0 0 ");
Hal Canary5c41f362019-09-30 10:54:54 -0400662 AppendScalar(-pimg.fImage->height() * bitmapScale, &content);
Hal Canary8ef78ea2018-10-01 13:38:30 -0400663 content.writeText(" ");
Hal Canary5c41f362019-09-30 10:54:54 -0400664 AppendScalar(pimg.fOffset.x() * bitmapScale, &content);
Hal Canary8ef78ea2018-10-01 13:38:30 -0400665 content.writeText(" ");
Hal Canary5c41f362019-09-30 10:54:54 -0400666 AppendScalar((pimg.fImage->height() + pimg.fOffset.y()) * bitmapScale,
667 &content);
Hal Canaryb3907a82018-12-17 09:53:30 -0500668 content.writeText(" cm\n/X");
669 content.write(characterName.c_str(), characterName.size());
670 content.writeText(" Do\n");
halcanary7e8d5d32016-08-12 07:59:38 -0700671 }
halcanary7e8d5d32016-08-12 07:59:38 -0700672 }
Hal Canary9a3f5542018-12-10 19:59:07 -0500673 charProcs->insertRef(characterName, SkPDFStreamOut(nullptr,
674 content.detachAsStream(), doc));
halcanary5bf60ad2016-08-11 13:59:18 -0700675 }
Hal Canaryb10f92e2018-11-16 17:01:50 -0500676 encDiffs->appendName(std::move(characterName));
halcanary7e8d5d32016-08-12 07:59:38 -0700677 widthArray->appendScalar(advance);
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000678 }
679
Hal Canaryb3907a82018-12-17 09:53:30 -0500680 if (!imageGlyphs.empty()) {
Hal Canary74801582018-12-18 16:30:41 -0500681 auto d0 = SkPDFMakeDict();
Hal Canaryb3907a82018-12-17 09:53:30 -0500682 for (const auto& pair : imageGlyphs) {
683 d0->insertRef(SkStringPrintf("Xg%X", pair.first), pair.second);
684 }
Hal Canary74801582018-12-18 16:30:41 -0500685 auto d1 = SkPDFMakeDict();
Hal Canaryb3907a82018-12-17 09:53:30 -0500686 d1->insertObject("XObject", std::move(d0));
687 font.insertObject("Resources", std::move(d1));
688 }
689
halcanary8103a342016-03-08 15:10:16 -0800690 encoding->insertObject("Differences", std::move(encDiffs));
Hal Canaryb10f92e2018-11-16 17:01:50 -0500691 font.insertInt("FirstChar", 0);
692 font.insertInt("LastChar", lastGlyphID - firstGlyphID + 1);
halcanary7e8d5d32016-08-12 07:59:38 -0700693 /* FontBBox: "A rectangle expressed in the glyph coordinate
694 system, specifying the font bounding box. This is the smallest
695 rectangle enclosing the shape that would result if all of the
696 glyphs of the font were placed with their origins coincident and
697 then filled." */
Hal Canaryb10f92e2018-11-16 17:01:50 -0500698 font.insertObject("FontBBox", SkPDFMakeArray(bbox.left(),
Hal Canarye650b852018-09-12 09:12:36 -0400699 bbox.bottom(),
700 bbox.right(),
701 bbox.top()));
702
Hal Canaryb10f92e2018-11-16 17:01:50 -0500703 font.insertName("CIDToGIDMap", "Identity");
Hal Canary46cc3da2018-05-09 11:50:34 -0400704
Hal Canary4ca9fa32018-12-21 16:15:01 -0500705 const std::vector<SkUnichar>& glyphToUnicode = SkPDFFont::GetUnicodeMap(typeface, doc);
Hal Canary46cc3da2018-05-09 11:50:34 -0400706 SkASSERT(glyphToUnicode.size() == SkToSizeT(typeface->countGlyphs()));
Hal Canary9a3f5542018-12-10 19:59:07 -0500707 auto toUnicodeCmap = SkPDFMakeToUnicodeCmap(glyphToUnicode.data(),
708 &subset,
709 false,
710 firstGlyphID,
711 lastGlyphID);
712 font.insertRef("ToUnicode", SkPDFStreamOut(nullptr, std::move(toUnicodeCmap), doc));
Herb Derbycb443a52019-11-11 18:01:36 -0500713 font.insertRef("FontDescriptor", type3_descriptor(doc, typeface, xHeight));
Hal Canaryb10f92e2018-11-16 17:01:50 -0500714 font.insertObject("Widths", std::move(widthArray));
715 font.insertObject("Encoding", std::move(encoding));
716 font.insertObject("CharProcs", std::move(charProcs));
717
Hal Canary9a3f5542018-12-10 19:59:07 -0500718 doc->emit(font, pdfFont.indirectReference());
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000719}
halcanaryfb62b3d2015-01-21 09:59:14 -0800720
Hal Canaryb10f92e2018-11-16 17:01:50 -0500721void SkPDFFont::emitSubset(SkPDFDocument* doc) const {
Hal Canaryb10f92e2018-11-16 17:01:50 -0500722 switch (fFontType) {
723 case SkAdvancedTypefaceMetrics::kType1CID_Font:
724 case SkAdvancedTypefaceMetrics::kTrueType_Font:
Ben Wagner45eeedd2024-04-08 15:59:43 -0400725 case SkAdvancedTypefaceMetrics::kCFF_Font:
Hal Canaryb10f92e2018-11-16 17:01:50 -0500726 return emit_subset_type0(*this, doc);
Hal Canary2e904bc2019-04-18 15:40:27 -0400727#ifndef SK_PDF_DO_NOT_SUPPORT_TYPE_1_FONTS
Hal Canaryb10f92e2018-11-16 17:01:50 -0500728 case SkAdvancedTypefaceMetrics::kType1_Font:
Hal Canary2e904bc2019-04-18 15:40:27 -0400729 return SkPDFEmitType1Font(*this, doc);
730#endif
Hal Canaryb10f92e2018-11-16 17:01:50 -0500731 default:
732 return emit_subset_type3(*this, doc);
733 }
halcanary7e8d5d32016-08-12 07:59:38 -0700734}
735
halcanary7e8d5d32016-08-12 07:59:38 -0700736////////////////////////////////////////////////////////////////////////////////
737
Hal Canary4ca9fa32018-12-21 16:15:01 -0500738bool SkPDFFont::CanEmbedTypeface(SkTypeface* typeface, SkPDFDocument* doc) {
739 const SkAdvancedTypefaceMetrics* metrics = SkPDFFont::GetMetrics(typeface, doc);
halcanarycee13422016-08-18 09:52:48 -0700740 return metrics && can_embed(*metrics);
halcanary66a82f32015-10-12 13:05:04 -0700741}
halcanarybae235e2016-03-21 10:05:23 -0700742