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 |