| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright 2011 Google Inc. | 2 * Copyright 2011 Google Inc. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
| 6 */ | 6 */ |
| 7 | 7 |
| 8 #include "SkData.h" | 8 #include "SkData.h" |
| 9 #include "SkGlyphCache.h" | 9 #include "SkGlyphCache.h" |
| 10 #include "SkPaint.h" | 10 #include "SkPaint.h" |
| (...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 129 * page/pdf device. c) in the document, retrieve the per font glyph usage | 129 * page/pdf device. c) in the document, retrieve the per font glyph usage |
| 130 * from each page and combine it and ask for a resource with that subset. | 130 * from each page and combine it and ask for a resource with that subset. |
| 131 */ | 131 */ |
| 132 | 132 |
| 133 SkPDFFont::~SkPDFFont() {} | 133 SkPDFFont::~SkPDFFont() {} |
| 134 | 134 |
| 135 static bool can_embed(const SkAdvancedTypefaceMetrics& metrics) { | 135 static bool can_embed(const SkAdvancedTypefaceMetrics& metrics) { |
| 136 return !SkToBool(metrics.fFlags & SkAdvancedTypefaceMetrics::kNotEmbeddable_
FontFlag); | 136 return !SkToBool(metrics.fFlags & SkAdvancedTypefaceMetrics::kNotEmbeddable_
FontFlag); |
| 137 } | 137 } |
| 138 | 138 |
| 139 #ifdef SK_PDF_USE_SFNTLY | |
| 140 static bool can_subset(const SkAdvancedTypefaceMetrics& metrics) { | |
| 141 return !SkToBool(metrics.fFlags & SkAdvancedTypefaceMetrics::kNotSubsettable
_FontFlag); | |
| 142 } | |
| 143 #endif | |
| 144 | |
| 145 const SkAdvancedTypefaceMetrics* SkPDFFont::GetMetrics(SkTypeface* typeface, | 139 const SkAdvancedTypefaceMetrics* SkPDFFont::GetMetrics(SkTypeface* typeface, |
| 146 SkPDFCanon* canon) { | 140 SkPDFCanon* canon) { |
| 147 SkASSERT(typeface); | 141 SkASSERT(typeface); |
| 148 SkFontID id = typeface->uniqueID(); | 142 SkFontID id = typeface->uniqueID(); |
| 149 if (SkAdvancedTypefaceMetrics** ptr = canon->fTypefaceMetrics.find(id)) { | 143 if (SkAdvancedTypefaceMetrics** ptr = canon->fTypefaceMetrics.find(id)) { |
| 150 return *ptr; | 144 return *ptr; |
| 151 } | 145 } |
| 152 int count = typeface->countGlyphs(); | 146 int count = typeface->countGlyphs(); |
| 153 if (count <= 0 || count > 1 + SK_MaxU16) { | 147 if (count <= 0 || count > 1 + SK_MaxU16) { |
| 154 // Cache nullptr to skip this check. Use SkSafeUnref(). | 148 // Cache nullptr to skip this check. Use SkSafeUnref(). |
| (...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 294 | 288 |
| 295 #ifdef SK_PDF_USE_SFNTLY | 289 #ifdef SK_PDF_USE_SFNTLY |
| 296 // if possible, make no copy. | 290 // if possible, make no copy. |
| 297 static sk_sp<SkData> stream_to_data(std::unique_ptr<SkStreamAsset> stream) { | 291 static sk_sp<SkData> stream_to_data(std::unique_ptr<SkStreamAsset> stream) { |
| 298 SkASSERT(stream); | 292 SkASSERT(stream); |
| 299 (void)stream->rewind(); | 293 (void)stream->rewind(); |
| 300 SkASSERT(stream->hasLength()); | 294 SkASSERT(stream->hasLength()); |
| 301 size_t size = stream->getLength(); | 295 size_t size = stream->getLength(); |
| 302 if (const void* base = stream->getMemoryBase()) { | 296 if (const void* base = stream->getMemoryBase()) { |
| 303 SkData::ReleaseProc proc = | 297 SkData::ReleaseProc proc = |
| 304 [](const void*, void* ctx) { delete (SkStream*)ctx; }; | 298 [](const void*, void* ctx) { delete (SkStreamAsset*)ctx; }; |
| 305 return SkData::MakeWithProc(base, size, proc, stream.release()); | 299 return SkData::MakeWithProc(base, size, proc, stream.release()); |
| 306 } | 300 } |
| 307 return SkData::MakeFromStream(stream.get(), size); | 301 return SkData::MakeFromStream(stream.get(), size); |
| 308 } | 302 } |
| 309 | 303 |
| 310 static sk_sp<SkPDFObject> get_subset_font_stream( | 304 static sk_sp<SkPDFStream> get_subset_font_stream( |
| 311 std::unique_ptr<SkStreamAsset> fontAsset, | 305 std::unique_ptr<SkStreamAsset> fontAsset, |
| 312 const SkTDArray<uint32_t>& subset, | 306 const SkBitSet& glyphUsage, |
| 313 const char* fontName) { | 307 const char* fontName, |
| 314 // sfntly requires unsigned int* to be passed in, | 308 int ttcIndex) { |
| 315 // as far as we know, unsigned int is equivalent | 309 // Generate glyph id array in format needed by sfntly. |
| 316 // to uint32_t on all platforms. | 310 // TODO(halcanary): sfntly should take a more compact format. |
| 317 static_assert(sizeof(unsigned) == sizeof(uint32_t), ""); | 311 SkTDArray<unsigned> subset; |
| 318 | 312 if (!glyphUsage.has(0)) { |
| 319 // TODO(halcanary): Use ttcIndex, not fontName. | 313 subset.push(0); // Always include glyph 0. |
| 314 } |
| 315 glyphUsage.exportTo(&subset); |
| 320 | 316 |
| 321 unsigned char* subsetFont{nullptr}; | 317 unsigned char* subsetFont{nullptr}; |
| 322 int subsetFontSize{0}; | 318 sk_sp<SkData> fontData(stream_to_data(std::move(fontAsset))); |
| 323 { | 319 #if defined(SK_BUILD_FOR_ANDROID_FRAMEWORK) || defined(GOOGLE3) |
| 324 sk_sp<SkData> fontData(stream_to_data(std::move(fontAsset))); | 320 // TODO(halcanary): update Android Framework to newest version of Sfntly. |
| 325 subsetFontSize = | 321 (void)ttcIndex; |
| 326 SfntlyWrapper::SubsetFont(fontName, | 322 int subsetFontSize = SfntlyWrapper::SubsetFont(fontName, |
| 327 fontData->bytes(), | 323 fontData->bytes(), |
| 328 fontData->size(), | 324 fontData->size(), |
| 329 subset.begin(), | 325 subset.begin(), |
| 330 subset.count(), | 326 subset.count(), |
| 331 &subsetFont); | 327 &subsetFont); |
| 332 } | 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(); |
| 333 SkASSERT(subsetFontSize > 0 || subsetFont == nullptr); | 339 SkASSERT(subsetFontSize > 0 || subsetFont == nullptr); |
| 334 if (subsetFontSize < 1) { | 340 if (subsetFontSize < 1) { |
| 335 return nullptr; | 341 return nullptr; |
| 336 } | 342 } |
| 337 SkASSERT(subsetFont != nullptr); | 343 SkASSERT(subsetFont != nullptr); |
| 338 auto subsetStream = sk_make_sp<SkPDFStream>( | 344 auto subsetStream = sk_make_sp<SkPDFStream>( |
| 339 SkData::MakeWithProc( | 345 SkData::MakeWithProc( |
| 340 subsetFont, subsetFontSize, | 346 subsetFont, subsetFontSize, |
| 341 [](const void* p, void*) { delete[] (unsigned char*)p; }, | 347 [](const void* p, void*) { delete[] (unsigned char*)p; }, |
| 342 nullptr)); | 348 nullptr)); |
| 343 subsetStream->dict()->insertInt("Length1", subsetFontSize); | 349 subsetStream->dict()->insertInt("Length1", subsetFontSize); |
| 344 return subsetStream; | 350 return subsetStream; |
| 345 } | 351 } |
| 346 #endif // SK_PDF_USE_SFNTLY | 352 #endif // SK_PDF_USE_SFNTLY |
| 347 | 353 |
| 348 void SkPDFType0Font::getFontSubset(SkPDFCanon* canon) { | 354 void SkPDFType0Font::getFontSubset(SkPDFCanon* canon) { |
| 349 const SkAdvancedTypefaceMetrics* metricsPtr = | 355 const SkAdvancedTypefaceMetrics* metricsPtr = |
| 350 SkPDFFont::GetMetrics(this->typeface(), canon); | 356 SkPDFFont::GetMetrics(this->typeface(), canon); |
| 351 SkASSERT(metricsPtr); | 357 SkASSERT(metricsPtr); |
| 352 if (!metricsPtr) { return; } | 358 if (!metricsPtr) { return; } |
| 353 const SkAdvancedTypefaceMetrics& metrics = *metricsPtr; | 359 const SkAdvancedTypefaceMetrics& metrics = *metricsPtr; |
| 354 SkASSERT(can_embed(metrics)); | 360 SkASSERT(can_embed(metrics)); |
| 355 SkAdvancedTypefaceMetrics::FontType type = this->getType(); | 361 SkAdvancedTypefaceMetrics::FontType type = this->getType(); |
| 356 SkTypeface* face = this->typeface(); | 362 SkTypeface* face = this->typeface(); |
| 357 SkASSERT(face); | 363 SkASSERT(face); |
| 358 const SkString& name = metrics.fFontName; | |
| 359 | 364 |
| 360 auto descriptor = sk_make_sp<SkPDFDict>("FontDescriptor"); | 365 auto descriptor = sk_make_sp<SkPDFDict>("FontDescriptor"); |
| 361 add_common_font_descriptor_entries(descriptor.get(), metrics, 0); | 366 add_common_font_descriptor_entries(descriptor.get(), metrics, 0); |
| 362 switch (type) { | 367 |
| 363 case SkAdvancedTypefaceMetrics::kTrueType_Font: { | 368 int ttcIndex; |
| 364 int ttcIndex; | 369 std::unique_ptr<SkStreamAsset> fontAsset(face->openStream(&ttcIndex)); |
| 365 std::unique_ptr<SkStreamAsset> fontAsset(face->openStream(&ttcIndex)
); | 370 size_t fontSize = fontAsset ? fontAsset->getLength() : 0; |
| 366 SkASSERT(fontAsset); | 371 SkASSERT(fontAsset); |
| 367 if (!fontAsset) { | 372 SkASSERT(fontSize > 0); |
| 368 return; | 373 if (fontSize > 0) { |
| 374 switch (type) { |
| 375 case SkAdvancedTypefaceMetrics::kTrueType_Font: { |
| 376 #ifdef SK_PDF_USE_SFNTLY |
| 377 if (!SkToBool(metrics.fFlags & |
| 378 SkAdvancedTypefaceMetrics::kNotSubsettable_FontFla
g)) { |
| 379 sk_sp<SkPDFStream> subsetStream = get_subset_font_stream( |
| 380 std::move(fontAsset), this->glyphUsage(), |
| 381 metrics.fFontName.c_str(), ttcIndex); |
| 382 if (subsetStream) { |
| 383 descriptor->insertObjRef("FontFile2", std::move(subsetSt
ream)); |
| 384 break; |
| 385 } |
| 386 // If subsetting fails, fall back to original font data. |
| 387 fontAsset.reset(face->openStream(&ttcIndex)); |
| 388 SkASSERT(fontAsset); |
| 389 SkASSERT(fontAsset->getLength() == fontSize); |
| 390 if (!fontAsset || fontAsset->getLength() == 0) { break; } |
| 391 } |
| 392 #endif // SK_PDF_USE_SFNTLY |
| 393 auto fontStream = sk_make_sp<SkPDFSharedStream>(std::move(fontAs
set)); |
| 394 fontStream->dict()->insertInt("Length1", fontSize); |
| 395 descriptor->insertObjRef("FontFile2", std::move(fontStream)); |
| 396 break; |
| 369 } | 397 } |
| 370 size_t fontSize = fontAsset->getLength(); | 398 case SkAdvancedTypefaceMetrics::kType1CID_Font: { |
| 371 SkASSERT(fontSize > 0); | 399 auto fontStream = sk_make_sp<SkPDFSharedStream>(std::move(fontAs
set)); |
| 372 if (fontSize == 0) { | 400 fontStream->dict()->insertName("Subtype", "CIDFontType0C"); |
| 373 return; | 401 descriptor->insertObjRef("FontFile3", std::move(fontStream)); |
| 402 break; |
| 374 } | 403 } |
| 375 | 404 default: |
| 376 #ifdef SK_PDF_USE_SFNTLY | 405 SkASSERT(false); |
| 377 if (can_subset(metrics)) { | |
| 378 // Generate glyph id array. in format needed by sfntly | |
| 379 SkTDArray<uint32_t> glyphIDs; | |
| 380 if (!this->glyphUsage().has(0)) { | |
| 381 glyphIDs.push(0); // Always include glyph 0. | |
| 382 } | |
| 383 this->glyphUsage().exportTo(&glyphIDs); | |
| 384 sk_sp<SkPDFObject> subsetStream = get_subset_font_stream( | |
| 385 std::move(fontAsset), glyphIDs, name.c_str()); | |
| 386 if (subsetStream) { | |
| 387 descriptor->insertObjRef("FontFile2", std::move(subsetStream
)); | |
| 388 break; | |
| 389 } | |
| 390 // If subsetting fails, fall back to original font data. | |
| 391 fontAsset.reset(face->openStream(&ttcIndex)); | |
| 392 } | |
| 393 #endif // SK_PDF_USE_SFNTLY | |
| 394 auto fontStream = sk_make_sp<SkPDFSharedStream>(std::move(fontAsset)
); | |
| 395 fontStream->dict()->insertInt("Length1", fontSize); | |
| 396 descriptor->insertObjRef("FontFile2", std::move(fontStream)); | |
| 397 break; | |
| 398 } | 406 } |
| 399 case SkAdvancedTypefaceMetrics::kType1CID_Font: { | |
| 400 std::unique_ptr<SkStreamAsset> fontData(face->openStream(nullptr)); | |
| 401 SkASSERT(fontData); | |
| 402 SkASSERT(fontData->getLength() > 0); | |
| 403 if (!fontData || 0 == fontData->getLength()) { | |
| 404 return; | |
| 405 } | |
| 406 auto fontStream = sk_make_sp<SkPDFSharedStream>(std::move(fontData))
; | |
| 407 fontStream->dict()->insertName("Subtype", "CIDFontType0c"); | |
| 408 descriptor->insertObjRef("FontFile3", std::move(fontStream)); | |
| 409 break; | |
| 410 } | |
| 411 default: | |
| 412 SkASSERT(false); | |
| 413 } | 407 } |
| 414 | 408 |
| 415 auto newCIDFont = sk_make_sp<SkPDFDict>("Font"); | 409 auto newCIDFont = sk_make_sp<SkPDFDict>("Font"); |
| 416 newCIDFont->insertObjRef("FontDescriptor", std::move(descriptor)); | 410 newCIDFont->insertObjRef("FontDescriptor", std::move(descriptor)); |
| 417 newCIDFont->insertName("BaseFont", name); | 411 newCIDFont->insertName("BaseFont", metrics.fFontName); |
| 418 | 412 |
| 419 if (type == SkAdvancedTypefaceMetrics::kType1CID_Font) { | 413 switch (type) { |
| 420 newCIDFont->insertName("Subtype", "CIDFontType0"); | 414 case SkAdvancedTypefaceMetrics::kType1CID_Font: |
| 421 } else if (type == SkAdvancedTypefaceMetrics::kTrueType_Font) { | 415 newCIDFont->insertName("Subtype", "CIDFontType0"); |
| 422 newCIDFont->insertName("Subtype", "CIDFontType2"); | 416 break; |
| 423 newCIDFont->insertName("CIDToGIDMap", "Identity"); | 417 case SkAdvancedTypefaceMetrics::kTrueType_Font: |
| 424 } else { | 418 newCIDFont->insertName("Subtype", "CIDFontType2"); |
| 425 SkASSERT(false); | 419 newCIDFont->insertName("CIDToGIDMap", "Identity"); |
| 420 break; |
| 421 default: |
| 422 SkASSERT(false); |
| 426 } | 423 } |
| 427 | |
| 428 auto sysInfo = sk_make_sp<SkPDFDict>(); | 424 auto sysInfo = sk_make_sp<SkPDFDict>(); |
| 429 sysInfo->insertString("Registry", "Adobe"); | 425 sysInfo->insertString("Registry", "Adobe"); |
| 430 sysInfo->insertString("Ordering", "Identity"); | 426 sysInfo->insertString("Ordering", "Identity"); |
| 431 sysInfo->insertInt("Supplement", 0); | 427 sysInfo->insertInt("Supplement", 0); |
| 432 newCIDFont->insertObject("CIDSystemInfo", std::move(sysInfo)); | 428 newCIDFont->insertObject("CIDSystemInfo", std::move(sysInfo)); |
| 433 | 429 |
| 434 uint16_t emSize = metrics.fEmSize; | 430 uint16_t emSize = metrics.fEmSize; |
| 435 int16_t defaultWidth = 0; | 431 int16_t defaultWidth = 0; |
| 436 { | 432 { |
| 437 SkAutoGlyphCache glyphCache = vector_cache(face); | 433 SkAutoGlyphCache glyphCache = vector_cache(face); |
| (...skipping 288 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 726 | 722 |
| 727 bool SkPDFFont::CanEmbedTypeface(SkTypeface* typeface, SkPDFCanon* canon) { | 723 bool SkPDFFont::CanEmbedTypeface(SkTypeface* typeface, SkPDFCanon* canon) { |
| 728 const SkAdvancedTypefaceMetrics* metrics = SkPDFFont::GetMetrics(typeface, c
anon); | 724 const SkAdvancedTypefaceMetrics* metrics = SkPDFFont::GetMetrics(typeface, c
anon); |
| 729 return metrics && can_embed(*metrics); | 725 return metrics && can_embed(*metrics); |
| 730 } | 726 } |
| 731 | 727 |
| 732 void SkPDFFont::drop() { | 728 void SkPDFFont::drop() { |
| 733 fTypeface = nullptr; | 729 fTypeface = nullptr; |
| 734 this->SkPDFDict::drop(); | 730 this->SkPDFDict::drop(); |
| 735 } | 731 } |
| OLD | NEW |