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