blob: 5cc80b04ec814f34398f89d3934e1b06075cdeb1 [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"
vandebo@chromium.org28be72b2010-11-11 21:37:00 +000010#include "SkPaint.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"
halcanary8eccc302016-08-09 13:04:34 -070014#include "SkPDFMakeToUnicodeCmap.h"
vandebo@chromium.org28be72b2010-11-11 21:37:00 +000015#include "SkPDFFont.h"
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +000016#include "SkPDFUtils.h"
vandebo@chromium.orgf77e27d2011-03-10 22:50:28 +000017#include "SkRefCnt.h"
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +000018#include "SkScalar.h"
vandebo@chromium.org2a22e102011-01-25 21:01:34 +000019#include "SkStream.h"
reed@google.comfed86bd2013-03-14 15:04:57 +000020#include "SkTypefacePriv.h"
vandebo@chromium.org325cb9a2011-03-30 18:36:29 +000021#include "SkTypes.h"
vandebo@chromium.org28be72b2010-11-11 21:37:00 +000022#include "SkUtils.h"
23
benjaminwagnerbc348f42016-01-05 17:00:04 -080024#if defined (SK_SFNTLY_SUBSETTER)
25 #if defined (GOOGLE3)
benjaminwagner86ea33e2015-10-26 10:46:25 -070026 // #including #defines doesn't work with this build system.
27 #include "typography/font/sfntly/src/sample/chromium/font_subsetter.h"
benjaminwagnerbc348f42016-01-05 17:00:04 -080028 #else
29 #include SK_SFNTLY_SUBSETTER
benjaminwagner86ea33e2015-10-26 10:46:25 -070030 #endif
vandebo@chromium.org1f165892011-07-26 02:11:41 +000031#endif
32
halcanary8eccc302016-08-09 13:04:34 -070033namespace {
34
vandebo@chromium.orgdcf9c192013-03-13 20:01:51 +000035// PDF's notion of symbolic vs non-symbolic is related to the character set, not
36// symbols vs. characters. Rarely is a font the right character set to call it
37// non-symbolic, so always call it symbolic. (PDF 1.4 spec, section 5.7.1)
38static const int kPdfSymbolic = 4;
39
halcanary8b1d32c2016-08-08 09:09:59 -070040struct AdvanceMetric {
41 enum MetricType {
42 kDefault, // Default advance: fAdvance.count = 1
43 kRange, // Advances for a range: fAdvance.count = fEndID-fStartID
44 kRun // fStartID-fEndID have same advance: fAdvance.count = 1
45 };
46 MetricType fType;
47 uint16_t fStartId;
48 uint16_t fEndId;
49 SkTDArray<int16_t> fAdvance;
50 AdvanceMetric(uint16_t startId) : fStartId(startId) {}
51 AdvanceMetric(AdvanceMetric&&) = default;
52 AdvanceMetric& operator=(AdvanceMetric&& other) = default;
53 AdvanceMetric(const AdvanceMetric&) = delete;
54 AdvanceMetric& operator=(const AdvanceMetric&) = delete;
55};
56
halcanary8eccc302016-08-09 13:04:34 -070057class SkPDFType0Font final : public SkPDFFont {
58public:
halcanary32875882016-08-16 09:36:23 -070059 SkPDFType0Font(sk_sp<const SkAdvancedTypefaceMetrics> info,
60 sk_sp<SkTypeface> typeface,
61 SkAdvancedTypefaceMetrics::FontType type);
halcanary8eccc302016-08-09 13:04:34 -070062 virtual ~SkPDFType0Font();
halcanary7e8d5d32016-08-12 07:59:38 -070063 sk_sp<SkPDFObject> getFontSubset(const SkPDFGlyphSet* usage) override;
halcanary8eccc302016-08-09 13:04:34 -070064#ifdef SK_DEBUG
65 void emitObject(SkWStream*,
66 const SkPDFObjNumMap&,
67 const SkPDFSubstituteMap&) const override;
68#endif
69
70private:
71#ifdef SK_DEBUG
72 bool fPopulated;
73#endif
74 bool populate(const SkPDFGlyphSet* subset);
75 typedef SkPDFDict INHERITED;
76};
77
halcanary8eccc302016-08-09 13:04:34 -070078class SkPDFType1Font final : public SkPDFFont {
79public:
halcanary32875882016-08-16 09:36:23 -070080 SkPDFType1Font(sk_sp<const SkAdvancedTypefaceMetrics> info,
81 sk_sp<SkTypeface> typeface,
halcanary8eccc302016-08-09 13:04:34 -070082 uint16_t glyphID,
halcanary32875882016-08-16 09:36:23 -070083 sk_sp<SkPDFDict> relatedFontDescriptor);
halcanary8eccc302016-08-09 13:04:34 -070084 virtual ~SkPDFType1Font();
halcanary8eccc302016-08-09 13:04:34 -070085
86private:
87 bool populate(int16_t glyphID);
88 bool addFontDescriptor(int16_t defaultWidth);
89};
90
91class SkPDFType3Font final : public SkPDFFont {
92public:
halcanary32875882016-08-16 09:36:23 -070093 SkPDFType3Font(sk_sp<const SkAdvancedTypefaceMetrics> info,
94 sk_sp<SkTypeface> typeface,
95 SkAdvancedTypefaceMetrics::FontType fontType,
halcanary8eccc302016-08-09 13:04:34 -070096 uint16_t glyphID);
halcanary7e8d5d32016-08-12 07:59:38 -070097 virtual ~SkPDFType3Font() {}
98 void emitObject(SkWStream*,
99 const SkPDFObjNumMap&,
100 const SkPDFSubstituteMap&) const override {
101 SkDEBUGFAIL("should call getFontSubset!");
102 }
103 sk_sp<SkPDFObject> getFontSubset(const SkPDFGlyphSet* usage) override;
halcanary8eccc302016-08-09 13:04:34 -0700104};
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000105
vandebo@chromium.org98594282011-07-25 22:34:12 +0000106///////////////////////////////////////////////////////////////////////////////
107// File-Local Functions
108///////////////////////////////////////////////////////////////////////////////
109
halcanary8b1d32c2016-08-08 09:09:59 -0700110const int16_t kInvalidAdvance = SK_MinS16;
111const int16_t kDontCareAdvance = SK_MinS16 + 1;
112
113static void stripUninterestingTrailingAdvancesFromRange(
114 AdvanceMetric* range) {
115 SkASSERT(range);
116
117 int expectedAdvanceCount = range->fEndId - range->fStartId + 1;
118 if (range->fAdvance.count() < expectedAdvanceCount) {
119 return;
120 }
121
122 for (int i = expectedAdvanceCount - 1; i >= 0; --i) {
123 if (range->fAdvance[i] != kDontCareAdvance &&
124 range->fAdvance[i] != kInvalidAdvance &&
125 range->fAdvance[i] != 0) {
126 range->fEndId = range->fStartId + i;
127 break;
128 }
129 }
130}
131
132static void zeroWildcardsInRange(AdvanceMetric* range) {
133 SkASSERT(range);
134 if (range->fType != AdvanceMetric::kRange) {
135 return;
136 }
137 SkASSERT(range->fAdvance.count() == range->fEndId - range->fStartId + 1);
138
139 // Zero out wildcards.
140 for (int i = 0; i < range->fAdvance.count(); ++i) {
141 if (range->fAdvance[i] == kDontCareAdvance) {
142 range->fAdvance[i] = 0;
143 }
144 }
145}
146
147static void FinishRange(
148 AdvanceMetric* range,
149 int endId,
150 AdvanceMetric::MetricType type) {
151 range->fEndId = endId;
152 range->fType = type;
153 stripUninterestingTrailingAdvancesFromRange(range);
154 int newLength;
155 if (type == AdvanceMetric::kRange) {
156 newLength = range->fEndId - range->fStartId + 1;
157 } else {
158 if (range->fEndId == range->fStartId) {
159 range->fType = AdvanceMetric::kRange;
160 }
161 newLength = 1;
162 }
163 SkASSERT(range->fAdvance.count() >= newLength);
164 range->fAdvance.setCount(newLength);
165 zeroWildcardsInRange(range);
166}
167
halcanary28c6d832016-08-16 10:29:38 -0700168/** Retrieve advance data for glyphs. Used by the PDF backend. */
halcanary8b1d32c2016-08-08 09:09:59 -0700169// TODO(halcanary): this function is complex enough to need its logic
170// tested with unit tests. On the other hand, I want to do another
171// round of re-factoring before figuring out how to mock this.
172// TODO(halcanary): this function should be combined with
173// composeAdvanceData() so that we don't need to produce a linked list
174// of intermediate values. Or we could make the intermediate value
175// something other than a linked list.
halcanary28c6d832016-08-16 10:29:38 -0700176static void set_glyph_widths(SkTypeface* typeface,
177 const SkPDFGlyphSet* subset,
178 SkSinglyLinkedList<AdvanceMetric>* glyphWidths) {
179 SkPaint tmpPaint;
180 tmpPaint.setHinting(SkPaint::kNo_Hinting);
181 tmpPaint.setTypeface(sk_ref_sp(typeface));
182 tmpPaint.setTextSize((SkScalar)typeface->getUnitsPerEm());
183 const SkSurfaceProps props(0, kUnknown_SkPixelGeometry);
184 SkAutoGlyphCache glyphCache(tmpPaint, &props, nullptr);
185 SkASSERT(glyphCache.get());
186
halcanary8b1d32c2016-08-08 09:09:59 -0700187 // Assuming that on average, the ASCII representation of an advance plus
188 // a space is 8 characters and the ASCII representation of a glyph id is 3
189 // characters, then the following cut offs for using different range types
190 // apply:
191 // The cost of stopping and starting the range is 7 characers
192 // a. Removing 4 0's or don't care's is a win
193 // The cost of stopping and starting the range plus a run is 22
194 // characters
195 // b. Removing 3 repeating advances is a win
196 // c. Removing 2 repeating advances and 3 don't cares is a win
197 // When not currently in a range the cost of a run over a range is 16
198 // characaters, so:
199 // d. Removing a leading 0/don't cares is a win because it is omitted
200 // e. Removing 2 repeating advances is a win
201
halcanary28c6d832016-08-16 10:29:38 -0700202 int num_glyphs = typeface->countGlyphs();
203
halcanary8b1d32c2016-08-08 09:09:59 -0700204 AdvanceMetric* prevRange = nullptr;
205 int16_t lastAdvance = kInvalidAdvance;
206 int repeatedAdvances = 0;
207 int wildCardsInRun = 0;
208 int trailingWildCards = 0;
halcanary8b1d32c2016-08-08 09:09:59 -0700209
210 // Limit the loop count to glyph id ranges provided.
halcanary8b1d32c2016-08-08 09:09:59 -0700211 int lastIndex = num_glyphs;
halcanary28c6d832016-08-16 10:29:38 -0700212 if (subset) {
213 while (!subset->has(lastIndex - 1) && lastIndex > 0) {
214 --lastIndex;
215 }
halcanary8b1d32c2016-08-08 09:09:59 -0700216 }
halcanary28c6d832016-08-16 10:29:38 -0700217 AdvanceMetric curRange(0);
halcanary8b1d32c2016-08-08 09:09:59 -0700218
halcanary28c6d832016-08-16 10:29:38 -0700219 for (int gId = 0; gId <= lastIndex; gId++) {
halcanary8b1d32c2016-08-08 09:09:59 -0700220 int16_t advance = kInvalidAdvance;
221 if (gId < lastIndex) {
halcanary28c6d832016-08-16 10:29:38 -0700222 if (!subset || 0 == gId || subset->has(gId)) {
halcanary8b1d32c2016-08-08 09:09:59 -0700223 advance = (int16_t)glyphCache->getGlyphIDAdvance(gId).fAdvanceX;
halcanary8b1d32c2016-08-08 09:09:59 -0700224 } else {
225 advance = kDontCareAdvance;
226 }
227 }
228 if (advance == lastAdvance) {
229 repeatedAdvances++;
230 trailingWildCards = 0;
231 } else if (advance == kDontCareAdvance) {
232 wildCardsInRun++;
233 trailingWildCards++;
234 } else if (curRange.fAdvance.count() ==
235 repeatedAdvances + 1 + wildCardsInRun) { // All in run.
236 if (lastAdvance == 0) {
237 curRange.fStartId = gId; // reset
238 curRange.fAdvance.setCount(0);
239 trailingWildCards = 0;
240 } else if (repeatedAdvances + 1 >= 2 || trailingWildCards >= 4) {
241 FinishRange(&curRange, gId - 1, AdvanceMetric::kRun);
242 prevRange = glyphWidths->emplace_back(std::move(curRange));
243 curRange = AdvanceMetric(gId);
244 trailingWildCards = 0;
245 }
246 repeatedAdvances = 0;
247 wildCardsInRun = trailingWildCards;
248 trailingWildCards = 0;
249 } else {
250 if (lastAdvance == 0 &&
251 repeatedAdvances + 1 + wildCardsInRun >= 4) {
252 FinishRange(&curRange,
253 gId - repeatedAdvances - wildCardsInRun - 2,
254 AdvanceMetric::kRange);
255 prevRange = glyphWidths->emplace_back(std::move(curRange));
256 curRange = AdvanceMetric(gId);
257 trailingWildCards = 0;
258 } else if (trailingWildCards >= 4 && repeatedAdvances + 1 < 2) {
259 FinishRange(&curRange, gId - trailingWildCards - 1,
260 AdvanceMetric::kRange);
261 prevRange = glyphWidths->emplace_back(std::move(curRange));
262 curRange = AdvanceMetric(gId);
263 trailingWildCards = 0;
264 } else if (lastAdvance != 0 &&
265 (repeatedAdvances + 1 >= 3 ||
266 (repeatedAdvances + 1 >= 2 && wildCardsInRun >= 3))) {
267 FinishRange(&curRange,
268 gId - repeatedAdvances - wildCardsInRun - 2,
269 AdvanceMetric::kRange);
270 (void)glyphWidths->emplace_back(std::move(curRange));
271 curRange =
272 AdvanceMetric(gId - repeatedAdvances - wildCardsInRun - 1);
273 curRange.fAdvance.append(1, &lastAdvance);
274 FinishRange(&curRange, gId - 1, AdvanceMetric::kRun);
275 prevRange = glyphWidths->emplace_back(std::move(curRange));
276 curRange = AdvanceMetric(gId);
277 trailingWildCards = 0;
278 }
279 repeatedAdvances = 0;
280 wildCardsInRun = trailingWildCards;
281 trailingWildCards = 0;
282 }
283 curRange.fAdvance.append(1, &advance);
284 if (advance != kDontCareAdvance) {
285 lastAdvance = advance;
286 }
287 }
288 if (curRange.fStartId == lastIndex) {
289 if (!prevRange) {
290 glyphWidths->reset();
291 return; // https://crbug.com/567031
292 }
293 } else {
294 FinishRange(&curRange, lastIndex - 1, AdvanceMetric::kRange);
295 glyphWidths->emplace_back(std::move(curRange));
296 }
297}
298
299////////////////////////////////////////////////////////////////////////////////
300
reed@google.com3f0dcf92011-03-18 21:23:45 +0000301// scale from em-units to base-1000, returning as a SkScalar
halcanary8eccc302016-08-09 13:04:34 -0700302SkScalar from_font_units(SkScalar scaled, uint16_t emSize) {
reed@google.com3f0dcf92011-03-18 21:23:45 +0000303 if (emSize == 1000) {
304 return scaled;
305 } else {
306 return SkScalarMulDiv(scaled, 1000, emSize);
307 }
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000308}
309
halcanary8eccc302016-08-09 13:04:34 -0700310SkScalar scaleFromFontUnits(int16_t val, uint16_t emSize) {
311 return from_font_units(SkIntToScalar(val), emSize);
312}
313
314
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000315void setGlyphWidthAndBoundingBox(SkScalar width, SkIRect box,
halcanary7e8d5d32016-08-12 07:59:38 -0700316 SkDynamicMemoryWStream* content) {
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000317 // Specify width and bounding box for the glyph.
halcanarybc4696b2015-05-06 10:56:04 -0700318 SkPDFUtils::AppendScalar(width, content);
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +0000319 content->writeText(" 0 ");
320 content->writeDecAsText(box.fLeft);
321 content->writeText(" ");
322 content->writeDecAsText(box.fTop);
323 content->writeText(" ");
324 content->writeDecAsText(box.fRight);
325 content->writeText(" ");
326 content->writeDecAsText(box.fBottom);
327 content->writeText(" d1\n");
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000328}
329
halcanary8103a342016-03-08 15:10:16 -0800330static sk_sp<SkPDFArray> makeFontBBox(SkIRect glyphBBox, uint16_t emSize) {
331 auto bbox = sk_make_sp<SkPDFArray>();
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000332 bbox->reserve(4);
reed@google.comc789cf12011-07-20 12:14:33 +0000333 bbox->appendScalar(scaleFromFontUnits(glyphBBox.fLeft, emSize));
334 bbox->appendScalar(scaleFromFontUnits(glyphBBox.fBottom, emSize));
335 bbox->appendScalar(scaleFromFontUnits(glyphBBox.fRight, emSize));
336 bbox->appendScalar(scaleFromFontUnits(glyphBBox.fTop, emSize));
halcanary51d04d32016-03-08 13:03:55 -0800337 return bbox;
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000338}
339
halcanary462d0142016-08-05 13:51:46 -0700340sk_sp<SkPDFArray> composeAdvanceData(
halcanary8b1d32c2016-08-08 09:09:59 -0700341 const SkSinglyLinkedList<AdvanceMetric>& advanceInfo,
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000342 uint16_t emSize,
halcanary462d0142016-08-05 13:51:46 -0700343 int16_t* defaultAdvance) {
344 auto result = sk_make_sp<SkPDFArray>();
halcanary8b1d32c2016-08-08 09:09:59 -0700345 for (const AdvanceMetric& range : advanceInfo) {
halcanarye20a8752016-05-08 18:47:16 -0700346 switch (range.fType) {
halcanary8b1d32c2016-08-08 09:09:59 -0700347 case AdvanceMetric::kDefault: {
halcanarye20a8752016-05-08 18:47:16 -0700348 SkASSERT(range.fAdvance.count() == 1);
349 *defaultAdvance = range.fAdvance[0];
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000350 break;
351 }
halcanary8b1d32c2016-08-08 09:09:59 -0700352 case AdvanceMetric::kRange: {
halcanaryece83922016-03-08 08:32:12 -0800353 auto advanceArray = sk_make_sp<SkPDFArray>();
halcanarye20a8752016-05-08 18:47:16 -0700354 for (int j = 0; j < range.fAdvance.count(); j++)
halcanary462d0142016-08-05 13:51:46 -0700355 advanceArray->appendScalar(
356 scaleFromFontUnits(range.fAdvance[j], emSize));
halcanarye20a8752016-05-08 18:47:16 -0700357 result->appendInt(range.fStartId);
halcanary8103a342016-03-08 15:10:16 -0800358 result->appendObject(std::move(advanceArray));
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000359 break;
360 }
halcanary8b1d32c2016-08-08 09:09:59 -0700361 case AdvanceMetric::kRun: {
halcanarye20a8752016-05-08 18:47:16 -0700362 SkASSERT(range.fAdvance.count() == 1);
363 result->appendInt(range.fStartId);
364 result->appendInt(range.fEndId);
halcanary462d0142016-08-05 13:51:46 -0700365 result->appendScalar(
366 scaleFromFontUnits(range.fAdvance[0], emSize));
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000367 break;
368 }
369 }
370 }
371 return result;
372}
373
374} // namespace
375
vandebo@chromium.org98594282011-07-25 22:34:12 +0000376
377///////////////////////////////////////////////////////////////////////////////
378// class SkPDFGlyphSet
379///////////////////////////////////////////////////////////////////////////////
380
381SkPDFGlyphSet::SkPDFGlyphSet() : fBitSet(SK_MaxU16 + 1) {
382}
383
384void SkPDFGlyphSet::set(const uint16_t* glyphIDs, int numGlyphs) {
385 for (int i = 0; i < numGlyphs; ++i) {
386 fBitSet.setBit(glyphIDs[i], true);
387 }
388}
389
390bool SkPDFGlyphSet::has(uint16_t glyphID) const {
391 return fBitSet.isBitSet(glyphID);
392}
393
vandebo@chromium.org17e66e22011-07-27 20:59:55 +0000394void SkPDFGlyphSet::exportTo(SkTDArray<unsigned int>* glyphIDs) const {
395 fBitSet.exportTo(glyphIDs);
396}
halcanaryfe8f0e02016-07-27 14:14:04 -0700397
vandebo@chromium.org98594282011-07-25 22:34:12 +0000398///////////////////////////////////////////////////////////////////////////////
399// class SkPDFGlyphSetMap
400///////////////////////////////////////////////////////////////////////////////
vandebo@chromium.org98594282011-07-25 22:34:12 +0000401
halcanary3c35fb32016-06-30 11:55:07 -0700402SkPDFGlyphSetMap::SkPDFGlyphSetMap() {}
vandebo@chromium.org98594282011-07-25 22:34:12 +0000403
404SkPDFGlyphSetMap::~SkPDFGlyphSetMap() {
vandebo@chromium.org98594282011-07-25 22:34:12 +0000405 fMap.reset();
406}
407
408void SkPDFGlyphSetMap::noteGlyphUsage(SkPDFFont* font, const uint16_t* glyphIDs,
409 int numGlyphs) {
410 SkPDFGlyphSet* subset = getGlyphSetForFont(font);
411 if (subset) {
412 subset->set(glyphIDs, numGlyphs);
413 }
414}
415
416SkPDFGlyphSet* SkPDFGlyphSetMap::getGlyphSetForFont(SkPDFFont* font) {
417 int index = fMap.count();
418 for (int i = 0; i < index; ++i) {
419 if (fMap[i].fFont == font) {
halcanary3c35fb32016-06-30 11:55:07 -0700420 return &fMap[i].fGlyphSet;
vandebo@chromium.org98594282011-07-25 22:34:12 +0000421 }
422 }
halcanary3c35fb32016-06-30 11:55:07 -0700423 FontGlyphSetPair& pair = fMap.push_back();
424 pair.fFont = font;
425 return &pair.fGlyphSet;
vandebo@chromium.org98594282011-07-25 22:34:12 +0000426}
427
428///////////////////////////////////////////////////////////////////////////////
429// class SkPDFFont
430///////////////////////////////////////////////////////////////////////////////
431
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000432/* Font subset design: It would be nice to be able to subset fonts
433 * (particularly type 3 fonts), but it's a lot of work and not a priority.
434 *
435 * Resources are canonicalized and uniqueified by pointer so there has to be
436 * some additional state indicating which subset of the font is used. It
437 * must be maintained at the page granularity and then combined at the document
438 * granularity. a) change SkPDFFont to fill in its state on demand, kind of
439 * like SkPDFGraphicState. b) maintain a per font glyph usage class in each
440 * page/pdf device. c) in the document, retrieve the per font glyph usage
441 * from each page and combine it and ask for a resource with that subset.
442 */
443
halcanary2e3f9d82015-02-27 12:41:03 -0800444SkPDFFont::~SkPDFFont() {}
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000445
vandebo0f9bad02014-06-19 11:05:39 -0700446bool SkPDFFont::canEmbed() const {
447 if (!fFontInfo.get()) {
448 SkASSERT(fFontType == SkAdvancedTypefaceMetrics::kOther_Font);
449 return true;
450 }
451 return (fFontInfo->fFlags &
452 SkAdvancedTypefaceMetrics::kNotEmbeddable_FontFlag) == 0;
453}
454
455bool SkPDFFont::canSubset() const {
456 if (!fFontInfo.get()) {
457 SkASSERT(fFontType == SkAdvancedTypefaceMetrics::kOther_Font);
458 return true;
459 }
460 return (fFontInfo->fFlags &
461 SkAdvancedTypefaceMetrics::kNotSubsettable_FontFlag) == 0;
462}
463
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000464bool SkPDFFont::hasGlyph(uint16_t id) {
465 return (id >= fFirstGlyphID && id <= fLastGlyphID) || id == 0;
466}
467
halcanary4ed2f012016-08-15 18:40:07 -0700468int SkPDFFont::glyphsToPDFFontEncoding(SkGlyphID* glyphIDs, int numGlyphs) const {
vandebo@chromium.org01294102011-02-28 19:52:18 +0000469 // A font with multibyte glyphs will support all glyph IDs in a single font.
vandebo@chromium.org98594282011-07-25 22:34:12 +0000470 if (this->multiByteGlyphs()) {
vandebo@chromium.org01294102011-02-28 19:52:18 +0000471 return numGlyphs;
472 }
473
reed@google.comaec40662014-04-18 19:29:07 +0000474 for (int i = 0; i < numGlyphs; i++) {
vandebo@chromium.org01294102011-02-28 19:52:18 +0000475 if (glyphIDs[i] == 0) {
476 continue;
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000477 }
vandebo@chromium.org01294102011-02-28 19:52:18 +0000478 if (glyphIDs[i] < fFirstGlyphID || glyphIDs[i] > fLastGlyphID) {
479 return i;
480 }
481 glyphIDs[i] -= (fFirstGlyphID - 1);
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000482 }
483
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000484 return numGlyphs;
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000485}
486
halcanary4ed2f012016-08-15 18:40:07 -0700487int SkPDFFont::glyphsToPDFFontEncodingCount(const SkGlyphID* glyphIDs,
488 int numGlyphs) const {
489 if (this->multiByteGlyphs()) { // A font with multibyte glyphs will
490 return numGlyphs; // support all glyph IDs in a single font.
491 }
492 for (int i = 0; i < numGlyphs; i++) {
493 if (glyphIDs[i] != 0 &&
494 (glyphIDs[i] < fFirstGlyphID || glyphIDs[i] > fLastGlyphID)) {
495 return i;
496 }
497 }
498 return numGlyphs;
499}
500
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000501// static
halcanary792c80f2015-02-20 07:21:05 -0800502SkPDFFont* SkPDFFont::GetFontResource(SkPDFCanon* canon,
halcanary32875882016-08-16 09:36:23 -0700503 SkTypeface* face,
halcanary792c80f2015-02-20 07:21:05 -0800504 uint16_t glyphID) {
505 SkASSERT(canon);
halcanary32875882016-08-16 09:36:23 -0700506 const uint32_t fontID = SkTypeface::UniqueID(face);
halcanaryfb62b3d2015-01-21 09:59:14 -0800507 SkPDFFont* relatedFont;
halcanary792c80f2015-02-20 07:21:05 -0800508 if (SkPDFFont* pdfFont = canon->findFont(fontID, glyphID, &relatedFont)) {
halcanaryfb62b3d2015-01-21 09:59:14 -0800509 return SkRef(pdfFont);
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000510 }
halcanary32875882016-08-16 09:36:23 -0700511 sk_sp<SkTypeface> typeface(face ? sk_ref_sp(face) : SkTypeface::MakeDefault());
halcanary7e8d5d32016-08-12 07:59:38 -0700512 SkASSERT(typeface);
513 int glyphCount = typeface->countGlyphs();
514 if (glyphCount < 1 || // typeface lacks even a NOTDEF glyph.
515 glyphCount > 1 + SK_MaxU16 || // invalid glyphCount
516 glyphID >= glyphCount) { // invalid glyph
517 return nullptr;
518 }
halcanary48810a02016-03-07 14:57:50 -0800519 sk_sp<const SkAdvancedTypefaceMetrics> fontMetrics;
halcanary32875882016-08-16 09:36:23 -0700520 sk_sp<SkPDFDict> relatedFontDescriptor;
halcanaryfb62b3d2015-01-21 09:59:14 -0800521 if (relatedFont) {
halcanary32875882016-08-16 09:36:23 -0700522 fontMetrics = relatedFont->refFontInfo();
523 relatedFontDescriptor = relatedFont->refFontDescriptor();
edisonn@google.com022e8572012-10-23 21:32:39 +0000524
525 // This only is to catch callers who pass invalid glyph ids.
526 // If glyph id is invalid, then we will create duplicate entries
vandebo0f9bad02014-06-19 11:05:39 -0700527 // for TrueType fonts.
halcanary32875882016-08-16 09:36:23 -0700528 SkDEBUGCODE(SkAdvancedTypefaceMetrics::FontType fontType = relatedFont->getType());
529 SkASSERT(fontType != SkAdvancedTypefaceMetrics::kType1CID_Font);
530 SkASSERT(fontType != SkAdvancedTypefaceMetrics::kTrueType_Font);
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000531 } else {
halcanary32875882016-08-16 09:36:23 -0700532 SkTypeface::PerGlyphInfo info = SkTypeface::kGlyphNames_PerGlyphInfo |
533 SkTypeface::kToUnicode_PerGlyphInfo;
vandebo@chromium.orgd96d17b2013-01-04 19:31:24 +0000534 fontMetrics.reset(
halcanary96fcdcc2015-08-27 07:41:13 -0700535 typeface->getAdvancedTypefaceMetrics(info, nullptr, 0));
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000536 }
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000537
halcanary32875882016-08-16 09:36:23 -0700538 SkAdvancedTypefaceMetrics::FontType type =
539 fontMetrics ? fontMetrics->fType : SkAdvancedTypefaceMetrics::kOther_Font;
540 if (fontMetrics &&
541 SkToBool(fontMetrics->fFlags &
542 SkAdvancedTypefaceMetrics::kMultiMaster_FontFlag)) {
543 // force Type3 fallback.
544 type = SkAdvancedTypefaceMetrics::kOther_Font;
545 }
546
547 sk_sp<SkPDFFont> font;
548 switch (type) {
549 case SkAdvancedTypefaceMetrics::kType1CID_Font:
550 case SkAdvancedTypefaceMetrics::kTrueType_Font:
551 SkASSERT(relatedFontDescriptor == nullptr);
552 SkASSERT(fontMetrics != nullptr);
553 font = sk_make_sp<SkPDFType0Font>(std::move(fontMetrics),
554 std::move(typeface),
555 type);
556 break;
557 case SkAdvancedTypefaceMetrics::kType1_Font:
558 SkASSERT(fontMetrics != nullptr);
559 font = sk_make_sp<SkPDFType1Font>(std::move(fontMetrics),
560 std::move(typeface),
561 glyphID,
562 std::move(relatedFontDescriptor));
563 break;
564 case SkAdvancedTypefaceMetrics::kCFF_Font:
565 SkASSERT(fontMetrics != nullptr);
566 // fallthrough
567 case SkAdvancedTypefaceMetrics::kOther_Font:
568 font = sk_make_sp<SkPDFType3Font>(std::move(fontMetrics),
569 std::move(typeface),
570 type,
571 glyphID);
572 break;
573 default:
574 SkDEBUGFAIL("invalid SkAdvancedTypefaceMetrics::FontType");
575 return nullptr;
576 }
577 // When firstGlyphID==0, SkFont::IsMatch() matches all glyphs in font.
578 SkGlyphID firstGlyphID = font->multiByteGlyphs() ? 0 : font->fFirstGlyphID;
579 // TODO(halcanary) Make SkCanon::addFont take sk_sp<SkPDFFont>.
580 canon->addFont(font.get(), fontID, firstGlyphID);
581 return font.release(); // TODO(halcanary) return sk_sp<SkPDFFont>.
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000582}
583
halcanary7e8d5d32016-08-12 07:59:38 -0700584sk_sp<SkPDFObject> SkPDFFont::getFontSubset(const SkPDFGlyphSet*) {
halcanary96fcdcc2015-08-27 07:41:13 -0700585 return nullptr; // Default: no support.
vandebo@chromium.org98594282011-07-25 22:34:12 +0000586}
587
halcanary7e8d5d32016-08-12 07:59:38 -0700588// TODO: take a sk_sp<SkAdvancedTypefaceMetrics> and sk_sp<SkTypeface>
halcanary32875882016-08-16 09:36:23 -0700589SkPDFFont::SkPDFFont(sk_sp<const SkAdvancedTypefaceMetrics> info,
590 sk_sp<SkTypeface> typeface,
591 sk_sp<SkPDFDict> relatedFontDescriptor,
592 SkAdvancedTypefaceMetrics::FontType fontType,
593 bool multiByteGlyphs)
halcanary792c80f2015-02-20 07:21:05 -0800594 : SkPDFDict("Font")
halcanary32875882016-08-16 09:36:23 -0700595 , fTypeface(std::move(typeface))
596 , fFontInfo(std::move(info))
597 , fDescriptor(std::move(relatedFontDescriptor))
halcanary792c80f2015-02-20 07:21:05 -0800598 , fFirstGlyphID(1)
halcanary32875882016-08-16 09:36:23 -0700599 , fFontType(fontType)
600 , fMultiByteGlyphs(multiByteGlyphs) {
halcanary7e8d5d32016-08-12 07:59:38 -0700601 SkASSERT(fTypeface);
halcanary32875882016-08-16 09:36:23 -0700602 fLastGlyphID = fFontInfo ? fFontInfo->fLastGlyphID : 0;
halcanary7e8d5d32016-08-12 07:59:38 -0700603 if (0 == fLastGlyphID) {
604 fLastGlyphID = SkToU16(fTypeface->countGlyphs() - 1);
vandebo@chromium.org98594282011-07-25 22:34:12 +0000605 }
606}
607
halcanary32875882016-08-16 09:36:23 -0700608void SkPDFFont::setFontInfo(sk_sp<const SkAdvancedTypefaceMetrics> info) {
609 if (info) {
610 fFontInfo = std::move(info);
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000611 }
vandebo@chromium.org98594282011-07-25 22:34:12 +0000612}
613
614void SkPDFFont::setLastGlyphID(uint16_t glyphID) {
615 fLastGlyphID = glyphID;
616}
617
halcanary32875882016-08-16 09:36:23 -0700618void SkPDFFont::setFontDescriptor(sk_sp<SkPDFDict> descriptor) {
619 fDescriptor = std::move(descriptor);
vandebo@chromium.org98594282011-07-25 22:34:12 +0000620}
621
halcanary28c6d832016-08-16 10:29:38 -0700622static void add_common_font_descriptor_entries(SkPDFDict* descriptor,
623 const SkAdvancedTypefaceMetrics& metrics,
624 int16_t defaultWidth) {
625 const uint16_t emSize = metrics.fEmSize;
626 descriptor->insertName("FontName", metrics.fFontName);
627 descriptor->insertInt("Flags", (size_t)(metrics.fStyle | kPdfSymbolic));
628 descriptor->insertScalar("Ascent",
629 scaleFromFontUnits(metrics.fAscent, emSize));
630 descriptor->insertScalar("Descent",
631 scaleFromFontUnits(metrics.fDescent, emSize));
632 descriptor->insertScalar("StemV",
633 scaleFromFontUnits(metrics.fStemV, emSize));
634 descriptor->insertScalar("CapHeight",
635 scaleFromFontUnits(metrics.fCapHeight, emSize));
636 descriptor->insertInt("ItalicAngle", metrics.fItalicAngle);
637 descriptor->insertObject(
638 "FontBBox", makeFontBBox(metrics.fBBox, metrics.fEmSize));
vandebo@chromium.org98594282011-07-25 22:34:12 +0000639 if (defaultWidth > 0) {
halcanary28c6d832016-08-16 10:29:38 -0700640 descriptor->insertScalar("MissingWidth",
vandebo@chromium.org98594282011-07-25 22:34:12 +0000641 scaleFromFontUnits(defaultWidth, emSize));
642 }
vandebo@chromium.org98594282011-07-25 22:34:12 +0000643}
644
bungeman22edc832014-10-03 07:55:58 -0700645void SkPDFFont::adjustGlyphRangeForSingleByteEncoding(uint16_t glyphID) {
vandebo@chromium.org98594282011-07-25 22:34:12 +0000646 // Single byte glyph encoding supports a max of 255 glyphs.
647 fFirstGlyphID = glyphID - (glyphID - 1) % 255;
648 if (fLastGlyphID > fFirstGlyphID + 255 - 1) {
649 fLastGlyphID = fFirstGlyphID + 255 - 1;
650 }
651}
652
vandebo@chromium.org98594282011-07-25 22:34:12 +0000653void SkPDFFont::populateToUnicodeTable(const SkPDFGlyphSet* subset) {
halcanary96fcdcc2015-08-27 07:41:13 -0700654 if (fFontInfo == nullptr || fFontInfo->fGlyphToUnicode.begin() == nullptr) {
vandebo@chromium.org98594282011-07-25 22:34:12 +0000655 return;
656 }
halcanarybf51cfd2015-05-05 10:24:09 -0700657 this->insertObjRef("ToUnicode",
halcanary8eccc302016-08-09 13:04:34 -0700658 SkPDFMakeToUnicodeCmap(fFontInfo->fGlyphToUnicode,
659 subset,
660 multiByteGlyphs(),
661 firstGlyphID(),
662 lastGlyphID()));
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000663}
664
vandebo@chromium.org98594282011-07-25 22:34:12 +0000665///////////////////////////////////////////////////////////////////////////////
666// class SkPDFType0Font
667///////////////////////////////////////////////////////////////////////////////
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000668
halcanary32875882016-08-16 09:36:23 -0700669SkPDFType0Font::SkPDFType0Font(sk_sp<const SkAdvancedTypefaceMetrics> info,
670 sk_sp<SkTypeface> typeface,
671 SkAdvancedTypefaceMetrics::FontType fontType)
672 : SkPDFFont(std::move(info), std::move(typeface), nullptr, fontType, true) {
vandebo@chromium.org98594282011-07-25 22:34:12 +0000673 SkDEBUGCODE(fPopulated = false);
vandebo0f9bad02014-06-19 11:05:39 -0700674 if (!canSubset()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700675 this->populate(nullptr);
vandebo0f9bad02014-06-19 11:05:39 -0700676 }
vandebo@chromium.org98594282011-07-25 22:34:12 +0000677}
678
679SkPDFType0Font::~SkPDFType0Font() {}
680
halcanary7e8d5d32016-08-12 07:59:38 -0700681sk_sp<SkPDFObject> SkPDFType0Font::getFontSubset(const SkPDFGlyphSet* subset) {
vandebo0f9bad02014-06-19 11:05:39 -0700682 if (!canSubset()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700683 return nullptr;
vandebo0f9bad02014-06-19 11:05:39 -0700684 }
halcanary32875882016-08-16 09:36:23 -0700685 auto newSubset = sk_make_sp<SkPDFType0Font>(refFontInfo(), refTypeface(), getType());
vandebo@chromium.org98594282011-07-25 22:34:12 +0000686 newSubset->populate(subset);
687 return newSubset;
688}
689
690#ifdef SK_DEBUG
halcanary37c46ca2015-03-31 12:30:20 -0700691void SkPDFType0Font::emitObject(SkWStream* stream,
692 const SkPDFObjNumMap& objNumMap,
halcanarya060eba2015-08-19 12:26:46 -0700693 const SkPDFSubstituteMap& substitutes) const {
vandebo@chromium.org98594282011-07-25 22:34:12 +0000694 SkASSERT(fPopulated);
halcanary37c46ca2015-03-31 12:30:20 -0700695 return INHERITED::emitObject(stream, objNumMap, substitutes);
vandebo@chromium.org98594282011-07-25 22:34:12 +0000696}
697#endif
698
halcanaryfe8f0e02016-07-27 14:14:04 -0700699#ifdef SK_SFNTLY_SUBSETTER
700// if possible, make no copy.
701static sk_sp<SkData> stream_to_data(std::unique_ptr<SkStreamAsset> stream) {
702 SkASSERT(stream);
703 (void)stream->rewind();
704 SkASSERT(stream->hasLength());
705 size_t size = stream->getLength();
706 if (const void* base = stream->getMemoryBase()) {
707 SkData::ReleaseProc proc =
708 [](const void*, void* ctx) { delete (SkStream*)ctx; };
709 return SkData::MakeWithProc(base, size, proc, stream.release());
710 }
711 return SkData::MakeFromStream(stream.get(), size);
712}
713
714static sk_sp<SkPDFObject> get_subset_font_stream(
715 std::unique_ptr<SkStreamAsset> fontAsset,
716 const SkTDArray<uint32_t>& subset,
717 const char* fontName) {
718 // sfntly requires unsigned int* to be passed in,
719 // as far as we know, unsigned int is equivalent
720 // to uint32_t on all platforms.
721 static_assert(sizeof(unsigned) == sizeof(uint32_t), "");
722
723 // TODO(halcanary): Use ttcIndex, not fontName.
724
725 unsigned char* subsetFont{nullptr};
726 int subsetFontSize{0};
727 {
728 sk_sp<SkData> fontData(stream_to_data(std::move(fontAsset)));
729 subsetFontSize =
730 SfntlyWrapper::SubsetFont(fontName,
731 fontData->bytes(),
732 fontData->size(),
733 subset.begin(),
734 subset.count(),
735 &subsetFont);
736 }
737 SkASSERT(subsetFontSize > 0 || subsetFont == nullptr);
738 if (subsetFontSize < 1) {
739 return nullptr;
740 }
741 SkASSERT(subsetFont != nullptr);
742 auto subsetStream = sk_make_sp<SkPDFStream>(
743 SkData::MakeWithProc(
744 subsetFont, subsetFontSize,
745 [](const void* p, void*) { delete[] (unsigned char*)p; },
746 nullptr));
halcanaryfa251062016-07-29 10:13:18 -0700747 subsetStream->dict()->insertInt("Length1", subsetFontSize);
halcanaryfe8f0e02016-07-27 14:14:04 -0700748 return subsetStream;
749}
750#endif // SK_SFNTLY_SUBSETTER
751
halcanary28c6d832016-08-16 10:29:38 -0700752bool SkPDFType0Font::populate(const SkPDFGlyphSet* subset) {
halcanary66a82f32015-10-12 13:05:04 -0700753 SkASSERT(this->canEmbed());
halcanary28c6d832016-08-16 10:29:38 -0700754 SkASSERT(this->getFontInfo());
755 const SkAdvancedTypefaceMetrics& metrics = *(this->getFontInfo());
756 SkAdvancedTypefaceMetrics::FontType type = this->getType();
757 SkTypeface* face = this->typeface();
758 SkASSERT(face);
halcanary6c80a9d2016-08-16 11:54:57 -0700759 const SkString& name = metrics.fFontName;
vandebo@chromium.org98594282011-07-25 22:34:12 +0000760
halcanary28c6d832016-08-16 10:29:38 -0700761 auto descriptor = sk_make_sp<SkPDFDict>("FontDescriptor");
762 add_common_font_descriptor_entries(descriptor.get(), metrics, 0);
763 switch (type) {
vandebo@chromium.org98594282011-07-25 22:34:12 +0000764 case SkAdvancedTypefaceMetrics::kTrueType_Font: {
halcanaryfe8f0e02016-07-27 14:14:04 -0700765 int ttcIndex;
halcanary28c6d832016-08-16 10:29:38 -0700766 std::unique_ptr<SkStreamAsset> fontAsset(face->openStream(&ttcIndex));
halcanaryfe8f0e02016-07-27 14:14:04 -0700767 SkASSERT(fontAsset);
768 if (!fontAsset) {
halcanary32431432016-03-30 12:59:14 -0700769 return false;
770 }
halcanaryfe8f0e02016-07-27 14:14:04 -0700771 size_t fontSize = fontAsset->getLength();
halcanary725c6202015-08-20 08:09:37 -0700772 SkASSERT(fontSize > 0);
halcanaryfe8f0e02016-07-27 14:14:04 -0700773 if (fontSize == 0) {
774 return false;
775 }
776
777 #ifdef SK_SFNTLY_SUBSETTER
778 if (this->canSubset() && subset) {
halcanary28c6d832016-08-16 10:29:38 -0700779 // Generate glyph id array. in format needed by sfntly
780 SkTDArray<uint32_t> glyphIDs;
781 if (subset) {
782 if (!subset->has(0)) {
783 glyphIDs.push(0); // Always include glyph 0.
784 }
785 subset->exportTo(&glyphIDs);
786 }
halcanaryfe8f0e02016-07-27 14:14:04 -0700787 sk_sp<SkPDFObject> subsetStream = get_subset_font_stream(
halcanary6c80a9d2016-08-16 11:54:57 -0700788 std::move(fontAsset), glyphIDs, name.c_str());
halcanaryfe8f0e02016-07-27 14:14:04 -0700789 if (subsetStream) {
790 descriptor->insertObjRef("FontFile2", std::move(subsetStream));
791 break;
792 }
793 // If subsetting fails, fall back to original font data.
halcanary28c6d832016-08-16 10:29:38 -0700794 fontAsset.reset(face->openStream(&ttcIndex));
halcanaryfe8f0e02016-07-27 14:14:04 -0700795 }
796 #endif // SK_SFNTLY_SUBSETTER
halcanaryfa251062016-07-29 10:13:18 -0700797 auto fontStream = sk_make_sp<SkPDFSharedStream>(std::move(fontAsset));
halcanary725c6202015-08-20 08:09:37 -0700798 fontStream->dict()->insertInt("Length1", fontSize);
halcanary8103a342016-03-08 15:10:16 -0800799 descriptor->insertObjRef("FontFile2", std::move(fontStream));
vandebo@chromium.org98594282011-07-25 22:34:12 +0000800 break;
801 }
vandebo@chromium.org98594282011-07-25 22:34:12 +0000802 case SkAdvancedTypefaceMetrics::kType1CID_Font: {
halcanary28c6d832016-08-16 10:29:38 -0700803 std::unique_ptr<SkStreamAsset> fontData(face->openStream(nullptr));
halcanary32431432016-03-30 12:59:14 -0700804 SkASSERT(fontData);
805 SkASSERT(fontData->getLength() > 0);
806 if (!fontData || 0 == fontData->getLength()) {
807 return false;
808 }
halcanaryfa251062016-07-29 10:13:18 -0700809 auto fontStream = sk_make_sp<SkPDFSharedStream>(std::move(fontData));
halcanary28c6d832016-08-16 10:29:38 -0700810 fontStream->dict()->insertName("Subtype", "CIDFontType0c");
halcanary8103a342016-03-08 15:10:16 -0800811 descriptor->insertObjRef("FontFile3", std::move(fontStream));
vandebo@chromium.org98594282011-07-25 22:34:12 +0000812 break;
813 }
814 default:
815 SkASSERT(false);
816 }
vandebo@chromium.org98594282011-07-25 22:34:12 +0000817
halcanary28c6d832016-08-16 10:29:38 -0700818 auto newCIDFont = sk_make_sp<SkPDFDict>("Font");
819 newCIDFont->insertObjRef("FontDescriptor", std::move(descriptor));
820 newCIDFont->insertName("BaseFont", name);
821
822 if (type == SkAdvancedTypefaceMetrics::kType1CID_Font) {
823 newCIDFont->insertName("Subtype", "CIDFontType0");
824 } else if (type == SkAdvancedTypefaceMetrics::kTrueType_Font) {
825 newCIDFont->insertName("Subtype", "CIDFontType2");
826 newCIDFont->insertName("CIDToGIDMap", "Identity");
halcanary462d0142016-08-05 13:51:46 -0700827 } else {
halcanary28c6d832016-08-16 10:29:38 -0700828 SkASSERT(false);
halcanary462d0142016-08-05 13:51:46 -0700829 }
halcanary462d0142016-08-05 13:51:46 -0700830
halcanary28c6d832016-08-16 10:29:38 -0700831 auto sysInfo = sk_make_sp<SkPDFDict>();
832 sysInfo->insertString("Registry", "Adobe");
833 sysInfo->insertString("Ordering", "Identity");
834 sysInfo->insertInt("Supplement", 0);
835 newCIDFont->insertObject("CIDSystemInfo", std::move(sysInfo));
836
837 SkSinglyLinkedList<AdvanceMetric> tmpMetrics;
838 set_glyph_widths(face, subset, &tmpMetrics);
839 int16_t defaultWidth = 0;
840 uint16_t emSize = (uint16_t)this->getFontInfo()->fEmSize;
841 sk_sp<SkPDFArray> widths = composeAdvanceData(tmpMetrics, emSize, &defaultWidth);
842 if (widths->size()) {
843 newCIDFont->insertObject("W", std::move(widths));
844 }
845
846 newCIDFont->insertScalar(
847 "DW", scaleFromFontUnits(defaultWidth, emSize));
848
849
850 ////////////////////////////////////////////////////////////////////////////
851
852 this->insertName("Subtype", "Type0");
853 this->insertName("BaseFont", metrics.fFontName);
854 this->insertName("Encoding", "Identity-H");
855 auto descendantFonts = sk_make_sp<SkPDFArray>();
856 descendantFonts->appendObjRef(std::move(newCIDFont));
857 this->insertObject("DescendantFonts", std::move(descendantFonts));
858 this->populateToUnicodeTable(subset);
859 SkDEBUGCODE(fPopulated = true);
860 return true;
halcanary8eccc302016-08-09 13:04:34 -0700861}
862
863sk_sp<const SkAdvancedTypefaceMetrics> SkPDFFont::GetFontMetricsWithToUnicode(
864 SkTypeface* typeface, uint32_t* glyphs, uint32_t glyphsCount) {
865 return sk_sp<const SkAdvancedTypefaceMetrics>(
866 typeface->getAdvancedTypefaceMetrics(
867 SkTypeface::kToUnicode_PerGlyphInfo, glyphs, glyphsCount));
868}
869
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000870
vandebo@chromium.org98594282011-07-25 22:34:12 +0000871///////////////////////////////////////////////////////////////////////////////
872// class SkPDFType1Font
873///////////////////////////////////////////////////////////////////////////////
874
halcanary32875882016-08-16 09:36:23 -0700875SkPDFType1Font::SkPDFType1Font(sk_sp<const SkAdvancedTypefaceMetrics> info,
876 sk_sp<SkTypeface> typeface,
vandebo@chromium.org98594282011-07-25 22:34:12 +0000877 uint16_t glyphID,
halcanary32875882016-08-16 09:36:23 -0700878 sk_sp<SkPDFDict> relatedFontDescriptor)
879 : SkPDFFont(std::move(info),
880 std::move(typeface),
881 std::move(relatedFontDescriptor),
882 SkAdvancedTypefaceMetrics::kType1_Font,
883 /* multiByteGlyphs = */ false) {
884 this->populate(glyphID); // TODO(halcanary): subset this.
vandebo@chromium.org98594282011-07-25 22:34:12 +0000885}
886
887SkPDFType1Font::~SkPDFType1Font() {}
888
889bool SkPDFType1Font::addFontDescriptor(int16_t defaultWidth) {
halcanary32875882016-08-16 09:36:23 -0700890 if (sk_sp<SkPDFDict> descriptor = this->refFontDescriptor()) {
891 this->insertObjRef("FontDescriptor", std::move(descriptor));
vandebo@chromium.org98594282011-07-25 22:34:12 +0000892 return true;
893 }
894
halcanaryece83922016-03-08 08:32:12 -0800895 auto descriptor = sk_make_sp<SkPDFDict>("FontDescriptor");
halcanary32875882016-08-16 09:36:23 -0700896 setFontDescriptor(descriptor);
vandebo@chromium.org98594282011-07-25 22:34:12 +0000897
reed@google.comfed86bd2013-03-14 15:04:57 +0000898 int ttcIndex;
vandebo@chromium.org98594282011-07-25 22:34:12 +0000899 size_t header SK_INIT_TO_AVOID_WARNING;
900 size_t data SK_INIT_TO_AVOID_WARNING;
901 size_t trailer SK_INIT_TO_AVOID_WARNING;
halcanary32431432016-03-30 12:59:14 -0700902 std::unique_ptr<SkStreamAsset> rawFontData(typeface()->openStream(&ttcIndex));
halcanary8eccc302016-08-09 13:04:34 -0700903 sk_sp<SkData> fontData = SkPDFConvertType1FontStream(std::move(rawFontData),
904 &header, &data, &trailer);
905 if (!fontData) {
vandebo@chromium.org98594282011-07-25 22:34:12 +0000906 return false;
907 }
halcanary66a82f32015-10-12 13:05:04 -0700908 SkASSERT(this->canEmbed());
halcanaryfe8f0e02016-07-27 14:14:04 -0700909 auto fontStream = sk_make_sp<SkPDFStream>(std::move(fontData));
halcanaryfa251062016-07-29 10:13:18 -0700910 fontStream->dict()->insertInt("Length1", header);
911 fontStream->dict()->insertInt("Length2", data);
912 fontStream->dict()->insertInt("Length3", trailer);
halcanary8103a342016-03-08 15:10:16 -0800913 descriptor->insertObjRef("FontFile", std::move(fontStream));
vandebo@chromium.org98594282011-07-25 22:34:12 +0000914
halcanary28c6d832016-08-16 10:29:38 -0700915 SkASSERT(this->getFontInfo());
916 add_common_font_descriptor_entries(descriptor.get(),
917 *this->getFontInfo(),
918 defaultWidth);
halcanary8103a342016-03-08 15:10:16 -0800919 this->insertObjRef("FontDescriptor", std::move(descriptor));
halcanary28c6d832016-08-16 10:29:38 -0700920 return true;
vandebo@chromium.org98594282011-07-25 22:34:12 +0000921}
922
923bool SkPDFType1Font::populate(int16_t glyphID) {
halcanary8eccc302016-08-09 13:04:34 -0700924 this->insertName("Subtype", "Type1");
halcanary32875882016-08-16 09:36:23 -0700925 this->insertName("BaseFont", this->getFontInfo()->fFontName);
vandebo@chromium.orgf77e27d2011-03-10 22:50:28 +0000926 adjustGlyphRangeForSingleByteEncoding(glyphID);
halcanary8eccc302016-08-09 13:04:34 -0700927 SkGlyphID firstGlyphID = this->firstGlyphID();
928 SkGlyphID lastGlyphID = this->lastGlyphID();
vandebo@chromium.orgf77e27d2011-03-10 22:50:28 +0000929
halcanary8eccc302016-08-09 13:04:34 -0700930 // glyphCount not including glyph 0
931 unsigned glyphCount = 1 + lastGlyphID - firstGlyphID;
932 SkASSERT(glyphCount > 0 && glyphCount <= 255);
933 this->insertInt("FirstChar", (size_t)0);
934 this->insertInt("LastChar", (size_t)glyphCount);
halcanary462d0142016-08-05 13:51:46 -0700935 {
halcanary8eccc302016-08-09 13:04:34 -0700936 SkPaint tmpPaint;
937 tmpPaint.setHinting(SkPaint::kNo_Hinting);
938 tmpPaint.setTypeface(sk_ref_sp(this->typeface()));
939 tmpPaint.setTextSize((SkScalar)this->typeface()->getUnitsPerEm());
halcanary7e8d5d32016-08-12 07:59:38 -0700940 const SkSurfaceProps props(0, kUnknown_SkPixelGeometry);
941 SkAutoGlyphCache glyphCache(tmpPaint, &props, nullptr);
halcanary8eccc302016-08-09 13:04:34 -0700942 auto widths = sk_make_sp<SkPDFArray>();
943 SkScalar advance = glyphCache->getGlyphIDAdvance(0).fAdvanceX;
halcanary32875882016-08-16 09:36:23 -0700944 const uint16_t emSize = this->getFontInfo()->fEmSize;
halcanary8eccc302016-08-09 13:04:34 -0700945 widths->appendScalar(from_font_units(advance, emSize));
946 for (unsigned gID = firstGlyphID; gID <= lastGlyphID; gID++) {
947 advance = glyphCache->getGlyphIDAdvance(gID).fAdvanceX;
948 widths->appendScalar(from_font_units(advance, emSize));
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000949 }
halcanary8eccc302016-08-09 13:04:34 -0700950 this->insertObject("Widths", std::move(widths));
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000951 }
halcanary8eccc302016-08-09 13:04:34 -0700952 if (!addFontDescriptor(0)) {
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000953 return false;
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000954 }
halcanaryece83922016-03-08 08:32:12 -0800955 auto encDiffs = sk_make_sp<SkPDFArray>();
halcanary8eccc302016-08-09 13:04:34 -0700956 encDiffs->reserve(lastGlyphID - firstGlyphID + 3);
957 encDiffs->appendInt(0);
halcanary32875882016-08-16 09:36:23 -0700958 const SkTArray<SkString>& glyphNames = this->getFontInfo()->fGlyphNames;
halcanary8eccc302016-08-09 13:04:34 -0700959 SkASSERT(glyphNames.count() > lastGlyphID);
960 encDiffs->appendName(glyphNames[0].c_str());
961 const SkString unknown("UNKNOWN");
962 for (int gID = firstGlyphID; gID <= lastGlyphID; gID++) {
963 const bool valid = gID < glyphNames.count() && !glyphNames[gID].isEmpty();
964 const SkString& name = valid ? glyphNames[gID] : unknown;
965 encDiffs->appendName(name);
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000966 }
967
halcanaryece83922016-03-08 08:32:12 -0800968 auto encoding = sk_make_sp<SkPDFDict>("Encoding");
halcanary8103a342016-03-08 15:10:16 -0800969 encoding->insertObject("Differences", std::move(encDiffs));
970 this->insertObject("Encoding", std::move(encoding));
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000971 return true;
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000972}
973
vandebo@chromium.org98594282011-07-25 22:34:12 +0000974///////////////////////////////////////////////////////////////////////////////
975// class SkPDFType3Font
976///////////////////////////////////////////////////////////////////////////////
977
halcanary7e8d5d32016-08-12 07:59:38 -0700978namespace {
979// returns [0, first, first+1, ... last-1, last]
980struct SingleByteGlyphIdIterator {
981 SingleByteGlyphIdIterator(SkGlyphID first, SkGlyphID last)
982 : fFirst(first), fLast(last) {
983 SkASSERT(fFirst > 0);
984 SkASSERT(fLast >= first);
985 }
986 struct Iter {
987 void operator++() {
988 fCurrent = (0 == fCurrent) ? fFirst : fCurrent + 1;
989 }
990 // This is an input_iterator
991 SkGlyphID operator*() const { return (SkGlyphID)fCurrent; }
992 bool operator!=(const Iter& rhs) const {
993 return fCurrent != rhs.fCurrent;
994 }
995 Iter(SkGlyphID f, int c) : fFirst(f), fCurrent(c) {}
996 private:
997 const SkGlyphID fFirst;
998 int fCurrent; // must be int to make fLast+1 to fit
999 };
1000 Iter begin() const { return Iter(fFirst, 0); }
1001 Iter end() const { return Iter(fFirst, (int)fLast + 1); }
1002private:
1003 const SkGlyphID fFirst;
1004 const SkGlyphID fLast;
1005};
vandebo@chromium.org98594282011-07-25 22:34:12 +00001006}
1007
halcanary7e8d5d32016-08-12 07:59:38 -07001008static void add_type3_font_info(SkPDFDict* font,
1009 SkTypeface* typeface,
1010 SkScalar emSize,
1011 const SkPDFGlyphSet* subset,
1012 SkGlyphID firstGlyphID,
1013 SkGlyphID lastGlyphID) {
1014 SkASSERT(lastGlyphID >= firstGlyphID);
halcanary5bf60ad2016-08-11 13:59:18 -07001015 SkPaint paint;
halcanary7e8d5d32016-08-12 07:59:38 -07001016 paint.setHinting(SkPaint::kNo_Hinting);
1017 paint.setTypeface(sk_ref_sp(typeface));
1018 paint.setTextSize(emSize);
halcanary5bf60ad2016-08-11 13:59:18 -07001019 const SkSurfaceProps props(0, kUnknown_SkPixelGeometry);
halcanary7e8d5d32016-08-12 07:59:38 -07001020 SkAutoGlyphCache cache(paint, &props, nullptr);
halcanary5bf60ad2016-08-11 13:59:18 -07001021
halcanary7e8d5d32016-08-12 07:59:38 -07001022 font->insertName("Subtype", "Type3");
1023 // Flip about the x-axis and scale by 1/emSize.
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +00001024 SkMatrix fontMatrix;
halcanary7e8d5d32016-08-12 07:59:38 -07001025 fontMatrix.setScale(SkScalarInvert(emSize), -SkScalarInvert(emSize));
1026 font->insertObject("FontMatrix", SkPDFUtils::MatrixToArray(fontMatrix));
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +00001027
halcanaryece83922016-03-08 08:32:12 -08001028 auto charProcs = sk_make_sp<SkPDFDict>();
1029 auto encoding = sk_make_sp<SkPDFDict>("Encoding");
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +00001030
halcanaryece83922016-03-08 08:32:12 -08001031 auto encDiffs = sk_make_sp<SkPDFArray>();
halcanary7e8d5d32016-08-12 07:59:38 -07001032 // length(firstGlyphID .. lastGlyphID) == lastGlyphID - firstGlyphID + 1
1033 // plus 1 for glyph 0;
1034 SkASSERT(firstGlyphID > 0);
1035 SkASSERT(lastGlyphID >= firstGlyphID);
1036 int glyphCount = lastGlyphID - firstGlyphID + 2;
1037 // one other entry for the index of first glyph.
1038 encDiffs->reserve(glyphCount + 1);
1039 encDiffs->appendInt(0); // index of first glyph
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +00001040
halcanaryece83922016-03-08 08:32:12 -08001041 auto widthArray = sk_make_sp<SkPDFArray>();
halcanary7e8d5d32016-08-12 07:59:38 -07001042 widthArray->reserve(glyphCount);
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +00001043
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +00001044 SkIRect bbox = SkIRect::MakeEmpty();
halcanary7e8d5d32016-08-12 07:59:38 -07001045
1046 sk_sp<SkPDFStream> emptyStream;
1047 for (SkGlyphID gID : SingleByteGlyphIdIterator(firstGlyphID, lastGlyphID)) {
1048 bool skipGlyph = subset && gID != 0 && !subset->has(gID);
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +00001049 SkString characterName;
halcanary7e8d5d32016-08-12 07:59:38 -07001050 SkScalar advance = 0.0f;
1051 SkIRect glyphBBox;
1052 if (skipGlyph) {
1053 characterName.set("g0");
1054 } else {
1055 characterName.printf("g%X", gID);
1056 const SkGlyph& glyph = cache->getGlyphIDMetrics(gID);
1057 advance = SkFloatToScalar(glyph.fAdvanceX);
1058 glyphBBox = SkIRect::MakeXYWH(glyph.fLeft, glyph.fTop,
1059 glyph.fWidth, glyph.fHeight);
1060 bbox.join(glyphBBox);
1061 const SkPath* path = cache->findPath(glyph);
1062 if (path && !path->isEmpty()) {
1063 SkDynamicMemoryWStream content;
1064 setGlyphWidthAndBoundingBox(SkFloatToScalar(glyph.fAdvanceX), glyphBBox,
1065 &content);
1066 SkPDFUtils::EmitPath(*path, SkPaint::kFill_Style, &content);
1067 SkPDFUtils::PaintPath(SkPaint::kFill_Style, path->getFillType(),
1068 &content);
1069 charProcs->insertObjRef(
1070 characterName, sk_make_sp<SkPDFStream>(
1071 std::unique_ptr<SkStreamAsset>(content.detachAsStream())));
1072 } else {
1073 if (!emptyStream) {
1074 emptyStream = sk_make_sp<SkPDFStream>(
1075 std::unique_ptr<SkStreamAsset>(
1076 new SkMemoryStream((size_t)0)));
1077 }
1078 charProcs->insertObjRef(characterName, emptyStream);
1079 }
halcanary5bf60ad2016-08-11 13:59:18 -07001080 }
halcanary7e8d5d32016-08-12 07:59:38 -07001081 encDiffs->appendName(characterName.c_str());
1082 widthArray->appendScalar(advance);
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +00001083 }
1084
halcanary8103a342016-03-08 15:10:16 -08001085 encoding->insertObject("Differences", std::move(encDiffs));
halcanary7e8d5d32016-08-12 07:59:38 -07001086 font->insertInt("FirstChar", 0);
1087 font->insertInt("LastChar", lastGlyphID - firstGlyphID + 1);
1088 /* FontBBox: "A rectangle expressed in the glyph coordinate
1089 system, specifying the font bounding box. This is the smallest
1090 rectangle enclosing the shape that would result if all of the
1091 glyphs of the font were placed with their origins coincident and
1092 then filled." */
1093 auto fontBBox = sk_make_sp<SkPDFArray>();
1094 fontBBox->reserve(4);
1095 fontBBox->appendInt(bbox.left());
1096 fontBBox->appendInt(bbox.bottom());
1097 fontBBox->appendInt(bbox.right());
1098 fontBBox->appendInt(bbox.top());
1099 font->insertObject("FontBBox", std::move(fontBBox));
1100 font->insertName("CIDToGIDMap", "Identity");
1101 sk_sp<const SkAdvancedTypefaceMetrics> metrics;
1102 if (subset) {
1103 SkTDArray<uint32_t> subsetList;
1104 for (SkGlyphID gID : SingleByteGlyphIdIterator(firstGlyphID, lastGlyphID)) {
1105 if (gID == 0 || subset->has(gID)) { // Always include glyph 0.
1106 subsetList.push(0);
1107 }
1108 }
1109 subset->exportTo(&subsetList);
1110 metrics = SkPDFFont::GetFontMetricsWithToUnicode(typeface, subsetList.begin(),
1111 subsetList.count());
1112 } else {
1113 metrics = SkPDFFont::GetFontMetricsWithToUnicode(typeface, nullptr, 0);
1114 }
1115 if (metrics) {
1116 font->insertObjRef("ToUnicode",
1117 SkPDFMakeToUnicodeCmap(metrics->fGlyphToUnicode,
1118 subset,
1119 false,
1120 firstGlyphID,
1121 lastGlyphID));
1122 }
1123 font->insertObject("Widths", std::move(widthArray));
1124 font->insertObject("Encoding", std::move(encoding));
1125 font->insertObject("CharProcs", std::move(charProcs));
vandebo@chromium.org2a22e102011-01-25 21:01:34 +00001126}
halcanaryfb62b3d2015-01-21 09:59:14 -08001127
halcanary32875882016-08-16 09:36:23 -07001128SkPDFType3Font::SkPDFType3Font(sk_sp<const SkAdvancedTypefaceMetrics> info,
1129 sk_sp<SkTypeface> typeface,
1130 SkAdvancedTypefaceMetrics::FontType fontType,
halcanary7e8d5d32016-08-12 07:59:38 -07001131 uint16_t glyphID)
halcanary32875882016-08-16 09:36:23 -07001132 : SkPDFFont(std::move(info), std::move(typeface), nullptr,
1133 fontType, /* multiByteGlyphs = */ false) {
halcanary7e8d5d32016-08-12 07:59:38 -07001134 // If fLastGlyphID isn't set (because there is not fFontInfo), look it up.
halcanary32875882016-08-16 09:36:23 -07001135 this->setLastGlyphID(SkToU16(this->typeface()->countGlyphs() - 1));
halcanary7e8d5d32016-08-12 07:59:38 -07001136 this->adjustGlyphRangeForSingleByteEncoding(glyphID);
1137}
1138
1139sk_sp<SkPDFObject> SkPDFType3Font::getFontSubset(const SkPDFGlyphSet* usage) {
1140 // All fonts are subset before serialization.
1141 // TODO(halcanary): all fonts should follow this pattern.
1142 auto font = sk_make_sp<SkPDFDict>("Font");
halcanary32875882016-08-16 09:36:23 -07001143 const SkAdvancedTypefaceMetrics* info = this->getFontInfo();
halcanary7e8d5d32016-08-12 07:59:38 -07001144 uint16_t emSize = info && info->fEmSize > 0 ? info->fEmSize : 1000;
1145 add_type3_font_info(font.get(), this->typeface(), (SkScalar)emSize, usage,
1146 this->firstGlyphID(), this->lastGlyphID());
1147 return font;
1148}
1149
1150
1151////////////////////////////////////////////////////////////////////////////////
1152
halcanaryfb62b3d2015-01-21 09:59:14 -08001153SkPDFFont::Match SkPDFFont::IsMatch(SkPDFFont* existingFont,
1154 uint32_t existingFontID,
1155 uint16_t existingGlyphID,
1156 uint32_t searchFontID,
1157 uint16_t searchGlyphID) {
1158 if (existingFontID != searchFontID) {
1159 return SkPDFFont::kNot_Match;
1160 }
1161 if (existingGlyphID == 0 || searchGlyphID == 0) {
1162 return SkPDFFont::kExact_Match;
1163 }
halcanary96fcdcc2015-08-27 07:41:13 -07001164 if (existingFont != nullptr) {
halcanaryfb62b3d2015-01-21 09:59:14 -08001165 return (existingFont->fFirstGlyphID <= searchGlyphID &&
1166 searchGlyphID <= existingFont->fLastGlyphID)
1167 ? SkPDFFont::kExact_Match
1168 : SkPDFFont::kRelated_Match;
1169 }
1170 return (existingGlyphID == searchGlyphID) ? SkPDFFont::kExact_Match
1171 : SkPDFFont::kRelated_Match;
1172}
halcanary66a82f32015-10-12 13:05:04 -07001173
1174// Since getAdvancedTypefaceMetrics is expensive, cache the result.
1175bool SkPDFFont::CanEmbedTypeface(SkTypeface* typeface, SkPDFCanon* canon) {
halcanary4ed2f012016-08-15 18:40:07 -07001176 SkFontID id = SkTypeface::UniqueID(typeface);
halcanary66a82f32015-10-12 13:05:04 -07001177 if (bool* value = canon->fCanEmbedTypeface.find(id)) {
1178 return *value;
1179 }
halcanary4ed2f012016-08-15 18:40:07 -07001180 SkAutoResolveDefaultTypeface face(typeface);
halcanary66a82f32015-10-12 13:05:04 -07001181 bool canEmbed = true;
halcanary48810a02016-03-07 14:57:50 -08001182 sk_sp<const SkAdvancedTypefaceMetrics> fontMetrics(
halcanary66a82f32015-10-12 13:05:04 -07001183 face->getAdvancedTypefaceMetrics(
1184 SkTypeface::kNo_PerGlyphInfo, nullptr, 0));
1185 if (fontMetrics) {
1186 canEmbed = !SkToBool(
1187 fontMetrics->fFlags &
1188 SkAdvancedTypefaceMetrics::kNotEmbeddable_FontFlag);
1189 }
1190 return *canon->fCanEmbedTypeface.set(id, canEmbed);
1191}
halcanarybae235e2016-03-21 10:05:23 -07001192
1193void SkPDFFont::drop() {
1194 fTypeface = nullptr;
1195 fFontInfo = nullptr;
1196 fDescriptor = nullptr;
1197 this->SkPDFDict::drop();
1198}