Coverage Report

Created: 2018-09-25 14:53

/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_ */