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 "SkTime.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, nullptr, nullptr, 0, nullptr)
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        auto start = SkTime::GetNSecs();
35        fDraw(command);
36        this->print(command, SkTime::GetNSecs() - start);
37    }
38
39    void operator()(const SkRecords::NoOp&) {
40        // Move on without printing anything.
41    }
42
43    template <typename T>
44    void print(const T& command, double ns) {
45        this->printNameAndTime(command, ns);
46    }
47
48    void print(const SkRecords::Restore& command, double ns) {
49        --fIndent;
50        this->printNameAndTime(command, ns);
51    }
52
53    void print(const SkRecords::Save& command, double ns) {
54        this->printNameAndTime(command, ns);
55        ++fIndent;
56    }
57
58    void print(const SkRecords::SaveLayer& command, double ns) {
59        this->printNameAndTime(command, ns);
60        ++fIndent;
61    }
62
63    void print(const SkRecords::DrawPicture& command, double ns) {
64        this->printNameAndTime(command, ns);
65
66        if (auto bp = command.picture->asSkBigPicture()) {
67            ++fIndent;
68
69            const SkRecord& record = *bp->record();
70            for (int i = 0; i < record.count(); i++) {
71                record.visit<void>(i, *this);
72            }
73
74            --fIndent;
75        }
76    }
77
78private:
79    template <typename T>
80    void printNameAndTime(const T& command, double ns) {
81        int us = (int)(ns * 1e-3);
82        if (!fTimeWithCommand) {
83            printf("%6dus  ", us);
84        }
85        printf("%*d ", fDigits, fIndex++);
86        for (int i = 0; i < fIndent; i++) {
87            printf("    ");
88        }
89        if (fTimeWithCommand) {
90            printf("%6dus  ", us);
91        }
92        puts(NameOf(command));
93    }
94
95    template <typename T>
96    static const char* NameOf(const T&) {
97    #define CASE(U) case SkRecords::U##_Type: return #U;
98        switch(T::kType) { SK_RECORD_TYPES(CASE); }
99    #undef CASE
100        SkDEBUGFAIL("Unknown T");
101        return "Unknown T";
102    }
103
104    static const char* NameOf(const SkRecords::SaveLayer&) {
105        return "\x1b[31;1mSaveLayer\x1b[0m";  // Bold red.
106    }
107
108    int fDigits;
109    int fIndent;
110    int fIndex;
111    SkRecords::Draw fDraw;
112    const bool fTimeWithCommand;
113};
114
115}  // namespace
116
117void DumpRecord(const SkRecord& record,
118                  SkCanvas* canvas,
119                  bool timeWithCommand) {
120    Dumper dumper(canvas, record.count(), timeWithCommand);
121    for (int i = 0; i < record.count(); i++) {
122        record.visit<void>(i, dumper);
123    }
124}
125