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 "SkPdfDiffEncoder.h"
9 #include "SkPdfNativeTokenizer.h"
10 
11 #ifdef PDF_TRACE_DIFF_IN_PNG
12 #include "SkBitmap.h"
13 #include "SkBitmapDevice.h"
14 #include "SkCanvas.h"
15 #include "SkClipStack.h"
16 #include "SkColor.h"
17 #include "SkImageEncoder.h"
18 #include "SkPaint.h"
19 #include "SkPath.h"
20 #include "SkRegion.h"
21 #include "SkScalar.h"
22 #include "SkString.h"
23 
24 extern "C" SkBitmap* gDumpBitmap;
25 extern "C" SkCanvas* gDumpCanvas;
26 SkBitmap* gDumpBitmap = NULL;
27 SkCanvas* gDumpCanvas = NULL;
28 static int gReadOp;
29 static int gOpCounter;
30 static SkString gLastKeyword;
31 #endif  // PDF_TRACE_DIFF_IN_PNG
32 
WriteToFile(PdfToken * token)33 void SkPdfDiffEncoder::WriteToFile(PdfToken* token) {
34 #ifdef PDF_TRACE_DIFF_IN_PNG
35     gReadOp++;
36     gOpCounter++;
37 
38     // Only attempt to write if the dump bitmap and canvas are non NULL. They are set by
39     // pdf_viewer_main.cpp
40     if (NULL == gDumpBitmap || NULL == gDumpCanvas) {
41         return;
42     }
43 
44     // TODO(edisonn): this code is used to make a step by step history of all the draw operations
45     // so we could find the step where something is wrong.
46     if (!gLastKeyword.isEmpty()) {
47         gDumpCanvas->flush();
48 
49         // Copy the existing drawing. Then we will draw the difference caused by this command,
50         // highlighted with a blue border.
51         SkBitmap bitmap;
52         if (gDumpBitmap->copyTo(&bitmap, SkBitmap::kARGB_8888_Config)) {
53 
54             SkAutoTUnref<SkBaseDevice> device(SkNEW_ARGS(SkBitmapDevice, (bitmap)));
55             SkCanvas canvas(device);
56 
57             // draw context stuff here
58             SkPaint blueBorder;
59             blueBorder.setColor(SK_ColorBLUE);
60             blueBorder.setStyle(SkPaint::kStroke_Style);
61             blueBorder.setTextSize(SkDoubleToScalar(20));
62 
63             SkString str;
64 
65             const SkClipStack* clipStack = gDumpCanvas->getClipStack();
66             if (clipStack) {
67                 SkClipStack::Iter iter(*clipStack, SkClipStack::Iter::kBottom_IterStart);
68                 const SkClipStack::Element* elem;
69                 double y = 0;
70                 int total = 0;
71                 while ((elem = iter.next()) != NULL) {
72                     total++;
73                     y += 30;
74 
75                     switch (elem->getType()) {
76                         case SkClipStack::Element::kRect_Type:
77                             canvas.drawRect(elem->getRect(), blueBorder);
78                             canvas.drawText("Rect Clip", strlen("Rect Clip"),
79                                             SkDoubleToScalar(10), SkDoubleToScalar(y), blueBorder);
80                             break;
81                         case SkClipStack::Element::kPath_Type:
82                             canvas.drawPath(elem->getPath(), blueBorder);
83                             canvas.drawText("Path Clip", strlen("Path Clip"),
84                                             SkDoubleToScalar(10), SkDoubleToScalar(y), blueBorder);
85                             break;
86                         case SkClipStack::Element::kEmpty_Type:
87                             canvas.drawText("Empty Clip!!!", strlen("Empty Clip!!!"),
88                                             SkDoubleToScalar(10), SkDoubleToScalar(y), blueBorder);
89                             break;
90                         default:
91                             canvas.drawText("Unknown Clip!!!", strlen("Unknown Clip!!!"),
92                                             SkDoubleToScalar(10), SkDoubleToScalar(y), blueBorder);
93                             break;
94                     }
95                 }
96 
97                 y += 30;
98                 str.printf("Number of clips in stack: %i", total);
99                 canvas.drawText(str.c_str(), str.size(),
100                                 SkDoubleToScalar(10), SkDoubleToScalar(y), blueBorder);
101             }
102 
103             const SkRegion& clipRegion = gDumpCanvas->getTotalClip();
104             SkPath clipPath;
105             if (clipRegion.getBoundaryPath(&clipPath)) {
106                 SkPaint redBorder;
107                 redBorder.setColor(SK_ColorRED);
108                 redBorder.setStyle(SkPaint::kStroke_Style);
109                 canvas.drawPath(clipPath, redBorder);
110             }
111 
112             canvas.flush();
113 
114             SkString out;
115 
116             // TODO(edisonn): overlay on top of image inf about the clip , grafic state, the stack
117 
118             out.appendf("/tmp/log_step_by_step/step-%i-%s.png", gOpCounter, gLastKeyword.c_str());
119 
120             SkImageEncoder::EncodeFile(out.c_str(), bitmap, SkImageEncoder::kPNG_Type, 100);
121         }
122     }
123 
124     if (token->fType == kKeyword_TokenType && token->fKeyword && token->fKeywordLength > 0) {
125         gLastKeyword.set(token->fKeyword, token->fKeywordLength);
126     } else {
127         gLastKeyword.reset();
128     }
129 #endif
130 }
131