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