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

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

Issue 1033543002: SKPDF: refactor pdfcatalog and pdfdocument (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: 2015-03-25 (Wednesday) 14:17:42 EDT Created 5 years, 9 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/SkPDFCatalog.cpp ('k') | src/pdf/SkPDFPage.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 /* 2 /*
3 * Copyright 2011 Google Inc. 3 * Copyright 2011 Google Inc.
4 * 4 *
5 * Use of this source code is governed by a BSD-style license that can be 5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file. 6 * found in the LICENSE file.
7 */ 7 */
8 8
9 9
10 #include "SkPDFCatalog.h" 10 #include "SkPDFCatalog.h"
11 #include "SkPDFDevice.h" 11 #include "SkPDFDevice.h"
12 #include "SkPDFDocument.h" 12 #include "SkPDFDocument.h"
13 #include "SkPDFFont.h" 13 #include "SkPDFFont.h"
14 #include "SkPDFPage.h" 14 #include "SkPDFPage.h"
15 #include "SkPDFTypes.h" 15 #include "SkPDFTypes.h"
16 #include "SkStream.h" 16 #include "SkStream.h"
17 17
18 18
19 static void perform_font_subsetting(SkPDFCatalog* catalog, 19 static void perform_font_subsetting(SkPDFCatalog* catalog,
20 const SkTDArray<SkPDFPage*>& pages, 20 const SkTDArray<SkPDFPage*>& pages) {
21 SkTDArray<SkPDFObject*>* substitutes) {
22 SkASSERT(catalog); 21 SkASSERT(catalog);
23 SkASSERT(substitutes);
24 22
25 SkPDFGlyphSetMap usage; 23 SkPDFGlyphSetMap usage;
26 for (int i = 0; i < pages.count(); ++i) { 24 for (int i = 0; i < pages.count(); ++i) {
27 usage.merge(pages[i]->getFontGlyphUsage()); 25 usage.merge(pages[i]->getFontGlyphUsage());
28 } 26 }
29 SkPDFGlyphSetMap::F2BIter iterator(usage); 27 SkPDFGlyphSetMap::F2BIter iterator(usage);
30 const SkPDFGlyphSetMap::FontGlyphSetPair* entry = iterator.next(); 28 const SkPDFGlyphSetMap::FontGlyphSetPair* entry = iterator.next();
31 while (entry) { 29 while (entry) {
32 SkPDFFont* subsetFont = 30 SkAutoTUnref<SkPDFFont> subsetFont(
33 entry->fFont->getFontSubset(entry->fGlyphSet); 31 entry->fFont->getFontSubset(entry->fGlyphSet));
34 if (subsetFont) { 32 if (subsetFont) {
35 catalog->setSubstitute(entry->fFont, subsetFont); 33 catalog->setSubstitute(entry->fFont, subsetFont.get());
36 substitutes->push(subsetFont); // Transfer ownership to substitutes
37 } 34 }
38 entry = iterator.next(); 35 entry = iterator.next();
39 } 36 }
40 } 37 }
41 38
42 static void emit_pdf_header(SkWStream* stream) { 39 static void emit_pdf_header(SkWStream* stream) {
43 stream->writeText("%PDF-1.4\n%"); 40 stream->writeText("%PDF-1.4\n%");
44 // The PDF spec recommends including a comment with four bytes, all 41 // The PDF spec recommends including a comment with four bytes, all
45 // with their high bits set. This is "Skia" with the high bits set. 42 // with their high bits set. This is "Skia" with the high bits set.
46 stream->write32(0xD3EBE9E1); 43 stream->write32(0xD3EBE9E1);
(...skipping 18 matching lines...) Expand all
65 stream->writeText("\n%%EOF"); 62 stream->writeText("\n%%EOF");
66 } 63 }
67 64
68 bool SkPDFDocument::EmitPDF(const SkTDArray<const SkPDFDevice*>& pageDevices, 65 bool SkPDFDocument::EmitPDF(const SkTDArray<const SkPDFDevice*>& pageDevices,
69 SkWStream* stream) { 66 SkWStream* stream) {
70 if (pageDevices.isEmpty()) { 67 if (pageDevices.isEmpty()) {
71 return false; 68 return false;
72 } 69 }
73 70
74 SkTDArray<SkPDFPage*> pages; 71 SkTDArray<SkPDFPage*> pages;
72 SkAutoTUnref<SkPDFDict> dests(SkNEW(SkPDFDict));
73
75 for (int i = 0; i < pageDevices.count(); i++) { 74 for (int i = 0; i < pageDevices.count(); i++) {
76 SkASSERT(pageDevices[i]); 75 SkASSERT(pageDevices[i]);
77 SkASSERT(i == 0 || 76 SkASSERT(i == 0 ||
78 pageDevices[i - 1]->getCanon() == pageDevices[i]->getCanon()); 77 pageDevices[i - 1]->getCanon() == pageDevices[i]->getCanon());
79 // Reference from new passed to pages. 78 // Reference from new passed to pages.
80 pages.push(SkNEW_ARGS(SkPDFPage, (pageDevices[i]))); 79 SkAutoTUnref<SkPDFPage> page(SkNEW_ARGS(SkPDFPage, (pageDevices[i])));
80 page->finalizePage();
81 page->appendDestinations(dests);
82 pages.push(page.detach());
81 } 83 }
82 SkPDFCatalog catalog; 84 SkPDFCatalog catalog;
83 85
84 SkTDArray<SkPDFDict*> pageTree; 86 SkTDArray<SkPDFDict*> pageTree;
85 SkAutoTUnref<SkPDFDict> docCatalog(SkNEW_ARGS(SkPDFDict, ("Catalog"))); 87 SkAutoTUnref<SkPDFDict> docCatalog(SkNEW_ARGS(SkPDFDict, ("Catalog")));
86 SkTSet<SkPDFObject*> firstPageResources;
87 SkTSet<SkPDFObject*> otherPageResources;
88 SkTDArray<SkPDFObject*> substitutes;
89 catalog.addObject(docCatalog.get(), true);
90 88
91 SkPDFDict* pageTreeRoot; 89 SkPDFDict* pageTreeRoot;
92 SkPDFPage::GeneratePageTree(pages, &catalog, &pageTree, &pageTreeRoot); 90 SkPDFPage::GeneratePageTree(pages, &pageTree, &pageTreeRoot);
91
93 docCatalog->insert("Pages", new SkPDFObjRef(pageTreeRoot))->unref(); 92 docCatalog->insert("Pages", new SkPDFObjRef(pageTreeRoot))->unref();
94 93
95 /* TODO(vandebo): output intent 94 /* TODO(vandebo): output intent
96 SkAutoTUnref<SkPDFDict> outputIntent = new SkPDFDict("OutputIntent"); 95 SkAutoTUnref<SkPDFDict> outputIntent = new SkPDFDict("OutputIntent");
97 outputIntent->insert("S", new SkPDFName("GTS_PDFA1"))->unref(); 96 outputIntent->insert("S", new SkPDFName("GTS_PDFA1"))->unref();
98 outputIntent->insert("OutputConditionIdentifier", 97 outputIntent->insert("OutputConditionIdentifier",
99 new SkPDFString("sRGB"))->unref(); 98 new SkPDFString("sRGB"))->unref();
100 SkAutoTUnref<SkPDFArray> intentArray = new SkPDFArray; 99 SkAutoTUnref<SkPDFArray> intentArray = new SkPDFArray;
101 intentArray->append(outputIntent.get()); 100 intentArray->append(outputIntent.get());
102 docCatalog->insert("OutputIntent", intentArray.get()); 101 docCatalog->insert("OutputIntent", intentArray.get());
103 */ 102 */
104 103
105 SkAutoTUnref<SkPDFDict> dests(SkNEW(SkPDFDict));
106
107 bool firstPage = true;
108 /* The references returned in newResources are transfered to
109 * firstPageResources or otherPageResources depending on firstPage and
110 * knownResources doesn't have a reference but just relies on the other
111 * two sets to maintain a reference.
112 */
113 SkTSet<SkPDFObject*> knownResources;
114
115 // mergeInto returns the number of duplicates.
116 // If there are duplicates, there is a bug and we mess ref counting.
117 SkDEBUGCODE(int duplicates = ) knownResources.mergeInto(firstPageResources);
118 SkASSERT(duplicates == 0);
119
120 for (int i = 0; i < pages.count(); i++) {
121 if (i == 1) {
122 firstPage = false;
123 SkDEBUGCODE(duplicates = )
124 knownResources.mergeInto(otherPageResources);
125 }
126 SkTSet<SkPDFObject*> newResources;
127 pages[i]->finalizePage(&catalog, firstPage, knownResources,
128 &newResources);
129 for (int j = 0; j < newResources.count(); j++) {
130 catalog.addObject(newResources[i], firstPage);
131 }
132 if (firstPage) {
133 SkDEBUGCODE(duplicates = )
134 firstPageResources.mergeInto(newResources);
135 } else {
136 SkDEBUGCODE(duplicates = )
137 otherPageResources.mergeInto(newResources);
138 }
139 SkASSERT(duplicates == 0);
140
141 SkDEBUGCODE(duplicates = ) knownResources.mergeInto(newResources);
142 SkASSERT(duplicates == 0);
143
144 pages[i]->appendDestinations(dests);
145 }
146
147 if (dests->size() > 0) { 104 if (dests->size() > 0) {
148 SkPDFDict* raw_dests = dests.get(); 105 docCatalog->insert("Dests", SkNEW_ARGS(SkPDFObjRef, (dests.get())))
149 firstPageResources.add(dests.detach()); // Transfer ownership.
150 catalog.addObject(raw_dests, true /* onFirstPage */);
151 docCatalog->insert("Dests", SkNEW_ARGS(SkPDFObjRef, (raw_dests)))
152 ->unref(); 106 ->unref();
153 } 107 }
154 108
155 // Build font subsetting info before proceeding. 109 // Build font subsetting info before proceeding.
156 perform_font_subsetting(&catalog, pages, &substitutes); 110 perform_font_subsetting(&catalog, pages);
157 111
158 SkTSet<SkPDFObject*> resourceSet; 112 SkTSet<SkPDFObject*> resourceSet;
159 if (resourceSet.add(docCatalog.get())) { 113 if (resourceSet.add(docCatalog.get())) {
160 docCatalog->addResources(&resourceSet, &catalog); 114 docCatalog->addResources(&resourceSet, &catalog);
161 } 115 }
116 for (int i = 0; i < resourceSet.count(); ++i) {
117 SkAssertResult(catalog.addObject(resourceSet[i]));
118 }
119
162 size_t baseOffset = SkToOffT(stream->bytesWritten()); 120 size_t baseOffset = SkToOffT(stream->bytesWritten());
163 emit_pdf_header(stream); 121 emit_pdf_header(stream);
122 SkTDArray<int32_t> offsets;
164 for (int i = 0; i < resourceSet.count(); ++i) { 123 for (int i = 0; i < resourceSet.count(); ++i) {
165 SkPDFObject* object = resourceSet[i]; 124 SkPDFObject* object = resourceSet[i];
166 catalog.setFileOffset(object, 125 offsets.push(SkToS32(stream->bytesWritten() - baseOffset));
167 SkToOffT(stream->bytesWritten() - baseOffset));
168 SkASSERT(object == catalog.getSubstituteObject(object)); 126 SkASSERT(object == catalog.getSubstituteObject(object));
169 stream->writeDecAsText(catalog.getObjectNumber(object)); 127 SkASSERT(catalog.getObjectNumber(object) == i + 1);
128 stream->writeDecAsText(i + 1);
170 stream->writeText(" 0 obj\n"); // Generation number is always 0. 129 stream->writeText(" 0 obj\n"); // Generation number is always 0.
171 object->emitObject(stream, &catalog); 130 object->emitObject(stream, &catalog);
172 stream->writeText("\nendobj\n"); 131 stream->writeText("\nendobj\n");
173 } 132 }
174 int32_t xRefFileOffset = SkToS32(stream->bytesWritten() - baseOffset); 133 int32_t xRefFileOffset = SkToS32(stream->bytesWritten() - baseOffset);
175 int64_t objCount = catalog.emitXrefTable(stream, pages.count() > 1);
176 134
135 int32_t objCount = SkToS32(offsets.count() + 1);
136
137 stream->writeText("xref\n0 ");
138 stream->writeDecAsText(objCount + 1);
139 stream->writeText("\n0000000000 65535 f \n");
140 for (int i = 0; i < offsets.count(); i++) {
141 SkASSERT(offsets[i] > 0);
142 stream->writeBigDecAsText(offsets[i], 10);
143 stream->writeText(" 00000 n \n");
144 }
177 emit_pdf_footer(stream, &catalog, docCatalog.get(), objCount, 145 emit_pdf_footer(stream, &catalog, docCatalog.get(), objCount,
178 xRefFileOffset); 146 xRefFileOffset);
179 147
180 // The page tree has both child and parent pointers, so it creates a 148 // The page tree has both child and parent pointers, so it creates a
181 // reference cycle. We must clear that cycle to properly reclaim memory. 149 // reference cycle. We must clear that cycle to properly reclaim memory.
182 for (int i = 0; i < pageTree.count(); i++) { 150 for (int i = 0; i < pageTree.count(); i++) {
183 pageTree[i]->clear(); 151 pageTree[i]->clear();
184 } 152 }
185 pageTree.safeUnrefAll(); 153 pageTree.safeUnrefAll();
186 pages.unrefAll(); 154 pages.unrefAll();
187
188 firstPageResources.safeUnrefAll();
189 otherPageResources.safeUnrefAll();
190
191 substitutes.unrefAll();
192 docCatalog.reset(NULL);
193 return true; 155 return true;
194 } 156 }
195 157
196 // TODO(halcanary): expose notEmbeddableCount in SkDocument 158 // TODO(halcanary): expose notEmbeddableCount in SkDocument
197 void SkPDFDocument::GetCountOfFontTypes( 159 void SkPDFDocument::GetCountOfFontTypes(
198 const SkTDArray<SkPDFDevice*>& pageDevices, 160 const SkTDArray<SkPDFDevice*>& pageDevices,
199 int counts[SkAdvancedTypefaceMetrics::kOther_Font + 1], 161 int counts[SkAdvancedTypefaceMetrics::kOther_Font + 1],
200 int* notSubsettableCount, 162 int* notSubsettableCount,
201 int* notEmbeddableCount) { 163 int* notEmbeddableCount) {
202 sk_bzero(counts, sizeof(int) * 164 sk_bzero(counts, sizeof(int) *
(...skipping 20 matching lines...) Expand all
223 } 185 }
224 } 186 }
225 if (notSubsettableCount) { 187 if (notSubsettableCount) {
226 *notSubsettableCount = notSubsettable; 188 *notSubsettableCount = notSubsettable;
227 189
228 } 190 }
229 if (notEmbeddableCount) { 191 if (notEmbeddableCount) {
230 *notEmbeddableCount = notEmbeddable; 192 *notEmbeddableCount = notEmbeddable;
231 } 193 }
232 } 194 }
OLDNEW
« no previous file with comments | « src/pdf/SkPDFCatalog.cpp ('k') | src/pdf/SkPDFPage.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698