1 /* 2 * Copyright 2011 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #include "SkData.h" 9 #include "SkGlyphCache.h" 10 #include "SkMakeUnique.h" 11 #include "SkPDFCanon.h" 12 #include "SkPDFConvertType1FontStream.h" 13 #include "SkPDFDevice.h" 14 #include "SkPDFFont.h" 15 #include "SkPDFMakeCIDGlyphWidthsArray.h" 16 #include "SkPDFMakeToUnicodeCmap.h" 17 #include "SkPDFUtils.h" 18 #include "SkPaint.h" 19 #include "SkRefCnt.h" 20 #include "SkScalar.h" 21 #include "SkStream.h" 22 #include "SkTypes.h" 23 #include "SkUtils.h" 24 25 #ifdef SK_PDF_USE_SFNTLY 26 #include "sample/chromium/font_subsetter.h" 27 #endif 28 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 47 namespace { 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) 51 static const int32_t kPdfSymbolic = 4; 52 53 struct SkPDFType0Font final : public SkPDFFont { 54 SkPDFType0Font(SkPDFFont::Info, const SkAdvancedTypefaceMetrics&); 55 ~SkPDFType0Font() override; 56 void getFontSubset(SkPDFCanon*) override; 57 #ifdef SK_DEBUG 58 void emitObject(SkWStream*, const SkPDFObjNumMap&) const override; 59 bool fPopulated; 60 #endif 61 typedef SkPDFDict INHERITED; 62 }; 63 64 struct SkPDFType1Font final : public SkPDFFont { 65 SkPDFType1Font(SkPDFFont::Info, const SkAdvancedTypefaceMetrics&, SkPDFCanon*); 66 ~SkPDFType1Font() override {} 67 void getFontSubset(SkPDFCanon*) override {} // TODO(halcanary): implement 68 }; 69 70 struct SkPDFType3Font final : public SkPDFFont { 71 SkPDFType3Font(SkPDFFont::Info, const SkAdvancedTypefaceMetrics&); 72 ~SkPDFType3Font() override {} 73 void getFontSubset(SkPDFCanon*) override; 74 }; 75 76 /////////////////////////////////////////////////////////////////////////////// 77 // File-Local Functions 78 /////////////////////////////////////////////////////////////////////////////// 79 80 // scale from em-units to base-1000, returning as a SkScalar 81 SkScalar from_font_units(SkScalar scaled, uint16_t emSize) { 82 if (emSize == 1000) { 83 return scaled; 84 } else { 85 return scaled * 1000 / emSize; 86 } 87 } 88 89 SkScalar scaleFromFontUnits(int16_t val, uint16_t emSize) { 90 return from_font_units(SkIntToScalar(val), emSize); 91 } 92 93 94 void setGlyphWidthAndBoundingBox(SkScalar width, SkIRect box, 95 SkDynamicMemoryWStream* content) { 96 // Specify width and bounding box for the glyph. 97 SkPDFUtils::AppendScalar(width, content); 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"); 107 } 108 109 static sk_sp<SkPDFArray> makeFontBBox(SkIRect glyphBBox, uint16_t emSize) { 110 auto bbox = sk_make_sp<SkPDFArray>(); 111 bbox->reserve(4); 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)); 116 return bbox; 117 } 118 } // namespace 119 120 /////////////////////////////////////////////////////////////////////////////// 121 // class SkPDFFont 122 /////////////////////////////////////////////////////////////////////////////// 123 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 136 SkPDFFont::~SkPDFFont() {} 137 138 static bool can_embed(const SkAdvancedTypefaceMetrics& metrics) { 139 return !SkToBool(metrics.fFlags & SkAdvancedTypefaceMetrics::kNotEmbeddable_FontFlag); 140 } 141 142 const SkAdvancedTypefaceMetrics* SkPDFFont::GetMetrics(SkTypeface* typeface, 143 SkPDFCanon* canon) { 144 SkASSERT(typeface); 145 SkFontID id = typeface->uniqueID(); 146 if (std::unique_ptr<SkAdvancedTypefaceMetrics>* ptr = canon->fTypefaceMetrics.find(id)) { 147 return ptr->get(); // canon retains ownership. 148 } 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; 154 } 155 std::unique_ptr<SkAdvancedTypefaceMetrics> metrics = typeface->getAdvancedMetrics(); 156 if (!metrics) { 157 metrics = skstd::make_unique<SkAdvancedTypefaceMetrics>(); 158 } 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 } 187 return canon->fTypefaceMetrics.set(id, std::move(metrics))->get(); 188 } 189 190 SkAdvancedTypefaceMetrics::FontType SkPDFFont::FontType(const SkAdvancedTypefaceMetrics& metrics) { 191 if (SkToBool(metrics.fFlags & SkAdvancedTypefaceMetrics::kMultiMaster_FontFlag) || 192 SkToBool(metrics.fFlags & SkAdvancedTypefaceMetrics::kNotEmbeddable_FontFlag)) { 193 // force Type3 fallback. 194 return SkAdvancedTypefaceMetrics::kOther_Font; 195 } 196 return metrics.fType; 197 } 198 199 static SkGlyphID first_nonzero_glyph_for_single_byte_encoding(SkGlyphID gid) { 200 return gid != 0 ? gid - (gid - 1) % 255 : 1; 201 } 202 203 sk_sp<SkPDFFont> SkPDFFont::GetFontResource(SkPDFCanon* canon, 204 SkTypeface* face, 205 SkGlyphID glyphID) { 206 SkASSERT(canon); 207 SkASSERT(face); // All SkPDFDevice::internalDrawText ensures this. 208 const SkAdvancedTypefaceMetrics* fontMetrics = SkPDFFont::GetMetrics(face, canon); 209 SkASSERT(fontMetrics); // SkPDFDevice::internalDrawText ensures the typeface is good. 210 // GetMetrics only returns null to signify a bad typeface. 211 const SkAdvancedTypefaceMetrics& metrics = *fontMetrics; 212 SkAdvancedTypefaceMetrics::FontType type = SkPDFFont::FontType(metrics); 213 bool multibyte = SkPDFFont::IsMultiByte(type); 214 SkGlyphID subsetCode = multibyte ? 0 : first_nonzero_glyph_for_single_byte_encoding(glyphID); 215 uint64_t fontID = (SkTypeface::UniqueID(face) << 16) | subsetCode; 216 217 if (sk_sp<SkPDFFont>* found = canon->fFontMap.find(fontID)) { 218 SkDEBUGCODE(SkPDFFont* foundFont = found->get()); 219 SkASSERT(foundFont && multibyte == foundFont->multiByteGlyphs()); 220 return *found; 221 } 222 223 sk_sp<SkTypeface> typeface(sk_ref_sp(face)); 224 SkASSERT(typeface); 225 226 SkGlyphID lastGlyph = SkToU16(typeface->countGlyphs() - 1); 227 228 // should be caught by SkPDFDevice::internalDrawText 229 SkASSERT(glyphID <= lastGlyph); 230 231 SkGlyphID firstNonZeroGlyph; 232 if (multibyte) { 233 firstNonZeroGlyph = 1; 234 } else { 235 firstNonZeroGlyph = subsetCode; 236 lastGlyph = SkToU16(SkTMin<int>((int)lastGlyph, 254 + (int)subsetCode)); 237 } 238 SkPDFFont::Info info = {std::move(typeface), firstNonZeroGlyph, lastGlyph, type}; 239 sk_sp<SkPDFFont> font; 240 switch (type) { 241 case SkAdvancedTypefaceMetrics::kType1CID_Font: 242 case SkAdvancedTypefaceMetrics::kTrueType_Font: 243 SkASSERT(multibyte); 244 font = sk_make_sp<SkPDFType0Font>(std::move(info), metrics); 245 break; 246 case SkAdvancedTypefaceMetrics::kType1_Font: 247 SkASSERT(!multibyte); 248 font = sk_make_sp<SkPDFType1Font>(std::move(info), metrics, canon); 249 break; 250 default: 251 SkASSERT(!multibyte); 252 // Type3 is our fallback font. 253 font = sk_make_sp<SkPDFType3Font>(std::move(info), metrics); 254 break; 255 } 256 canon->fFontMap.set(fontID, font); 257 return font; 258 } 259 260 SkPDFFont::SkPDFFont(SkPDFFont::Info info) 261 : SkPDFDict("Font") 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) { 267 SkASSERT(fTypeface); 268 } 269 270 static void add_common_font_descriptor_entries(SkPDFDict* descriptor, 271 const SkAdvancedTypefaceMetrics& metrics, 272 uint16_t emSize, 273 int16_t defaultWidth) { 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( 286 "FontBBox", makeFontBBox(metrics.fBBox, emSize)); 287 if (defaultWidth > 0) { 288 descriptor->insertScalar("MissingWidth", 289 scaleFromFontUnits(defaultWidth, emSize)); 290 } 291 } 292 293 /////////////////////////////////////////////////////////////////////////////// 294 // class SkPDFType0Font 295 /////////////////////////////////////////////////////////////////////////////// 296 297 SkPDFType0Font::SkPDFType0Font( 298 SkPDFFont::Info info, 299 const SkAdvancedTypefaceMetrics& metrics) 300 : SkPDFFont(std::move(info)) { 301 SkDEBUGCODE(fPopulated = false); 302 } 303 304 SkPDFType0Font::~SkPDFType0Font() {} 305 306 307 #ifdef SK_DEBUG 308 void SkPDFType0Font::emitObject(SkWStream* stream, 309 const SkPDFObjNumMap& objNumMap) const { 310 SkASSERT(fPopulated); 311 return INHERITED::emitObject(stream, objNumMap); 312 } 313 #endif 314 315 #ifdef SK_PDF_USE_SFNTLY 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 = 324 [](const void*, void* ctx) { delete (SkStreamAsset*)ctx; }; 325 return SkData::MakeWithProc(base, size, proc, stream.release()); 326 } 327 return SkData::MakeFromStream(stream.get(), size); 328 } 329 330 static sk_sp<SkPDFStream> get_subset_font_stream( 331 std::unique_ptr<SkStreamAsset> fontAsset, 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); 342 343 unsigned char* subsetFont{nullptr}; 344 sk_sp<SkData> fontData(stream_to_data(std::move(fontAsset))); 345 #if defined(GOOGLE3) 346 // TODO(halcanary): update GOOGLE3 to newest version of Sfntly. 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(); 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)); 375 subsetStream->dict()->insertInt("Length1", subsetFontSize); 376 return subsetStream; 377 } 378 #endif // SK_PDF_USE_SFNTLY 379 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; 386 SkASSERT(can_embed(metrics)); 387 SkAdvancedTypefaceMetrics::FontType type = this->getType(); 388 SkTypeface* face = this->typeface(); 389 SkASSERT(face); 390 391 auto descriptor = sk_make_sp<SkPDFDict>("FontDescriptor"); 392 uint16_t emSize = SkToU16(this->typeface()->getUnitsPerEm()); 393 add_common_font_descriptor_entries(descriptor.get(), metrics, emSize , 0); 394 395 int ttcIndex; 396 std::unique_ptr<SkStreamAsset> fontAsset(face->openStream(&ttcIndex)); 397 size_t fontSize = fontAsset ? fontAsset->getLength() : 0; 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 { 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; } 420 } 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; 426 } 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; 432 } 433 default: 434 SkASSERT(false); 435 } 436 } 437 438 auto newCIDFont = sk_make_sp<SkPDFDict>("Font"); 439 newCIDFont->insertObjRef("FontDescriptor", std::move(descriptor)); 440 newCIDFont->insertName("BaseFont", metrics.fFontName); 441 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); 452 } 453 auto sysInfo = sk_make_sp<SkPDFDict>(); 454 sysInfo->insertString("Registry", "Adobe"); 455 sysInfo->insertString("Ordering", "Identity"); 456 sysInfo->insertInt("Supplement", 0); 457 newCIDFont->insertObject("CIDSystemInfo", std::move(sysInfo)); 458 459 int16_t defaultWidth = 0; 460 { 461 int emSize; 462 SkAutoGlyphCache glyphCache = SkPDFFont::MakeVectorCache(face, &emSize); 463 sk_sp<SkPDFArray> widths = SkPDFMakeCIDGlyphWidthsArray( 464 glyphCache.get(), &this->glyphUsage(), SkToS16(emSize), &defaultWidth); 465 if (widths && widths->size() > 0) { 466 newCIDFont->insertObject("W", std::move(widths)); 467 } 468 newCIDFont->insertScalar( 469 "DW", scaleFromFontUnits(defaultWidth, SkToS16(emSize))); 470 } 471 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)); 480 481 if (metrics.fGlyphToUnicode.count() > 0) { 482 this->insertObjRef("ToUnicode", 483 SkPDFMakeToUnicodeCmap(metrics.fGlyphToUnicode, 484 &this->glyphUsage(), 485 multiByteGlyphs(), 486 firstGlyphID(), 487 lastGlyphID())); 488 } 489 SkDEBUGCODE(fPopulated = true); 490 return; 491 } 492 493 /////////////////////////////////////////////////////////////////////////////// 494 // class SkPDFType1Font 495 /////////////////////////////////////////////////////////////////////////////// 496 497 static sk_sp<SkPDFDict> make_type1_font_descriptor( 498 SkTypeface* typeface, 499 const SkAdvancedTypefaceMetrics& info) { 500 auto descriptor = sk_make_sp<SkPDFDict>("FontDescriptor"); 501 uint16_t emSize = SkToU16(typeface->getUnitsPerEm()); 502 add_common_font_descriptor_entries(descriptor.get(), info, emSize, 0); 503 if (!can_embed(info)) { 504 return descriptor; 505 } 506 int ttcIndex; 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; 510 std::unique_ptr<SkStreamAsset> rawFontData(typeface->openStream(&ttcIndex)); 511 sk_sp<SkData> fontData = SkPDFConvertType1FontStream(std::move(rawFontData), 512 &header, &data, &trailer); 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)); 519 } 520 return descriptor; 521 } 522 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); 530 531 // glyphCount not including glyph 0 532 unsigned glyphCount = 1 + lastGlyphID - firstGlyphID; 533 SkASSERT(glyphCount > 0 && glyphCount <= 255); 534 font->insertInt("FirstChar", (size_t)0); 535 font->insertInt("LastChar", (size_t)glyphCount); 536 { 537 int emSize; 538 SkAutoGlyphCache glyphCache = SkPDFFont::MakeVectorCache(typeface, &emSize); 539 auto widths = sk_make_sp<SkPDFArray>(); 540 SkScalar advance = glyphCache->getGlyphIDAdvance(0).fAdvanceX; 541 widths->appendScalar(from_font_units(advance, SkToU16(emSize))); 542 for (unsigned gID = firstGlyphID; gID <= lastGlyphID; gID++) { 543 advance = glyphCache->getGlyphIDAdvance(gID).fAdvanceX; 544 widths->appendScalar(from_font_units(advance, SkToU16(emSize))); 545 } 546 font->insertObject("Widths", std::move(widths)); 547 } 548 auto encDiffs = sk_make_sp<SkPDFArray>(); 549 encDiffs->reserve(lastGlyphID - firstGlyphID + 3); 550 encDiffs->appendInt(0); 551 const SkTArray<SkString>& glyphNames = info.fGlyphNames; 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); 559 } 560 561 auto encoding = sk_make_sp<SkPDFDict>("Encoding"); 562 encoding->insertObject("Differences", std::move(encDiffs)); 563 font->insertObject("Encoding", std::move(encoding)); 564 } 565 566 SkPDFType1Font::SkPDFType1Font(SkPDFFont::Info info, 567 const SkAdvancedTypefaceMetrics& metrics, 568 SkPDFCanon* canon) 569 : SkPDFFont(std::move(info)) 570 { 571 SkFontID fontID = this->typeface()->uniqueID(); 572 sk_sp<SkPDFDict> fontDescriptor; 573 if (sk_sp<SkPDFDict>* ptr = canon->fFontDescriptors.find(fontID)) { 574 fontDescriptor = *ptr; 575 } else { 576 fontDescriptor = make_type1_font_descriptor(this->typeface(), metrics); 577 canon->fFontDescriptors.set(fontID, fontDescriptor); 578 } 579 this->insertObjRef("FontDescriptor", std::move(fontDescriptor)); 580 // TODO(halcanary): subset this (advances and names). 581 populate_type_1_font(this, metrics, this->typeface(), 582 this->firstGlyphID(), this->lastGlyphID()); 583 } 584 585 /////////////////////////////////////////////////////////////////////////////// 586 // class SkPDFType3Font 587 /////////////////////////////////////////////////////////////////////////////// 588 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 }; 617 } 618 619 static void add_type3_font_info(SkPDFCanon* canon, 620 SkPDFDict* font, 621 SkTypeface* typeface, 622 const SkBitSet& subset, 623 SkGlyphID firstGlyphID, 624 SkGlyphID lastGlyphID) { 625 const SkAdvancedTypefaceMetrics* metrics = SkPDFFont::GetMetrics(typeface, canon); 626 SkASSERT(lastGlyphID >= firstGlyphID); 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 } 632 int unitsPerEm; 633 SkAutoGlyphCache cache = SkPDFFont::MakeVectorCache(typeface, &unitsPerEm); 634 SkScalar emSize = (SkScalar)unitsPerEm; 635 font->insertName("Subtype", "Type3"); 636 // Flip about the x-axis and scale by 1/emSize. 637 SkMatrix fontMatrix; 638 fontMatrix.setScale(SkScalarInvert(emSize), -SkScalarInvert(emSize)); 639 font->insertObject("FontMatrix", SkPDFUtils::MatrixToArray(fontMatrix)); 640 641 auto charProcs = sk_make_sp<SkPDFDict>(); 642 auto encoding = sk_make_sp<SkPDFDict>("Encoding"); 643 644 auto encDiffs = sk_make_sp<SkPDFArray>(); 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 653 654 auto widthArray = sk_make_sp<SkPDFArray>(); 655 widthArray->reserve(glyphCount); 656 657 SkIRect bbox = SkIRect::MakeEmpty(); 658 659 sk_sp<SkPDFStream> emptyStream; 660 for (SkGlyphID gID : SingleByteGlyphIdIterator(firstGlyphID, lastGlyphID)) { 661 bool skipGlyph = gID != 0 && !subset.has(gID); 662 SkString characterName; 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 } 693 } 694 encDiffs->appendName(characterName.c_str()); 695 widthArray->appendScalar(advance); 696 } 697 698 encoding->insertObject("Differences", std::move(encDiffs)); 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"); 714 if (metrics && metrics->fGlyphToUnicode.count() > 0) { 715 font->insertObjRef("ToUnicode", 716 SkPDFMakeToUnicodeCmap(metrics->fGlyphToUnicode, 717 &subset, 718 false, 719 firstGlyphID, 720 lastGlyphID)); 721 } 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)); 732 font->insertObject("Widths", std::move(widthArray)); 733 font->insertObject("Encoding", std::move(encoding)); 734 font->insertObject("CharProcs", std::move(charProcs)); 735 } 736 737 SkPDFType3Font::SkPDFType3Font(SkPDFFont::Info info, 738 const SkAdvancedTypefaceMetrics& metrics) 739 : SkPDFFont(std::move(info)) {} 740 741 void SkPDFType3Font::getFontSubset(SkPDFCanon* canon) { 742 add_type3_font_info(canon, this, this->typeface(), this->glyphUsage(), 743 this->firstGlyphID(), this->lastGlyphID()); 744 } 745 746 //////////////////////////////////////////////////////////////////////////////// 747 748 bool SkPDFFont::CanEmbedTypeface(SkTypeface* typeface, SkPDFCanon* canon) { 749 const SkAdvancedTypefaceMetrics* metrics = SkPDFFont::GetMetrics(typeface, canon); 750 return metrics && can_embed(*metrics); 751 } 752 753 void SkPDFFont::drop() { 754 fTypeface = nullptr; 755 fGlyphUsage.~SkBitSet(); 756 new (&fGlyphUsage) SkBitSet(0); 757 this->SkPDFDict::drop(); 758 } 759