1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "pdf/range_set.h"
6 
7 #include <algorithm>
8 #include <sstream>
9 #include <vector>
10 
11 namespace chrome_pdf {
12 
13 namespace {
14 
FixDirection(const gfx::Range & range)15 gfx::Range FixDirection(const gfx::Range& range) {
16   if (!range.IsValid() || !range.is_reversed())
17     return range;
18   return gfx::Range(range.end() + 1, range.start() + 1);
19 }
20 
21 }  // namespace
22 
23 RangeSet::RangeSet() = default;
24 
RangeSet(const gfx::Range & range)25 RangeSet::RangeSet(const gfx::Range& range) {
26   Union(range);
27 }
28 
29 RangeSet::RangeSet(const RangeSet& range_set) = default;
30 
RangeSet(RangeSet && range_set)31 RangeSet::RangeSet(RangeSet&& range_set)
32     : ranges_(std::move(range_set.ranges_)) {}
33 
34 RangeSet& RangeSet::operator=(const RangeSet& other) = default;
35 
36 RangeSet::~RangeSet() = default;
37 
operator ==(const RangeSet & other) const38 bool RangeSet::operator==(const RangeSet& other) const {
39   return other.ranges_ == ranges_;
40 }
41 
operator !=(const RangeSet & other) const42 bool RangeSet::operator!=(const RangeSet& other) const {
43   return other.ranges_ != ranges_;
44 }
45 
Union(const gfx::Range & range)46 void RangeSet::Union(const gfx::Range& range) {
47   if (range.is_empty())
48     return;
49   gfx::Range fixed_range = FixDirection(range);
50   if (IsEmpty()) {
51     ranges_.insert(fixed_range);
52     return;
53   }
54 
55   auto start = ranges_.upper_bound(fixed_range);
56   if (start != ranges_.begin())
57     --start;  // start now points to the key equal or lower than offset.
58   if (start->end() < fixed_range.start())
59     ++start;  // start element is entirely before current range, skip it.
60 
61   auto end = ranges_.upper_bound(gfx::Range(fixed_range.end()));
62   if (start == end) {  // No ranges to merge.
63     ranges_.insert(fixed_range);
64     return;
65   }
66 
67   --end;
68 
69   int new_start = std::min<size_t>(start->start(), fixed_range.start());
70   int new_end = std::max(end->end(), fixed_range.end());
71 
72   ranges_.erase(start, ++end);
73   ranges_.insert(gfx::Range(new_start, new_end));
74 }
75 
Union(const RangeSet & range_set)76 void RangeSet::Union(const RangeSet& range_set) {
77   if (&range_set == this)
78     return;
79   for (const auto& it : range_set.ranges()) {
80     Union(it);
81   }
82 }
83 
Contains(uint32_t point) const84 bool RangeSet::Contains(uint32_t point) const {
85   return Contains(gfx::Range(point, point + 1));
86 }
87 
Contains(const gfx::Range & range) const88 bool RangeSet::Contains(const gfx::Range& range) const {
89   if (range.is_empty())
90     return false;
91   const gfx::Range fixed_range = FixDirection(range);
92   auto it = ranges().upper_bound(fixed_range);
93   if (it == ranges().begin())
94     return false;  // No ranges includes range.start().
95 
96   --it;  // Now it starts equal or before range.start().
97   return it->end() >= fixed_range.end();
98 }
99 
Contains(const RangeSet & range_set) const100 bool RangeSet::Contains(const RangeSet& range_set) const {
101   for (const auto& it : range_set.ranges()) {
102     if (!Contains(it))
103       return false;
104   }
105   return true;
106 }
107 
Intersects(const gfx::Range & range) const108 bool RangeSet::Intersects(const gfx::Range& range) const {
109   if (IsEmpty() || range.is_empty())
110     return false;
111   const gfx::Range fixed_range = FixDirection(range);
112   auto start = ranges_.upper_bound(fixed_range);
113   if (start != ranges_.begin()) {
114     --start;
115   }
116   // start now points to the key equal or lower than range.start().
117   if (start->end() < range.start()) {
118     // start element is entirely before current range, skip it.
119     ++start;
120   }
121   auto end = ranges_.upper_bound(gfx::Range(fixed_range.end()));
122   for (auto it = start; it != end; ++it) {
123     if (fixed_range.end() > it->start() && fixed_range.start() < it->end())
124       return true;
125   }
126   return false;
127 }
128 
Intersects(const RangeSet & range_set) const129 bool RangeSet::Intersects(const RangeSet& range_set) const {
130   for (const auto& it : range_set.ranges()) {
131     if (Intersects(it))
132       return true;
133   }
134   return false;
135 }
136 
Intersect(const gfx::Range & range)137 void RangeSet::Intersect(const gfx::Range& range) {
138   Intersect(RangeSet(range));
139 }
140 
Intersect(const RangeSet & range_set)141 void RangeSet::Intersect(const RangeSet& range_set) {
142   if (IsEmpty())
143     return;
144   RangesContainer new_ranges;
145   for (const auto& range : range_set.ranges()) {
146     auto start = ranges_.upper_bound(range);
147     if (start != ranges_.begin())
148       --start;  // start now points to the key equal or lower than
149                 // range.start().
150     if (start->end() < range.start())
151       ++start;  // start element is entirely before current range, skip it.
152     auto end = ranges_.upper_bound(gfx::Range(range.end()));
153     if (start == end) {  // No data in the current range available.
154       continue;
155     }
156     for (auto it = start; it != end; ++it) {
157       const gfx::Range new_range = range.Intersect(*it);
158       if (!new_range.is_empty()) {
159         new_ranges.insert(new_range);
160       }
161     }
162   }
163   new_ranges.swap(ranges_);
164 }
165 
Subtract(const gfx::Range & range)166 void RangeSet::Subtract(const gfx::Range& range) {
167   if (range.is_empty() || IsEmpty())
168     return;
169   const gfx::Range fixed_range = FixDirection(range);
170   auto start = ranges_.upper_bound(fixed_range);
171   if (start != ranges_.begin())
172     --start;  // start now points to the key equal or lower than
173               // range.start().
174   if (start->end() < fixed_range.start())
175     ++start;  // start element is entirely before current range, skip it.
176   auto end = ranges_.upper_bound(gfx::Range(fixed_range.end()));
177   if (start == end) {  // No data in the current range available.
178     return;
179   }
180   std::vector<gfx::Range> new_ranges;
181   for (auto it = start; it != end; ++it) {
182     const gfx::Range left(it->start(),
183                           std::min(it->end(), fixed_range.start()));
184     const gfx::Range right(std::max(it->start(), fixed_range.end()), it->end());
185     if (!left.is_empty() && !left.is_reversed()) {
186       new_ranges.push_back(left);
187     }
188     if (!right.is_empty() && !right.is_reversed() && right != left) {
189       new_ranges.push_back(right);
190     }
191   }
192   ranges_.erase(start, end);
193   for (const auto& it : new_ranges) {
194     ranges_.insert(it);
195   }
196 }
197 
Subtract(const RangeSet & range_set)198 void RangeSet::Subtract(const RangeSet& range_set) {
199   if (&range_set == this) {
200     ranges_.clear();
201     return;
202   }
203   for (const auto& range : range_set.ranges()) {
204     Subtract(range);
205   }
206 }
207 
Xor(const gfx::Range & range)208 void RangeSet::Xor(const gfx::Range& range) {
209   Xor(RangeSet(range));
210 }
211 
Xor(const RangeSet & range_set)212 void RangeSet::Xor(const RangeSet& range_set) {
213   RangeSet tmp = *this;
214   tmp.Intersect(range_set);
215   Union(range_set);
216   Subtract(tmp);
217 }
218 
IsEmpty() const219 bool RangeSet::IsEmpty() const {
220   return ranges().empty();
221 }
222 
Clear()223 void RangeSet::Clear() {
224   ranges_.clear();
225 }
226 
First() const227 gfx::Range RangeSet::First() const {
228   return *ranges().begin();
229 }
230 
Last() const231 gfx::Range RangeSet::Last() const {
232   return *ranges().rbegin();
233 }
234 
ToString() const235 std::string RangeSet::ToString() const {
236   std::stringstream ss;
237   ss << "{";
238   for (const auto& it : ranges()) {
239     ss << "[" << it.start() << "," << it.end() << ")";
240   }
241   ss << "}";
242   return ss.str();
243 }
244 
245 }  // namespace chrome_pdf
246 
operator <<(std::ostream & os,const chrome_pdf::RangeSet & range_set)247 std::ostream& operator<<(std::ostream& os,
248                          const chrome_pdf::RangeSet& range_set) {
249   return (os << range_set.ToString());
250 }
251