OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2013 Google Inc. | 2 * Copyright 2013 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 "podofo.h" | |
9 #include "SkPdfHeaders_autogen.h" | 8 #include "SkPdfHeaders_autogen.h" |
10 #include "SkPdfPodofoMapper_autogen.h" | 9 #include "SkPdfMapper_autogen.h" |
11 | 10 |
12 #ifndef SkPdfParser_DEFINED | 11 #ifndef SkPdfParser_DEFINED |
13 #define SkPdfParser_DEFINED | 12 #define SkPdfParser_DEFINED |
14 | 13 |
15 | 14 #include "SkPdfBasics.h" |
16 enum SkPdfTokenType { | 15 #include "SkPdfPodofoTokenizer.h" |
17 kKeyword_TokenType, | |
18 kObject_TokenType, | |
19 kImageData_TokenType, // TODO(edisonn): inline images seem to work without
it | |
20 }; | |
21 | |
22 struct PdfToken { | |
23 const char* fKeyword; | |
24 SkPdfObject* fObject; | |
25 SkPdfTokenType fType; | |
26 | |
27 PdfToken() : fKeyword(NULL), fObject(NULL) {} | |
28 }; | |
29 | |
30 class SkPdfTokenizer { | |
31 PdfMemDocument* fDoc; | |
32 PdfContentsTokenizer* fTokenizer; | |
33 | |
34 char* fUncompressedStream; | |
35 pdf_long fUncompressedStreamLength; | |
36 | |
37 bool fEmpty; | |
38 bool fHasPutBack; | |
39 PdfToken fPutBack; | |
40 | |
41 public: | |
42 SkPdfTokenizer(PdfMemDocument* doc = NULL, PdfContentsTokenizer* tokenizer =
NULL) : fDoc(doc), fTokenizer(tokenizer), fUncompressedStream(NULL), fUncompres
sedStreamLength(0), fEmpty(false), fHasPutBack(false) {} | |
43 SkPdfTokenizer(const SkPdfObject* objWithStream) : fDoc(NULL), fTokenizer(NU
LL), fEmpty(false), fHasPutBack(false) { | |
44 fUncompressedStream = NULL; | |
45 fUncompressedStreamLength = 0; | |
46 | |
47 fDoc = NULL; | |
48 | |
49 | |
50 try { | |
51 objWithStream->podofo()->GetStream()->GetFilteredCopy(&fUncompressed
Stream, &fUncompressedStreamLength); | |
52 if (fUncompressedStream != NULL && fUncompressedStreamLength != 0) { | |
53 fTokenizer = new PdfContentsTokenizer(fUncompressedStream, fUnco
mpressedStreamLength); | |
54 } else { | |
55 fEmpty = true; | |
56 } | |
57 } catch (PdfError& e) { | |
58 fEmpty = true; | |
59 } | |
60 | |
61 } | |
62 | |
63 SkPdfTokenizer(const char* buffer, int len) : fDoc(NULL), fTokenizer(NULL),
fUncompressedStream(NULL), fUncompressedStreamLength(0), fEmpty(false), fHasPutB
ack(false) { | |
64 try { | |
65 fTokenizer = new PdfContentsTokenizer(buffer, len); | |
66 } catch (PdfError& e) { | |
67 fEmpty = true; | |
68 } | |
69 } | |
70 | |
71 ~SkPdfTokenizer() { | |
72 free(fUncompressedStream); | |
73 } | |
74 | |
75 void PutBack(PdfToken token) { | |
76 SkASSERT(!fHasPutBack); | |
77 fHasPutBack = true; | |
78 fPutBack = token; | |
79 } | |
80 | |
81 bool readToken(PdfToken* token) { | |
82 if (fHasPutBack) { | |
83 *token = fPutBack; | |
84 fHasPutBack = false; | |
85 return true; | |
86 } | |
87 | |
88 if (fEmpty) { | |
89 return false; | |
90 } | |
91 | |
92 PdfVariant var; | |
93 EPdfContentsType type; | |
94 | |
95 token->fKeyword = NULL; | |
96 token->fObject = NULL; | |
97 | |
98 bool ret = fTokenizer->ReadNext(type, token->fKeyword, var); | |
99 | |
100 if (!ret) return ret; | |
101 | |
102 switch (type) { | |
103 case ePdfContentsType_Keyword: | |
104 token->fType = kKeyword_TokenType; | |
105 break; | |
106 | |
107 case ePdfContentsType_Variant: { | |
108 token->fType = kObject_TokenType; | |
109 PdfObject* obj = new PdfObject(var); | |
110 mapObject(*fDoc, *obj, &token->fObject); | |
111 } | |
112 break; | |
113 | |
114 case ePdfContentsType_ImageData: | |
115 token->fType = kImageData_TokenType; | |
116 // TODO(edisonn): inline images seem to work without it | |
117 break; | |
118 } | |
119 #ifdef PDF_TRACE | |
120 std::string str; | |
121 if (token->fObject) { | |
122 token->fObject->podofo()->ToString(str); | |
123 } | |
124 printf("%s %s\n", token->fType == kKeyword_TokenType ? "Keyword" : token
->fType == kObject_TokenType ? "Object" : "ImageData", token->fKeyword ? token->
fKeyword : str.c_str()); | |
125 #endif | |
126 return ret; | |
127 } | |
128 }; | |
129 | 16 |
130 extern "C" PdfContext* gPdfContext; | 17 extern "C" PdfContext* gPdfContext; |
131 extern "C" SkBitmap* gDumpBitmap; | 18 extern "C" SkBitmap* gDumpBitmap; |
132 extern "C" SkCanvas* gDumpCanvas; | 19 extern "C" SkCanvas* gDumpCanvas; |
133 | 20 |
134 // TODO(edisonn): move in trace util. | |
135 #ifdef PDF_TRACE | |
136 static void SkTraceMatrix(const SkMatrix& matrix, const char* sz = "") { | |
137 printf("SkMatrix %s ", sz); | |
138 for (int i = 0 ; i < 9 ; i++) { | |
139 printf("%f ", SkScalarToDouble(matrix.get(i))); | |
140 } | |
141 printf("\n"); | |
142 } | |
143 | |
144 static void SkTraceRect(const SkRect& rect, const char* sz = "") { | |
145 printf("SkRect %s ", sz); | |
146 printf("x = %f ", SkScalarToDouble(rect.x())); | |
147 printf("y = %f ", SkScalarToDouble(rect.y())); | |
148 printf("w = %f ", SkScalarToDouble(rect.width())); | |
149 printf("h = %f ", SkScalarToDouble(rect.height())); | |
150 printf("\n"); | |
151 } | |
152 | |
153 #else | |
154 #define SkTraceMatrix(a,b) | |
155 #define SkTraceRect(a,b) | |
156 #endif | |
157 | |
158 // TODO(edisonn): Document PdfTokenLooper and subclasses. | 21 // TODO(edisonn): Document PdfTokenLooper and subclasses. |
159 class PdfTokenLooper { | 22 class PdfTokenLooper { |
160 protected: | 23 protected: |
161 PdfTokenLooper* fParent; | 24 PdfTokenLooper* fParent; |
162 SkPdfTokenizer* fTokenizer; | 25 SkPdfPodofoTokenizer* fTokenizer; |
163 PdfContext* fPdfContext; | 26 PdfContext* fPdfContext; |
164 SkCanvas* fCanvas; | 27 SkCanvas* fCanvas; |
165 | 28 |
166 public: | 29 public: |
167 PdfTokenLooper(PdfTokenLooper* parent, | 30 PdfTokenLooper(PdfTokenLooper* parent, |
168 SkPdfTokenizer* tokenizer, | 31 SkPdfPodofoTokenizer* tokenizer, |
169 PdfContext* pdfContext, | 32 PdfContext* pdfContext, |
170 SkCanvas* canvas) | 33 SkCanvas* canvas) |
171 : fParent(parent), fTokenizer(tokenizer), fPdfContext(pdfContext), fCanv
as(canvas) {} | 34 : fParent(parent), fTokenizer(tokenizer), fPdfContext(pdfContext), fCanv
as(canvas) {} |
172 | 35 |
173 virtual PdfResult consumeToken(PdfToken& token) = 0; | 36 virtual PdfResult consumeToken(PdfToken& token) = 0; |
174 virtual void loop() = 0; | 37 virtual void loop() = 0; |
175 | 38 |
176 void setUp(PdfTokenLooper* parent) { | 39 void setUp(PdfTokenLooper* parent) { |
177 fParent = parent; | 40 fParent = parent; |
178 fTokenizer = parent->fTokenizer; | 41 fTokenizer = parent->fTokenizer; |
179 fPdfContext = parent->fPdfContext; | 42 fPdfContext = parent->fPdfContext; |
180 fCanvas = parent->fCanvas; | 43 fCanvas = parent->fCanvas; |
181 } | 44 } |
182 }; | 45 }; |
183 | 46 |
184 class PdfMainLooper : public PdfTokenLooper { | 47 class PdfMainLooper : public PdfTokenLooper { |
185 public: | 48 public: |
186 PdfMainLooper(PdfTokenLooper* parent, | 49 PdfMainLooper(PdfTokenLooper* parent, |
187 SkPdfTokenizer* tokenizer, | 50 SkPdfPodofoTokenizer* tokenizer, |
188 PdfContext* pdfContext, | 51 PdfContext* pdfContext, |
189 SkCanvas* canvas) | 52 SkCanvas* canvas) |
190 : PdfTokenLooper(parent, tokenizer, pdfContext, canvas) {} | 53 : PdfTokenLooper(parent, tokenizer, pdfContext, canvas) {} |
191 | 54 |
192 virtual PdfResult consumeToken(PdfToken& token); | 55 virtual PdfResult consumeToken(PdfToken& token); |
193 virtual void loop(); | 56 virtual void loop(); |
194 }; | 57 }; |
195 | 58 |
196 class PdfInlineImageLooper : public PdfTokenLooper { | 59 class PdfInlineImageLooper : public PdfTokenLooper { |
197 public: | 60 public: |
198 PdfInlineImageLooper() | 61 PdfInlineImageLooper() |
199 : PdfTokenLooper(NULL, NULL, NULL, NULL) {} | 62 : PdfTokenLooper(NULL, NULL, NULL, NULL) {} |
200 | 63 |
201 virtual PdfResult consumeToken(PdfToken& token); | 64 virtual PdfResult consumeToken(PdfToken& token); |
202 virtual void loop(); | 65 virtual void loop(); |
203 PdfResult done(); | 66 PdfResult done(); |
204 }; | 67 }; |
205 | 68 |
206 class PdfCompatibilitySectionLooper : public PdfTokenLooper { | 69 class PdfCompatibilitySectionLooper : public PdfTokenLooper { |
207 public: | 70 public: |
208 PdfCompatibilitySectionLooper() | 71 PdfCompatibilitySectionLooper() |
209 : PdfTokenLooper(NULL, NULL, NULL, NULL) {} | 72 : PdfTokenLooper(NULL, NULL, NULL, NULL) {} |
210 | 73 |
211 virtual PdfResult consumeToken(PdfToken& token); | 74 virtual PdfResult consumeToken(PdfToken& token); |
212 virtual void loop(); | 75 virtual void loop(); |
213 }; | 76 }; |
214 | 77 |
215 class SkPdfDoc { | |
216 PdfMemDocument fDoc; | |
217 public: | |
218 | |
219 PdfMemDocument& podofo() {return fDoc;} | |
220 | |
221 SkPdfDoc(const char* path) : fDoc(path) {} | |
222 | |
223 int pages() { | |
224 return fDoc.GetPageCount(); | |
225 } | |
226 | |
227 double width(int n) { | |
228 PdfRect rect = fDoc.GetPage(n)->GetMediaBox(); | |
229 return rect.GetWidth() + rect.GetLeft(); | |
230 } | |
231 | |
232 double height(int n) { | |
233 PdfRect rect = fDoc.GetPage(n)->GetMediaBox(); | |
234 return rect.GetHeight() + rect.GetBottom(); | |
235 } | |
236 | |
237 // Can return NULL | |
238 SkPdfPageObjectDictionary* page(int n) { | |
239 SkPdfPageObjectDictionary* page = NULL; | |
240 mapPageObjectDictionary(fDoc, *fDoc.GetPage(n)->GetObject(), &page); | |
241 return page; | |
242 } | |
243 | |
244 SkRect MediaBox(int n) { | |
245 PdfRect rect = fDoc.GetPage(n)->GetMediaBox(); | |
246 SkRect skrect = SkRect::MakeLTRB(SkDoubleToScalar(rect.GetLeft()), | |
247 SkDoubleToScalar(rect.GetBottom()), | |
248 SkDoubleToScalar(rect.GetLeft() + rect.
GetWidth()), | |
249 SkDoubleToScalar(rect.GetBottom() + rec
t.GetHeight())); | |
250 return skrect; | |
251 } | |
252 | |
253 void drawPage(int n, SkCanvas* canvas) { | |
254 SkPdfPageObjectDictionary* pg = page(n); | |
255 SkPdfTokenizer* tokenizer = tokenizerOfPage(n); | |
256 | |
257 PdfContext pdfContext(this); | |
258 pdfContext.fOriginalMatrix = SkMatrix::I(); | |
259 pdfContext.fGraphicsState.fResources = NULL; | |
260 mapResourceDictionary(*pg->Resources(), &pdfContext.fGraphicsState.fReso
urces); | |
261 | |
262 gPdfContext = &pdfContext; | |
263 gDumpCanvas = canvas; | |
264 | |
265 // TODO(edisonn): get matrix stuff right. | |
266 // TODO(edisonn): add DPI/scale/zoom. | |
267 SkScalar z = SkIntToScalar(0); | |
268 SkRect rect = MediaBox(n); | |
269 SkScalar w = rect.width(); | |
270 SkScalar h = rect.height(); | |
271 | |
272 SkPoint pdfSpace[4] = {SkPoint::Make(z, z), SkPoint::Make(w, z), SkPoint
::Make(w, h), SkPoint::Make(z, h)}; | |
273 // SkPoint skiaSpace[4] = {SkPoint::Make(z, h), SkPoint::Make(w,
h), SkPoint::Make(w, z), SkPoint::Make(z, z)}; | |
274 | |
275 // TODO(edisonn): add flag for this app to create sourunding buffer zone | |
276 // TODO(edisonn): add flagg for no clipping. | |
277 // Use larger image to make sure we do not draw anything outside of page | |
278 // could be used in tests. | |
279 | |
280 #ifdef PDF_DEBUG_3X | |
281 SkPoint skiaSpace[4] = {SkPoint::Make(w+z, h+h), SkPoint::Make(w+w, h+h)
, SkPoint::Make(w+w, h+z), SkPoint::Make(w+z, h+z)}; | |
282 #else | |
283 SkPoint skiaSpace[4] = {SkPoint::Make(z, h), SkPoint::Make(w, h), SkPoin
t::Make(w, z), SkPoint::Make(z, z)}; | |
284 #endif | |
285 //SkPoint pdfSpace[2] = {SkPoint::Make(z, z), SkPoint::Make(w, h)}; | |
286 //SkPoint skiaSpace[2] = {SkPoint::Make(w, z), SkPoint::Make(z, h)}; | |
287 | |
288 //SkPoint pdfSpace[2] = {SkPoint::Make(z, z), SkPoint::Make(z, h)}; | |
289 //SkPoint skiaSpace[2] = {SkPoint::Make(z, h), SkPoint::Make(z, z)}; | |
290 | |
291 //SkPoint pdfSpace[3] = {SkPoint::Make(z, z), SkPoint::Make(z, h), SkPoi
nt::Make(w, h)}; | |
292 //SkPoint skiaSpace[3] = {SkPoint::Make(z, h), SkPoint::Make(z, z), SkPo
int::Make(w, 0)}; | |
293 | |
294 SkAssertResult(pdfContext.fOriginalMatrix.setPolyToPoly(pdfSpace, skiaSp
ace, 4)); | |
295 SkTraceMatrix(pdfContext.fOriginalMatrix, "Original matrix"); | |
296 | |
297 | |
298 pdfContext.fGraphicsState.fMatrix = pdfContext.fOriginalMatrix; | |
299 pdfContext.fGraphicsState.fMatrixTm = pdfContext.fGraphicsState.fMatrix; | |
300 pdfContext.fGraphicsState.fMatrixTlm = pdfContext.fGraphicsState.fMatrix
; | |
301 | |
302 canvas->setMatrix(pdfContext.fOriginalMatrix); | |
303 | |
304 #ifndef PDF_DEBUG_NO_PAGE_CLIPING | |
305 canvas->clipRect(SkRect::MakeXYWH(z, z, w, h), SkRegion::kIntersect_Op,
true); | |
306 #endif | |
307 | |
308 // erase with red before? | |
309 // SkPaint paint; | |
310 // paint.setColor(SK_ColorRED); | |
311 // canvas->drawRect(rect, paint); | |
312 | |
313 PdfMainLooper looper(NULL, tokenizer, &pdfContext, canvas); | |
314 looper.loop(); | |
315 | |
316 delete tokenizer; | |
317 | |
318 | |
319 canvas->flush(); | |
320 } | |
321 | |
322 SkPdfTokenizer* tokenizerOfPage(int n) { | |
323 PdfContentsTokenizer* t = new PdfContentsTokenizer(fDoc.GetPage(n)); | |
324 return new SkPdfTokenizer(&fDoc, t); | |
325 } | |
326 }; | |
327 | |
328 // TODO(edisonn): move in another file | 78 // TODO(edisonn): move in another file |
329 class SkPdfViewer : public SkRefCnt { | 79 class SkPdfViewer : public SkRefCnt { |
330 public: | 80 public: |
331 | 81 |
332 bool load(const SkString inputFileName, SkPicture* out); | 82 bool load(const SkString inputFileName, SkPicture* out); |
333 bool write(void*) const { return false; } | 83 bool write(void*) const { return false; } |
334 }; | 84 }; |
335 | 85 |
336 void reportPdfRenderStats(); | 86 void reportPdfRenderStats(); |
337 | 87 |
338 #endif // SkPdfParser_DEFINED | 88 #endif // SkPdfParser_DEFINED |
OLD | NEW |