Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(688)

Unified Diff: pdf/range_set.cc

Issue 2349753003: Improve linearized pdf load/show time. (Closed)
Patch Set: rebase Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « pdf/range_set.h ('k') | pdf/range_set_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pdf/range_set.cc
diff --git a/pdf/range_set.cc b/pdf/range_set.cc
new file mode 100644
index 0000000000000000000000000000000000000000..df53d660023e5f1bec8d1cbcf01005d39c7b0cb2
--- /dev/null
+++ b/pdf/range_set.cc
@@ -0,0 +1,253 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "pdf/range_set.h"
+
+#include <algorithm>
+#include <sstream>
+#include <vector>
+
+namespace chrome_pdf {
+
+namespace {
+
+gfx::Range FixDirection(const gfx::Range& range) {
+ if (!range.IsValid() || !range.is_reversed())
+ return range;
+ return gfx::Range(range.end() + 1, range.start() + 1);
+}
+
+} // namespace
+
+RangeSet::RangeSet() {}
+
+RangeSet::RangeSet(const gfx::Range& range) {
+ Union(range);
+}
+
+RangeSet::RangeSet(const RangeSet& range_set) : ranges_(range_set.ranges_) {}
+
+RangeSet::RangeSet(RangeSet&& range_set)
+ : ranges_(std::move(range_set.ranges_)) {}
+
+RangeSet& RangeSet::operator=(const RangeSet& other) {
+ ranges_ = other.ranges_;
+ return *this;
+}
+
+RangeSet::~RangeSet() {}
+
+bool RangeSet::operator==(const RangeSet& other) const {
+ return other.ranges_ == ranges_;
+}
+
+bool RangeSet::operator!=(const RangeSet& other) const {
+ return other.ranges_ != ranges_;
+}
+
+void RangeSet::Union(const gfx::Range& range) {
+ if (range.is_empty())
+ return;
+ gfx::Range fixed_range = FixDirection(range);
+ if (IsEmpty()) {
+ ranges_.insert(fixed_range);
+ return;
+ }
+
+ auto start = ranges_.upper_bound(fixed_range);
+ if (start != ranges_.begin())
+ --start; // start now points to the key equal or lower than offset.
+ if (start->end() < fixed_range.start())
+ ++start; // start element is entirely before current range, skip it.
+
+ auto end = ranges_.upper_bound(gfx::Range(fixed_range.end()));
+ if (start == end) { // No ranges to merge.
+ ranges_.insert(fixed_range);
+ return;
+ }
+
+ --end;
+
+ int new_start = std::min<size_t>(start->start(), fixed_range.start());
+ int new_end = std::max(end->end(), fixed_range.end());
+
+ ranges_.erase(start, ++end);
+ ranges_.insert(gfx::Range(new_start, new_end));
+}
+
+void RangeSet::Union(const RangeSet& range_set) {
+ if (&range_set == this)
+ return;
+ for (const auto& it : range_set.ranges()) {
+ Union(it);
+ }
+}
+
+bool RangeSet::Contains(uint32_t point) const {
+ return Contains(gfx::Range(point, point + 1));
+}
+
+bool RangeSet::Contains(const gfx::Range& range) const {
+ if (range.is_empty())
+ return false;
+ const gfx::Range fixed_range = FixDirection(range);
+ auto it = ranges().upper_bound(fixed_range);
+ if (it == ranges().begin())
+ return false; // No ranges includes range.start().
+
+ --it; // Now it starts equal or before range.start().
+ return it->end() >= fixed_range.end();
+}
+
+bool RangeSet::Contains(const RangeSet& range_set) const {
+ for (const auto& it : range_set.ranges()) {
+ if (!Contains(it))
+ return false;
+ }
+ return true;
+}
+
+bool RangeSet::Intersects(const gfx::Range& range) const {
+ if (IsEmpty() || range.is_empty())
+ return false;
+ const gfx::Range fixed_range = FixDirection(range);
+ auto start = ranges_.upper_bound(fixed_range);
+ if (start != ranges_.begin()) {
+ --start;
+ }
+ // start now points to the key equal or lower than range.start().
+ if (start->end() < range.start()) {
+ // start element is entirely before current range, skip it.
+ ++start;
+ }
+ auto end = ranges_.upper_bound(gfx::Range(fixed_range.end()));
+ for (auto it = start; it != end; ++it) {
+ if (fixed_range.end() > it->start() && fixed_range.start() < it->end())
+ return true;
+ }
+ return false;
+}
+
+bool RangeSet::Intersects(const RangeSet& range_set) const {
+ for (const auto& it : range_set.ranges()) {
+ if (Intersects(it))
+ return true;
+ }
+ return false;
+}
+
+void RangeSet::Intersect(const gfx::Range& range) {
+ Intersect(RangeSet(range));
+}
+
+void RangeSet::Intersect(const RangeSet& range_set) {
+ if (IsEmpty())
+ return;
+ RangesContainer new_ranges;
+ for (const auto& range : range_set.ranges()) {
+ auto start = ranges_.upper_bound(range);
+ if (start != ranges_.begin())
+ --start; // start now points to the key equal or lower than
+ // range.start().
+ if (start->end() < range.start())
+ ++start; // start element is entirely before current range, skip it.
+ auto end = ranges_.upper_bound(gfx::Range(range.end()));
+ if (start == end) { // No data in the current range available.
+ continue;
+ }
+ for (auto it = start; it != end; ++it) {
+ const gfx::Range new_range = range.Intersect(*it);
+ if (!new_range.is_empty()) {
+ new_ranges.insert(new_range);
+ }
+ }
+ }
+ new_ranges.swap(ranges_);
+}
+
+void RangeSet::Subtract(const gfx::Range& range) {
+ if (range.is_empty() || IsEmpty())
+ return;
+ const gfx::Range fixed_range = FixDirection(range);
+ auto start = ranges_.upper_bound(fixed_range);
+ if (start != ranges_.begin())
+ --start; // start now points to the key equal or lower than
+ // range.start().
+ if (start->end() < fixed_range.start())
+ ++start; // start element is entirely before current range, skip it.
+ auto end = ranges_.upper_bound(gfx::Range(fixed_range.end()));
+ if (start == end) { // No data in the current range available.
+ return;
+ }
+ std::vector<gfx::Range> new_ranges;
+ for (auto it = start; it != end; ++it) {
+ const gfx::Range left(it->start(),
+ std::min(it->end(), fixed_range.start()));
+ const gfx::Range right(std::max(it->start(), fixed_range.end()), it->end());
+ if (!left.is_empty() && !left.is_reversed()) {
+ new_ranges.push_back(left);
+ }
+ if (!right.is_empty() && !right.is_reversed() && right != left) {
+ new_ranges.push_back(right);
+ }
+ }
+ ranges_.erase(start, end);
+ for (const auto& it : new_ranges) {
+ ranges_.insert(it);
+ }
+}
+
+void RangeSet::Subtract(const RangeSet& range_set) {
+ if (&range_set == this) {
+ ranges_.clear();
+ return;
+ }
+ for (const auto& range : range_set.ranges()) {
+ Subtract(range);
+ }
+}
+
+void RangeSet::Xor(const gfx::Range& range) {
+ Xor(RangeSet(range));
+}
+
+void RangeSet::Xor(const RangeSet& range_set) {
+ RangeSet tmp = *this;
+ tmp.Intersect(range_set);
+ Union(range_set);
+ Subtract(tmp);
+}
+
+bool RangeSet::IsEmpty() const {
+ return ranges().empty();
+}
+
+void RangeSet::Clear() {
+ ranges_.clear();
+}
+
+gfx::Range RangeSet::First() const {
+ return *ranges().begin();
+}
+
+gfx::Range RangeSet::Last() const {
+ return *ranges().rbegin();
+}
+
+std::string RangeSet::ToString() const {
+ std::stringstream ss;
+ ss << "{";
+ for (const auto& it : ranges()) {
+ ss << "[" << it.start() << "," << it.end() << ")";
+ }
+ ss << "}";
+ return ss.str();
+}
+
+} // namespace chrome_pdf
+
+std::ostream& operator<<(std::ostream& os,
+ const chrome_pdf::RangeSet& range_set) {
+ return (os << range_set.ToString());
+}
« no previous file with comments | « pdf/range_set.h ('k') | pdf/range_set_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698