15092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com/*
25092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com * Copyright 2013 Google Inc.
35092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com *
45092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com * Use of this source code is governed by a BSD-style license that can be
55092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com * found in the LICENSE file.
65092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com */
75092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com
85092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com#include "SkPdfDiffEncoder.h"
95092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com#include "SkPdfNativeTokenizer.h"
105092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com
115092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com#ifdef PDF_TRACE_DIFF_IN_PNG
125092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com#include "SkBitmap.h"
135092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com#include "SkBitmapDevice.h"
145092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com#include "SkCanvas.h"
155092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com#include "SkClipStack.h"
165092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com#include "SkColor.h"
175092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com#include "SkImageEncoder.h"
185092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com#include "SkPaint.h"
195092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com#include "SkPath.h"
205092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com#include "SkRegion.h"
215092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com#include "SkScalar.h"
225092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com#include "SkString.h"
235092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com
245092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.comextern "C" SkBitmap* gDumpBitmap;
255092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.comextern "C" SkCanvas* gDumpCanvas;
265092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.comSkBitmap* gDumpBitmap = NULL;
275092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.comSkCanvas* gDumpCanvas = NULL;
285092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.comstatic int gReadOp;
295092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.comstatic int gOpCounter;
305092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.comstatic SkString gLastKeyword;
315092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com#endif  // PDF_TRACE_DIFF_IN_PNG
325092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com
335092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.comvoid SkPdfDiffEncoder::WriteToFile(PdfToken* token) {
345092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com#ifdef PDF_TRACE_DIFF_IN_PNG
355092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com    gReadOp++;
365092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com    gOpCounter++;
375092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com
385092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com    // Only attempt to write if the dump bitmap and canvas are non NULL. They are set by
395092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com    // pdf_viewer_main.cpp
405092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com    if (NULL == gDumpBitmap || NULL == gDumpCanvas) {
415092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com        return;
425092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com    }
435092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com
445092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com    // TODO(edisonn): this code is used to make a step by step history of all the draw operations
455092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com    // so we could find the step where something is wrong.
465092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com    if (!gLastKeyword.isEmpty()) {
475092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com        gDumpCanvas->flush();
485092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com
495092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com        // Copy the existing drawing. Then we will draw the difference caused by this command,
505092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com        // highlighted with a blue border.
515092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com        SkBitmap bitmap;
525092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com        if (gDumpBitmap->copyTo(&bitmap, SkBitmap::kARGB_8888_Config)) {
535092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com
545092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com            SkAutoTUnref<SkBaseDevice> device(SkNEW_ARGS(SkBitmapDevice, (bitmap)));
555092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com            SkCanvas canvas(device);
565092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com
575092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com            // draw context stuff here
585092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com            SkPaint blueBorder;
595092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com            blueBorder.setColor(SK_ColorBLUE);
605092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com            blueBorder.setStyle(SkPaint::kStroke_Style);
615092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com            blueBorder.setTextSize(SkDoubleToScalar(20));
625092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com
635092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com            SkString str;
645092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com
655092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com            const SkClipStack* clipStack = gDumpCanvas->getClipStack();
665092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com            if (clipStack) {
675092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com                SkClipStack::Iter iter(*clipStack, SkClipStack::Iter::kBottom_IterStart);
685092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com                const SkClipStack::Element* elem;
695092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com                double y = 0;
705092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com                int total = 0;
715092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com                while ((elem = iter.next()) != NULL) {
725092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com                    total++;
735092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com                    y += 30;
745092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com
755092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com                    switch (elem->getType()) {
765092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com                        case SkClipStack::Element::kRect_Type:
775092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com                            canvas.drawRect(elem->getRect(), blueBorder);
785092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com                            canvas.drawText("Rect Clip", strlen("Rect Clip"),
795092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com                                            SkDoubleToScalar(10), SkDoubleToScalar(y), blueBorder);
805092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com                            break;
815092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com                        case SkClipStack::Element::kPath_Type:
825092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com                            canvas.drawPath(elem->getPath(), blueBorder);
835092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com                            canvas.drawText("Path Clip", strlen("Path Clip"),
845092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com                                            SkDoubleToScalar(10), SkDoubleToScalar(y), blueBorder);
855092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com                            break;
865092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com                        case SkClipStack::Element::kEmpty_Type:
875092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com                            canvas.drawText("Empty Clip!!!", strlen("Empty Clip!!!"),
885092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com                                            SkDoubleToScalar(10), SkDoubleToScalar(y), blueBorder);
895092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com                            break;
905092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com                        default:
915092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com                            canvas.drawText("Unknown Clip!!!", strlen("Unknown Clip!!!"),
925092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com                                            SkDoubleToScalar(10), SkDoubleToScalar(y), blueBorder);
935092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com                            break;
945092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com                    }
955092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com                }
965092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com
975092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com                y += 30;
985092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com                str.printf("Number of clips in stack: %i", total);
995092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com                canvas.drawText(str.c_str(), str.size(),
1005092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com                                SkDoubleToScalar(10), SkDoubleToScalar(y), blueBorder);
1015092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com            }
1025092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com
1035092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com            const SkRegion& clipRegion = gDumpCanvas->getTotalClip();
1045092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com            SkPath clipPath;
1055092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com            if (clipRegion.getBoundaryPath(&clipPath)) {
1065092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com                SkPaint redBorder;
1075092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com                redBorder.setColor(SK_ColorRED);
1085092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com                redBorder.setStyle(SkPaint::kStroke_Style);
1095092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com                canvas.drawPath(clipPath, redBorder);
1105092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com            }
1115092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com
1125092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com            canvas.flush();
1135092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com
1145092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com            SkString out;
1155092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com
1165092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com            // TODO(edisonn): overlay on top of image inf about the clip , grafic state, the stack
1175092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com
1185092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com            out.appendf("/tmp/log_step_by_step/step-%i-%s.png", gOpCounter, gLastKeyword.c_str());
1195092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com
1205092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com            SkImageEncoder::EncodeFile(out.c_str(), bitmap, SkImageEncoder::kPNG_Type, 100);
1215092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com        }
1225092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com    }
1235092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com
1245092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com    if (token->fType == kKeyword_TokenType && token->fKeyword && token->fKeywordLength > 0) {
1255092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com        gLastKeyword.set(token->fKeyword, token->fKeywordLength);
1265092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com    } else {
1275092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com        gLastKeyword.reset();
1285092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com    }
1295092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com#endif
1305092adc5461a7c5cb3e1fad01be2174c3f4a0c46scroggo@google.com}
131