1/*
2 * Copyright 2014 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 <stdio.h>
9
10#include "SkRecord.h"
11#include "SkRecordDraw.h"
12
13#include "DumpRecord.h"
14#include "Timer.h"
15
16namespace {
17
18class Dumper {
19public:
20    explicit Dumper(SkCanvas* canvas, int count, bool timeWithCommand)
21        : fDigits(0)
22        , fIndent(0)
23        , fIndex(0)
24        , fDraw(canvas)
25        , fTimeWithCommand(timeWithCommand) {
26        while (count > 0) {
27            count /= 10;
28            fDigits++;
29        }
30    }
31
32    template <typename T>
33    void operator()(const T& command) {
34        Timer timer;
35        timer.start();
36            fDraw(command);
37        timer.end();
38
39        this->print(command, timer.fCpu);
40    }
41
42    void operator()(const SkRecords::NoOp&) {
43        // Move on without printing anything.
44    }
45
46    template <typename T>
47    void print(const T& command, double time) {
48        this->printNameAndTime(command, time);
49    }
50
51    void print(const SkRecords::Restore& command, double time) {
52        --fIndent;
53        this->printNameAndTime(command, time);
54    }
55
56    void print(const SkRecords::Save& command, double time) {
57        this->printNameAndTime(command, time);
58        ++fIndent;
59    }
60
61    void print(const SkRecords::SaveLayer& command, double time) {
62        this->printNameAndTime(command, time);
63        ++fIndent;
64    }
65
66private:
67    template <typename T>
68    void printNameAndTime(const T& command, double time) {
69        if (!fTimeWithCommand) {
70            printf("%6.1f ", time * 1000);
71        }
72        printf("%*d ", fDigits, fIndex++);
73        for (int i = 0; i < fIndent; i++) {
74            putchar('\t');
75        }
76        if (fTimeWithCommand) {
77            printf("%6.1f ", time * 1000);
78        }
79        puts(NameOf(command));
80    }
81
82    template <typename T>
83    static const char* NameOf(const T&) {
84    #define CASE(U) case SkRecords::U##_Type: return #U;
85        switch(T::kType) { SK_RECORD_TYPES(CASE); }
86    #undef CASE
87        SkDEBUGFAIL("Unknown T");
88        return "Unknown T";
89    }
90
91    static const char* NameOf(const SkRecords::SaveLayer&) {
92        return "\x1b[31;1mSaveLayer\x1b[0m";  // Bold red.
93    }
94
95    int fDigits;
96    int fIndent;
97    int fIndex;
98    SkRecords::Draw fDraw;
99    const bool fTimeWithCommand;
100};
101
102}  // namespace
103
104void DumpRecord(const SkRecord& record,
105                  SkCanvas* canvas,
106                  bool timeWithCommand) {
107    Dumper dumper(canvas, record.count(), timeWithCommand);
108    for (unsigned i = 0; i < record.count(); i++) {
109        record.visit<void>(i, dumper);
110    }
111}
112