Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(443)

Side by Side Diff: src/pdf/SkPDFDocument.cpp

Issue 2253283004: SkPDF: in-place font subsetting (Closed) Base URL: https://skia.googlesource.com/skia.git@SkPdfCacheMetrics
Patch Set: 2016-08-18 (Thursday) 16:02:16 EDT Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/pdf/SkPDFDocument.h ('k') | src/pdf/SkPDFFont.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 "SkPDFCanon.h" 8 #include "SkPDFCanon.h"
9 #include "SkPDFCanvas.h" 9 #include "SkPDFCanvas.h"
10 #include "SkPDFDevice.h" 10 #include "SkPDFDevice.h"
11 #include "SkPDFDocument.h" 11 #include "SkPDFDocument.h"
12 #include "SkPDFUtils.h" 12 #include "SkPDFUtils.h"
13 #include "SkStream.h" 13 #include "SkStream.h"
14 14
15 SkPDFObjectSerializer::SkPDFObjectSerializer() : fBaseOffset(0), fNextToBeSerial ized(0) {} 15 SkPDFObjectSerializer::SkPDFObjectSerializer() : fBaseOffset(0), fNextToBeSerial ized(0) {}
16 16
17 template <class T> static void renew(T* t) { t->~T(); new (t) T; } 17 template <class T> static void renew(T* t) { t->~T(); new (t) T; }
18 18
19 SkPDFObjectSerializer::~SkPDFObjectSerializer() { 19 SkPDFObjectSerializer::~SkPDFObjectSerializer() {
20 for (int i = 0; i < fObjNumMap.objects().count(); ++i) { 20 for (int i = 0; i < fObjNumMap.objects().count(); ++i) {
21 fObjNumMap.objects()[i]->drop(); 21 fObjNumMap.objects()[i]->drop();
22 } 22 }
23 } 23 }
24 24
25 void SkPDFObjectSerializer::addObjectRecursively(const sk_sp<SkPDFObject>& objec t) { 25 void SkPDFObjectSerializer::addObjectRecursively(const sk_sp<SkPDFObject>& objec t) {
26 fObjNumMap.addObjectRecursively(object.get(), fSubstituteMap); 26 fObjNumMap.addObjectRecursively(object.get());
27 } 27 }
28 28
29 #define SKPDF_MAGIC "\xD3\xEB\xE9\xE1" 29 #define SKPDF_MAGIC "\xD3\xEB\xE9\xE1"
30 #ifndef SK_BUILD_FOR_WIN32 30 #ifndef SK_BUILD_FOR_WIN32
31 static_assert((SKPDF_MAGIC[0] & 0x7F) == "Skia"[0], ""); 31 static_assert((SKPDF_MAGIC[0] & 0x7F) == "Skia"[0], "");
32 static_assert((SKPDF_MAGIC[1] & 0x7F) == "Skia"[1], ""); 32 static_assert((SKPDF_MAGIC[1] & 0x7F) == "Skia"[1], "");
33 static_assert((SKPDF_MAGIC[2] & 0x7F) == "Skia"[2], ""); 33 static_assert((SKPDF_MAGIC[2] & 0x7F) == "Skia"[2], "");
34 static_assert((SKPDF_MAGIC[3] & 0x7F) == "Skia"[3], ""); 34 static_assert((SKPDF_MAGIC[3] & 0x7F) == "Skia"[3], "");
35 #endif 35 #endif
36 void SkPDFObjectSerializer::serializeHeader(SkWStream* wStream, 36 void SkPDFObjectSerializer::serializeHeader(SkWStream* wStream,
(...skipping 14 matching lines...) Expand all
51 void SkPDFObjectSerializer::serializeObjects(SkWStream* wStream) { 51 void SkPDFObjectSerializer::serializeObjects(SkWStream* wStream) {
52 const SkTArray<sk_sp<SkPDFObject>>& objects = fObjNumMap.objects(); 52 const SkTArray<sk_sp<SkPDFObject>>& objects = fObjNumMap.objects();
53 while (fNextToBeSerialized < objects.count()) { 53 while (fNextToBeSerialized < objects.count()) {
54 SkPDFObject* object = objects[fNextToBeSerialized].get(); 54 SkPDFObject* object = objects[fNextToBeSerialized].get();
55 int32_t index = fNextToBeSerialized + 1; // Skip object 0. 55 int32_t index = fNextToBeSerialized + 1; // Skip object 0.
56 // "The first entry in the [XREF] table (object number 0) is 56 // "The first entry in the [XREF] table (object number 0) is
57 // always free and has a generation number of 65,535; it is 57 // always free and has a generation number of 65,535; it is
58 // the head of the linked list of free objects." 58 // the head of the linked list of free objects."
59 SkASSERT(fOffsets.count() == fNextToBeSerialized); 59 SkASSERT(fOffsets.count() == fNextToBeSerialized);
60 fOffsets.push(this->offset(wStream)); 60 fOffsets.push(this->offset(wStream));
61 SkASSERT(object == fSubstituteMap.getSubstitute(object));
62 wStream->writeDecAsText(index); 61 wStream->writeDecAsText(index);
63 wStream->writeText(" 0 obj\n"); // Generation number is always 0. 62 wStream->writeText(" 0 obj\n"); // Generation number is always 0.
64 object->emitObject(wStream, fObjNumMap, fSubstituteMap); 63 object->emitObject(wStream, fObjNumMap);
65 wStream->writeText("\nendobj\n"); 64 wStream->writeText("\nendobj\n");
66 object->drop(); 65 object->drop();
67 ++fNextToBeSerialized; 66 ++fNextToBeSerialized;
68 } 67 }
69 } 68 }
70 69
71 // Xref table and footer 70 // Xref table and footer
72 void SkPDFObjectSerializer::serializeFooter(SkWStream* wStream, 71 void SkPDFObjectSerializer::serializeFooter(SkWStream* wStream,
73 const sk_sp<SkPDFObject> docCatalog, 72 const sk_sp<SkPDFObject> docCatalog,
74 sk_sp<SkPDFObject> id) { 73 sk_sp<SkPDFObject> id) {
(...skipping 11 matching lines...) Expand all
86 SkPDFDict trailerDict; 85 SkPDFDict trailerDict;
87 trailerDict.insertInt("Size", objCount); 86 trailerDict.insertInt("Size", objCount);
88 SkASSERT(docCatalog); 87 SkASSERT(docCatalog);
89 trailerDict.insertObjRef("Root", docCatalog); 88 trailerDict.insertObjRef("Root", docCatalog);
90 SkASSERT(fInfoDict); 89 SkASSERT(fInfoDict);
91 trailerDict.insertObjRef("Info", std::move(fInfoDict)); 90 trailerDict.insertObjRef("Info", std::move(fInfoDict));
92 if (id) { 91 if (id) {
93 trailerDict.insertObject("ID", std::move(id)); 92 trailerDict.insertObject("ID", std::move(id));
94 } 93 }
95 wStream->writeText("trailer\n"); 94 wStream->writeText("trailer\n");
96 trailerDict.emitObject(wStream, fObjNumMap, fSubstituteMap); 95 trailerDict.emitObject(wStream, fObjNumMap);
97 wStream->writeText("\nstartxref\n"); 96 wStream->writeText("\nstartxref\n");
98 wStream->writeBigDecAsText(xRefFileOffset); 97 wStream->writeBigDecAsText(xRefFileOffset);
99 wStream->writeText("\n%%EOF"); 98 wStream->writeText("\n%%EOF");
100 } 99 }
101 100
102 int32_t SkPDFObjectSerializer::offset(SkWStream* wStream) { 101 int32_t SkPDFObjectSerializer::offset(SkWStream* wStream) {
103 size_t offset = wStream->bytesWritten(); 102 size_t offset = wStream->bytesWritten();
104 SkASSERT(offset > fBaseOffset); 103 SkASSERT(offset > fBaseOffset);
105 return SkToS32(offset - fBaseOffset); 104 return SkToS32(offset - fBaseOffset);
106 } 105 }
(...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after
239 } 238 }
240 auto contentObject = sk_make_sp<SkPDFStream>(fPageDevice->content()); 239 auto contentObject = sk_make_sp<SkPDFStream>(fPageDevice->content());
241 this->serialize(contentObject); 240 this->serialize(contentObject);
242 page->insertObjRef("Contents", std::move(contentObject)); 241 page->insertObjRef("Contents", std::move(contentObject));
243 fPageDevice->appendDestinations(fDests.get(), page.get()); 242 fPageDevice->appendDestinations(fDests.get(), page.get());
244 fPages.emplace_back(std::move(page)); 243 fPages.emplace_back(std::move(page));
245 fPageDevice.reset(nullptr); 244 fPageDevice.reset(nullptr);
246 } 245 }
247 246
248 void SkPDFDocument::onAbort() { 247 void SkPDFDocument::onAbort() {
248 this->reset();
249 }
250
251 void SkPDFDocument::reset() {
249 fCanvas.reset(nullptr); 252 fCanvas.reset(nullptr);
250 fPages.reset(); 253 fPages.reset();
251 fCanon.reset(); 254 fCanon.reset();
252 renew(&fObjectSerializer); 255 renew(&fObjectSerializer);
253 renew(&fGlyphUsage); 256 fFonts.reset();
254 } 257 }
255 258
256 #ifdef SK_SUPPORT_LEGACY_DOCUMENT_API 259 #ifdef SK_SUPPORT_LEGACY_DOCUMENT_API
257 void SkPDFDocument::setMetadata(const SkDocument::Attribute info[], 260 void SkPDFDocument::setMetadata(const SkDocument::Attribute info[],
258 int infoCount, 261 int infoCount,
259 const SkTime::DateTime* creationDate, 262 const SkTime::DateTime* creationDate,
260 const SkTime::DateTime* modifiedDate) { 263 const SkTime::DateTime* modifiedDate) {
261 for (int i = 0; i < infoCount; ++i) { 264 for (int i = 0; i < infoCount; ++i) {
262 const SkDocument::Attribute& kv = info[i]; 265 const SkDocument::Attribute& kv = info[i];
263 SkPDFMetadata::SetMetadataByKey(kv.fKey, kv.fValue, &fMetadata); 266 SkPDFMetadata::SetMetadataByKey(kv.fKey, kv.fValue, &fMetadata);
(...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after
412 outputIntent->insertObjRef("DestOutputProfile", 415 outputIntent->insertObjRef("DestOutputProfile",
413 make_srgb_color_profile()); 416 make_srgb_color_profile());
414 auto intentArray = sk_make_sp<SkPDFArray>(); 417 auto intentArray = sk_make_sp<SkPDFArray>();
415 intentArray->appendObject(std::move(outputIntent)); 418 intentArray->appendObject(std::move(outputIntent));
416 return intentArray; 419 return intentArray;
417 } 420 }
418 421
419 bool SkPDFDocument::onClose(SkWStream* stream) { 422 bool SkPDFDocument::onClose(SkWStream* stream) {
420 SkASSERT(!fCanvas.get()); 423 SkASSERT(!fCanvas.get());
421 if (fPages.empty()) { 424 if (fPages.empty()) {
422 fPages.reset(); 425 this->reset();
423 fCanon.reset();
424 renew(&fObjectSerializer);
425 renew(&fGlyphUsage);
426 return false; 426 return false;
427 } 427 }
428 auto docCatalog = sk_make_sp<SkPDFDict>("Catalog"); 428 auto docCatalog = sk_make_sp<SkPDFDict>("Catalog");
429 if (fPDFA) { 429 if (fPDFA) {
430 SkASSERT(fXMP); 430 SkASSERT(fXMP);
431 docCatalog->insertObjRef("Metadata", fXMP); 431 docCatalog->insertObjRef("Metadata", fXMP);
432 // Don't specify OutputIntents if we are not in PDF/A mode since 432 // Don't specify OutputIntents if we are not in PDF/A mode since
433 // no one has ever asked for this feature. 433 // no one has ever asked for this feature.
434 docCatalog->insertObject("OutputIntents", make_srgb_output_intents()); 434 docCatalog->insertObject("OutputIntents", make_srgb_output_intents());
435 } 435 }
436 SkASSERT(!fPages.empty()); 436 SkASSERT(!fPages.empty());
437 docCatalog->insertObjRef("Pages", generate_page_tree(&fPages)); 437 docCatalog->insertObjRef("Pages", generate_page_tree(&fPages));
438 SkASSERT(fPages.empty()); 438 SkASSERT(fPages.empty());
439 439
440 if (fDests->size() > 0) { 440 if (fDests->size() > 0) {
441 docCatalog->insertObjRef("Dests", std::move(fDests)); 441 docCatalog->insertObjRef("Dests", std::move(fDests));
442 } 442 }
443 443
444 // Build font subsetting info before calling addObjectRecursively(). 444 // Build font subsetting info before calling addObjectRecursively().
445 for (const auto& entry : fGlyphUsage) { 445 SkPDFCanon* canon = &fCanon;
446 sk_sp<SkPDFObject> subsetFont = 446 fFonts.foreach([canon](SkPDFFont* p){ p->getFontSubset(canon); });
447 entry.fFont->getFontSubset(&fCanon, &entry.fGlyphSet);
448 if (subsetFont) {
449 fObjectSerializer.fSubstituteMap.setSubstitute(
450 entry.fFont, subsetFont.get());
451 }
452 }
453
454 fObjectSerializer.addObjectRecursively(docCatalog); 447 fObjectSerializer.addObjectRecursively(docCatalog);
455 fObjectSerializer.serializeObjects(this->getStream()); 448 fObjectSerializer.serializeObjects(this->getStream());
456 fObjectSerializer.serializeFooter(this->getStream(), docCatalog, fID); 449 fObjectSerializer.serializeFooter(this->getStream(), docCatalog, fID);
457 fCanon.reset(); 450 this->reset();
458 renew(&fObjectSerializer);
459 renew(&fGlyphUsage);
460 return true; 451 return true;
461 } 452 }
462 453
463 /////////////////////////////////////////////////////////////////////////////// 454 ///////////////////////////////////////////////////////////////////////////////
464 455
465 sk_sp<SkDocument> SkPDFMakeDocument(SkWStream* stream, 456 sk_sp<SkDocument> SkPDFMakeDocument(SkWStream* stream,
466 void (*proc)(SkWStream*, bool), 457 void (*proc)(SkWStream*, bool),
467 SkScalar dpi, 458 SkScalar dpi,
468 const SkDocument::PDFMetadata& metadata, 459 const SkDocument::PDFMetadata& metadata,
469 sk_sp<SkPixelSerializer> jpeg, 460 sk_sp<SkPixelSerializer> jpeg,
(...skipping 14 matching lines...) Expand all
484 } 475 }
485 476
486 sk_sp<SkDocument> SkDocument::MakePDF(SkWStream* stream, 477 sk_sp<SkDocument> SkDocument::MakePDF(SkWStream* stream,
487 SkScalar dpi, 478 SkScalar dpi,
488 const SkDocument::PDFMetadata& metadata, 479 const SkDocument::PDFMetadata& metadata,
489 sk_sp<SkPixelSerializer> jpegEncoder, 480 sk_sp<SkPixelSerializer> jpegEncoder,
490 bool pdfa) { 481 bool pdfa) {
491 return SkPDFMakeDocument(stream, nullptr, dpi, metadata, 482 return SkPDFMakeDocument(stream, nullptr, dpi, metadata,
492 std::move(jpegEncoder), pdfa); 483 std::move(jpegEncoder), pdfa);
493 } 484 }
OLDNEW
« no previous file with comments | « src/pdf/SkPDFDocument.h ('k') | src/pdf/SkPDFFont.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698