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 "Test.h"
9
10#include "SkBitmap.h"
11#include "SkImageInfo.h"
12#include "SkShader.h"
13#include "SkRecord.h"
14#include "SkRecords.h"
15
16// Sums the area of any DrawRect command it sees.
17class AreaSummer {
18public:
19    AreaSummer() : fArea(0) {}
20
21    template <typename T> void operator()(const T&) { }
22
23    void operator()(const SkRecords::DrawRect& draw) {
24        fArea += (int)(draw.rect.width() * draw.rect.height());
25    }
26
27    int area() const { return fArea; }
28
29    void apply(const SkRecord& record) {
30        for (unsigned i = 0; i < record.count(); i++) {
31            record.visit<void>(i, *this);
32        }
33    }
34
35private:
36    int fArea;
37};
38
39// Scales out the bottom-right corner of any DrawRect command it sees by 2x.
40struct Stretch {
41    template <typename T> void operator()(T*) {}
42    void operator()(SkRecords::DrawRect* draw) {
43        draw->rect.fRight *= 2;
44        draw->rect.fBottom *= 2;
45    }
46
47    void apply(SkRecord* record) {
48        for (unsigned i = 0; i < record->count(); i++) {
49            record->mutate<void>(i, *this);
50        }
51    }
52};
53
54#define APPEND(record, type, ...) SkNEW_PLACEMENT_ARGS(record.append<type>(), type, (__VA_ARGS__))
55
56// Basic tests for the low-level SkRecord code.
57DEF_TEST(Record, r) {
58    SkRecord record;
59
60    // Add a simple DrawRect command.
61    SkRect rect = SkRect::MakeWH(10, 10);
62    SkPaint paint;
63    APPEND(record, SkRecords::DrawRect, paint, rect);
64
65    // Its area should be 100.
66    AreaSummer summer;
67    summer.apply(record);
68    REPORTER_ASSERT(r, summer.area() == 100);
69
70    // Scale 2x.
71    Stretch stretch;
72    stretch.apply(&record);
73
74    // Now its area should be 100 + 400.
75    summer.apply(record);
76    REPORTER_ASSERT(r, summer.area() == 500);
77}
78
79#undef APPEND
80
81template <typename T>
82static bool is_aligned(const T* p) {
83    return (((uintptr_t)p) & (sizeof(T) - 1)) == 0;
84}
85
86DEF_TEST(Record_Alignment, r) {
87    SkRecord record;
88
89    // Of course a byte's always aligned.
90    REPORTER_ASSERT(r, is_aligned(record.alloc<uint8_t>()));
91
92    // (If packed tightly, the rest below here would be off by one.)
93
94    // It happens that the first implementation always aligned to 4 bytes,
95    // so these two were always correct.
96    REPORTER_ASSERT(r, is_aligned(record.alloc<uint16_t>()));
97    REPORTER_ASSERT(r, is_aligned(record.alloc<uint32_t>()));
98
99    // These two are regression tests (void* only on 64-bit machines).
100    REPORTER_ASSERT(r, is_aligned(record.alloc<uint64_t>()));
101    REPORTER_ASSERT(r, is_aligned(record.alloc<void*>()));
102
103    // We're not testing beyond sizeof(void*), which is where the current implementation will break.
104}
105
106