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

Side by Side Diff: experimental/PdfViewer/SkPdfParser.cpp

Issue 17856004: refactoring for pdf viewer lib (Closed) Base URL: http://skia.googlecode.com/svn/trunk/
Patch Set: Created 7 years, 6 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 | Annotate | Revision Log
« no previous file with comments | « experimental/PdfViewer/SkPdfParser.h ('k') | experimental/PdfViewer/SkPdfUtils.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /*
2 * Copyright 2013 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "SkCanvas.h"
9 #include "SkDevice.h"
10 #include "SkForceLinking.h"
11 #include "SkGraphics.h"
12 #include "SkImageDecoder.h"
13 #include "SkImageEncoder.h"
14 #include "SkOSFile.h"
15 #include "SkPicture.h"
16 #include "SkStream.h"
17 #include "SkTypeface.h"
18 #include "SkTArray.h"
19 #include "picture_utils.h"
20
21 #include <iostream>
22 #include <cstdio>
23 #include <stack>
24
25 #include "podofo.h"
26 using namespace PoDoFo;
27
28
29 __SK_FORCE_IMAGE_DECODER_LINKING;
30
31 // TODO(edisonn): tool, show what objects were read at least, show the ones not even read
32 // keep for each object pos in file
33 // plug in for VS? syntax coloring, show selected object ... from the text, or f rom rendered x,y
34
35 // TODO(edisonn): security - validate all the user input, all pdf!
36
37
38 #include "SkPdfHeaders_autogen.h"
39 #include "SkPdfPodofoMapper_autogen.h"
40 #include "SkPdfParser.h"
41
42 #include "SkPdfBasics.h"
43 #include "SkPdfUtils.h"
44
45 #include "SkPdfFont.h"
46
47 bool skpdfmap(const PdfMemDocument& podofoDoc, const PdfObject& podofoObj, SkPdf Object** out) {
48 return mapObject(podofoDoc, podofoObj, out);
49 }
50
51
52 /*
53 * TODO(edisonn):
54 * - all font types and all ppdf font features
55 * - word spacing
56 * - load font for baidu.pdf
57 * - load font for youtube.pdf
58 * - parser for pdf from the definition already available in pdfspec_autoge n.py
59 * - all docs from ~/work
60 * - encapsulate podofo in the pdf api so the skpdf does not know anything about podofo ... in progress
61 * - load gs/ especially smask and already known prop (skp) ... in progress
62 * - wrapper on classes for customizations? e.g.
63 * SkPdfPageObjectVanila - has only the basic loaders/getters
64 * SkPdfPageObject : public SkPdfPageObjectVanila, extends, and I can add custom izations here
65 * need to find a nice object model for all this with constructors and factories
66 * - deal with inheritable automatically ?
67 * - deal with specific type in spec directly, add all dictionary types to known types
68 */
69
70 using namespace std;
71 using namespace PoDoFo;
72
73 // Utilities
74 static void setup_bitmap(SkBitmap* bitmap, int width, int height, SkColor color = SK_ColorWHITE) {
75 bitmap->setConfig(SkBitmap::kARGB_8888_Config, width, height);
76
77 bitmap->allocPixels();
78 bitmap->eraseColor(color);
79 }
80
81 // TODO(edisonn): synonyms? DeviceRGB and RGB ...
82 int GetColorSpaceComponents(const std::string& colorSpace) {
83 if (colorSpace == "DeviceCMYK") {
84 return 4;
85 } else if (colorSpace == "DeviceGray" ||
86 colorSpace == "CalGray" ||
87 colorSpace == "Indexed") {
88 return 1;
89 } else if (colorSpace == "DeviceRGB" ||
90 colorSpace == "CalRGB" ||
91 colorSpace == "Lab") {
92 return 3;
93 } else {
94 return 0;
95 }
96 }
97
98 const PdfObject* resolveReferenceObject(const PdfMemDocument* pdfDoc,
99 const PdfObject* obj,
100 bool resolveOneElementArrays) {
101 while (obj && (obj->IsReference() || (resolveOneElementArrays &&
102 obj->IsArray() &&
103 obj->GetArray().GetSize() == 1))) {
104 if (obj->IsReference()) {
105 // We need to force the non const, the only update we will do is for recurssion checks.
106 PdfReference& ref = (PdfReference&)obj->GetReference();
107 obj = pdfDoc->GetObjects().GetObject(ref);
108 } else {
109 obj = &obj->GetArray()[0];
110 }
111 }
112
113 return obj;
114 }
115
116 static SkMatrix SkMatrixFromPdfMatrix(double array[6]) {
117 SkMatrix matrix;
118 matrix.setAll(SkDoubleToScalar(array[0]),
119 SkDoubleToScalar(array[2]),
120 SkDoubleToScalar(array[4]),
121 SkDoubleToScalar(array[1]),
122 SkDoubleToScalar(array[3]),
123 SkDoubleToScalar(array[5]),
124 SkDoubleToScalar(0),
125 SkDoubleToScalar(0),
126 SkDoubleToScalar(1));
127
128 return matrix;
129 }
130
131 SkMatrix SkMatrixFromPdfArray(SkPdfArray* pdfArray) {
132 double array[6];
133
134 // TODO(edisonn): security issue, ret if size() != 6
135 for (int i = 0; i < 6; i++) {
136 const PdfObject* elem = resolveReferenceObject(pdfArray->doc(), (*pdfArr ay)[i]->podofo());
137 if (elem == NULL || (!elem->IsReal() && !elem->IsNumber())) {
138 return SkMatrix::I(); // TODO(edisonn): report issue
139 }
140 array[i] = elem->GetReal();
141 }
142
143 return SkMatrixFromPdfMatrix(array);
144 }
145
146 PdfContext* gPdfContext = NULL;
147 SkBitmap* gDumpBitmap = NULL;
148 SkCanvas* gDumpCanvas = NULL;
149 char gLastKeyword[100] = "";
150 int gLastOpKeyword = -1;
151 char allOpWithVisualEffects[100] = ",S,s,f,F,f*,B,B*,b,b*,n,Tj,TJ,\',\",d0,d1,sh ,EI,Do,EX,";
152 int gReadOp = 0;
153
154
155
156 bool hasVisualEffect(const char* pdfOp) {
157 return true;
158 if (*pdfOp == '\0') return false;
159
160 char markedPdfOp[100] = ",";
161 strcat(markedPdfOp, pdfOp);
162 strcat(markedPdfOp, ",");
163
164 return (strstr(allOpWithVisualEffects, markedPdfOp) != NULL);
165 }
166
167 // TODO(edisonn): Pass PdfContext and SkCanvasd only with the define for instrum entation.
168 static bool readToken(SkPdfTokenizer* fTokenizer, PdfToken* token) {
169 bool ret = fTokenizer->readToken(token);
170
171 gReadOp++;
172
173 #ifdef PDF_TRACE_DIFF_IN_PNG
174 // TODO(edisonn): compare with old bitmap, and save only new bits are availa ble, and save
175 // the numbar and name of last operation, so the file name will reflect op t hat changed.
176 if (hasVisualEffect(gLastKeyword)) { // TODO(edisonn): and has dirty bits.
177 gDumpCanvas->flush();
178
179 SkBitmap bitmap;
180 setup_bitmap(&bitmap, gDumpBitmap->width(), gDumpBitmap->height());
181
182 memcpy(bitmap.getPixels(), gDumpBitmap->getPixels(), gDumpBitmap->getSiz e());
183
184 SkAutoTUnref<SkDevice> device(SkNEW_ARGS(SkDevice, (bitmap)));
185 SkCanvas canvas(device);
186
187 // draw context stuff here
188 SkPaint blueBorder;
189 blueBorder.setColor(SK_ColorBLUE);
190 blueBorder.setStyle(SkPaint::kStroke_Style);
191 blueBorder.setTextSize(SkDoubleToScalar(20));
192
193 SkString str;
194
195 const SkClipStack* clipStack = gDumpCanvas->getClipStack();
196 if (clipStack) {
197 SkClipStack::Iter iter(*clipStack, SkClipStack::Iter::kBottom_IterSt art);
198 const SkClipStack::Element* elem;
199 double y = 0;
200 int total = 0;
201 while (elem = iter.next()) {
202 total++;
203 y += 30;
204
205 switch (elem->getType()) {
206 case SkClipStack::Element::kRect_Type:
207 canvas.drawRect(elem->getRect(), blueBorder);
208 canvas.drawText("Rect Clip", strlen("Rect Clip"), SkDoub leToScalar(10), SkDoubleToScalar(y), blueBorder);
209 break;
210 case SkClipStack::Element::kPath_Type:
211 canvas.drawPath(elem->getPath(), blueBorder);
212 canvas.drawText("Path Clip", strlen("Path Clip"), SkDoub leToScalar(10), SkDoubleToScalar(y), blueBorder);
213 break;
214 case SkClipStack::Element::kEmpty_Type:
215 canvas.drawText("Empty Clip!!!", strlen("Empty Clip!!!") , SkDoubleToScalar(10), SkDoubleToScalar(y), blueBorder);
216 break;
217 default:
218 canvas.drawText("Unkown Clip!!!", strlen("Unkown Clip!!! "), SkDoubleToScalar(10), SkDoubleToScalar(y), blueBorder);
219 break;
220 }
221 }
222
223 y += 30;
224 str.printf("Number of clips in stack: %i", total);
225 canvas.drawText(str.c_str(), str.size(), SkDoubleToScalar(10), SkDou bleToScalar(y), blueBorder);
226 }
227
228 const SkRegion& clipRegion = gDumpCanvas->getTotalClip();
229 SkPath clipPath;
230 if (clipRegion.getBoundaryPath(&clipPath)) {
231 SkPaint redBorder;
232 redBorder.setColor(SK_ColorRED);
233 redBorder.setStyle(SkPaint::kStroke_Style);
234 canvas.drawPath(clipPath, redBorder);
235 }
236
237 canvas.flush();
238
239 SkString out;
240
241 // TODO(edisonn): get the image, and overlay on top of it, the clip , gr afic state, teh stack,
242 // ... and other properties, to be able to debug th code easily
243
244 out.appendf("/usr/local/google/home/edisonn/log_view2/step-%i-%s.png", g LastOpKeyword, gLastKeyword);
245 SkImageEncoder::EncodeFile(out.c_str(), bitmap, SkImageEncoder::kPNG_Typ e, 100);
246 }
247
248 if (token->fType == kKeyword_TokenType) {
249 strcpy(gLastKeyword, token->fKeyword);
250 gLastOpKeyword = gReadOp;
251 } else {
252 strcpy(gLastKeyword, "");
253 }
254 #endif
255
256 return ret;
257 }
258
259
260
261 typedef PdfResult (*PdfOperatorRenderer)(PdfContext*, SkCanvas*, PdfTokenLooper* *);
262
263 map<std::string, PdfOperatorRenderer> gPdfOps;
264
265 map<std::string, int> gRenderStats[kCount_PdfResult];
266
267 char* gRenderStatsNames[kCount_PdfResult] = {
268 "Success",
269 "Partially implemented",
270 "Not yet implemented",
271 "Ignore Error",
272 "Error",
273 "Unsupported/Unknown"
274 };
275
276 static SkTypeface* SkTypefaceFromPdfFont(PdfFont* font) {
277 if (font == NULL) {
278 return SkTypeface::CreateFromName("Times New Roman", SkTypeface::kNormal );
279 }
280
281 PdfObject* fontObject = font->GetObject();
282
283 PdfObject* pBaseFont = NULL;
284 // TODO(edisonn): warning, PoDoFo has a bug in PdfFont constructor, does not call InitVars()
285 // for now fixed locally.
286 pBaseFont = fontObject->GetIndirectKey( "BaseFont" );
287 const char* pszBaseFontName = pBaseFont->GetName().GetName().c_str();
288
289 #ifdef PDF_TRACE
290 std::string str;
291 fontObject->ToString(str);
292 printf("Base Font Name: %s\n", pszBaseFontName);
293 printf("Font Object Data: %s\n", str.c_str());
294 #endif
295
296 SkTypeface* typeface = SkTypefaceFromPdfStandardFont(pszBaseFontName, font-> IsBold(), font->IsItalic());
297
298 if (typeface != NULL) {
299 return typeface;
300 }
301
302 char name[1000];
303 // HACK
304 strncpy(name, pszBaseFontName, 1000);
305 char* comma = strstr(name, ",");
306 char* dash = strstr(name, "-");
307 if (comma) *comma = '\0';
308 if (dash) *dash = '\0';
309
310 typeface = SkTypeface::CreateFromName(
311 name,
312 SkTypeface::Style((font->IsBold() ? SkTypeface::kBold : 0) |
313 (font->IsItalic() ? SkTypeface::kItalic : 0))) ;
314
315 if (typeface != NULL) {
316 #ifdef PDF_TRACE
317 printf("HACKED FONT found %s\n", name);
318 #endif
319 return typeface;
320 }
321
322 #ifdef PDF_TRACE
323 printf("FONT_NOT_FOUND %s\n", pszBaseFontName);
324 #endif
325
326 // TODO(edisonn): Report Warning, NYI
327 return SkTypeface::CreateFromName(
328 "Times New Roman",
329 SkTypeface::Style((font->IsBold() ? SkTypeface::kBold : 0) |
330 (font->IsItalic() ? SkTypeface::kItalic : 0))) ;
331 }
332
333 PdfResult DrawText(PdfContext* pdfContext,
334 const SkPdfObject* str,
335 SkCanvas* canvas)
336 {
337
338 SkPdfFont* skfont = pdfContext->fGraphicsState.fSkFont;
339 if (skfont == NULL) {
340 skfont = SkPdfFont::Default();
341 }
342
343 SkUnencodedText binary(str);
344
345 SkDecodedText decoded;
346
347 if (skfont->encoding() == NULL) {
348 // TODO(edisonn): report warning
349 return kNYI_PdfResult;
350 }
351
352 skfont->encoding()->decodeText(binary, &decoded);
353
354 SkPaint paint;
355 // TODO(edisonn): when should fCurFont->GetFontSize() used? When cur is fCur FontSize == 0?
356 // Or maybe just not call setTextSize at all?
357 if (pdfContext->fGraphicsState.fCurFontSize != 0) {
358 paint.setTextSize(SkDoubleToScalar(pdfContext->fGraphicsState.fCurFontSi ze));
359 }
360
361 // if (fCurFont && fCurFont->GetFontScale() != 0) {
362 // paint.setTextScaleX(SkFloatToScalar(fCurFont->GetFontScale() / 100.0)) ;
363 // }
364
365 pdfContext->fGraphicsState.applyGraphicsState(&paint, false);
366
367 canvas->save();
368
369 #if 1
370 SkMatrix matrix = pdfContext->fGraphicsState.fMatrixTm;
371
372 SkPoint point1;
373 pdfContext->fGraphicsState.fMatrixTm.mapXY(SkIntToScalar(0), SkIntToScalar(0 ), &point1);
374
375 SkMatrix mirror;
376 mirror.setTranslate(0, -point1.y());
377 // TODO(edisonn): fix rotated text, and skewed too
378 mirror.postScale(SK_Scalar1, -SK_Scalar1);
379 // TODO(edisonn): post rotate, skew
380 mirror.postTranslate(0, point1.y());
381
382 matrix.postConcat(mirror);
383
384 canvas->setMatrix(matrix);
385
386 SkTraceMatrix(matrix, "mirrored");
387 #endif
388
389 skfont->drawText(decoded, &paint, pdfContext, canvas, &pdfContext->fGraphics State.fMatrixTm);
390 canvas->restore();
391
392 return kPartial_PdfResult;
393 }
394
395 // TODO(edisonn): create header files with declarations!
396 PdfResult PdfOp_q(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** loo per);
397 PdfResult PdfOp_Q(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** loo per);
398 PdfResult PdfOp_Tw(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** lo oper);
399 PdfResult PdfOp_Tc(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** lo oper);
400
401 // TODO(edisonn): deal with synonyms (/BPC == /BitsPerComponent), here or in Get Key?
402 // Always pass long form in key, and have a map of long -> short key
403 bool LongFromDictionary(const PdfMemDocument* pdfDoc,
404 const PdfDictionary& dict,
405 const char* key,
406 long* data) {
407 const PdfObject* value = resolveReferenceObject(pdfDoc,
408 dict.GetKey(PdfName(key)));
409
410 if (value == NULL || !value->IsNumber()) {
411 return false;
412 }
413 if (data == NULL) {
414 return true;
415 }
416
417 *data = value->GetNumber();
418 return true;
419 }
420
421 bool LongFromDictionary(const PdfMemDocument* pdfDoc,
422 const PdfDictionary& dict,
423 const char* key,
424 const char* abr,
425 long* data) {
426 if (LongFromDictionary(pdfDoc, dict, key, data)) return true;
427 if (abr == NULL || *abr == '\0') return false;
428 return LongFromDictionary(pdfDoc, dict, abr, data);
429 }
430
431 bool DoubleFromDictionary(const PdfMemDocument* pdfDoc,
432 const PdfDictionary& dict,
433 const char* key,
434 double* data) {
435 const PdfObject* value = resolveReferenceObject(pdfDoc,
436 dict.GetKey(PdfName(key)));
437
438 if (value == NULL || (!value->IsReal() && !value->IsNumber())) {
439 return false;
440 }
441 if (data == NULL) {
442 return true;
443 }
444
445 *data = value->GetReal();
446 return true;
447 }
448
449 bool DoubleFromDictionary(const PdfMemDocument* pdfDoc,
450 const PdfDictionary& dict,
451 const char* key,
452 const char* abr,
453 double* data) {
454 if (DoubleFromDictionary(pdfDoc, dict, key, data)) return true;
455 if (abr == NULL || *abr == '\0') return false;
456 return DoubleFromDictionary(pdfDoc, dict, abr, data);
457 }
458
459
460 bool BoolFromDictionary(const PdfMemDocument* pdfDoc,
461 const PdfDictionary& dict,
462 const char* key,
463 bool* data) {
464 const PdfObject* value = resolveReferenceObject(pdfDoc,
465 dict.GetKey(PdfName(key)));
466
467 if (value == NULL || !value->IsBool()) {
468 return false;
469 }
470 if (data == NULL) {
471 return true;
472 }
473
474 *data = value->GetBool();
475 return true;
476 }
477
478 bool BoolFromDictionary(const PdfMemDocument* pdfDoc,
479 const PdfDictionary& dict,
480 const char* key,
481 const char* abr,
482 bool* data) {
483 if (BoolFromDictionary(pdfDoc, dict, key, data)) return true;
484 if (abr == NULL || *abr == '\0') return false;
485 return BoolFromDictionary(pdfDoc, dict, abr, data);
486 }
487
488 bool NameFromDictionary(const PdfMemDocument* pdfDoc,
489 const PdfDictionary& dict,
490 const char* key,
491 std::string* data) {
492 const PdfObject* value = resolveReferenceObject(pdfDoc,
493 dict.GetKey(PdfName(key)),
494 true);
495 if (value == NULL || !value->IsName()) {
496 return false;
497 }
498 if (data == NULL) {
499 return true;
500 }
501
502 *data = value->GetName().GetName();
503 return true;
504 }
505
506 bool NameFromDictionary(const PdfMemDocument* pdfDoc,
507 const PdfDictionary& dict,
508 const char* key,
509 const char* abr,
510 std::string* data) {
511 if (NameFromDictionary(pdfDoc, dict, key, data)) return true;
512 if (abr == NULL || *abr == '\0') return false;
513 return NameFromDictionary(pdfDoc, dict, abr, data);
514 }
515
516 bool StringFromDictionary(const PdfMemDocument* pdfDoc,
517 const PdfDictionary& dict,
518 const char* key,
519 std::string* data) {
520 const PdfObject* value = resolveReferenceObject(pdfDoc,
521 dict.GetKey(PdfName(key)),
522 true);
523 if (value == NULL || (!value->IsString() && !value->IsHexString())) {
524 return false;
525 }
526 if (data == NULL) {
527 return true;
528 }
529
530 *data = value->GetString().GetString();
531 return true;
532 }
533
534 bool StringFromDictionary(const PdfMemDocument* pdfDoc,
535 const PdfDictionary& dict,
536 const char* key,
537 const char* abr,
538 std::string* data) {
539 if (StringFromDictionary(pdfDoc, dict, key, data)) return true;
540 if (abr == NULL || *abr == '\0') return false;
541 return StringFromDictionary(pdfDoc, dict, abr, data);
542 }
543
544 /*
545 bool ArrayFromDictionary(const PdfMemDocument* pdfDoc,
546 const PdfDictionary& dict,
547 const char* key,
548 SkPdfArray** data) {
549 const PdfObject* value = resolveReferenceObject(pdfDoc,
550 dict.GetKey(PdfName(key)),
551 true);
552 if (value == NULL || !value->IsArray()) {
553 return false;
554 }
555 if (data == NULL) {
556 return true;
557 }
558
559 return mapArray(*pdfDoc, *value, data);
560 }
561
562
563 bool ArrayFromDictionary(const PdfMemDocument* pdfDoc,
564 const PdfDictionary& dict,
565 const char* key,
566 const char* abr,
567 SkPdfArray** data) {
568 if (ArrayFromDictionary(pdfDoc, dict, key, data)) return true;
569 if (abr == NULL || *abr == '\0') return false;
570 return ArrayFromDictionary(pdfDoc, dict, abr, data);
571 }
572
573
574 bool DictionaryFromDictionary(const PdfMemDocument* pdfDoc,
575 const PdfDictionary& dict,
576 const char* key,
577 SkPdfDictionary** data) {
578 const PdfObject* value = resolveReferenceObject(pdfDoc,
579 dict.GetKey(PdfName(key)),
580 true);
581 if (value == NULL || !value->IsDictionary()) {
582 return false;
583 }
584 if (data == NULL) {
585 return true;
586 }
587
588 return mapDictionary(*pdfDoc, *value, data);
589 }
590
591 bool DictionaryFromDictionary(const PdfMemDocument* pdfDoc,
592 const PdfDictionary& dict,
593 const char* key,
594 const char* abr,
595 SkPdfDictionary** data) {
596 if (DictionaryFromDictionary(pdfDoc, dict, key, data)) return true;
597 if (abr == NULL || *abr == '\0') return false;
598 return DictionaryFromDictionary(pdfDoc, dict, abr, data);
599 }
600
601
602 bool ObjectFromDictionary(const PdfMemDocument* pdfDoc,
603 const PdfDictionary& dict,
604 const char* key,
605 SkPdfObject** data) {
606 const PdfObject* value = resolveReferenceObject(pdfDoc,
607 dict.GetKey(PdfName(key)),
608 true);
609 if (value == NULL) {
610 return false;
611 }
612 if (data == NULL) {
613 return true;
614 }
615 return mapObject(*pdfDoc, *value, data);
616 }
617
618 bool ObjectFromDictionary(const PdfMemDocument* pdfDoc,
619 const PdfDictionary& dict,
620 const char* key,
621 const char* abr,
622 SkPdfObject** data) {
623 if (ObjectFromDictionary(pdfDoc, dict, key, data)) return true;
624 if (abr == NULL || *abr == '\0') return false;
625 return ObjectFromDictionary(pdfDoc, dict, abr, data);
626 }
627
628 bool StreamFromDictionary(const PdfMemDocument* pdfDoc,
629 const PdfDictionary& dict,
630 const char* key,
631 SkPdfStream** data) {
632 const PdfObject* value = resolveReferenceObject(pdfDoc,
633 dict.GetKey(PdfName(key)),
634 true);
635 if (value == NULL) {
636 return false;
637 }
638 if (data == NULL) {
639 return true;
640 }
641 return mapStream(*pdfDoc, *value, data);
642 }
643
644 bool StreamFromDictionary(const PdfMemDocument* pdfDoc,
645 const PdfDictionary& dict,
646 const char* key,
647 const char* abr,
648 SkPdfStream** data) {
649 if (StreamFromDictionary(pdfDoc, dict, key, data)) return true;
650 if (abr == NULL || *abr == '\0') return false;
651 return StreamFromDictionary(pdfDoc, dict, abr, data);
652 }
653 */
654
655 // TODO(edisonn): perf!!!
656
657 static SkColorTable* getGrayColortable() {
658 static SkColorTable* grayColortable = NULL;
659 if (grayColortable == NULL) {
660 SkPMColor* colors = new SkPMColor[256];
661 for (int i = 0 ; i < 256; i++) {
662 colors[i] = SkPreMultiplyARGB(255, i, i, i);
663 }
664 grayColortable = new SkColorTable(colors, 256);
665 }
666 return grayColortable;
667 }
668
669 SkBitmap transferImageStreamToBitmap(unsigned char* uncompressedStream, pdf_long uncompressedStreamLength,
670 int width, int height, int bytesPerLine,
671 int bpc, const std::string& colorSpace,
672 bool transparencyMask) {
673 SkBitmap bitmap;
674
675 int components = GetColorSpaceComponents(colorSpace);
676 //#define MAX_COMPONENTS 10
677
678 int bitsPerLine = width * components * bpc;
679 // TODO(edisonn): assume start of lines are aligned at 32 bits?
680 // Is there a faster way to load the uncompressed stream into a bitmap?
681
682 // minimal support for now
683 if ((colorSpace == "DeviceRGB" || colorSpace == "RGB") && bpc == 8) {
684 SkColor* uncompressedStreamArgb = (SkColor*)malloc(width * height * size of(SkColor));
685
686 for (int h = 0 ; h < height; h++) {
687 long i = width * (height - 1 - h);
688 for (int w = 0 ; w < width; w++) {
689 uncompressedStreamArgb[i] = SkColorSetRGB(uncompressedStream[3 * w],
690 uncompressedStream[3 * w + 1],
691 uncompressedStream[3 * w + 2]);
692 i++;
693 }
694 uncompressedStream += bytesPerLine;
695 }
696
697 bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height);
698 bitmap.setPixels(uncompressedStreamArgb);
699 }
700 else if ((colorSpace == "DeviceGray" || colorSpace == "Gray") && bpc == 8) {
701 unsigned char* uncompressedStreamA8 = (unsigned char*)malloc(width * hei ght);
702
703 for (int h = 0 ; h < height; h++) {
704 long i = width * (height - 1 - h);
705 for (int w = 0 ; w < width; w++) {
706 uncompressedStreamA8[i] = transparencyMask ? 255 - uncompressedS tream[w] :
707 uncompressedStream[ w];
708 i++;
709 }
710 uncompressedStream += bytesPerLine;
711 }
712
713 bitmap.setConfig(transparencyMask ? SkBitmap::kA8_Config : SkBitmap::kIn dex8_Config,
714 width, height);
715 bitmap.setPixels(uncompressedStreamA8, transparencyMask ? NULL : getGray Colortable());
716 }
717
718 // TODO(edisonn): Report Warning, NYI, or error
719 return bitmap;
720 }
721
722 bool transferImageStreamToARGB(unsigned char* uncompressedStream, pdf_long uncom pressedStreamLength,
723 int width, int bytesPerLine,
724 int bpc, const std::string& colorSpace,
725 SkColor** uncompressedStreamArgb,
726 pdf_long* uncompressedStreamLengthInBytesArgb) {
727 int components = GetColorSpaceComponents(colorSpace);
728 //#define MAX_COMPONENTS 10
729
730 int bitsPerLine = width * components * bpc;
731 // TODO(edisonn): assume start of lines are aligned at 32 bits?
732 int height = uncompressedStreamLength / bytesPerLine;
733
734 // minimal support for now
735 if ((colorSpace == "DeviceRGB" || colorSpace == "RGB") && bpc == 8) {
736 *uncompressedStreamLengthInBytesArgb = width * height * 4;
737 *uncompressedStreamArgb = (SkColor*)malloc(*uncompressedStreamLengthInBy tesArgb);
738
739 for (int h = 0 ; h < height; h++) {
740 long i = width * (height - 1 - h);
741 for (int w = 0 ; w < width; w++) {
742 (*uncompressedStreamArgb)[i] = SkColorSetRGB(uncompressedStream[ 3 * w],
743 uncompressedStream[ 3 * w + 1],
744 uncompressedStream[ 3 * w + 2]);
745 i++;
746 }
747 uncompressedStream += bytesPerLine;
748 }
749 return true;
750 }
751
752 if ((colorSpace == "DeviceGray" || colorSpace == "Gray") && bpc == 8) {
753 *uncompressedStreamLengthInBytesArgb = width * height * 4;
754 *uncompressedStreamArgb = (SkColor*)malloc(*uncompressedStreamLengthInBy tesArgb);
755
756 for (int h = 0 ; h < height; h++) {
757 long i = width * (height - 1 - h);
758 for (int w = 0 ; w < width; w++) {
759 (*uncompressedStreamArgb)[i] = SkColorSetRGB(uncompressedStream[ w],
760 uncompressedStream[ w],
761 uncompressedStream[ w]);
762 i++;
763 }
764 uncompressedStream += bytesPerLine;
765 }
766 return true;
767 }
768
769 return false;
770 }
771
772 // utils
773
774 // TODO(edisonn): add cache, or put the bitmap property directly on the PdfObjec t
775 // TODO(edisonn): deal with colorSpaces, we could add them to SkBitmap::Config
776 // TODO(edisonn): preserve A1 format that skia knows, + fast convert from 111, 2 22, 444 to closest
777 // skia format, through a table
778
779 // this functions returns the image, it does not look at the smask.
780
781 SkBitmap getImageFromObject(PdfContext* pdfContext, const SkPdfImageDictionary* image, bool transparencyMask) {
782 if (image == NULL || !image->valid()) {
783 // TODO(edisonn): report warning to be used in testing.
784 return SkBitmap();
785 }
786
787 // TODO (edisonn): Fast Jpeg(DCTDecode) draw, or fast PNG(FlateDecode) draw ...
788 // PdfObject* value = resolveReferenceObject(pdfContext->fPdfDoc,
789 // obj.GetDictionary().GetKey(PdfNa me("Filter")));
790 // if (value && value->IsArray() && value->GetArray().GetSize() == 1) {
791 // value = resolveReferenceObject(pdfContext->fPdfDoc,
792 // &value->GetArray()[0]);
793 // }
794 // if (value && value->IsName() && value->GetName().GetName() == "DCTDecode") {
795 // SkStream stream = SkStream::
796 // SkImageDecoder::Factory()
797 // }
798
799 long bpc = image->BitsPerComponent();
800 long width = image->Width();
801 long height = image->Height();
802 std::string colorSpace = "DeviceRGB";
803
804 // TODO(edisonn): color space can be an array too!
805 if (image->isColorSpaceAName()) {
806 colorSpace = image->getColorSpaceAsName();
807 }
808
809 /*
810 bool imageMask = image->imageMask();
811
812 if (imageMask) {
813 if (bpc != 0 && bpc != 1) {
814 // TODO(edisonn): report warning to be used in testing.
815 return SkBitmap();
816 }
817 bpc = 1;
818 }
819 */
820
821 const PdfObject* obj = image->podofo();
822
823 char* uncompressedStream = NULL;
824 pdf_long uncompressedStreamLength = 0;
825
826 PdfResult ret = kPartial_PdfResult;
827 // TODO(edisonn): get rid of try/catch exceptions! We should not throw on us er data!
828 try {
829 obj->GetStream()->GetFilteredCopy(&uncompressedStream, &uncompressedStre amLength);
830 } catch (PdfError& e) {
831 // TODO(edisonn): report warning to be used in testing.
832 return SkBitmap();
833 }
834
835 int bytesPerLine = uncompressedStreamLength / height;
836 #ifdef PDF_TRACE
837 if (uncompressedStreamLength % height != 0) {
838 printf("Warning uncompressedStreamLength % height != 0 !!!\n");
839 }
840 #endif
841
842 SkBitmap bitmap = transferImageStreamToBitmap(
843 (unsigned char*)uncompressedStream, uncompressedStreamLength,
844 width, height, bytesPerLine,
845 bpc, colorSpace,
846 transparencyMask);
847
848 free(uncompressedStream);
849
850 return bitmap;
851 }
852
853 SkBitmap getSmaskFromObject(PdfContext* pdfContext, const SkPdfImageDictionary* obj) {
854 const PdfObject* sMask = resolveReferenceObject(&pdfContext->fPdfDoc->podofo (),
855 obj->podofo()->GetDictionary().Get Key(PdfName("SMask")));
856
857 #ifdef PDF_TRACE
858 std::string str;
859 if (sMask) {
860 sMask->ToString(str);
861 printf("/SMask of /Subtype /Image: %s\n", str.c_str());
862 }
863 #endif
864
865 if (sMask) {
866 SkPdfImageDictionary skxobjmask(&pdfContext->fPdfDoc->podofo(), sMask);
867 return getImageFromObject(pdfContext, &skxobjmask, true);
868 }
869
870 // TODO(edisonn): implement GS SMask. Default to empty right now.
871 return pdfContext->fGraphicsState.fSMask;
872 }
873
874 PdfResult doXObject_Image(PdfContext* pdfContext, SkCanvas* canvas, const SkPdfI mageDictionary* skpdfimage) {
875 if (skpdfimage == NULL || !skpdfimage->valid()) {
876 return kIgnoreError_PdfResult;
877 }
878
879 SkBitmap image = getImageFromObject(pdfContext, skpdfimage, false);
880 SkBitmap sMask = getSmaskFromObject(pdfContext, skpdfimage);
881
882 canvas->save();
883 canvas->setMatrix(pdfContext->fGraphicsState.fMatrix);
884 SkRect dst = SkRect::MakeXYWH(SkDoubleToScalar(0.0), SkDoubleToScalar(0.0), SkDoubleToScalar(1.0), SkDoubleToScalar(1.0));
885
886 if (sMask.empty()) {
887 canvas->drawBitmapRect(image, dst, NULL);
888 } else {
889 canvas->saveLayer(&dst, NULL);
890 canvas->drawBitmapRect(image, dst, NULL);
891 SkPaint xfer;
892 pdfContext->fGraphicsState.applyGraphicsState(&xfer, false);
893 xfer.setXfermodeMode(SkXfermode::kSrcOut_Mode); // SkXfermode::kSdtOut_M ode
894 canvas->drawBitmapRect(sMask, dst, &xfer);
895 canvas->restore();
896 }
897
898 canvas->restore();
899
900 return kPartial_PdfResult;
901 }
902
903 bool SkMatrixFromDictionary(const PdfMemDocument* pdfDoc,
904 const PdfDictionary& dict,
905 const char* key,
906 SkMatrix** matrix) {
907 const PdfObject* value = resolveReferenceObject(pdfDoc,
908 dict.GetKey(PdfName(key)));
909
910 if (value == NULL || !value->IsArray()) {
911 return false;
912 }
913
914 if (value->GetArray().GetSize() != 6) {
915 return false;
916 }
917
918 double array[6];
919 for (int i = 0; i < 6; i++) {
920 const PdfObject* elem = resolveReferenceObject(pdfDoc, &value->GetArray( )[i]);
921 if (elem == NULL || (!elem->IsReal() && !elem->IsNumber())) {
922 return false;
923 }
924 array[i] = elem->GetReal();
925 }
926
927 *matrix = new SkMatrix();
928 **matrix = SkMatrixFromPdfMatrix(array);
929 return true;
930 }
931
932 bool SkMatrixFromDictionary(const PdfMemDocument* pdfDoc,
933 const PdfDictionary& dict,
934 const char* key,
935 const char* abr,
936 SkMatrix** data) {
937 if (SkMatrixFromDictionary(pdfDoc, dict, key, data)) return true;
938 if (abr == NULL || *abr == '\0') return false;
939 return SkMatrixFromDictionary(pdfDoc, dict, abr, data);
940
941 }
942
943 bool SkRectFromDictionary(const PdfMemDocument* pdfDoc,
944 const PdfDictionary& dict,
945 const char* key,
946 SkRect** rect) {
947 const PdfObject* value = resolveReferenceObject(pdfDoc,
948 dict.GetKey(PdfName(key)));
949
950 if (value == NULL || !value->IsArray()) {
951 return false;
952 }
953
954 if (value->GetArray().GetSize() != 4) {
955 return false;
956 }
957
958 double array[4];
959 for (int i = 0; i < 4; i++) {
960 const PdfObject* elem = resolveReferenceObject(pdfDoc, &value->GetArray( )[i]);
961 if (elem == NULL || (!elem->IsReal() && !elem->IsNumber())) {
962 return false;
963 }
964 array[i] = elem->GetReal();
965 }
966
967 *rect = new SkRect();
968 **rect = SkRect::MakeLTRB(SkDoubleToScalar(array[0]),
969 SkDoubleToScalar(array[1]),
970 SkDoubleToScalar(array[2]),
971 SkDoubleToScalar(array[3]));
972 return true;
973 }
974
975 bool SkRectFromDictionary(const PdfMemDocument* pdfDoc,
976 const PdfDictionary& dict,
977 const char* key,
978 const char* abr,
979 SkRect** data) {
980 if (SkRectFromDictionary(pdfDoc, dict, key, data)) return true;
981 if (abr == NULL || *abr == '\0') return false;
982 return SkRectFromDictionary(pdfDoc, dict, abr, data);
983
984 }
985
986
987 SkPdfObject* get(const SkPdfObject* obj, const char* key, const char* abr = "") {
988 SkPdfObject* ret = NULL;
989 if (obj == NULL) return NULL;
990 const SkPdfDictionary* dict = obj->asDictionary();
991 if (dict == NULL) return NULL;
992 if (!dict->podofo()->IsDictionary()) return NULL;
993 ObjectFromDictionary(dict->doc(), dict->podofo()->GetDictionary(), key, abr, &ret);
994 return ret;
995 }
996
997 PdfResult doXObject_Form(PdfContext* pdfContext, SkCanvas* canvas, SkPdfType1For mDictionary* skobj) {
998 if (!skobj || !skobj->podofo() || !skobj->podofo()->HasStream() || skobj->po dofo()->GetStream() == NULL || skobj->podofo()->GetStream()->GetLength() == 0) {
999 return kOK_PdfResult;
1000 }
1001
1002 PdfOp_q(pdfContext, canvas, NULL);
1003 canvas->save();
1004
1005
1006 if (skobj->Resources()) {
1007 pdfContext->fGraphicsState.fResources = skobj->Resources();
1008 }
1009
1010 SkTraceMatrix(pdfContext->fGraphicsState.fMatrix, "Current matrix");
1011
1012 if (skobj->Matrix()) {
1013 pdfContext->fGraphicsState.fMatrix.preConcat(*skobj->Matrix());
1014 pdfContext->fGraphicsState.fMatrixTm = pdfContext->fGraphicsState.fMatri x;
1015 pdfContext->fGraphicsState.fMatrixTlm = pdfContext->fGraphicsState.fMatr ix;
1016 // TODO(edisonn) reset matrixTm and matricTlm also?
1017 }
1018
1019 SkTraceMatrix(pdfContext->fGraphicsState.fMatrix, "Total matrix");
1020
1021 canvas->setMatrix(pdfContext->fGraphicsState.fMatrix);
1022
1023 if (skobj->BBox()) {
1024 canvas->clipRect(*skobj->BBox(), SkRegion::kIntersect_Op, true); // TOD O(edisonn): AA from settings.
1025 }
1026
1027 // TODO(edisonn): iterate smart on the stream even if it is compressed, toke nize it as we go.
1028 // For this PdfContentsTokenizer needs to be extended.
1029
1030 PdfResult ret = kPartial_PdfResult;
1031 SkPdfTokenizer tokenizer(skobj);
1032 PdfMainLooper looper(NULL, &tokenizer, pdfContext, canvas);
1033 looper.loop();
1034
1035 // TODO(edisonn): should we restore the variable stack at the same state?
1036 // There could be operands left, that could be consumed by a parent tokenize r when we pop.
1037 canvas->restore();
1038 PdfOp_Q(pdfContext, canvas, NULL);
1039 return ret;
1040 }
1041
1042 PdfResult doXObject_PS(PdfContext* pdfContext, SkCanvas* canvas, const PdfObject & obj) {
1043 return kNYI_PdfResult;
1044 }
1045
1046 PdfResult doType3Char(PdfContext* pdfContext, SkCanvas* canvas, SkPdfObject* sko bj, SkRect bBox, SkMatrix matrix, double textSize) {
1047 if (!skobj || !skobj->podofo() || !skobj->podofo()->HasStream() || skobj->po dofo()->GetStream() == NULL || skobj->podofo()->GetStream()->GetLength() == 0) {
1048 return kOK_PdfResult;
1049 }
1050
1051 PdfOp_q(pdfContext, canvas, NULL);
1052 canvas->save();
1053
1054 pdfContext->fGraphicsState.fMatrixTm.preConcat(matrix);
1055 pdfContext->fGraphicsState.fMatrixTm.preScale(SkDoubleToScalar(textSize), Sk DoubleToScalar(textSize));
1056
1057 pdfContext->fGraphicsState.fMatrix = pdfContext->fGraphicsState.fMatrixTm;
1058 pdfContext->fGraphicsState.fMatrixTlm = pdfContext->fGraphicsState.fMatrix;
1059
1060 SkTraceMatrix(pdfContext->fGraphicsState.fMatrix, "Total matrix");
1061
1062 canvas->setMatrix(pdfContext->fGraphicsState.fMatrix);
1063
1064 SkRect rm = bBox;
1065 pdfContext->fGraphicsState.fMatrix.mapRect(&rm);
1066
1067 SkTraceRect(rm, "bbox mapped");
1068
1069 canvas->clipRect(bBox, SkRegion::kIntersect_Op, true); // TODO(edisonn): AA from settings.
1070
1071 // TODO(edisonn): iterate smart on the stream even if it is compressed, toke nize it as we go.
1072 // For this PdfContentsTokenizer needs to be extended.
1073
1074 PdfResult ret = kPartial_PdfResult;
1075 SkPdfTokenizer tokenizer(skobj);
1076 PdfMainLooper looper(NULL, &tokenizer, pdfContext, canvas);
1077 looper.loop();
1078
1079 // TODO(edisonn): should we restore the variable stack at the same state?
1080 // There could be operands left, that could be consumed by a parent tokenize r when we pop.
1081 canvas->restore();
1082 PdfOp_Q(pdfContext, canvas, NULL);
1083 return ret;
1084 }
1085
1086
1087 // TODO(edisonn): faster, have the property on the SkPdfObject itself?
1088 std::set<const PdfObject*> gInRendering;
1089
1090 class CheckRecursiveRendering {
1091 const PdfObject& fObj;
1092 public:
1093 CheckRecursiveRendering(const PdfObject& obj) : fObj(obj) {
1094 gInRendering.insert(&obj);
1095 }
1096
1097 ~CheckRecursiveRendering() {
1098 //SkASSERT(fObj.fInRendering);
1099 gInRendering.erase(&fObj);
1100 }
1101
1102 static bool IsInRendering(const PdfObject& obj) {
1103 return gInRendering.find(&obj) != gInRendering.end();
1104 }
1105 };
1106
1107 PdfResult doXObject(PdfContext* pdfContext, SkCanvas* canvas, const SkPdfObject& obj) {
1108 if (CheckRecursiveRendering::IsInRendering(*obj.podofo())) {
1109 // Oops, corrupt PDF!
1110 return kIgnoreError_PdfResult;
1111 }
1112
1113 CheckRecursiveRendering checkRecursion(*obj.podofo());
1114
1115 // TODO(edisonn): check type
1116 SkPdfXObjectDictionary* skobj = NULL;
1117 if (!mapXObjectDictionary(obj, &skobj)) return kIgnoreError_PdfResult;
1118
1119 if (!skobj || !skobj->valid()) return kIgnoreError_PdfResult;
1120
1121 PdfResult ret = kIgnoreError_PdfResult;
1122 switch (skobj->getType())
1123 {
1124 case kImageDictionary_SkPdfObjectType:
1125 ret = doXObject_Image(pdfContext, canvas, skobj->asImageDictionary() );
1126 break;
1127 case kType1FormDictionary_SkPdfObjectType:
1128 ret = doXObject_Form(pdfContext, canvas, skobj->asType1FormDictionar y());
1129 break;
1130 //case kObjectDictionaryXObjectPS_SkPdfObjectType:
1131 //return doXObject_PS(skxobj.asPS());
1132 }
1133
1134 delete skobj;
1135 return ret;
1136 }
1137
1138 PdfResult PdfOp_q(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** loo per) {
1139 pdfContext->fStateStack.push(pdfContext->fGraphicsState);
1140 canvas->save();
1141 return kOK_PdfResult;
1142 }
1143
1144 PdfResult PdfOp_Q(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** loo per) {
1145 pdfContext->fGraphicsState = pdfContext->fStateStack.top();
1146 pdfContext->fStateStack.pop();
1147 canvas->restore();
1148 return kOK_PdfResult;
1149 }
1150
1151 PdfResult PdfOp_cm(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** lo oper) {
1152 double array[6];
1153 for (int i = 0 ; i < 6 ; i++) {
1154 array[5 - i] = pdfContext->fObjectStack.top()->asNumber()->value();
1155 pdfContext->fObjectStack.pop();
1156 }
1157
1158 // a b
1159 // c d
1160 // e f
1161
1162 // 0 1
1163 // 2 3
1164 // 4 5
1165
1166 // sx ky
1167 // kx sy
1168 // tx ty
1169 SkMatrix matrix = SkMatrixFromPdfMatrix(array);
1170
1171 pdfContext->fGraphicsState.fMatrix.preConcat(matrix);
1172
1173 #ifdef PDF_TRACE
1174 printf("cm ");
1175 for (int i = 0 ; i < 6 ; i++) {
1176 printf("%f ", array[i]);
1177 }
1178 printf("\n");
1179 SkTraceMatrix(pdfContext->fGraphicsState.fMatrix);
1180 #endif
1181
1182 return kOK_PdfResult;
1183 }
1184
1185 //leading TL Set the text leading, Tl
1186 //, to leading, which is a number expressed in unscaled text
1187 //space units. Text leading is used only by the T*, ', and " operators. Initial value: 0.
1188 PdfResult PdfOp_TL(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** lo oper) {
1189 double ty = pdfContext->fObjectStack.top()->asNumber()->value(); pdfContext- >fObjectStack.pop();
1190
1191 pdfContext->fGraphicsState.fTextLeading = ty;
1192
1193 return kOK_PdfResult;
1194 }
1195
1196 PdfResult PdfOp_Td(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** lo oper) {
1197 double ty = pdfContext->fObjectStack.top()->asNumber()->value(); pdfContext- >fObjectStack.pop();
1198 double tx = pdfContext->fObjectStack.top()->asNumber()->value(); pdfContext- >fObjectStack.pop();
1199
1200 double array[6] = {1, 0, 0, 1, tx, ty};
1201 SkMatrix matrix = SkMatrixFromPdfMatrix(array);
1202
1203 pdfContext->fGraphicsState.fMatrixTm.preConcat(matrix);
1204 pdfContext->fGraphicsState.fMatrixTlm.preConcat(matrix);
1205
1206 return kPartial_PdfResult;
1207 }
1208
1209 PdfResult PdfOp_TD(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** lo oper) {
1210 double ty = pdfContext->fObjectStack.top()->asNumber()->value(); pdfContext- >fObjectStack.pop();
1211 double tx = pdfContext->fObjectStack.top()->asNumber()->value(); pdfContext- >fObjectStack.pop();
1212
1213 // TODO(edisonn): Create factory methods or constructors so podofo is hidden
1214 PdfObject _ty(PdfVariant(-ty));
1215 pdfContext->fObjectStack.push(new SkPdfNumber(&pdfContext->fPdfDoc->podofo() , &_ty));
1216
1217 PdfOp_TL(pdfContext, canvas, looper);
1218
1219 PdfObject vtx(PdfVariant(-(-tx))); // TODO(edisonn): Hmm, the compiler thin ks I have here a function pointer if we use (tx), but not -(-tx)
1220 pdfContext->fObjectStack.push(new SkPdfNumber(&pdfContext->fPdfDoc->podofo() , &vtx));
1221
1222 PdfObject vty(PdfVariant(-(-ty)));
1223 pdfContext->fObjectStack.push(new SkPdfNumber(&pdfContext->fPdfDoc->podofo() , &vty));
1224
1225 return PdfOp_Td(pdfContext, canvas, looper);
1226 }
1227
1228 PdfResult PdfOp_Tm(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** lo oper) {
1229 double f = pdfContext->fObjectStack.top()->asNumber()->value(); pdfContext-> fObjectStack.pop();
1230 double e = pdfContext->fObjectStack.top()->asNumber()->value(); pdfContext-> fObjectStack.pop();
1231 double d = pdfContext->fObjectStack.top()->asNumber()->value(); pdfContext-> fObjectStack.pop();
1232 double c = pdfContext->fObjectStack.top()->asNumber()->value(); pdfContext-> fObjectStack.pop();
1233 double b = pdfContext->fObjectStack.top()->asNumber()->value(); pdfContext-> fObjectStack.pop();
1234 double a = pdfContext->fObjectStack.top()->asNumber()->value(); pdfContext-> fObjectStack.pop();
1235
1236 double array[6];
1237 array[0] = a;
1238 array[1] = b;
1239 array[2] = c;
1240 array[3] = d;
1241 array[4] = e;
1242 array[5] = f;
1243
1244 SkMatrix matrix = SkMatrixFromPdfMatrix(array);
1245 matrix.postConcat(pdfContext->fGraphicsState.fMatrix);
1246
1247 // TODO(edisonn): Text positioning.
1248 pdfContext->fGraphicsState.fMatrixTm = matrix;
1249 pdfContext->fGraphicsState.fMatrixTlm = matrix;;
1250
1251 return kPartial_PdfResult;
1252 }
1253
1254 //— T* Move to the start of the next line. This operator has the same effect as the code
1255 //0 Tl Td
1256 //where Tl is the current leading parameter in the text state
1257 PdfResult PdfOp_T_star(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper* * looper) {
1258 PdfObject zero(PdfVariant(0.0));
1259 PdfObject tl(PdfVariant(-(-pdfContext->fGraphicsState.fTextLeading)));
1260
1261 pdfContext->fObjectStack.push(new SkPdfNumber(&pdfContext->fPdfDoc->podofo() , &zero));
1262 pdfContext->fObjectStack.push(new SkPdfNumber(&pdfContext->fPdfDoc->podofo() , &tl));
1263 return PdfOp_Td(pdfContext, canvas, looper);
1264 }
1265
1266 PdfResult PdfOp_m(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** loo per) {
1267 if (pdfContext->fGraphicsState.fPathClosed) {
1268 pdfContext->fGraphicsState.fPath.reset();
1269 pdfContext->fGraphicsState.fPathClosed = false;
1270 }
1271
1272 pdfContext->fGraphicsState.fCurPosY = pdfContext->fObjectStack.top()->asNumb er()->value(); pdfContext->fObjectStack.pop();
1273 pdfContext->fGraphicsState.fCurPosX = pdfContext->fObjectStack.top()->asNumb er()->value(); pdfContext->fObjectStack.pop();
1274
1275 pdfContext->fGraphicsState.fPath.moveTo(SkDoubleToScalar(pdfContext->fGraphi csState.fCurPosX),
1276 SkDoubleToScalar(pdfContext->fGraphics State.fCurPosY));
1277
1278 return kOK_PdfResult;
1279 }
1280
1281 PdfResult PdfOp_l(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** loo per) {
1282 if (pdfContext->fGraphicsState.fPathClosed) {
1283 pdfContext->fGraphicsState.fPath.reset();
1284 pdfContext->fGraphicsState.fPathClosed = false;
1285 }
1286
1287 pdfContext->fGraphicsState.fCurPosY = pdfContext->fObjectStack.top()->asNumb er()->value(); pdfContext->fObjectStack.pop();
1288 pdfContext->fGraphicsState.fCurPosX = pdfContext->fObjectStack.top()->asNumb er()->value(); pdfContext->fObjectStack.pop();
1289
1290 pdfContext->fGraphicsState.fPath.lineTo(SkDoubleToScalar(pdfContext->fGraphi csState.fCurPosX),
1291 SkDoubleToScalar(pdfContext->fGraphics State.fCurPosY));
1292
1293 return kOK_PdfResult;
1294 }
1295
1296 PdfResult PdfOp_c(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** loo per) {
1297 if (pdfContext->fGraphicsState.fPathClosed) {
1298 pdfContext->fGraphicsState.fPath.reset();
1299 pdfContext->fGraphicsState.fPathClosed = false;
1300 }
1301
1302 double y3 = pdfContext->fObjectStack.top()->asNumber()->value(); pdfConte xt->fObjectStack.pop();
1303 double x3 = pdfContext->fObjectStack.top()->asNumber()->value(); pdfConte xt->fObjectStack.pop();
1304 double y2 = pdfContext->fObjectStack.top()->asNumber()->value(); pdfConte xt->fObjectStack.pop();
1305 double x2 = pdfContext->fObjectStack.top()->asNumber()->value(); pdfConte xt->fObjectStack.pop();
1306 double y1 = pdfContext->fObjectStack.top()->asNumber()->value(); pdfConte xt->fObjectStack.pop();
1307 double x1 = pdfContext->fObjectStack.top()->asNumber()->value(); pdfConte xt->fObjectStack.pop();
1308
1309 pdfContext->fGraphicsState.fPath.cubicTo(SkDoubleToScalar(x1), SkDoubleToSca lar(y1),
1310 SkDoubleToScalar(x2), SkDoubleToScal ar(y2),
1311 SkDoubleToScalar(x3), SkDoubleToScal ar(y3));
1312
1313 pdfContext->fGraphicsState.fCurPosX = x3;
1314 pdfContext->fGraphicsState.fCurPosY = y3;
1315
1316 return kOK_PdfResult;
1317 }
1318
1319 PdfResult PdfOp_v(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** loo per) {
1320 if (pdfContext->fGraphicsState.fPathClosed) {
1321 pdfContext->fGraphicsState.fPath.reset();
1322 pdfContext->fGraphicsState.fPathClosed = false;
1323 }
1324
1325 double y3 = pdfContext->fObjectStack.top()->asNumber()->value(); pdfConte xt->fObjectStack.pop();
1326 double x3 = pdfContext->fObjectStack.top()->asNumber()->value(); pdfConte xt->fObjectStack.pop();
1327 double y2 = pdfContext->fObjectStack.top()->asNumber()->value(); pdfConte xt->fObjectStack.pop();
1328 double x2 = pdfContext->fObjectStack.top()->asNumber()->value(); pdfConte xt->fObjectStack.pop();
1329 double y1 = pdfContext->fGraphicsState.fCurPosY;
1330 double x1 = pdfContext->fGraphicsState.fCurPosX;
1331
1332 pdfContext->fGraphicsState.fPath.cubicTo(SkDoubleToScalar(x1), SkDoubleToSca lar(y1),
1333 SkDoubleToScalar(x2), SkDoubleToScal ar(y2),
1334 SkDoubleToScalar(x3), SkDoubleToScal ar(y3));
1335
1336 pdfContext->fGraphicsState.fCurPosX = x3;
1337 pdfContext->fGraphicsState.fCurPosY = y3;
1338
1339 return kOK_PdfResult;
1340 }
1341
1342 PdfResult PdfOp_y(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** loo per) {
1343 if (pdfContext->fGraphicsState.fPathClosed) {
1344 pdfContext->fGraphicsState.fPath.reset();
1345 pdfContext->fGraphicsState.fPathClosed = false;
1346 }
1347
1348 double y3 = pdfContext->fObjectStack.top()->asNumber()->value(); pdfConte xt->fObjectStack.pop();
1349 double x3 = pdfContext->fObjectStack.top()->asNumber()->value(); pdfConte xt->fObjectStack.pop();
1350 double y2 = pdfContext->fGraphicsState.fCurPosY;
1351 double x2 = pdfContext->fGraphicsState.fCurPosX;
1352 double y1 = pdfContext->fObjectStack.top()->asNumber()->value(); pdfConte xt->fObjectStack.pop();
1353 double x1 = pdfContext->fObjectStack.top()->asNumber()->value(); pdfConte xt->fObjectStack.pop();
1354
1355 pdfContext->fGraphicsState.fPath.cubicTo(SkDoubleToScalar(x1), SkDoubleToSca lar(y1),
1356 SkDoubleToScalar(x2), SkDoubleToScal ar(y2),
1357 SkDoubleToScalar(x3), SkDoubleToScal ar(y3));
1358
1359 pdfContext->fGraphicsState.fCurPosX = x3;
1360 pdfContext->fGraphicsState.fCurPosY = y3;
1361
1362 return kOK_PdfResult;
1363 }
1364
1365 PdfResult PdfOp_re(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** lo oper) {
1366 if (pdfContext->fGraphicsState.fPathClosed) {
1367 pdfContext->fGraphicsState.fPath.reset();
1368 pdfContext->fGraphicsState.fPathClosed = false;
1369 }
1370
1371 double height = pdfContext->fObjectStack.top()->asNumber()->value(); pd fContext->fObjectStack.pop();
1372 double width = pdfContext->fObjectStack.top()->asNumber()->value(); pd fContext->fObjectStack.pop();
1373 double y = pdfContext->fObjectStack.top()->asNumber()->value(); pd fContext->fObjectStack.pop();
1374 double x = pdfContext->fObjectStack.top()->asNumber()->value(); pd fContext->fObjectStack.pop();
1375
1376 pdfContext->fGraphicsState.fPath.addRect(SkDoubleToScalar(x), SkDoubleToScal ar(y),
1377 SkDoubleToScalar(x + width), SkDouble ToScalar(y + height));
1378
1379 pdfContext->fGraphicsState.fCurPosX = x;
1380 pdfContext->fGraphicsState.fCurPosY = y + height;
1381
1382 return kOK_PdfResult;
1383 }
1384
1385 PdfResult PdfOp_h(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** loo per) {
1386 pdfContext->fGraphicsState.fPath.close();
1387 return kOK_PdfResult;
1388 }
1389
1390 PdfResult PdfOp_fillAndStroke(PdfContext* pdfContext, SkCanvas* canvas, bool fil l, bool stroke, bool close, bool evenOdd) {
1391 SkPath path = pdfContext->fGraphicsState.fPath;
1392
1393 if (close) {
1394 path.close();
1395 }
1396
1397 canvas->setMatrix(pdfContext->fGraphicsState.fMatrix);
1398
1399 SkPaint paint;
1400
1401 SkPoint line[2];
1402 if (fill && !stroke && path.isLine(line)) {
1403 paint.setStyle(SkPaint::kStroke_Style);
1404
1405 pdfContext->fGraphicsState.applyGraphicsState(&paint, false);
1406 paint.setStrokeWidth(SkDoubleToScalar(0));
1407
1408 canvas->drawPath(path, paint);
1409 } else {
1410 if (fill) {
1411 paint.setStyle(SkPaint::kFill_Style);
1412 if (evenOdd) {
1413 path.setFillType(SkPath::kEvenOdd_FillType);
1414 }
1415
1416 pdfContext->fGraphicsState.applyGraphicsState(&paint, false);
1417
1418 canvas->drawPath(path, paint);
1419 }
1420
1421 if (stroke) {
1422 paint.setStyle(SkPaint::kStroke_Style);
1423
1424 pdfContext->fGraphicsState.applyGraphicsState(&paint, true);
1425
1426 path.setFillType(SkPath::kWinding_FillType); // reset it, just in c ase it messes up the stroke
1427 canvas->drawPath(path, paint);
1428 }
1429 }
1430
1431 pdfContext->fGraphicsState.fPath.reset();
1432 // todo zoom ... other stuff ?
1433
1434 if (pdfContext->fGraphicsState.fHasClipPathToApply) {
1435 #ifndef PDF_DEBUG_NO_CLIPING
1436 canvas->clipPath(pdfContext->fGraphicsState.fClipPath, SkRegion::kInters ect_Op, true);
1437 #endif
1438 }
1439
1440 //pdfContext->fGraphicsState.fClipPath.reset();
1441 pdfContext->fGraphicsState.fHasClipPathToApply = false;
1442
1443 return kPartial_PdfResult;
1444
1445 }
1446
1447 PdfResult PdfOp_S(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** loo per) {
1448 return PdfOp_fillAndStroke(pdfContext, canvas, false, true, false, false);
1449 }
1450
1451 PdfResult PdfOp_s(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** loo per) {
1452 return PdfOp_fillAndStroke(pdfContext, canvas, false, true, true, false);
1453 }
1454
1455 PdfResult PdfOp_F(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** loo per) {
1456 return PdfOp_fillAndStroke(pdfContext, canvas, true, false, false, false);
1457 }
1458
1459 PdfResult PdfOp_f(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** loo per) {
1460 return PdfOp_fillAndStroke(pdfContext, canvas, true, false, false, false);
1461 }
1462
1463 PdfResult PdfOp_f_star(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper* * looper) {
1464 return PdfOp_fillAndStroke(pdfContext, canvas, true, false, false, true);
1465 }
1466
1467 PdfResult PdfOp_B(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** loo per) {
1468 return PdfOp_fillAndStroke(pdfContext, canvas, true, true, false, false);
1469 }
1470
1471 PdfResult PdfOp_B_star(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper* * looper) {
1472 return PdfOp_fillAndStroke(pdfContext, canvas, true, true, false, true);
1473 }
1474
1475 PdfResult PdfOp_b(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** loo per) {
1476 return PdfOp_fillAndStroke(pdfContext, canvas, true, true, true, false);
1477 }
1478
1479 PdfResult PdfOp_b_star(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper* * looper) {
1480 return PdfOp_fillAndStroke(pdfContext, canvas, true, true, true, true);
1481 }
1482
1483 PdfResult PdfOp_n(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** loo per) {
1484 canvas->setMatrix(pdfContext->fGraphicsState.fMatrix);
1485 if (pdfContext->fGraphicsState.fHasClipPathToApply) {
1486 #ifndef PDF_DEBUG_NO_CLIPING
1487 canvas->clipPath(pdfContext->fGraphicsState.fClipPath, SkRegion::kInters ect_Op, true);
1488 #endif
1489 }
1490
1491 //pdfContext->fGraphicsState.fClipPath.reset();
1492 pdfContext->fGraphicsState.fHasClipPathToApply = false;
1493
1494 pdfContext->fGraphicsState.fPathClosed = true;
1495
1496 return kOK_PdfResult;
1497 }
1498
1499 PdfResult PdfOp_BT(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** lo oper) {
1500 pdfContext->fGraphicsState.fTextBlock = true;
1501 pdfContext->fGraphicsState.fMatrixTm = pdfContext->fGraphicsState.fMatrix;
1502 pdfContext->fGraphicsState.fMatrixTlm = pdfContext->fGraphicsState.fMatrix;
1503
1504 return kPartial_PdfResult;
1505 }
1506
1507 PdfResult PdfOp_ET(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** lo oper) {
1508 if (!pdfContext->fGraphicsState.fTextBlock) {
1509 return kIgnoreError_PdfResult;
1510 }
1511 // TODO(edisonn): anything else to be done once we are done with draw text? Like restore stack?
1512 return kPartial_PdfResult;
1513 }
1514
1515 //font size Tf Set the text font, Tf
1516 //, to font and the text font size, Tfs, to size. font is the name of a
1517 //font resource in the Fontsubdictionary of the current resource dictionary; siz e is
1518 //a number representing a scale factor. There is no initial value for either fon t or
1519 //size; they must be specified explicitly using Tf before any text is shown.
1520 PdfResult PdfOp_Tf(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** lo oper) {
1521 pdfContext->fGraphicsState.fCurFontSize = pdfContext->fObjectStack.top()->as Number()->value(); pdfContext->fObjectStack.pop();
1522 std::string fontName = pdfContext->fObjectStack.top()->asName()->value(); pdfContext->fObjectStack.pop();
1523
1524 #ifdef PDF_TRACE
1525 printf("font name: %s\n", fontName.c_str());
1526 std::string str;
1527 pdfContext->fGraphicsState.fResources->podofo()->ToString(str);
1528 printf("Print Tf Resources: %s\n", str.c_str());
1529 pdfContext->fGraphicsState.fResources->Font()->podofo()->ToString(str);
1530 printf("Print Tf Resources/Font: %s\n", str.c_str());
1531 #endif
1532
1533 SkPdfFontDictionary* fd = NULL;
1534 if (pdfContext->fGraphicsState.fResources->Font()) {
1535 SkPdfObject* objFont = pdfContext->fGraphicsState.fResources->Font()->ge t(fontName.c_str());
1536 mapFontDictionary(*objFont, &fd);
1537
1538 #ifdef PDF_TRACE
1539 objFont->podofo()->ToString(str);
1540 printf("Print Font loaded: %s\n", str.c_str());
1541 fd->podofo()->ToString(str);
1542 printf("Print Font loaded and resolved and upgraded: %s\n", str.c_str()) ;
1543 #endif
1544
1545 }
1546
1547 SkPdfFont* skfont = SkPdfFont::fontFromPdfDictionary(fd);
1548
1549 if (skfont) {
1550 pdfContext->fGraphicsState.fSkFont = skfont;
1551 }
1552
1553 return kPartial_PdfResult;
1554 }
1555
1556 PdfResult PdfOp_Tj(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** lo oper) {
1557 if (!pdfContext->fGraphicsState.fTextBlock) {
1558 // TODO(edisonn): try to recover and draw it any way?
1559 return kIgnoreError_PdfResult;
1560 }
1561
1562 PdfResult ret = DrawText(pdfContext,
1563 pdfContext->fObjectStack.top(),
1564 canvas);
1565 pdfContext->fObjectStack.pop();
1566
1567 return ret;
1568 }
1569
1570 PdfResult PdfOp_quote(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** looper) {
1571 if (!pdfContext->fGraphicsState.fTextBlock) {
1572 // TODO(edisonn): try to recover and draw it any way?
1573 return kIgnoreError_PdfResult;
1574 }
1575
1576 PdfOp_T_star(pdfContext, canvas, looper);
1577 // Do not pop, and push, just transfer the param to Tj
1578 return PdfOp_Tj(pdfContext, canvas, looper);
1579 }
1580
1581 PdfResult PdfOp_doublequote(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLo oper** looper) {
1582 if (!pdfContext->fGraphicsState.fTextBlock) {
1583 // TODO(edisonn): try to recover and draw it any way?
1584 return kIgnoreError_PdfResult;
1585 }
1586
1587 SkPdfObject* str = pdfContext->fObjectStack.top(); pdfContext->fObject Stack.pop();
1588 SkPdfObject* ac = pdfContext->fObjectStack.top(); pdfContext->fObject Stack.pop();
1589 SkPdfObject* aw = pdfContext->fObjectStack.top(); pdfContext->fObject Stack.pop();
1590
1591 pdfContext->fObjectStack.push(aw);
1592 PdfOp_Tw(pdfContext, canvas, looper);
1593
1594 pdfContext->fObjectStack.push(ac);
1595 PdfOp_Tc(pdfContext, canvas, looper);
1596
1597 pdfContext->fObjectStack.push(str);
1598 PdfOp_quote(pdfContext, canvas, looper);
1599
1600 return kPartial_PdfResult;
1601 }
1602
1603 PdfResult PdfOp_TJ(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** lo oper) {
1604 if (!pdfContext->fGraphicsState.fTextBlock) {
1605 // TODO(edisonn): try to recover and draw it any way?
1606 return kIgnoreError_PdfResult;
1607 }
1608
1609 SkPdfArray* array = pdfContext->fObjectStack.top()->asArray();
1610 pdfContext->fObjectStack.pop();
1611
1612 for( int i=0; i<static_cast<int>(array->size()); i++ )
1613 {
1614 if( (*array)[i]->asString()) {
1615 SkPdfObject* obj = (*array)[i];
1616 DrawText(pdfContext,
1617 obj,
1618 canvas);
1619 } else if ((*array)[i]->asInteger() || (*array)[i]->asNumber()) {
1620 double dx = (*array)[i]->asNumber()->value();
1621 SkMatrix matrix;
1622 matrix.setAll(SkDoubleToScalar(1),
1623 SkDoubleToScalar(0),
1624 // TODO(edisonn): use writing mode, vertical/horizonta l.
1625 SkDoubleToScalar(-dx), // amount is substracted!!!
1626 SkDoubleToScalar(0),
1627 SkDoubleToScalar(1),
1628 SkDoubleToScalar(0),
1629 SkDoubleToScalar(0),
1630 SkDoubleToScalar(0),
1631 SkDoubleToScalar(1));
1632
1633 pdfContext->fGraphicsState.fMatrixTm.preConcat(matrix);
1634 }
1635 }
1636 return kPartial_PdfResult; // TODO(edisonn): Implement fully DrawText befor e returing OK.
1637 }
1638
1639 PdfResult PdfOp_CS_cs(PdfContext* pdfContext, SkCanvas* canvas, PdfColorOperator * colorOperator) {
1640 colorOperator->fColorSpace = pdfContext->fObjectStack.top()->asName()->value (); pdfContext->fObjectStack.pop();
1641 return kOK_PdfResult;
1642 }
1643
1644 PdfResult PdfOp_CS(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** lo oper) {
1645 return PdfOp_CS_cs(pdfContext, canvas, &pdfContext->fGraphicsState.fStroking );
1646 }
1647
1648 PdfResult PdfOp_cs(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** lo oper) {
1649 return PdfOp_CS_cs(pdfContext, canvas, &pdfContext->fGraphicsState.fNonStrok ing);
1650 }
1651
1652 PdfResult PdfOp_SC_sc(PdfContext* pdfContext, SkCanvas* canvas, PdfColorOperator * colorOperator) {
1653 double c[4];
1654 pdf_int64 v[4];
1655
1656 int n = GetColorSpaceComponents(colorOperator->fColorSpace);
1657
1658 bool doubles = true;
1659 if (colorOperator->fColorSpace == "Indexed") {
1660 doubles = false;
1661 }
1662
1663 #ifdef PDF_TRACE
1664 printf("color space = %s, N = %i\n", colorOperator->fColorSpace.c_str(), n);
1665 #endif
1666
1667 for (int i = n - 1; i >= 0 ; i--) {
1668 if (doubles) {
1669 c[i] = pdfContext->fObjectStack.top()->asNumber()->value(); pdfC ontext->fObjectStack.pop();
1670 } else {
1671 v[i] = pdfContext->fObjectStack.top()->asInteger()->value(); pdfCo ntext->fObjectStack.pop();
1672 }
1673 }
1674
1675 // TODO(edisonn): Now, set that color. Only DeviceRGB supported.
1676 if (colorOperator->fColorSpace == "DeviceRGB") {
1677 colorOperator->setRGBColor(SkColorSetRGB(255*c[0], 255*c[1], 255*c[2]));
1678 }
1679 return kPartial_PdfResult;
1680 }
1681
1682 PdfResult PdfOp_SC(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** lo oper) {
1683 return PdfOp_SC_sc(pdfContext, canvas, &pdfContext->fGraphicsState.fStroking );
1684 }
1685
1686 PdfResult PdfOp_sc(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** lo oper) {
1687 return PdfOp_SC_sc(pdfContext, canvas, &pdfContext->fGraphicsState.fNonStrok ing);
1688 }
1689
1690 PdfResult PdfOp_SCN_scn(PdfContext* pdfContext, SkCanvas* canvas, PdfColorOperat or* colorOperator) {
1691 PdfString name;
1692
1693 if (pdfContext->fObjectStack.top()->asName()) {
1694 pdfContext->fObjectStack.pop();
1695 }
1696
1697 // TODO(edisonn): SCN supports more color spaces than SCN. Read and implemen t spec.
1698 PdfOp_SC_sc(pdfContext, canvas, colorOperator);
1699
1700 return kPartial_PdfResult;
1701 }
1702
1703 PdfResult PdfOp_SCN(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** l ooper) {
1704 return PdfOp_SCN_scn(pdfContext, canvas, &pdfContext->fGraphicsState.fStroki ng);
1705 }
1706
1707 PdfResult PdfOp_scn(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** l ooper) {
1708 return PdfOp_SCN_scn(pdfContext, canvas, &pdfContext->fGraphicsState.fNonStr oking);
1709 }
1710
1711 PdfResult PdfOp_G_g(PdfContext* pdfContext, SkCanvas* canvas, PdfColorOperator* colorOperator) {
1712 double gray = pdfContext->fObjectStack.top()->asNumber()->value(); pdfCo ntext->fObjectStack.pop();
1713 return kNYI_PdfResult;
1714 }
1715
1716 PdfResult PdfOp_G(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** loo per) {
1717 return PdfOp_G_g(pdfContext, canvas, &pdfContext->fGraphicsState.fStroking);
1718 }
1719
1720 PdfResult PdfOp_g(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** loo per) {
1721 return PdfOp_G_g(pdfContext, canvas, &pdfContext->fGraphicsState.fNonStrokin g);
1722 }
1723
1724 PdfResult PdfOp_RG_rg(PdfContext* pdfContext, SkCanvas* canvas, PdfColorOperator * colorOperator) {
1725 double b = pdfContext->fObjectStack.top()->asNumber()->value(); pdfConte xt->fObjectStack.pop();
1726 double g = pdfContext->fObjectStack.top()->asNumber()->value(); pdfConte xt->fObjectStack.pop();
1727 double r = pdfContext->fObjectStack.top()->asNumber()->value(); pdfConte xt->fObjectStack.pop();
1728
1729 colorOperator->fColorSpace = "DeviceRGB";
1730 colorOperator->setRGBColor(SkColorSetRGB(255*r, 255*g, 255*b));
1731 return kOK_PdfResult;
1732 }
1733
1734 PdfResult PdfOp_RG(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** lo oper) {
1735 return PdfOp_RG_rg(pdfContext, canvas, &pdfContext->fGraphicsState.fStroking );
1736 }
1737
1738 PdfResult PdfOp_rg(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** lo oper) {
1739 return PdfOp_RG_rg(pdfContext, canvas, &pdfContext->fGraphicsState.fNonStrok ing);
1740 }
1741
1742 PdfResult PdfOp_K_k(PdfContext* pdfContext, SkCanvas* canvas, PdfColorOperator* colorOperator) {
1743 // TODO(edisonn): spec has some rules about overprint, implement them.
1744 double k = pdfContext->fObjectStack.top()->asNumber()->value(); pdfConte xt->fObjectStack.pop();
1745 double y = pdfContext->fObjectStack.top()->asNumber()->value(); pdfConte xt->fObjectStack.pop();
1746 double m = pdfContext->fObjectStack.top()->asNumber()->value(); pdfConte xt->fObjectStack.pop();
1747 double c = pdfContext->fObjectStack.top()->asNumber()->value(); pdfConte xt->fObjectStack.pop();
1748
1749 colorOperator->fColorSpace = "DeviceCMYK";
1750 // TODO(edisonn): Set color.
1751 return kNYI_PdfResult;
1752 }
1753
1754 PdfResult PdfOp_K(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** loo per) {
1755 return PdfOp_K_k(pdfContext, canvas, &pdfContext->fGraphicsState.fStroking);
1756 }
1757
1758 PdfResult PdfOp_k(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** loo per) {
1759 return PdfOp_K_k(pdfContext, canvas, &pdfContext->fGraphicsState.fNonStrokin g);
1760 }
1761
1762 PdfResult PdfOp_W(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** loo per) {
1763 pdfContext->fGraphicsState.fClipPath = pdfContext->fGraphicsState.fPath;
1764 pdfContext->fGraphicsState.fHasClipPathToApply = true;
1765
1766 return kOK_PdfResult;
1767 }
1768
1769 PdfResult PdfOp_W_star(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper* * looper) {
1770 pdfContext->fGraphicsState.fClipPath = pdfContext->fGraphicsState.fPath;
1771
1772 #ifdef PDF_TRACE
1773 if (pdfContext->fGraphicsState.fClipPath.isRect(NULL)) {
1774 printf("CLIP IS RECT\n");
1775 }
1776 #endif
1777
1778 // TODO(edisonn): there seem to be a bug with clipPath of a rect with even o dd.
1779 pdfContext->fGraphicsState.fClipPath.setFillType(SkPath::kEvenOdd_FillType);
1780 pdfContext->fGraphicsState.fHasClipPathToApply = true;
1781
1782 return kPartial_PdfResult;
1783 }
1784
1785 PdfResult PdfOp_BX(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** lo oper) {
1786 *looper = new PdfCompatibilitySectionLooper();
1787 return kOK_PdfResult;
1788 }
1789
1790 PdfResult PdfOp_EX(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** lo oper) {
1791 #ifdef ASSERT_BAD_PDF_OPS
1792 SkASSERT(false); // EX must be consumed by PdfCompatibilitySectionLooper, b ut let's
1793 // have the assert when testing good pdfs.
1794 #endif
1795 return kIgnoreError_PdfResult;
1796 }
1797
1798 PdfResult PdfOp_BI(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** lo oper) {
1799 *looper = new PdfInlineImageLooper();
1800 return kOK_PdfResult;
1801 }
1802
1803 PdfResult PdfOp_ID(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** lo oper) {
1804 #ifdef ASSERT_BAD_PDF_OPS
1805 SkASSERT(false); // must be processed in inline image looper, but let's
1806 // have the assert when testing good pdfs.
1807 #endif
1808 return kIgnoreError_PdfResult;
1809 }
1810
1811 PdfResult PdfOp_EI(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** lo oper) {
1812 #ifdef ASSERT_BAD_PDF_OPS
1813 SkASSERT(false); // must be processed in inline image looper, but let's
1814 // have the assert when testing good pdfs.
1815 #endif
1816 return kIgnoreError_PdfResult;
1817 }
1818
1819 //lineWidth w Set the line width in the graphics state (see “Line Width” on page 152).
1820 PdfResult PdfOp_w(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** loo per) {
1821 double lineWidth = pdfContext->fObjectStack.top()->asNumber()->value(); pdfContext->fObjectStack.pop();
1822 pdfContext->fGraphicsState.fLineWidth = lineWidth;
1823
1824 return kOK_PdfResult;
1825 }
1826
1827 //lineCap J Set the line cap style in the graphics state (see “Line Cap Style” o n page 153).
1828 PdfResult PdfOp_J(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** loo per) {
1829 pdfContext->fObjectStack.pop();
1830 //double lineCap = pdfContext->fObjectStack.top()->asNumber()->value(); pdfContext->fObjectStack.pop();
1831
1832 return kNYI_PdfResult;
1833 }
1834
1835 //lineJoin j Set the line join style in the graphics state (see “Line Join Style ” on page 153).
1836 PdfResult PdfOp_j(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** loo per) {
1837 pdfContext->fObjectStack.pop();
1838 //double lineJoin = pdfContext->fObjectStack.top()->asNumber()->value(); pdfContext->fObjectStack.pop();
1839
1840 return kNYI_PdfResult;
1841 }
1842
1843 //miterLimit M Set the miter limit in the graphics state (see “Miter Limit” on p age 153).
1844 PdfResult PdfOp_M(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** loo per) {
1845 pdfContext->fObjectStack.pop();
1846 //double miterLimit = pdfContext->fObjectStack.top()->asNumber()->value(); pdfContext->fObjectStack.pop();
1847
1848 return kNYI_PdfResult;
1849 }
1850
1851 //dashArray dashPhase d Set the line dash pattern in the graphics state (see “Li ne Dash Pattern” on
1852 //page 155).
1853 PdfResult PdfOp_d(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** loo per) {
1854 pdfContext->fObjectStack.pop();
1855 pdfContext->fObjectStack.pop();
1856
1857 return kNYI_PdfResult;
1858 }
1859
1860 //intent ri (PDF 1.1) Set the color rendering intent in the graphics state (see “Rendering Intents” on page 197).
1861 PdfResult PdfOp_ri(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** lo oper) {
1862 pdfContext->fObjectStack.pop();
1863
1864 return kNYI_PdfResult;
1865 }
1866
1867 //flatness i Set the flatness tolerance in the graphics state (see Section 6.5.1, “Flatness
1868 //Tolerance”). flatness is a number in the range 0 to 100; a value of 0 speci-
1869 //fies the output device’s default flatness tolerance.
1870 PdfResult PdfOp_i(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** loo per) {
1871 pdfContext->fObjectStack.pop();
1872
1873 return kNYI_PdfResult;
1874 }
1875
1876 //dictName gs (PDF 1.2) Set the specified parameters in the graphics state. dictN ame is
1877 //the name of a graphics state parameter dictionary in the ExtGState subdictiona ry of the current resource dictionary (see the next section).
1878 PdfResult PdfOp_gs(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** lo oper) {
1879 std::string name = pdfContext->fObjectStack.top()->asName()->value(); pdf Context->fObjectStack.pop();
1880
1881 #ifdef PDF_TRACE
1882 std::string str;
1883 #endif
1884
1885 //Next, get the ExtGState Dictionary from the Resource Dictionary:
1886 const SkPdfDictionary* extGStateDictionary = pdfContext->fGraphicsState.fRes ources->ExtGState();
1887
1888 if (extGStateDictionary == NULL) {
1889 #ifdef PDF_TRACE
1890 printf("ExtGState is NULL!\n");
1891 #endif
1892 return kIgnoreError_PdfResult;
1893 }
1894
1895 SkPdfObject* value = extGStateDictionary->get(name.c_str());
1896
1897 #ifdef PDF_TRACE
1898 // value->ToString(str);
1899 // printf("gs object value: %s\n", str.c_str());
1900 #endif
1901
1902 SkPdfGraphicsStateDictionary* gs = NULL;
1903 mapGraphicsStateDictionary(*value, &gs);
1904
1905 // TODO(edisonn): now load all those properties in graphic state.
1906 if (gs == NULL) {
1907 return kIgnoreError_PdfResult;
1908 }
1909
1910 if (gs->has_CA()) {
1911 pdfContext->fGraphicsState.fStroking.fOpacity = gs->CA();
1912 }
1913
1914 if (gs->has_ca()) {
1915 pdfContext->fGraphicsState.fNonStroking.fOpacity = gs->ca();
1916 }
1917
1918 if (gs->has_LW()) {
1919 pdfContext->fGraphicsState.fLineWidth = gs->LW();
1920 }
1921
1922
1923
1924 return kNYI_PdfResult;
1925 }
1926
1927 //charSpace Tc Set the character spacing, Tc
1928 //, to charSpace, which is a number expressed in unscaled text space units. Char acter spacing is used by the Tj, TJ, and ' operators.
1929 //Initial value: 0.
1930 PdfResult PdfOp_Tc(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** lo oper) {
1931 double charSpace = pdfContext->fObjectStack.top()->asNumber()->value(); pdfContext->fObjectStack.pop();
1932 pdfContext->fGraphicsState.fCharSpace = charSpace;
1933
1934 return kOK_PdfResult;
1935 }
1936
1937 //wordSpace Tw Set the word spacing, T
1938 //w
1939 //, to wordSpace, which is a number expressed in unscaled
1940 //text space units. Word spacing is used by the Tj, TJ, and ' operators. Initial
1941 //value: 0.
1942 PdfResult PdfOp_Tw(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** lo oper) {
1943 double wordSpace = pdfContext->fObjectStack.top()->asNumber()->value(); pdfContext->fObjectStack.pop();
1944 pdfContext->fGraphicsState.fWordSpace = wordSpace;
1945
1946 return kOK_PdfResult;
1947 }
1948
1949 //scale Tz Set the horizontal scaling, Th
1950 //, to (scale ˜ 100). scale is a number specifying the
1951 //percentage of the normal width. Initial value: 100 (normal width).
1952 PdfResult PdfOp_Tz(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** lo oper) {
1953 double scale = pdfContext->fObjectStack.top()->asNumber()->value(); pdfC ontext->fObjectStack.pop();
1954
1955 return kNYI_PdfResult;
1956 }
1957
1958 //render Tr Set the text rendering mode, T
1959 //mode, to render, which is an integer. Initial value: 0.
1960 PdfResult PdfOp_Tr(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** lo oper) {
1961 double render = pdfContext->fObjectStack.top()->asNumber()->value(); pdf Context->fObjectStack.pop();
1962
1963 return kNYI_PdfResult;
1964 }
1965 //rise Ts Set the text rise, Trise, to rise, which is a number expressed in unsc aled text space
1966 //units. Initial value: 0.
1967 PdfResult PdfOp_Ts(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** lo oper) {
1968 double rise = pdfContext->fObjectStack.top()->asNumber()->value(); pdfCo ntext->fObjectStack.pop();
1969
1970 return kNYI_PdfResult;
1971 }
1972
1973 //wx wy d0
1974 PdfResult PdfOp_d0(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** lo oper) {
1975 pdfContext->fObjectStack.pop();
1976 pdfContext->fObjectStack.pop();
1977
1978 return kNYI_PdfResult;
1979 }
1980
1981 //wx wy llx lly urx ury d1
1982 PdfResult PdfOp_d1(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** lo oper) {
1983 pdfContext->fObjectStack.pop();
1984 pdfContext->fObjectStack.pop();
1985 pdfContext->fObjectStack.pop();
1986 pdfContext->fObjectStack.pop();
1987 pdfContext->fObjectStack.pop();
1988 pdfContext->fObjectStack.pop();
1989
1990 return kNYI_PdfResult;
1991 }
1992
1993 //name sh
1994 PdfResult PdfOp_sh(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** lo oper) {
1995 pdfContext->fObjectStack.pop();
1996
1997 return kNYI_PdfResult;
1998 }
1999
2000 //name Do
2001 PdfResult PdfOp_Do(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** lo oper) {
2002 std::string name = pdfContext->fObjectStack.top()->asName()->value(); pdf Context->fObjectStack.pop();
2003
2004 SkPdfDictionary* xObject = pdfContext->fGraphicsState.fResources->XObject() ;
2005
2006 if (xObject == NULL) {
2007 #ifdef PDF_TRACE
2008 printf("XObject is NULL!\n");
2009 #endif
2010 return kIgnoreError_PdfResult;
2011 }
2012
2013 SkPdfObject* value = xObject->get(name.c_str());
2014
2015 #ifdef PDF_TRACE
2016 // value->ToString(str);
2017 // printf("Do object value: %s\n", str.c_str());
2018 #endif
2019
2020 return doXObject(pdfContext, canvas, *value);
2021 }
2022
2023 //tag MP Designate a marked-content point. tag is a name object indicating the r ole or
2024 //significance of the point.
2025 PdfResult PdfOp_MP(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** lo oper) {
2026 pdfContext->fObjectStack.pop();
2027
2028 return kNYI_PdfResult;
2029 }
2030
2031 //tag properties DP Designate a marked-content point with an associated property list. tag is a
2032 //name object indicating the role or significance of the point; properties is
2033 //either an inline dictionary containing the property list or a name object
2034 //associated with it in the Properties subdictionary of the current resource
2035 //dictionary (see Section 9.5.1, “Property Lists”).
2036 PdfResult PdfOp_DP(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** lo oper) {
2037 pdfContext->fObjectStack.pop();
2038 pdfContext->fObjectStack.pop();
2039
2040 return kNYI_PdfResult;
2041 }
2042
2043 //tag BMC Begin a marked-content sequence terminated by a balancing EMC operator .
2044 //tag is a name object indicating the role or significance of the sequence.
2045 PdfResult PdfOp_BMC(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** l ooper) {
2046 pdfContext->fObjectStack.pop();
2047
2048 return kNYI_PdfResult;
2049 }
2050
2051 //tag properties BDC Begin a marked-content sequence with an associated property list, terminated
2052 //by a balancing EMCoperator. tag is a name object indicating the role or signif icance of the sequence; propertiesis either an inline dictionary containing the
2053 //property list or a name object associated with it in the Properties subdiction ary of the current resource dictionary (see Section 9.5.1, “Property Lists”).
2054 PdfResult PdfOp_BDC(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** l ooper) {
2055 pdfContext->fObjectStack.pop();
2056 pdfContext->fObjectStack.pop();
2057
2058 return kNYI_PdfResult;
2059 }
2060
2061 //— EMC End a marked-content sequence begun by a BMC or BDC operator.
2062 PdfResult PdfOp_EMC(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** l ooper) {
2063 return kNYI_PdfResult;
2064 }
2065
2066 void initPdfOperatorRenderes() {
2067 static bool gInitialized = false;
2068 if (gInitialized) {
2069 return;
2070 }
2071
2072 gPdfOps["q"] = PdfOp_q;
2073 gPdfOps["Q"] = PdfOp_Q;
2074 gPdfOps["cm"] = PdfOp_cm;
2075
2076 gPdfOps["TD"] = PdfOp_TD;
2077 gPdfOps["Td"] = PdfOp_Td;
2078 gPdfOps["Tm"] = PdfOp_Tm;
2079 gPdfOps["T*"] = PdfOp_T_star;
2080
2081 gPdfOps["m"] = PdfOp_m;
2082 gPdfOps["l"] = PdfOp_l;
2083 gPdfOps["c"] = PdfOp_c;
2084 gPdfOps["v"] = PdfOp_v;
2085 gPdfOps["y"] = PdfOp_y;
2086 gPdfOps["h"] = PdfOp_h;
2087 gPdfOps["re"] = PdfOp_re;
2088
2089 gPdfOps["S"] = PdfOp_S;
2090 gPdfOps["s"] = PdfOp_s;
2091 gPdfOps["f"] = PdfOp_f;
2092 gPdfOps["F"] = PdfOp_F;
2093 gPdfOps["f*"] = PdfOp_f_star;
2094 gPdfOps["B"] = PdfOp_B;
2095 gPdfOps["B*"] = PdfOp_B_star;
2096 gPdfOps["b"] = PdfOp_b;
2097 gPdfOps["b*"] = PdfOp_b_star;
2098 gPdfOps["n"] = PdfOp_n;
2099
2100 gPdfOps["BT"] = PdfOp_BT;
2101 gPdfOps["ET"] = PdfOp_ET;
2102
2103 gPdfOps["Tj"] = PdfOp_Tj;
2104 gPdfOps["'"] = PdfOp_quote;
2105 gPdfOps["\""] = PdfOp_doublequote;
2106 gPdfOps["TJ"] = PdfOp_TJ;
2107
2108 gPdfOps["CS"] = PdfOp_CS;
2109 gPdfOps["cs"] = PdfOp_cs;
2110 gPdfOps["SC"] = PdfOp_SC;
2111 gPdfOps["SCN"] = PdfOp_SCN;
2112 gPdfOps["sc"] = PdfOp_sc;
2113 gPdfOps["scn"] = PdfOp_scn;
2114 gPdfOps["G"] = PdfOp_G;
2115 gPdfOps["g"] = PdfOp_g;
2116 gPdfOps["RG"] = PdfOp_RG;
2117 gPdfOps["rg"] = PdfOp_rg;
2118 gPdfOps["K"] = PdfOp_K;
2119 gPdfOps["k"] = PdfOp_k;
2120
2121 gPdfOps["W"] = PdfOp_W;
2122 gPdfOps["W*"] = PdfOp_W_star;
2123
2124 gPdfOps["BX"] = PdfOp_BX;
2125 gPdfOps["EX"] = PdfOp_EX;
2126
2127 gPdfOps["BI"] = PdfOp_BI;
2128 gPdfOps["ID"] = PdfOp_ID;
2129 gPdfOps["EI"] = PdfOp_EI;
2130
2131 gPdfOps["w"] = PdfOp_w;
2132 gPdfOps["J"] = PdfOp_J;
2133 gPdfOps["j"] = PdfOp_j;
2134 gPdfOps["M"] = PdfOp_M;
2135 gPdfOps["d"] = PdfOp_d;
2136 gPdfOps["ri"] = PdfOp_ri;
2137 gPdfOps["i"] = PdfOp_i;
2138 gPdfOps["gs"] = PdfOp_gs;
2139
2140 gPdfOps["Tc"] = PdfOp_Tc;
2141 gPdfOps["Tw"] = PdfOp_Tw;
2142 gPdfOps["Tz"] = PdfOp_Tz;
2143 gPdfOps["TL"] = PdfOp_TL;
2144 gPdfOps["Tf"] = PdfOp_Tf;
2145 gPdfOps["Tr"] = PdfOp_Tr;
2146 gPdfOps["Ts"] = PdfOp_Ts;
2147
2148 gPdfOps["d0"] = PdfOp_d0;
2149 gPdfOps["d1"] = PdfOp_d1;
2150
2151 gPdfOps["sh"] = PdfOp_sh;
2152
2153 gPdfOps["Do"] = PdfOp_Do;
2154
2155 gPdfOps["MP"] = PdfOp_MP;
2156 gPdfOps["DP"] = PdfOp_DP;
2157 gPdfOps["BMC"] = PdfOp_BMC;
2158 gPdfOps["BDC"] = PdfOp_BDC;
2159 gPdfOps["EMC"] = PdfOp_EMC;
2160
2161 gInitialized = true;
2162 }
2163
2164 class InitPdfOps {
2165 public:
2166 InitPdfOps() {
2167 initPdfOperatorRenderes();
2168 }
2169 };
2170
2171 InitPdfOps gInitPdfOps;
2172
2173 void reportPdfRenderStats() {
2174 std::map<std::string, int>::iterator iter;
2175
2176 for (int i = 0 ; i < kCount_PdfResult; i++) {
2177 for (iter = gRenderStats[i].begin(); iter != gRenderStats[i].end(); ++it er) {
2178 printf("%s: %s -> count %i\n", gRenderStatsNames[i], iter->first.c_s tr(), iter->second);
2179 }
2180 }
2181 }
2182
2183 PdfResult PdfMainLooper::consumeToken(PdfToken& token) {
2184 if (token.fType == kKeyword_TokenType)
2185 {
2186 // TODO(edisonn): log trace flag (verbose, error, info, warning, ...)
2187 PdfOperatorRenderer pdfOperatorRenderer = gPdfOps[token.fKeyword];
2188 if (pdfOperatorRenderer) {
2189 // caller, main work is done by pdfOperatorRenderer(...)
2190 PdfTokenLooper* childLooper = NULL;
2191 gRenderStats[pdfOperatorRenderer(fPdfContext, fCanvas, &childLooper) ][token.fKeyword]++;
2192
2193 if (childLooper) {
2194 childLooper->setUp(this);
2195 childLooper->loop();
2196 delete childLooper;
2197 }
2198 } else {
2199 gRenderStats[kUnsupported_PdfResult][token.fKeyword]++;
2200 }
2201 }
2202 else if (token.fType == kObject_TokenType)
2203 {
2204 fPdfContext->fObjectStack.push( token.fObject );
2205 }
2206 else if ( token.fType == kImageData_TokenType) {
2207 // TODO(edisonn): implement inline image.
2208 }
2209 else {
2210 return kIgnoreError_PdfResult;
2211 }
2212 return kOK_PdfResult;
2213 }
2214
2215 void PdfMainLooper::loop() {
2216 PdfToken token;
2217 while (readToken(fTokenizer, &token)) {
2218 consumeToken(token);
2219 }
2220 }
2221
2222 PdfResult PdfInlineImageLooper::consumeToken(PdfToken& token) {
2223 //pdfContext.fInlineImage.fKeyValuePairs[key] = value;
2224 return kNYI_PdfResult;
2225 }
2226
2227 void PdfInlineImageLooper::loop() {
2228 PdfToken token;
2229 while (readToken(fTokenizer, &token)) {
2230 if (token.fType == kKeyword_TokenType && strcmp(token.fKeyword, "BX") == 0) {
2231 PdfTokenLooper* looper = new PdfCompatibilitySectionLooper();
2232 looper->setUp(this);
2233 looper->loop();
2234 } else {
2235 if (token.fType == kKeyword_TokenType && strcmp(token.fKeyword, "EI" ) == 0) {
2236 done();
2237 return;
2238 }
2239
2240 consumeToken(token);
2241 }
2242 }
2243 // TODO(edisonn): report error/warning, EOF without EI.
2244 }
2245
2246 PdfResult PdfInlineImageLooper::done() {
2247
2248 // TODO(edisonn): long to short names
2249 // TODO(edisonn): set properties in a map
2250 // TODO(edisonn): extract bitmap stream, check if PoDoFo has public utilitie s to uncompress
2251 // the stream.
2252
2253 SkBitmap bitmap;
2254 setup_bitmap(&bitmap, 50, 50, SK_ColorRED);
2255
2256 // TODO(edisonn): matrix use.
2257 // Draw dummy red square, to show the prezence of the inline image.
2258 fCanvas->drawBitmap(bitmap,
2259 SkDoubleToScalar(0),
2260 SkDoubleToScalar(0),
2261 NULL);
2262 return kNYI_PdfResult;
2263 }
2264
2265 PdfResult PdfCompatibilitySectionLooper::consumeToken(PdfToken& token) {
2266 return fParent->consumeToken(token);
2267 }
2268
2269 void PdfCompatibilitySectionLooper::loop() {
2270 // TODO(edisonn): save stacks position, or create a new stack?
2271 // TODO(edisonn): what happens if we pop out more variables then when we sta rted?
2272 // restore them? fail? We could create a new operands stack for every new BX /EX section,
2273 // pop-ing too much will not affect outside the section.
2274 PdfToken token;
2275 while (readToken(fTokenizer, &token)) {
2276 if (token.fType == kKeyword_TokenType && strcmp(token.fKeyword, "BX") == 0) {
2277 PdfTokenLooper* looper = new PdfCompatibilitySectionLooper();
2278 looper->setUp(this);
2279 looper->loop();
2280 delete looper;
2281 } else {
2282 if (token.fType == kKeyword_TokenType && strcmp(token.fKeyword, "EX" ) == 0) break;
2283 fParent->consumeToken(token);
2284 }
2285 }
2286 // TODO(edisonn): restore stack.
2287 }
2288
2289 // TODO(edisonn): fix PoDoFo load ~/crashing/Shading.pdf
2290 // TODO(edisonn): Add API for Forms viewing and editing
2291 // e.g. SkBitmap getPage(int page);
2292 // int formsCount();
2293 // SkForm getForm(int formID); // SkForm(SkRect, .. other data)
2294 // TODO (edisonn): Add intend when loading pdf, for example: for viewing, parsin g all content, ...
2295 // if we load the first page, and we zoom to fit to screen horizontally, then lo ad only those
2296 // resources needed, so the preview is fast.
2297 // TODO (edisonn): hide parser/tokenizer behind and interface and a query langua ge, and resolve
2298 // references automatically.
2299
2300 bool SkPdfViewer::load(const SkString inputFileName, SkPicture* out) {
2301 try
2302 {
2303 std::cout << "Init: " << inputFileName.c_str() << std::endl;
2304
2305 SkPdfDoc doc(inputFileName.c_str());
2306 if (!doc.pages())
2307 {
2308 std::cout << "ERROR: Empty Document" << inputFileName.c_str() << std ::endl;
2309 return false;
2310 } else {
2311
2312 for (int pn = 0; pn < doc.pages(); ++pn) {
2313 // TODO(edisonn): implement inheritance properties as per PDF sp ec
2314 //SkRect rect = page->MediaBox();
2315 SkRect rect = doc.MediaBox(pn);
2316
2317 #ifdef PDF_TRACE
2318 printf("Page Width: %f, Page Height: %f\n", SkScalarToDouble(rec t.width()), SkScalarToDouble(rect.height()));
2319 #endif
2320
2321 // TODO(edisonn): page->GetCropBox(), page->GetTrimBox() ... how to use?
2322
2323 SkBitmap bitmap;
2324 #ifdef PDF_DEBUG_3X
2325 setup_bitmap(&bitmap, 3 * (int)SkScalarToDouble(rect.width()), 3 * (int)SkScalarToDouble(rect.height()));
2326 #else
2327 setup_bitmap(&bitmap, (int)SkScalarToDouble(rect.width()), (int) SkScalarToDouble(rect.height()));
2328 #endif
2329 SkAutoTUnref<SkDevice> device(SkNEW_ARGS(SkDevice, (bitmap)));
2330 SkCanvas canvas(device);
2331
2332 gDumpBitmap = &bitmap;
2333
2334 doc.drawPage(pn, &canvas);
2335
2336 SkString out;
2337 out.appendf("%s-%i.png", inputFileName.c_str(), pn);
2338 SkImageEncoder::EncodeFile(out.c_str(), bitmap, SkImageEncoder:: kPNG_Type, 100);
2339 }
2340 return true;
2341 }
2342 }
2343 catch( PdfError & e )
2344 {
2345 std::cout << "ERROR: PDF can't be parsed!" << inputFileName.c_str() << s td::endl;
2346 return false;
2347 }
2348
2349 return true;
2350 }
2351
2352
OLDNEW
« no previous file with comments | « experimental/PdfViewer/SkPdfParser.h ('k') | experimental/PdfViewer/SkPdfUtils.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698