vandebo@chromium.org | 28be72b | 2010-11-11 21:37:00 +0000 | [diff] [blame] | 1 | /* |
epoger@google.com | ec3ed6a | 2011-07-28 14:26:00 +0000 | [diff] [blame] | 2 | * Copyright 2011 Google Inc. |
vandebo@chromium.org | 28be72b | 2010-11-11 21:37:00 +0000 | [diff] [blame] | 3 | * |
epoger@google.com | ec3ed6a | 2011-07-28 14:26:00 +0000 | [diff] [blame] | 4 | * Use of this source code is governed by a BSD-style license that can be |
| 5 | * found in the LICENSE file. |
vandebo@chromium.org | 28be72b | 2010-11-11 21:37:00 +0000 | [diff] [blame] | 6 | */ |
| 7 | |
reed@google.com | 8a85d0c | 2011-06-24 19:12:12 +0000 | [diff] [blame] | 8 | #include "SkData.h" |
ctguil@chromium.org | 9db86bb | 2011-03-04 21:43:27 +0000 | [diff] [blame] | 9 | #include "SkGlyphCache.h" |
Hal Canary | 209e4b1 | 2017-05-04 14:23:55 -0400 | [diff] [blame] | 10 | #include "SkMakeUnique.h" |
halcanary | fb62b3d | 2015-01-21 09:59:14 -0800 | [diff] [blame] | 11 | #include "SkPDFCanon.h" |
halcanary | 8eccc30 | 2016-08-09 13:04:34 -0700 | [diff] [blame] | 12 | #include "SkPDFConvertType1FontStream.h" |
ctguil@chromium.org | 9db86bb | 2011-03-04 21:43:27 +0000 | [diff] [blame] | 13 | #include "SkPDFDevice.h" |
Hal Canary | 209e4b1 | 2017-05-04 14:23:55 -0400 | [diff] [blame] | 14 | #include "SkPDFFont.h" |
halcanary | 86b6eab | 2016-08-17 07:57:27 -0700 | [diff] [blame] | 15 | #include "SkPDFMakeCIDGlyphWidthsArray.h" |
halcanary | 8eccc30 | 2016-08-09 13:04:34 -0700 | [diff] [blame] | 16 | #include "SkPDFMakeToUnicodeCmap.h" |
ctguil@chromium.org | 9db86bb | 2011-03-04 21:43:27 +0000 | [diff] [blame] | 17 | #include "SkPDFUtils.h" |
Hal Canary | 209e4b1 | 2017-05-04 14:23:55 -0400 | [diff] [blame] | 18 | #include "SkPaint.h" |
vandebo@chromium.org | f77e27d | 2011-03-10 22:50:28 +0000 | [diff] [blame] | 19 | #include "SkRefCnt.h" |
ctguil@chromium.org | 9db86bb | 2011-03-04 21:43:27 +0000 | [diff] [blame] | 20 | #include "SkScalar.h" |
vandebo@chromium.org | 2a22e10 | 2011-01-25 21:01:34 +0000 | [diff] [blame] | 21 | #include "SkStream.h" |
vandebo@chromium.org | 325cb9a | 2011-03-30 18:36:29 +0000 | [diff] [blame] | 22 | #include "SkTypes.h" |
vandebo@chromium.org | 28be72b | 2010-11-11 21:37:00 +0000 | [diff] [blame] | 23 | #include "SkUtils.h" |
| 24 | |
halcanary | 650e20d | 2016-08-25 09:07:02 -0700 | [diff] [blame] | 25 | #ifdef SK_PDF_USE_SFNTLY |
| 26 | #include "sample/chromium/font_subsetter.h" |
vandebo@chromium.org | 1f16589 | 2011-07-26 02:11:41 +0000 | [diff] [blame] | 27 | #endif |
| 28 | |
Hal Canary | aa3af7b | 2017-03-06 16:18:49 -0500 | [diff] [blame] | 29 | SkAutoGlyphCache SkPDFFont::MakeVectorCache(SkTypeface* face, int* size) { |
| 30 | SkPaint tmpPaint; |
| 31 | tmpPaint.setHinting(SkPaint::kNo_Hinting); |
| 32 | tmpPaint.setTypeface(sk_ref_sp(face)); |
| 33 | int unitsPerEm = face->getUnitsPerEm(); |
| 34 | if (unitsPerEm <= 0) { |
| 35 | unitsPerEm = 1024; |
| 36 | } |
| 37 | if (size) { |
| 38 | *size = unitsPerEm; |
| 39 | } |
| 40 | tmpPaint.setTextSize((SkScalar)unitsPerEm); |
| 41 | const SkSurfaceProps props(0, kUnknown_SkPixelGeometry); |
| 42 | SkAutoGlyphCache glyphCache(tmpPaint, &props, nullptr); |
| 43 | SkASSERT(glyphCache.get()); |
| 44 | return glyphCache; |
| 45 | } |
| 46 | |
halcanary | 8eccc30 | 2016-08-09 13:04:34 -0700 | [diff] [blame] | 47 | namespace { |
vandebo@chromium.org | dcf9c19 | 2013-03-13 20:01:51 +0000 | [diff] [blame] | 48 | // PDF's notion of symbolic vs non-symbolic is related to the character set, not |
| 49 | // symbols vs. characters. Rarely is a font the right character set to call it |
| 50 | // non-symbolic, so always call it symbolic. (PDF 1.4 spec, section 5.7.1) |
halcanary | 3d01c62 | 2016-08-31 12:52:35 -0700 | [diff] [blame] | 51 | static const int32_t kPdfSymbolic = 4; |
vandebo@chromium.org | dcf9c19 | 2013-03-13 20:01:51 +0000 | [diff] [blame] | 52 | |
halcanary | 530032a | 2016-08-18 14:22:52 -0700 | [diff] [blame] | 53 | struct SkPDFType0Font final : public SkPDFFont { |
| 54 | SkPDFType0Font(SkPDFFont::Info, const SkAdvancedTypefaceMetrics&); |
Brian Salomon | d3b6597 | 2017-03-22 12:05:03 -0400 | [diff] [blame] | 55 | ~SkPDFType0Font() override; |
halcanary | 530032a | 2016-08-18 14:22:52 -0700 | [diff] [blame] | 56 | void getFontSubset(SkPDFCanon*) override; |
halcanary | 8eccc30 | 2016-08-09 13:04:34 -0700 | [diff] [blame] | 57 | #ifdef SK_DEBUG |
halcanary | 530032a | 2016-08-18 14:22:52 -0700 | [diff] [blame] | 58 | void emitObject(SkWStream*, const SkPDFObjNumMap&) const override; |
halcanary | 8eccc30 | 2016-08-09 13:04:34 -0700 | [diff] [blame] | 59 | bool fPopulated; |
| 60 | #endif |
halcanary | 8eccc30 | 2016-08-09 13:04:34 -0700 | [diff] [blame] | 61 | typedef SkPDFDict INHERITED; |
| 62 | }; |
| 63 | |
halcanary | 530032a | 2016-08-18 14:22:52 -0700 | [diff] [blame] | 64 | struct SkPDFType1Font final : public SkPDFFont { |
| 65 | SkPDFType1Font(SkPDFFont::Info, const SkAdvancedTypefaceMetrics&, SkPDFCanon*); |
Brian Salomon | d3b6597 | 2017-03-22 12:05:03 -0400 | [diff] [blame] | 66 | ~SkPDFType1Font() override {} |
halcanary | 530032a | 2016-08-18 14:22:52 -0700 | [diff] [blame] | 67 | void getFontSubset(SkPDFCanon*) override {} // TODO(halcanary): implement |
halcanary | 8eccc30 | 2016-08-09 13:04:34 -0700 | [diff] [blame] | 68 | }; |
| 69 | |
halcanary | 530032a | 2016-08-18 14:22:52 -0700 | [diff] [blame] | 70 | struct SkPDFType3Font final : public SkPDFFont { |
| 71 | SkPDFType3Font(SkPDFFont::Info, const SkAdvancedTypefaceMetrics&); |
Brian Salomon | d3b6597 | 2017-03-22 12:05:03 -0400 | [diff] [blame] | 72 | ~SkPDFType3Font() override {} |
halcanary | 530032a | 2016-08-18 14:22:52 -0700 | [diff] [blame] | 73 | void getFontSubset(SkPDFCanon*) override; |
halcanary | 8eccc30 | 2016-08-09 13:04:34 -0700 | [diff] [blame] | 74 | }; |
vandebo@chromium.org | 28be72b | 2010-11-11 21:37:00 +0000 | [diff] [blame] | 75 | |
vandebo@chromium.org | 9859428 | 2011-07-25 22:34:12 +0000 | [diff] [blame] | 76 | /////////////////////////////////////////////////////////////////////////////// |
| 77 | // File-Local Functions |
| 78 | /////////////////////////////////////////////////////////////////////////////// |
| 79 | |
reed@google.com | 3f0dcf9 | 2011-03-18 21:23:45 +0000 | [diff] [blame] | 80 | // scale from em-units to base-1000, returning as a SkScalar |
halcanary | 8eccc30 | 2016-08-09 13:04:34 -0700 | [diff] [blame] | 81 | SkScalar from_font_units(SkScalar scaled, uint16_t emSize) { |
reed@google.com | 3f0dcf9 | 2011-03-18 21:23:45 +0000 | [diff] [blame] | 82 | if (emSize == 1000) { |
| 83 | return scaled; |
| 84 | } else { |
Mike Reed | 8be952a | 2017-02-13 20:44:33 -0500 | [diff] [blame] | 85 | return scaled * 1000 / emSize; |
reed@google.com | 3f0dcf9 | 2011-03-18 21:23:45 +0000 | [diff] [blame] | 86 | } |
vandebo@chromium.org | c48b2b3 | 2011-02-02 02:11:22 +0000 | [diff] [blame] | 87 | } |
| 88 | |
halcanary | 8eccc30 | 2016-08-09 13:04:34 -0700 | [diff] [blame] | 89 | SkScalar scaleFromFontUnits(int16_t val, uint16_t emSize) { |
| 90 | return from_font_units(SkIntToScalar(val), emSize); |
| 91 | } |
| 92 | |
| 93 | |
ctguil@chromium.org | 9db86bb | 2011-03-04 21:43:27 +0000 | [diff] [blame] | 94 | void setGlyphWidthAndBoundingBox(SkScalar width, SkIRect box, |
halcanary | 7e8d5d3 | 2016-08-12 07:59:38 -0700 | [diff] [blame] | 95 | SkDynamicMemoryWStream* content) { |
ctguil@chromium.org | 9db86bb | 2011-03-04 21:43:27 +0000 | [diff] [blame] | 96 | // Specify width and bounding box for the glyph. |
halcanary | bc4696b | 2015-05-06 10:56:04 -0700 | [diff] [blame] | 97 | SkPDFUtils::AppendScalar(width, content); |
vandebo@chromium.org | cae5fba | 2011-03-28 19:03:50 +0000 | [diff] [blame] | 98 | content->writeText(" 0 "); |
| 99 | content->writeDecAsText(box.fLeft); |
| 100 | content->writeText(" "); |
| 101 | content->writeDecAsText(box.fTop); |
| 102 | content->writeText(" "); |
| 103 | content->writeDecAsText(box.fRight); |
| 104 | content->writeText(" "); |
| 105 | content->writeDecAsText(box.fBottom); |
| 106 | content->writeText(" d1\n"); |
ctguil@chromium.org | 9db86bb | 2011-03-04 21:43:27 +0000 | [diff] [blame] | 107 | } |
| 108 | |
halcanary | 8103a34 | 2016-03-08 15:10:16 -0800 | [diff] [blame] | 109 | static sk_sp<SkPDFArray> makeFontBBox(SkIRect glyphBBox, uint16_t emSize) { |
| 110 | auto bbox = sk_make_sp<SkPDFArray>(); |
ctguil@chromium.org | 9db86bb | 2011-03-04 21:43:27 +0000 | [diff] [blame] | 111 | bbox->reserve(4); |
reed@google.com | c789cf1 | 2011-07-20 12:14:33 +0000 | [diff] [blame] | 112 | bbox->appendScalar(scaleFromFontUnits(glyphBBox.fLeft, emSize)); |
| 113 | bbox->appendScalar(scaleFromFontUnits(glyphBBox.fBottom, emSize)); |
| 114 | bbox->appendScalar(scaleFromFontUnits(glyphBBox.fRight, emSize)); |
| 115 | bbox->appendScalar(scaleFromFontUnits(glyphBBox.fTop, emSize)); |
halcanary | 51d04d3 | 2016-03-08 13:03:55 -0800 | [diff] [blame] | 116 | return bbox; |
ctguil@chromium.org | 9db86bb | 2011-03-04 21:43:27 +0000 | [diff] [blame] | 117 | } |
vandebo@chromium.org | 2a22e10 | 2011-01-25 21:01:34 +0000 | [diff] [blame] | 118 | } // namespace |
| 119 | |
vandebo@chromium.org | 9859428 | 2011-07-25 22:34:12 +0000 | [diff] [blame] | 120 | /////////////////////////////////////////////////////////////////////////////// |
| 121 | // class SkPDFFont |
| 122 | /////////////////////////////////////////////////////////////////////////////// |
| 123 | |
vandebo@chromium.org | 2a22e10 | 2011-01-25 21:01:34 +0000 | [diff] [blame] | 124 | /* Font subset design: It would be nice to be able to subset fonts |
| 125 | * (particularly type 3 fonts), but it's a lot of work and not a priority. |
| 126 | * |
| 127 | * Resources are canonicalized and uniqueified by pointer so there has to be |
| 128 | * some additional state indicating which subset of the font is used. It |
| 129 | * must be maintained at the page granularity and then combined at the document |
| 130 | * granularity. a) change SkPDFFont to fill in its state on demand, kind of |
| 131 | * like SkPDFGraphicState. b) maintain a per font glyph usage class in each |
| 132 | * page/pdf device. c) in the document, retrieve the per font glyph usage |
| 133 | * from each page and combine it and ask for a resource with that subset. |
| 134 | */ |
| 135 | |
halcanary | 2e3f9d8 | 2015-02-27 12:41:03 -0800 | [diff] [blame] | 136 | SkPDFFont::~SkPDFFont() {} |
vandebo@chromium.org | 28be72b | 2010-11-11 21:37:00 +0000 | [diff] [blame] | 137 | |
halcanary | cee1342 | 2016-08-18 09:52:48 -0700 | [diff] [blame] | 138 | static bool can_embed(const SkAdvancedTypefaceMetrics& metrics) { |
| 139 | return !SkToBool(metrics.fFlags & SkAdvancedTypefaceMetrics::kNotEmbeddable_FontFlag); |
vandebo | 0f9bad0 | 2014-06-19 11:05:39 -0700 | [diff] [blame] | 140 | } |
| 141 | |
halcanary | cee1342 | 2016-08-18 09:52:48 -0700 | [diff] [blame] | 142 | const SkAdvancedTypefaceMetrics* SkPDFFont::GetMetrics(SkTypeface* typeface, |
| 143 | SkPDFCanon* canon) { |
halcanary | 4871f22 | 2016-08-26 13:17:44 -0700 | [diff] [blame] | 144 | SkASSERT(typeface); |
| 145 | SkFontID id = typeface->uniqueID(); |
Hal Canary | 209e4b1 | 2017-05-04 14:23:55 -0400 | [diff] [blame] | 146 | if (std::unique_ptr<SkAdvancedTypefaceMetrics>* ptr = canon->fTypefaceMetrics.find(id)) { |
Hal Canary | 5c1b360 | 2017-04-17 16:30:06 -0400 | [diff] [blame] | 147 | return ptr->get(); // canon retains ownership. |
halcanary | cee1342 | 2016-08-18 09:52:48 -0700 | [diff] [blame] | 148 | } |
halcanary | 4871f22 | 2016-08-26 13:17:44 -0700 | [diff] [blame] | 149 | int count = typeface->countGlyphs(); |
| 150 | if (count <= 0 || count > 1 + SK_MaxU16) { |
| 151 | // Cache nullptr to skip this check. Use SkSafeUnref(). |
| 152 | canon->fTypefaceMetrics.set(id, nullptr); |
| 153 | return nullptr; |
halcanary | cee1342 | 2016-08-18 09:52:48 -0700 | [diff] [blame] | 154 | } |
Hal Canary | 209e4b1 | 2017-05-04 14:23:55 -0400 | [diff] [blame] | 155 | std::unique_ptr<SkAdvancedTypefaceMetrics> metrics = typeface->getAdvancedMetrics(); |
halcanary | cee1342 | 2016-08-18 09:52:48 -0700 | [diff] [blame] | 156 | if (!metrics) { |
Hal Canary | 209e4b1 | 2017-05-04 14:23:55 -0400 | [diff] [blame] | 157 | metrics = skstd::make_unique<SkAdvancedTypefaceMetrics>(); |
halcanary | 1748432 | 2016-08-29 09:47:48 -0700 | [diff] [blame] | 158 | } |
Hal Canary | 3223e27 | 2017-07-05 16:47:59 -0400 | [diff] [blame] | 159 | |
| 160 | if (0 == metrics->fStemV || 0 == metrics->fCapHeight) { |
| 161 | SkPaint tmpPaint; |
| 162 | tmpPaint.setHinting(SkPaint::kNo_Hinting); |
| 163 | tmpPaint.setTypeface(sk_ref_sp(typeface)); |
| 164 | tmpPaint.setTextSize(1000); // glyph coordinate system |
| 165 | if (0 == metrics->fStemV) { |
| 166 | // Figure out a good guess for StemV - Min width of i, I, !, 1. |
| 167 | // This probably isn't very good with an italic font. |
| 168 | int16_t stemV = SHRT_MAX; |
| 169 | for (char c : {'i', 'I', '!', '1'}) { |
| 170 | SkRect bounds; |
| 171 | tmpPaint.measureText(&c, 1, &bounds); |
| 172 | stemV = SkTMin(stemV, SkToS16(SkScalarRoundToInt(bounds.width()))); |
| 173 | } |
| 174 | metrics->fStemV = stemV; |
| 175 | } |
| 176 | if (0 == metrics->fCapHeight) { |
| 177 | // Figure out a good guess for CapHeight: average the height of M and X. |
| 178 | SkScalar capHeight = 0; |
| 179 | for (char c : {'M', 'X'}) { |
| 180 | SkRect bounds; |
| 181 | tmpPaint.measureText(&c, 1, &bounds); |
| 182 | capHeight += bounds.height(); |
| 183 | } |
| 184 | metrics->fCapHeight = SkToS16(SkScalarRoundToInt(capHeight / 2)); |
| 185 | } |
| 186 | } |
Hal Canary | 5c1b360 | 2017-04-17 16:30:06 -0400 | [diff] [blame] | 187 | return canon->fTypefaceMetrics.set(id, std::move(metrics))->get(); |
halcanary | cee1342 | 2016-08-18 09:52:48 -0700 | [diff] [blame] | 188 | } |
| 189 | |
halcanary | c2f9ec1 | 2016-09-12 08:55:29 -0700 | [diff] [blame] | 190 | SkAdvancedTypefaceMetrics::FontType SkPDFFont::FontType(const SkAdvancedTypefaceMetrics& metrics) { |
Hal Canary | b3480e1 | 2016-09-30 14:53:15 -0400 | [diff] [blame] | 191 | if (SkToBool(metrics.fFlags & SkAdvancedTypefaceMetrics::kMultiMaster_FontFlag) || |
| 192 | SkToBool(metrics.fFlags & SkAdvancedTypefaceMetrics::kNotEmbeddable_FontFlag)) { |
halcanary | cee1342 | 2016-08-18 09:52:48 -0700 | [diff] [blame] | 193 | // force Type3 fallback. |
| 194 | return SkAdvancedTypefaceMetrics::kOther_Font; |
| 195 | } |
| 196 | return metrics.fType; |
| 197 | } |
| 198 | |
halcanary | 4871f22 | 2016-08-26 13:17:44 -0700 | [diff] [blame] | 199 | static SkGlyphID first_nonzero_glyph_for_single_byte_encoding(SkGlyphID gid) { |
halcanary | cee1342 | 2016-08-18 09:52:48 -0700 | [diff] [blame] | 200 | return gid != 0 ? gid - (gid - 1) % 255 : 1; |
| 201 | } |
| 202 | |
Hal Canary | 5c1b360 | 2017-04-17 16:30:06 -0400 | [diff] [blame] | 203 | sk_sp<SkPDFFont> SkPDFFont::GetFontResource(SkPDFCanon* canon, |
| 204 | SkTypeface* face, |
| 205 | SkGlyphID glyphID) { |
halcanary | 792c80f | 2015-02-20 07:21:05 -0800 | [diff] [blame] | 206 | SkASSERT(canon); |
halcanary | 4871f22 | 2016-08-26 13:17:44 -0700 | [diff] [blame] | 207 | SkASSERT(face); // All SkPDFDevice::internalDrawText ensures this. |
halcanary | cee1342 | 2016-08-18 09:52:48 -0700 | [diff] [blame] | 208 | const SkAdvancedTypefaceMetrics* fontMetrics = SkPDFFont::GetMetrics(face, canon); |
halcanary | 4871f22 | 2016-08-26 13:17:44 -0700 | [diff] [blame] | 209 | SkASSERT(fontMetrics); // SkPDFDevice::internalDrawText ensures the typeface is good. |
| 210 | // GetMetrics only returns null to signify a bad typeface. |
halcanary | cee1342 | 2016-08-18 09:52:48 -0700 | [diff] [blame] | 211 | const SkAdvancedTypefaceMetrics& metrics = *fontMetrics; |
halcanary | c2f9ec1 | 2016-09-12 08:55:29 -0700 | [diff] [blame] | 212 | SkAdvancedTypefaceMetrics::FontType type = SkPDFFont::FontType(metrics); |
halcanary | cee1342 | 2016-08-18 09:52:48 -0700 | [diff] [blame] | 213 | bool multibyte = SkPDFFont::IsMultiByte(type); |
halcanary | 4871f22 | 2016-08-26 13:17:44 -0700 | [diff] [blame] | 214 | SkGlyphID subsetCode = multibyte ? 0 : first_nonzero_glyph_for_single_byte_encoding(glyphID); |
| 215 | uint64_t fontID = (SkTypeface::UniqueID(face) << 16) | subsetCode; |
halcanary | cee1342 | 2016-08-18 09:52:48 -0700 | [diff] [blame] | 216 | |
Hal Canary | 5c1b360 | 2017-04-17 16:30:06 -0400 | [diff] [blame] | 217 | if (sk_sp<SkPDFFont>* found = canon->fFontMap.find(fontID)) { |
| 218 | SkDEBUGCODE(SkPDFFont* foundFont = found->get()); |
halcanary | 4871f22 | 2016-08-26 13:17:44 -0700 | [diff] [blame] | 219 | SkASSERT(foundFont && multibyte == foundFont->multiByteGlyphs()); |
Hal Canary | 5c1b360 | 2017-04-17 16:30:06 -0400 | [diff] [blame] | 220 | return *found; |
halcanary | cee1342 | 2016-08-18 09:52:48 -0700 | [diff] [blame] | 221 | } |
| 222 | |
halcanary | 4871f22 | 2016-08-26 13:17:44 -0700 | [diff] [blame] | 223 | sk_sp<SkTypeface> typeface(sk_ref_sp(face)); |
halcanary | 7e8d5d3 | 2016-08-12 07:59:38 -0700 | [diff] [blame] | 224 | SkASSERT(typeface); |
halcanary | 4871f22 | 2016-08-26 13:17:44 -0700 | [diff] [blame] | 225 | |
Hal Canary | aa3af7b | 2017-03-06 16:18:49 -0500 | [diff] [blame] | 226 | SkGlyphID lastGlyph = SkToU16(typeface->countGlyphs() - 1); |
halcanary | 4871f22 | 2016-08-26 13:17:44 -0700 | [diff] [blame] | 227 | |
| 228 | // should be caught by SkPDFDevice::internalDrawText |
| 229 | SkASSERT(glyphID <= lastGlyph); |
halcanary | 3287588 | 2016-08-16 09:36:23 -0700 | [diff] [blame] | 230 | |
halcanary | 530032a | 2016-08-18 14:22:52 -0700 | [diff] [blame] | 231 | SkGlyphID firstNonZeroGlyph; |
halcanary | 530032a | 2016-08-18 14:22:52 -0700 | [diff] [blame] | 232 | if (multibyte) { |
| 233 | firstNonZeroGlyph = 1; |
halcanary | 530032a | 2016-08-18 14:22:52 -0700 | [diff] [blame] | 234 | } else { |
halcanary | 4871f22 | 2016-08-26 13:17:44 -0700 | [diff] [blame] | 235 | firstNonZeroGlyph = subsetCode; |
| 236 | lastGlyph = SkToU16(SkTMin<int>((int)lastGlyph, 254 + (int)subsetCode)); |
halcanary | 530032a | 2016-08-18 14:22:52 -0700 | [diff] [blame] | 237 | } |
| 238 | SkPDFFont::Info info = {std::move(typeface), firstNonZeroGlyph, lastGlyph, type}; |
halcanary | 3287588 | 2016-08-16 09:36:23 -0700 | [diff] [blame] | 239 | sk_sp<SkPDFFont> font; |
| 240 | switch (type) { |
| 241 | case SkAdvancedTypefaceMetrics::kType1CID_Font: |
| 242 | case SkAdvancedTypefaceMetrics::kTrueType_Font: |
halcanary | cee1342 | 2016-08-18 09:52:48 -0700 | [diff] [blame] | 243 | SkASSERT(multibyte); |
halcanary | 530032a | 2016-08-18 14:22:52 -0700 | [diff] [blame] | 244 | font = sk_make_sp<SkPDFType0Font>(std::move(info), metrics); |
halcanary | 3287588 | 2016-08-16 09:36:23 -0700 | [diff] [blame] | 245 | break; |
| 246 | case SkAdvancedTypefaceMetrics::kType1_Font: |
halcanary | cee1342 | 2016-08-18 09:52:48 -0700 | [diff] [blame] | 247 | SkASSERT(!multibyte); |
halcanary | 530032a | 2016-08-18 14:22:52 -0700 | [diff] [blame] | 248 | font = sk_make_sp<SkPDFType1Font>(std::move(info), metrics, canon); |
halcanary | 3287588 | 2016-08-16 09:36:23 -0700 | [diff] [blame] | 249 | break; |
halcanary | cee1342 | 2016-08-18 09:52:48 -0700 | [diff] [blame] | 250 | default: |
| 251 | SkASSERT(!multibyte); |
| 252 | // Type3 is our fallback font. |
halcanary | 530032a | 2016-08-18 14:22:52 -0700 | [diff] [blame] | 253 | font = sk_make_sp<SkPDFType3Font>(std::move(info), metrics); |
halcanary | 3287588 | 2016-08-16 09:36:23 -0700 | [diff] [blame] | 254 | break; |
halcanary | 3287588 | 2016-08-16 09:36:23 -0700 | [diff] [blame] | 255 | } |
Hal Canary | 5c1b360 | 2017-04-17 16:30:06 -0400 | [diff] [blame] | 256 | canon->fFontMap.set(fontID, font); |
| 257 | return font; |
vandebo@chromium.org | 28be72b | 2010-11-11 21:37:00 +0000 | [diff] [blame] | 258 | } |
| 259 | |
halcanary | 530032a | 2016-08-18 14:22:52 -0700 | [diff] [blame] | 260 | SkPDFFont::SkPDFFont(SkPDFFont::Info info) |
halcanary | 792c80f | 2015-02-20 07:21:05 -0800 | [diff] [blame] | 261 | : SkPDFDict("Font") |
halcanary | 530032a | 2016-08-18 14:22:52 -0700 | [diff] [blame] | 262 | , fTypeface(std::move(info.fTypeface)) |
| 263 | , fGlyphUsage(info.fLastGlyphID + 1) // TODO(halcanary): Adjust mapping? |
| 264 | , fFirstGlyphID(info.fFirstGlyphID) |
| 265 | , fLastGlyphID(info.fLastGlyphID) |
| 266 | , fFontType(info.fFontType) { |
halcanary | 7e8d5d3 | 2016-08-12 07:59:38 -0700 | [diff] [blame] | 267 | SkASSERT(fTypeface); |
vandebo@chromium.org | 9859428 | 2011-07-25 22:34:12 +0000 | [diff] [blame] | 268 | } |
| 269 | |
halcanary | 28c6d83 | 2016-08-16 10:29:38 -0700 | [diff] [blame] | 270 | static void add_common_font_descriptor_entries(SkPDFDict* descriptor, |
| 271 | const SkAdvancedTypefaceMetrics& metrics, |
Hal Canary | aa3af7b | 2017-03-06 16:18:49 -0500 | [diff] [blame] | 272 | uint16_t emSize, |
halcanary | 28c6d83 | 2016-08-16 10:29:38 -0700 | [diff] [blame] | 273 | int16_t defaultWidth) { |
halcanary | 28c6d83 | 2016-08-16 10:29:38 -0700 | [diff] [blame] | 274 | descriptor->insertName("FontName", metrics.fFontName); |
| 275 | descriptor->insertInt("Flags", (size_t)(metrics.fStyle | kPdfSymbolic)); |
| 276 | descriptor->insertScalar("Ascent", |
| 277 | scaleFromFontUnits(metrics.fAscent, emSize)); |
| 278 | descriptor->insertScalar("Descent", |
| 279 | scaleFromFontUnits(metrics.fDescent, emSize)); |
| 280 | descriptor->insertScalar("StemV", |
| 281 | scaleFromFontUnits(metrics.fStemV, emSize)); |
| 282 | descriptor->insertScalar("CapHeight", |
| 283 | scaleFromFontUnits(metrics.fCapHeight, emSize)); |
| 284 | descriptor->insertInt("ItalicAngle", metrics.fItalicAngle); |
| 285 | descriptor->insertObject( |
Hal Canary | aa3af7b | 2017-03-06 16:18:49 -0500 | [diff] [blame] | 286 | "FontBBox", makeFontBBox(metrics.fBBox, emSize)); |
vandebo@chromium.org | 9859428 | 2011-07-25 22:34:12 +0000 | [diff] [blame] | 287 | if (defaultWidth > 0) { |
halcanary | 28c6d83 | 2016-08-16 10:29:38 -0700 | [diff] [blame] | 288 | descriptor->insertScalar("MissingWidth", |
vandebo@chromium.org | 9859428 | 2011-07-25 22:34:12 +0000 | [diff] [blame] | 289 | scaleFromFontUnits(defaultWidth, emSize)); |
| 290 | } |
vandebo@chromium.org | 9859428 | 2011-07-25 22:34:12 +0000 | [diff] [blame] | 291 | } |
| 292 | |
vandebo@chromium.org | 9859428 | 2011-07-25 22:34:12 +0000 | [diff] [blame] | 293 | /////////////////////////////////////////////////////////////////////////////// |
| 294 | // class SkPDFType0Font |
| 295 | /////////////////////////////////////////////////////////////////////////////// |
vandebo@chromium.org | f7c1576 | 2011-02-01 22:19:44 +0000 | [diff] [blame] | 296 | |
halcanary | 530032a | 2016-08-18 14:22:52 -0700 | [diff] [blame] | 297 | SkPDFType0Font::SkPDFType0Font( |
| 298 | SkPDFFont::Info info, |
| 299 | const SkAdvancedTypefaceMetrics& metrics) |
| 300 | : SkPDFFont(std::move(info)) { |
vandebo@chromium.org | 9859428 | 2011-07-25 22:34:12 +0000 | [diff] [blame] | 301 | SkDEBUGCODE(fPopulated = false); |
| 302 | } |
| 303 | |
| 304 | SkPDFType0Font::~SkPDFType0Font() {} |
| 305 | |
vandebo@chromium.org | 9859428 | 2011-07-25 22:34:12 +0000 | [diff] [blame] | 306 | |
| 307 | #ifdef SK_DEBUG |
halcanary | 37c46ca | 2015-03-31 12:30:20 -0700 | [diff] [blame] | 308 | void SkPDFType0Font::emitObject(SkWStream* stream, |
halcanary | 530032a | 2016-08-18 14:22:52 -0700 | [diff] [blame] | 309 | const SkPDFObjNumMap& objNumMap) const { |
vandebo@chromium.org | 9859428 | 2011-07-25 22:34:12 +0000 | [diff] [blame] | 310 | SkASSERT(fPopulated); |
halcanary | 530032a | 2016-08-18 14:22:52 -0700 | [diff] [blame] | 311 | return INHERITED::emitObject(stream, objNumMap); |
vandebo@chromium.org | 9859428 | 2011-07-25 22:34:12 +0000 | [diff] [blame] | 312 | } |
| 313 | #endif |
| 314 | |
halcanary | 650e20d | 2016-08-25 09:07:02 -0700 | [diff] [blame] | 315 | #ifdef SK_PDF_USE_SFNTLY |
halcanary | fe8f0e0 | 2016-07-27 14:14:04 -0700 | [diff] [blame] | 316 | // if possible, make no copy. |
| 317 | static sk_sp<SkData> stream_to_data(std::unique_ptr<SkStreamAsset> stream) { |
| 318 | SkASSERT(stream); |
| 319 | (void)stream->rewind(); |
| 320 | SkASSERT(stream->hasLength()); |
| 321 | size_t size = stream->getLength(); |
| 322 | if (const void* base = stream->getMemoryBase()) { |
| 323 | SkData::ReleaseProc proc = |
halcanary | 426a245 | 2016-09-08 15:04:38 -0700 | [diff] [blame] | 324 | [](const void*, void* ctx) { delete (SkStreamAsset*)ctx; }; |
halcanary | fe8f0e0 | 2016-07-27 14:14:04 -0700 | [diff] [blame] | 325 | return SkData::MakeWithProc(base, size, proc, stream.release()); |
| 326 | } |
| 327 | return SkData::MakeFromStream(stream.get(), size); |
| 328 | } |
| 329 | |
halcanary | 426a245 | 2016-09-08 15:04:38 -0700 | [diff] [blame] | 330 | static sk_sp<SkPDFStream> get_subset_font_stream( |
halcanary | fe8f0e0 | 2016-07-27 14:14:04 -0700 | [diff] [blame] | 331 | std::unique_ptr<SkStreamAsset> fontAsset, |
halcanary | 426a245 | 2016-09-08 15:04:38 -0700 | [diff] [blame] | 332 | const SkBitSet& glyphUsage, |
| 333 | const char* fontName, |
| 334 | int ttcIndex) { |
| 335 | // Generate glyph id array in format needed by sfntly. |
| 336 | // TODO(halcanary): sfntly should take a more compact format. |
| 337 | SkTDArray<unsigned> subset; |
| 338 | if (!glyphUsage.has(0)) { |
| 339 | subset.push(0); // Always include glyph 0. |
| 340 | } |
| 341 | glyphUsage.exportTo(&subset); |
halcanary | fe8f0e0 | 2016-07-27 14:14:04 -0700 | [diff] [blame] | 342 | |
| 343 | unsigned char* subsetFont{nullptr}; |
halcanary | 426a245 | 2016-09-08 15:04:38 -0700 | [diff] [blame] | 344 | sk_sp<SkData> fontData(stream_to_data(std::move(fontAsset))); |
Hal Canary | 7ad8793 | 2017-02-16 10:33:49 -0500 | [diff] [blame] | 345 | #if defined(GOOGLE3) |
| 346 | // TODO(halcanary): update GOOGLE3 to newest version of Sfntly. |
halcanary | 426a245 | 2016-09-08 15:04:38 -0700 | [diff] [blame] | 347 | (void)ttcIndex; |
| 348 | int subsetFontSize = SfntlyWrapper::SubsetFont(fontName, |
| 349 | fontData->bytes(), |
| 350 | fontData->size(), |
| 351 | subset.begin(), |
| 352 | subset.count(), |
| 353 | &subsetFont); |
| 354 | #else |
| 355 | (void)fontName; |
| 356 | int subsetFontSize = SfntlyWrapper::SubsetFont(ttcIndex, |
| 357 | fontData->bytes(), |
| 358 | fontData->size(), |
| 359 | subset.begin(), |
| 360 | subset.count(), |
| 361 | &subsetFont); |
| 362 | #endif |
| 363 | fontData.reset(); |
| 364 | subset.reset(); |
halcanary | fe8f0e0 | 2016-07-27 14:14:04 -0700 | [diff] [blame] | 365 | SkASSERT(subsetFontSize > 0 || subsetFont == nullptr); |
| 366 | if (subsetFontSize < 1) { |
| 367 | return nullptr; |
| 368 | } |
| 369 | SkASSERT(subsetFont != nullptr); |
| 370 | auto subsetStream = sk_make_sp<SkPDFStream>( |
| 371 | SkData::MakeWithProc( |
| 372 | subsetFont, subsetFontSize, |
| 373 | [](const void* p, void*) { delete[] (unsigned char*)p; }, |
| 374 | nullptr)); |
halcanary | fa25106 | 2016-07-29 10:13:18 -0700 | [diff] [blame] | 375 | subsetStream->dict()->insertInt("Length1", subsetFontSize); |
halcanary | fe8f0e0 | 2016-07-27 14:14:04 -0700 | [diff] [blame] | 376 | return subsetStream; |
| 377 | } |
halcanary | 650e20d | 2016-08-25 09:07:02 -0700 | [diff] [blame] | 378 | #endif // SK_PDF_USE_SFNTLY |
halcanary | fe8f0e0 | 2016-07-27 14:14:04 -0700 | [diff] [blame] | 379 | |
halcanary | 530032a | 2016-08-18 14:22:52 -0700 | [diff] [blame] | 380 | void SkPDFType0Font::getFontSubset(SkPDFCanon* canon) { |
| 381 | const SkAdvancedTypefaceMetrics* metricsPtr = |
| 382 | SkPDFFont::GetMetrics(this->typeface(), canon); |
| 383 | SkASSERT(metricsPtr); |
| 384 | if (!metricsPtr) { return; } |
| 385 | const SkAdvancedTypefaceMetrics& metrics = *metricsPtr; |
halcanary | cee1342 | 2016-08-18 09:52:48 -0700 | [diff] [blame] | 386 | SkASSERT(can_embed(metrics)); |
halcanary | 28c6d83 | 2016-08-16 10:29:38 -0700 | [diff] [blame] | 387 | SkAdvancedTypefaceMetrics::FontType type = this->getType(); |
| 388 | SkTypeface* face = this->typeface(); |
| 389 | SkASSERT(face); |
vandebo@chromium.org | 9859428 | 2011-07-25 22:34:12 +0000 | [diff] [blame] | 390 | |
halcanary | 28c6d83 | 2016-08-16 10:29:38 -0700 | [diff] [blame] | 391 | auto descriptor = sk_make_sp<SkPDFDict>("FontDescriptor"); |
Hal Canary | aa3af7b | 2017-03-06 16:18:49 -0500 | [diff] [blame] | 392 | uint16_t emSize = SkToU16(this->typeface()->getUnitsPerEm()); |
| 393 | add_common_font_descriptor_entries(descriptor.get(), metrics, emSize , 0); |
halcanary | fe8f0e0 | 2016-07-27 14:14:04 -0700 | [diff] [blame] | 394 | |
halcanary | 426a245 | 2016-09-08 15:04:38 -0700 | [diff] [blame] | 395 | int ttcIndex; |
| 396 | std::unique_ptr<SkStreamAsset> fontAsset(face->openStream(&ttcIndex)); |
| 397 | size_t fontSize = fontAsset ? fontAsset->getLength() : 0; |
halcanary | 2a4d1e1 | 2016-09-22 14:13:16 -0700 | [diff] [blame] | 398 | if (0 == fontSize) { |
| 399 | SkDebugf("Error: (SkTypeface)(%p)::openStream() returned " |
| 400 | "empty stream (%p) when identified as kType1CID_Font " |
| 401 | "or kTrueType_Font.\n", face, fontAsset.get()); |
| 402 | } else { |
halcanary | 426a245 | 2016-09-08 15:04:38 -0700 | [diff] [blame] | 403 | switch (type) { |
| 404 | case SkAdvancedTypefaceMetrics::kTrueType_Font: { |
| 405 | #ifdef SK_PDF_USE_SFNTLY |
| 406 | if (!SkToBool(metrics.fFlags & |
| 407 | SkAdvancedTypefaceMetrics::kNotSubsettable_FontFlag)) { |
| 408 | sk_sp<SkPDFStream> subsetStream = get_subset_font_stream( |
| 409 | std::move(fontAsset), this->glyphUsage(), |
| 410 | metrics.fFontName.c_str(), ttcIndex); |
| 411 | if (subsetStream) { |
| 412 | descriptor->insertObjRef("FontFile2", std::move(subsetStream)); |
| 413 | break; |
| 414 | } |
| 415 | // If subsetting fails, fall back to original font data. |
| 416 | fontAsset.reset(face->openStream(&ttcIndex)); |
| 417 | SkASSERT(fontAsset); |
| 418 | SkASSERT(fontAsset->getLength() == fontSize); |
| 419 | if (!fontAsset || fontAsset->getLength() == 0) { break; } |
halcanary | 28c6d83 | 2016-08-16 10:29:38 -0700 | [diff] [blame] | 420 | } |
halcanary | 426a245 | 2016-09-08 15:04:38 -0700 | [diff] [blame] | 421 | #endif // SK_PDF_USE_SFNTLY |
| 422 | auto fontStream = sk_make_sp<SkPDFSharedStream>(std::move(fontAsset)); |
| 423 | fontStream->dict()->insertInt("Length1", fontSize); |
| 424 | descriptor->insertObjRef("FontFile2", std::move(fontStream)); |
| 425 | break; |
halcanary | fe8f0e0 | 2016-07-27 14:14:04 -0700 | [diff] [blame] | 426 | } |
halcanary | 426a245 | 2016-09-08 15:04:38 -0700 | [diff] [blame] | 427 | case SkAdvancedTypefaceMetrics::kType1CID_Font: { |
| 428 | auto fontStream = sk_make_sp<SkPDFSharedStream>(std::move(fontAsset)); |
| 429 | fontStream->dict()->insertName("Subtype", "CIDFontType0C"); |
| 430 | descriptor->insertObjRef("FontFile3", std::move(fontStream)); |
| 431 | break; |
halcanary | 8e3f54d | 2016-08-30 11:58:52 -0700 | [diff] [blame] | 432 | } |
halcanary | 426a245 | 2016-09-08 15:04:38 -0700 | [diff] [blame] | 433 | default: |
| 434 | SkASSERT(false); |
halcanary | 8e3f54d | 2016-08-30 11:58:52 -0700 | [diff] [blame] | 435 | } |
vandebo@chromium.org | 9859428 | 2011-07-25 22:34:12 +0000 | [diff] [blame] | 436 | } |
vandebo@chromium.org | 9859428 | 2011-07-25 22:34:12 +0000 | [diff] [blame] | 437 | |
halcanary | 28c6d83 | 2016-08-16 10:29:38 -0700 | [diff] [blame] | 438 | auto newCIDFont = sk_make_sp<SkPDFDict>("Font"); |
| 439 | newCIDFont->insertObjRef("FontDescriptor", std::move(descriptor)); |
halcanary | 426a245 | 2016-09-08 15:04:38 -0700 | [diff] [blame] | 440 | newCIDFont->insertName("BaseFont", metrics.fFontName); |
halcanary | 28c6d83 | 2016-08-16 10:29:38 -0700 | [diff] [blame] | 441 | |
halcanary | 426a245 | 2016-09-08 15:04:38 -0700 | [diff] [blame] | 442 | switch (type) { |
| 443 | case SkAdvancedTypefaceMetrics::kType1CID_Font: |
| 444 | newCIDFont->insertName("Subtype", "CIDFontType0"); |
| 445 | break; |
| 446 | case SkAdvancedTypefaceMetrics::kTrueType_Font: |
| 447 | newCIDFont->insertName("Subtype", "CIDFontType2"); |
| 448 | newCIDFont->insertName("CIDToGIDMap", "Identity"); |
| 449 | break; |
| 450 | default: |
| 451 | SkASSERT(false); |
halcanary | 462d014 | 2016-08-05 13:51:46 -0700 | [diff] [blame] | 452 | } |
halcanary | 28c6d83 | 2016-08-16 10:29:38 -0700 | [diff] [blame] | 453 | auto sysInfo = sk_make_sp<SkPDFDict>(); |
halcanary | 59be20c | 2016-09-01 14:10:00 -0700 | [diff] [blame] | 454 | sysInfo->insertString("Registry", "Adobe"); |
| 455 | sysInfo->insertString("Ordering", "Identity"); |
halcanary | 28c6d83 | 2016-08-16 10:29:38 -0700 | [diff] [blame] | 456 | sysInfo->insertInt("Supplement", 0); |
| 457 | newCIDFont->insertObject("CIDSystemInfo", std::move(sysInfo)); |
| 458 | |
halcanary | 28c6d83 | 2016-08-16 10:29:38 -0700 | [diff] [blame] | 459 | int16_t defaultWidth = 0; |
halcanary | 86b6eab | 2016-08-17 07:57:27 -0700 | [diff] [blame] | 460 | { |
Hal Canary | aa3af7b | 2017-03-06 16:18:49 -0500 | [diff] [blame] | 461 | int emSize; |
| 462 | SkAutoGlyphCache glyphCache = SkPDFFont::MakeVectorCache(face, &emSize); |
halcanary | 86b6eab | 2016-08-17 07:57:27 -0700 | [diff] [blame] | 463 | sk_sp<SkPDFArray> widths = SkPDFMakeCIDGlyphWidthsArray( |
Hal Canary | aa3af7b | 2017-03-06 16:18:49 -0500 | [diff] [blame] | 464 | glyphCache.get(), &this->glyphUsage(), SkToS16(emSize), &defaultWidth); |
halcanary | 86b6eab | 2016-08-17 07:57:27 -0700 | [diff] [blame] | 465 | if (widths && widths->size() > 0) { |
| 466 | newCIDFont->insertObject("W", std::move(widths)); |
| 467 | } |
| 468 | newCIDFont->insertScalar( |
Hal Canary | aa3af7b | 2017-03-06 16:18:49 -0500 | [diff] [blame] | 469 | "DW", scaleFromFontUnits(defaultWidth, SkToS16(emSize))); |
halcanary | 28c6d83 | 2016-08-16 10:29:38 -0700 | [diff] [blame] | 470 | } |
| 471 | |
halcanary | 28c6d83 | 2016-08-16 10:29:38 -0700 | [diff] [blame] | 472 | //////////////////////////////////////////////////////////////////////////// |
| 473 | |
| 474 | this->insertName("Subtype", "Type0"); |
| 475 | this->insertName("BaseFont", metrics.fFontName); |
| 476 | this->insertName("Encoding", "Identity-H"); |
| 477 | auto descendantFonts = sk_make_sp<SkPDFArray>(); |
| 478 | descendantFonts->appendObjRef(std::move(newCIDFont)); |
| 479 | this->insertObject("DescendantFonts", std::move(descendantFonts)); |
halcanary | cee1342 | 2016-08-18 09:52:48 -0700 | [diff] [blame] | 480 | |
| 481 | if (metrics.fGlyphToUnicode.count() > 0) { |
| 482 | this->insertObjRef("ToUnicode", |
| 483 | SkPDFMakeToUnicodeCmap(metrics.fGlyphToUnicode, |
halcanary | 530032a | 2016-08-18 14:22:52 -0700 | [diff] [blame] | 484 | &this->glyphUsage(), |
halcanary | cee1342 | 2016-08-18 09:52:48 -0700 | [diff] [blame] | 485 | multiByteGlyphs(), |
| 486 | firstGlyphID(), |
| 487 | lastGlyphID())); |
| 488 | } |
halcanary | 28c6d83 | 2016-08-16 10:29:38 -0700 | [diff] [blame] | 489 | SkDEBUGCODE(fPopulated = true); |
halcanary | 530032a | 2016-08-18 14:22:52 -0700 | [diff] [blame] | 490 | return; |
halcanary | 8eccc30 | 2016-08-09 13:04:34 -0700 | [diff] [blame] | 491 | } |
| 492 | |
vandebo@chromium.org | 9859428 | 2011-07-25 22:34:12 +0000 | [diff] [blame] | 493 | /////////////////////////////////////////////////////////////////////////////// |
| 494 | // class SkPDFType1Font |
| 495 | /////////////////////////////////////////////////////////////////////////////// |
| 496 | |
halcanary | cee1342 | 2016-08-18 09:52:48 -0700 | [diff] [blame] | 497 | static sk_sp<SkPDFDict> make_type1_font_descriptor( |
| 498 | SkTypeface* typeface, |
| 499 | const SkAdvancedTypefaceMetrics& info) { |
halcanary | ece8392 | 2016-03-08 08:32:12 -0800 | [diff] [blame] | 500 | auto descriptor = sk_make_sp<SkPDFDict>("FontDescriptor"); |
Hal Canary | aa3af7b | 2017-03-06 16:18:49 -0500 | [diff] [blame] | 501 | uint16_t emSize = SkToU16(typeface->getUnitsPerEm()); |
| 502 | add_common_font_descriptor_entries(descriptor.get(), info, emSize, 0); |
halcanary | cee1342 | 2016-08-18 09:52:48 -0700 | [diff] [blame] | 503 | if (!can_embed(info)) { |
| 504 | return descriptor; |
| 505 | } |
reed@google.com | fed86bd | 2013-03-14 15:04:57 +0000 | [diff] [blame] | 506 | int ttcIndex; |
vandebo@chromium.org | 9859428 | 2011-07-25 22:34:12 +0000 | [diff] [blame] | 507 | size_t header SK_INIT_TO_AVOID_WARNING; |
| 508 | size_t data SK_INIT_TO_AVOID_WARNING; |
| 509 | size_t trailer SK_INIT_TO_AVOID_WARNING; |
halcanary | cee1342 | 2016-08-18 09:52:48 -0700 | [diff] [blame] | 510 | std::unique_ptr<SkStreamAsset> rawFontData(typeface->openStream(&ttcIndex)); |
halcanary | 8eccc30 | 2016-08-09 13:04:34 -0700 | [diff] [blame] | 511 | sk_sp<SkData> fontData = SkPDFConvertType1FontStream(std::move(rawFontData), |
| 512 | &header, &data, &trailer); |
halcanary | cee1342 | 2016-08-18 09:52:48 -0700 | [diff] [blame] | 513 | if (fontData) { |
| 514 | auto fontStream = sk_make_sp<SkPDFStream>(std::move(fontData)); |
| 515 | fontStream->dict()->insertInt("Length1", header); |
| 516 | fontStream->dict()->insertInt("Length2", data); |
| 517 | fontStream->dict()->insertInt("Length3", trailer); |
| 518 | descriptor->insertObjRef("FontFile", std::move(fontStream)); |
vandebo@chromium.org | 9859428 | 2011-07-25 22:34:12 +0000 | [diff] [blame] | 519 | } |
halcanary | cee1342 | 2016-08-18 09:52:48 -0700 | [diff] [blame] | 520 | return descriptor; |
vandebo@chromium.org | 9859428 | 2011-07-25 22:34:12 +0000 | [diff] [blame] | 521 | } |
| 522 | |
halcanary | cee1342 | 2016-08-18 09:52:48 -0700 | [diff] [blame] | 523 | static void populate_type_1_font(SkPDFDict* font, |
| 524 | const SkAdvancedTypefaceMetrics& info, |
| 525 | SkTypeface* typeface, |
| 526 | SkGlyphID firstGlyphID, |
| 527 | SkGlyphID lastGlyphID) { |
| 528 | font->insertName("Subtype", "Type1"); |
| 529 | font->insertName("BaseFont", info.fFontName); |
vandebo@chromium.org | f77e27d | 2011-03-10 22:50:28 +0000 | [diff] [blame] | 530 | |
halcanary | 8eccc30 | 2016-08-09 13:04:34 -0700 | [diff] [blame] | 531 | // glyphCount not including glyph 0 |
| 532 | unsigned glyphCount = 1 + lastGlyphID - firstGlyphID; |
| 533 | SkASSERT(glyphCount > 0 && glyphCount <= 255); |
halcanary | cee1342 | 2016-08-18 09:52:48 -0700 | [diff] [blame] | 534 | font->insertInt("FirstChar", (size_t)0); |
| 535 | font->insertInt("LastChar", (size_t)glyphCount); |
halcanary | 462d014 | 2016-08-05 13:51:46 -0700 | [diff] [blame] | 536 | { |
Hal Canary | aa3af7b | 2017-03-06 16:18:49 -0500 | [diff] [blame] | 537 | int emSize; |
| 538 | SkAutoGlyphCache glyphCache = SkPDFFont::MakeVectorCache(typeface, &emSize); |
halcanary | 8eccc30 | 2016-08-09 13:04:34 -0700 | [diff] [blame] | 539 | auto widths = sk_make_sp<SkPDFArray>(); |
| 540 | SkScalar advance = glyphCache->getGlyphIDAdvance(0).fAdvanceX; |
Hal Canary | aa3af7b | 2017-03-06 16:18:49 -0500 | [diff] [blame] | 541 | widths->appendScalar(from_font_units(advance, SkToU16(emSize))); |
halcanary | 8eccc30 | 2016-08-09 13:04:34 -0700 | [diff] [blame] | 542 | for (unsigned gID = firstGlyphID; gID <= lastGlyphID; gID++) { |
| 543 | advance = glyphCache->getGlyphIDAdvance(gID).fAdvanceX; |
Hal Canary | aa3af7b | 2017-03-06 16:18:49 -0500 | [diff] [blame] | 544 | widths->appendScalar(from_font_units(advance, SkToU16(emSize))); |
vandebo@chromium.org | 2a22e10 | 2011-01-25 21:01:34 +0000 | [diff] [blame] | 545 | } |
halcanary | cee1342 | 2016-08-18 09:52:48 -0700 | [diff] [blame] | 546 | font->insertObject("Widths", std::move(widths)); |
ctguil@chromium.org | 769fa6a | 2011-08-20 00:36:18 +0000 | [diff] [blame] | 547 | } |
halcanary | ece8392 | 2016-03-08 08:32:12 -0800 | [diff] [blame] | 548 | auto encDiffs = sk_make_sp<SkPDFArray>(); |
halcanary | 8eccc30 | 2016-08-09 13:04:34 -0700 | [diff] [blame] | 549 | encDiffs->reserve(lastGlyphID - firstGlyphID + 3); |
| 550 | encDiffs->appendInt(0); |
halcanary | cee1342 | 2016-08-18 09:52:48 -0700 | [diff] [blame] | 551 | const SkTArray<SkString>& glyphNames = info.fGlyphNames; |
halcanary | 8eccc30 | 2016-08-09 13:04:34 -0700 | [diff] [blame] | 552 | SkASSERT(glyphNames.count() > lastGlyphID); |
| 553 | encDiffs->appendName(glyphNames[0].c_str()); |
| 554 | const SkString unknown("UNKNOWN"); |
| 555 | for (int gID = firstGlyphID; gID <= lastGlyphID; gID++) { |
| 556 | const bool valid = gID < glyphNames.count() && !glyphNames[gID].isEmpty(); |
| 557 | const SkString& name = valid ? glyphNames[gID] : unknown; |
| 558 | encDiffs->appendName(name); |
vandebo@chromium.org | 2a22e10 | 2011-01-25 21:01:34 +0000 | [diff] [blame] | 559 | } |
| 560 | |
halcanary | ece8392 | 2016-03-08 08:32:12 -0800 | [diff] [blame] | 561 | auto encoding = sk_make_sp<SkPDFDict>("Encoding"); |
halcanary | 8103a34 | 2016-03-08 15:10:16 -0800 | [diff] [blame] | 562 | encoding->insertObject("Differences", std::move(encDiffs)); |
halcanary | cee1342 | 2016-08-18 09:52:48 -0700 | [diff] [blame] | 563 | font->insertObject("Encoding", std::move(encoding)); |
| 564 | } |
| 565 | |
halcanary | 530032a | 2016-08-18 14:22:52 -0700 | [diff] [blame] | 566 | SkPDFType1Font::SkPDFType1Font(SkPDFFont::Info info, |
| 567 | const SkAdvancedTypefaceMetrics& metrics, |
halcanary | cee1342 | 2016-08-18 09:52:48 -0700 | [diff] [blame] | 568 | SkPDFCanon* canon) |
halcanary | 530032a | 2016-08-18 14:22:52 -0700 | [diff] [blame] | 569 | : SkPDFFont(std::move(info)) |
halcanary | cee1342 | 2016-08-18 09:52:48 -0700 | [diff] [blame] | 570 | { |
| 571 | SkFontID fontID = this->typeface()->uniqueID(); |
| 572 | sk_sp<SkPDFDict> fontDescriptor; |
Hal Canary | 5c1b360 | 2017-04-17 16:30:06 -0400 | [diff] [blame] | 573 | if (sk_sp<SkPDFDict>* ptr = canon->fFontDescriptors.find(fontID)) { |
| 574 | fontDescriptor = *ptr; |
halcanary | cee1342 | 2016-08-18 09:52:48 -0700 | [diff] [blame] | 575 | } else { |
halcanary | 530032a | 2016-08-18 14:22:52 -0700 | [diff] [blame] | 576 | fontDescriptor = make_type1_font_descriptor(this->typeface(), metrics); |
Hal Canary | 5c1b360 | 2017-04-17 16:30:06 -0400 | [diff] [blame] | 577 | canon->fFontDescriptors.set(fontID, fontDescriptor); |
halcanary | cee1342 | 2016-08-18 09:52:48 -0700 | [diff] [blame] | 578 | } |
| 579 | this->insertObjRef("FontDescriptor", std::move(fontDescriptor)); |
halcanary | cee1342 | 2016-08-18 09:52:48 -0700 | [diff] [blame] | 580 | // TODO(halcanary): subset this (advances and names). |
halcanary | 530032a | 2016-08-18 14:22:52 -0700 | [diff] [blame] | 581 | populate_type_1_font(this, metrics, this->typeface(), |
halcanary | cee1342 | 2016-08-18 09:52:48 -0700 | [diff] [blame] | 582 | this->firstGlyphID(), this->lastGlyphID()); |
vandebo@chromium.org | 28be72b | 2010-11-11 21:37:00 +0000 | [diff] [blame] | 583 | } |
| 584 | |
vandebo@chromium.org | 9859428 | 2011-07-25 22:34:12 +0000 | [diff] [blame] | 585 | /////////////////////////////////////////////////////////////////////////////// |
| 586 | // class SkPDFType3Font |
| 587 | /////////////////////////////////////////////////////////////////////////////// |
| 588 | |
halcanary | 7e8d5d3 | 2016-08-12 07:59:38 -0700 | [diff] [blame] | 589 | namespace { |
| 590 | // returns [0, first, first+1, ... last-1, last] |
| 591 | struct SingleByteGlyphIdIterator { |
| 592 | SingleByteGlyphIdIterator(SkGlyphID first, SkGlyphID last) |
| 593 | : fFirst(first), fLast(last) { |
| 594 | SkASSERT(fFirst > 0); |
| 595 | SkASSERT(fLast >= first); |
| 596 | } |
| 597 | struct Iter { |
| 598 | void operator++() { |
| 599 | fCurrent = (0 == fCurrent) ? fFirst : fCurrent + 1; |
| 600 | } |
| 601 | // This is an input_iterator |
| 602 | SkGlyphID operator*() const { return (SkGlyphID)fCurrent; } |
| 603 | bool operator!=(const Iter& rhs) const { |
| 604 | return fCurrent != rhs.fCurrent; |
| 605 | } |
| 606 | Iter(SkGlyphID f, int c) : fFirst(f), fCurrent(c) {} |
| 607 | private: |
| 608 | const SkGlyphID fFirst; |
| 609 | int fCurrent; // must be int to make fLast+1 to fit |
| 610 | }; |
| 611 | Iter begin() const { return Iter(fFirst, 0); } |
| 612 | Iter end() const { return Iter(fFirst, (int)fLast + 1); } |
| 613 | private: |
| 614 | const SkGlyphID fFirst; |
| 615 | const SkGlyphID fLast; |
| 616 | }; |
vandebo@chromium.org | 9859428 | 2011-07-25 22:34:12 +0000 | [diff] [blame] | 617 | } |
| 618 | |
halcanary | cee1342 | 2016-08-18 09:52:48 -0700 | [diff] [blame] | 619 | static void add_type3_font_info(SkPDFCanon* canon, |
| 620 | SkPDFDict* font, |
halcanary | 7e8d5d3 | 2016-08-12 07:59:38 -0700 | [diff] [blame] | 621 | SkTypeface* typeface, |
halcanary | 530032a | 2016-08-18 14:22:52 -0700 | [diff] [blame] | 622 | const SkBitSet& subset, |
halcanary | 7e8d5d3 | 2016-08-12 07:59:38 -0700 | [diff] [blame] | 623 | SkGlyphID firstGlyphID, |
| 624 | SkGlyphID lastGlyphID) { |
halcanary | 3d01c62 | 2016-08-31 12:52:35 -0700 | [diff] [blame] | 625 | const SkAdvancedTypefaceMetrics* metrics = SkPDFFont::GetMetrics(typeface, canon); |
halcanary | 7e8d5d3 | 2016-08-12 07:59:38 -0700 | [diff] [blame] | 626 | SkASSERT(lastGlyphID >= firstGlyphID); |
halcanary | 1748432 | 2016-08-29 09:47:48 -0700 | [diff] [blame] | 627 | // Remove unused glyphs at the end of the range. |
| 628 | // Keep the lastGlyphID >= firstGlyphID invariant true. |
| 629 | while (lastGlyphID > firstGlyphID && !subset.has(lastGlyphID)) { |
| 630 | --lastGlyphID; |
| 631 | } |
Hal Canary | aa3af7b | 2017-03-06 16:18:49 -0500 | [diff] [blame] | 632 | int unitsPerEm; |
| 633 | SkAutoGlyphCache cache = SkPDFFont::MakeVectorCache(typeface, &unitsPerEm); |
| 634 | SkScalar emSize = (SkScalar)unitsPerEm; |
halcanary | 7e8d5d3 | 2016-08-12 07:59:38 -0700 | [diff] [blame] | 635 | font->insertName("Subtype", "Type3"); |
| 636 | // Flip about the x-axis and scale by 1/emSize. |
ctguil@chromium.org | 9db86bb | 2011-03-04 21:43:27 +0000 | [diff] [blame] | 637 | SkMatrix fontMatrix; |
halcanary | 7e8d5d3 | 2016-08-12 07:59:38 -0700 | [diff] [blame] | 638 | fontMatrix.setScale(SkScalarInvert(emSize), -SkScalarInvert(emSize)); |
| 639 | font->insertObject("FontMatrix", SkPDFUtils::MatrixToArray(fontMatrix)); |
ctguil@chromium.org | 9db86bb | 2011-03-04 21:43:27 +0000 | [diff] [blame] | 640 | |
halcanary | ece8392 | 2016-03-08 08:32:12 -0800 | [diff] [blame] | 641 | auto charProcs = sk_make_sp<SkPDFDict>(); |
| 642 | auto encoding = sk_make_sp<SkPDFDict>("Encoding"); |
ctguil@chromium.org | 9db86bb | 2011-03-04 21:43:27 +0000 | [diff] [blame] | 643 | |
halcanary | ece8392 | 2016-03-08 08:32:12 -0800 | [diff] [blame] | 644 | auto encDiffs = sk_make_sp<SkPDFArray>(); |
halcanary | 7e8d5d3 | 2016-08-12 07:59:38 -0700 | [diff] [blame] | 645 | // length(firstGlyphID .. lastGlyphID) == lastGlyphID - firstGlyphID + 1 |
| 646 | // plus 1 for glyph 0; |
| 647 | SkASSERT(firstGlyphID > 0); |
| 648 | SkASSERT(lastGlyphID >= firstGlyphID); |
| 649 | int glyphCount = lastGlyphID - firstGlyphID + 2; |
| 650 | // one other entry for the index of first glyph. |
| 651 | encDiffs->reserve(glyphCount + 1); |
| 652 | encDiffs->appendInt(0); // index of first glyph |
ctguil@chromium.org | 9db86bb | 2011-03-04 21:43:27 +0000 | [diff] [blame] | 653 | |
halcanary | ece8392 | 2016-03-08 08:32:12 -0800 | [diff] [blame] | 654 | auto widthArray = sk_make_sp<SkPDFArray>(); |
halcanary | 7e8d5d3 | 2016-08-12 07:59:38 -0700 | [diff] [blame] | 655 | widthArray->reserve(glyphCount); |
ctguil@chromium.org | 9db86bb | 2011-03-04 21:43:27 +0000 | [diff] [blame] | 656 | |
ctguil@chromium.org | 9db86bb | 2011-03-04 21:43:27 +0000 | [diff] [blame] | 657 | SkIRect bbox = SkIRect::MakeEmpty(); |
halcanary | 7e8d5d3 | 2016-08-12 07:59:38 -0700 | [diff] [blame] | 658 | |
| 659 | sk_sp<SkPDFStream> emptyStream; |
| 660 | for (SkGlyphID gID : SingleByteGlyphIdIterator(firstGlyphID, lastGlyphID)) { |
halcanary | 530032a | 2016-08-18 14:22:52 -0700 | [diff] [blame] | 661 | bool skipGlyph = gID != 0 && !subset.has(gID); |
ctguil@chromium.org | 9db86bb | 2011-03-04 21:43:27 +0000 | [diff] [blame] | 662 | SkString characterName; |
halcanary | 7e8d5d3 | 2016-08-12 07:59:38 -0700 | [diff] [blame] | 663 | SkScalar advance = 0.0f; |
| 664 | SkIRect glyphBBox; |
| 665 | if (skipGlyph) { |
| 666 | characterName.set("g0"); |
| 667 | } else { |
| 668 | characterName.printf("g%X", gID); |
| 669 | const SkGlyph& glyph = cache->getGlyphIDMetrics(gID); |
| 670 | advance = SkFloatToScalar(glyph.fAdvanceX); |
| 671 | glyphBBox = SkIRect::MakeXYWH(glyph.fLeft, glyph.fTop, |
| 672 | glyph.fWidth, glyph.fHeight); |
| 673 | bbox.join(glyphBBox); |
| 674 | const SkPath* path = cache->findPath(glyph); |
| 675 | if (path && !path->isEmpty()) { |
| 676 | SkDynamicMemoryWStream content; |
| 677 | setGlyphWidthAndBoundingBox(SkFloatToScalar(glyph.fAdvanceX), glyphBBox, |
| 678 | &content); |
| 679 | SkPDFUtils::EmitPath(*path, SkPaint::kFill_Style, &content); |
| 680 | SkPDFUtils::PaintPath(SkPaint::kFill_Style, path->getFillType(), |
| 681 | &content); |
| 682 | charProcs->insertObjRef( |
| 683 | characterName, sk_make_sp<SkPDFStream>( |
| 684 | std::unique_ptr<SkStreamAsset>(content.detachAsStream()))); |
| 685 | } else { |
| 686 | if (!emptyStream) { |
| 687 | emptyStream = sk_make_sp<SkPDFStream>( |
| 688 | std::unique_ptr<SkStreamAsset>( |
| 689 | new SkMemoryStream((size_t)0))); |
| 690 | } |
| 691 | charProcs->insertObjRef(characterName, emptyStream); |
| 692 | } |
halcanary | 5bf60ad | 2016-08-11 13:59:18 -0700 | [diff] [blame] | 693 | } |
halcanary | 7e8d5d3 | 2016-08-12 07:59:38 -0700 | [diff] [blame] | 694 | encDiffs->appendName(characterName.c_str()); |
| 695 | widthArray->appendScalar(advance); |
ctguil@chromium.org | 9db86bb | 2011-03-04 21:43:27 +0000 | [diff] [blame] | 696 | } |
| 697 | |
halcanary | 8103a34 | 2016-03-08 15:10:16 -0800 | [diff] [blame] | 698 | encoding->insertObject("Differences", std::move(encDiffs)); |
halcanary | 7e8d5d3 | 2016-08-12 07:59:38 -0700 | [diff] [blame] | 699 | font->insertInt("FirstChar", 0); |
| 700 | font->insertInt("LastChar", lastGlyphID - firstGlyphID + 1); |
| 701 | /* FontBBox: "A rectangle expressed in the glyph coordinate |
| 702 | system, specifying the font bounding box. This is the smallest |
| 703 | rectangle enclosing the shape that would result if all of the |
| 704 | glyphs of the font were placed with their origins coincident and |
| 705 | then filled." */ |
| 706 | auto fontBBox = sk_make_sp<SkPDFArray>(); |
| 707 | fontBBox->reserve(4); |
| 708 | fontBBox->appendInt(bbox.left()); |
| 709 | fontBBox->appendInt(bbox.bottom()); |
| 710 | fontBBox->appendInt(bbox.right()); |
| 711 | fontBBox->appendInt(bbox.top()); |
| 712 | font->insertObject("FontBBox", std::move(fontBBox)); |
| 713 | font->insertName("CIDToGIDMap", "Identity"); |
halcanary | 3d01c62 | 2016-08-31 12:52:35 -0700 | [diff] [blame] | 714 | if (metrics && metrics->fGlyphToUnicode.count() > 0) { |
halcanary | 7e8d5d3 | 2016-08-12 07:59:38 -0700 | [diff] [blame] | 715 | font->insertObjRef("ToUnicode", |
| 716 | SkPDFMakeToUnicodeCmap(metrics->fGlyphToUnicode, |
halcanary | 530032a | 2016-08-18 14:22:52 -0700 | [diff] [blame] | 717 | &subset, |
halcanary | 7e8d5d3 | 2016-08-12 07:59:38 -0700 | [diff] [blame] | 718 | false, |
| 719 | firstGlyphID, |
| 720 | lastGlyphID)); |
| 721 | } |
halcanary | 3d01c62 | 2016-08-31 12:52:35 -0700 | [diff] [blame] | 722 | auto descriptor = sk_make_sp<SkPDFDict>("FontDescriptor"); |
| 723 | int32_t fontDescriptorFlags = kPdfSymbolic; |
| 724 | if (metrics) { |
| 725 | // Type3 FontDescriptor does not require all the same fields. |
| 726 | descriptor->insertName("FontName", metrics->fFontName); |
| 727 | descriptor->insertInt("ItalicAngle", metrics->fItalicAngle); |
| 728 | fontDescriptorFlags |= (int32_t)metrics->fStyle; |
| 729 | } |
| 730 | descriptor->insertInt("Flags", fontDescriptorFlags); |
| 731 | font->insertObjRef("FontDescriptor", std::move(descriptor)); |
halcanary | 7e8d5d3 | 2016-08-12 07:59:38 -0700 | [diff] [blame] | 732 | font->insertObject("Widths", std::move(widthArray)); |
| 733 | font->insertObject("Encoding", std::move(encoding)); |
| 734 | font->insertObject("CharProcs", std::move(charProcs)); |
vandebo@chromium.org | 2a22e10 | 2011-01-25 21:01:34 +0000 | [diff] [blame] | 735 | } |
halcanary | fb62b3d | 2015-01-21 09:59:14 -0800 | [diff] [blame] | 736 | |
halcanary | 530032a | 2016-08-18 14:22:52 -0700 | [diff] [blame] | 737 | SkPDFType3Font::SkPDFType3Font(SkPDFFont::Info info, |
| 738 | const SkAdvancedTypefaceMetrics& metrics) |
| 739 | : SkPDFFont(std::move(info)) {} |
halcanary | 7e8d5d3 | 2016-08-12 07:59:38 -0700 | [diff] [blame] | 740 | |
halcanary | 530032a | 2016-08-18 14:22:52 -0700 | [diff] [blame] | 741 | void SkPDFType3Font::getFontSubset(SkPDFCanon* canon) { |
Hal Canary | aa3af7b | 2017-03-06 16:18:49 -0500 | [diff] [blame] | 742 | add_type3_font_info(canon, this, this->typeface(), this->glyphUsage(), |
halcanary | 7e8d5d3 | 2016-08-12 07:59:38 -0700 | [diff] [blame] | 743 | this->firstGlyphID(), this->lastGlyphID()); |
halcanary | 7e8d5d3 | 2016-08-12 07:59:38 -0700 | [diff] [blame] | 744 | } |
| 745 | |
halcanary | 7e8d5d3 | 2016-08-12 07:59:38 -0700 | [diff] [blame] | 746 | //////////////////////////////////////////////////////////////////////////////// |
| 747 | |
halcanary | 66a82f3 | 2015-10-12 13:05:04 -0700 | [diff] [blame] | 748 | bool SkPDFFont::CanEmbedTypeface(SkTypeface* typeface, SkPDFCanon* canon) { |
halcanary | cee1342 | 2016-08-18 09:52:48 -0700 | [diff] [blame] | 749 | const SkAdvancedTypefaceMetrics* metrics = SkPDFFont::GetMetrics(typeface, canon); |
| 750 | return metrics && can_embed(*metrics); |
halcanary | 66a82f3 | 2015-10-12 13:05:04 -0700 | [diff] [blame] | 751 | } |
halcanary | bae235e | 2016-03-21 10:05:23 -0700 | [diff] [blame] | 752 | |
| 753 | void SkPDFFont::drop() { |
| 754 | fTypeface = nullptr; |
halcanary | e202bd8 | 2016-09-19 10:27:03 -0700 | [diff] [blame] | 755 | fGlyphUsage.~SkBitSet(); |
| 756 | new (&fGlyphUsage) SkBitSet(0); |
halcanary | bae235e | 2016-03-21 10:05:23 -0700 | [diff] [blame] | 757 | this->SkPDFDict::drop(); |
| 758 | } |