Optimized DesktopRegion implementation.
Now DestktopRegion can merge overlapping rectangles. R=wez@chromium.org Review URL: https://webrtc-codereview.appspot.com/1526004 git-svn-id: http://webrtc.googlecode.com/svn/trunk@4161 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
parent
34a77354a8
commit
3ee13e4ac2
@ -59,6 +59,7 @@
|
||||
'<(DEPTH)/testing/gtest.gyp:gtest',
|
||||
],
|
||||
'sources': [
|
||||
"desktop_region_unittest.cc",
|
||||
"window_capturer_unittest.cc",
|
||||
],
|
||||
},
|
||||
|
||||
@ -10,18 +10,70 @@
|
||||
|
||||
#include "webrtc/modules/desktop_capture/desktop_region.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
DesktopRegion::RowSpan::RowSpan(int32_t left, int32_t right)
|
||||
: left(left), right(right) {
|
||||
}
|
||||
|
||||
DesktopRegion::Row::Row(int32_t top, int32_t bottom)
|
||||
: top(top), bottom(bottom) {
|
||||
}
|
||||
|
||||
DesktopRegion::DesktopRegion() {}
|
||||
|
||||
DesktopRegion::DesktopRegion(const DesktopRegion& other)
|
||||
: rects_(other.rects_) {
|
||||
DesktopRegion::DesktopRegion(const DesktopRect& rect) {
|
||||
AddRect(rect);
|
||||
}
|
||||
|
||||
DesktopRegion::~DesktopRegion() {}
|
||||
DesktopRegion::DesktopRegion(const DesktopRect* rects, int count) {
|
||||
AddRects(rects, count);
|
||||
}
|
||||
|
||||
DesktopRegion::DesktopRegion(const DesktopRegion& other) {
|
||||
*this = other;
|
||||
}
|
||||
|
||||
DesktopRegion::~DesktopRegion() {
|
||||
Clear();
|
||||
}
|
||||
|
||||
DesktopRegion& DesktopRegion::operator=(const DesktopRegion& other) {
|
||||
rows_ = other.rows_;
|
||||
for (Rows::iterator it = rows_.begin(); it != rows_.end(); ++it) {
|
||||
// Copy each row.
|
||||
Row* row = it->second;
|
||||
it->second = new Row(*row);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool DesktopRegion::Equals(const DesktopRegion& region) const {
|
||||
// Iterate over rows of the tow regions and compare each row.
|
||||
Rows::const_iterator it1 = rows_.begin();
|
||||
Rows::const_iterator it2 = region.rows_.begin();
|
||||
while (it1 != rows_.end()) {
|
||||
if (it2 == region.rows_.end() ||
|
||||
it1->first != it2->first ||
|
||||
it1->second->top != it2->second->top ||
|
||||
it1->second->bottom != it2->second->bottom ||
|
||||
it1->second->spans != it2->second->spans) {
|
||||
return false;
|
||||
}
|
||||
++it1;
|
||||
++it2;
|
||||
}
|
||||
return it2 == region.rows_.end();
|
||||
}
|
||||
|
||||
void DesktopRegion::Clear() {
|
||||
rects_.clear();
|
||||
for (Rows::iterator row = rows_.begin(); row != rows_.end(); ++row) {
|
||||
delete row->second;
|
||||
}
|
||||
rows_.clear();
|
||||
}
|
||||
|
||||
void DesktopRegion::SetRect(const DesktopRect& rect) {
|
||||
@ -30,55 +82,352 @@ void DesktopRegion::SetRect(const DesktopRect& rect) {
|
||||
}
|
||||
|
||||
void DesktopRegion::AddRect(const DesktopRect& rect) {
|
||||
if (!rect.is_empty())
|
||||
rects_.push_back(rect);
|
||||
if (rect.is_empty())
|
||||
return;
|
||||
|
||||
// Top of the part of the |rect| that hasn't been inserted yet. Increased as
|
||||
// we iterate over the rows until it reaches |rect.bottom()|.
|
||||
int top = rect.top();
|
||||
|
||||
// Iterate over all rows that may intersect with |rect| and add new rows when
|
||||
// necessary.
|
||||
Rows::iterator row = rows_.upper_bound(top);
|
||||
while (top < rect.bottom()) {
|
||||
if (row == rows_.end() || top < row->second->top) {
|
||||
// If |top| is above the top of the current |row| then add a new row above
|
||||
// the current one.
|
||||
int32_t bottom = rect.bottom();
|
||||
if (row != rows_.end() && row->second->top < bottom)
|
||||
bottom = row->second->top;
|
||||
row = rows_.insert(
|
||||
row, Rows::value_type(bottom, new Row(top, bottom)));
|
||||
} else if (top > row->second->top) {
|
||||
// If the |top| falls in the middle of the |row| then split |row| into
|
||||
// two, at |top|, and leave |row| referring to the lower of of the two,
|
||||
// ready to insert a new span into.
|
||||
assert(top <= row->second->bottom);
|
||||
Rows::iterator new_row = rows_.insert(
|
||||
row, Rows::value_type(top, new Row(row->second->top, top)));
|
||||
row->second->top = top;
|
||||
new_row->second->spans = row->second->spans;
|
||||
}
|
||||
|
||||
if (rect.bottom() < row->second->bottom) {
|
||||
// If the bottom of the |rect| falls in the middle of the |row| split
|
||||
// |row| into two, at |top|, and leave |row| referring to the upper of
|
||||
// the two, ready to insert a new span into.
|
||||
Rows::iterator new_row = rows_.insert(
|
||||
row, Rows::value_type(rect.bottom(), new Row(top, rect.bottom())));
|
||||
row->second->top = rect.bottom();
|
||||
new_row->second->spans = row->second->spans;
|
||||
row = new_row;
|
||||
}
|
||||
|
||||
// Add a new span to the current row.
|
||||
AddSpanToRow(row->second, rect.left(), rect.right());
|
||||
top = row->second->bottom;
|
||||
|
||||
MergeWithPrecedingRow(row);
|
||||
|
||||
// Move to the next row.
|
||||
row++;
|
||||
}
|
||||
|
||||
if (row != rows_.end())
|
||||
MergeWithPrecedingRow(row);
|
||||
}
|
||||
|
||||
void DesktopRegion::AddRects(const DesktopRect* rects, int count) {
|
||||
for (int i = 0; i < count; ++i) {
|
||||
AddRect(rects[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void DesktopRegion::MergeWithPrecedingRow(Rows::iterator row) {
|
||||
assert(row != rows_.end());
|
||||
|
||||
if (row != rows_.begin()) {
|
||||
Rows::iterator previous_row = row;
|
||||
previous_row--;
|
||||
|
||||
// If |row| and |previous_row| are next to each other and contain the same
|
||||
// set of spans then they can be merged.
|
||||
if (previous_row->second->bottom == row->second->top &&
|
||||
previous_row->second->spans == row->second->spans) {
|
||||
row->second->top = previous_row->second->top;
|
||||
delete previous_row->second;
|
||||
rows_.erase(previous_row);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DesktopRegion::AddRegion(const DesktopRegion& region) {
|
||||
// TODO(sergeyu): This function is not optimized - potentially it can iterate
|
||||
// over rows of the two regions similar to how it works in Intersect().
|
||||
for (Iterator it(region); !it.IsAtEnd(); it.Advance()) {
|
||||
AddRect(it.rect());
|
||||
}
|
||||
}
|
||||
|
||||
void DesktopRegion::IntersectWith(const DesktopRect& rect) {
|
||||
bool remove_empty_rects = false;
|
||||
for (RectsList::iterator it = rects_.begin(); it != rects_.end(); ++it) {
|
||||
it->IntersectWith(rect);
|
||||
remove_empty_rects = remove_empty_rects | it->is_empty();
|
||||
}
|
||||
if (remove_empty_rects) {
|
||||
RectsList new_rects;
|
||||
new_rects.reserve(rects_.size());
|
||||
for (RectsList::iterator it = rects_.begin(); it != rects_.end(); ++it) {
|
||||
if (!it->is_empty())
|
||||
new_rects.push_back(*it);
|
||||
void DesktopRegion::Intersect(const DesktopRegion& region1,
|
||||
const DesktopRegion& region2) {
|
||||
Clear();
|
||||
|
||||
Rows::const_iterator it1 = region1.rows_.begin();
|
||||
Rows::const_iterator end1 = region1.rows_.end();
|
||||
Rows::const_iterator it2 = region2.rows_.begin();
|
||||
Rows::const_iterator end2 = region2.rows_.end();
|
||||
if (it1 == end1 || it2 == end2)
|
||||
return;
|
||||
|
||||
while (it1 != end1 && it2 != end2) {
|
||||
// Arrange for |it1| to always be the top-most of the rows.
|
||||
if (it2->second->top < it1->second->top) {
|
||||
std::swap(it1, it2);
|
||||
std::swap(end1, end2);
|
||||
}
|
||||
rects_.swap(new_rects);
|
||||
|
||||
// Skip |it1| if it doesn't intersect |it2| at all.
|
||||
if (it1->second->bottom <= it2->second->top) {
|
||||
++it1;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Top of the |it1| row is above the top of |it2|, so top of the
|
||||
// intersection is always the top of |it2|.
|
||||
int32_t top = it2->second->top;
|
||||
int32_t bottom = std::min(it1->second->bottom, it2->second->bottom);
|
||||
|
||||
Rows::iterator new_row = rows_.insert(
|
||||
rows_.end(), Rows::value_type(bottom, new Row(top, bottom)));
|
||||
IntersectRows(it1->second->spans, it2->second->spans,
|
||||
&new_row->second->spans);
|
||||
if (new_row->second->spans.empty()) {
|
||||
delete new_row->second;
|
||||
rows_.erase(new_row);
|
||||
}
|
||||
|
||||
MergeWithPrecedingRow(new_row);
|
||||
|
||||
// If |it1| was completely consumed, move to the next one.
|
||||
if (it1->second->bottom == bottom)
|
||||
++it1;
|
||||
// If |it2| was completely consumed, move to the next one.
|
||||
if (it2->second->bottom == bottom)
|
||||
++it2;
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
void DesktopRegion::IntersectRows(const RowSpanSet& set1,
|
||||
const RowSpanSet& set2,
|
||||
RowSpanSet* output) {
|
||||
RowSpanSet::const_iterator it1 = set1.begin();
|
||||
RowSpanSet::const_iterator end1 = set1.end();
|
||||
RowSpanSet::const_iterator it2 = set2.begin();
|
||||
RowSpanSet::const_iterator end2 = set2.end();
|
||||
assert(it1 != end1 && it2 != end2);
|
||||
|
||||
do {
|
||||
// Arrange for |it1| to always be the left-most of the spans.
|
||||
if (it2->left < it1->left) {
|
||||
std::swap(it1, it2);
|
||||
std::swap(end1, end2);
|
||||
}
|
||||
|
||||
// Skip |it1| if it doesn't intersect |it2| at all.
|
||||
if (it1->right <= it2->left) {
|
||||
++it1;
|
||||
continue;
|
||||
}
|
||||
|
||||
int32_t left = it2->left;
|
||||
int32_t right = std::min(it1->right, it2->right);
|
||||
assert(left < right);
|
||||
|
||||
output->push_back(RowSpan(left, right));
|
||||
|
||||
// If |it1| was completely consumed, move to the next one.
|
||||
if (it1->right == right)
|
||||
++it1;
|
||||
// If |it2| was completely consumed, move to the next one.
|
||||
if (it2->right == right)
|
||||
++it2;
|
||||
} while (it1 != end1 && it2 != end2);
|
||||
}
|
||||
|
||||
void DesktopRegion::IntersectWith(const DesktopRegion& region) {
|
||||
DesktopRegion old_region;
|
||||
Swap(&old_region);
|
||||
Intersect(old_region, region);
|
||||
}
|
||||
|
||||
void DesktopRegion::IntersectWith(const DesktopRect& rect) {
|
||||
DesktopRegion region;
|
||||
region.AddRect(rect);
|
||||
IntersectWith(region);
|
||||
}
|
||||
|
||||
void DesktopRegion::Translate(int32_t dx, int32_t dy) {
|
||||
for (RectsList::iterator it = rects_.begin(); it != rects_.end(); ++it) {
|
||||
it->Translate(dx, dy);
|
||||
Rows new_rows;
|
||||
|
||||
for (Rows::iterator it = rows_.begin(); it != rows_.end(); ++it) {
|
||||
Row* row = it->second;
|
||||
|
||||
row->top += dy;
|
||||
row->bottom += dy;
|
||||
|
||||
if (dx != 0) {
|
||||
// Translate each span.
|
||||
for (RowSpanSet::iterator span = row->spans.begin();
|
||||
span != row->spans.end(); ++span) {
|
||||
span->left += dx;
|
||||
span->right += dx;
|
||||
}
|
||||
}
|
||||
|
||||
if (dy != 0)
|
||||
new_rows.insert(new_rows.end(), Rows::value_type(row->bottom, row));
|
||||
}
|
||||
|
||||
if (dy != 0)
|
||||
new_rows.swap(rows_);
|
||||
}
|
||||
|
||||
void DesktopRegion::Swap(DesktopRegion* region) {
|
||||
rects_.swap(region->rects_);
|
||||
rows_.swap(region->rows_);
|
||||
}
|
||||
|
||||
// static
|
||||
bool DesktopRegion::CompareSpanRight(const RowSpan& r, int32_t value) {
|
||||
return r.right < value;
|
||||
}
|
||||
|
||||
// static
|
||||
bool DesktopRegion::CompareSpanLeft(const RowSpan& r, int32_t value) {
|
||||
return r.left < value;
|
||||
}
|
||||
|
||||
// static
|
||||
void DesktopRegion::AddSpanToRow(Row* row, int left, int right) {
|
||||
// First check if the new span is located to the right of all existing spans.
|
||||
// This is an optimization to avoid binary search in the case when rectangles
|
||||
// are inserted sequentially from left to right.
|
||||
if (row->spans.empty() || left > row->spans.back().right) {
|
||||
row->spans.push_back(RowSpan(left, right));
|
||||
return;
|
||||
}
|
||||
|
||||
// Find the first span that ends at or after |left|.
|
||||
RowSpanSet::iterator start =
|
||||
std::lower_bound(row->spans.begin(), row->spans.end(), left,
|
||||
CompareSpanRight);
|
||||
assert(start < row->spans.end());
|
||||
|
||||
// Find the first span that starts after |right|.
|
||||
RowSpanSet::iterator end =
|
||||
std::lower_bound(start, row->spans.end(), right + 1, CompareSpanLeft);
|
||||
if (end == row->spans.begin()) {
|
||||
// There are no overlaps. Just insert the new span at the beginning.
|
||||
row->spans.insert(row->spans.begin(), RowSpan(left, right));
|
||||
return;
|
||||
}
|
||||
|
||||
// Move end to the left, so that it points the last span that ends at or
|
||||
// before |right|.
|
||||
end--;
|
||||
|
||||
// At this point [start, end] is the range of spans that intersect with the
|
||||
// new one.
|
||||
if (end < start) {
|
||||
// There are no overlaps. Just insert the new span at the correct position.
|
||||
row->spans.insert(start, RowSpan(left, right));
|
||||
return;
|
||||
}
|
||||
|
||||
left = std::min(left, start->left);
|
||||
right = std::max(right, end->right);
|
||||
|
||||
// Replace range [start, end] with the new span.
|
||||
*start = RowSpan(left, right);
|
||||
++start;
|
||||
++end;
|
||||
if (start < end)
|
||||
row->spans.erase(start, end);
|
||||
}
|
||||
|
||||
// static
|
||||
bool DesktopRegion::IsSpanInRow(const Row& row, const RowSpan& span) {
|
||||
// Find the first span that starts at or after |span.left| and then check if
|
||||
// it's the same span.
|
||||
RowSpanSet::const_iterator it =
|
||||
std::lower_bound(row.spans.begin(), row.spans.end(), span.left,
|
||||
CompareSpanLeft);
|
||||
return it != row.spans.end() && *it == span;
|
||||
}
|
||||
|
||||
DesktopRegion::Iterator::Iterator(const DesktopRegion& region)
|
||||
: region_(region),
|
||||
it_(region.rects_.begin()) {
|
||||
row_(region.rows_.begin()),
|
||||
previous_row_(region.rows_.end()) {
|
||||
if (!IsAtEnd()) {
|
||||
assert(row_->second->spans.size() > 0);
|
||||
row_span_ = row_->second->spans.begin();
|
||||
UpdateCurrentRect();
|
||||
}
|
||||
}
|
||||
|
||||
bool DesktopRegion::Iterator::IsAtEnd() const {
|
||||
return it_ == region_.rects_.end();
|
||||
return row_ == region_.rows_.end();
|
||||
}
|
||||
|
||||
void DesktopRegion::Iterator::Advance() {
|
||||
++it_;
|
||||
assert(!IsAtEnd());
|
||||
|
||||
while (true) {
|
||||
++row_span_;
|
||||
if (row_span_ == row_->second->spans.end()) {
|
||||
previous_row_ = row_;
|
||||
++row_;
|
||||
if (row_ != region_.rows_.end()) {
|
||||
assert(row_->second->spans.size() > 0);
|
||||
row_span_ = row_->second->spans.begin();
|
||||
}
|
||||
}
|
||||
|
||||
if (IsAtEnd())
|
||||
return;
|
||||
|
||||
// If the same span exists on the previous row then skip it, as we've
|
||||
// already returned this span merged into the previous one, via
|
||||
// UpdateCurrentRect().
|
||||
if (previous_row_ != region_.rows_.end() &&
|
||||
previous_row_->second->bottom == row_->second->top &&
|
||||
IsSpanInRow(*previous_row_->second, *row_span_)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
assert(!IsAtEnd());
|
||||
UpdateCurrentRect();
|
||||
}
|
||||
|
||||
void DesktopRegion::Iterator::UpdateCurrentRect() {
|
||||
// Merge the current rectangle with the matching spans from later rows.
|
||||
int bottom;
|
||||
Rows::const_iterator bottom_row = row_;
|
||||
Rows::const_iterator previous;
|
||||
do {
|
||||
bottom = bottom_row->second->bottom;
|
||||
previous = bottom_row;
|
||||
++bottom_row;
|
||||
} while (bottom_row != region_.rows_.end() &&
|
||||
previous->second->bottom == bottom_row->second->top &&
|
||||
IsSpanInRow(*bottom_row->second, *row_span_));
|
||||
rect_ = DesktopRect::MakeLTRB(row_span_->left, row_->second->top,
|
||||
row_span_->right, bottom);
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
|
||||
@ -11,6 +11,7 @@
|
||||
#ifndef WEBRTC_MODULES_DESKTOP_CAPTURE_DESKTOP_REGION_H_
|
||||
#define WEBRTC_MODULES_DESKTOP_CAPTURE_DESKTOP_REGION_H_
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include "webrtc/modules/desktop_capture/desktop_geometry.h"
|
||||
@ -21,9 +22,44 @@ namespace webrtc {
|
||||
|
||||
// DesktopRegion represents a region of the screen or window.
|
||||
//
|
||||
// TODO(sergeyu): Current implementation just stores list of rectangles that may
|
||||
// overlap. Optimize it.
|
||||
// Internally each region is stored as a set of rows where each row contains one
|
||||
// or more rectangles aligned vertically.
|
||||
class DesktopRegion {
|
||||
private:
|
||||
// The following private types need to be declared first because they are used
|
||||
// in the public Iterator.
|
||||
|
||||
// RowSpan represents a horizontal span withing a single row.
|
||||
struct RowSpan {
|
||||
RowSpan(int32_t left, int32_t right);
|
||||
|
||||
// Used by std::vector<>.
|
||||
bool operator==(const RowSpan& that) const {
|
||||
return left == that.left && right == that.right;
|
||||
}
|
||||
|
||||
int32_t left;
|
||||
int32_t right;
|
||||
};
|
||||
|
||||
typedef std::vector<RowSpan> RowSpanSet;
|
||||
|
||||
// Row represents a single row of a region. A row is set of rectangles that
|
||||
// have the same vertical position.
|
||||
struct Row {
|
||||
Row(int32_t top, int32_t bottom);
|
||||
|
||||
int32_t top;
|
||||
int32_t bottom;
|
||||
|
||||
RowSpanSet spans;
|
||||
};
|
||||
|
||||
// Type used to store list of rows in the region. The bottom position of row
|
||||
// is used as the key so that rows are always ordered by their position. The
|
||||
// map stores pointers to make Translate() more efficient.
|
||||
typedef std::map<int, Row*> Rows;
|
||||
|
||||
public:
|
||||
// Iterator that can be used to iterate over rectangles of a DesktopRegion.
|
||||
// The region must not be mutated while the iterator is used.
|
||||
@ -34,24 +70,51 @@ class DesktopRegion {
|
||||
bool IsAtEnd() const;
|
||||
void Advance();
|
||||
|
||||
const DesktopRect& rect() const { return *it_; }
|
||||
const DesktopRect& rect() const { return rect_; }
|
||||
|
||||
private:
|
||||
const DesktopRegion& region_;
|
||||
std::vector<DesktopRect>::const_iterator it_;
|
||||
|
||||
// Updates |rect_| based on the current |row_| and |row_span_|. If
|
||||
// |row_span_| matches spans on consecutive rows then they are also merged
|
||||
// into |rect_|, to generate more efficient output.
|
||||
void UpdateCurrentRect();
|
||||
|
||||
Rows::const_iterator row_;
|
||||
Rows::const_iterator previous_row_;
|
||||
RowSpanSet::const_iterator row_span_;
|
||||
DesktopRect rect_;
|
||||
};
|
||||
|
||||
DesktopRegion();
|
||||
explicit DesktopRegion(const DesktopRect& rect);
|
||||
DesktopRegion(const DesktopRect* rects, int count);
|
||||
DesktopRegion(const DesktopRegion& other);
|
||||
~DesktopRegion();
|
||||
|
||||
bool is_empty() const { return rects_.empty(); }
|
||||
DesktopRegion& operator=(const DesktopRegion& other);
|
||||
|
||||
bool is_empty() const { return rows_.empty(); }
|
||||
|
||||
bool Equals(const DesktopRegion& region) const;
|
||||
|
||||
// Reset the region to be empty.
|
||||
void Clear();
|
||||
|
||||
// Reset region to contain just |rect|.
|
||||
void SetRect(const DesktopRect& rect);
|
||||
|
||||
// Adds specified rect(s) or region to the region.
|
||||
void AddRect(const DesktopRect& rect);
|
||||
void AddRects(const DesktopRect* rects, int count);
|
||||
void AddRegion(const DesktopRegion& region);
|
||||
|
||||
// Finds intersection of two regions and stores them in the current region.
|
||||
void Intersect(const DesktopRegion& region1, const DesktopRegion& region2);
|
||||
|
||||
// Same as above but intersects content of the current region with |region|.
|
||||
void IntersectWith(const DesktopRegion& region);
|
||||
|
||||
// Clips the region by the |rect|.
|
||||
void IntersectWith(const DesktopRect& rect);
|
||||
|
||||
@ -61,8 +124,29 @@ class DesktopRegion {
|
||||
void Swap(DesktopRegion* region);
|
||||
|
||||
private:
|
||||
typedef std::vector<DesktopRect> RectsList;
|
||||
RectsList rects_;
|
||||
// Comparison functions used for std::lower_bound(). Compare left or right
|
||||
// edges withs a given |value|.
|
||||
static bool CompareSpanLeft(const RowSpan& r, int32_t value);
|
||||
static bool CompareSpanRight(const RowSpan& r, int32_t value);
|
||||
|
||||
// Adds a new span to the row, coalescing spans if necessary.
|
||||
static void AddSpanToRow(Row* row, int32_t left, int32_t right);
|
||||
|
||||
// Returns true if the |span| exists in the given |row|.
|
||||
static bool IsSpanInRow(const Row& row, const RowSpan& rect);
|
||||
|
||||
// Calculates the intersection of two sets of spans.
|
||||
static void IntersectRows(const RowSpanSet& set1,
|
||||
const RowSpanSet& set2,
|
||||
RowSpanSet* output);
|
||||
|
||||
// Merges |row| with the row above it if they contain the same spans. Doesn't
|
||||
// do anything if called with |row| set to rows_.begin() (i.e. first row of
|
||||
// the region). If the rows were merged |row| remains a valid iterator to the
|
||||
// merged row.
|
||||
void MergeWithPrecedingRow(Rows::iterator row);
|
||||
|
||||
Rows rows_;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
464
webrtc/modules/desktop_capture/desktop_region_unittest.cc
Normal file
464
webrtc/modules/desktop_capture/desktop_region_unittest.cc
Normal file
@ -0,0 +1,464 @@
|
||||
/*
|
||||
* Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "webrtc/modules/desktop_capture/desktop_region.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
namespace {
|
||||
|
||||
int RadmonInt(int max) {
|
||||
return (rand() / 256) % max;
|
||||
}
|
||||
|
||||
void CompareRegion(const DesktopRegion& region,
|
||||
const DesktopRect rects[], int rects_size) {
|
||||
DesktopRegion::Iterator it(region);
|
||||
for (int i = 0; i < rects_size; ++i) {
|
||||
SCOPED_TRACE(i);
|
||||
ASSERT_FALSE(it.IsAtEnd());
|
||||
EXPECT_TRUE(it.rect().equals(rects[i]))
|
||||
<< it.rect().left() << "-" << it.rect().right() << "."
|
||||
<< it.rect().top() << "-" << it.rect().bottom() << " "
|
||||
<< rects[i].left() << "-" << rects[i].right() << "."
|
||||
<< rects[i].top() << "-" << rects[i].bottom();
|
||||
it.Advance();
|
||||
}
|
||||
EXPECT_TRUE(it.IsAtEnd());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// Verify that regions are empty when created.
|
||||
TEST(DesktopRegionTest, Empty) {
|
||||
DesktopRegion r;
|
||||
CompareRegion(r, NULL, 0);
|
||||
}
|
||||
|
||||
// Verify that empty rectangles are ignored.
|
||||
TEST(DesktopRegionTest, AddEmpty) {
|
||||
DesktopRegion r;
|
||||
DesktopRect rect = DesktopRect::MakeXYWH(1, 2, 0, 0);
|
||||
r.AddRect(rect);
|
||||
CompareRegion(r, NULL, 0);
|
||||
}
|
||||
|
||||
// Verify that regions with a single rectangles are handled properly.
|
||||
TEST(DesktopRegionTest, SingleRect) {
|
||||
DesktopRegion r;
|
||||
DesktopRect rect = DesktopRect::MakeXYWH(1, 2, 3, 4);
|
||||
r.AddRect(rect);
|
||||
CompareRegion(r, &rect, 1);
|
||||
}
|
||||
|
||||
// Verify that non-overlapping rectangles are not merged.
|
||||
TEST(DesktopRegionTest, NonOverlappingRects) {
|
||||
struct Case {
|
||||
int count;
|
||||
DesktopRect rects[4];
|
||||
} cases[] = {
|
||||
{ 1, { DesktopRect::MakeXYWH(10, 10, 10, 10) } },
|
||||
{ 2, { DesktopRect::MakeXYWH(10, 10, 10, 10),
|
||||
DesktopRect::MakeXYWH(30, 10, 10, 15) } },
|
||||
{ 2, { DesktopRect::MakeXYWH(10, 10, 10, 10),
|
||||
DesktopRect::MakeXYWH(10, 30, 10, 5) } },
|
||||
{ 3, { DesktopRect::MakeXYWH(10, 10, 10, 9),
|
||||
DesktopRect::MakeXYWH(30, 10, 15, 10),
|
||||
DesktopRect::MakeXYWH(10, 30, 8, 10) } },
|
||||
{ 4, { DesktopRect::MakeXYWH(0, 0, 30, 10),
|
||||
DesktopRect::MakeXYWH(40, 0, 10, 30),
|
||||
DesktopRect::MakeXYWH(0, 20, 10, 30),
|
||||
DesktopRect::MakeXYWH(20, 40, 30, 10) } },
|
||||
{ 4, { DesktopRect::MakeXYWH(0, 0, 10, 100),
|
||||
DesktopRect::MakeXYWH(20, 10, 30, 10),
|
||||
DesktopRect::MakeXYWH(20, 30, 30, 10),
|
||||
DesktopRect::MakeXYWH(20, 50, 30, 10) } },
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < (sizeof(cases) / sizeof(Case)); ++i) {
|
||||
SCOPED_TRACE(i);
|
||||
|
||||
DesktopRegion r;
|
||||
|
||||
for (int j = 0; j < cases[i].count; ++j) {
|
||||
r.AddRect(cases[i].rects[j]);
|
||||
}
|
||||
CompareRegion(r, cases[i].rects, cases[i].count);
|
||||
|
||||
SCOPED_TRACE("Reverse");
|
||||
|
||||
// Try inserting rects in reverse order.
|
||||
r.Clear();
|
||||
for (int j = cases[i].count - 1; j >= 0; --j) {
|
||||
r.AddRect(cases[i].rects[j]);
|
||||
}
|
||||
CompareRegion(r, cases[i].rects, cases[i].count);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(DesktopRegionTest, TwoRects) {
|
||||
struct Case {
|
||||
DesktopRect input_rect1;
|
||||
DesktopRect input_rect2;
|
||||
int expected_count;
|
||||
DesktopRect expected_rects[3];
|
||||
} cases[] = {
|
||||
// Touching rectangles that merge into one.
|
||||
{ DesktopRect::MakeLTRB(100, 100, 200, 200),
|
||||
DesktopRect::MakeLTRB(0, 100, 100, 200),
|
||||
1, { DesktopRect::MakeLTRB(0, 100, 200, 200) } },
|
||||
{ DesktopRect::MakeLTRB(100, 100, 200, 200),
|
||||
DesktopRect::MakeLTRB(100, 0, 200, 100),
|
||||
1, { DesktopRect::MakeLTRB(100, 0, 200, 200) } },
|
||||
|
||||
// Rectangles touching on the vertical edge.
|
||||
{ DesktopRect::MakeLTRB(100, 100, 200, 200),
|
||||
DesktopRect::MakeLTRB(0, 150, 100, 250),
|
||||
3, { DesktopRect::MakeLTRB(100, 100, 200, 150),
|
||||
DesktopRect::MakeLTRB(0, 150, 200, 200),
|
||||
DesktopRect::MakeLTRB(0, 200, 100, 250) } },
|
||||
{ DesktopRect::MakeLTRB(100, 100, 200, 200),
|
||||
DesktopRect::MakeLTRB(0, 50, 100, 150),
|
||||
3, { DesktopRect::MakeLTRB(0, 50, 100, 100),
|
||||
DesktopRect::MakeLTRB(0, 100, 200, 150),
|
||||
DesktopRect::MakeLTRB(100, 150, 200, 200) } },
|
||||
{ DesktopRect::MakeLTRB(100, 100, 200, 200),
|
||||
DesktopRect::MakeLTRB(0, 120, 100, 180),
|
||||
3, { DesktopRect::MakeLTRB(100, 100, 200, 120),
|
||||
DesktopRect::MakeLTRB(0, 120, 200, 180),
|
||||
DesktopRect::MakeLTRB(100, 180, 200, 200) } },
|
||||
|
||||
// Rectangles touching on the horizontal edge.
|
||||
{ DesktopRect::MakeLTRB(100, 100, 200, 200),
|
||||
DesktopRect::MakeLTRB(150, 0, 250, 100),
|
||||
2, { DesktopRect::MakeLTRB(150, 0, 250, 100),
|
||||
DesktopRect::MakeLTRB(100, 100, 200, 200) } },
|
||||
{ DesktopRect::MakeLTRB(100, 100, 200, 200),
|
||||
DesktopRect::MakeLTRB(50, 0, 150, 100),
|
||||
2, { DesktopRect::MakeLTRB(50, 0, 150, 100),
|
||||
DesktopRect::MakeLTRB(100, 100, 200, 200) } },
|
||||
{ DesktopRect::MakeLTRB(100, 100, 200, 200),
|
||||
DesktopRect::MakeLTRB(120, 0, 180, 100),
|
||||
2, { DesktopRect::MakeLTRB(120, 0, 180, 100),
|
||||
DesktopRect::MakeLTRB(100, 100, 200, 200) } },
|
||||
|
||||
// Overlapping rectangles.
|
||||
{ DesktopRect::MakeLTRB(100, 100, 200, 200),
|
||||
DesktopRect::MakeLTRB(50, 50, 150, 150),
|
||||
3, { DesktopRect::MakeLTRB(50, 50, 150, 100),
|
||||
DesktopRect::MakeLTRB(50, 100, 200, 150),
|
||||
DesktopRect::MakeLTRB(100, 150, 200, 200) } },
|
||||
{ DesktopRect::MakeLTRB(100, 100, 200, 200),
|
||||
DesktopRect::MakeLTRB(150, 50, 250, 150),
|
||||
3, { DesktopRect::MakeLTRB(150, 50, 250, 100),
|
||||
DesktopRect::MakeLTRB(100, 100, 250, 150),
|
||||
DesktopRect::MakeLTRB(100, 150, 200, 200) } },
|
||||
{ DesktopRect::MakeLTRB(100, 100, 200, 200),
|
||||
DesktopRect::MakeLTRB(0, 120, 150, 180),
|
||||
3, { DesktopRect::MakeLTRB(100, 100, 200, 120),
|
||||
DesktopRect::MakeLTRB(0, 120, 200, 180),
|
||||
DesktopRect::MakeLTRB(100, 180, 200, 200) } },
|
||||
{ DesktopRect::MakeLTRB(100, 100, 200, 200),
|
||||
DesktopRect::MakeLTRB(120, 0, 180, 150),
|
||||
2, { DesktopRect::MakeLTRB(120, 0, 180, 100),
|
||||
DesktopRect::MakeLTRB(100, 100, 200, 200) } },
|
||||
{ DesktopRect::MakeLTRB(100, 0, 200, 300),
|
||||
DesktopRect::MakeLTRB(0, 100, 300, 200),
|
||||
3, { DesktopRect::MakeLTRB(100, 0, 200, 100),
|
||||
DesktopRect::MakeLTRB(0, 100, 300, 200),
|
||||
DesktopRect::MakeLTRB(100, 200, 200, 300)} },
|
||||
|
||||
// One rectangle enclosing another.
|
||||
{ DesktopRect::MakeLTRB(100, 100, 200, 200),
|
||||
DesktopRect::MakeLTRB(150, 150, 180, 180),
|
||||
1, { DesktopRect::MakeLTRB(100, 100, 200, 200) } },
|
||||
{ DesktopRect::MakeLTRB(100, 100, 200, 200),
|
||||
DesktopRect::MakeLTRB(100, 100, 180, 180),
|
||||
1, { DesktopRect::MakeLTRB(100, 100, 200, 200) } },
|
||||
{ DesktopRect::MakeLTRB(100, 100, 200, 200),
|
||||
DesktopRect::MakeLTRB(150, 150, 200, 200),
|
||||
1, { DesktopRect::MakeLTRB(100, 100, 200, 200) } },
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < (sizeof(cases) / sizeof(Case)); ++i) {
|
||||
SCOPED_TRACE(i);
|
||||
|
||||
DesktopRegion r;
|
||||
|
||||
r.AddRect(cases[i].input_rect1);
|
||||
r.AddRect(cases[i].input_rect2);
|
||||
CompareRegion(r, cases[i].expected_rects, cases[i].expected_count);
|
||||
|
||||
SCOPED_TRACE("Reverse");
|
||||
|
||||
// Run the same test with rectangles inserted in reverse order.
|
||||
r.Clear();
|
||||
r.AddRect(cases[i].input_rect2);
|
||||
r.AddRect(cases[i].input_rect1);
|
||||
CompareRegion(r, cases[i].expected_rects, cases[i].expected_count);
|
||||
}
|
||||
}
|
||||
|
||||
// Verify that DesktopRegion::AddRectToRow() works correctly by creating a row
|
||||
// of not overlapping rectangles and insert an overlapping rectangle into the
|
||||
// row at different positions. Result is verified by building a map of the
|
||||
// region in an array and comparing it with the expected values.
|
||||
TEST(DesktopRegionTest, SameRow) {
|
||||
const int kMapWidth = 50;
|
||||
const int kLastRectSizes[] = {3, 27};
|
||||
|
||||
DesktopRegion base_region;
|
||||
bool base_map[kMapWidth] = { false, };
|
||||
|
||||
base_region.AddRect(DesktopRect::MakeXYWH(5, 0, 5, 1));
|
||||
std::fill_n(base_map + 5, 5, true);
|
||||
base_region.AddRect(DesktopRect::MakeXYWH(15, 0, 5, 1));
|
||||
std::fill_n(base_map + 15, 5, true);
|
||||
base_region.AddRect(DesktopRect::MakeXYWH(25, 0, 5, 1));
|
||||
std::fill_n(base_map + 25, 5, true);
|
||||
base_region.AddRect(DesktopRect::MakeXYWH(35, 0, 5, 1));
|
||||
std::fill_n(base_map + 35, 5, true);
|
||||
base_region.AddRect(DesktopRect::MakeXYWH(45, 0, 5, 1));
|
||||
std::fill_n(base_map + 45, 5, true);
|
||||
|
||||
for (size_t i = 0; i < sizeof(kLastRectSizes) / sizeof(kLastRectSizes[0]);
|
||||
i++) {
|
||||
int last_rect_size = kLastRectSizes[i];
|
||||
for (int x = 0; x < kMapWidth - last_rect_size; x++) {
|
||||
SCOPED_TRACE(x);
|
||||
|
||||
DesktopRegion r = base_region;
|
||||
r.AddRect(DesktopRect::MakeXYWH(x, 0, last_rect_size, 1));
|
||||
|
||||
bool expected_map[kMapWidth];
|
||||
std::copy(base_map, base_map + kMapWidth, expected_map);
|
||||
std::fill_n(expected_map + x, last_rect_size, true);
|
||||
|
||||
bool map[kMapWidth] = { false, };
|
||||
|
||||
int pos = -1;
|
||||
for (DesktopRegion::Iterator it(r); !it.IsAtEnd(); it.Advance()) {
|
||||
EXPECT_GT(it.rect().left(), pos);
|
||||
pos = it.rect().right();
|
||||
std::fill_n(map + it.rect().left(), it.rect().width(), true);
|
||||
}
|
||||
|
||||
EXPECT_TRUE(std::equal(map, map + kMapWidth, expected_map));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(DesktopRegionTest, ComplexRegions) {
|
||||
struct Case {
|
||||
int input_count;
|
||||
DesktopRect input_rects[4];
|
||||
int expected_count;
|
||||
DesktopRect expected_rects[6];
|
||||
} cases[] = {
|
||||
{ 3, { DesktopRect::MakeLTRB(100, 100, 200, 200),
|
||||
DesktopRect::MakeLTRB(0, 100, 100, 200),
|
||||
DesktopRect::MakeLTRB(310, 110, 320, 120), },
|
||||
2, { DesktopRect::MakeLTRB(0, 100, 200, 200),
|
||||
DesktopRect::MakeLTRB(310, 110, 320, 120) } },
|
||||
{ 3, { DesktopRect::MakeLTRB(100, 100, 200, 200),
|
||||
DesktopRect::MakeLTRB(50, 50, 150, 150),
|
||||
DesktopRect::MakeLTRB(300, 125, 350, 175) },
|
||||
4, { DesktopRect::MakeLTRB(50, 50, 150, 100),
|
||||
DesktopRect::MakeLTRB(50, 100, 200, 150),
|
||||
DesktopRect::MakeLTRB(300, 125, 350, 175),
|
||||
DesktopRect::MakeLTRB(100, 150, 200, 200) } },
|
||||
{ 4, { DesktopRect::MakeLTRB(0, 0, 30, 30),
|
||||
DesktopRect::MakeLTRB(10, 10, 40, 40),
|
||||
DesktopRect::MakeLTRB(20, 20, 50, 50),
|
||||
DesktopRect::MakeLTRB(50, 0, 65, 15) },
|
||||
6, { DesktopRect::MakeLTRB(0, 0, 30, 10),
|
||||
DesktopRect::MakeLTRB(50, 0, 65, 15),
|
||||
DesktopRect::MakeLTRB(0, 10, 40, 20),
|
||||
DesktopRect::MakeLTRB(0, 20, 50, 30),
|
||||
DesktopRect::MakeLTRB(10, 30, 50, 40),
|
||||
DesktopRect::MakeLTRB(20, 40, 50, 50) } },
|
||||
{ 3, { DesktopRect::MakeLTRB(10, 10, 40, 20),
|
||||
DesktopRect::MakeLTRB(10, 30, 40, 40),
|
||||
DesktopRect::MakeLTRB(10, 20, 40, 30) },
|
||||
1, { DesktopRect::MakeLTRB(10, 10, 40, 40) } },
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < (sizeof(cases) / sizeof(Case)); ++i) {
|
||||
SCOPED_TRACE(i);
|
||||
|
||||
DesktopRegion r;
|
||||
r.AddRects(cases[i].input_rects, cases[i].input_count);
|
||||
CompareRegion(r, cases[i].expected_rects, cases[i].expected_count);
|
||||
|
||||
// Try inserting rectangles in reverse order.
|
||||
r.Clear();
|
||||
for (int j = cases[i].input_count - 1; j >= 0; --j) {
|
||||
r.AddRect(cases[i].input_rects[j]);
|
||||
}
|
||||
CompareRegion(r, cases[i].expected_rects, cases[i].expected_count);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(DesktopRegionTest, Equals) {
|
||||
struct Region {
|
||||
int count;
|
||||
DesktopRect rects[4];
|
||||
int id;
|
||||
} regions[] = {
|
||||
// Same region with one of the rectangles 1 pixel wider/taller.
|
||||
{ 2, { DesktopRect::MakeLTRB(0, 100, 200, 200),
|
||||
DesktopRect::MakeLTRB(310, 110, 320, 120) }, 0 },
|
||||
{ 2, { DesktopRect::MakeLTRB(0, 100, 201, 200),
|
||||
DesktopRect::MakeLTRB(310, 110, 320, 120) }, 1 },
|
||||
{ 2, { DesktopRect::MakeLTRB(0, 100, 200, 201),
|
||||
DesktopRect::MakeLTRB(310, 110, 320, 120) }, 2 },
|
||||
|
||||
// Same region with one of the rectangles shifted horizontally and
|
||||
// vertically.
|
||||
{ 4, { DesktopRect::MakeLTRB(0, 0, 30, 30),
|
||||
DesktopRect::MakeLTRB(10, 10, 40, 40),
|
||||
DesktopRect::MakeLTRB(20, 20, 50, 50),
|
||||
DesktopRect::MakeLTRB(50, 0, 65, 15) }, 3 },
|
||||
{ 4, { DesktopRect::MakeLTRB(0, 0, 30, 30),
|
||||
DesktopRect::MakeLTRB(10, 10, 40, 40),
|
||||
DesktopRect::MakeLTRB(20, 20, 50, 50),
|
||||
DesktopRect::MakeLTRB(50, 1, 65, 16) }, 4 },
|
||||
{ 4, { DesktopRect::MakeLTRB(0, 0, 30, 30),
|
||||
DesktopRect::MakeLTRB(10, 10, 40, 40),
|
||||
DesktopRect::MakeLTRB(20, 20, 50, 50),
|
||||
DesktopRect::MakeLTRB(51, 0, 66, 15) }, 5 },
|
||||
|
||||
// Same region defined by a different set of rectangles - one of the
|
||||
// rectangle is split horizontally into two.
|
||||
{ 3, { DesktopRect::MakeLTRB(100, 100, 200, 200),
|
||||
DesktopRect::MakeLTRB(50, 50, 150, 150),
|
||||
DesktopRect::MakeLTRB(300, 125, 350, 175) }, 6 },
|
||||
{ 4, { DesktopRect::MakeLTRB(100, 100, 200, 200),
|
||||
DesktopRect::MakeLTRB(50, 50, 100, 150),
|
||||
DesktopRect::MakeLTRB(100, 50, 150, 150),
|
||||
DesktopRect::MakeLTRB(300, 125, 350, 175) }, 6 },
|
||||
|
||||
// Rectangle region defined by a set of rectangles that merge into one.
|
||||
{ 3, { DesktopRect::MakeLTRB(10, 10, 40, 20),
|
||||
DesktopRect::MakeLTRB(10, 30, 40, 40),
|
||||
DesktopRect::MakeLTRB(10, 20, 40, 30) }, 7 },
|
||||
{ 1, { DesktopRect::MakeLTRB(10, 10, 40, 40) }, 7 },
|
||||
};
|
||||
int kTotalRegions = sizeof(regions) / sizeof(Region);
|
||||
|
||||
for (int i = 0; i < kTotalRegions; ++i) {
|
||||
SCOPED_TRACE(i);
|
||||
|
||||
DesktopRegion r1(regions[i].rects, regions[i].count);
|
||||
for (int j = 0; j < kTotalRegions; ++j) {
|
||||
SCOPED_TRACE(j);
|
||||
|
||||
DesktopRegion r2(regions[j].rects, regions[j].count);
|
||||
EXPECT_EQ(regions[i].id == regions[j].id, r1.Equals(r2));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(DesktopRegionTest, Translate) {
|
||||
struct Case {
|
||||
int input_count;
|
||||
DesktopRect input_rects[4];
|
||||
int dx;
|
||||
int dy;
|
||||
int expected_count;
|
||||
DesktopRect expected_rects[5];
|
||||
} cases[] = {
|
||||
{ 3, { DesktopRect::MakeLTRB(0, 0, 30, 30),
|
||||
DesktopRect::MakeLTRB(10, 10, 40, 40),
|
||||
DesktopRect::MakeLTRB(20, 20, 50, 50) },
|
||||
3, 5,
|
||||
5, { DesktopRect::MakeLTRB(3, 5, 33, 15),
|
||||
DesktopRect::MakeLTRB(3, 15, 43, 25),
|
||||
DesktopRect::MakeLTRB(3, 25, 53, 35),
|
||||
DesktopRect::MakeLTRB(13, 35, 53, 45),
|
||||
DesktopRect::MakeLTRB(23, 45, 53, 55) } },
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < (sizeof(cases) / sizeof(Case)); ++i) {
|
||||
SCOPED_TRACE(i);
|
||||
|
||||
DesktopRegion r(cases[i].input_rects, cases[i].input_count);
|
||||
r.Translate(cases[i].dx, cases[i].dy);
|
||||
CompareRegion(r, cases[i].expected_rects, cases[i].expected_count);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(DesktopRegionTest, Intersect) {
|
||||
struct Case {
|
||||
int input1_count;
|
||||
DesktopRect input1_rects[4];
|
||||
int input2_count;
|
||||
DesktopRect input2_rects[4];
|
||||
int expected_count;
|
||||
DesktopRect expected_rects[5];
|
||||
} cases[] = {
|
||||
{ 1, { DesktopRect::MakeLTRB(0, 0, 100, 100) },
|
||||
1, { DesktopRect::MakeLTRB(50, 50, 150, 150) },
|
||||
1, { DesktopRect::MakeLTRB(50, 50, 100, 100) } },
|
||||
|
||||
{ 1, { DesktopRect::MakeLTRB(100, 0, 200, 300) },
|
||||
1, { DesktopRect::MakeLTRB(0, 100, 300, 200) },
|
||||
1, { DesktopRect::MakeLTRB(100, 100, 200, 200) } },
|
||||
|
||||
{ 1, { DesktopRect::MakeLTRB(0, 0, 100, 100) },
|
||||
2, { DesktopRect::MakeLTRB(50, 10, 150, 30),
|
||||
DesktopRect::MakeLTRB(50, 30, 160, 50) },
|
||||
1, { DesktopRect::MakeLTRB(50, 10, 100, 50) } },
|
||||
|
||||
{ 1, { DesktopRect::MakeLTRB(0, 0, 100, 100) },
|
||||
2, { DesktopRect::MakeLTRB(50, 10, 150, 30),
|
||||
DesktopRect::MakeLTRB(50, 30, 90, 50) },
|
||||
2, { DesktopRect::MakeLTRB(50, 10, 100, 30),
|
||||
DesktopRect::MakeLTRB(50, 30, 90, 50) } },
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < (sizeof(cases) / sizeof(Case)); ++i) {
|
||||
SCOPED_TRACE(i);
|
||||
|
||||
DesktopRegion r1(cases[i].input1_rects, cases[i].input1_count);
|
||||
DesktopRegion r2(cases[i].input2_rects, cases[i].input2_count);
|
||||
|
||||
DesktopRegion r;
|
||||
r.Intersect(r1, r2);
|
||||
|
||||
CompareRegion(r, cases[i].expected_rects, cases[i].expected_count);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(DesktopRegionTest, DISABLED_Performance) {
|
||||
for (int c = 0; c < 1000; ++c) {
|
||||
DesktopRegion r;
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
r.AddRect(DesktopRect::MakeXYWH(
|
||||
RadmonInt(1000), RadmonInt(1000), 200, 200));
|
||||
}
|
||||
|
||||
for (int i = 0; i < 1000; ++i) {
|
||||
r.AddRect(DesktopRect::MakeXYWH(
|
||||
RadmonInt(1000), RadmonInt(1000),
|
||||
5 + RadmonInt(10) * 5, 5 + RadmonInt(10) * 5));
|
||||
}
|
||||
|
||||
// Iterate over the rectangles.
|
||||
for (DesktopRegion::Iterator it(r); !it.IsAtEnd(); it.Advance()) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
Loading…
x
Reference in New Issue
Block a user