blob: 8fd833e716f12e57f934afe526cace809fb69e5a [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
reed@google.com8a85d0c2011-06-24 19:12:12 +00008#include "SkData.h"
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +00009#include "SkGlyphCache.h"
Hal Canary209e4b12017-05-04 14:23:55 -040010#include "SkMakeUnique.h"
halcanaryfb62b3d2015-01-21 09:59:14 -080011#include "SkPDFCanon.h"
halcanary8eccc302016-08-09 13:04:34 -070012#include "SkPDFConvertType1FontStream.h"
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +000013#include "SkPDFDevice.h"
Hal Canary209e4b12017-05-04 14:23:55 -040014#include "SkPDFFont.h"
halcanary86b6eab2016-08-17 07:57:27 -070015#include "SkPDFMakeCIDGlyphWidthsArray.h"
halcanary8eccc302016-08-09 13:04:34 -070016#include "SkPDFMakeToUnicodeCmap.h"
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +000017#include "SkPDFUtils.h"
Hal Canary209e4b12017-05-04 14:23:55 -040018#include "SkPaint.h"
vandebo@chromium.orgf77e27d2011-03-10 22:50:28 +000019#include "SkRefCnt.h"
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +000020#include "SkScalar.h"
vandebo@chromium.org2a22e102011-01-25 21:01:34 +000021#include "SkStream.h"
vandebo@chromium.org325cb9a2011-03-30 18:36:29 +000022#include "SkTypes.h"
vandebo@chromium.org28be72b2010-11-11 21:37:00 +000023#include "SkUtils.h"
24
halcanary650e20d2016-08-25 09:07:02 -070025#ifdef SK_PDF_USE_SFNTLY
26 #include "sample/chromium/font_subsetter.h"
vandebo@chromium.org1f165892011-07-26 02:11:41 +000027#endif
28
Hal Canaryaa3af7b2017-03-06 16:18:49 -050029SkAutoGlyphCache SkPDFFont::MakeVectorCache(SkTypeface* face, int* size) {
30 SkPaint tmpPaint;
31 tmpPaint.setHinting(SkPaint::kNo_Hinting);
32 tmpPaint.setTypeface(sk_ref_sp(face));
33 int unitsPerEm = face->getUnitsPerEm();
34 if (unitsPerEm <= 0) {
35 unitsPerEm = 1024;
36 }
37 if (size) {
38 *size = unitsPerEm;
39 }
40 tmpPaint.setTextSize((SkScalar)unitsPerEm);
41 const SkSurfaceProps props(0, kUnknown_SkPixelGeometry);
42 SkAutoGlyphCache glyphCache(tmpPaint, &props, nullptr);
43 SkASSERT(glyphCache.get());
44 return glyphCache;
45}
46
halcanary8eccc302016-08-09 13:04:34 -070047namespace {
vandebo@chromium.orgdcf9c192013-03-13 20:01:51 +000048// PDF's notion of symbolic vs non-symbolic is related to the character set, not
49// symbols vs. characters. Rarely is a font the right character set to call it
50// non-symbolic, so always call it symbolic. (PDF 1.4 spec, section 5.7.1)
halcanary3d01c622016-08-31 12:52:35 -070051static const int32_t kPdfSymbolic = 4;
vandebo@chromium.orgdcf9c192013-03-13 20:01:51 +000052
halcanary530032a2016-08-18 14:22:52 -070053struct SkPDFType0Font final : public SkPDFFont {
54 SkPDFType0Font(SkPDFFont::Info, const SkAdvancedTypefaceMetrics&);
Brian Salomond3b65972017-03-22 12:05:03 -040055 ~SkPDFType0Font() override;
halcanary530032a2016-08-18 14:22:52 -070056 void getFontSubset(SkPDFCanon*) override;
halcanary8eccc302016-08-09 13:04:34 -070057#ifdef SK_DEBUG
halcanary530032a2016-08-18 14:22:52 -070058 void emitObject(SkWStream*, const SkPDFObjNumMap&) const override;
halcanary8eccc302016-08-09 13:04:34 -070059 bool fPopulated;
60#endif
halcanary8eccc302016-08-09 13:04:34 -070061 typedef SkPDFDict INHERITED;
62};
63
halcanary530032a2016-08-18 14:22:52 -070064struct SkPDFType1Font final : public SkPDFFont {
65 SkPDFType1Font(SkPDFFont::Info, const SkAdvancedTypefaceMetrics&, SkPDFCanon*);
Brian Salomond3b65972017-03-22 12:05:03 -040066 ~SkPDFType1Font() override {}
halcanary530032a2016-08-18 14:22:52 -070067 void getFontSubset(SkPDFCanon*) override {} // TODO(halcanary): implement
halcanary8eccc302016-08-09 13:04:34 -070068};
69
halcanary530032a2016-08-18 14:22:52 -070070struct SkPDFType3Font final : public SkPDFFont {
71 SkPDFType3Font(SkPDFFont::Info, const SkAdvancedTypefaceMetrics&);
Brian Salomond3b65972017-03-22 12:05:03 -040072 ~SkPDFType3Font() override {}
halcanary530032a2016-08-18 14:22:52 -070073 void getFontSubset(SkPDFCanon*) override;
halcanary8eccc302016-08-09 13:04:34 -070074};
vandebo@chromium.org28be72b2010-11-11 21:37:00 +000075
vandebo@chromium.org98594282011-07-25 22:34:12 +000076///////////////////////////////////////////////////////////////////////////////
77// File-Local Functions
78///////////////////////////////////////////////////////////////////////////////
79
reed@google.com3f0dcf92011-03-18 21:23:45 +000080// scale from em-units to base-1000, returning as a SkScalar
halcanary8eccc302016-08-09 13:04:34 -070081SkScalar from_font_units(SkScalar scaled, uint16_t emSize) {
reed@google.com3f0dcf92011-03-18 21:23:45 +000082 if (emSize == 1000) {
83 return scaled;
84 } else {
Mike Reed8be952a2017-02-13 20:44:33 -050085 return scaled * 1000 / emSize;
reed@google.com3f0dcf92011-03-18 21:23:45 +000086 }
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +000087}
88
halcanary8eccc302016-08-09 13:04:34 -070089SkScalar scaleFromFontUnits(int16_t val, uint16_t emSize) {
90 return from_font_units(SkIntToScalar(val), emSize);
91}
92
93
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +000094void setGlyphWidthAndBoundingBox(SkScalar width, SkIRect box,
halcanary7e8d5d32016-08-12 07:59:38 -070095 SkDynamicMemoryWStream* content) {
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +000096 // Specify width and bounding box for the glyph.
halcanarybc4696b2015-05-06 10:56:04 -070097 SkPDFUtils::AppendScalar(width, content);
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +000098 content->writeText(" 0 ");
99 content->writeDecAsText(box.fLeft);
100 content->writeText(" ");
101 content->writeDecAsText(box.fTop);
102 content->writeText(" ");
103 content->writeDecAsText(box.fRight);
104 content->writeText(" ");
105 content->writeDecAsText(box.fBottom);
106 content->writeText(" d1\n");
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000107}
108
halcanary8103a342016-03-08 15:10:16 -0800109static sk_sp<SkPDFArray> makeFontBBox(SkIRect glyphBBox, uint16_t emSize) {
110 auto bbox = sk_make_sp<SkPDFArray>();
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000111 bbox->reserve(4);
reed@google.comc789cf12011-07-20 12:14:33 +0000112 bbox->appendScalar(scaleFromFontUnits(glyphBBox.fLeft, emSize));
113 bbox->appendScalar(scaleFromFontUnits(glyphBBox.fBottom, emSize));
114 bbox->appendScalar(scaleFromFontUnits(glyphBBox.fRight, emSize));
115 bbox->appendScalar(scaleFromFontUnits(glyphBBox.fTop, emSize));
halcanary51d04d32016-03-08 13:03:55 -0800116 return bbox;
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000117}
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000118} // namespace
119
vandebo@chromium.org98594282011-07-25 22:34:12 +0000120///////////////////////////////////////////////////////////////////////////////
121// class SkPDFFont
122///////////////////////////////////////////////////////////////////////////////
123
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000124/* Font subset design: It would be nice to be able to subset fonts
125 * (particularly type 3 fonts), but it's a lot of work and not a priority.
126 *
127 * Resources are canonicalized and uniqueified by pointer so there has to be
128 * some additional state indicating which subset of the font is used. It
129 * must be maintained at the page granularity and then combined at the document
130 * granularity. a) change SkPDFFont to fill in its state on demand, kind of
131 * like SkPDFGraphicState. b) maintain a per font glyph usage class in each
132 * page/pdf device. c) in the document, retrieve the per font glyph usage
133 * from each page and combine it and ask for a resource with that subset.
134 */
135
halcanary2e3f9d82015-02-27 12:41:03 -0800136SkPDFFont::~SkPDFFont() {}
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000137
halcanarycee13422016-08-18 09:52:48 -0700138static bool can_embed(const SkAdvancedTypefaceMetrics& metrics) {
139 return !SkToBool(metrics.fFlags & SkAdvancedTypefaceMetrics::kNotEmbeddable_FontFlag);
vandebo0f9bad02014-06-19 11:05:39 -0700140}
141
halcanarycee13422016-08-18 09:52:48 -0700142const SkAdvancedTypefaceMetrics* SkPDFFont::GetMetrics(SkTypeface* typeface,
143 SkPDFCanon* canon) {
halcanary4871f222016-08-26 13:17:44 -0700144 SkASSERT(typeface);
145 SkFontID id = typeface->uniqueID();
Hal Canary209e4b12017-05-04 14:23:55 -0400146 if (std::unique_ptr<SkAdvancedTypefaceMetrics>* ptr = canon->fTypefaceMetrics.find(id)) {
Hal Canary5c1b3602017-04-17 16:30:06 -0400147 return ptr->get(); // canon retains ownership.
halcanarycee13422016-08-18 09:52:48 -0700148 }
halcanary4871f222016-08-26 13:17:44 -0700149 int count = typeface->countGlyphs();
150 if (count <= 0 || count > 1 + SK_MaxU16) {
151 // Cache nullptr to skip this check. Use SkSafeUnref().
152 canon->fTypefaceMetrics.set(id, nullptr);
153 return nullptr;
halcanarycee13422016-08-18 09:52:48 -0700154 }
Hal Canary209e4b12017-05-04 14:23:55 -0400155 std::unique_ptr<SkAdvancedTypefaceMetrics> metrics = typeface->getAdvancedMetrics();
halcanarycee13422016-08-18 09:52:48 -0700156 if (!metrics) {
Hal Canary209e4b12017-05-04 14:23:55 -0400157 metrics = skstd::make_unique<SkAdvancedTypefaceMetrics>();
halcanary17484322016-08-29 09:47:48 -0700158 }
Hal Canary3223e272017-07-05 16:47:59 -0400159
160 if (0 == metrics->fStemV || 0 == metrics->fCapHeight) {
161 SkPaint tmpPaint;
162 tmpPaint.setHinting(SkPaint::kNo_Hinting);
163 tmpPaint.setTypeface(sk_ref_sp(typeface));
164 tmpPaint.setTextSize(1000); // glyph coordinate system
165 if (0 == metrics->fStemV) {
166 // Figure out a good guess for StemV - Min width of i, I, !, 1.
167 // This probably isn't very good with an italic font.
168 int16_t stemV = SHRT_MAX;
169 for (char c : {'i', 'I', '!', '1'}) {
170 SkRect bounds;
171 tmpPaint.measureText(&c, 1, &bounds);
172 stemV = SkTMin(stemV, SkToS16(SkScalarRoundToInt(bounds.width())));
173 }
174 metrics->fStemV = stemV;
175 }
176 if (0 == metrics->fCapHeight) {
177 // Figure out a good guess for CapHeight: average the height of M and X.
178 SkScalar capHeight = 0;
179 for (char c : {'M', 'X'}) {
180 SkRect bounds;
181 tmpPaint.measureText(&c, 1, &bounds);
182 capHeight += bounds.height();
183 }
184 metrics->fCapHeight = SkToS16(SkScalarRoundToInt(capHeight / 2));
185 }
186 }
Hal Canary5c1b3602017-04-17 16:30:06 -0400187 return canon->fTypefaceMetrics.set(id, std::move(metrics))->get();
halcanarycee13422016-08-18 09:52:48 -0700188}
189
halcanaryc2f9ec12016-09-12 08:55:29 -0700190SkAdvancedTypefaceMetrics::FontType SkPDFFont::FontType(const SkAdvancedTypefaceMetrics& metrics) {
Hal Canaryb3480e12016-09-30 14:53:15 -0400191 if (SkToBool(metrics.fFlags & SkAdvancedTypefaceMetrics::kMultiMaster_FontFlag) ||
192 SkToBool(metrics.fFlags & SkAdvancedTypefaceMetrics::kNotEmbeddable_FontFlag)) {
halcanarycee13422016-08-18 09:52:48 -0700193 // force Type3 fallback.
194 return SkAdvancedTypefaceMetrics::kOther_Font;
195 }
196 return metrics.fType;
197}
198
halcanary4871f222016-08-26 13:17:44 -0700199static SkGlyphID first_nonzero_glyph_for_single_byte_encoding(SkGlyphID gid) {
halcanarycee13422016-08-18 09:52:48 -0700200 return gid != 0 ? gid - (gid - 1) % 255 : 1;
201}
202
Hal Canary5c1b3602017-04-17 16:30:06 -0400203sk_sp<SkPDFFont> SkPDFFont::GetFontResource(SkPDFCanon* canon,
204 SkTypeface* face,
205 SkGlyphID glyphID) {
halcanary792c80f2015-02-20 07:21:05 -0800206 SkASSERT(canon);
halcanary4871f222016-08-26 13:17:44 -0700207 SkASSERT(face); // All SkPDFDevice::internalDrawText ensures this.
halcanarycee13422016-08-18 09:52:48 -0700208 const SkAdvancedTypefaceMetrics* fontMetrics = SkPDFFont::GetMetrics(face, canon);
halcanary4871f222016-08-26 13:17:44 -0700209 SkASSERT(fontMetrics); // SkPDFDevice::internalDrawText ensures the typeface is good.
210 // GetMetrics only returns null to signify a bad typeface.
halcanarycee13422016-08-18 09:52:48 -0700211 const SkAdvancedTypefaceMetrics& metrics = *fontMetrics;
halcanaryc2f9ec12016-09-12 08:55:29 -0700212 SkAdvancedTypefaceMetrics::FontType type = SkPDFFont::FontType(metrics);
halcanarycee13422016-08-18 09:52:48 -0700213 bool multibyte = SkPDFFont::IsMultiByte(type);
halcanary4871f222016-08-26 13:17:44 -0700214 SkGlyphID subsetCode = multibyte ? 0 : first_nonzero_glyph_for_single_byte_encoding(glyphID);
215 uint64_t fontID = (SkTypeface::UniqueID(face) << 16) | subsetCode;
halcanarycee13422016-08-18 09:52:48 -0700216
Hal Canary5c1b3602017-04-17 16:30:06 -0400217 if (sk_sp<SkPDFFont>* found = canon->fFontMap.find(fontID)) {
218 SkDEBUGCODE(SkPDFFont* foundFont = found->get());
halcanary4871f222016-08-26 13:17:44 -0700219 SkASSERT(foundFont && multibyte == foundFont->multiByteGlyphs());
Hal Canary5c1b3602017-04-17 16:30:06 -0400220 return *found;
halcanarycee13422016-08-18 09:52:48 -0700221 }
222
halcanary4871f222016-08-26 13:17:44 -0700223 sk_sp<SkTypeface> typeface(sk_ref_sp(face));
halcanary7e8d5d32016-08-12 07:59:38 -0700224 SkASSERT(typeface);
halcanary4871f222016-08-26 13:17:44 -0700225
Hal Canaryaa3af7b2017-03-06 16:18:49 -0500226 SkGlyphID lastGlyph = SkToU16(typeface->countGlyphs() - 1);
halcanary4871f222016-08-26 13:17:44 -0700227
228 // should be caught by SkPDFDevice::internalDrawText
229 SkASSERT(glyphID <= lastGlyph);
halcanary32875882016-08-16 09:36:23 -0700230
halcanary530032a2016-08-18 14:22:52 -0700231 SkGlyphID firstNonZeroGlyph;
halcanary530032a2016-08-18 14:22:52 -0700232 if (multibyte) {
233 firstNonZeroGlyph = 1;
halcanary530032a2016-08-18 14:22:52 -0700234 } else {
halcanary4871f222016-08-26 13:17:44 -0700235 firstNonZeroGlyph = subsetCode;
236 lastGlyph = SkToU16(SkTMin<int>((int)lastGlyph, 254 + (int)subsetCode));
halcanary530032a2016-08-18 14:22:52 -0700237 }
238 SkPDFFont::Info info = {std::move(typeface), firstNonZeroGlyph, lastGlyph, type};
halcanary32875882016-08-16 09:36:23 -0700239 sk_sp<SkPDFFont> font;
240 switch (type) {
241 case SkAdvancedTypefaceMetrics::kType1CID_Font:
242 case SkAdvancedTypefaceMetrics::kTrueType_Font:
halcanarycee13422016-08-18 09:52:48 -0700243 SkASSERT(multibyte);
halcanary530032a2016-08-18 14:22:52 -0700244 font = sk_make_sp<SkPDFType0Font>(std::move(info), metrics);
halcanary32875882016-08-16 09:36:23 -0700245 break;
246 case SkAdvancedTypefaceMetrics::kType1_Font:
halcanarycee13422016-08-18 09:52:48 -0700247 SkASSERT(!multibyte);
halcanary530032a2016-08-18 14:22:52 -0700248 font = sk_make_sp<SkPDFType1Font>(std::move(info), metrics, canon);
halcanary32875882016-08-16 09:36:23 -0700249 break;
halcanarycee13422016-08-18 09:52:48 -0700250 default:
251 SkASSERT(!multibyte);
252 // Type3 is our fallback font.
halcanary530032a2016-08-18 14:22:52 -0700253 font = sk_make_sp<SkPDFType3Font>(std::move(info), metrics);
halcanary32875882016-08-16 09:36:23 -0700254 break;
halcanary32875882016-08-16 09:36:23 -0700255 }
Hal Canary5c1b3602017-04-17 16:30:06 -0400256 canon->fFontMap.set(fontID, font);
257 return font;
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000258}
259
halcanary530032a2016-08-18 14:22:52 -0700260SkPDFFont::SkPDFFont(SkPDFFont::Info info)
halcanary792c80f2015-02-20 07:21:05 -0800261 : SkPDFDict("Font")
halcanary530032a2016-08-18 14:22:52 -0700262 , fTypeface(std::move(info.fTypeface))
263 , fGlyphUsage(info.fLastGlyphID + 1) // TODO(halcanary): Adjust mapping?
264 , fFirstGlyphID(info.fFirstGlyphID)
265 , fLastGlyphID(info.fLastGlyphID)
266 , fFontType(info.fFontType) {
halcanary7e8d5d32016-08-12 07:59:38 -0700267 SkASSERT(fTypeface);
vandebo@chromium.org98594282011-07-25 22:34:12 +0000268}
269
halcanary28c6d832016-08-16 10:29:38 -0700270static void add_common_font_descriptor_entries(SkPDFDict* descriptor,
271 const SkAdvancedTypefaceMetrics& metrics,
Hal Canaryaa3af7b2017-03-06 16:18:49 -0500272 uint16_t emSize,
halcanary28c6d832016-08-16 10:29:38 -0700273 int16_t defaultWidth) {
halcanary28c6d832016-08-16 10:29:38 -0700274 descriptor->insertName("FontName", metrics.fFontName);
275 descriptor->insertInt("Flags", (size_t)(metrics.fStyle | kPdfSymbolic));
276 descriptor->insertScalar("Ascent",
277 scaleFromFontUnits(metrics.fAscent, emSize));
278 descriptor->insertScalar("Descent",
279 scaleFromFontUnits(metrics.fDescent, emSize));
280 descriptor->insertScalar("StemV",
281 scaleFromFontUnits(metrics.fStemV, emSize));
282 descriptor->insertScalar("CapHeight",
283 scaleFromFontUnits(metrics.fCapHeight, emSize));
284 descriptor->insertInt("ItalicAngle", metrics.fItalicAngle);
285 descriptor->insertObject(
Hal Canaryaa3af7b2017-03-06 16:18:49 -0500286 "FontBBox", makeFontBBox(metrics.fBBox, emSize));
vandebo@chromium.org98594282011-07-25 22:34:12 +0000287 if (defaultWidth > 0) {
halcanary28c6d832016-08-16 10:29:38 -0700288 descriptor->insertScalar("MissingWidth",
vandebo@chromium.org98594282011-07-25 22:34:12 +0000289 scaleFromFontUnits(defaultWidth, emSize));
290 }
vandebo@chromium.org98594282011-07-25 22:34:12 +0000291}
292
vandebo@chromium.org98594282011-07-25 22:34:12 +0000293///////////////////////////////////////////////////////////////////////////////
294// class SkPDFType0Font
295///////////////////////////////////////////////////////////////////////////////
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000296
halcanary530032a2016-08-18 14:22:52 -0700297SkPDFType0Font::SkPDFType0Font(
298 SkPDFFont::Info info,
299 const SkAdvancedTypefaceMetrics& metrics)
300 : SkPDFFont(std::move(info)) {
vandebo@chromium.org98594282011-07-25 22:34:12 +0000301 SkDEBUGCODE(fPopulated = false);
302}
303
304SkPDFType0Font::~SkPDFType0Font() {}
305
vandebo@chromium.org98594282011-07-25 22:34:12 +0000306
307#ifdef SK_DEBUG
halcanary37c46ca2015-03-31 12:30:20 -0700308void SkPDFType0Font::emitObject(SkWStream* stream,
halcanary530032a2016-08-18 14:22:52 -0700309 const SkPDFObjNumMap& objNumMap) const {
vandebo@chromium.org98594282011-07-25 22:34:12 +0000310 SkASSERT(fPopulated);
halcanary530032a2016-08-18 14:22:52 -0700311 return INHERITED::emitObject(stream, objNumMap);
vandebo@chromium.org98594282011-07-25 22:34:12 +0000312}
313#endif
314
halcanary650e20d2016-08-25 09:07:02 -0700315#ifdef SK_PDF_USE_SFNTLY
halcanaryfe8f0e02016-07-27 14:14:04 -0700316// if possible, make no copy.
317static sk_sp<SkData> stream_to_data(std::unique_ptr<SkStreamAsset> stream) {
318 SkASSERT(stream);
319 (void)stream->rewind();
320 SkASSERT(stream->hasLength());
321 size_t size = stream->getLength();
322 if (const void* base = stream->getMemoryBase()) {
323 SkData::ReleaseProc proc =
halcanary426a2452016-09-08 15:04:38 -0700324 [](const void*, void* ctx) { delete (SkStreamAsset*)ctx; };
halcanaryfe8f0e02016-07-27 14:14:04 -0700325 return SkData::MakeWithProc(base, size, proc, stream.release());
326 }
327 return SkData::MakeFromStream(stream.get(), size);
328}
329
halcanary426a2452016-09-08 15:04:38 -0700330static sk_sp<SkPDFStream> get_subset_font_stream(
halcanaryfe8f0e02016-07-27 14:14:04 -0700331 std::unique_ptr<SkStreamAsset> fontAsset,
halcanary426a2452016-09-08 15:04:38 -0700332 const SkBitSet& glyphUsage,
333 const char* fontName,
334 int ttcIndex) {
335 // Generate glyph id array in format needed by sfntly.
336 // TODO(halcanary): sfntly should take a more compact format.
337 SkTDArray<unsigned> subset;
338 if (!glyphUsage.has(0)) {
339 subset.push(0); // Always include glyph 0.
340 }
341 glyphUsage.exportTo(&subset);
halcanaryfe8f0e02016-07-27 14:14:04 -0700342
343 unsigned char* subsetFont{nullptr};
halcanary426a2452016-09-08 15:04:38 -0700344 sk_sp<SkData> fontData(stream_to_data(std::move(fontAsset)));
Hal Canary7ad87932017-02-16 10:33:49 -0500345#if defined(GOOGLE3)
346 // TODO(halcanary): update GOOGLE3 to newest version of Sfntly.
halcanary426a2452016-09-08 15:04:38 -0700347 (void)ttcIndex;
348 int subsetFontSize = SfntlyWrapper::SubsetFont(fontName,
349 fontData->bytes(),
350 fontData->size(),
351 subset.begin(),
352 subset.count(),
353 &subsetFont);
354#else
355 (void)fontName;
356 int subsetFontSize = SfntlyWrapper::SubsetFont(ttcIndex,
357 fontData->bytes(),
358 fontData->size(),
359 subset.begin(),
360 subset.count(),
361 &subsetFont);
362#endif
363 fontData.reset();
364 subset.reset();
halcanaryfe8f0e02016-07-27 14:14:04 -0700365 SkASSERT(subsetFontSize > 0 || subsetFont == nullptr);
366 if (subsetFontSize < 1) {
367 return nullptr;
368 }
369 SkASSERT(subsetFont != nullptr);
370 auto subsetStream = sk_make_sp<SkPDFStream>(
371 SkData::MakeWithProc(
372 subsetFont, subsetFontSize,
373 [](const void* p, void*) { delete[] (unsigned char*)p; },
374 nullptr));
halcanaryfa251062016-07-29 10:13:18 -0700375 subsetStream->dict()->insertInt("Length1", subsetFontSize);
halcanaryfe8f0e02016-07-27 14:14:04 -0700376 return subsetStream;
377}
halcanary650e20d2016-08-25 09:07:02 -0700378#endif // SK_PDF_USE_SFNTLY
halcanaryfe8f0e02016-07-27 14:14:04 -0700379
halcanary530032a2016-08-18 14:22:52 -0700380void SkPDFType0Font::getFontSubset(SkPDFCanon* canon) {
381 const SkAdvancedTypefaceMetrics* metricsPtr =
382 SkPDFFont::GetMetrics(this->typeface(), canon);
383 SkASSERT(metricsPtr);
384 if (!metricsPtr) { return; }
385 const SkAdvancedTypefaceMetrics& metrics = *metricsPtr;
halcanarycee13422016-08-18 09:52:48 -0700386 SkASSERT(can_embed(metrics));
halcanary28c6d832016-08-16 10:29:38 -0700387 SkAdvancedTypefaceMetrics::FontType type = this->getType();
388 SkTypeface* face = this->typeface();
389 SkASSERT(face);
vandebo@chromium.org98594282011-07-25 22:34:12 +0000390
halcanary28c6d832016-08-16 10:29:38 -0700391 auto descriptor = sk_make_sp<SkPDFDict>("FontDescriptor");
Hal Canaryaa3af7b2017-03-06 16:18:49 -0500392 uint16_t emSize = SkToU16(this->typeface()->getUnitsPerEm());
393 add_common_font_descriptor_entries(descriptor.get(), metrics, emSize , 0);
halcanaryfe8f0e02016-07-27 14:14:04 -0700394
halcanary426a2452016-09-08 15:04:38 -0700395 int ttcIndex;
396 std::unique_ptr<SkStreamAsset> fontAsset(face->openStream(&ttcIndex));
397 size_t fontSize = fontAsset ? fontAsset->getLength() : 0;
halcanary2a4d1e12016-09-22 14:13:16 -0700398 if (0 == fontSize) {
399 SkDebugf("Error: (SkTypeface)(%p)::openStream() returned "
400 "empty stream (%p) when identified as kType1CID_Font "
401 "or kTrueType_Font.\n", face, fontAsset.get());
402 } else {
halcanary426a2452016-09-08 15:04:38 -0700403 switch (type) {
404 case SkAdvancedTypefaceMetrics::kTrueType_Font: {
405 #ifdef SK_PDF_USE_SFNTLY
406 if (!SkToBool(metrics.fFlags &
407 SkAdvancedTypefaceMetrics::kNotSubsettable_FontFlag)) {
408 sk_sp<SkPDFStream> subsetStream = get_subset_font_stream(
409 std::move(fontAsset), this->glyphUsage(),
410 metrics.fFontName.c_str(), ttcIndex);
411 if (subsetStream) {
412 descriptor->insertObjRef("FontFile2", std::move(subsetStream));
413 break;
414 }
415 // If subsetting fails, fall back to original font data.
416 fontAsset.reset(face->openStream(&ttcIndex));
417 SkASSERT(fontAsset);
418 SkASSERT(fontAsset->getLength() == fontSize);
419 if (!fontAsset || fontAsset->getLength() == 0) { break; }
halcanary28c6d832016-08-16 10:29:38 -0700420 }
halcanary426a2452016-09-08 15:04:38 -0700421 #endif // SK_PDF_USE_SFNTLY
422 auto fontStream = sk_make_sp<SkPDFSharedStream>(std::move(fontAsset));
423 fontStream->dict()->insertInt("Length1", fontSize);
424 descriptor->insertObjRef("FontFile2", std::move(fontStream));
425 break;
halcanaryfe8f0e02016-07-27 14:14:04 -0700426 }
halcanary426a2452016-09-08 15:04:38 -0700427 case SkAdvancedTypefaceMetrics::kType1CID_Font: {
428 auto fontStream = sk_make_sp<SkPDFSharedStream>(std::move(fontAsset));
429 fontStream->dict()->insertName("Subtype", "CIDFontType0C");
430 descriptor->insertObjRef("FontFile3", std::move(fontStream));
431 break;
halcanary8e3f54d2016-08-30 11:58:52 -0700432 }
halcanary426a2452016-09-08 15:04:38 -0700433 default:
434 SkASSERT(false);
halcanary8e3f54d2016-08-30 11:58:52 -0700435 }
vandebo@chromium.org98594282011-07-25 22:34:12 +0000436 }
vandebo@chromium.org98594282011-07-25 22:34:12 +0000437
halcanary28c6d832016-08-16 10:29:38 -0700438 auto newCIDFont = sk_make_sp<SkPDFDict>("Font");
439 newCIDFont->insertObjRef("FontDescriptor", std::move(descriptor));
halcanary426a2452016-09-08 15:04:38 -0700440 newCIDFont->insertName("BaseFont", metrics.fFontName);
halcanary28c6d832016-08-16 10:29:38 -0700441
halcanary426a2452016-09-08 15:04:38 -0700442 switch (type) {
443 case SkAdvancedTypefaceMetrics::kType1CID_Font:
444 newCIDFont->insertName("Subtype", "CIDFontType0");
445 break;
446 case SkAdvancedTypefaceMetrics::kTrueType_Font:
447 newCIDFont->insertName("Subtype", "CIDFontType2");
448 newCIDFont->insertName("CIDToGIDMap", "Identity");
449 break;
450 default:
451 SkASSERT(false);
halcanary462d0142016-08-05 13:51:46 -0700452 }
halcanary28c6d832016-08-16 10:29:38 -0700453 auto sysInfo = sk_make_sp<SkPDFDict>();
halcanary59be20c2016-09-01 14:10:00 -0700454 sysInfo->insertString("Registry", "Adobe");
455 sysInfo->insertString("Ordering", "Identity");
halcanary28c6d832016-08-16 10:29:38 -0700456 sysInfo->insertInt("Supplement", 0);
457 newCIDFont->insertObject("CIDSystemInfo", std::move(sysInfo));
458
halcanary28c6d832016-08-16 10:29:38 -0700459 int16_t defaultWidth = 0;
halcanary86b6eab2016-08-17 07:57:27 -0700460 {
Hal Canaryaa3af7b2017-03-06 16:18:49 -0500461 int emSize;
462 SkAutoGlyphCache glyphCache = SkPDFFont::MakeVectorCache(face, &emSize);
halcanary86b6eab2016-08-17 07:57:27 -0700463 sk_sp<SkPDFArray> widths = SkPDFMakeCIDGlyphWidthsArray(
Hal Canaryaa3af7b2017-03-06 16:18:49 -0500464 glyphCache.get(), &this->glyphUsage(), SkToS16(emSize), &defaultWidth);
halcanary86b6eab2016-08-17 07:57:27 -0700465 if (widths && widths->size() > 0) {
466 newCIDFont->insertObject("W", std::move(widths));
467 }
468 newCIDFont->insertScalar(
Hal Canaryaa3af7b2017-03-06 16:18:49 -0500469 "DW", scaleFromFontUnits(defaultWidth, SkToS16(emSize)));
halcanary28c6d832016-08-16 10:29:38 -0700470 }
471
halcanary28c6d832016-08-16 10:29:38 -0700472 ////////////////////////////////////////////////////////////////////////////
473
474 this->insertName("Subtype", "Type0");
475 this->insertName("BaseFont", metrics.fFontName);
476 this->insertName("Encoding", "Identity-H");
477 auto descendantFonts = sk_make_sp<SkPDFArray>();
478 descendantFonts->appendObjRef(std::move(newCIDFont));
479 this->insertObject("DescendantFonts", std::move(descendantFonts));
halcanarycee13422016-08-18 09:52:48 -0700480
481 if (metrics.fGlyphToUnicode.count() > 0) {
482 this->insertObjRef("ToUnicode",
483 SkPDFMakeToUnicodeCmap(metrics.fGlyphToUnicode,
halcanary530032a2016-08-18 14:22:52 -0700484 &this->glyphUsage(),
halcanarycee13422016-08-18 09:52:48 -0700485 multiByteGlyphs(),
486 firstGlyphID(),
487 lastGlyphID()));
488 }
halcanary28c6d832016-08-16 10:29:38 -0700489 SkDEBUGCODE(fPopulated = true);
halcanary530032a2016-08-18 14:22:52 -0700490 return;
halcanary8eccc302016-08-09 13:04:34 -0700491}
492
vandebo@chromium.org98594282011-07-25 22:34:12 +0000493///////////////////////////////////////////////////////////////////////////////
494// class SkPDFType1Font
495///////////////////////////////////////////////////////////////////////////////
496
halcanarycee13422016-08-18 09:52:48 -0700497static sk_sp<SkPDFDict> make_type1_font_descriptor(
498 SkTypeface* typeface,
499 const SkAdvancedTypefaceMetrics& info) {
halcanaryece83922016-03-08 08:32:12 -0800500 auto descriptor = sk_make_sp<SkPDFDict>("FontDescriptor");
Hal Canaryaa3af7b2017-03-06 16:18:49 -0500501 uint16_t emSize = SkToU16(typeface->getUnitsPerEm());
502 add_common_font_descriptor_entries(descriptor.get(), info, emSize, 0);
halcanarycee13422016-08-18 09:52:48 -0700503 if (!can_embed(info)) {
504 return descriptor;
505 }
reed@google.comfed86bd2013-03-14 15:04:57 +0000506 int ttcIndex;
vandebo@chromium.org98594282011-07-25 22:34:12 +0000507 size_t header SK_INIT_TO_AVOID_WARNING;
508 size_t data SK_INIT_TO_AVOID_WARNING;
509 size_t trailer SK_INIT_TO_AVOID_WARNING;
halcanarycee13422016-08-18 09:52:48 -0700510 std::unique_ptr<SkStreamAsset> rawFontData(typeface->openStream(&ttcIndex));
halcanary8eccc302016-08-09 13:04:34 -0700511 sk_sp<SkData> fontData = SkPDFConvertType1FontStream(std::move(rawFontData),
512 &header, &data, &trailer);
halcanarycee13422016-08-18 09:52:48 -0700513 if (fontData) {
514 auto fontStream = sk_make_sp<SkPDFStream>(std::move(fontData));
515 fontStream->dict()->insertInt("Length1", header);
516 fontStream->dict()->insertInt("Length2", data);
517 fontStream->dict()->insertInt("Length3", trailer);
518 descriptor->insertObjRef("FontFile", std::move(fontStream));
vandebo@chromium.org98594282011-07-25 22:34:12 +0000519 }
halcanarycee13422016-08-18 09:52:48 -0700520 return descriptor;
vandebo@chromium.org98594282011-07-25 22:34:12 +0000521}
522
halcanarycee13422016-08-18 09:52:48 -0700523static void populate_type_1_font(SkPDFDict* font,
524 const SkAdvancedTypefaceMetrics& info,
525 SkTypeface* typeface,
526 SkGlyphID firstGlyphID,
527 SkGlyphID lastGlyphID) {
528 font->insertName("Subtype", "Type1");
529 font->insertName("BaseFont", info.fFontName);
vandebo@chromium.orgf77e27d2011-03-10 22:50:28 +0000530
halcanary8eccc302016-08-09 13:04:34 -0700531 // glyphCount not including glyph 0
532 unsigned glyphCount = 1 + lastGlyphID - firstGlyphID;
533 SkASSERT(glyphCount > 0 && glyphCount <= 255);
halcanarycee13422016-08-18 09:52:48 -0700534 font->insertInt("FirstChar", (size_t)0);
535 font->insertInt("LastChar", (size_t)glyphCount);
halcanary462d0142016-08-05 13:51:46 -0700536 {
Hal Canaryaa3af7b2017-03-06 16:18:49 -0500537 int emSize;
538 SkAutoGlyphCache glyphCache = SkPDFFont::MakeVectorCache(typeface, &emSize);
halcanary8eccc302016-08-09 13:04:34 -0700539 auto widths = sk_make_sp<SkPDFArray>();
540 SkScalar advance = glyphCache->getGlyphIDAdvance(0).fAdvanceX;
Hal Canaryaa3af7b2017-03-06 16:18:49 -0500541 widths->appendScalar(from_font_units(advance, SkToU16(emSize)));
halcanary8eccc302016-08-09 13:04:34 -0700542 for (unsigned gID = firstGlyphID; gID <= lastGlyphID; gID++) {
543 advance = glyphCache->getGlyphIDAdvance(gID).fAdvanceX;
Hal Canaryaa3af7b2017-03-06 16:18:49 -0500544 widths->appendScalar(from_font_units(advance, SkToU16(emSize)));
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000545 }
halcanarycee13422016-08-18 09:52:48 -0700546 font->insertObject("Widths", std::move(widths));
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000547 }
halcanaryece83922016-03-08 08:32:12 -0800548 auto encDiffs = sk_make_sp<SkPDFArray>();
halcanary8eccc302016-08-09 13:04:34 -0700549 encDiffs->reserve(lastGlyphID - firstGlyphID + 3);
550 encDiffs->appendInt(0);
halcanarycee13422016-08-18 09:52:48 -0700551 const SkTArray<SkString>& glyphNames = info.fGlyphNames;
halcanary8eccc302016-08-09 13:04:34 -0700552 SkASSERT(glyphNames.count() > lastGlyphID);
553 encDiffs->appendName(glyphNames[0].c_str());
554 const SkString unknown("UNKNOWN");
555 for (int gID = firstGlyphID; gID <= lastGlyphID; gID++) {
556 const bool valid = gID < glyphNames.count() && !glyphNames[gID].isEmpty();
557 const SkString& name = valid ? glyphNames[gID] : unknown;
558 encDiffs->appendName(name);
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000559 }
560
halcanaryece83922016-03-08 08:32:12 -0800561 auto encoding = sk_make_sp<SkPDFDict>("Encoding");
halcanary8103a342016-03-08 15:10:16 -0800562 encoding->insertObject("Differences", std::move(encDiffs));
halcanarycee13422016-08-18 09:52:48 -0700563 font->insertObject("Encoding", std::move(encoding));
564}
565
halcanary530032a2016-08-18 14:22:52 -0700566SkPDFType1Font::SkPDFType1Font(SkPDFFont::Info info,
567 const SkAdvancedTypefaceMetrics& metrics,
halcanarycee13422016-08-18 09:52:48 -0700568 SkPDFCanon* canon)
halcanary530032a2016-08-18 14:22:52 -0700569 : SkPDFFont(std::move(info))
halcanarycee13422016-08-18 09:52:48 -0700570{
571 SkFontID fontID = this->typeface()->uniqueID();
572 sk_sp<SkPDFDict> fontDescriptor;
Hal Canary5c1b3602017-04-17 16:30:06 -0400573 if (sk_sp<SkPDFDict>* ptr = canon->fFontDescriptors.find(fontID)) {
574 fontDescriptor = *ptr;
halcanarycee13422016-08-18 09:52:48 -0700575 } else {
halcanary530032a2016-08-18 14:22:52 -0700576 fontDescriptor = make_type1_font_descriptor(this->typeface(), metrics);
Hal Canary5c1b3602017-04-17 16:30:06 -0400577 canon->fFontDescriptors.set(fontID, fontDescriptor);
halcanarycee13422016-08-18 09:52:48 -0700578 }
579 this->insertObjRef("FontDescriptor", std::move(fontDescriptor));
halcanarycee13422016-08-18 09:52:48 -0700580 // TODO(halcanary): subset this (advances and names).
halcanary530032a2016-08-18 14:22:52 -0700581 populate_type_1_font(this, metrics, this->typeface(),
halcanarycee13422016-08-18 09:52:48 -0700582 this->firstGlyphID(), this->lastGlyphID());
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000583}
584
vandebo@chromium.org98594282011-07-25 22:34:12 +0000585///////////////////////////////////////////////////////////////////////////////
586// class SkPDFType3Font
587///////////////////////////////////////////////////////////////////////////////
588
halcanary7e8d5d32016-08-12 07:59:38 -0700589namespace {
590// returns [0, first, first+1, ... last-1, last]
591struct SingleByteGlyphIdIterator {
592 SingleByteGlyphIdIterator(SkGlyphID first, SkGlyphID last)
593 : fFirst(first), fLast(last) {
594 SkASSERT(fFirst > 0);
595 SkASSERT(fLast >= first);
596 }
597 struct Iter {
598 void operator++() {
599 fCurrent = (0 == fCurrent) ? fFirst : fCurrent + 1;
600 }
601 // This is an input_iterator
602 SkGlyphID operator*() const { return (SkGlyphID)fCurrent; }
603 bool operator!=(const Iter& rhs) const {
604 return fCurrent != rhs.fCurrent;
605 }
606 Iter(SkGlyphID f, int c) : fFirst(f), fCurrent(c) {}
607 private:
608 const SkGlyphID fFirst;
609 int fCurrent; // must be int to make fLast+1 to fit
610 };
611 Iter begin() const { return Iter(fFirst, 0); }
612 Iter end() const { return Iter(fFirst, (int)fLast + 1); }
613private:
614 const SkGlyphID fFirst;
615 const SkGlyphID fLast;
616};
vandebo@chromium.org98594282011-07-25 22:34:12 +0000617}
618
halcanarycee13422016-08-18 09:52:48 -0700619static void add_type3_font_info(SkPDFCanon* canon,
620 SkPDFDict* font,
halcanary7e8d5d32016-08-12 07:59:38 -0700621 SkTypeface* typeface,
halcanary530032a2016-08-18 14:22:52 -0700622 const SkBitSet& subset,
halcanary7e8d5d32016-08-12 07:59:38 -0700623 SkGlyphID firstGlyphID,
624 SkGlyphID lastGlyphID) {
halcanary3d01c622016-08-31 12:52:35 -0700625 const SkAdvancedTypefaceMetrics* metrics = SkPDFFont::GetMetrics(typeface, canon);
halcanary7e8d5d32016-08-12 07:59:38 -0700626 SkASSERT(lastGlyphID >= firstGlyphID);
halcanary17484322016-08-29 09:47:48 -0700627 // Remove unused glyphs at the end of the range.
628 // Keep the lastGlyphID >= firstGlyphID invariant true.
629 while (lastGlyphID > firstGlyphID && !subset.has(lastGlyphID)) {
630 --lastGlyphID;
631 }
Hal Canaryaa3af7b2017-03-06 16:18:49 -0500632 int unitsPerEm;
633 SkAutoGlyphCache cache = SkPDFFont::MakeVectorCache(typeface, &unitsPerEm);
634 SkScalar emSize = (SkScalar)unitsPerEm;
halcanary7e8d5d32016-08-12 07:59:38 -0700635 font->insertName("Subtype", "Type3");
636 // Flip about the x-axis and scale by 1/emSize.
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000637 SkMatrix fontMatrix;
halcanary7e8d5d32016-08-12 07:59:38 -0700638 fontMatrix.setScale(SkScalarInvert(emSize), -SkScalarInvert(emSize));
639 font->insertObject("FontMatrix", SkPDFUtils::MatrixToArray(fontMatrix));
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000640
halcanaryece83922016-03-08 08:32:12 -0800641 auto charProcs = sk_make_sp<SkPDFDict>();
642 auto encoding = sk_make_sp<SkPDFDict>("Encoding");
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000643
halcanaryece83922016-03-08 08:32:12 -0800644 auto encDiffs = sk_make_sp<SkPDFArray>();
halcanary7e8d5d32016-08-12 07:59:38 -0700645 // length(firstGlyphID .. lastGlyphID) == lastGlyphID - firstGlyphID + 1
646 // plus 1 for glyph 0;
647 SkASSERT(firstGlyphID > 0);
648 SkASSERT(lastGlyphID >= firstGlyphID);
649 int glyphCount = lastGlyphID - firstGlyphID + 2;
650 // one other entry for the index of first glyph.
651 encDiffs->reserve(glyphCount + 1);
652 encDiffs->appendInt(0); // index of first glyph
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000653
halcanaryece83922016-03-08 08:32:12 -0800654 auto widthArray = sk_make_sp<SkPDFArray>();
halcanary7e8d5d32016-08-12 07:59:38 -0700655 widthArray->reserve(glyphCount);
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000656
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000657 SkIRect bbox = SkIRect::MakeEmpty();
halcanary7e8d5d32016-08-12 07:59:38 -0700658
659 sk_sp<SkPDFStream> emptyStream;
660 for (SkGlyphID gID : SingleByteGlyphIdIterator(firstGlyphID, lastGlyphID)) {
halcanary530032a2016-08-18 14:22:52 -0700661 bool skipGlyph = gID != 0 && !subset.has(gID);
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000662 SkString characterName;
halcanary7e8d5d32016-08-12 07:59:38 -0700663 SkScalar advance = 0.0f;
664 SkIRect glyphBBox;
665 if (skipGlyph) {
666 characterName.set("g0");
667 } else {
668 characterName.printf("g%X", gID);
669 const SkGlyph& glyph = cache->getGlyphIDMetrics(gID);
670 advance = SkFloatToScalar(glyph.fAdvanceX);
671 glyphBBox = SkIRect::MakeXYWH(glyph.fLeft, glyph.fTop,
672 glyph.fWidth, glyph.fHeight);
673 bbox.join(glyphBBox);
674 const SkPath* path = cache->findPath(glyph);
675 if (path && !path->isEmpty()) {
676 SkDynamicMemoryWStream content;
677 setGlyphWidthAndBoundingBox(SkFloatToScalar(glyph.fAdvanceX), glyphBBox,
678 &content);
679 SkPDFUtils::EmitPath(*path, SkPaint::kFill_Style, &content);
680 SkPDFUtils::PaintPath(SkPaint::kFill_Style, path->getFillType(),
681 &content);
682 charProcs->insertObjRef(
683 characterName, sk_make_sp<SkPDFStream>(
684 std::unique_ptr<SkStreamAsset>(content.detachAsStream())));
685 } else {
686 if (!emptyStream) {
687 emptyStream = sk_make_sp<SkPDFStream>(
688 std::unique_ptr<SkStreamAsset>(
689 new SkMemoryStream((size_t)0)));
690 }
691 charProcs->insertObjRef(characterName, emptyStream);
692 }
halcanary5bf60ad2016-08-11 13:59:18 -0700693 }
halcanary7e8d5d32016-08-12 07:59:38 -0700694 encDiffs->appendName(characterName.c_str());
695 widthArray->appendScalar(advance);
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000696 }
697
halcanary8103a342016-03-08 15:10:16 -0800698 encoding->insertObject("Differences", std::move(encDiffs));
halcanary7e8d5d32016-08-12 07:59:38 -0700699 font->insertInt("FirstChar", 0);
700 font->insertInt("LastChar", lastGlyphID - firstGlyphID + 1);
701 /* FontBBox: "A rectangle expressed in the glyph coordinate
702 system, specifying the font bounding box. This is the smallest
703 rectangle enclosing the shape that would result if all of the
704 glyphs of the font were placed with their origins coincident and
705 then filled." */
706 auto fontBBox = sk_make_sp<SkPDFArray>();
707 fontBBox->reserve(4);
708 fontBBox->appendInt(bbox.left());
709 fontBBox->appendInt(bbox.bottom());
710 fontBBox->appendInt(bbox.right());
711 fontBBox->appendInt(bbox.top());
712 font->insertObject("FontBBox", std::move(fontBBox));
713 font->insertName("CIDToGIDMap", "Identity");
halcanary3d01c622016-08-31 12:52:35 -0700714 if (metrics && metrics->fGlyphToUnicode.count() > 0) {
halcanary7e8d5d32016-08-12 07:59:38 -0700715 font->insertObjRef("ToUnicode",
716 SkPDFMakeToUnicodeCmap(metrics->fGlyphToUnicode,
halcanary530032a2016-08-18 14:22:52 -0700717 &subset,
halcanary7e8d5d32016-08-12 07:59:38 -0700718 false,
719 firstGlyphID,
720 lastGlyphID));
721 }
halcanary3d01c622016-08-31 12:52:35 -0700722 auto descriptor = sk_make_sp<SkPDFDict>("FontDescriptor");
723 int32_t fontDescriptorFlags = kPdfSymbolic;
724 if (metrics) {
725 // Type3 FontDescriptor does not require all the same fields.
726 descriptor->insertName("FontName", metrics->fFontName);
727 descriptor->insertInt("ItalicAngle", metrics->fItalicAngle);
728 fontDescriptorFlags |= (int32_t)metrics->fStyle;
729 }
730 descriptor->insertInt("Flags", fontDescriptorFlags);
731 font->insertObjRef("FontDescriptor", std::move(descriptor));
halcanary7e8d5d32016-08-12 07:59:38 -0700732 font->insertObject("Widths", std::move(widthArray));
733 font->insertObject("Encoding", std::move(encoding));
734 font->insertObject("CharProcs", std::move(charProcs));
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000735}
halcanaryfb62b3d2015-01-21 09:59:14 -0800736
halcanary530032a2016-08-18 14:22:52 -0700737SkPDFType3Font::SkPDFType3Font(SkPDFFont::Info info,
738 const SkAdvancedTypefaceMetrics& metrics)
739 : SkPDFFont(std::move(info)) {}
halcanary7e8d5d32016-08-12 07:59:38 -0700740
halcanary530032a2016-08-18 14:22:52 -0700741void SkPDFType3Font::getFontSubset(SkPDFCanon* canon) {
Hal Canaryaa3af7b2017-03-06 16:18:49 -0500742 add_type3_font_info(canon, this, this->typeface(), this->glyphUsage(),
halcanary7e8d5d32016-08-12 07:59:38 -0700743 this->firstGlyphID(), this->lastGlyphID());
halcanary7e8d5d32016-08-12 07:59:38 -0700744}
745
halcanary7e8d5d32016-08-12 07:59:38 -0700746////////////////////////////////////////////////////////////////////////////////
747
halcanary66a82f32015-10-12 13:05:04 -0700748bool SkPDFFont::CanEmbedTypeface(SkTypeface* typeface, SkPDFCanon* canon) {
halcanarycee13422016-08-18 09:52:48 -0700749 const SkAdvancedTypefaceMetrics* metrics = SkPDFFont::GetMetrics(typeface, canon);
750 return metrics && can_embed(*metrics);
halcanary66a82f32015-10-12 13:05:04 -0700751}
halcanarybae235e2016-03-21 10:05:23 -0700752
753void SkPDFFont::drop() {
754 fTypeface = nullptr;
halcanarye202bd82016-09-19 10:27:03 -0700755 fGlyphUsage.~SkBitSet();
756 new (&fGlyphUsage) SkBitSet(0);
halcanarybae235e2016-03-21 10:05:23 -0700757 this->SkPDFDict::drop();
758}