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
24extern "C" SkBitmap* gDumpBitmap;
25extern "C" SkCanvas* gDumpCanvas;
26SkBitmap* gDumpBitmap = NULL;
27SkCanvas* gDumpCanvas = NULL;
28static int gReadOp;
29static int gOpCounter;
30static SkString gLastKeyword;
31#endif  // PDF_TRACE_DIFF_IN_PNG
32
33void 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