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