/work/obj-fuzz/dist/include/mozilla/gfx/TiledRegion.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
2 | | /* vim: set ts=8 sts=2 et sw=2 tw=80: */ |
3 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
4 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
5 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
6 | | |
7 | | #ifndef MOZILLA_GFX_TILEDREGION_H_ |
8 | | #define MOZILLA_GFX_TILEDREGION_H_ |
9 | | |
10 | | #include "mozilla/ArrayView.h" |
11 | | #include "mozilla/gfx/Rect.h" |
12 | | #include "mozilla/Move.h" |
13 | | #include "nsRegion.h" |
14 | | #include "pixman.h" |
15 | | |
16 | | namespace mozilla { |
17 | | namespace gfx { |
18 | | |
19 | | // See TiledRegion.cpp for documentation on TiledRegionImpl. |
20 | | class TiledRegionImpl { |
21 | | public: |
22 | 0 | void Clear() { mRects.Clear(); } |
23 | | bool AddRect(const pixman_box32_t& aRect); |
24 | | bool Intersects(const pixman_box32_t& aRect) const; |
25 | | bool Contains(const pixman_box32_t& aRect) const; |
26 | 0 | operator ArrayView<pixman_box32_t>() const { return ArrayView<pixman_box32_t>(mRects); } |
27 | | |
28 | | private: |
29 | | nsTArray<pixman_box32_t> mRects; |
30 | | }; |
31 | | |
32 | | /** |
33 | | * A auto-simplifying region type that supports one rectangle per tile. |
34 | | * The virtual tile grid is anchored at (0, 0) and has quadratic tiles whose |
35 | | * size is hard-coded as kTileSize in TiledRegion.cpp. |
36 | | * A TiledRegion starts out empty. You can add rectangles or (regular) regions |
37 | | * into it by calling Add(). Add() is a mutating union operation (similar to |
38 | | * OrWith on nsRegion) that's *not* exact, because it will enlarge the region as |
39 | | * necessary to satisfy the "one rectangle per tile" requirement. |
40 | | * Tiled regions convert implicitly to the underlying regular region type. |
41 | | * The only way to remove parts from a TiledRegion is by calling SetEmpty(). |
42 | | */ |
43 | | template<typename RegionT> |
44 | | class TiledRegion { |
45 | | public: |
46 | | typedef typename RegionT::RectType RectT; |
47 | | |
48 | | TiledRegion() |
49 | | : mCoversBounds(false) |
50 | 0 | {} |
51 | | |
52 | | TiledRegion(const TiledRegion& aOther) |
53 | | : mBounds(aOther.mBounds) |
54 | | , mImpl(aOther.mImpl) |
55 | | , mCoversBounds(false) |
56 | | {} |
57 | | |
58 | | TiledRegion(TiledRegion&& aOther) |
59 | | : mBounds(aOther.mBounds) |
60 | | , mImpl(std::move(aOther.mImpl)) |
61 | | , mCoversBounds(false) |
62 | | {} |
63 | | |
64 | | RegionT GetRegion() const |
65 | 0 | { |
66 | 0 | if (mBounds.IsEmpty()) { |
67 | 0 | return RegionT(); |
68 | 0 | } |
69 | 0 | if (mCoversBounds) { |
70 | 0 | // Rect limit hit or allocation failed, treat as 1 rect. |
71 | 0 | return RegionT(mBounds); |
72 | 0 | } |
73 | 0 | return RegionT(mImpl); |
74 | 0 | } |
75 | | |
76 | | TiledRegion& operator=(const TiledRegion& aOther) |
77 | | { |
78 | | if (&aOther != this) { |
79 | | mBounds = aOther.mBounds; |
80 | | mImpl = aOther.mImpl; |
81 | | mCoversBounds = aOther.mCoversBounds; |
82 | | } |
83 | | return *this; |
84 | | } |
85 | | |
86 | | void Add(const RectT& aRect) |
87 | 0 | { |
88 | 0 | if (aRect.IsEmpty()) { |
89 | 0 | return; |
90 | 0 | } |
91 | 0 | |
92 | 0 | Maybe<RectT> newBounds = mBounds.SafeUnion(aRect); |
93 | 0 | if (!newBounds) { |
94 | 0 | return; |
95 | 0 | } |
96 | 0 | mBounds = newBounds.value(); |
97 | 0 | MOZ_ASSERT(!mBounds.Overflows()); |
98 | 0 |
|
99 | 0 | if (mCoversBounds) { |
100 | 0 | return; |
101 | 0 | } |
102 | 0 | |
103 | 0 | if (!mImpl.AddRect(RectToBox(aRect))) { |
104 | 0 | FallBackToBounds(); |
105 | 0 | } |
106 | 0 | } |
107 | | |
108 | | void Add(const RegionT& aRegion) |
109 | 0 | { |
110 | 0 | Maybe<RectT> newBounds = mBounds.SafeUnion(aRegion.GetBounds()); |
111 | 0 | if (!newBounds) { |
112 | 0 | return; |
113 | 0 | } |
114 | 0 | mBounds = newBounds.value(); |
115 | 0 | MOZ_ASSERT(!mBounds.Overflows()); |
116 | 0 |
|
117 | 0 | if (mCoversBounds) { |
118 | 0 | return; |
119 | 0 | } |
120 | 0 | |
121 | 0 | for (auto iter = aRegion.RectIter(); !iter.Done(); iter.Next()) { |
122 | 0 | RectT r = iter.Get(); |
123 | 0 | if (r.IsEmpty() || r.Overflows()) { |
124 | 0 | // This can happen if e.g. a negative-width rect was wrapped into a |
125 | 0 | // region. Treat it the same as we would if such a rect was passed to |
126 | 0 | // the Add(const RectT&) function. |
127 | 0 | continue; |
128 | 0 | } |
129 | 0 | if (!mImpl.AddRect(RectToBox(r))) { |
130 | 0 | FallBackToBounds(); |
131 | 0 | return; |
132 | 0 | } |
133 | 0 | } |
134 | 0 | } |
135 | | |
136 | 0 | bool IsEmpty() const { return mBounds.IsEmpty(); } |
137 | | |
138 | | void SetEmpty() |
139 | 0 | { |
140 | 0 | mBounds.SetEmpty(); |
141 | 0 | mImpl.Clear(); |
142 | 0 | mCoversBounds = false; |
143 | 0 | } |
144 | | |
145 | | RectT GetBounds() const { return mBounds; } |
146 | | bool CoversBounds() const { return mCoversBounds; } |
147 | | |
148 | | bool Intersects(const RectT& aRect) const |
149 | 0 | { |
150 | 0 | if (aRect.IsEmpty()) { |
151 | 0 | return true; |
152 | 0 | } |
153 | 0 | if (aRect.Overflows() || !mBounds.Intersects(aRect)) { |
154 | 0 | return false; |
155 | 0 | } |
156 | 0 | if (mCoversBounds) { |
157 | 0 | return true; |
158 | 0 | } |
159 | 0 | |
160 | 0 | return mImpl.Intersects(RectToBox(aRect)); |
161 | 0 | } |
162 | | |
163 | | bool Contains(const RectT& aRect) const |
164 | 0 | { |
165 | 0 | if (aRect.IsEmpty()) { |
166 | 0 | return true; |
167 | 0 | } |
168 | 0 | if (aRect.Overflows() || !mBounds.Contains(aRect)) { |
169 | 0 | return false; |
170 | 0 | } |
171 | 0 | if (mCoversBounds) { |
172 | 0 | return true; |
173 | 0 | } |
174 | 0 | return mImpl.Contains(RectToBox(aRect)); |
175 | 0 | } |
176 | | |
177 | | private: |
178 | | |
179 | | void FallBackToBounds() |
180 | 0 | { |
181 | 0 | mCoversBounds = true; |
182 | 0 | mImpl.Clear(); |
183 | 0 | } |
184 | | |
185 | | static pixman_box32_t RectToBox(const RectT& aRect) |
186 | 0 | { |
187 | 0 | MOZ_ASSERT(!aRect.IsEmpty()); |
188 | 0 | MOZ_ASSERT(!aRect.Overflows()); |
189 | 0 | return { aRect.X(), aRect.Y(), aRect.XMost(), aRect.YMost() }; |
190 | 0 | } |
191 | | |
192 | | RectT mBounds; |
193 | | TiledRegionImpl mImpl; |
194 | | |
195 | | // mCoversBounds is true if we bailed out due to a large number of tiles. |
196 | | // mCoversBounds being true means that this TiledRegion is just a simple |
197 | | // rectangle (our mBounds). |
198 | | // Once set to true, the TiledRegion will stay in this state until SetEmpty |
199 | | // is called. |
200 | | bool mCoversBounds; |
201 | | }; |
202 | | |
203 | | typedef TiledRegion<IntRegion> TiledIntRegion; |
204 | | |
205 | | } // namespace gfx |
206 | | } // namespace mozilla |
207 | | |
208 | | #endif /* MOZILLA_GFX_TILEDREGION_H_ */ |