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(i, *this);
72            }
73
74            --fIndent;
75        }
76    }
77
78#if 1
79    void print(const SkRecords::DrawAnnotation& command, double ns) {
80        int us = (int)(ns * 1e-3);
81        if (!fTimeWithCommand) {
82            printf("%6dus  ", us);
83        }
84        printf("%*d ", fDigits, fIndex++);
85        for (int i = 0; i < fIndent; i++) {
86            printf("    ");
87        }
88        if (fTimeWithCommand) {
89            printf("%6dus  ", us);
90        }
91        printf("DrawAnnotation [%g %g %g %g] %s\n",
92               command.rect.left(), command.rect.top(), command.rect.right(), command.rect.bottom(),
93               command.key.c_str());
94    }
95#endif
96
97private:
98    template <typename T>
99    void printNameAndTime(const T& command, double ns) {
100        int us = (int)(ns * 1e-3);
101        if (!fTimeWithCommand) {
102            printf("%6dus  ", us);
103        }
104        printf("%*d ", fDigits, fIndex++);
105        for (int i = 0; i < fIndent; i++) {
106            printf("    ");
107        }
108        if (fTimeWithCommand) {
109            printf("%6dus  ", us);
110        }
111        puts(NameOf(command));
112    }
113
114    template <typename T>
115    static const char* NameOf(const T&) {
116    #define CASE(U) case SkRecords::U##_Type: return #U;
117        switch(T::kType) { SK_RECORD_TYPES(CASE); }
118    #undef CASE
119        SkDEBUGFAIL("Unknown T");
120        return "Unknown T";
121    }
122
123    static const char* NameOf(const SkRecords::SaveLayer&) {
124        return "\x1b[31;1mSaveLayer\x1b[0m";  // Bold red.
125    }
126
127    int fDigits;
128    int fIndent;
129    int fIndex;
130    SkRecords::Draw fDraw;
131    const bool fTimeWithCommand;
132};
133
134}  // namespace
135
136void DumpRecord(const SkRecord& record,
137                  SkCanvas* canvas,
138                  bool timeWithCommand) {
139    Dumper dumper(canvas, record.count(), timeWithCommand);
140    for (int i = 0; i < record.count(); i++) {
141        record.visit(i, dumper);
142    }
143}
144