| 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 |