1 /*
2  * Copyright 2016 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 #ifndef GrWindowRectangles_DEFINED
9 #define GrWindowRectangles_DEFINED
10 
11 #include "GrNonAtomicRef.h"
12 #include "SkRect.h"
13 
14 class GrWindowRectangles {
15 public:
16     constexpr static int kMaxWindows = 8;
17 
18     GrWindowRectangles() : fCount(0) {}
19     GrWindowRectangles(const GrWindowRectangles& that) : fCount(0) { *this = that; }
20     ~GrWindowRectangles() { SkSafeUnref(this->rec()); }
21 
22     GrWindowRectangles makeOffset(int dx, int dy) const;
23 
24     bool empty() const { return !fCount; }
25     int count() const { return fCount; }
26     const SkIRect* data() const;
27 
28     void reset();
29     GrWindowRectangles& operator=(const GrWindowRectangles&);
30 
31     SkIRect& addWindow(const SkIRect& window) { return this->addWindow() = window; }
32     SkIRect& addWindow();
33 
34     bool operator!=(const GrWindowRectangles& that) const { return !(*this == that); }
35     bool operator==(const GrWindowRectangles&) const;
36 
37 private:
38     constexpr static int kNumLocalWindows = 1;
39     struct Rec;
40 
41     const Rec* rec() const { return fCount <= kNumLocalWindows ? nullptr : fRec; }
42 
43     int fCount;
44     union {
45         SkIRect   fLocalWindows[kNumLocalWindows]; // If fCount <= kNumLocalWindows.
46         Rec*      fRec;                            // If fCount > kNumLocalWindows.
47     };
48 };
49 
50 struct GrWindowRectangles::Rec : public GrNonAtomicRef<Rec> {
51     Rec(const SkIRect* windows, int numWindows) {
52         SkASSERT(numWindows < kMaxWindows);
53         memcpy(fData, windows, sizeof(SkIRect) * numWindows);
54     }
55     Rec() = default;
56 
57     SkIRect fData[kMaxWindows];
58 };
59 
60 inline const SkIRect* GrWindowRectangles::data() const {
61     return fCount <= kNumLocalWindows ? fLocalWindows : fRec->fData;
62 }
63 
64 inline void GrWindowRectangles::reset() {
65     SkSafeUnref(this->rec());
66     fCount = 0;
67 }
68 
69 inline GrWindowRectangles& GrWindowRectangles::operator=(const GrWindowRectangles& that) {
70     SkSafeUnref(this->rec());
71     fCount = that.fCount;
72     if (fCount <= kNumLocalWindows) {
73         memcpy(fLocalWindows, that.fLocalWindows, fCount * sizeof(SkIRect));
74     } else {
75         fRec = SkRef(that.fRec);
76     }
77     return *this;
78 }
79 
80 inline GrWindowRectangles GrWindowRectangles::makeOffset(int dx, int dy) const {
81     if (!dx && !dy) {
82         return *this;
83     }
84     GrWindowRectangles result;
85     result.fCount = fCount;
86     SkIRect* windows;
87     if (result.fCount > kNumLocalWindows) {
88         result.fRec = new Rec();
89         windows = result.fRec->fData;
90     } else {
91         windows = result.fLocalWindows;
92     }
93     for (int i = 0; i < fCount; ++i) {
94         windows[i] = this->data()[i].makeOffset(dx, dy);
95     }
96     return result;
97 }
98 
99 inline SkIRect& GrWindowRectangles::addWindow() {
100     SkASSERT(fCount < kMaxWindows);
101     if (fCount < kNumLocalWindows) {
102         return fLocalWindows[fCount++];
103     }
104     if (fCount == kNumLocalWindows) {
105         fRec = new Rec(fLocalWindows, kNumLocalWindows);
106     } else if (!fRec->unique()) { // Simple copy-on-write.
107         fRec->unref();
108         fRec = new Rec(fRec->fData, fCount);
109     }
110     return fRec->fData[fCount++];
111 }
112 
113 inline bool GrWindowRectangles::operator==(const GrWindowRectangles& that) const {
114     if (fCount != that.fCount) {
115         return false;
116     }
117     if (fCount > kNumLocalWindows && fRec == that.fRec) {
118         return true;
119     }
120     return !fCount || !memcmp(this->data(), that.data(), sizeof(SkIRect) * fCount);
121 }
122 
123 #endif
124