blob: c24737ffad164cdd5dadf0308d264263bda34c4c [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:
59 SkPDFType0Font(const SkAdvancedTypefaceMetrics* info,
60 SkTypeface* typeface);
61 virtual ~SkPDFType0Font();
62 bool multiByteGlyphs() const override { return true; }
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
78class SkPDFCIDFont final : public SkPDFFont {
79public:
80 SkPDFCIDFont(const SkAdvancedTypefaceMetrics* info,
81 SkTypeface* typeface,
82 const SkPDFGlyphSet* subset);
83 virtual ~SkPDFCIDFont();
84 bool multiByteGlyphs() const override { return true; }
85
86private:
87 bool populate(const SkPDFGlyphSet* subset);
88 bool addFontDescriptor(int16_t defaultWidth,
89 const SkTDArray<uint32_t>* subset);
90};
91
92class SkPDFType1Font final : public SkPDFFont {
93public:
94 SkPDFType1Font(const SkAdvancedTypefaceMetrics* info,
95 SkTypeface* typeface,
96 uint16_t glyphID,
97 SkPDFDict* relatedFontDescriptor);
98 virtual ~SkPDFType1Font();
99 bool multiByteGlyphs() const override { return false; }
100
101private:
102 bool populate(int16_t glyphID);
103 bool addFontDescriptor(int16_t defaultWidth);
104};
105
106class SkPDFType3Font final : public SkPDFFont {
107public:
108 SkPDFType3Font(const SkAdvancedTypefaceMetrics* info,
109 SkTypeface* typeface,
110 uint16_t glyphID);
halcanary7e8d5d32016-08-12 07:59:38 -0700111 virtual ~SkPDFType3Font() {}
112 void emitObject(SkWStream*,
113 const SkPDFObjNumMap&,
114 const SkPDFSubstituteMap&) const override {
115 SkDEBUGFAIL("should call getFontSubset!");
116 }
117 sk_sp<SkPDFObject> getFontSubset(const SkPDFGlyphSet* usage) override;
halcanary8eccc302016-08-09 13:04:34 -0700118 bool multiByteGlyphs() const override { return false; }
halcanary8eccc302016-08-09 13:04:34 -0700119};
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000120
vandebo@chromium.org98594282011-07-25 22:34:12 +0000121///////////////////////////////////////////////////////////////////////////////
122// File-Local Functions
123///////////////////////////////////////////////////////////////////////////////
124
halcanary8b1d32c2016-08-08 09:09:59 -0700125const int16_t kInvalidAdvance = SK_MinS16;
126const int16_t kDontCareAdvance = SK_MinS16 + 1;
127
128static void stripUninterestingTrailingAdvancesFromRange(
129 AdvanceMetric* range) {
130 SkASSERT(range);
131
132 int expectedAdvanceCount = range->fEndId - range->fStartId + 1;
133 if (range->fAdvance.count() < expectedAdvanceCount) {
134 return;
135 }
136
137 for (int i = expectedAdvanceCount - 1; i >= 0; --i) {
138 if (range->fAdvance[i] != kDontCareAdvance &&
139 range->fAdvance[i] != kInvalidAdvance &&
140 range->fAdvance[i] != 0) {
141 range->fEndId = range->fStartId + i;
142 break;
143 }
144 }
145}
146
147static void zeroWildcardsInRange(AdvanceMetric* range) {
148 SkASSERT(range);
149 if (range->fType != AdvanceMetric::kRange) {
150 return;
151 }
152 SkASSERT(range->fAdvance.count() == range->fEndId - range->fStartId + 1);
153
154 // Zero out wildcards.
155 for (int i = 0; i < range->fAdvance.count(); ++i) {
156 if (range->fAdvance[i] == kDontCareAdvance) {
157 range->fAdvance[i] = 0;
158 }
159 }
160}
161
162static void FinishRange(
163 AdvanceMetric* range,
164 int endId,
165 AdvanceMetric::MetricType type) {
166 range->fEndId = endId;
167 range->fType = type;
168 stripUninterestingTrailingAdvancesFromRange(range);
169 int newLength;
170 if (type == AdvanceMetric::kRange) {
171 newLength = range->fEndId - range->fStartId + 1;
172 } else {
173 if (range->fEndId == range->fStartId) {
174 range->fType = AdvanceMetric::kRange;
175 }
176 newLength = 1;
177 }
178 SkASSERT(range->fAdvance.count() >= newLength);
179 range->fAdvance.setCount(newLength);
180 zeroWildcardsInRange(range);
181}
182
183
184/** Retrieve advance data for glyphs. Used by the PDF backend.
185 @param num_glyphs Total number of glyphs in the given font.
186 @param glyphIDs For per-glyph info, specify subset of the
187 font by giving glyph ids. Each integer
188 represents a glyph id. Passing nullptr
189 means all glyphs in the font.
190 @param glyphIDsCount Number of elements in subsetGlyphIds.
191 Ignored if glyphIDs is nullptr.
192*/
193// TODO(halcanary): this function is complex enough to need its logic
194// tested with unit tests. On the other hand, I want to do another
195// round of re-factoring before figuring out how to mock this.
196// TODO(halcanary): this function should be combined with
197// composeAdvanceData() so that we don't need to produce a linked list
198// of intermediate values. Or we could make the intermediate value
199// something other than a linked list.
200static void get_glyph_widths(SkSinglyLinkedList<AdvanceMetric>* glyphWidths,
201 int num_glyphs,
202 const uint32_t* subsetGlyphIDs,
203 uint32_t subsetGlyphIDsLength,
204 SkGlyphCache* glyphCache) {
205 // Assuming that on average, the ASCII representation of an advance plus
206 // a space is 8 characters and the ASCII representation of a glyph id is 3
207 // characters, then the following cut offs for using different range types
208 // apply:
209 // The cost of stopping and starting the range is 7 characers
210 // a. Removing 4 0's or don't care's is a win
211 // The cost of stopping and starting the range plus a run is 22
212 // characters
213 // b. Removing 3 repeating advances is a win
214 // c. Removing 2 repeating advances and 3 don't cares is a win
215 // When not currently in a range the cost of a run over a range is 16
216 // characaters, so:
217 // d. Removing a leading 0/don't cares is a win because it is omitted
218 // e. Removing 2 repeating advances is a win
219
220 AdvanceMetric* prevRange = nullptr;
221 int16_t lastAdvance = kInvalidAdvance;
222 int repeatedAdvances = 0;
223 int wildCardsInRun = 0;
224 int trailingWildCards = 0;
225 uint32_t subsetIndex = 0;
226
227 // Limit the loop count to glyph id ranges provided.
228 int firstIndex = 0;
229 int lastIndex = num_glyphs;
230 if (subsetGlyphIDs) {
231 firstIndex = static_cast<int>(subsetGlyphIDs[0]);
232 lastIndex =
233 static_cast<int>(subsetGlyphIDs[subsetGlyphIDsLength - 1]) + 1;
234 }
235 AdvanceMetric curRange(firstIndex);
236
237 for (int gId = firstIndex; gId <= lastIndex; gId++) {
238 int16_t advance = kInvalidAdvance;
239 if (gId < lastIndex) {
240 // Get glyph id only when subset is nullptr, or the id is in subset.
241 SkASSERT(!subsetGlyphIDs || (subsetIndex < subsetGlyphIDsLength &&
242 static_cast<uint32_t>(gId) <= subsetGlyphIDs[subsetIndex]));
243 if (!subsetGlyphIDs ||
244 (subsetIndex < subsetGlyphIDsLength &&
245 static_cast<uint32_t>(gId) == subsetGlyphIDs[subsetIndex])) {
246 advance = (int16_t)glyphCache->getGlyphIDAdvance(gId).fAdvanceX;
247 ++subsetIndex;
248 } else {
249 advance = kDontCareAdvance;
250 }
251 }
252 if (advance == lastAdvance) {
253 repeatedAdvances++;
254 trailingWildCards = 0;
255 } else if (advance == kDontCareAdvance) {
256 wildCardsInRun++;
257 trailingWildCards++;
258 } else if (curRange.fAdvance.count() ==
259 repeatedAdvances + 1 + wildCardsInRun) { // All in run.
260 if (lastAdvance == 0) {
261 curRange.fStartId = gId; // reset
262 curRange.fAdvance.setCount(0);
263 trailingWildCards = 0;
264 } else if (repeatedAdvances + 1 >= 2 || trailingWildCards >= 4) {
265 FinishRange(&curRange, gId - 1, AdvanceMetric::kRun);
266 prevRange = glyphWidths->emplace_back(std::move(curRange));
267 curRange = AdvanceMetric(gId);
268 trailingWildCards = 0;
269 }
270 repeatedAdvances = 0;
271 wildCardsInRun = trailingWildCards;
272 trailingWildCards = 0;
273 } else {
274 if (lastAdvance == 0 &&
275 repeatedAdvances + 1 + wildCardsInRun >= 4) {
276 FinishRange(&curRange,
277 gId - repeatedAdvances - wildCardsInRun - 2,
278 AdvanceMetric::kRange);
279 prevRange = glyphWidths->emplace_back(std::move(curRange));
280 curRange = AdvanceMetric(gId);
281 trailingWildCards = 0;
282 } else if (trailingWildCards >= 4 && repeatedAdvances + 1 < 2) {
283 FinishRange(&curRange, gId - trailingWildCards - 1,
284 AdvanceMetric::kRange);
285 prevRange = glyphWidths->emplace_back(std::move(curRange));
286 curRange = AdvanceMetric(gId);
287 trailingWildCards = 0;
288 } else if (lastAdvance != 0 &&
289 (repeatedAdvances + 1 >= 3 ||
290 (repeatedAdvances + 1 >= 2 && wildCardsInRun >= 3))) {
291 FinishRange(&curRange,
292 gId - repeatedAdvances - wildCardsInRun - 2,
293 AdvanceMetric::kRange);
294 (void)glyphWidths->emplace_back(std::move(curRange));
295 curRange =
296 AdvanceMetric(gId - repeatedAdvances - wildCardsInRun - 1);
297 curRange.fAdvance.append(1, &lastAdvance);
298 FinishRange(&curRange, gId - 1, AdvanceMetric::kRun);
299 prevRange = glyphWidths->emplace_back(std::move(curRange));
300 curRange = AdvanceMetric(gId);
301 trailingWildCards = 0;
302 }
303 repeatedAdvances = 0;
304 wildCardsInRun = trailingWildCards;
305 trailingWildCards = 0;
306 }
307 curRange.fAdvance.append(1, &advance);
308 if (advance != kDontCareAdvance) {
309 lastAdvance = advance;
310 }
311 }
312 if (curRange.fStartId == lastIndex) {
313 if (!prevRange) {
314 glyphWidths->reset();
315 return; // https://crbug.com/567031
316 }
317 } else {
318 FinishRange(&curRange, lastIndex - 1, AdvanceMetric::kRange);
319 glyphWidths->emplace_back(std::move(curRange));
320 }
321}
322
323////////////////////////////////////////////////////////////////////////////////
324
325
reed@google.com3f0dcf92011-03-18 21:23:45 +0000326// scale from em-units to base-1000, returning as a SkScalar
halcanary8eccc302016-08-09 13:04:34 -0700327SkScalar from_font_units(SkScalar scaled, uint16_t emSize) {
reed@google.com3f0dcf92011-03-18 21:23:45 +0000328 if (emSize == 1000) {
329 return scaled;
330 } else {
331 return SkScalarMulDiv(scaled, 1000, emSize);
332 }
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000333}
334
halcanary8eccc302016-08-09 13:04:34 -0700335SkScalar scaleFromFontUnits(int16_t val, uint16_t emSize) {
336 return from_font_units(SkIntToScalar(val), emSize);
337}
338
339
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000340void setGlyphWidthAndBoundingBox(SkScalar width, SkIRect box,
halcanary7e8d5d32016-08-12 07:59:38 -0700341 SkDynamicMemoryWStream* content) {
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000342 // Specify width and bounding box for the glyph.
halcanarybc4696b2015-05-06 10:56:04 -0700343 SkPDFUtils::AppendScalar(width, content);
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +0000344 content->writeText(" 0 ");
345 content->writeDecAsText(box.fLeft);
346 content->writeText(" ");
347 content->writeDecAsText(box.fTop);
348 content->writeText(" ");
349 content->writeDecAsText(box.fRight);
350 content->writeText(" ");
351 content->writeDecAsText(box.fBottom);
352 content->writeText(" d1\n");
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000353}
354
halcanary8103a342016-03-08 15:10:16 -0800355static sk_sp<SkPDFArray> makeFontBBox(SkIRect glyphBBox, uint16_t emSize) {
356 auto bbox = sk_make_sp<SkPDFArray>();
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000357 bbox->reserve(4);
reed@google.comc789cf12011-07-20 12:14:33 +0000358 bbox->appendScalar(scaleFromFontUnits(glyphBBox.fLeft, emSize));
359 bbox->appendScalar(scaleFromFontUnits(glyphBBox.fBottom, emSize));
360 bbox->appendScalar(scaleFromFontUnits(glyphBBox.fRight, emSize));
361 bbox->appendScalar(scaleFromFontUnits(glyphBBox.fTop, emSize));
halcanary51d04d32016-03-08 13:03:55 -0800362 return bbox;
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000363}
364
halcanary462d0142016-08-05 13:51:46 -0700365sk_sp<SkPDFArray> composeAdvanceData(
halcanary8b1d32c2016-08-08 09:09:59 -0700366 const SkSinglyLinkedList<AdvanceMetric>& advanceInfo,
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000367 uint16_t emSize,
halcanary462d0142016-08-05 13:51:46 -0700368 int16_t* defaultAdvance) {
369 auto result = sk_make_sp<SkPDFArray>();
halcanary8b1d32c2016-08-08 09:09:59 -0700370 for (const AdvanceMetric& range : advanceInfo) {
halcanarye20a8752016-05-08 18:47:16 -0700371 switch (range.fType) {
halcanary8b1d32c2016-08-08 09:09:59 -0700372 case AdvanceMetric::kDefault: {
halcanarye20a8752016-05-08 18:47:16 -0700373 SkASSERT(range.fAdvance.count() == 1);
374 *defaultAdvance = range.fAdvance[0];
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000375 break;
376 }
halcanary8b1d32c2016-08-08 09:09:59 -0700377 case AdvanceMetric::kRange: {
halcanaryece83922016-03-08 08:32:12 -0800378 auto advanceArray = sk_make_sp<SkPDFArray>();
halcanarye20a8752016-05-08 18:47:16 -0700379 for (int j = 0; j < range.fAdvance.count(); j++)
halcanary462d0142016-08-05 13:51:46 -0700380 advanceArray->appendScalar(
381 scaleFromFontUnits(range.fAdvance[j], emSize));
halcanarye20a8752016-05-08 18:47:16 -0700382 result->appendInt(range.fStartId);
halcanary8103a342016-03-08 15:10:16 -0800383 result->appendObject(std::move(advanceArray));
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000384 break;
385 }
halcanary8b1d32c2016-08-08 09:09:59 -0700386 case AdvanceMetric::kRun: {
halcanarye20a8752016-05-08 18:47:16 -0700387 SkASSERT(range.fAdvance.count() == 1);
388 result->appendInt(range.fStartId);
389 result->appendInt(range.fEndId);
halcanary462d0142016-08-05 13:51:46 -0700390 result->appendScalar(
391 scaleFromFontUnits(range.fAdvance[0], emSize));
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000392 break;
393 }
394 }
395 }
396 return result;
397}
398
399} // namespace
400
vandebo@chromium.org98594282011-07-25 22:34:12 +0000401
402///////////////////////////////////////////////////////////////////////////////
403// class SkPDFGlyphSet
404///////////////////////////////////////////////////////////////////////////////
405
406SkPDFGlyphSet::SkPDFGlyphSet() : fBitSet(SK_MaxU16 + 1) {
407}
408
409void SkPDFGlyphSet::set(const uint16_t* glyphIDs, int numGlyphs) {
410 for (int i = 0; i < numGlyphs; ++i) {
411 fBitSet.setBit(glyphIDs[i], true);
412 }
413}
414
415bool SkPDFGlyphSet::has(uint16_t glyphID) const {
416 return fBitSet.isBitSet(glyphID);
417}
418
vandebo@chromium.org17e66e22011-07-27 20:59:55 +0000419void SkPDFGlyphSet::exportTo(SkTDArray<unsigned int>* glyphIDs) const {
420 fBitSet.exportTo(glyphIDs);
421}
halcanaryfe8f0e02016-07-27 14:14:04 -0700422
vandebo@chromium.org98594282011-07-25 22:34:12 +0000423///////////////////////////////////////////////////////////////////////////////
424// class SkPDFGlyphSetMap
425///////////////////////////////////////////////////////////////////////////////
vandebo@chromium.org98594282011-07-25 22:34:12 +0000426
halcanary3c35fb32016-06-30 11:55:07 -0700427SkPDFGlyphSetMap::SkPDFGlyphSetMap() {}
vandebo@chromium.org98594282011-07-25 22:34:12 +0000428
429SkPDFGlyphSetMap::~SkPDFGlyphSetMap() {
vandebo@chromium.org98594282011-07-25 22:34:12 +0000430 fMap.reset();
431}
432
433void SkPDFGlyphSetMap::noteGlyphUsage(SkPDFFont* font, const uint16_t* glyphIDs,
434 int numGlyphs) {
435 SkPDFGlyphSet* subset = getGlyphSetForFont(font);
436 if (subset) {
437 subset->set(glyphIDs, numGlyphs);
438 }
439}
440
441SkPDFGlyphSet* SkPDFGlyphSetMap::getGlyphSetForFont(SkPDFFont* font) {
442 int index = fMap.count();
443 for (int i = 0; i < index; ++i) {
444 if (fMap[i].fFont == font) {
halcanary3c35fb32016-06-30 11:55:07 -0700445 return &fMap[i].fGlyphSet;
vandebo@chromium.org98594282011-07-25 22:34:12 +0000446 }
447 }
halcanary3c35fb32016-06-30 11:55:07 -0700448 FontGlyphSetPair& pair = fMap.push_back();
449 pair.fFont = font;
450 return &pair.fGlyphSet;
vandebo@chromium.org98594282011-07-25 22:34:12 +0000451}
452
453///////////////////////////////////////////////////////////////////////////////
454// class SkPDFFont
455///////////////////////////////////////////////////////////////////////////////
456
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000457/* Font subset design: It would be nice to be able to subset fonts
458 * (particularly type 3 fonts), but it's a lot of work and not a priority.
459 *
460 * Resources are canonicalized and uniqueified by pointer so there has to be
461 * some additional state indicating which subset of the font is used. It
462 * must be maintained at the page granularity and then combined at the document
463 * granularity. a) change SkPDFFont to fill in its state on demand, kind of
464 * like SkPDFGraphicState. b) maintain a per font glyph usage class in each
465 * page/pdf device. c) in the document, retrieve the per font glyph usage
466 * from each page and combine it and ask for a resource with that subset.
467 */
468
halcanary2e3f9d82015-02-27 12:41:03 -0800469SkPDFFont::~SkPDFFont() {}
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000470
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000471SkTypeface* SkPDFFont::typeface() {
472 return fTypeface.get();
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000473}
474
vandebo@chromium.orgf0ec2662011-05-29 05:55:42 +0000475SkAdvancedTypefaceMetrics::FontType SkPDFFont::getType() {
vandebo@chromium.org98594282011-07-25 22:34:12 +0000476 return fFontType;
vandebo@chromium.orgf0ec2662011-05-29 05:55:42 +0000477}
478
vandebo0f9bad02014-06-19 11:05:39 -0700479bool SkPDFFont::canEmbed() const {
480 if (!fFontInfo.get()) {
481 SkASSERT(fFontType == SkAdvancedTypefaceMetrics::kOther_Font);
482 return true;
483 }
484 return (fFontInfo->fFlags &
485 SkAdvancedTypefaceMetrics::kNotEmbeddable_FontFlag) == 0;
486}
487
488bool SkPDFFont::canSubset() const {
489 if (!fFontInfo.get()) {
490 SkASSERT(fFontType == SkAdvancedTypefaceMetrics::kOther_Font);
491 return true;
492 }
493 return (fFontInfo->fFlags &
494 SkAdvancedTypefaceMetrics::kNotSubsettable_FontFlag) == 0;
495}
496
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000497bool SkPDFFont::hasGlyph(uint16_t id) {
498 return (id >= fFirstGlyphID && id <= fLastGlyphID) || id == 0;
499}
500
halcanary4ed2f012016-08-15 18:40:07 -0700501int SkPDFFont::glyphsToPDFFontEncoding(SkGlyphID* glyphIDs, int numGlyphs) const {
vandebo@chromium.org01294102011-02-28 19:52:18 +0000502 // A font with multibyte glyphs will support all glyph IDs in a single font.
vandebo@chromium.org98594282011-07-25 22:34:12 +0000503 if (this->multiByteGlyphs()) {
vandebo@chromium.org01294102011-02-28 19:52:18 +0000504 return numGlyphs;
505 }
506
reed@google.comaec40662014-04-18 19:29:07 +0000507 for (int i = 0; i < numGlyphs; i++) {
vandebo@chromium.org01294102011-02-28 19:52:18 +0000508 if (glyphIDs[i] == 0) {
509 continue;
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000510 }
vandebo@chromium.org01294102011-02-28 19:52:18 +0000511 if (glyphIDs[i] < fFirstGlyphID || glyphIDs[i] > fLastGlyphID) {
512 return i;
513 }
514 glyphIDs[i] -= (fFirstGlyphID - 1);
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000515 }
516
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000517 return numGlyphs;
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000518}
519
halcanary4ed2f012016-08-15 18:40:07 -0700520int SkPDFFont::glyphsToPDFFontEncodingCount(const SkGlyphID* glyphIDs,
521 int numGlyphs) const {
522 if (this->multiByteGlyphs()) { // A font with multibyte glyphs will
523 return numGlyphs; // support all glyph IDs in a single font.
524 }
525 for (int i = 0; i < numGlyphs; i++) {
526 if (glyphIDs[i] != 0 &&
527 (glyphIDs[i] < fFirstGlyphID || glyphIDs[i] > fLastGlyphID)) {
528 return i;
529 }
530 }
531 return numGlyphs;
532}
533
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000534// static
halcanary792c80f2015-02-20 07:21:05 -0800535SkPDFFont* SkPDFFont::GetFontResource(SkPDFCanon* canon,
536 SkTypeface* typeface,
537 uint16_t glyphID) {
538 SkASSERT(canon);
halcanary7e8d5d32016-08-12 07:59:38 -0700539 const uint32_t fontID = SkTypeface::UniqueID(typeface);
halcanaryfb62b3d2015-01-21 09:59:14 -0800540 SkPDFFont* relatedFont;
halcanary792c80f2015-02-20 07:21:05 -0800541 if (SkPDFFont* pdfFont = canon->findFont(fontID, glyphID, &relatedFont)) {
halcanaryfb62b3d2015-01-21 09:59:14 -0800542 return SkRef(pdfFont);
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000543 }
halcanary7e8d5d32016-08-12 07:59:38 -0700544 SkAutoResolveDefaultTypeface autoResolve(typeface);
545 typeface = autoResolve.get();
546 SkASSERT(typeface);
547 int glyphCount = typeface->countGlyphs();
548 if (glyphCount < 1 || // typeface lacks even a NOTDEF glyph.
549 glyphCount > 1 + SK_MaxU16 || // invalid glyphCount
550 glyphID >= glyphCount) { // invalid glyph
551 return nullptr;
552 }
halcanary48810a02016-03-07 14:57:50 -0800553 sk_sp<const SkAdvancedTypefaceMetrics> fontMetrics;
halcanary96fcdcc2015-08-27 07:41:13 -0700554 SkPDFDict* relatedFontDescriptor = nullptr;
halcanaryfb62b3d2015-01-21 09:59:14 -0800555 if (relatedFont) {
556 fontMetrics.reset(SkSafeRef(relatedFont->fontInfo()));
vandebo@chromium.org98594282011-07-25 22:34:12 +0000557 relatedFontDescriptor = relatedFont->getFontDescriptor();
edisonn@google.com022e8572012-10-23 21:32:39 +0000558
559 // This only is to catch callers who pass invalid glyph ids.
560 // If glyph id is invalid, then we will create duplicate entries
vandebo0f9bad02014-06-19 11:05:39 -0700561 // for TrueType fonts.
skia.committer@gmail.com1e34ff72012-10-24 02:01:24 +0000562 SkAdvancedTypefaceMetrics::FontType fontType =
edisonn@google.com022e8572012-10-23 21:32:39 +0000563 fontMetrics.get() ? fontMetrics.get()->fType :
564 SkAdvancedTypefaceMetrics::kOther_Font;
565
566 if (fontType == SkAdvancedTypefaceMetrics::kType1CID_Font ||
567 fontType == SkAdvancedTypefaceMetrics::kTrueType_Font) {
halcanaryfb62b3d2015-01-21 09:59:14 -0800568 return SkRef(relatedFont);
skia.committer@gmail.com1e34ff72012-10-24 02:01:24 +0000569 }
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000570 } else {
halcanary462d0142016-08-05 13:51:46 -0700571 SkTypeface::PerGlyphInfo info =
572 SkTBitOr(SkTypeface::kGlyphNames_PerGlyphInfo,
573 SkTypeface::kToUnicode_PerGlyphInfo);
vandebo@chromium.orgd96d17b2013-01-04 19:31:24 +0000574 fontMetrics.reset(
halcanary96fcdcc2015-08-27 07:41:13 -0700575 typeface->getAdvancedTypefaceMetrics(info, nullptr, 0));
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000576 }
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000577
halcanary792c80f2015-02-20 07:21:05 -0800578 SkPDFFont* font = SkPDFFont::Create(canon, fontMetrics.get(), typeface,
579 glyphID, relatedFontDescriptor);
580 canon->addFont(font, fontID, font->fFirstGlyphID);
581 return font;
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>
halcanary2e3f9d82015-02-27 12:41:03 -0800589SkPDFFont::SkPDFFont(const SkAdvancedTypefaceMetrics* info,
halcanaryfb747e22014-07-11 19:45:23 -0700590 SkTypeface* typeface,
sugoi@google.come2e81132013-03-05 18:35:55 +0000591 SkPDFDict* relatedFontDescriptor)
halcanary792c80f2015-02-20 07:21:05 -0800592 : SkPDFDict("Font")
halcanary792c80f2015-02-20 07:21:05 -0800593 , fTypeface(ref_or_default(typeface))
594 , fFirstGlyphID(1)
595 , fLastGlyphID(info ? info->fLastGlyphID : 0)
596 , fFontInfo(SkSafeRef(info))
halcanary7e8d5d32016-08-12 07:59:38 -0700597 , fDescriptor(SkSafeRef(relatedFontDescriptor))
598 , fFontType((!info || info->fFlags & SkAdvancedTypefaceMetrics::kMultiMaster_FontFlag)
599 ? SkAdvancedTypefaceMetrics::kOther_Font
600 : info->fType) {
601 SkASSERT(fTypeface);
602 if (0 == fLastGlyphID) {
603 fLastGlyphID = SkToU16(fTypeface->countGlyphs() - 1);
vandebo@chromium.org98594282011-07-25 22:34:12 +0000604 }
605}
606
607// static
halcanary792c80f2015-02-20 07:21:05 -0800608SkPDFFont* SkPDFFont::Create(SkPDFCanon* canon,
609 const SkAdvancedTypefaceMetrics* info,
610 SkTypeface* typeface,
611 uint16_t glyphID,
vandebo@chromium.org98594282011-07-25 22:34:12 +0000612 SkPDFDict* relatedFontDescriptor) {
613 SkAdvancedTypefaceMetrics::FontType type =
vandebo0f9bad02014-06-19 11:05:39 -0700614 info ? info->fType : SkAdvancedTypefaceMetrics::kOther_Font;
halcanary7e8d5d32016-08-12 07:59:38 -0700615 SkAdvancedTypefaceMetrics::FontFlags flags =
616 info ? info->fFlags : SkAdvancedTypefaceMetrics::kEmpty_FontFlag;
617 if (SkToBool(flags & SkAdvancedTypefaceMetrics::kMultiMaster_FontFlag)) {
halcanary2e3f9d82015-02-27 12:41:03 -0800618 return new SkPDFType3Font(info, typeface, glyphID);
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +0000619 }
halcanary7e8d5d32016-08-12 07:59:38 -0700620 switch (type) {
621 case SkAdvancedTypefaceMetrics::kType1CID_Font:
622 case SkAdvancedTypefaceMetrics::kTrueType_Font:
623 SkASSERT(relatedFontDescriptor == nullptr);
624 SkASSERT(info != nullptr);
625 return new SkPDFType0Font(info, typeface);
626 case SkAdvancedTypefaceMetrics::kType1_Font:
627 SkASSERT(info != nullptr);
628 return new SkPDFType1Font(info, typeface, glyphID, relatedFontDescriptor);
629 case SkAdvancedTypefaceMetrics::kCFF_Font:
630 SkASSERT(info != nullptr);
631 // fallthrough
632 case SkAdvancedTypefaceMetrics::kOther_Font:
633 return new SkPDFType3Font(info, typeface, glyphID);
vandebo@chromium.org98594282011-07-25 22:34:12 +0000634 }
halcanary7e8d5d32016-08-12 07:59:38 -0700635 SkDEBUGFAIL("invalid SkAdvancedTypefaceMetrics::FontType");
636 return nullptr;
vandebo@chromium.org31dcee72011-07-23 21:13:30 +0000637}
638
halcanaryfb747e22014-07-11 19:45:23 -0700639const SkAdvancedTypefaceMetrics* SkPDFFont::fontInfo() {
vandebo@chromium.org98594282011-07-25 22:34:12 +0000640 return fFontInfo.get();
vandebo@chromium.org31dcee72011-07-23 21:13:30 +0000641}
642
halcanaryfb747e22014-07-11 19:45:23 -0700643void SkPDFFont::setFontInfo(const SkAdvancedTypefaceMetrics* info) {
halcanary96fcdcc2015-08-27 07:41:13 -0700644 if (info == nullptr || info == fFontInfo.get()) {
vandebo@chromium.org37ad8fb2011-08-18 02:38:50 +0000645 return;
646 }
vandebo@chromium.orgd96d17b2013-01-04 19:31:24 +0000647 fFontInfo.reset(info);
648 SkSafeRef(info);
vandebo@chromium.org37ad8fb2011-08-18 02:38:50 +0000649}
650
vandebo@chromium.org98594282011-07-25 22:34:12 +0000651uint16_t SkPDFFont::firstGlyphID() const {
652 return fFirstGlyphID;
653}
654
655uint16_t SkPDFFont::lastGlyphID() const {
656 return fLastGlyphID;
657}
658
659void SkPDFFont::setLastGlyphID(uint16_t glyphID) {
660 fLastGlyphID = glyphID;
661}
662
vandebo@chromium.org98594282011-07-25 22:34:12 +0000663SkPDFDict* SkPDFFont::getFontDescriptor() {
664 return fDescriptor.get();
665}
666
667void SkPDFFont::setFontDescriptor(SkPDFDict* descriptor) {
vandebo@chromium.orgd96d17b2013-01-04 19:31:24 +0000668 fDescriptor.reset(descriptor);
669 SkSafeRef(descriptor);
vandebo@chromium.org98594282011-07-25 22:34:12 +0000670}
671
672bool SkPDFFont::addCommonFontDescriptorEntries(int16_t defaultWidth) {
halcanary96fcdcc2015-08-27 07:41:13 -0700673 if (fDescriptor.get() == nullptr) {
vandebo@chromium.org98594282011-07-25 22:34:12 +0000674 return false;
vandebo@chromium.org31dcee72011-07-23 21:13:30 +0000675 }
676
vandebo@chromium.org98594282011-07-25 22:34:12 +0000677 const uint16_t emSize = fFontInfo->fEmSize;
678
679 fDescriptor->insertName("FontName", fFontInfo->fFontName);
vandebo@chromium.orgdcf9c192013-03-13 20:01:51 +0000680 fDescriptor->insertInt("Flags", fFontInfo->fStyle | kPdfSymbolic);
vandebo@chromium.org98594282011-07-25 22:34:12 +0000681 fDescriptor->insertScalar("Ascent",
682 scaleFromFontUnits(fFontInfo->fAscent, emSize));
683 fDescriptor->insertScalar("Descent",
684 scaleFromFontUnits(fFontInfo->fDescent, emSize));
685 fDescriptor->insertScalar("StemV",
686 scaleFromFontUnits(fFontInfo->fStemV, emSize));
halcanaryfb747e22014-07-11 19:45:23 -0700687
vandebo@chromium.org98594282011-07-25 22:34:12 +0000688 fDescriptor->insertScalar("CapHeight",
689 scaleFromFontUnits(fFontInfo->fCapHeight, emSize));
690 fDescriptor->insertInt("ItalicAngle", fFontInfo->fItalicAngle);
halcanarybf51cfd2015-05-05 10:24:09 -0700691 fDescriptor->insertObject(
692 "FontBBox", makeFontBBox(fFontInfo->fBBox, fFontInfo->fEmSize));
vandebo@chromium.org98594282011-07-25 22:34:12 +0000693
694 if (defaultWidth > 0) {
695 fDescriptor->insertScalar("MissingWidth",
696 scaleFromFontUnits(defaultWidth, emSize));
697 }
698 return true;
699}
700
bungeman22edc832014-10-03 07:55:58 -0700701void SkPDFFont::adjustGlyphRangeForSingleByteEncoding(uint16_t glyphID) {
vandebo@chromium.org98594282011-07-25 22:34:12 +0000702 // Single byte glyph encoding supports a max of 255 glyphs.
703 fFirstGlyphID = glyphID - (glyphID - 1) % 255;
704 if (fLastGlyphID > fFirstGlyphID + 255 - 1) {
705 fLastGlyphID = fFirstGlyphID + 255 - 1;
706 }
707}
708
vandebo@chromium.org98594282011-07-25 22:34:12 +0000709void SkPDFFont::populateToUnicodeTable(const SkPDFGlyphSet* subset) {
halcanary96fcdcc2015-08-27 07:41:13 -0700710 if (fFontInfo == nullptr || fFontInfo->fGlyphToUnicode.begin() == nullptr) {
vandebo@chromium.org98594282011-07-25 22:34:12 +0000711 return;
712 }
halcanarybf51cfd2015-05-05 10:24:09 -0700713 this->insertObjRef("ToUnicode",
halcanary8eccc302016-08-09 13:04:34 -0700714 SkPDFMakeToUnicodeCmap(fFontInfo->fGlyphToUnicode,
715 subset,
716 multiByteGlyphs(),
717 firstGlyphID(),
718 lastGlyphID()));
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000719}
720
vandebo@chromium.org98594282011-07-25 22:34:12 +0000721///////////////////////////////////////////////////////////////////////////////
722// class SkPDFType0Font
723///////////////////////////////////////////////////////////////////////////////
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000724
robertphillips8e0c1502015-07-07 10:28:43 -0700725SkPDFType0Font::SkPDFType0Font(const SkAdvancedTypefaceMetrics* info, SkTypeface* typeface)
halcanary96fcdcc2015-08-27 07:41:13 -0700726 : SkPDFFont(info, typeface, nullptr) {
vandebo@chromium.org98594282011-07-25 22:34:12 +0000727 SkDEBUGCODE(fPopulated = false);
vandebo0f9bad02014-06-19 11:05:39 -0700728 if (!canSubset()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700729 this->populate(nullptr);
vandebo0f9bad02014-06-19 11:05:39 -0700730 }
vandebo@chromium.org98594282011-07-25 22:34:12 +0000731}
732
733SkPDFType0Font::~SkPDFType0Font() {}
734
halcanary7e8d5d32016-08-12 07:59:38 -0700735sk_sp<SkPDFObject> SkPDFType0Font::getFontSubset(const SkPDFGlyphSet* subset) {
vandebo0f9bad02014-06-19 11:05:39 -0700736 if (!canSubset()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700737 return nullptr;
vandebo0f9bad02014-06-19 11:05:39 -0700738 }
halcanary7e8d5d32016-08-12 07:59:38 -0700739 auto newSubset = sk_make_sp<SkPDFType0Font>(fontInfo(), typeface());
vandebo@chromium.org98594282011-07-25 22:34:12 +0000740 newSubset->populate(subset);
741 return newSubset;
742}
743
744#ifdef SK_DEBUG
halcanary37c46ca2015-03-31 12:30:20 -0700745void SkPDFType0Font::emitObject(SkWStream* stream,
746 const SkPDFObjNumMap& objNumMap,
halcanarya060eba2015-08-19 12:26:46 -0700747 const SkPDFSubstituteMap& substitutes) const {
vandebo@chromium.org98594282011-07-25 22:34:12 +0000748 SkASSERT(fPopulated);
halcanary37c46ca2015-03-31 12:30:20 -0700749 return INHERITED::emitObject(stream, objNumMap, substitutes);
vandebo@chromium.org98594282011-07-25 22:34:12 +0000750}
751#endif
752
753bool SkPDFType0Font::populate(const SkPDFGlyphSet* subset) {
754 insertName("Subtype", "Type0");
755 insertName("BaseFont", fontInfo()->fFontName);
756 insertName("Encoding", "Identity-H");
757
halcanary48810a02016-03-07 14:57:50 -0800758 sk_sp<SkPDFCIDFont> newCIDFont(
halcanary2e3f9d82015-02-27 12:41:03 -0800759 new SkPDFCIDFont(fontInfo(), typeface(), subset));
halcanaryece83922016-03-08 08:32:12 -0800760 auto descendantFonts = sk_make_sp<SkPDFArray>();
halcanary8103a342016-03-08 15:10:16 -0800761 descendantFonts->appendObjRef(std::move(newCIDFont));
762 this->insertObject("DescendantFonts", std::move(descendantFonts));
vandebo@chromium.org98594282011-07-25 22:34:12 +0000763
robertphillips8e0c1502015-07-07 10:28:43 -0700764 this->populateToUnicodeTable(subset);
vandebo@chromium.org98594282011-07-25 22:34:12 +0000765
766 SkDEBUGCODE(fPopulated = true);
767 return true;
768}
769
770///////////////////////////////////////////////////////////////////////////////
771// class SkPDFCIDFont
772///////////////////////////////////////////////////////////////////////////////
773
halcanary2e3f9d82015-02-27 12:41:03 -0800774SkPDFCIDFont::SkPDFCIDFont(const SkAdvancedTypefaceMetrics* info,
halcanary792c80f2015-02-20 07:21:05 -0800775 SkTypeface* typeface,
776 const SkPDFGlyphSet* subset)
halcanary96fcdcc2015-08-27 07:41:13 -0700777 : SkPDFFont(info, typeface, nullptr) {
robertphillips8e0c1502015-07-07 10:28:43 -0700778 this->populate(subset);
vandebo@chromium.org98594282011-07-25 22:34:12 +0000779}
780
781SkPDFCIDFont::~SkPDFCIDFont() {}
782
halcanaryfe8f0e02016-07-27 14:14:04 -0700783#ifdef SK_SFNTLY_SUBSETTER
784// if possible, make no copy.
785static sk_sp<SkData> stream_to_data(std::unique_ptr<SkStreamAsset> stream) {
786 SkASSERT(stream);
787 (void)stream->rewind();
788 SkASSERT(stream->hasLength());
789 size_t size = stream->getLength();
790 if (const void* base = stream->getMemoryBase()) {
791 SkData::ReleaseProc proc =
792 [](const void*, void* ctx) { delete (SkStream*)ctx; };
793 return SkData::MakeWithProc(base, size, proc, stream.release());
794 }
795 return SkData::MakeFromStream(stream.get(), size);
796}
797
798static sk_sp<SkPDFObject> get_subset_font_stream(
799 std::unique_ptr<SkStreamAsset> fontAsset,
800 const SkTDArray<uint32_t>& subset,
801 const char* fontName) {
802 // sfntly requires unsigned int* to be passed in,
803 // as far as we know, unsigned int is equivalent
804 // to uint32_t on all platforms.
805 static_assert(sizeof(unsigned) == sizeof(uint32_t), "");
806
807 // TODO(halcanary): Use ttcIndex, not fontName.
808
809 unsigned char* subsetFont{nullptr};
810 int subsetFontSize{0};
811 {
812 sk_sp<SkData> fontData(stream_to_data(std::move(fontAsset)));
813 subsetFontSize =
814 SfntlyWrapper::SubsetFont(fontName,
815 fontData->bytes(),
816 fontData->size(),
817 subset.begin(),
818 subset.count(),
819 &subsetFont);
820 }
821 SkASSERT(subsetFontSize > 0 || subsetFont == nullptr);
822 if (subsetFontSize < 1) {
823 return nullptr;
824 }
825 SkASSERT(subsetFont != nullptr);
826 auto subsetStream = sk_make_sp<SkPDFStream>(
827 SkData::MakeWithProc(
828 subsetFont, subsetFontSize,
829 [](const void* p, void*) { delete[] (unsigned char*)p; },
830 nullptr));
halcanaryfa251062016-07-29 10:13:18 -0700831 subsetStream->dict()->insertInt("Length1", subsetFontSize);
halcanaryfe8f0e02016-07-27 14:14:04 -0700832 return subsetStream;
833}
834#endif // SK_SFNTLY_SUBSETTER
835
vandebo@chromium.org98594282011-07-25 22:34:12 +0000836bool SkPDFCIDFont::addFontDescriptor(int16_t defaultWidth,
vandebo@chromium.org37ad8fb2011-08-18 02:38:50 +0000837 const SkTDArray<uint32_t>* subset) {
halcanaryece83922016-03-08 08:32:12 -0800838 auto descriptor = sk_make_sp<SkPDFDict>("FontDescriptor");
vandebo@chromium.org98594282011-07-25 22:34:12 +0000839 setFontDescriptor(descriptor.get());
vandebo0f9bad02014-06-19 11:05:39 -0700840 if (!addCommonFontDescriptorEntries(defaultWidth)) {
halcanary8103a342016-03-08 15:10:16 -0800841 this->insertObjRef("FontDescriptor", std::move(descriptor));
vandebo0f9bad02014-06-19 11:05:39 -0700842 return false;
843 }
halcanary66a82f32015-10-12 13:05:04 -0700844 SkASSERT(this->canEmbed());
vandebo@chromium.org98594282011-07-25 22:34:12 +0000845
846 switch (getType()) {
847 case SkAdvancedTypefaceMetrics::kTrueType_Font: {
halcanaryfe8f0e02016-07-27 14:14:04 -0700848 int ttcIndex;
849 std::unique_ptr<SkStreamAsset> fontAsset(
850 this->typeface()->openStream(&ttcIndex));
851 SkASSERT(fontAsset);
852 if (!fontAsset) {
halcanary32431432016-03-30 12:59:14 -0700853 return false;
854 }
halcanaryfe8f0e02016-07-27 14:14:04 -0700855 size_t fontSize = fontAsset->getLength();
halcanary725c6202015-08-20 08:09:37 -0700856 SkASSERT(fontSize > 0);
halcanaryfe8f0e02016-07-27 14:14:04 -0700857 if (fontSize == 0) {
858 return false;
859 }
860
861 #ifdef SK_SFNTLY_SUBSETTER
862 if (this->canSubset() && subset) {
863 sk_sp<SkPDFObject> subsetStream = get_subset_font_stream(
864 std::move(fontAsset), *subset, fontInfo()->fFontName.c_str());
865 if (subsetStream) {
866 descriptor->insertObjRef("FontFile2", std::move(subsetStream));
867 break;
868 }
869 // If subsetting fails, fall back to original font data.
870 fontAsset.reset(this->typeface()->openStream(&ttcIndex));
871 }
872 #endif // SK_SFNTLY_SUBSETTER
halcanaryfa251062016-07-29 10:13:18 -0700873 auto fontStream = sk_make_sp<SkPDFSharedStream>(std::move(fontAsset));
halcanary725c6202015-08-20 08:09:37 -0700874 fontStream->dict()->insertInt("Length1", fontSize);
halcanary8103a342016-03-08 15:10:16 -0800875 descriptor->insertObjRef("FontFile2", std::move(fontStream));
vandebo@chromium.org98594282011-07-25 22:34:12 +0000876 break;
877 }
878 case SkAdvancedTypefaceMetrics::kCFF_Font:
879 case SkAdvancedTypefaceMetrics::kType1CID_Font: {
halcanary32431432016-03-30 12:59:14 -0700880 std::unique_ptr<SkStreamAsset> fontData(
881 this->typeface()->openStream(nullptr));
882 SkASSERT(fontData);
883 SkASSERT(fontData->getLength() > 0);
884 if (!fontData || 0 == fontData->getLength()) {
885 return false;
886 }
halcanaryfa251062016-07-29 10:13:18 -0700887 auto fontStream = sk_make_sp<SkPDFSharedStream>(std::move(fontData));
vandebo@chromium.org98594282011-07-25 22:34:12 +0000888 if (getType() == SkAdvancedTypefaceMetrics::kCFF_Font) {
halcanary725c6202015-08-20 08:09:37 -0700889 fontStream->dict()->insertName("Subtype", "Type1C");
vandebo@chromium.org98594282011-07-25 22:34:12 +0000890 } else {
halcanary725c6202015-08-20 08:09:37 -0700891 fontStream->dict()->insertName("Subtype", "CIDFontType0c");
vandebo@chromium.org98594282011-07-25 22:34:12 +0000892 }
halcanary8103a342016-03-08 15:10:16 -0800893 descriptor->insertObjRef("FontFile3", std::move(fontStream));
vandebo@chromium.org98594282011-07-25 22:34:12 +0000894 break;
895 }
896 default:
897 SkASSERT(false);
898 }
halcanary8103a342016-03-08 15:10:16 -0800899 this->insertObjRef("FontDescriptor", std::move(descriptor));
vandebo0f9bad02014-06-19 11:05:39 -0700900 return true;
vandebo@chromium.org98594282011-07-25 22:34:12 +0000901}
902
halcanary462d0142016-08-05 13:51:46 -0700903void set_glyph_widths(SkTypeface* tf,
904 const SkTDArray<uint32_t>* glyphIDs,
halcanary8b1d32c2016-08-08 09:09:59 -0700905 SkSinglyLinkedList<AdvanceMetric>* dst) {
halcanary462d0142016-08-05 13:51:46 -0700906 SkPaint tmpPaint;
907 tmpPaint.setHinting(SkPaint::kNo_Hinting);
908 tmpPaint.setTypeface(sk_ref_sp(tf));
909 tmpPaint.setTextSize((SkScalar)tf->getUnitsPerEm());
halcanary7e8d5d32016-08-12 07:59:38 -0700910 const SkSurfaceProps props(0, kUnknown_SkPixelGeometry);
911 SkAutoGlyphCache autoGlyphCache(tmpPaint, &props, nullptr);
halcanary462d0142016-08-05 13:51:46 -0700912 if (!glyphIDs || glyphIDs->isEmpty()) {
halcanary8b1d32c2016-08-08 09:09:59 -0700913 get_glyph_widths(dst, tf->countGlyphs(), nullptr, 0, autoGlyphCache.get());
halcanary462d0142016-08-05 13:51:46 -0700914 } else {
halcanary8b1d32c2016-08-08 09:09:59 -0700915 get_glyph_widths(dst, tf->countGlyphs(), glyphIDs->begin(),
916 glyphIDs->count(), autoGlyphCache.get());
halcanary462d0142016-08-05 13:51:46 -0700917 }
918}
919
halcanary8eccc302016-08-09 13:04:34 -0700920sk_sp<const SkAdvancedTypefaceMetrics> SkPDFFont::GetFontMetricsWithGlyphNames(
921 SkTypeface* typeface, uint32_t* glyphs, uint32_t glyphsCount) {
922 return sk_sp<const SkAdvancedTypefaceMetrics>(
923 typeface->getAdvancedTypefaceMetrics(
924 SkTypeface::kGlyphNames_PerGlyphInfo, glyphs, glyphsCount));
925}
926
927sk_sp<const SkAdvancedTypefaceMetrics> SkPDFFont::GetFontMetricsWithToUnicode(
928 SkTypeface* typeface, uint32_t* glyphs, uint32_t glyphsCount) {
929 return sk_sp<const SkAdvancedTypefaceMetrics>(
930 typeface->getAdvancedTypefaceMetrics(
931 SkTypeface::kToUnicode_PerGlyphInfo, glyphs, glyphsCount));
932}
933
vandebo@chromium.org98594282011-07-25 22:34:12 +0000934bool SkPDFCIDFont::populate(const SkPDFGlyphSet* subset) {
vandebo@chromium.org37ad8fb2011-08-18 02:38:50 +0000935 // Generate new font metrics with advance info for true type fonts.
halcanary462d0142016-08-05 13:51:46 -0700936 // Generate glyph id array.
937 SkTDArray<uint32_t> glyphIDs;
938 if (subset) {
939 if (!subset->has(0)) {
940 glyphIDs.push(0); // Always include glyph 0.
vandebo@chromium.org37ad8fb2011-08-18 02:38:50 +0000941 }
halcanary462d0142016-08-05 13:51:46 -0700942 subset->exportTo(&glyphIDs);
943 }
944 if (fontInfo()->fType == SkAdvancedTypefaceMetrics::kTrueType_Font) {
halcanary96fcdcc2015-08-27 07:41:13 -0700945 uint32_t* glyphs = (glyphIDs.count() == 0) ? nullptr : glyphIDs.begin();
vandebo@chromium.org37ad8fb2011-08-18 02:38:50 +0000946 uint32_t glyphsCount = glyphs ? glyphIDs.count() : 0;
halcanary8eccc302016-08-09 13:04:34 -0700947 sk_sp<const SkAdvancedTypefaceMetrics> fontMetrics =
948 SkPDFFont::GetFontMetricsWithGlyphNames(this->typeface(), glyphs, glyphsCount);
949 this->setFontInfo(fontMetrics.get());
950 this->addFontDescriptor(0, &glyphIDs);
vandebo@chromium.org37ad8fb2011-08-18 02:38:50 +0000951 } else {
952 // Other CID fonts
halcanary96fcdcc2015-08-27 07:41:13 -0700953 addFontDescriptor(0, nullptr);
vandebo@chromium.org37ad8fb2011-08-18 02:38:50 +0000954 }
955
vandebo@chromium.org98594282011-07-25 22:34:12 +0000956 insertName("BaseFont", fontInfo()->fFontName);
957
958 if (getType() == SkAdvancedTypefaceMetrics::kType1CID_Font) {
reed@google.comc789cf12011-07-20 12:14:33 +0000959 insertName("Subtype", "CIDFontType0");
vandebo@chromium.org98594282011-07-25 22:34:12 +0000960 } else if (getType() == SkAdvancedTypefaceMetrics::kTrueType_Font) {
reed@google.comc789cf12011-07-20 12:14:33 +0000961 insertName("Subtype", "CIDFontType2");
962 insertName("CIDToGIDMap", "Identity");
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000963 } else {
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000964 SkASSERT(false);
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000965 }
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000966
halcanaryece83922016-03-08 08:32:12 -0800967 auto sysInfo = sk_make_sp<SkPDFDict>();
halcanarybf51cfd2015-05-05 10:24:09 -0700968 sysInfo->insertString("Registry", "Adobe");
969 sysInfo->insertString("Ordering", "Identity");
reed@google.comc789cf12011-07-20 12:14:33 +0000970 sysInfo->insertInt("Supplement", 0);
halcanary8103a342016-03-08 15:10:16 -0800971 this->insertObject("CIDSystemInfo", std::move(sysInfo));
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000972
halcanary8b1d32c2016-08-08 09:09:59 -0700973 SkSinglyLinkedList<AdvanceMetric> tmpMetrics;
halcanary462d0142016-08-05 13:51:46 -0700974 set_glyph_widths(this->typeface(), &glyphIDs, &tmpMetrics);
975 int16_t defaultWidth = 0;
976 uint16_t emSize = (uint16_t)this->fontInfo()->fEmSize;
halcanary8b1d32c2016-08-08 09:09:59 -0700977 sk_sp<SkPDFArray> widths = composeAdvanceData(tmpMetrics, emSize, &defaultWidth);
halcanary462d0142016-08-05 13:51:46 -0700978 if (widths->size()) {
979 this->insertObject("W", std::move(widths));
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000980 }
vandebo@chromium.org98594282011-07-25 22:34:12 +0000981
halcanary462d0142016-08-05 13:51:46 -0700982 this->insertScalar(
983 "DW", scaleFromFontUnits(defaultWidth, emSize));
vandebo@chromium.org98594282011-07-25 22:34:12 +0000984 return true;
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000985}
986
vandebo@chromium.org98594282011-07-25 22:34:12 +0000987///////////////////////////////////////////////////////////////////////////////
988// class SkPDFType1Font
989///////////////////////////////////////////////////////////////////////////////
990
halcanary2e3f9d82015-02-27 12:41:03 -0800991SkPDFType1Font::SkPDFType1Font(const SkAdvancedTypefaceMetrics* info,
vandebo@chromium.org98594282011-07-25 22:34:12 +0000992 SkTypeface* typeface,
993 uint16_t glyphID,
994 SkPDFDict* relatedFontDescriptor)
halcanary2e3f9d82015-02-27 12:41:03 -0800995 : SkPDFFont(info, typeface, relatedFontDescriptor) {
robertphillips8e0c1502015-07-07 10:28:43 -0700996 this->populate(glyphID);
vandebo@chromium.org98594282011-07-25 22:34:12 +0000997}
998
999SkPDFType1Font::~SkPDFType1Font() {}
1000
1001bool SkPDFType1Font::addFontDescriptor(int16_t defaultWidth) {
halcanarybf51cfd2015-05-05 10:24:09 -07001002 if (SkPDFDict* descriptor = getFontDescriptor()) {
halcanary8103a342016-03-08 15:10:16 -08001003 this->insertObjRef("FontDescriptor",
halcanarye94ea622016-03-09 07:52:09 -08001004 sk_ref_sp(descriptor));
vandebo@chromium.org98594282011-07-25 22:34:12 +00001005 return true;
1006 }
1007
halcanaryece83922016-03-08 08:32:12 -08001008 auto descriptor = sk_make_sp<SkPDFDict>("FontDescriptor");
vandebo@chromium.org98594282011-07-25 22:34:12 +00001009 setFontDescriptor(descriptor.get());
1010
reed@google.comfed86bd2013-03-14 15:04:57 +00001011 int ttcIndex;
vandebo@chromium.org98594282011-07-25 22:34:12 +00001012 size_t header SK_INIT_TO_AVOID_WARNING;
1013 size_t data SK_INIT_TO_AVOID_WARNING;
1014 size_t trailer SK_INIT_TO_AVOID_WARNING;
halcanary32431432016-03-30 12:59:14 -07001015 std::unique_ptr<SkStreamAsset> rawFontData(typeface()->openStream(&ttcIndex));
halcanary8eccc302016-08-09 13:04:34 -07001016 sk_sp<SkData> fontData = SkPDFConvertType1FontStream(std::move(rawFontData),
1017 &header, &data, &trailer);
1018 if (!fontData) {
vandebo@chromium.org98594282011-07-25 22:34:12 +00001019 return false;
1020 }
halcanary66a82f32015-10-12 13:05:04 -07001021 SkASSERT(this->canEmbed());
halcanaryfe8f0e02016-07-27 14:14:04 -07001022 auto fontStream = sk_make_sp<SkPDFStream>(std::move(fontData));
halcanaryfa251062016-07-29 10:13:18 -07001023 fontStream->dict()->insertInt("Length1", header);
1024 fontStream->dict()->insertInt("Length2", data);
1025 fontStream->dict()->insertInt("Length3", trailer);
halcanary8103a342016-03-08 15:10:16 -08001026 descriptor->insertObjRef("FontFile", std::move(fontStream));
vandebo@chromium.org98594282011-07-25 22:34:12 +00001027
halcanary8103a342016-03-08 15:10:16 -08001028 this->insertObjRef("FontDescriptor", std::move(descriptor));
vandebo@chromium.org98594282011-07-25 22:34:12 +00001029
1030 return addCommonFontDescriptorEntries(defaultWidth);
1031}
1032
1033bool SkPDFType1Font::populate(int16_t glyphID) {
halcanary8eccc302016-08-09 13:04:34 -07001034 this->insertName("Subtype", "Type1");
1035 this->insertName("BaseFont", fontInfo()->fFontName);
vandebo@chromium.orgf77e27d2011-03-10 22:50:28 +00001036 adjustGlyphRangeForSingleByteEncoding(glyphID);
halcanary8eccc302016-08-09 13:04:34 -07001037 SkGlyphID firstGlyphID = this->firstGlyphID();
1038 SkGlyphID lastGlyphID = this->lastGlyphID();
vandebo@chromium.orgf77e27d2011-03-10 22:50:28 +00001039
halcanary8eccc302016-08-09 13:04:34 -07001040 // glyphCount not including glyph 0
1041 unsigned glyphCount = 1 + lastGlyphID - firstGlyphID;
1042 SkASSERT(glyphCount > 0 && glyphCount <= 255);
1043 this->insertInt("FirstChar", (size_t)0);
1044 this->insertInt("LastChar", (size_t)glyphCount);
halcanary462d0142016-08-05 13:51:46 -07001045 {
halcanary8eccc302016-08-09 13:04:34 -07001046 SkPaint tmpPaint;
1047 tmpPaint.setHinting(SkPaint::kNo_Hinting);
1048 tmpPaint.setTypeface(sk_ref_sp(this->typeface()));
1049 tmpPaint.setTextSize((SkScalar)this->typeface()->getUnitsPerEm());
halcanary7e8d5d32016-08-12 07:59:38 -07001050 const SkSurfaceProps props(0, kUnknown_SkPixelGeometry);
1051 SkAutoGlyphCache glyphCache(tmpPaint, &props, nullptr);
halcanary8eccc302016-08-09 13:04:34 -07001052 auto widths = sk_make_sp<SkPDFArray>();
1053 SkScalar advance = glyphCache->getGlyphIDAdvance(0).fAdvanceX;
1054 const uint16_t emSize = this->fontInfo()->fEmSize;
1055 widths->appendScalar(from_font_units(advance, emSize));
1056 for (unsigned gID = firstGlyphID; gID <= lastGlyphID; gID++) {
1057 advance = glyphCache->getGlyphIDAdvance(gID).fAdvanceX;
1058 widths->appendScalar(from_font_units(advance, emSize));
vandebo@chromium.org2a22e102011-01-25 21:01:34 +00001059 }
halcanary8eccc302016-08-09 13:04:34 -07001060 this->insertObject("Widths", std::move(widths));
vandebo@chromium.org2a22e102011-01-25 21:01:34 +00001061 }
halcanary8eccc302016-08-09 13:04:34 -07001062 if (!addFontDescriptor(0)) {
vandebo@chromium.org2a22e102011-01-25 21:01:34 +00001063 return false;
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +00001064 }
halcanaryece83922016-03-08 08:32:12 -08001065 auto encDiffs = sk_make_sp<SkPDFArray>();
halcanary8eccc302016-08-09 13:04:34 -07001066 encDiffs->reserve(lastGlyphID - firstGlyphID + 3);
1067 encDiffs->appendInt(0);
1068 const SkTArray<SkString>& glyphNames = this->fontInfo()->fGlyphNames;
1069 SkASSERT(glyphNames.count() > lastGlyphID);
1070 encDiffs->appendName(glyphNames[0].c_str());
1071 const SkString unknown("UNKNOWN");
1072 for (int gID = firstGlyphID; gID <= lastGlyphID; gID++) {
1073 const bool valid = gID < glyphNames.count() && !glyphNames[gID].isEmpty();
1074 const SkString& name = valid ? glyphNames[gID] : unknown;
1075 encDiffs->appendName(name);
vandebo@chromium.org2a22e102011-01-25 21:01:34 +00001076 }
1077
halcanaryece83922016-03-08 08:32:12 -08001078 auto encoding = sk_make_sp<SkPDFDict>("Encoding");
halcanary8103a342016-03-08 15:10:16 -08001079 encoding->insertObject("Differences", std::move(encDiffs));
1080 this->insertObject("Encoding", std::move(encoding));
vandebo@chromium.org2a22e102011-01-25 21:01:34 +00001081 return true;
vandebo@chromium.org28be72b2010-11-11 21:37:00 +00001082}
1083
vandebo@chromium.org98594282011-07-25 22:34:12 +00001084///////////////////////////////////////////////////////////////////////////////
1085// class SkPDFType3Font
1086///////////////////////////////////////////////////////////////////////////////
1087
halcanary7e8d5d32016-08-12 07:59:38 -07001088namespace {
1089// returns [0, first, first+1, ... last-1, last]
1090struct SingleByteGlyphIdIterator {
1091 SingleByteGlyphIdIterator(SkGlyphID first, SkGlyphID last)
1092 : fFirst(first), fLast(last) {
1093 SkASSERT(fFirst > 0);
1094 SkASSERT(fLast >= first);
1095 }
1096 struct Iter {
1097 void operator++() {
1098 fCurrent = (0 == fCurrent) ? fFirst : fCurrent + 1;
1099 }
1100 // This is an input_iterator
1101 SkGlyphID operator*() const { return (SkGlyphID)fCurrent; }
1102 bool operator!=(const Iter& rhs) const {
1103 return fCurrent != rhs.fCurrent;
1104 }
1105 Iter(SkGlyphID f, int c) : fFirst(f), fCurrent(c) {}
1106 private:
1107 const SkGlyphID fFirst;
1108 int fCurrent; // must be int to make fLast+1 to fit
1109 };
1110 Iter begin() const { return Iter(fFirst, 0); }
1111 Iter end() const { return Iter(fFirst, (int)fLast + 1); }
1112private:
1113 const SkGlyphID fFirst;
1114 const SkGlyphID fLast;
1115};
vandebo@chromium.org98594282011-07-25 22:34:12 +00001116}
1117
halcanary7e8d5d32016-08-12 07:59:38 -07001118static void add_type3_font_info(SkPDFDict* font,
1119 SkTypeface* typeface,
1120 SkScalar emSize,
1121 const SkPDFGlyphSet* subset,
1122 SkGlyphID firstGlyphID,
1123 SkGlyphID lastGlyphID) {
1124 SkASSERT(lastGlyphID >= firstGlyphID);
halcanary5bf60ad2016-08-11 13:59:18 -07001125 SkPaint paint;
halcanary7e8d5d32016-08-12 07:59:38 -07001126 paint.setHinting(SkPaint::kNo_Hinting);
1127 paint.setTypeface(sk_ref_sp(typeface));
1128 paint.setTextSize(emSize);
halcanary5bf60ad2016-08-11 13:59:18 -07001129 const SkSurfaceProps props(0, kUnknown_SkPixelGeometry);
halcanary7e8d5d32016-08-12 07:59:38 -07001130 SkAutoGlyphCache cache(paint, &props, nullptr);
halcanary5bf60ad2016-08-11 13:59:18 -07001131
halcanary7e8d5d32016-08-12 07:59:38 -07001132 font->insertName("Subtype", "Type3");
1133 // Flip about the x-axis and scale by 1/emSize.
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +00001134 SkMatrix fontMatrix;
halcanary7e8d5d32016-08-12 07:59:38 -07001135 fontMatrix.setScale(SkScalarInvert(emSize), -SkScalarInvert(emSize));
1136 font->insertObject("FontMatrix", SkPDFUtils::MatrixToArray(fontMatrix));
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +00001137
halcanaryece83922016-03-08 08:32:12 -08001138 auto charProcs = sk_make_sp<SkPDFDict>();
1139 auto encoding = sk_make_sp<SkPDFDict>("Encoding");
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +00001140
halcanaryece83922016-03-08 08:32:12 -08001141 auto encDiffs = sk_make_sp<SkPDFArray>();
halcanary7e8d5d32016-08-12 07:59:38 -07001142 // length(firstGlyphID .. lastGlyphID) == lastGlyphID - firstGlyphID + 1
1143 // plus 1 for glyph 0;
1144 SkASSERT(firstGlyphID > 0);
1145 SkASSERT(lastGlyphID >= firstGlyphID);
1146 int glyphCount = lastGlyphID - firstGlyphID + 2;
1147 // one other entry for the index of first glyph.
1148 encDiffs->reserve(glyphCount + 1);
1149 encDiffs->appendInt(0); // index of first glyph
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +00001150
halcanaryece83922016-03-08 08:32:12 -08001151 auto widthArray = sk_make_sp<SkPDFArray>();
halcanary7e8d5d32016-08-12 07:59:38 -07001152 widthArray->reserve(glyphCount);
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +00001153
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +00001154 SkIRect bbox = SkIRect::MakeEmpty();
halcanary7e8d5d32016-08-12 07:59:38 -07001155
1156 sk_sp<SkPDFStream> emptyStream;
1157 for (SkGlyphID gID : SingleByteGlyphIdIterator(firstGlyphID, lastGlyphID)) {
1158 bool skipGlyph = subset && gID != 0 && !subset->has(gID);
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +00001159 SkString characterName;
halcanary7e8d5d32016-08-12 07:59:38 -07001160 SkScalar advance = 0.0f;
1161 SkIRect glyphBBox;
1162 if (skipGlyph) {
1163 characterName.set("g0");
1164 } else {
1165 characterName.printf("g%X", gID);
1166 const SkGlyph& glyph = cache->getGlyphIDMetrics(gID);
1167 advance = SkFloatToScalar(glyph.fAdvanceX);
1168 glyphBBox = SkIRect::MakeXYWH(glyph.fLeft, glyph.fTop,
1169 glyph.fWidth, glyph.fHeight);
1170 bbox.join(glyphBBox);
1171 const SkPath* path = cache->findPath(glyph);
1172 if (path && !path->isEmpty()) {
1173 SkDynamicMemoryWStream content;
1174 setGlyphWidthAndBoundingBox(SkFloatToScalar(glyph.fAdvanceX), glyphBBox,
1175 &content);
1176 SkPDFUtils::EmitPath(*path, SkPaint::kFill_Style, &content);
1177 SkPDFUtils::PaintPath(SkPaint::kFill_Style, path->getFillType(),
1178 &content);
1179 charProcs->insertObjRef(
1180 characterName, sk_make_sp<SkPDFStream>(
1181 std::unique_ptr<SkStreamAsset>(content.detachAsStream())));
1182 } else {
1183 if (!emptyStream) {
1184 emptyStream = sk_make_sp<SkPDFStream>(
1185 std::unique_ptr<SkStreamAsset>(
1186 new SkMemoryStream((size_t)0)));
1187 }
1188 charProcs->insertObjRef(characterName, emptyStream);
1189 }
halcanary5bf60ad2016-08-11 13:59:18 -07001190 }
halcanary7e8d5d32016-08-12 07:59:38 -07001191 encDiffs->appendName(characterName.c_str());
1192 widthArray->appendScalar(advance);
ctguil@chromium.org9db86bb2011-03-04 21:43:27 +00001193 }
1194
halcanary8103a342016-03-08 15:10:16 -08001195 encoding->insertObject("Differences", std::move(encDiffs));
halcanary7e8d5d32016-08-12 07:59:38 -07001196 font->insertInt("FirstChar", 0);
1197 font->insertInt("LastChar", lastGlyphID - firstGlyphID + 1);
1198 /* FontBBox: "A rectangle expressed in the glyph coordinate
1199 system, specifying the font bounding box. This is the smallest
1200 rectangle enclosing the shape that would result if all of the
1201 glyphs of the font were placed with their origins coincident and
1202 then filled." */
1203 auto fontBBox = sk_make_sp<SkPDFArray>();
1204 fontBBox->reserve(4);
1205 fontBBox->appendInt(bbox.left());
1206 fontBBox->appendInt(bbox.bottom());
1207 fontBBox->appendInt(bbox.right());
1208 fontBBox->appendInt(bbox.top());
1209 font->insertObject("FontBBox", std::move(fontBBox));
1210 font->insertName("CIDToGIDMap", "Identity");
1211 sk_sp<const SkAdvancedTypefaceMetrics> metrics;
1212 if (subset) {
1213 SkTDArray<uint32_t> subsetList;
1214 for (SkGlyphID gID : SingleByteGlyphIdIterator(firstGlyphID, lastGlyphID)) {
1215 if (gID == 0 || subset->has(gID)) { // Always include glyph 0.
1216 subsetList.push(0);
1217 }
1218 }
1219 subset->exportTo(&subsetList);
1220 metrics = SkPDFFont::GetFontMetricsWithToUnicode(typeface, subsetList.begin(),
1221 subsetList.count());
1222 } else {
1223 metrics = SkPDFFont::GetFontMetricsWithToUnicode(typeface, nullptr, 0);
1224 }
1225 if (metrics) {
1226 font->insertObjRef("ToUnicode",
1227 SkPDFMakeToUnicodeCmap(metrics->fGlyphToUnicode,
1228 subset,
1229 false,
1230 firstGlyphID,
1231 lastGlyphID));
1232 }
1233 font->insertObject("Widths", std::move(widthArray));
1234 font->insertObject("Encoding", std::move(encoding));
1235 font->insertObject("CharProcs", std::move(charProcs));
vandebo@chromium.org2a22e102011-01-25 21:01:34 +00001236}
halcanaryfb62b3d2015-01-21 09:59:14 -08001237
halcanary7e8d5d32016-08-12 07:59:38 -07001238SkPDFType3Font::SkPDFType3Font(const SkAdvancedTypefaceMetrics* info,
1239 SkTypeface* typeface,
1240 uint16_t glyphID)
1241 : SkPDFFont(info, typeface, nullptr) {
1242 // If fLastGlyphID isn't set (because there is not fFontInfo), look it up.
1243 this->setLastGlyphID(SkToU16(typeface->countGlyphs() - 1));
1244 this->adjustGlyphRangeForSingleByteEncoding(glyphID);
1245}
1246
1247sk_sp<SkPDFObject> SkPDFType3Font::getFontSubset(const SkPDFGlyphSet* usage) {
1248 // All fonts are subset before serialization.
1249 // TODO(halcanary): all fonts should follow this pattern.
1250 auto font = sk_make_sp<SkPDFDict>("Font");
1251 const SkAdvancedTypefaceMetrics* info = this->fontInfo();
1252 uint16_t emSize = info && info->fEmSize > 0 ? info->fEmSize : 1000;
1253 add_type3_font_info(font.get(), this->typeface(), (SkScalar)emSize, usage,
1254 this->firstGlyphID(), this->lastGlyphID());
1255 return font;
1256}
1257
1258
1259////////////////////////////////////////////////////////////////////////////////
1260
halcanaryfb62b3d2015-01-21 09:59:14 -08001261SkPDFFont::Match SkPDFFont::IsMatch(SkPDFFont* existingFont,
1262 uint32_t existingFontID,
1263 uint16_t existingGlyphID,
1264 uint32_t searchFontID,
1265 uint16_t searchGlyphID) {
1266 if (existingFontID != searchFontID) {
1267 return SkPDFFont::kNot_Match;
1268 }
1269 if (existingGlyphID == 0 || searchGlyphID == 0) {
1270 return SkPDFFont::kExact_Match;
1271 }
halcanary96fcdcc2015-08-27 07:41:13 -07001272 if (existingFont != nullptr) {
halcanaryfb62b3d2015-01-21 09:59:14 -08001273 return (existingFont->fFirstGlyphID <= searchGlyphID &&
1274 searchGlyphID <= existingFont->fLastGlyphID)
1275 ? SkPDFFont::kExact_Match
1276 : SkPDFFont::kRelated_Match;
1277 }
1278 return (existingGlyphID == searchGlyphID) ? SkPDFFont::kExact_Match
1279 : SkPDFFont::kRelated_Match;
1280}
halcanary66a82f32015-10-12 13:05:04 -07001281
1282// Since getAdvancedTypefaceMetrics is expensive, cache the result.
1283bool SkPDFFont::CanEmbedTypeface(SkTypeface* typeface, SkPDFCanon* canon) {
halcanary4ed2f012016-08-15 18:40:07 -07001284 SkFontID id = SkTypeface::UniqueID(typeface);
halcanary66a82f32015-10-12 13:05:04 -07001285 if (bool* value = canon->fCanEmbedTypeface.find(id)) {
1286 return *value;
1287 }
halcanary4ed2f012016-08-15 18:40:07 -07001288 SkAutoResolveDefaultTypeface face(typeface);
halcanary66a82f32015-10-12 13:05:04 -07001289 bool canEmbed = true;
halcanary48810a02016-03-07 14:57:50 -08001290 sk_sp<const SkAdvancedTypefaceMetrics> fontMetrics(
halcanary66a82f32015-10-12 13:05:04 -07001291 face->getAdvancedTypefaceMetrics(
1292 SkTypeface::kNo_PerGlyphInfo, nullptr, 0));
1293 if (fontMetrics) {
1294 canEmbed = !SkToBool(
1295 fontMetrics->fFlags &
1296 SkAdvancedTypefaceMetrics::kNotEmbeddable_FontFlag);
1297 }
1298 return *canon->fCanEmbedTypeface.set(id, canEmbed);
1299}
halcanarybae235e2016-03-21 10:05:23 -07001300
1301void SkPDFFont::drop() {
1302 fTypeface = nullptr;
1303 fFontInfo = nullptr;
1304 fDescriptor = nullptr;
1305 this->SkPDFDict::drop();
1306}