summaryrefslogtreecommitdiff
path: root/chromium/cc/base
diff options
context:
space:
mode:
authorZeno Albisser <zeno.albisser@digia.com>2013-08-15 21:46:11 +0200
committerZeno Albisser <zeno.albisser@digia.com>2013-08-15 21:46:11 +0200
commit679147eead574d186ebf3069647b4c23e8ccace6 (patch)
treefc247a0ac8ff119f7c8550879ebb6d3dd8d1ff69 /chromium/cc/base
downloadqtwebengine-chromium-679147eead574d186ebf3069647b4c23e8ccace6.tar.gz
Initial import.
Diffstat (limited to 'chromium/cc/base')
-rw-r--r--chromium/cc/base/cc_export.h29
-rw-r--r--chromium/cc/base/completion_event.h63
-rw-r--r--chromium/cc/base/float_quad_unittest.cc65
-rw-r--r--chromium/cc/base/invalidation_region.cc48
-rw-r--r--chromium/cc/base/invalidation_region.h34
-rw-r--r--chromium/cc/base/math_util.cc576
-rw-r--r--chromium/cc/base/math_util.h175
-rw-r--r--chromium/cc/base/math_util_unittest.cc122
-rw-r--r--chromium/cc/base/region.cc133
-rw-r--r--chromium/cc/base/region.h135
-rw-r--r--chromium/cc/base/region_unittest.cc454
-rw-r--r--chromium/cc/base/scoped_ptr_algorithm.h30
-rw-r--r--chromium/cc/base/scoped_ptr_deque.h137
-rw-r--r--chromium/cc/base/scoped_ptr_hash_map.h157
-rw-r--r--chromium/cc/base/scoped_ptr_vector.h180
-rw-r--r--chromium/cc/base/scoped_ptr_vector_unittest.cc72
-rw-r--r--chromium/cc/base/switches.cc150
-rw-r--r--chromium/cc/base/switches.h73
-rw-r--r--chromium/cc/base/tiling_data.cc408
-rw-r--r--chromium/cc/base/tiling_data.h148
-rw-r--r--chromium/cc/base/tiling_data_unittest.cc1171
-rw-r--r--chromium/cc/base/util.h29
-rw-r--r--chromium/cc/base/util_unittest.cc67
23 files changed, 4456 insertions, 0 deletions
diff --git a/chromium/cc/base/cc_export.h b/chromium/cc/base/cc_export.h
new file mode 100644
index 00000000000..fe0e0e369c7
--- /dev/null
+++ b/chromium/cc/base/cc_export.h
@@ -0,0 +1,29 @@
+// Copyright (c) 2012 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.
+
+#ifndef CC_BASE_CC_EXPORT_H_
+#define CC_BASE_CC_EXPORT_H_
+
+#if defined(COMPONENT_BUILD)
+#if defined(WIN32)
+
+#if defined(CC_IMPLEMENTATION)
+#define CC_EXPORT __declspec(dllexport)
+#else
+#define CC_EXPORT __declspec(dllimport)
+#endif // defined(CC_IMPLEMENTATION)
+
+#else // defined(WIN32)
+#if defined(CC_IMPLEMENTATION)
+#define CC_EXPORT __attribute__((visibility("default")))
+#else
+#define CC_EXPORT
+#endif
+#endif
+
+#else // defined(COMPONENT_BUILD)
+#define CC_EXPORT
+#endif
+
+#endif // CC_BASE_CC_EXPORT_H_
diff --git a/chromium/cc/base/completion_event.h b/chromium/cc/base/completion_event.h
new file mode 100644
index 00000000000..759ce9c3a27
--- /dev/null
+++ b/chromium/cc/base/completion_event.h
@@ -0,0 +1,63 @@
+// Copyright 2011 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.
+
+#ifndef CC_BASE_COMPLETION_EVENT_H_
+#define CC_BASE_COMPLETION_EVENT_H_
+
+#include "base/logging.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/thread_restrictions.h"
+
+namespace cc {
+
+// Used for making blocking calls from one thread to another. Use only when
+// absolutely certain that doing-so will not lead to a deadlock.
+//
+// It is safe to destroy this object as soon as Wait() returns.
+class CompletionEvent {
+ public:
+ CompletionEvent()
+ : event_(false /* manual_reset */, false /* initially_signaled */) {
+#ifndef NDEBUG
+ waited_ = false;
+ signaled_ = false;
+#endif
+ }
+
+ ~CompletionEvent() {
+#ifndef NDEBUG
+ DCHECK(waited_);
+ DCHECK(signaled_);
+#endif
+ }
+
+ void Wait() {
+#ifndef NDEBUG
+ DCHECK(!waited_);
+ waited_ = true;
+#endif
+ base::ThreadRestrictions::ScopedAllowWait allow_wait;
+ event_.Wait();
+ }
+
+ void Signal() {
+#ifndef NDEBUG
+ DCHECK(!signaled_);
+ signaled_ = true;
+#endif
+ event_.Signal();
+ }
+
+ private:
+ base::WaitableEvent event_;
+#ifndef NDEBUG
+ // Used to assert that Wait() and Signal() are each called exactly once.
+ bool waited_;
+ bool signaled_;
+#endif
+};
+
+} // namespace cc
+
+#endif // CC_BASE_COMPLETION_EVENT_H_
diff --git a/chromium/cc/base/float_quad_unittest.cc b/chromium/cc/base/float_quad_unittest.cc
new file mode 100644
index 00000000000..bb3446c0d69
--- /dev/null
+++ b/chromium/cc/base/float_quad_unittest.cc
@@ -0,0 +1,65 @@
+// Copyright 2011 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 "cc/base/math_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/quad_f.h"
+#include "ui/gfx/rect_f.h"
+#include "ui/gfx/transform.h"
+
+namespace cc {
+namespace {
+
+// TODO(danakj) Move this test to ui/gfx/ when we don't need MathUtil::MapQuad.
+TEST(FloatQuadTest, IsRectilinearTest) {
+ const int kNumRectilinear = 8;
+ gfx::Transform rectilinear_trans[kNumRectilinear];
+ rectilinear_trans[1].Rotate(90.0);
+ rectilinear_trans[2].Rotate(180.0);
+ rectilinear_trans[3].Rotate(270.0);
+ rectilinear_trans[4].SkewX(0.00000000001);
+ rectilinear_trans[5].SkewY(0.00000000001);
+ rectilinear_trans[6].Scale(0.00001, 0.00001);
+ rectilinear_trans[6].Rotate(180.0);
+ rectilinear_trans[7].Scale(100000, 100000);
+ rectilinear_trans[7].Rotate(180.0);
+
+ for (int i = 0; i < kNumRectilinear; ++i) {
+ bool clipped = false;
+ gfx::QuadF quad = MathUtil::MapQuad(
+ rectilinear_trans[i],
+ gfx::QuadF(
+ gfx::RectF(0.01010101f, 0.01010101f, 100.01010101f, 100.01010101f)),
+ &clipped);
+ ASSERT_TRUE(!clipped);
+ EXPECT_TRUE(quad.IsRectilinear());
+ }
+
+ const int kNumNonRectilinear = 10;
+ gfx::Transform non_rectilinear_trans[kNumNonRectilinear];
+ non_rectilinear_trans[0].Rotate(359.999);
+ non_rectilinear_trans[1].Rotate(0.0000001);
+ non_rectilinear_trans[2].Rotate(89.999999);
+ non_rectilinear_trans[3].Rotate(90.0000001);
+ non_rectilinear_trans[4].Rotate(179.999999);
+ non_rectilinear_trans[5].Rotate(180.0000001);
+ non_rectilinear_trans[6].Rotate(269.999999);
+ non_rectilinear_trans[7].Rotate(270.0000001);
+ non_rectilinear_trans[8].SkewX(0.00001);
+ non_rectilinear_trans[9].SkewY(0.00001);
+
+ for (int i = 0; i < kNumNonRectilinear; ++i) {
+ bool clipped = false;
+ gfx::QuadF quad = MathUtil::MapQuad(
+ non_rectilinear_trans[i],
+ gfx::QuadF(
+ gfx::RectF(0.01010101f, 0.01010101f, 100.01010101f, 100.01010101f)),
+ &clipped);
+ ASSERT_TRUE(!clipped);
+ EXPECT_FALSE(quad.IsRectilinear());
+ }
+}
+
+} // namespace
+} // namespace cc
diff --git a/chromium/cc/base/invalidation_region.cc b/chromium/cc/base/invalidation_region.cc
new file mode 100644
index 00000000000..2c39d25ba06
--- /dev/null
+++ b/chromium/cc/base/invalidation_region.cc
@@ -0,0 +1,48 @@
+// Copyright 2013 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 "cc/base/invalidation_region.h"
+
+#include "base/metrics/histogram.h"
+
+namespace {
+
+const int kMaxInvalidationRectCount = 256;
+
+} // namespace
+
+namespace cc {
+
+InvalidationRegion::InvalidationRegion() {}
+
+InvalidationRegion::~InvalidationRegion() {}
+
+void InvalidationRegion::Swap(Region* region) {
+ UMA_HISTOGRAM_CUSTOM_COUNTS(
+ "Renderer4.InvalidationRegionApproximateRectCount",
+ region_.GetRegionComplexity(),
+ 1,
+ 5000,
+ 50);
+
+ SimplifyIfNeeded();
+ region_.Swap(region);
+}
+
+void InvalidationRegion::Clear() {
+ region_.Clear();
+}
+
+void InvalidationRegion::Union(gfx::Rect rect) {
+ // TODO(vmpstr): We should simplify the region after Union() after we get a
+ // good idea of what kind of regions are typical (from the UMA histogram).
+ region_.Union(rect);
+}
+
+void InvalidationRegion::SimplifyIfNeeded() {
+ if (region_.GetRegionComplexity() > kMaxInvalidationRectCount)
+ region_ = region_.bounds();
+}
+
+} // namespace cc
diff --git a/chromium/cc/base/invalidation_region.h b/chromium/cc/base/invalidation_region.h
new file mode 100644
index 00000000000..fd061e8cba3
--- /dev/null
+++ b/chromium/cc/base/invalidation_region.h
@@ -0,0 +1,34 @@
+// Copyright 2013 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.
+
+#ifndef CC_BASE_INVALIDATION_REGION_H_
+#define CC_BASE_INVALIDATION_REGION_H_
+
+#include "cc/base/cc_export.h"
+#include "cc/base/region.h"
+#include "ui/gfx/rect.h"
+
+namespace cc {
+
+// This class behaves similarly to Region, but it may have false positives. That
+// is, InvalidationRegion can be simplified to encompass a larger area than the
+// collection of rects unioned.
+class CC_EXPORT InvalidationRegion {
+ public:
+ InvalidationRegion();
+ ~InvalidationRegion();
+
+ void Swap(Region* region);
+ void Clear();
+ void Union(gfx::Rect rect);
+
+ private:
+ void SimplifyIfNeeded();
+
+ Region region_;
+};
+
+} // namespace cc
+
+#endif // CC_BASE_INVALIDATION_REGION_H_
diff --git a/chromium/cc/base/math_util.cc b/chromium/cc/base/math_util.cc
new file mode 100644
index 00000000000..fa7b21a8c29
--- /dev/null
+++ b/chromium/cc/base/math_util.cc
@@ -0,0 +1,576 @@
+// Copyright 2012 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 "cc/base/math_util.h"
+
+#include <algorithm>
+#include <cmath>
+#include <limits>
+
+#include "base/values.h"
+#include "ui/gfx/quad_f.h"
+#include "ui/gfx/rect.h"
+#include "ui/gfx/rect_conversions.h"
+#include "ui/gfx/rect_f.h"
+#include "ui/gfx/transform.h"
+#include "ui/gfx/vector2d_f.h"
+
+namespace cc {
+
+const double MathUtil::kPiDouble = 3.14159265358979323846;
+const float MathUtil::kPiFloat = 3.14159265358979323846f;
+
+static HomogeneousCoordinate ProjectHomogeneousPoint(
+ const gfx::Transform& transform,
+ gfx::PointF p) {
+ // In this case, the layer we are trying to project onto is perpendicular to
+ // ray (point p and z-axis direction) that we are trying to project. This
+ // happens when the layer is rotated so that it is infinitesimally thin, or
+ // when it is co-planar with the camera origin -- i.e. when the layer is
+ // invisible anyway.
+ if (!transform.matrix().get(2, 2))
+ return HomogeneousCoordinate(0.0, 0.0, 0.0, 1.0);
+
+ SkMScalar z = -(transform.matrix().get(2, 0) * p.x() +
+ transform.matrix().get(2, 1) * p.y() +
+ transform.matrix().get(2, 3)) /
+ transform.matrix().get(2, 2);
+ HomogeneousCoordinate result(p.x(), p.y(), z, 1.0);
+ transform.matrix().mapMScalars(result.vec, result.vec);
+ return result;
+}
+
+static HomogeneousCoordinate MapHomogeneousPoint(
+ const gfx::Transform& transform,
+ const gfx::Point3F& p) {
+ HomogeneousCoordinate result(p.x(), p.y(), p.z(), 1.0);
+ transform.matrix().mapMScalars(result.vec, result.vec);
+ return result;
+}
+
+static HomogeneousCoordinate ComputeClippedPointForEdge(
+ const HomogeneousCoordinate& h1,
+ const HomogeneousCoordinate& h2) {
+ // Points h1 and h2 form a line in 4d, and any point on that line can be
+ // represented as an interpolation between h1 and h2:
+ // p = (1-t) h1 + (t) h2
+ //
+ // We want to compute point p such that p.w == epsilon, where epsilon is a
+ // small non-zero number. (but the smaller the number is, the higher the risk
+ // of overflow)
+ // To do this, we solve for t in the following equation:
+ // p.w = epsilon = (1-t) * h1.w + (t) * h2.w
+ //
+ // Once paramter t is known, the rest of p can be computed via
+ // p = (1-t) h1 + (t) h2.
+
+ // Technically this is a special case of the following assertion, but its a
+ // good idea to keep it an explicit sanity check here.
+ DCHECK_NE(h2.w(), h1.w());
+ // Exactly one of h1 or h2 (but not both) must be on the negative side of the
+ // w plane when this is called.
+ DCHECK(h1.ShouldBeClipped() ^ h2.ShouldBeClipped());
+
+ SkMScalar w = 0.00001; // or any positive non-zero small epsilon
+
+ SkMScalar t = (w - h1.w()) / (h2.w() - h1.w());
+
+ SkMScalar x = (1 - t) * h1.x() + t * h2.x();
+ SkMScalar y = (1 - t) * h1.y() + t * h2.y();
+ SkMScalar z = (1 - t) * h1.z() + t * h2.z();
+
+ return HomogeneousCoordinate(x, y, z, w);
+}
+
+static inline void ExpandBoundsToIncludePoint(float* xmin,
+ float* xmax,
+ float* ymin,
+ float* ymax,
+ gfx::PointF p) {
+ *xmin = std::min(p.x(), *xmin);
+ *xmax = std::max(p.x(), *xmax);
+ *ymin = std::min(p.y(), *ymin);
+ *ymax = std::max(p.y(), *ymax);
+}
+
+static inline void AddVertexToClippedQuad(gfx::PointF new_vertex,
+ gfx::PointF clipped_quad[8],
+ int* num_vertices_in_clipped_quad) {
+ clipped_quad[*num_vertices_in_clipped_quad] = new_vertex;
+ (*num_vertices_in_clipped_quad)++;
+}
+
+gfx::Rect MathUtil::MapClippedRect(const gfx::Transform& transform,
+ gfx::Rect src_rect) {
+ return gfx::ToEnclosingRect(MapClippedRect(transform, gfx::RectF(src_rect)));
+}
+
+gfx::RectF MathUtil::MapClippedRect(const gfx::Transform& transform,
+ const gfx::RectF& src_rect) {
+ if (transform.IsIdentityOrTranslation())
+ return src_rect +
+ gfx::Vector2dF(
+ static_cast<float>(transform.matrix().getDouble(0, 3)),
+ static_cast<float>(transform.matrix().getDouble(1, 3)));
+
+ // Apply the transform, but retain the result in homogeneous coordinates.
+
+ double quad[4 * 2]; // input: 4 x 2D points
+ quad[0] = src_rect.x();
+ quad[1] = src_rect.y();
+ quad[2] = src_rect.right();
+ quad[3] = src_rect.y();
+ quad[4] = src_rect.right();
+ quad[5] = src_rect.bottom();
+ quad[6] = src_rect.x();
+ quad[7] = src_rect.bottom();
+
+ double result[4 * 4]; // output: 4 x 4D homogeneous points
+ transform.matrix().map2(quad, 4, result);
+
+ HomogeneousCoordinate hc0(result[0], result[1], result[2], result[3]);
+ HomogeneousCoordinate hc1(result[4], result[5], result[6], result[7]);
+ HomogeneousCoordinate hc2(result[8], result[9], result[10], result[11]);
+ HomogeneousCoordinate hc3(result[12], result[13], result[14], result[15]);
+ return ComputeEnclosingClippedRect(hc0, hc1, hc2, hc3);
+}
+
+gfx::RectF MathUtil::ProjectClippedRect(const gfx::Transform& transform,
+ const gfx::RectF& src_rect) {
+ if (transform.IsIdentityOrTranslation()) {
+ return src_rect +
+ gfx::Vector2dF(
+ static_cast<float>(transform.matrix().getDouble(0, 3)),
+ static_cast<float>(transform.matrix().getDouble(1, 3)));
+ }
+
+ // Perform the projection, but retain the result in homogeneous coordinates.
+ gfx::QuadF q = gfx::QuadF(src_rect);
+ HomogeneousCoordinate h1 = ProjectHomogeneousPoint(transform, q.p1());
+ HomogeneousCoordinate h2 = ProjectHomogeneousPoint(transform, q.p2());
+ HomogeneousCoordinate h3 = ProjectHomogeneousPoint(transform, q.p3());
+ HomogeneousCoordinate h4 = ProjectHomogeneousPoint(transform, q.p4());
+
+ return ComputeEnclosingClippedRect(h1, h2, h3, h4);
+}
+
+void MathUtil::MapClippedQuad(const gfx::Transform& transform,
+ const gfx::QuadF& src_quad,
+ gfx::PointF clipped_quad[8],
+ int* num_vertices_in_clipped_quad) {
+ HomogeneousCoordinate h1 =
+ MapHomogeneousPoint(transform, gfx::Point3F(src_quad.p1()));
+ HomogeneousCoordinate h2 =
+ MapHomogeneousPoint(transform, gfx::Point3F(src_quad.p2()));
+ HomogeneousCoordinate h3 =
+ MapHomogeneousPoint(transform, gfx::Point3F(src_quad.p3()));
+ HomogeneousCoordinate h4 =
+ MapHomogeneousPoint(transform, gfx::Point3F(src_quad.p4()));
+
+ // The order of adding the vertices to the array is chosen so that
+ // clockwise / counter-clockwise orientation is retained.
+
+ *num_vertices_in_clipped_quad = 0;
+
+ if (!h1.ShouldBeClipped()) {
+ AddVertexToClippedQuad(
+ h1.CartesianPoint2d(), clipped_quad, num_vertices_in_clipped_quad);
+ }
+
+ if (h1.ShouldBeClipped() ^ h2.ShouldBeClipped()) {
+ AddVertexToClippedQuad(
+ ComputeClippedPointForEdge(h1, h2).CartesianPoint2d(),
+ clipped_quad,
+ num_vertices_in_clipped_quad);
+ }
+
+ if (!h2.ShouldBeClipped()) {
+ AddVertexToClippedQuad(
+ h2.CartesianPoint2d(), clipped_quad, num_vertices_in_clipped_quad);
+ }
+
+ if (h2.ShouldBeClipped() ^ h3.ShouldBeClipped()) {
+ AddVertexToClippedQuad(
+ ComputeClippedPointForEdge(h2, h3).CartesianPoint2d(),
+ clipped_quad,
+ num_vertices_in_clipped_quad);
+ }
+
+ if (!h3.ShouldBeClipped()) {
+ AddVertexToClippedQuad(
+ h3.CartesianPoint2d(), clipped_quad, num_vertices_in_clipped_quad);
+ }
+
+ if (h3.ShouldBeClipped() ^ h4.ShouldBeClipped()) {
+ AddVertexToClippedQuad(
+ ComputeClippedPointForEdge(h3, h4).CartesianPoint2d(),
+ clipped_quad,
+ num_vertices_in_clipped_quad);
+ }
+
+ if (!h4.ShouldBeClipped()) {
+ AddVertexToClippedQuad(
+ h4.CartesianPoint2d(), clipped_quad, num_vertices_in_clipped_quad);
+ }
+
+ if (h4.ShouldBeClipped() ^ h1.ShouldBeClipped()) {
+ AddVertexToClippedQuad(
+ ComputeClippedPointForEdge(h4, h1).CartesianPoint2d(),
+ clipped_quad,
+ num_vertices_in_clipped_quad);
+ }
+
+ DCHECK_LE(*num_vertices_in_clipped_quad, 8);
+}
+
+gfx::RectF MathUtil::ComputeEnclosingRectOfVertices(gfx::PointF vertices[],
+ int num_vertices) {
+ if (num_vertices < 2)
+ return gfx::RectF();
+
+ float xmin = std::numeric_limits<float>::max();
+ float xmax = -std::numeric_limits<float>::max();
+ float ymin = std::numeric_limits<float>::max();
+ float ymax = -std::numeric_limits<float>::max();
+
+ for (int i = 0; i < num_vertices; ++i)
+ ExpandBoundsToIncludePoint(&xmin, &xmax, &ymin, &ymax, vertices[i]);
+
+ return gfx::RectF(gfx::PointF(xmin, ymin),
+ gfx::SizeF(xmax - xmin, ymax - ymin));
+}
+
+gfx::RectF MathUtil::ComputeEnclosingClippedRect(
+ const HomogeneousCoordinate& h1,
+ const HomogeneousCoordinate& h2,
+ const HomogeneousCoordinate& h3,
+ const HomogeneousCoordinate& h4) {
+ // This function performs clipping as necessary and computes the enclosing 2d
+ // gfx::RectF of the vertices. Doing these two steps simultaneously allows us
+ // to avoid the overhead of storing an unknown number of clipped vertices.
+
+ // If no vertices on the quad are clipped, then we can simply return the
+ // enclosing rect directly.
+ bool something_clipped = h1.ShouldBeClipped() || h2.ShouldBeClipped() ||
+ h3.ShouldBeClipped() || h4.ShouldBeClipped();
+ if (!something_clipped) {
+ gfx::QuadF mapped_quad = gfx::QuadF(h1.CartesianPoint2d(),
+ h2.CartesianPoint2d(),
+ h3.CartesianPoint2d(),
+ h4.CartesianPoint2d());
+ return mapped_quad.BoundingBox();
+ }
+
+ bool everything_clipped = h1.ShouldBeClipped() && h2.ShouldBeClipped() &&
+ h3.ShouldBeClipped() && h4.ShouldBeClipped();
+ if (everything_clipped)
+ return gfx::RectF();
+
+ float xmin = std::numeric_limits<float>::max();
+ float xmax = -std::numeric_limits<float>::max();
+ float ymin = std::numeric_limits<float>::max();
+ float ymax = -std::numeric_limits<float>::max();
+
+ if (!h1.ShouldBeClipped())
+ ExpandBoundsToIncludePoint(&xmin, &xmax, &ymin, &ymax,
+ h1.CartesianPoint2d());
+
+ if (h1.ShouldBeClipped() ^ h2.ShouldBeClipped())
+ ExpandBoundsToIncludePoint(&xmin,
+ &xmax,
+ &ymin,
+ &ymax,
+ ComputeClippedPointForEdge(h1, h2)
+ .CartesianPoint2d());
+
+ if (!h2.ShouldBeClipped())
+ ExpandBoundsToIncludePoint(&xmin, &xmax, &ymin, &ymax,
+ h2.CartesianPoint2d());
+
+ if (h2.ShouldBeClipped() ^ h3.ShouldBeClipped())
+ ExpandBoundsToIncludePoint(&xmin,
+ &xmax,
+ &ymin,
+ &ymax,
+ ComputeClippedPointForEdge(h2, h3)
+ .CartesianPoint2d());
+
+ if (!h3.ShouldBeClipped())
+ ExpandBoundsToIncludePoint(&xmin, &xmax, &ymin, &ymax,
+ h3.CartesianPoint2d());
+
+ if (h3.ShouldBeClipped() ^ h4.ShouldBeClipped())
+ ExpandBoundsToIncludePoint(&xmin,
+ &xmax,
+ &ymin,
+ &ymax,
+ ComputeClippedPointForEdge(h3, h4)
+ .CartesianPoint2d());
+
+ if (!h4.ShouldBeClipped())
+ ExpandBoundsToIncludePoint(&xmin, &xmax, &ymin, &ymax,
+ h4.CartesianPoint2d());
+
+ if (h4.ShouldBeClipped() ^ h1.ShouldBeClipped())
+ ExpandBoundsToIncludePoint(&xmin,
+ &xmax,
+ &ymin,
+ &ymax,
+ ComputeClippedPointForEdge(h4, h1)
+ .CartesianPoint2d());
+
+ return gfx::RectF(gfx::PointF(xmin, ymin),
+ gfx::SizeF(xmax - xmin, ymax - ymin));
+}
+
+gfx::QuadF MathUtil::MapQuad(const gfx::Transform& transform,
+ const gfx::QuadF& q,
+ bool* clipped) {
+ if (transform.IsIdentityOrTranslation()) {
+ gfx::QuadF mapped_quad(q);
+ mapped_quad +=
+ gfx::Vector2dF(static_cast<float>(transform.matrix().getDouble(0, 3)),
+ static_cast<float>(transform.matrix().getDouble(1, 3)));
+ *clipped = false;
+ return mapped_quad;
+ }
+
+ HomogeneousCoordinate h1 =
+ MapHomogeneousPoint(transform, gfx::Point3F(q.p1()));
+ HomogeneousCoordinate h2 =
+ MapHomogeneousPoint(transform, gfx::Point3F(q.p2()));
+ HomogeneousCoordinate h3 =
+ MapHomogeneousPoint(transform, gfx::Point3F(q.p3()));
+ HomogeneousCoordinate h4 =
+ MapHomogeneousPoint(transform, gfx::Point3F(q.p4()));
+
+ *clipped = h1.ShouldBeClipped() || h2.ShouldBeClipped() ||
+ h3.ShouldBeClipped() || h4.ShouldBeClipped();
+
+ // Result will be invalid if clipped == true. But, compute it anyway just in
+ // case, to emulate existing behavior.
+ return gfx::QuadF(h1.CartesianPoint2d(),
+ h2.CartesianPoint2d(),
+ h3.CartesianPoint2d(),
+ h4.CartesianPoint2d());
+}
+
+gfx::PointF MathUtil::MapPoint(const gfx::Transform& transform,
+ gfx::PointF p,
+ bool* clipped) {
+ HomogeneousCoordinate h = MapHomogeneousPoint(transform, gfx::Point3F(p));
+
+ if (h.w() > 0) {
+ *clipped = false;
+ return h.CartesianPoint2d();
+ }
+
+ // The cartesian coordinates will be invalid after dividing by w.
+ *clipped = true;
+
+ // Avoid dividing by w if w == 0.
+ if (!h.w())
+ return gfx::PointF();
+
+ // This return value will be invalid because clipped == true, but (1) users of
+ // this code should be ignoring the return value when clipped == true anyway,
+ // and (2) this behavior is more consistent with existing behavior of WebKit
+ // transforms if the user really does not ignore the return value.
+ return h.CartesianPoint2d();
+}
+
+gfx::Point3F MathUtil::MapPoint(const gfx::Transform& transform,
+ const gfx::Point3F& p,
+ bool* clipped) {
+ HomogeneousCoordinate h = MapHomogeneousPoint(transform, p);
+
+ if (h.w() > 0) {
+ *clipped = false;
+ return h.CartesianPoint3d();
+ }
+
+ // The cartesian coordinates will be invalid after dividing by w.
+ *clipped = true;
+
+ // Avoid dividing by w if w == 0.
+ if (!h.w())
+ return gfx::Point3F();
+
+ // This return value will be invalid because clipped == true, but (1) users of
+ // this code should be ignoring the return value when clipped == true anyway,
+ // and (2) this behavior is more consistent with existing behavior of WebKit
+ // transforms if the user really does not ignore the return value.
+ return h.CartesianPoint3d();
+}
+
+gfx::QuadF MathUtil::ProjectQuad(const gfx::Transform& transform,
+ const gfx::QuadF& q,
+ bool* clipped) {
+ gfx::QuadF projected_quad;
+ bool clipped_point;
+ projected_quad.set_p1(ProjectPoint(transform, q.p1(), &clipped_point));
+ *clipped = clipped_point;
+ projected_quad.set_p2(ProjectPoint(transform, q.p2(), &clipped_point));
+ *clipped |= clipped_point;
+ projected_quad.set_p3(ProjectPoint(transform, q.p3(), &clipped_point));
+ *clipped |= clipped_point;
+ projected_quad.set_p4(ProjectPoint(transform, q.p4(), &clipped_point));
+ *clipped |= clipped_point;
+
+ return projected_quad;
+}
+
+gfx::PointF MathUtil::ProjectPoint(const gfx::Transform& transform,
+ gfx::PointF p,
+ bool* clipped) {
+ HomogeneousCoordinate h = ProjectHomogeneousPoint(transform, p);
+
+ if (h.w() > 0) {
+ // The cartesian coordinates will be valid in this case.
+ *clipped = false;
+ return h.CartesianPoint2d();
+ }
+
+ // The cartesian coordinates will be invalid after dividing by w.
+ *clipped = true;
+
+ // Avoid dividing by w if w == 0.
+ if (!h.w())
+ return gfx::PointF();
+
+ // This return value will be invalid because clipped == true, but (1) users of
+ // this code should be ignoring the return value when clipped == true anyway,
+ // and (2) this behavior is more consistent with existing behavior of WebKit
+ // transforms if the user really does not ignore the return value.
+ return h.CartesianPoint2d();
+}
+
+static inline float ScaleOnAxis(double a, double b, double c) {
+ return std::sqrt(a * a + b * b + c * c);
+}
+
+gfx::Vector2dF MathUtil::ComputeTransform2dScaleComponents(
+ const gfx::Transform& transform,
+ float fallback_value) {
+ if (transform.HasPerspective())
+ return gfx::Vector2dF(fallback_value, fallback_value);
+ float x_scale = ScaleOnAxis(transform.matrix().getDouble(0, 0),
+ transform.matrix().getDouble(1, 0),
+ transform.matrix().getDouble(2, 0));
+ float y_scale = ScaleOnAxis(transform.matrix().getDouble(0, 1),
+ transform.matrix().getDouble(1, 1),
+ transform.matrix().getDouble(2, 1));
+ return gfx::Vector2dF(x_scale, y_scale);
+}
+
+float MathUtil::SmallestAngleBetweenVectors(gfx::Vector2dF v1,
+ gfx::Vector2dF v2) {
+ double dot_product = gfx::DotProduct(v1, v2) / v1.Length() / v2.Length();
+ // Clamp to compensate for rounding errors.
+ dot_product = std::max(-1.0, std::min(1.0, dot_product));
+ return static_cast<float>(Rad2Deg(std::acos(dot_product)));
+}
+
+gfx::Vector2dF MathUtil::ProjectVector(gfx::Vector2dF source,
+ gfx::Vector2dF destination) {
+ float projected_length =
+ gfx::DotProduct(source, destination) / destination.LengthSquared();
+ return gfx::Vector2dF(projected_length * destination.x(),
+ projected_length * destination.y());
+}
+
+scoped_ptr<base::Value> MathUtil::AsValue(gfx::Size s) {
+ scoped_ptr<base::DictionaryValue> res(new base::DictionaryValue());
+ res->SetDouble("width", s.width());
+ res->SetDouble("height", s.height());
+ return res.PassAs<base::Value>();
+}
+
+scoped_ptr<base::Value> MathUtil::AsValue(gfx::SizeF s) {
+ scoped_ptr<base::DictionaryValue> res(new base::DictionaryValue());
+ res->SetDouble("width", s.width());
+ res->SetDouble("height", s.height());
+ return res.PassAs<base::Value>();
+}
+
+scoped_ptr<base::Value> MathUtil::AsValue(gfx::Rect r) {
+ scoped_ptr<base::ListValue> res(new base::ListValue());
+ res->AppendInteger(r.x());
+ res->AppendInteger(r.y());
+ res->AppendInteger(r.width());
+ res->AppendInteger(r.height());
+ return res.PassAs<base::Value>();
+}
+
+bool MathUtil::FromValue(const base::Value* raw_value, gfx::Rect* out_rect) {
+ const base::ListValue* value = NULL;
+ if (!raw_value->GetAsList(&value))
+ return false;
+
+ if (value->GetSize() != 4)
+ return false;
+
+ int x, y, w, h;
+ bool ok = true;
+ ok &= value->GetInteger(0, &x);
+ ok &= value->GetInteger(1, &y);
+ ok &= value->GetInteger(2, &w);
+ ok &= value->GetInteger(3, &h);
+ if (!ok)
+ return false;
+
+ *out_rect = gfx::Rect(x, y, w, h);
+ return true;
+}
+
+scoped_ptr<base::Value> MathUtil::AsValue(gfx::PointF pt) {
+ scoped_ptr<base::ListValue> res(new base::ListValue());
+ res->AppendDouble(pt.x());
+ res->AppendDouble(pt.y());
+ return res.PassAs<base::Value>();
+}
+
+scoped_ptr<base::Value> MathUtil::AsValue(const gfx::QuadF& q) {
+ scoped_ptr<base::ListValue> res(new base::ListValue());
+ res->AppendDouble(q.p1().x());
+ res->AppendDouble(q.p1().y());
+ res->AppendDouble(q.p2().x());
+ res->AppendDouble(q.p2().y());
+ res->AppendDouble(q.p3().x());
+ res->AppendDouble(q.p3().y());
+ res->AppendDouble(q.p4().x());
+ res->AppendDouble(q.p4().y());
+ return res.PassAs<base::Value>();
+}
+
+scoped_ptr<base::Value> MathUtil::AsValue(const gfx::RectF& rect) {
+ scoped_ptr<base::ListValue> res(new base::ListValue());
+ res->AppendDouble(rect.x());
+ res->AppendDouble(rect.y());
+ res->AppendDouble(rect.width());
+ res->AppendDouble(rect.height());
+ return res.PassAs<base::Value>();
+}
+
+scoped_ptr<base::Value> MathUtil::AsValue(const gfx::Transform& transform) {
+ scoped_ptr<base::ListValue> res(new base::ListValue());
+ const SkMatrix44& m = transform.matrix();
+ for (int row = 0; row < 4; ++row) {
+ for (int col = 0; col < 4; ++col)
+ res->AppendDouble(m.getDouble(row, col));
+ }
+ return res.PassAs<base::Value>();
+}
+
+scoped_ptr<base::Value> MathUtil::AsValueSafely(double value) {
+ return scoped_ptr<base::Value>(base::Value::CreateDoubleValue(
+ std::min(value, std::numeric_limits<double>::max())));
+}
+
+scoped_ptr<base::Value> MathUtil::AsValueSafely(float value) {
+ return scoped_ptr<base::Value>(base::Value::CreateDoubleValue(
+ std::min(value, std::numeric_limits<float>::max())));
+}
+
+} // namespace cc
diff --git a/chromium/cc/base/math_util.h b/chromium/cc/base/math_util.h
new file mode 100644
index 00000000000..37f0c07602f
--- /dev/null
+++ b/chromium/cc/base/math_util.h
@@ -0,0 +1,175 @@
+// Copyright 2012 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.
+
+#ifndef CC_BASE_MATH_UTIL_H_
+#define CC_BASE_MATH_UTIL_H_
+
+#include <algorithm>
+#include <cmath>
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "cc/base/cc_export.h"
+#include "ui/gfx/point3_f.h"
+#include "ui/gfx/point_f.h"
+#include "ui/gfx/size.h"
+#include "ui/gfx/transform.h"
+
+namespace base { class Value; }
+
+namespace gfx {
+class QuadF;
+class Rect;
+class RectF;
+class Transform;
+class Vector2dF;
+}
+
+namespace cc {
+
+struct HomogeneousCoordinate {
+ HomogeneousCoordinate(SkMScalar x, SkMScalar y, SkMScalar z, SkMScalar w) {
+ vec[0] = x;
+ vec[1] = y;
+ vec[2] = z;
+ vec[3] = w;
+ }
+
+ bool ShouldBeClipped() const { return w() <= 0.0; }
+
+ gfx::PointF CartesianPoint2d() const {
+ if (w() == 1.0)
+ return gfx::PointF(x(), y());
+
+ // For now, because this code is used privately only by MathUtil, it should
+ // never be called when w == 0, and we do not yet need to handle that case.
+ DCHECK(w());
+ double inv_w = 1.0 / w();
+ return gfx::PointF(x() * inv_w, y() * inv_w);
+ }
+
+ gfx::Point3F CartesianPoint3d() const {
+ if (w() == 1)
+ return gfx::Point3F(x(), y(), z());
+
+ // For now, because this code is used privately only by MathUtil, it should
+ // never be called when w == 0, and we do not yet need to handle that case.
+ DCHECK(w());
+ double inv_w = 1.0 / w();
+ return gfx::Point3F(x() * inv_w, y() * inv_w, z() * inv_w);
+ }
+
+ SkMScalar x() const { return vec[0]; }
+ SkMScalar y() const { return vec[1]; }
+ SkMScalar z() const { return vec[2]; }
+ SkMScalar w() const { return vec[3]; }
+
+ SkMScalar vec[4];
+};
+
+class CC_EXPORT MathUtil {
+ public:
+ static const double kPiDouble;
+ static const float kPiFloat;
+
+ static double Deg2Rad(double deg) { return deg * kPiDouble / 180.0; }
+ static double Rad2Deg(double rad) { return rad * 180.0 / kPiDouble; }
+
+ static float Deg2Rad(float deg) { return deg * kPiFloat / 180.0f; }
+ static float Rad2Deg(float rad) { return rad * 180.0f / kPiFloat; }
+
+ static float Round(float f) {
+ return (f > 0.f) ? std::floor(f + 0.5f) : std::ceil(f - 0.5f);
+ }
+ static double Round(double d) {
+ return (d > 0.0) ? std::floor(d + 0.5) : std::ceil(d - 0.5);
+ }
+
+ template <typename T> static T ClampToRange(T value, T min, T max) {
+ return std::min(std::max(value, min), max);
+ }
+
+ // Background: Existing transform code does not do the right thing in
+ // MapRect / MapQuad / ProjectQuad when there is a perspective projection that
+ // causes one of the transformed vertices to go to w < 0. In those cases, it
+ // is necessary to perform clipping in homogeneous coordinates, after applying
+ // the transform, before dividing-by-w to convert to cartesian coordinates.
+ //
+ // These functions return the axis-aligned rect that encloses the correctly
+ // clipped, transformed polygon.
+ static gfx::Rect MapClippedRect(const gfx::Transform& transform,
+ gfx::Rect rect);
+ static gfx::RectF MapClippedRect(const gfx::Transform& transform,
+ const gfx::RectF& rect);
+ static gfx::RectF ProjectClippedRect(const gfx::Transform& transform,
+ const gfx::RectF& rect);
+
+ // Returns an array of vertices that represent the clipped polygon. After
+ // returning, indexes from 0 to num_vertices_in_clipped_quad are valid in the
+ // clipped_quad array. Note that num_vertices_in_clipped_quad may be zero,
+ // which means the entire quad was clipped, and none of the vertices in the
+ // array are valid.
+ static void MapClippedQuad(const gfx::Transform& transform,
+ const gfx::QuadF& src_quad,
+ gfx::PointF clipped_quad[8],
+ int* num_vertices_in_clipped_quad);
+
+ static gfx::RectF ComputeEnclosingRectOfVertices(gfx::PointF vertices[],
+ int num_vertices);
+ static gfx::RectF ComputeEnclosingClippedRect(
+ const HomogeneousCoordinate& h1,
+ const HomogeneousCoordinate& h2,
+ const HomogeneousCoordinate& h3,
+ const HomogeneousCoordinate& h4);
+
+ // NOTE: These functions do not do correct clipping against w = 0 plane, but
+ // they correctly detect the clipped condition via the boolean clipped.
+ static gfx::QuadF MapQuad(const gfx::Transform& transform,
+ const gfx::QuadF& quad,
+ bool* clipped);
+ static gfx::PointF MapPoint(const gfx::Transform& transform,
+ gfx::PointF point,
+ bool* clipped);
+ static gfx::Point3F MapPoint(const gfx::Transform&,
+ const gfx::Point3F&,
+ bool* clipped);
+ static gfx::QuadF ProjectQuad(const gfx::Transform& transform,
+ const gfx::QuadF& quad,
+ bool* clipped);
+ static gfx::PointF ProjectPoint(const gfx::Transform& transform,
+ gfx::PointF point,
+ bool* clipped);
+
+ static gfx::Vector2dF ComputeTransform2dScaleComponents(const gfx::Transform&,
+ float fallbackValue);
+
+ // Returns the smallest angle between the given two vectors in degrees.
+ // Neither vector is assumed to be normalized.
+ static float SmallestAngleBetweenVectors(gfx::Vector2dF v1,
+ gfx::Vector2dF v2);
+
+ // Projects the |source| vector onto |destination|. Neither vector is assumed
+ // to be normalized.
+ static gfx::Vector2dF ProjectVector(gfx::Vector2dF source,
+ gfx::Vector2dF destination);
+
+ // Conversion to value.
+ static scoped_ptr<base::Value> AsValue(gfx::Size s);
+ static scoped_ptr<base::Value> AsValue(gfx::SizeF s);
+ static scoped_ptr<base::Value> AsValue(gfx::Rect r);
+ static bool FromValue(const base::Value*, gfx::Rect* out_rect);
+ static scoped_ptr<base::Value> AsValue(gfx::PointF q);
+ static scoped_ptr<base::Value> AsValue(const gfx::QuadF& q);
+ static scoped_ptr<base::Value> AsValue(const gfx::RectF& rect);
+ static scoped_ptr<base::Value> AsValue(const gfx::Transform& transform);
+
+ // Returns a base::Value representation of the floating point value.
+ // If the value is inf, returns max double/float representation.
+ static scoped_ptr<base::Value> AsValueSafely(double value);
+ static scoped_ptr<base::Value> AsValueSafely(float value);
+};
+
+} // namespace cc
+
+#endif // CC_BASE_MATH_UTIL_H_
diff --git a/chromium/cc/base/math_util_unittest.cc b/chromium/cc/base/math_util_unittest.cc
new file mode 100644
index 00000000000..d62280ddb5f
--- /dev/null
+++ b/chromium/cc/base/math_util_unittest.cc
@@ -0,0 +1,122 @@
+// Copyright 2012 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 "cc/base/math_util.h"
+
+#include <cmath>
+
+#include "cc/test/geometry_test_utils.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/rect.h"
+#include "ui/gfx/rect_f.h"
+#include "ui/gfx/transform.h"
+
+namespace cc {
+namespace {
+
+TEST(MathUtilTest, ProjectionOfPerpendicularPlane) {
+ // In this case, the m33() element of the transform becomes zero, which could
+ // cause a divide-by-zero when projecting points/quads.
+
+ gfx::Transform transform;
+ transform.MakeIdentity();
+ transform.matrix().setDouble(2, 2, 0);
+
+ gfx::RectF rect = gfx::RectF(0, 0, 1, 1);
+ gfx::RectF projected_rect = MathUtil::ProjectClippedRect(transform, rect);
+
+ EXPECT_EQ(0, projected_rect.x());
+ EXPECT_EQ(0, projected_rect.y());
+ EXPECT_TRUE(projected_rect.IsEmpty());
+}
+
+TEST(MathUtilTest, EnclosingClippedRectUsesCorrectInitialBounds) {
+ HomogeneousCoordinate h1(-100, -100, 0, 1);
+ HomogeneousCoordinate h2(-10, -10, 0, 1);
+ HomogeneousCoordinate h3(10, 10, 0, -1);
+ HomogeneousCoordinate h4(100, 100, 0, -1);
+
+ // The bounds of the enclosing clipped rect should be -100 to -10 for both x
+ // and y. However, if there is a bug where the initial xmin/xmax/ymin/ymax are
+ // initialized to numeric_limits<float>::min() (which is zero, not -flt_max)
+ // then the enclosing clipped rect will be computed incorrectly.
+ gfx::RectF result = MathUtil::ComputeEnclosingClippedRect(h1, h2, h3, h4);
+
+ EXPECT_FLOAT_RECT_EQ(gfx::RectF(gfx::PointF(-100, -100), gfx::SizeF(90, 90)),
+ result);
+}
+
+TEST(MathUtilTest, EnclosingRectOfVerticesUsesCorrectInitialBounds) {
+ gfx::PointF vertices[3];
+ int num_vertices = 3;
+
+ vertices[0] = gfx::PointF(-10, -100);
+ vertices[1] = gfx::PointF(-100, -10);
+ vertices[2] = gfx::PointF(-30, -30);
+
+ // The bounds of the enclosing rect should be -100 to -10 for both x and y.
+ // However, if there is a bug where the initial xmin/xmax/ymin/ymax are
+ // initialized to numeric_limits<float>::min() (which is zero, not -flt_max)
+ // then the enclosing clipped rect will be computed incorrectly.
+ gfx::RectF result =
+ MathUtil::ComputeEnclosingRectOfVertices(vertices, num_vertices);
+
+ EXPECT_FLOAT_RECT_EQ(gfx::RectF(gfx::PointF(-100, -100), gfx::SizeF(90, 90)),
+ result);
+}
+
+TEST(MathUtilTest, SmallestAngleBetweenVectors) {
+ gfx::Vector2dF x(1, 0);
+ gfx::Vector2dF y(0, 1);
+ gfx::Vector2dF test_vector(0.5, 0.5);
+
+ // Orthogonal vectors are at an angle of 90 degress.
+ EXPECT_EQ(90, MathUtil::SmallestAngleBetweenVectors(x, y));
+
+ // A vector makes a zero angle with itself.
+ EXPECT_EQ(0, MathUtil::SmallestAngleBetweenVectors(x, x));
+ EXPECT_EQ(0, MathUtil::SmallestAngleBetweenVectors(y, y));
+ EXPECT_EQ(0, MathUtil::SmallestAngleBetweenVectors(test_vector, test_vector));
+
+ // Parallel but reversed vectors are at 180 degrees.
+ EXPECT_FLOAT_EQ(180, MathUtil::SmallestAngleBetweenVectors(x, -x));
+ EXPECT_FLOAT_EQ(180, MathUtil::SmallestAngleBetweenVectors(y, -y));
+ EXPECT_FLOAT_EQ(
+ 180, MathUtil::SmallestAngleBetweenVectors(test_vector, -test_vector));
+
+ // The test vector is at a known angle.
+ EXPECT_FLOAT_EQ(
+ 45, std::floor(MathUtil::SmallestAngleBetweenVectors(test_vector, x)));
+ EXPECT_FLOAT_EQ(
+ 45, std::floor(MathUtil::SmallestAngleBetweenVectors(test_vector, y)));
+}
+
+TEST(MathUtilTest, VectorProjection) {
+ gfx::Vector2dF x(1, 0);
+ gfx::Vector2dF y(0, 1);
+ gfx::Vector2dF test_vector(0.3f, 0.7f);
+
+ // Orthogonal vectors project to a zero vector.
+ EXPECT_VECTOR_EQ(gfx::Vector2dF(0, 0), MathUtil::ProjectVector(x, y));
+ EXPECT_VECTOR_EQ(gfx::Vector2dF(0, 0), MathUtil::ProjectVector(y, x));
+
+ // Projecting a vector onto the orthonormal basis gives the corresponding
+ // component of the vector.
+ EXPECT_VECTOR_EQ(gfx::Vector2dF(test_vector.x(), 0),
+ MathUtil::ProjectVector(test_vector, x));
+ EXPECT_VECTOR_EQ(gfx::Vector2dF(0, test_vector.y()),
+ MathUtil::ProjectVector(test_vector, y));
+
+ // Finally check than an arbitrary vector projected to another one gives a
+ // vector parallel to the second vector.
+ gfx::Vector2dF target_vector(0.5, 0.2f);
+ gfx::Vector2dF projected_vector =
+ MathUtil::ProjectVector(test_vector, target_vector);
+ EXPECT_EQ(projected_vector.x() / target_vector.x(),
+ projected_vector.y() / target_vector.y());
+}
+
+} // namespace
+} // namespace cc
diff --git a/chromium/cc/base/region.cc b/chromium/cc/base/region.cc
new file mode 100644
index 00000000000..1cda32d3ba2
--- /dev/null
+++ b/chromium/cc/base/region.cc
@@ -0,0 +1,133 @@
+// Copyright (c) 2012 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 "cc/base/region.h"
+#include "base/values.h"
+
+namespace cc {
+
+Region::Region() {
+}
+
+Region::Region(const Region& region)
+ : skregion_(region.skregion_) {
+}
+
+Region::Region(gfx::Rect rect)
+ : skregion_(gfx::RectToSkIRect(rect)) {
+}
+
+Region::~Region() {
+}
+
+const Region& Region::operator=(gfx::Rect rect) {
+ skregion_ = SkRegion(gfx::RectToSkIRect(rect));
+ return *this;
+}
+
+const Region& Region::operator=(const Region& region) {
+ skregion_ = region.skregion_;
+ return *this;
+}
+
+void Region::Swap(Region* region) {
+ region->skregion_.swap(skregion_);
+}
+
+void Region::Clear() {
+ skregion_.setEmpty();
+}
+
+bool Region::IsEmpty() const {
+ return skregion_.isEmpty();
+}
+
+int Region::GetRegionComplexity() const {
+ return skregion_.computeRegionComplexity();
+}
+
+bool Region::Contains(gfx::Point point) const {
+ return skregion_.contains(point.x(), point.y());
+}
+
+bool Region::Contains(gfx::Rect rect) const {
+ if (rect.IsEmpty())
+ return true;
+ return skregion_.contains(gfx::RectToSkIRect(rect));
+}
+
+bool Region::Contains(const Region& region) const {
+ if (region.IsEmpty())
+ return true;
+ return skregion_.contains(region.skregion_);
+}
+
+bool Region::Intersects(gfx::Rect rect) const {
+ return skregion_.intersects(gfx::RectToSkIRect(rect));
+}
+
+bool Region::Intersects(const Region& region) const {
+ return skregion_.intersects(region.skregion_);
+}
+
+void Region::Subtract(gfx::Rect rect) {
+ skregion_.op(gfx::RectToSkIRect(rect), SkRegion::kDifference_Op);
+}
+
+void Region::Subtract(const Region& region) {
+ skregion_.op(region.skregion_, SkRegion::kDifference_Op);
+}
+
+void Region::Union(gfx::Rect rect) {
+ skregion_.op(gfx::RectToSkIRect(rect), SkRegion::kUnion_Op);
+}
+
+void Region::Union(const Region& region) {
+ skregion_.op(region.skregion_, SkRegion::kUnion_Op);
+}
+
+void Region::Intersect(gfx::Rect rect) {
+ skregion_.op(gfx::RectToSkIRect(rect), SkRegion::kIntersect_Op);
+}
+
+void Region::Intersect(const Region& region) {
+ skregion_.op(region.skregion_, SkRegion::kIntersect_Op);
+}
+
+std::string Region::ToString() const {
+ if (IsEmpty())
+ return gfx::Rect().ToString();
+
+ std::string result;
+ for (Iterator it(*this); it.has_rect(); it.next()) {
+ if (!result.empty())
+ result += " | ";
+ result += it.rect().ToString();
+ }
+ return result;
+}
+
+scoped_ptr<base::Value> Region::AsValue() const {
+ scoped_ptr<base::ListValue> result(new base::ListValue());
+ for (Iterator it(*this); it.has_rect(); it.next()) {
+ gfx::Rect rect(it.rect());
+ result->AppendInteger(rect.x());
+ result->AppendInteger(rect.y());
+ result->AppendInteger(rect.width());
+ result->AppendInteger(rect.height());
+ }
+ return result.PassAs<base::Value>();
+}
+
+Region::Iterator::Iterator() {
+}
+
+Region::Iterator::Iterator(const Region& region)
+ : it_(region.skregion_) {
+}
+
+Region::Iterator::~Iterator() {
+}
+
+} // namespace cc
diff --git a/chromium/cc/base/region.h b/chromium/cc/base/region.h
new file mode 100644
index 00000000000..26c1d2b1990
--- /dev/null
+++ b/chromium/cc/base/region.h
@@ -0,0 +1,135 @@
+// Copyright (c) 2012 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.
+
+#ifndef CC_BASE_REGION_H_
+#define CC_BASE_REGION_H_
+
+#include <string>
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "cc/base/cc_export.h"
+#include "third_party/skia/include/core/SkRegion.h"
+#include "ui/gfx/rect.h"
+#include "ui/gfx/skia_util.h"
+
+namespace base {
+class Value;
+}
+
+namespace cc {
+
+class CC_EXPORT Region {
+ public:
+ Region();
+ Region(const Region& region);
+ Region(gfx::Rect rect); // NOLINT(runtime/explicit)
+ ~Region();
+
+ const Region& operator=(gfx::Rect rect);
+ const Region& operator=(const Region& region);
+
+ void Swap(Region* region);
+ void Clear();
+ bool IsEmpty() const;
+ int GetRegionComplexity() const;
+
+ bool Contains(gfx::Point point) const;
+ bool Contains(gfx::Rect rect) const;
+ bool Contains(const Region& region) const;
+
+ bool Intersects(gfx::Rect rect) const;
+ bool Intersects(const Region& region) const;
+
+ void Subtract(gfx::Rect rect);
+ void Subtract(const Region& region);
+ void Union(gfx::Rect rect);
+ void Union(const Region& region);
+ void Intersect(gfx::Rect rect);
+ void Intersect(const Region& region);
+
+ bool Equals(const Region& other) const {
+ return skregion_ == other.skregion_;
+ }
+
+ gfx::Rect bounds() const {
+ return gfx::SkIRectToRect(skregion_.getBounds());
+ }
+
+ std::string ToString() const;
+ scoped_ptr<base::Value> AsValue() const;
+
+ class CC_EXPORT Iterator {
+ public:
+ Iterator();
+ explicit Iterator(const Region& region);
+ ~Iterator();
+
+ gfx::Rect rect() const {
+ return gfx::SkIRectToRect(it_.rect());
+ }
+
+ void next() {
+ it_.next();
+ }
+
+ bool has_rect() const {
+ return !it_.done();
+ }
+
+ private:
+ SkRegion::Iterator it_;
+ };
+
+ private:
+ SkRegion skregion_;
+};
+
+inline bool operator==(const Region& a, const Region& b) {
+ return a.Equals(b);
+}
+
+inline bool operator!=(const Region& a, const Region& b) {
+ return !(a == b);
+}
+
+inline Region SubtractRegions(const Region& a, const Region& b) {
+ Region result = a;
+ result.Subtract(b);
+ return result;
+}
+
+inline Region SubtractRegions(const Region& a, gfx::Rect b) {
+ Region result = a;
+ result.Subtract(b);
+ return result;
+}
+
+inline Region IntersectRegions(const Region& a, const Region& b) {
+ Region result = a;
+ result.Intersect(b);
+ return result;
+}
+
+inline Region IntersectRegions(const Region& a, gfx::Rect b) {
+ Region result = a;
+ result.Intersect(b);
+ return result;
+}
+
+inline Region UnionRegions(const Region& a, const Region& b) {
+ Region result = a;
+ result.Union(b);
+ return result;
+}
+
+inline Region UnionRegions(const Region& a, gfx::Rect b) {
+ Region result = a;
+ result.Union(b);
+ return result;
+}
+
+} // namespace cc
+
+#endif // CC_BASE_REGION_H_
diff --git a/chromium/cc/base/region_unittest.cc b/chromium/cc/base/region_unittest.cc
new file mode 100644
index 00000000000..c9a218d692a
--- /dev/null
+++ b/chromium/cc/base/region_unittest.cc
@@ -0,0 +1,454 @@
+// Copyright 2012 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 "cc/base/region.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace cc {
+namespace {
+
+#define TEST_INSIDE_RECT(r, x, y, w, h) \
+ EXPECT_TRUE(r.Contains(gfx::Point(x, y))); \
+ EXPECT_TRUE(r.Contains(gfx::Point(x + w - 1, y))); \
+ EXPECT_TRUE(r.Contains(gfx::Point(x, y + h - 1))); \
+ EXPECT_TRUE(r.Contains(gfx::Point(x + w - 1, y + h - 1))); \
+ EXPECT_TRUE(r.Contains(gfx::Point(x, y + h / 2))); \
+ EXPECT_TRUE(r.Contains(gfx::Point(x + w - 1, y + h / 2))); \
+ EXPECT_TRUE(r.Contains(gfx::Point(x + w / 2, y))); \
+ EXPECT_TRUE(r.Contains(gfx::Point(x + w / 2, y + h - 1))); \
+ EXPECT_TRUE(r.Contains(gfx::Point(x + w / 2, y + h / 2))); \
+
+#define TEST_LEFT_OF_RECT(r, x, y, w, h) \
+ EXPECT_FALSE(r.Contains(gfx::Point(x - 1, y))); \
+ EXPECT_FALSE(r.Contains(gfx::Point(x - 1, y + h - 1))); \
+
+#define TEST_RIGHT_OF_RECT(r, x, y, w, h) \
+ EXPECT_FALSE(r.Contains(gfx::Point(x + w, y))); \
+ EXPECT_FALSE(r.Contains(gfx::Point(x + w, y + h - 1))); \
+
+#define TEST_TOP_OF_RECT(r, x, y, w, h) \
+ EXPECT_FALSE(r.Contains(gfx::Point(x, y - 1))); \
+ EXPECT_FALSE(r.Contains(gfx::Point(x + w - 1, y - 1))); \
+
+#define TEST_BOTTOM_OF_RECT(r, x, y, w, h) \
+ EXPECT_FALSE(r.Contains(gfx::Point(x, y + h))); \
+ EXPECT_FALSE(r.Contains(gfx::Point(x + w - 1, y + h))); \
+
+TEST(RegionTest, ContainsPoint) {
+ Region r;
+
+ EXPECT_FALSE(r.Contains(gfx::Point(0, 0)));
+
+ r.Union(gfx::Rect(35, 35, 1, 1));
+ TEST_INSIDE_RECT(r, 35, 35, 1, 1);
+ TEST_LEFT_OF_RECT(r, 35, 35, 1, 1);
+ TEST_RIGHT_OF_RECT(r, 35, 35, 1, 1);
+ TEST_TOP_OF_RECT(r, 35, 35, 1, 1);
+ TEST_BOTTOM_OF_RECT(r, 35, 35, 1, 1);
+
+ r.Union(gfx::Rect(30, 30, 10, 10));
+ TEST_INSIDE_RECT(r, 30, 30, 10, 10);
+ TEST_LEFT_OF_RECT(r, 30, 30, 10, 10);
+ TEST_RIGHT_OF_RECT(r, 30, 30, 10, 10);
+ TEST_TOP_OF_RECT(r, 30, 30, 10, 10);
+ TEST_BOTTOM_OF_RECT(r, 30, 30, 10, 10);
+
+ r.Union(gfx::Rect(31, 40, 10, 10));
+ EXPECT_FALSE(r.Contains(gfx::Point(30, 40)));
+ EXPECT_TRUE(r.Contains(gfx::Point(31, 40)));
+ EXPECT_FALSE(r.Contains(gfx::Point(40, 39)));
+ EXPECT_TRUE(r.Contains(gfx::Point(40, 40)));
+
+ TEST_INSIDE_RECT(r, 30, 30, 10, 10);
+ TEST_LEFT_OF_RECT(r, 30, 30, 10, 10);
+ TEST_RIGHT_OF_RECT(r, 30, 30, 10, 10);
+ TEST_TOP_OF_RECT(r, 30, 30, 10, 10);
+ TEST_INSIDE_RECT(r, 31, 40, 10, 10);
+ TEST_LEFT_OF_RECT(r, 31, 40, 10, 10);
+ TEST_RIGHT_OF_RECT(r, 31, 40, 10, 10);
+ TEST_BOTTOM_OF_RECT(r, 31, 40, 10, 10);
+
+ r.Union(gfx::Rect(42, 40, 10, 10));
+
+ TEST_INSIDE_RECT(r, 42, 40, 10, 10);
+ TEST_LEFT_OF_RECT(r, 42, 40, 10, 10);
+ TEST_RIGHT_OF_RECT(r, 42, 40, 10, 10);
+ TEST_TOP_OF_RECT(r, 42, 40, 10, 10);
+ TEST_BOTTOM_OF_RECT(r, 42, 40, 10, 10);
+
+ TEST_INSIDE_RECT(r, 30, 30, 10, 10);
+ TEST_LEFT_OF_RECT(r, 30, 30, 10, 10);
+ TEST_RIGHT_OF_RECT(r, 30, 30, 10, 10);
+ TEST_TOP_OF_RECT(r, 30, 30, 10, 10);
+ TEST_INSIDE_RECT(r, 31, 40, 10, 10);
+ TEST_LEFT_OF_RECT(r, 31, 40, 10, 10);
+ TEST_RIGHT_OF_RECT(r, 31, 40, 10, 10);
+ TEST_BOTTOM_OF_RECT(r, 31, 40, 10, 10);
+}
+
+TEST(RegionTest, EmptySpan) {
+ Region r;
+ r.Union(gfx::Rect(5, 0, 10, 10));
+ r.Union(gfx::Rect(0, 5, 10, 10));
+ r.Subtract(gfx::Rect(7, 7, 10, 0));
+
+ for (Region::Iterator it(r); it.has_rect(); it.next())
+ EXPECT_FALSE(it.rect().IsEmpty());
+}
+
+#define TEST_NO_INTERSECT(a, b) { \
+ Region ar = a; \
+ Region br = b; \
+ EXPECT_FALSE(ar.Intersects(br)); \
+ EXPECT_FALSE(br.Intersects(ar)); \
+ EXPECT_FALSE(ar.Intersects(b)); \
+ EXPECT_FALSE(br.Intersects(a)); \
+}
+
+#define TEST_INTERSECT(a, b) { \
+ Region ar = a; \
+ Region br = b; \
+ EXPECT_TRUE(ar.Intersects(br)); \
+ EXPECT_TRUE(br.Intersects(ar)); \
+ EXPECT_TRUE(ar.Intersects(b)); \
+ EXPECT_TRUE(br.Intersects(a)); \
+}
+
+TEST(RegionTest, IntersectsRegion) {
+ Region r;
+
+ TEST_NO_INTERSECT(gfx::Rect(), gfx::Rect());
+ TEST_NO_INTERSECT(gfx::Rect(), gfx::Rect(0, 0, 1, 1));
+ TEST_NO_INTERSECT(gfx::Rect(), gfx::Rect(1, 1, 1, 1));
+
+ TEST_NO_INTERSECT(gfx::Rect(-1, -1, 2, 2), gfx::Rect());
+
+ r.Union(gfx::Rect(0, 0, 1, 1));
+ TEST_NO_INTERSECT(r, gfx::Rect());
+ TEST_INTERSECT(r, gfx::Rect(0, 0, 1, 1));
+ TEST_INTERSECT(r, gfx::Rect(0, 0, 2, 2));
+ TEST_INTERSECT(r, gfx::Rect(-1, 0, 2, 2));
+ TEST_INTERSECT(r, gfx::Rect(-1, -1, 2, 2));
+ TEST_INTERSECT(r, gfx::Rect(0, -1, 2, 2));
+ TEST_INTERSECT(r, gfx::Rect(-1, -1, 3, 3));
+
+ r.Union(gfx::Rect(0, 0, 3, 3));
+ r.Union(gfx::Rect(10, 0, 3, 3));
+ r.Union(gfx::Rect(0, 10, 13, 3));
+ TEST_NO_INTERSECT(r, gfx::Rect());
+ TEST_INTERSECT(r, gfx::Rect(1, 1, 1, 1));
+ TEST_INTERSECT(r, gfx::Rect(0, 0, 2, 2));
+ TEST_INTERSECT(r, gfx::Rect(1, 0, 2, 2));
+ TEST_INTERSECT(r, gfx::Rect(1, 1, 2, 2));
+ TEST_INTERSECT(r, gfx::Rect(0, 1, 2, 2));
+ TEST_INTERSECT(r, gfx::Rect(0, 0, 3, 3));
+ TEST_INTERSECT(r, gfx::Rect(-1, -1, 2, 2));
+ TEST_INTERSECT(r, gfx::Rect(2, -1, 2, 2));
+ TEST_INTERSECT(r, gfx::Rect(2, 2, 2, 2));
+ TEST_INTERSECT(r, gfx::Rect(-1, 2, 2, 2));
+
+ TEST_INTERSECT(r, gfx::Rect(11, 1, 1, 1));
+ TEST_INTERSECT(r, gfx::Rect(10, 0, 2, 2));
+ TEST_INTERSECT(r, gfx::Rect(11, 0, 2, 2));
+ TEST_INTERSECT(r, gfx::Rect(11, 1, 2, 2));
+ TEST_INTERSECT(r, gfx::Rect(10, 1, 2, 2));
+ TEST_INTERSECT(r, gfx::Rect(10, 0, 3, 3));
+ TEST_INTERSECT(r, gfx::Rect(9, -1, 2, 2));
+ TEST_INTERSECT(r, gfx::Rect(12, -1, 2, 2));
+ TEST_INTERSECT(r, gfx::Rect(12, 2, 2, 2));
+ TEST_INTERSECT(r, gfx::Rect(9, 2, 2, 2));
+
+ TEST_INTERSECT(r, gfx::Rect(0, -1, 13, 5));
+ TEST_INTERSECT(r, gfx::Rect(1, -1, 11, 5));
+ TEST_INTERSECT(r, gfx::Rect(2, -1, 9, 5));
+ TEST_INTERSECT(r, gfx::Rect(2, -1, 8, 5));
+ TEST_INTERSECT(r, gfx::Rect(3, -1, 8, 5));
+ TEST_NO_INTERSECT(r, gfx::Rect(3, -1, 7, 5));
+
+ TEST_INTERSECT(r, gfx::Rect(0, 1, 13, 1));
+ TEST_INTERSECT(r, gfx::Rect(1, 1, 11, 1));
+ TEST_INTERSECT(r, gfx::Rect(2, 1, 9, 1));
+ TEST_INTERSECT(r, gfx::Rect(2, 1, 8, 1));
+ TEST_INTERSECT(r, gfx::Rect(3, 1, 8, 1));
+ TEST_NO_INTERSECT(r, gfx::Rect(3, 1, 7, 1));
+
+ TEST_INTERSECT(r, gfx::Rect(0, 0, 13, 13));
+ TEST_INTERSECT(r, gfx::Rect(0, 1, 13, 11));
+ TEST_INTERSECT(r, gfx::Rect(0, 2, 13, 9));
+ TEST_INTERSECT(r, gfx::Rect(0, 2, 13, 8));
+ TEST_INTERSECT(r, gfx::Rect(0, 3, 13, 8));
+ TEST_NO_INTERSECT(r, gfx::Rect(0, 3, 13, 7));
+}
+
+TEST(RegionTest, ReadPastFullSpanVectorInIntersectsTest) {
+ Region r;
+
+ // This region has enough spans to fill its allocated Vector exactly.
+ r.Union(gfx::Rect(400, 300, 1, 800));
+ r.Union(gfx::Rect(785, 585, 1, 1));
+ r.Union(gfx::Rect(787, 585, 1, 1));
+ r.Union(gfx::Rect(0, 587, 16, 162));
+ r.Union(gfx::Rect(26, 590, 300, 150));
+ r.Union(gfx::Rect(196, 750, 1, 1));
+ r.Union(gfx::Rect(0, 766, 1, 1));
+ r.Union(gfx::Rect(0, 782, 1, 1));
+ r.Union(gfx::Rect(745, 798, 1, 1));
+ r.Union(gfx::Rect(795, 882, 10, 585));
+ r.Union(gfx::Rect(100, 1499, 586, 1));
+ r.Union(gfx::Rect(100, 1500, 585, 784));
+ // This query rect goes past the bottom of the Region, causing the
+ // test to reach the last span and try go past it. It should not read
+ // memory off the end of the span Vector.
+ TEST_NO_INTERSECT(r, gfx::Rect(0, 2184, 1, 150));
+}
+
+#define TEST_NO_CONTAINS(a, b) \
+ { \
+ Region ar = a; \
+ Region br = b; \
+ EXPECT_FALSE(ar.Contains(br)); \
+ EXPECT_FALSE(ar.Contains(b)); \
+ }
+
+#define TEST_CONTAINS(a, b) \
+ { \
+ Region ar = a; \
+ Region br = b; \
+ EXPECT_TRUE(ar.Contains(br)); \
+ EXPECT_TRUE(ar.Contains(b)); \
+ }
+
+TEST(RegionTest, ContainsRegion) {
+ TEST_CONTAINS(gfx::Rect(), gfx::Rect());
+ TEST_CONTAINS(gfx::Rect(0, 0, 1, 1), gfx::Rect());
+ TEST_CONTAINS(gfx::Rect(10, 10, 1, 1), gfx::Rect());
+
+ TEST_NO_CONTAINS(gfx::Rect(), gfx::Rect(0, 0, 1, 1));
+ TEST_NO_CONTAINS(gfx::Rect(), gfx::Rect(1, 1, 1, 1));
+
+ TEST_NO_CONTAINS(gfx::Rect(10, 10, 1, 1), gfx::Rect(11, 10, 1, 1));
+ TEST_NO_CONTAINS(gfx::Rect(10, 10, 1, 1), gfx::Rect(10, 11, 1, 1));
+ TEST_NO_CONTAINS(gfx::Rect(10, 10, 1, 1), gfx::Rect(9, 10, 1, 1));
+ TEST_NO_CONTAINS(gfx::Rect(10, 10, 1, 1), gfx::Rect(10, 9, 1, 1));
+ TEST_NO_CONTAINS(gfx::Rect(10, 10, 1, 1), gfx::Rect(9, 9, 2, 2));
+ TEST_NO_CONTAINS(gfx::Rect(10, 10, 1, 1), gfx::Rect(10, 9, 2, 2));
+ TEST_NO_CONTAINS(gfx::Rect(10, 10, 1, 1), gfx::Rect(9, 10, 2, 2));
+ TEST_NO_CONTAINS(gfx::Rect(10, 10, 1, 1), gfx::Rect(10, 10, 2, 2));
+ TEST_NO_CONTAINS(gfx::Rect(10, 10, 1, 1), gfx::Rect(9, 9, 3, 3));
+
+ Region h_lines;
+ for (int i = 10; i < 20; i += 2)
+ h_lines.Union(gfx::Rect(i, 10, 1, 10));
+
+ TEST_CONTAINS(gfx::Rect(10, 10, 9, 10), h_lines);
+ TEST_NO_CONTAINS(gfx::Rect(10, 10, 9, 9), h_lines);
+ TEST_NO_CONTAINS(gfx::Rect(10, 11, 9, 9), h_lines);
+ TEST_NO_CONTAINS(gfx::Rect(10, 10, 8, 10), h_lines);
+ TEST_NO_CONTAINS(gfx::Rect(11, 10, 8, 10), h_lines);
+
+ Region v_lines;
+ for (int i = 10; i < 20; i += 2)
+ v_lines.Union(gfx::Rect(10, i, 10, 1));
+
+ TEST_CONTAINS(gfx::Rect(10, 10, 10, 9), v_lines);
+ TEST_NO_CONTAINS(gfx::Rect(10, 10, 9, 9), v_lines);
+ TEST_NO_CONTAINS(gfx::Rect(11, 10, 9, 9), v_lines);
+ TEST_NO_CONTAINS(gfx::Rect(10, 10, 10, 8), v_lines);
+ TEST_NO_CONTAINS(gfx::Rect(10, 11, 10, 8), v_lines);
+
+ Region grid;
+ for (int i = 10; i < 20; i += 2)
+ for (int j = 10; j < 20; j += 2)
+ grid.Union(gfx::Rect(i, j, 1, 1));
+
+ TEST_CONTAINS(gfx::Rect(10, 10, 9, 9), grid);
+ TEST_NO_CONTAINS(gfx::Rect(10, 10, 9, 8), grid);
+ TEST_NO_CONTAINS(gfx::Rect(10, 11, 9, 8), grid);
+ TEST_NO_CONTAINS(gfx::Rect(10, 10, 8, 9), grid);
+ TEST_NO_CONTAINS(gfx::Rect(11, 10, 8, 9), grid);
+
+ TEST_CONTAINS(h_lines, h_lines);
+ TEST_CONTAINS(v_lines, v_lines);
+ TEST_NO_CONTAINS(v_lines, h_lines);
+ TEST_NO_CONTAINS(h_lines, v_lines);
+ TEST_CONTAINS(grid, grid);
+ TEST_CONTAINS(h_lines, grid);
+ TEST_CONTAINS(v_lines, grid);
+ TEST_NO_CONTAINS(grid, h_lines);
+ TEST_NO_CONTAINS(grid, v_lines);
+
+ for (int i = 10; i < 20; i += 2)
+ TEST_CONTAINS(h_lines, gfx::Rect(i, 10, 1, 10));
+
+ for (int i = 10; i < 20; i += 2)
+ TEST_CONTAINS(v_lines, gfx::Rect(10, i, 10, 1));
+
+ for (int i = 10; i < 20; i += 2)
+ for (int j = 10; j < 20; j += 2)
+ TEST_CONTAINS(grid, gfx::Rect(i, j, 1, 1));
+
+ Region container;
+ container.Union(gfx::Rect(0, 0, 40, 20));
+ container.Union(gfx::Rect(0, 20, 41, 20));
+ TEST_CONTAINS(container, gfx::Rect(5, 5, 30, 30));
+
+ container.Clear();
+ container.Union(gfx::Rect(0, 0, 10, 10));
+ container.Union(gfx::Rect(0, 30, 10, 10));
+ container.Union(gfx::Rect(30, 30, 10, 10));
+ container.Union(gfx::Rect(30, 0, 10, 10));
+ TEST_NO_CONTAINS(container, gfx::Rect(5, 5, 30, 30));
+
+ container.Clear();
+ container.Union(gfx::Rect(0, 0, 10, 10));
+ container.Union(gfx::Rect(0, 30, 10, 10));
+ container.Union(gfx::Rect(30, 0, 10, 40));
+ TEST_NO_CONTAINS(container, gfx::Rect(5, 5, 30, 30));
+
+ container.Clear();
+ container.Union(gfx::Rect(30, 0, 10, 10));
+ container.Union(gfx::Rect(30, 30, 10, 10));
+ container.Union(gfx::Rect(0, 0, 10, 40));
+ TEST_NO_CONTAINS(container, gfx::Rect(5, 5, 30, 30));
+
+ container.Clear();
+ container.Union(gfx::Rect(0, 0, 10, 40));
+ container.Union(gfx::Rect(30, 0, 10, 40));
+ TEST_NO_CONTAINS(container, gfx::Rect(5, 5, 30, 30));
+
+ container.Clear();
+ container.Union(gfx::Rect(0, 0, 40, 40));
+ TEST_NO_CONTAINS(container, gfx::Rect(10, -1, 20, 10));
+
+ container.Clear();
+ container.Union(gfx::Rect(0, 0, 40, 40));
+ TEST_NO_CONTAINS(container, gfx::Rect(10, 31, 20, 10));
+
+ container.Clear();
+ container.Union(gfx::Rect(0, 0, 40, 20));
+ container.Union(gfx::Rect(0, 20, 41, 20));
+ TEST_NO_CONTAINS(container, gfx::Rect(-1, 10, 10, 20));
+
+ container.Clear();
+ container.Union(gfx::Rect(0, 0, 40, 20));
+ container.Union(gfx::Rect(0, 20, 41, 20));
+ TEST_NO_CONTAINS(container, gfx::Rect(31, 10, 10, 20));
+
+ container.Clear();
+ container.Union(gfx::Rect(0, 0, 40, 40));
+ container.Subtract(gfx::Rect(0, 20, 60, 0));
+ TEST_NO_CONTAINS(container, gfx::Rect(31, 10, 10, 20));
+
+ container.Clear();
+ container.Union(gfx::Rect(0, 0, 60, 20));
+ container.Union(gfx::Rect(30, 20, 10, 20));
+ TEST_NO_CONTAINS(container, gfx::Rect(0, 0, 10, 39));
+ TEST_NO_CONTAINS(container, gfx::Rect(0, 0, 10, 40));
+ TEST_NO_CONTAINS(container, gfx::Rect(0, 0, 10, 41));
+ TEST_NO_CONTAINS(container, gfx::Rect(29, 0, 10, 39));
+ TEST_CONTAINS(container, gfx::Rect(30, 0, 10, 40));
+ TEST_NO_CONTAINS(container, gfx::Rect(31, 0, 10, 41));
+ TEST_NO_CONTAINS(container, gfx::Rect(49, 0, 10, 39));
+ TEST_NO_CONTAINS(container, gfx::Rect(50, 0, 10, 40));
+ TEST_NO_CONTAINS(container, gfx::Rect(51, 0, 10, 41));
+
+ container.Clear();
+ container.Union(gfx::Rect(30, 0, 10, 20));
+ container.Union(gfx::Rect(0, 20, 60, 20));
+ TEST_NO_CONTAINS(container, gfx::Rect(0, 0, 10, 39));
+ TEST_NO_CONTAINS(container, gfx::Rect(0, 0, 10, 40));
+ TEST_NO_CONTAINS(container, gfx::Rect(0, 0, 10, 41));
+ TEST_NO_CONTAINS(container, gfx::Rect(29, 0, 10, 39));
+ TEST_CONTAINS(container, gfx::Rect(30, 0, 10, 40));
+ TEST_NO_CONTAINS(container, gfx::Rect(31, 0, 10, 41));
+ TEST_NO_CONTAINS(container, gfx::Rect(49, 0, 10, 39));
+ TEST_NO_CONTAINS(container, gfx::Rect(50, 0, 10, 40));
+ TEST_NO_CONTAINS(container, gfx::Rect(51, 0, 10, 41));
+}
+
+TEST(RegionTest, Union) {
+ Region r;
+ Region r2;
+
+ // A rect uniting a contained rect does not change the region.
+ r2 = r = gfx::Rect(0, 0, 50, 50);
+ r2.Union(gfx::Rect(20, 20, 10, 10));
+ EXPECT_EQ(r, r2);
+
+ // A rect uniting a containing rect gives back the containing rect.
+ r = gfx::Rect(0, 0, 50, 50);
+ r.Union(gfx::Rect(0, 0, 100, 100));
+ EXPECT_EQ(Region(gfx::Rect(0, 0, 100, 100)), r);
+
+ // A complex region uniting a contained rect does not change the region.
+ r = gfx::Rect(0, 0, 50, 50);
+ r.Union(gfx::Rect(100, 0, 50, 50));
+ r2 = r;
+ r2.Union(gfx::Rect(20, 20, 10, 10));
+ EXPECT_EQ(r, r2);
+
+ // A complex region uniting a containing rect gives back the containing rect.
+ r = gfx::Rect(0, 0, 50, 50);
+ r.Union(gfx::Rect(100, 0, 50, 50));
+ r.Union(gfx::Rect(0, 0, 500, 500));
+ EXPECT_EQ(Region(gfx::Rect(0, 0, 500, 500)), r);
+}
+
+TEST(RegionTest, IsEmpty) {
+ EXPECT_TRUE(Region().IsEmpty());
+ EXPECT_TRUE(Region(gfx::Rect()).IsEmpty());
+ EXPECT_TRUE(Region(Region()).IsEmpty());
+ EXPECT_TRUE(Region(gfx::Rect(10, 10, 10, 0)).IsEmpty());
+ EXPECT_TRUE(Region(gfx::Rect(10, 10, 0, 10)).IsEmpty());
+ EXPECT_TRUE(Region(gfx::Rect(-10, 10, 10, 0)).IsEmpty());
+ EXPECT_TRUE(Region(gfx::Rect(-10, 10, 0, 10)).IsEmpty());
+ EXPECT_FALSE(Region(gfx::Rect(-1, -1, 1, 1)).IsEmpty());
+ EXPECT_FALSE(Region(gfx::Rect(0, 0, 1, 1)).IsEmpty());
+ EXPECT_FALSE(Region(gfx::Rect(0, 0, 2, 2)).IsEmpty());
+
+ EXPECT_TRUE(SkIRect::MakeXYWH(10, 10, 10, 0).isEmpty());
+ EXPECT_TRUE(SkIRect::MakeXYWH(10, 10, 0, 10).isEmpty());
+ EXPECT_TRUE(SkIRect::MakeXYWH(-10, 10, 10, 0).isEmpty());
+ EXPECT_TRUE(SkIRect::MakeXYWH(-10, 10, 0, 10).isEmpty());
+ EXPECT_FALSE(SkIRect::MakeXYWH(-1, -1, 1, 1).isEmpty());
+ EXPECT_FALSE(SkIRect::MakeXYWH(0, 0, 1, 1).isEmpty());
+ EXPECT_FALSE(SkIRect::MakeXYWH(0, 0, 2, 2).isEmpty());
+}
+
+TEST(RegionTest, Clear) {
+ Region r;
+
+ r = gfx::Rect(0, 0, 50, 50);
+ EXPECT_FALSE(r.IsEmpty());
+ r.Clear();
+ EXPECT_TRUE(r.IsEmpty());
+
+ r = gfx::Rect(0, 0, 50, 50);
+ r.Union(gfx::Rect(100, 0, 50, 50));
+ r.Union(gfx::Rect(0, 0, 500, 500));
+ EXPECT_FALSE(r.IsEmpty());
+ r.Clear();
+ EXPECT_TRUE(r.IsEmpty());
+}
+
+TEST(RegionSwap, Swap) {
+ Region r1, r2, r3;
+
+ r1 = gfx::Rect(0, 0, 50, 50);
+ r1.Swap(&r2);
+ EXPECT_TRUE(r1.IsEmpty());
+ EXPECT_EQ(r2.ToString(), Region(gfx::Rect(0, 0, 50, 50)).ToString());
+
+ r1 = gfx::Rect(0, 0, 50, 50);
+ r1.Union(gfx::Rect(100, 0, 50, 50));
+ r1.Union(gfx::Rect(0, 0, 500, 500));
+ r3 = r1;
+ r1.Swap(&r2);
+ EXPECT_EQ(r1.ToString(), Region(gfx::Rect(0, 0, 50, 50)).ToString());
+ EXPECT_EQ(r2.ToString(), r3.ToString());
+}
+
+} // namespace
+} // namespace cc
diff --git a/chromium/cc/base/scoped_ptr_algorithm.h b/chromium/cc/base/scoped_ptr_algorithm.h
new file mode 100644
index 00000000000..79f4eee49e6
--- /dev/null
+++ b/chromium/cc/base/scoped_ptr_algorithm.h
@@ -0,0 +1,30 @@
+// Copyright 2012 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.
+
+#ifndef CC_BASE_SCOPED_PTR_ALGORITHM_H_
+#define CC_BASE_SCOPED_PTR_ALGORITHM_H_
+
+namespace cc {
+
+// ScopedContainers need to implement a swap() method since they do not allow
+// assignment to their iterators.
+template <class ForwardIterator, class Predicate, class ScopedContainer>
+ForwardIterator remove_if(
+ ScopedContainer* container,
+ ForwardIterator first,
+ ForwardIterator last,
+ Predicate predicate) {
+ ForwardIterator result = first;
+ for (; first != last; ++first) {
+ if (!predicate(*first)) {
+ container->swap(first, result);
+ ++result;
+ }
+ }
+ return result;
+}
+
+} // namespace cc
+
+#endif // CC_BASE_SCOPED_PTR_ALGORITHM_H_
diff --git a/chromium/cc/base/scoped_ptr_deque.h b/chromium/cc/base/scoped_ptr_deque.h
new file mode 100644
index 00000000000..cb4adfc15be
--- /dev/null
+++ b/chromium/cc/base/scoped_ptr_deque.h
@@ -0,0 +1,137 @@
+// Copyright 2012 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.
+
+#ifndef CC_BASE_SCOPED_PTR_DEQUE_H_
+#define CC_BASE_SCOPED_PTR_DEQUE_H_
+
+#include <algorithm>
+#include <deque>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/stl_util.h"
+
+namespace cc {
+
+// This type acts like a deque<scoped_ptr> based on top of std::deque. The
+// ScopedPtrDeque has ownership of all elements in the deque.
+template <typename T>
+class ScopedPtrDeque {
+ public:
+ typedef typename std::deque<T*>::const_iterator const_iterator;
+ typedef typename std::deque<T*>::reverse_iterator reverse_iterator;
+ typedef typename std::deque<T*>::const_reverse_iterator
+ const_reverse_iterator;
+
+#if defined(OS_ANDROID)
+ // On Android the iterator is not a class, so we can't block assignment.
+ typedef typename std::deque<T*>::iterator iterator;
+#else
+ // Ban setting values on the iterator directly. New pointers must be passed
+ // to methods on the ScopedPtrDeque class to appear in the deque.
+ class iterator : public std::deque<T*>::iterator {
+ public:
+ explicit iterator(const typename std::deque<T*>::iterator& other)
+ : std::deque<T*>::iterator(other) {}
+ T* const& operator*() { return std::deque<T*>::iterator::operator*(); }
+ };
+#endif
+
+ ScopedPtrDeque() {}
+
+ ~ScopedPtrDeque() { clear(); }
+
+ size_t size() const {
+ return data_.size();
+ }
+
+ T* at(size_t index) const {
+ DCHECK(index < size());
+ return data_[index];
+ }
+
+ T* operator[](size_t index) const {
+ return at(index);
+ }
+
+ T* front() const {
+ DCHECK(!empty());
+ return at(0);
+ }
+
+ T* back() const {
+ DCHECK(!empty());
+ return at(size() - 1);
+ }
+
+ bool empty() const {
+ return data_.empty();
+ }
+
+ scoped_ptr<T> take_front() {
+ scoped_ptr<T> ret(front());
+ data_.pop_front();
+ return ret.Pass();
+ }
+
+ scoped_ptr<T> take_back() {
+ scoped_ptr<T> ret(back());
+ data_.pop_back();
+ return ret.Pass();
+ }
+
+ void clear() {
+ STLDeleteElements(&data_);
+ }
+
+ void push_front(scoped_ptr<T> item) {
+ data_.push_front(item.release());
+ }
+
+ void push_back(scoped_ptr<T> item) {
+ data_.push_back(item.release());
+ }
+
+ void insert(iterator position, scoped_ptr<T> item) {
+ DCHECK(position <= end());
+ data_.insert(position, item.release());
+ }
+
+ scoped_ptr<T> take(iterator position) {
+ DCHECK(position < end());
+ scoped_ptr<T> ret(*position);
+ data_.erase(position);
+ return ret.Pass();
+ }
+
+ void swap(iterator a, iterator b) {
+ DCHECK(a < end());
+ DCHECK(b < end());
+ if (a == end() || b == end() || a == b)
+ return;
+ typename std::deque<T*>::iterator writable_a = a;
+ typename std::deque<T*>::iterator writable_b = b;
+ std::swap(*writable_a, *writable_b);
+ }
+
+ iterator begin() { return static_cast<iterator>(data_.begin()); }
+ const_iterator begin() const { return data_.begin(); }
+ iterator end() { return static_cast<iterator>(data_.end()); }
+ const_iterator end() const { return data_.end(); }
+
+ reverse_iterator rbegin() { return data_.rbegin(); }
+ const_reverse_iterator rbegin() const { return data_.rbegin(); }
+ reverse_iterator rend() { return data_.rend(); }
+ const_reverse_iterator rend() const { return data_.rend(); }
+
+ private:
+ std::deque<T*> data_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedPtrDeque);
+};
+
+} // namespace cc
+
+#endif // CC_BASE_SCOPED_PTR_DEQUE_H_
diff --git a/chromium/cc/base/scoped_ptr_hash_map.h b/chromium/cc/base/scoped_ptr_hash_map.h
new file mode 100644
index 00000000000..47135822d2d
--- /dev/null
+++ b/chromium/cc/base/scoped_ptr_hash_map.h
@@ -0,0 +1,157 @@
+// Copyright 2012 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.
+
+#ifndef CC_BASE_SCOPED_PTR_HASH_MAP_H_
+#define CC_BASE_SCOPED_PTR_HASH_MAP_H_
+
+#include <algorithm>
+#include <utility>
+
+#include "base/basictypes.h"
+#include "base/containers/hash_tables.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/stl_util.h"
+
+namespace cc {
+
+// This type acts like a hash_map<K, scoped_ptr<V> >, based on top of
+// base::hash_map. The ScopedPtrHashMap has ownership of all values in the data
+// structure.
+template <typename Key, typename Value>
+class ScopedPtrHashMap {
+ typedef base::hash_map<Key, Value*> Container;
+
+ public:
+ typedef typename Container::iterator iterator;
+ typedef typename Container::const_iterator const_iterator;
+
+ ScopedPtrHashMap() {}
+
+ ~ScopedPtrHashMap() { clear(); }
+
+ void swap(ScopedPtrHashMap<Key, Value>& other) {
+ data_.swap(other.data_);
+ }
+
+ std::pair<iterator, bool> insert(
+ std::pair<Key, const scoped_ptr<Value> > pair) {
+ return data_.insert(
+ std::pair<Key, Value*>(pair.first, pair.second.release()));
+ }
+
+ // Replaces value but not key if key is already present.
+ std::pair<iterator, bool> set(Key key, scoped_ptr<Value> data) {
+ iterator it = find(key);
+ if (it != end())
+ erase(it);
+ Value* raw_ptr = data.release();
+ return data_.insert(std::pair<Key, Value*>(key, raw_ptr));
+ }
+
+ // Does nothing if key is already present
+ std::pair<iterator, bool> add(Key key, scoped_ptr<Value> data) {
+ Value* raw_ptr = data.release();
+ return data_.insert(std::pair<Key, Value*>(key, raw_ptr));
+ }
+
+ void erase(iterator it) {
+ if (it->second)
+ delete it->second;
+ data_.erase(it);
+ }
+
+ size_t erase(const Key& k) {
+ iterator it = data_.find(k);
+ if (it == data_.end())
+ return 0;
+ erase(it);
+ return 1;
+ }
+
+ scoped_ptr<Value> take(iterator it) {
+ DCHECK(it != data_.end());
+ if (it == data_.end())
+ return scoped_ptr<Value>();
+
+ Key key = it->first;
+ scoped_ptr<Value> ret(it->second);
+ data_.erase(it);
+ data_.insert(std::pair<Key, Value*>(key, static_cast<Value*>(NULL)));
+ return ret.Pass();
+ }
+
+ scoped_ptr<Value> take(const Key& k) {
+ iterator it = find(k);
+ if (it == data_.end())
+ return scoped_ptr<Value>();
+
+ return take(it);
+ }
+
+ scoped_ptr<Value> take_and_erase(iterator it) {
+ DCHECK(it != data_.end());
+ if (it == data_.end())
+ return scoped_ptr<Value>();
+
+ scoped_ptr<Value> ret(it->second);
+ data_.erase(it);
+ return ret.Pass();
+ }
+
+ scoped_ptr<Value> take_and_erase(const Key& k) {
+ iterator it = find(k);
+ if (it == data_.end())
+ return scoped_ptr<Value>();
+
+ return take_and_erase(it);
+ }
+
+ // Returns the first element in the hash_map that matches the given key.
+ // If no such element exists it returns NULL.
+ Value* get(const Key& k) const {
+ const_iterator it = find(k);
+ if (it == end())
+ return 0;
+ return it->second;
+ }
+
+ inline bool contains(const Key& k) const { return data_.count(k) > 0; }
+
+ inline void clear() { STLDeleteValues(&data_); }
+
+ inline const_iterator find(const Key& k) const { return data_.find(k); }
+ inline iterator find(const Key& k) { return data_.find(k); }
+
+ inline size_t count(const Key& k) const { return data_.count(k); }
+ inline std::pair<const_iterator, const_iterator> equal_range(
+ const Key& k) const {
+ return data_.equal_range(k);
+ }
+ inline std::pair<iterator, iterator> equal_range(const Key& k) {
+ return data_.equal_range(k);
+ }
+
+ inline size_t size() const { return data_.size(); }
+ inline size_t max_size() const { return data_.max_size(); }
+
+ inline bool empty() const { return data_.empty(); }
+
+ inline size_t bucket_count() const { return data_.bucket_count(); }
+ inline void resize(size_t size) const { return data_.resize(size); }
+
+ inline iterator begin() { return data_.begin(); }
+ inline const_iterator begin() const { return data_.begin(); }
+ inline iterator end() { return data_.end(); }
+ inline const_iterator end() const { return data_.end(); }
+
+ private:
+ Container data_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedPtrHashMap);
+};
+
+} // namespace cc
+
+#endif // CC_BASE_SCOPED_PTR_HASH_MAP_H_
diff --git a/chromium/cc/base/scoped_ptr_vector.h b/chromium/cc/base/scoped_ptr_vector.h
new file mode 100644
index 00000000000..856e2f51cd1
--- /dev/null
+++ b/chromium/cc/base/scoped_ptr_vector.h
@@ -0,0 +1,180 @@
+// Copyright 2012 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.
+
+#ifndef CC_BASE_SCOPED_PTR_VECTOR_H_
+#define CC_BASE_SCOPED_PTR_VECTOR_H_
+
+#include <algorithm>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/stl_util.h"
+
+namespace cc {
+
+// This type acts like a vector<scoped_ptr> based on top of std::vector. The
+// ScopedPtrVector has ownership of all elements in the vector.
+template <typename T>
+class ScopedPtrVector {
+ public:
+ typedef typename std::vector<T*>::const_iterator const_iterator;
+ typedef typename std::vector<T*>::reverse_iterator reverse_iterator;
+ typedef typename std::vector<T*>::const_reverse_iterator
+ const_reverse_iterator;
+
+#if defined(OS_ANDROID)
+ // On Android the iterator is not a class, so we can't block assignment.
+ typedef typename std::vector<T*>::iterator iterator;
+#else
+ // Ban setting values on the iterator directly. New pointers must be passed
+ // to methods on the ScopedPtrVector class to appear in the vector.
+ class iterator : public std::vector<T*>::iterator {
+ public:
+ iterator(const typename std::vector<T*>::iterator& other) // NOLINT
+ : std::vector<T*>::iterator(other) {}
+ T* const& operator*() { return std::vector<T*>::iterator::operator*(); }
+ };
+#endif
+
+ ScopedPtrVector() {}
+
+ ~ScopedPtrVector() { clear(); }
+
+ size_t size() const {
+ return data_.size();
+ }
+
+ T* at(size_t index) const {
+ DCHECK(index < size());
+ return data_[index];
+ }
+
+ T* operator[](size_t index) const {
+ return at(index);
+ }
+
+ T* front() const {
+ DCHECK(!empty());
+ return at(0);
+ }
+
+ T* back() const {
+ DCHECK(!empty());
+ return at(size() - 1);
+ }
+
+ bool empty() const {
+ return data_.empty();
+ }
+
+ scoped_ptr<T> take(iterator position) {
+ if (position == end())
+ return scoped_ptr<T>();
+ DCHECK(position < end());
+
+ typename std::vector<T*>::iterator writable_position = position;
+ scoped_ptr<T> ret(*writable_position);
+ *writable_position = NULL;
+ return ret.Pass();
+ }
+
+ scoped_ptr<T> take_back() {
+ DCHECK(!empty());
+ if (empty())
+ return scoped_ptr<T>(NULL);
+ return take(end() - 1);
+ }
+
+ void erase(iterator position) {
+ if (position == end())
+ return;
+ typename std::vector<T*>::iterator writable_position = position;
+ delete *writable_position;
+ data_.erase(position);
+ }
+
+ void erase(iterator first, iterator last) {
+ DCHECK(first <= last);
+ for (iterator it = first; it != last; ++it) {
+ DCHECK(it < end());
+
+ typename std::vector<T*>::iterator writable_it = it;
+ delete *writable_it;
+ }
+ data_.erase(first, last);
+ }
+
+ void reserve(size_t size) {
+ data_.reserve(size);
+ }
+
+ void clear() {
+ STLDeleteElements(&data_);
+ }
+
+ void push_back(scoped_ptr<T> item) {
+ data_.push_back(item.release());
+ }
+
+ void pop_back() {
+ delete data_.back();
+ data_.pop_back();
+ }
+
+ void insert(iterator position, scoped_ptr<T> item) {
+ DCHECK(position <= end());
+ data_.insert(position, item.release());
+ }
+
+ void insert_and_take(iterator position,
+ ScopedPtrVector<T>& other) {
+ std::vector<T*> tmp_data;
+ for (ScopedPtrVector<T>::iterator it = other.begin();
+ it != other.end();
+ ++it) {
+ tmp_data.push_back(other.take(it).release());
+ }
+ data_.insert(position, tmp_data.begin(), tmp_data.end());
+ }
+
+ void swap(ScopedPtrVector<T>& other) {
+ data_.swap(other.data_);
+ }
+
+ void swap(iterator a, iterator b) {
+ DCHECK(a < end());
+ DCHECK(b < end());
+ if (a == end() || b == end() || a == b)
+ return;
+ typename std::vector<T*>::iterator writable_a = a;
+ typename std::vector<T*>::iterator writable_b = b;
+ std::swap(*writable_a, *writable_b);
+ }
+
+ template<class Compare>
+ inline void sort(Compare comp) {
+ std::sort(data_.begin(), data_.end(), comp);
+ }
+
+ iterator begin() { return static_cast<iterator>(data_.begin()); }
+ const_iterator begin() const { return data_.begin(); }
+ iterator end() { return static_cast<iterator>(data_.end()); }
+ const_iterator end() const { return data_.end(); }
+
+ reverse_iterator rbegin() { return data_.rbegin(); }
+ const_reverse_iterator rbegin() const { return data_.rbegin(); }
+ reverse_iterator rend() { return data_.rend(); }
+ const_reverse_iterator rend() const { return data_.rend(); }
+
+ private:
+ std::vector<T*> data_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedPtrVector);
+};
+
+} // namespace cc
+
+#endif // CC_BASE_SCOPED_PTR_VECTOR_H_
diff --git a/chromium/cc/base/scoped_ptr_vector_unittest.cc b/chromium/cc/base/scoped_ptr_vector_unittest.cc
new file mode 100644
index 00000000000..4e450b9c823
--- /dev/null
+++ b/chromium/cc/base/scoped_ptr_vector_unittest.cc
@@ -0,0 +1,72 @@
+// Copyright 2012 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 "cc/base/scoped_ptr_vector.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace cc {
+namespace {
+
+class Data {
+ public:
+ static scoped_ptr<Data> Create(int i) { return make_scoped_ptr(new Data(i)); }
+ int data() const { return data_; }
+ private:
+ explicit Data(int i) : data_(i) {}
+ int data_;
+};
+
+TEST(ScopedPtrVectorTest, PushBack) {
+ ScopedPtrVector<Data> v;
+
+ // Insert 5 things into the vector.
+ v.push_back(Data::Create(1));
+ v.push_back(Data::Create(2));
+ v.push_back(Data::Create(3));
+ v.push_back(Data::Create(4));
+ v.push_back(Data::Create(5));
+
+ EXPECT_EQ(5u, v.size());
+ EXPECT_EQ(1, v[0]->data());
+ EXPECT_EQ(2, v[1]->data());
+ EXPECT_EQ(3, v[2]->data());
+ EXPECT_EQ(4, v[3]->data());
+ EXPECT_EQ(5, v[4]->data());
+}
+
+TEST(ScopedPtrVectorTest, InsertAndTake) {
+ // Insert 3 things into each vector.
+ ScopedPtrVector<Data> v;
+ v.push_back(Data::Create(1));
+ v.push_back(Data::Create(2));
+ v.push_back(Data::Create(6));
+
+ ScopedPtrVector<Data> v2;
+ v2.push_back(Data::Create(3));
+ v2.push_back(Data::Create(4));
+ v2.push_back(Data::Create(5));
+
+ ScopedPtrVector<Data>::iterator it = v.begin();
+ ++it;
+ ++it;
+ EXPECT_EQ(6, (*it)->data());
+
+ v.insert_and_take(it, v2);
+
+ EXPECT_EQ(6u, v.size());
+ EXPECT_EQ(1, v[0]->data());
+ EXPECT_EQ(2, v[1]->data());
+ EXPECT_EQ(3, v[2]->data());
+ EXPECT_EQ(4, v[3]->data());
+ EXPECT_EQ(5, v[4]->data());
+ EXPECT_EQ(6, v[5]->data());
+
+ EXPECT_EQ(3u, v2.size());
+ EXPECT_EQ(NULL, v2[0]);
+ EXPECT_EQ(NULL, v2[1]);
+ EXPECT_EQ(NULL, v2[2]);
+}
+
+} // namespace
+} // namespace cc
diff --git a/chromium/cc/base/switches.cc b/chromium/cc/base/switches.cc
new file mode 100644
index 00000000000..2dac58b6911
--- /dev/null
+++ b/chromium/cc/base/switches.cc
@@ -0,0 +1,150 @@
+// Copyright (c) 2012 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 "cc/base/switches.h"
+
+#include "base/command_line.h"
+
+namespace cc {
+namespace switches {
+
+// On platforms where checkerboards are used, prefer background colors instead
+// of checkerboards.
+const char kBackgroundColorInsteadOfCheckerboard[] =
+ "background-color-instead-of-checkerboard";
+
+const char kDisableThreadedAnimation[] = "disable-threaded-animation";
+
+// Disables layer-edge anti-aliasing in the compositor.
+const char kDisableCompositedAntialiasing[] =
+ "disable-composited-antialiasing";
+
+// Paint content on the main thread instead of the compositor thread.
+// Overrides the kEnableImplSidePainting flag.
+const char kDisableImplSidePainting[] = "disable-impl-side-painting";
+
+// Paint content on the compositor thread instead of the main thread.
+const char kEnableImplSidePainting[] = "enable-impl-side-painting";
+
+const char kEnableTopControlsPositionCalculation[] =
+ "enable-top-controls-position-calculation";
+
+// For any layers that can get drawn directly to screen, draw them with the Skia
+// GPU backend. Only valid with gl rendering + threaded compositing + impl-side
+// painting.
+const char kForceDirectLayerDrawing[] = "force-direct-layer-drawing";
+
+// The height of the movable top controls.
+const char kTopControlsHeight[] = "top-controls-height";
+
+// Percentage of the top controls need to be hidden before they will auto hide.
+const char kTopControlsHideThreshold[] = "top-controls-hide-threshold";
+
+// Percentage of the top controls need to be shown before they will auto show.
+const char kTopControlsShowThreshold[] = "top-controls-show-threshold";
+
+// Number of worker threads used to rasterize content.
+const char kNumRasterThreads[] = "num-raster-threads";
+
+// Show metrics about overdraw in about:tracing recordings, such as the number
+// of pixels culled, and the number of pixels drawn, for each frame.
+const char kTraceOverdraw[] = "trace-overdraw";
+
+// Re-rasters everything multiple times to simulate a much slower machine.
+// Give a scale factor to cause raster to take that many times longer to
+// complete, such as --slow-down-raster-scale-factor=25.
+const char kSlowDownRasterScaleFactor[] = "slow-down-raster-scale-factor";
+
+// The scale factor for low resolution tile contents.
+const char kLowResolutionContentsScaleFactor[] =
+ "low-resolution-contents-scale-factor";
+
+// Max tiles allowed for each tilings interest area.
+const char kMaxTilesForInterestArea[] = "max-tiles-for-interest-area";
+
+// The amount of unused resource memory compositor is allowed to keep around.
+const char kMaxUnusedResourceMemoryUsagePercentage[] =
+ "max-unused-resource-memory-usage-percentage";
+
+// Causes the compositor to render to textures which are then sent to the parent
+// through the texture mailbox mechanism.
+// Requires --enable-compositor-frame-message.
+const char kCompositeToMailbox[] = "composite-to-mailbox";
+
+// Check that property changes during paint do not occur.
+const char kStrictLayerPropertyChangeChecking[] =
+ "strict-layer-property-change-checking";
+
+// Virtual viewport for fixed-position elements, scrollbars during pinch.
+const char kEnablePinchVirtualViewport[] = "enable-pinch-virtual-viewport";
+
+const char kEnablePartialSwap[] = "enable-partial-swap";
+// Disable partial swap which is needed for some OpenGL drivers / emulators.
+const char kUIDisablePartialSwap[] = "ui-disable-partial-swap";
+
+const char kEnablePerTilePainting[] = "enable-per-tile-painting";
+const char kUIEnablePerTilePainting[] = "ui-enable-per-tile-painting";
+
+// Renders a border around compositor layers to help debug and study
+// layer compositing.
+const char kShowCompositedLayerBorders[] = "show-composited-layer-borders";
+const char kUIShowCompositedLayerBorders[] = "ui-show-layer-borders";
+
+// Draws a FPS indicator
+const char kShowFPSCounter[] = "show-fps-counter";
+const char kUIShowFPSCounter[] = "ui-show-fps-counter";
+
+// Show rects in the HUD around layers whose properties have changed.
+const char kShowPropertyChangedRects[] = "show-property-changed-rects";
+const char kUIShowPropertyChangedRects[] = "ui-show-property-changed-rects";
+
+// Show rects in the HUD around damage as it is recorded into each render
+// surface.
+const char kShowSurfaceDamageRects[] = "show-surface-damage-rects";
+const char kUIShowSurfaceDamageRects[] = "ui-show-surface-damage-rects";
+
+// Show rects in the HUD around the screen-space transformed bounds of every
+// layer.
+const char kShowScreenSpaceRects[] = "show-screenspace-rects";
+const char kUIShowScreenSpaceRects[] = "ui-show-screenspace-rects";
+
+// Show rects in the HUD around the screen-space transformed bounds of every
+// layer's replica, when they have one.
+const char kShowReplicaScreenSpaceRects[] = "show-replica-screenspace-rects";
+const char kUIShowReplicaScreenSpaceRects[] =
+ "ui-show-replica-screenspace-rects";
+
+// Show rects in the HUD wherever something is known to be drawn opaque and is
+// considered occluding the pixels behind it.
+const char kShowOccludingRects[] = "show-occluding-rects";
+const char kUIShowOccludingRects[] = "ui-show-occluding-rects";
+
+// Show rects in the HUD wherever something is not known to be drawn opaque and
+// is not considered to be occluding the pixels behind it.
+const char kShowNonOccludingRects[] = "show-nonoccluding-rects";
+const char kUIShowNonOccludingRects[] = "ui-show-nonoccluding-rects";
+
+// Enable the codepath that uses images within TileManager.
+const char kUseMapImage[] = "use-map-image";
+
+// Prevents the layer tree unit tests from timing out.
+const char kCCLayerTreeTestNoTimeout[] = "cc-layer-tree-test-no-timeout";
+
+bool IsImplSidePaintingEnabled() {
+ const CommandLine& command_line = *CommandLine::ForCurrentProcess();
+
+ if (command_line.HasSwitch(cc::switches::kDisableImplSidePainting))
+ return false;
+ else if (command_line.HasSwitch(cc::switches::kEnableImplSidePainting))
+ return true;
+
+#if defined(OS_ANDROID)
+ return true;
+#else
+ return false;
+#endif
+}
+
+} // namespace switches
+} // namespace cc
diff --git a/chromium/cc/base/switches.h b/chromium/cc/base/switches.h
new file mode 100644
index 00000000000..f87eb53ee16
--- /dev/null
+++ b/chromium/cc/base/switches.h
@@ -0,0 +1,73 @@
+// Copyright (c) 2012 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.
+
+// Defines all the "cc" command-line switches.
+
+#ifndef CC_BASE_SWITCHES_H_
+#define CC_BASE_SWITCHES_H_
+
+#include "cc/base/cc_export.h"
+
+// Since cc is used from the render process, anything that goes here also needs
+// to be added to render_process_host_impl.cc.
+
+namespace cc {
+namespace switches {
+
+// Switches for the renderer compositor only.
+CC_EXPORT extern const char kBackgroundColorInsteadOfCheckerboard[];
+CC_EXPORT extern const char kDisableImplSidePainting[];
+CC_EXPORT extern const char kDisableThreadedAnimation[];
+CC_EXPORT extern const char kDisableCompositedAntialiasing[];
+CC_EXPORT extern const char kEnableImplSidePainting[];
+CC_EXPORT extern const char kEnableTopControlsPositionCalculation[];
+CC_EXPORT extern const char kForceDirectLayerDrawing[];
+CC_EXPORT extern const char kJankInsteadOfCheckerboard[];
+CC_EXPORT extern const char kNumRasterThreads[];
+CC_EXPORT extern const char kTopControlsHeight[];
+CC_EXPORT extern const char kTopControlsHideThreshold[];
+CC_EXPORT extern const char kTraceOverdraw[];
+CC_EXPORT extern const char kTopControlsShowThreshold[];
+CC_EXPORT extern const char kSlowDownRasterScaleFactor[];
+CC_EXPORT extern const char kLowResolutionContentsScaleFactor[];
+CC_EXPORT extern const char kCompositeToMailbox[];
+CC_EXPORT extern const char kMaxTilesForInterestArea[];
+CC_EXPORT extern const char kMaxUnusedResourceMemoryUsagePercentage[];
+CC_EXPORT extern const char kEnablePinchVirtualViewport[];
+CC_EXPORT extern const char kEnablePartialSwap[];
+CC_EXPORT extern const char kStrictLayerPropertyChangeChecking[];
+CC_EXPORT extern const char kUseMapImage[];
+
+// Switches for both the renderer and ui compositors.
+CC_EXPORT extern const char kUIDisablePartialSwap[];
+CC_EXPORT extern const char kEnablePerTilePainting[];
+CC_EXPORT extern const char kUIEnablePerTilePainting[];
+
+// Debug visualizations.
+CC_EXPORT extern const char kShowCompositedLayerBorders[];
+CC_EXPORT extern const char kUIShowCompositedLayerBorders[];
+CC_EXPORT extern const char kShowFPSCounter[];
+CC_EXPORT extern const char kUIShowFPSCounter[];
+CC_EXPORT extern const char kShowPropertyChangedRects[];
+CC_EXPORT extern const char kUIShowPropertyChangedRects[];
+CC_EXPORT extern const char kShowSurfaceDamageRects[];
+CC_EXPORT extern const char kUIShowSurfaceDamageRects[];
+CC_EXPORT extern const char kShowScreenSpaceRects[];
+CC_EXPORT extern const char kUIShowScreenSpaceRects[];
+CC_EXPORT extern const char kShowReplicaScreenSpaceRects[];
+CC_EXPORT extern const char kUIShowReplicaScreenSpaceRects[];
+CC_EXPORT extern const char kShowOccludingRects[];
+CC_EXPORT extern const char kUIShowOccludingRects[];
+CC_EXPORT extern const char kShowNonOccludingRects[];
+CC_EXPORT extern const char kUIShowNonOccludingRects[];
+
+// Unit test related.
+CC_EXPORT extern const char kCCLayerTreeTestNoTimeout[];
+
+CC_EXPORT bool IsImplSidePaintingEnabled();
+
+} // namespace switches
+} // namespace cc
+
+#endif // CC_BASE_SWITCHES_H_
diff --git a/chromium/cc/base/tiling_data.cc b/chromium/cc/base/tiling_data.cc
new file mode 100644
index 00000000000..1045d89addd
--- /dev/null
+++ b/chromium/cc/base/tiling_data.cc
@@ -0,0 +1,408 @@
+// Copyright 2010 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 "cc/base/tiling_data.h"
+
+#include <algorithm>
+
+#include "ui/gfx/rect.h"
+#include "ui/gfx/vector2d.h"
+
+namespace cc {
+
+static int ComputeNumTiles(int max_texture_size,
+ int total_size,
+ int border_texels) {
+ if (max_texture_size - 2 * border_texels <= 0)
+ return total_size > 0 && max_texture_size >= total_size ? 1 : 0;
+
+ int num_tiles = std::max(1,
+ 1 + (total_size - 1 - 2 * border_texels) /
+ (max_texture_size - 2 * border_texels));
+ return total_size > 0 ? num_tiles : 0;
+}
+
+TilingData::TilingData()
+ : border_texels_(0) {
+ RecomputeNumTiles();
+}
+
+TilingData::TilingData(
+ gfx::Size max_texture_size,
+ gfx::Size total_size,
+ bool has_border_texels)
+ : max_texture_size_(max_texture_size),
+ total_size_(total_size),
+ border_texels_(has_border_texels ? 1 : 0) {
+ RecomputeNumTiles();
+}
+
+TilingData::TilingData(
+ gfx::Size max_texture_size,
+ gfx::Size total_size,
+ int border_texels)
+ : max_texture_size_(max_texture_size),
+ total_size_(total_size),
+ border_texels_(border_texels) {
+ RecomputeNumTiles();
+}
+
+void TilingData::SetTotalSize(gfx::Size total_size) {
+ total_size_ = total_size;
+ RecomputeNumTiles();
+}
+
+void TilingData::SetMaxTextureSize(gfx::Size max_texture_size) {
+ max_texture_size_ = max_texture_size;
+ RecomputeNumTiles();
+}
+
+void TilingData::SetHasBorderTexels(bool has_border_texels) {
+ border_texels_ = has_border_texels ? 1 : 0;
+ RecomputeNumTiles();
+}
+
+void TilingData::SetBorderTexels(int border_texels) {
+ border_texels_ = border_texels;
+ RecomputeNumTiles();
+}
+
+int TilingData::TileXIndexFromSrcCoord(int src_position) const {
+ if (num_tiles_x_ <= 1)
+ return 0;
+
+ DCHECK_GT(max_texture_size_.width() - 2 * border_texels_, 0);
+ int x = (src_position - border_texels_) /
+ (max_texture_size_.width() - 2 * border_texels_);
+ return std::min(std::max(x, 0), num_tiles_x_ - 1);
+}
+
+int TilingData::TileYIndexFromSrcCoord(int src_position) const {
+ if (num_tiles_y_ <= 1)
+ return 0;
+
+ DCHECK_GT(max_texture_size_.height() - 2 * border_texels_, 0);
+ int y = (src_position - border_texels_) /
+ (max_texture_size_.height() - 2 * border_texels_);
+ return std::min(std::max(y, 0), num_tiles_y_ - 1);
+}
+
+int TilingData::FirstBorderTileXIndexFromSrcCoord(int src_position) const {
+ if (num_tiles_x_ <= 1)
+ return 0;
+
+ DCHECK_GT(max_texture_size_.width() - 2 * border_texels_, 0);
+ int inner_tile_size = max_texture_size_.width() - 2 * border_texels_;
+ int x = (src_position - 2 * border_texels_) / inner_tile_size;
+ return std::min(std::max(x, 0), num_tiles_x_ - 1);
+}
+
+int TilingData::FirstBorderTileYIndexFromSrcCoord(int src_position) const {
+ if (num_tiles_y_ <= 1)
+ return 0;
+
+ DCHECK_GT(max_texture_size_.height() - 2 * border_texels_, 0);
+ int inner_tile_size = max_texture_size_.height() - 2 * border_texels_;
+ int y = (src_position - 2 * border_texels_) / inner_tile_size;
+ return std::min(std::max(y, 0), num_tiles_y_ - 1);
+}
+
+int TilingData::LastBorderTileXIndexFromSrcCoord(int src_position) const {
+ if (num_tiles_x_ <= 1)
+ return 0;
+
+ DCHECK_GT(max_texture_size_.width() - 2 * border_texels_, 0);
+ int inner_tile_size = max_texture_size_.width() - 2 * border_texels_;
+ int x = src_position / inner_tile_size;
+ return std::min(std::max(x, 0), num_tiles_x_ - 1);
+}
+
+int TilingData::LastBorderTileYIndexFromSrcCoord(int src_position) const {
+ if (num_tiles_y_ <= 1)
+ return 0;
+
+ DCHECK_GT(max_texture_size_.height() - 2 * border_texels_, 0);
+ int inner_tile_size = max_texture_size_.height() - 2 * border_texels_;
+ int y = src_position / inner_tile_size;
+ return std::min(std::max(y, 0), num_tiles_y_ - 1);
+}
+
+gfx::Rect TilingData::TileBounds(int i, int j) const {
+ AssertTile(i, j);
+ int max_texture_size_x = max_texture_size_.width() - 2 * border_texels_;
+ int max_texture_size_y = max_texture_size_.height() - 2 * border_texels_;
+ int total_size_x = total_size_.width();
+ int total_size_y = total_size_.height();
+
+ int lo_x = max_texture_size_x * i;
+ if (i != 0)
+ lo_x += border_texels_;
+
+ int lo_y = max_texture_size_y * j;
+ if (j != 0)
+ lo_y += border_texels_;
+
+ int hi_x = max_texture_size_x * (i + 1) + border_texels_;
+ if (i + 1 == num_tiles_x_)
+ hi_x += border_texels_;
+
+ int hi_y = max_texture_size_y * (j + 1) + border_texels_;
+ if (j + 1 == num_tiles_y_)
+ hi_y += border_texels_;
+
+ hi_x = std::min(hi_x, total_size_x);
+ hi_y = std::min(hi_y, total_size_y);
+
+ int x = lo_x;
+ int y = lo_y;
+ int width = hi_x - lo_x;
+ int height = hi_y - lo_y;
+ DCHECK_GE(x, 0);
+ DCHECK_GE(y, 0);
+ DCHECK_GE(width, 0);
+ DCHECK_GE(height, 0);
+ DCHECK_LE(x, total_size_.width());
+ DCHECK_LE(y, total_size_.height());
+ return gfx::Rect(x, y, width, height);
+}
+
+gfx::Rect TilingData::TileBoundsWithBorder(int i, int j) const {
+ AssertTile(i, j);
+ int max_texture_size_x = max_texture_size_.width() - 2 * border_texels_;
+ int max_texture_size_y = max_texture_size_.height() - 2 * border_texels_;
+ int total_size_x = total_size_.width();
+ int total_size_y = total_size_.height();
+
+ int lo_x = max_texture_size_x * i;
+ int lo_y = max_texture_size_y * j;
+
+ int hi_x = lo_x + max_texture_size_x + 2 * border_texels_;
+ int hi_y = lo_y + max_texture_size_y + 2 * border_texels_;
+
+ hi_x = std::min(hi_x, total_size_x);
+ hi_y = std::min(hi_y, total_size_y);
+
+ int x = lo_x;
+ int y = lo_y;
+ int width = hi_x - lo_x;
+ int height = hi_y - lo_y;
+ DCHECK_GE(x, 0);
+ DCHECK_GE(y, 0);
+ DCHECK_GE(width, 0);
+ DCHECK_GE(height, 0);
+ DCHECK_LE(x, total_size_.width());
+ DCHECK_LE(y, total_size_.height());
+ return gfx::Rect(x, y, width, height);
+}
+
+int TilingData::TilePositionX(int x_index) const {
+ DCHECK_GE(x_index, 0);
+ DCHECK_LT(x_index, num_tiles_x_);
+
+ int pos = (max_texture_size_.width() - 2 * border_texels_) * x_index;
+ if (x_index != 0)
+ pos += border_texels_;
+
+ return pos;
+}
+
+int TilingData::TilePositionY(int y_index) const {
+ DCHECK_GE(y_index, 0);
+ DCHECK_LT(y_index, num_tiles_y_);
+
+ int pos = (max_texture_size_.height() - 2 * border_texels_) * y_index;
+ if (y_index != 0)
+ pos += border_texels_;
+
+ return pos;
+}
+
+int TilingData::TileSizeX(int x_index) const {
+ DCHECK_GE(x_index, 0);
+ DCHECK_LT(x_index, num_tiles_x_);
+
+ if (!x_index && num_tiles_x_ == 1)
+ return total_size_.width();
+ if (!x_index && num_tiles_x_ > 1)
+ return max_texture_size_.width() - border_texels_;
+ if (x_index < num_tiles_x_ - 1)
+ return max_texture_size_.width() - 2 * border_texels_;
+ if (x_index == num_tiles_x_ - 1)
+ return total_size_.width() - TilePositionX(x_index);
+
+ NOTREACHED();
+ return 0;
+}
+
+int TilingData::TileSizeY(int y_index) const {
+ DCHECK_GE(y_index, 0);
+ DCHECK_LT(y_index, num_tiles_y_);
+
+ if (!y_index && num_tiles_y_ == 1)
+ return total_size_.height();
+ if (!y_index && num_tiles_y_ > 1)
+ return max_texture_size_.height() - border_texels_;
+ if (y_index < num_tiles_y_ - 1)
+ return max_texture_size_.height() - 2 * border_texels_;
+ if (y_index == num_tiles_y_ - 1)
+ return total_size_.height() - TilePositionY(y_index);
+
+ NOTREACHED();
+ return 0;
+}
+
+gfx::Vector2d TilingData::TextureOffset(int x_index, int y_index) const {
+ int left = (!x_index || num_tiles_x_ == 1) ? 0 : border_texels_;
+ int top = (!y_index || num_tiles_y_ == 1) ? 0 : border_texels_;
+
+ return gfx::Vector2d(left, top);
+}
+
+void TilingData::RecomputeNumTiles() {
+ num_tiles_x_ = ComputeNumTiles(
+ max_texture_size_.width(), total_size_.width(), border_texels_);
+ num_tiles_y_ = ComputeNumTiles(
+ max_texture_size_.height(), total_size_.height(), border_texels_);
+}
+
+TilingData::BaseIterator::BaseIterator(const TilingData* tiling_data)
+ : tiling_data_(tiling_data),
+ index_x_(-1),
+ index_y_(-1) {
+}
+
+TilingData::Iterator::Iterator(const TilingData* tiling_data, gfx::Rect rect)
+ : BaseIterator(tiling_data),
+ left_(-1),
+ right_(-1),
+ bottom_(-1) {
+ if (tiling_data_->num_tiles_x() <= 0 || tiling_data_->num_tiles_y() <= 0) {
+ done();
+ return;
+ }
+
+ rect.Intersect(gfx::Rect(tiling_data_->total_size()));
+ index_x_ = tiling_data_->FirstBorderTileXIndexFromSrcCoord(rect.x());
+ index_y_ = tiling_data_->FirstBorderTileYIndexFromSrcCoord(rect.y());
+ left_ = index_x_;
+ right_ = tiling_data_->LastBorderTileXIndexFromSrcCoord(rect.right() - 1);
+ bottom_ = tiling_data_->LastBorderTileYIndexFromSrcCoord(rect.bottom() - 1);
+
+ // Index functions always return valid indices, so explicitly check
+ // for non-intersecting rects.
+ gfx::Rect new_rect = tiling_data_->TileBoundsWithBorder(index_x_, index_y_);
+ if (!new_rect.Intersects(rect))
+ done();
+}
+
+TilingData::Iterator& TilingData::Iterator::operator++() {
+ if (!*this)
+ return *this;
+
+ index_x_++;
+ if (index_x_ > right_) {
+ index_x_ = left_;
+ index_y_++;
+ if (index_y_ > bottom_)
+ done();
+ }
+
+ return *this;
+}
+
+TilingData::DifferenceIterator::DifferenceIterator(
+ const TilingData* tiling_data,
+ gfx::Rect consider,
+ gfx::Rect ignore)
+ : BaseIterator(tiling_data),
+ consider_left_(-1),
+ consider_top_(-1),
+ consider_right_(-1),
+ consider_bottom_(-1),
+ ignore_left_(-1),
+ ignore_top_(-1),
+ ignore_right_(-1),
+ ignore_bottom_(-1) {
+ if (tiling_data_->num_tiles_x() <= 0 || tiling_data_->num_tiles_y() <= 0) {
+ done();
+ return;
+ }
+
+ gfx::Rect bounds(tiling_data_->total_size());
+ consider.Intersect(bounds);
+ ignore.Intersect(bounds);
+ if (consider.IsEmpty()) {
+ done();
+ return;
+ }
+
+ consider_left_ =
+ tiling_data_->FirstBorderTileXIndexFromSrcCoord(consider.x());
+ consider_top_ =
+ tiling_data_->FirstBorderTileYIndexFromSrcCoord(consider.y());
+ consider_right_ =
+ tiling_data_->LastBorderTileXIndexFromSrcCoord(consider.right() - 1);
+ consider_bottom_ =
+ tiling_data_->LastBorderTileYIndexFromSrcCoord(consider.bottom() - 1);
+
+ if (!ignore.IsEmpty()) {
+ ignore_left_ =
+ tiling_data_->FirstBorderTileXIndexFromSrcCoord(ignore.x());
+ ignore_top_ =
+ tiling_data_->FirstBorderTileYIndexFromSrcCoord(ignore.y());
+ ignore_right_ =
+ tiling_data_->LastBorderTileXIndexFromSrcCoord(ignore.right() - 1);
+ ignore_bottom_ =
+ tiling_data_->LastBorderTileYIndexFromSrcCoord(ignore.bottom() - 1);
+
+ // Clamp ignore indices to consider indices.
+ ignore_left_ = std::max(ignore_left_, consider_left_);
+ ignore_top_ = std::max(ignore_top_, consider_top_);
+ ignore_right_ = std::min(ignore_right_, consider_right_);
+ ignore_bottom_ = std::min(ignore_bottom_, consider_bottom_);
+ }
+
+ if (ignore_left_ == consider_left_ && ignore_right_ == consider_right_ &&
+ ignore_top_ == consider_top_ && ignore_bottom_ == consider_bottom_) {
+ done();
+ return;
+ }
+
+ index_x_ = consider_left_;
+ index_y_ = consider_top_;
+
+ if (in_ignore_rect())
+ ++(*this);
+}
+
+TilingData::DifferenceIterator& TilingData::DifferenceIterator::operator++() {
+ if (!*this)
+ return *this;
+
+ index_x_++;
+ if (in_ignore_rect())
+ index_x_ = ignore_right_ + 1;
+
+ if (index_x_ > consider_right_) {
+ index_x_ = consider_left_;
+ index_y_++;
+
+ if (in_ignore_rect()) {
+ index_x_ = ignore_right_ + 1;
+ // If the ignore rect spans the whole consider rect horizontally, then
+ // ignore_right + 1 will be out of bounds.
+ if (in_ignore_rect() || index_x_ > consider_right_) {
+ index_y_ = ignore_bottom_ + 1;
+ index_x_ = consider_left_;
+ }
+ }
+
+ if (index_y_ > consider_bottom_)
+ done();
+ }
+
+ return *this;
+}
+
+} // namespace cc
diff --git a/chromium/cc/base/tiling_data.h b/chromium/cc/base/tiling_data.h
new file mode 100644
index 00000000000..3bf9809579f
--- /dev/null
+++ b/chromium/cc/base/tiling_data.h
@@ -0,0 +1,148 @@
+// Copyright 2010 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.
+
+#ifndef CC_BASE_TILING_DATA_H_
+#define CC_BASE_TILING_DATA_H_
+
+#include <utility>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "cc/base/cc_export.h"
+#include "ui/gfx/rect.h"
+#include "ui/gfx/size.h"
+
+namespace gfx {
+class Vector2d;
+}
+
+namespace cc {
+
+class CC_EXPORT TilingData {
+ public:
+ TilingData();
+ TilingData(
+ gfx::Size max_texture_size,
+ gfx::Size total_size,
+ bool has_border_texels);
+ TilingData(
+ gfx::Size max_texture_size,
+ gfx::Size total_size,
+ int border_texels);
+
+ gfx::Size total_size() const { return total_size_; }
+ void SetTotalSize(const gfx::Size total_size);
+
+ gfx::Size max_texture_size() const { return max_texture_size_; }
+ void SetMaxTextureSize(gfx::Size max_texture_size);
+
+ int border_texels() const { return border_texels_; }
+ void SetHasBorderTexels(bool has_border_texels);
+ void SetBorderTexels(int border_texels);
+
+ bool has_empty_bounds() const { return !num_tiles_x_ || !num_tiles_y_; }
+ int num_tiles_x() const { return num_tiles_x_; }
+ int num_tiles_y() const { return num_tiles_y_; }
+ // Return the tile index whose non-border texels include src_position.
+ int TileXIndexFromSrcCoord(int src_position) const;
+ int TileYIndexFromSrcCoord(int src_position) const;
+ // Return the lowest tile index whose border texels include src_position.
+ int FirstBorderTileXIndexFromSrcCoord(int src_position) const;
+ int FirstBorderTileYIndexFromSrcCoord(int src_position) const;
+ // Return the highest tile index whose border texels include src_position.
+ int LastBorderTileXIndexFromSrcCoord(int src_position) const;
+ int LastBorderTileYIndexFromSrcCoord(int src_position) const;
+
+ gfx::Rect TileBounds(int i, int j) const;
+ gfx::Rect TileBoundsWithBorder(int i, int j) const;
+ int TilePositionX(int x_index) const;
+ int TilePositionY(int y_index) const;
+ int TileSizeX(int x_index) const;
+ int TileSizeY(int y_index) const;
+
+ // Difference between TileBound's and TileBoundWithBorder's origin().
+ gfx::Vector2d TextureOffset(int x_index, int y_index) const;
+
+ class CC_EXPORT BaseIterator {
+ public:
+ operator bool() const { return index_x_ != -1 && index_y_ != -1; }
+
+ int index_x() const { return index_x_; }
+ int index_y() const { return index_y_; }
+ std::pair<int, int> index() const {
+ return std::make_pair(index_x_, index_y_);
+ }
+
+ protected:
+ explicit BaseIterator(const TilingData* tiling_data);
+ void done() {
+ index_x_ = -1;
+ index_y_ = -1;
+ }
+
+ const TilingData* tiling_data_;
+ int index_x_;
+ int index_y_;
+ };
+
+ // Iterate through all indices whose bounds + border intersect with |rect|.
+ class CC_EXPORT Iterator : public BaseIterator {
+ public:
+ Iterator(const TilingData* tiling_data, gfx::Rect rect);
+ Iterator& operator++();
+
+ private:
+ int left_;
+ int right_;
+ int bottom_;
+ };
+
+ // Iterate through all indices whose bounds + border intersect with
+ // |consider| but which also do not intersect with |ignore|.
+ class CC_EXPORT DifferenceIterator : public BaseIterator {
+ public:
+ DifferenceIterator(
+ const TilingData* tiling_data,
+ gfx::Rect consider,
+ gfx::Rect ignore);
+ DifferenceIterator& operator++();
+
+ private:
+ bool in_ignore_rect() const {
+ return index_x_ >= ignore_left_ && index_x_ <= ignore_right_ &&
+ index_y_ >= ignore_top_ && index_y_ <= ignore_bottom_;
+ }
+
+ int consider_left_;
+ int consider_top_;
+ int consider_right_;
+ int consider_bottom_;
+ int ignore_left_;
+ int ignore_top_;
+ int ignore_right_;
+ int ignore_bottom_;
+ };
+
+ private:
+ void AssertTile(int i, int j) const {
+ DCHECK_GE(i, 0);
+ DCHECK_LT(i, num_tiles_x_);
+ DCHECK_GE(j, 0);
+ DCHECK_LT(j, num_tiles_y_);
+ }
+
+ void RecomputeNumTiles();
+
+ gfx::Size max_texture_size_;
+ gfx::Size total_size_;
+ int border_texels_;
+
+ // These are computed values.
+ int num_tiles_x_;
+ int num_tiles_y_;
+};
+
+} // namespace cc
+
+#endif // CC_BASE_TILING_DATA_H_
diff --git a/chromium/cc/base/tiling_data_unittest.cc b/chromium/cc/base/tiling_data_unittest.cc
new file mode 100644
index 00000000000..db2d6f215a9
--- /dev/null
+++ b/chromium/cc/base/tiling_data_unittest.cc
@@ -0,0 +1,1171 @@
+// Copyright 2013 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 "cc/base/tiling_data.h"
+
+#include <vector>
+
+#include "cc/test/geometry_test_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace cc {
+namespace {
+
+int NumTiles(
+ gfx::Size max_texture_size,
+ gfx::Size total_size,
+ bool has_border_texels) {
+ TilingData tiling(max_texture_size, total_size, has_border_texels);
+ int num_tiles = tiling.num_tiles_x() * tiling.num_tiles_y();
+
+ // Assert no overflow.
+ EXPECT_GE(num_tiles, 0);
+ if (num_tiles > 0)
+ EXPECT_EQ(num_tiles / tiling.num_tiles_x(), tiling.num_tiles_y());
+
+ return num_tiles;
+}
+
+int XIndex(
+ gfx::Size max_texture_size,
+ gfx::Size total_size,
+ bool has_border_texels,
+ int x_coord) {
+ TilingData tiling(max_texture_size, total_size, has_border_texels);
+ return tiling.TileXIndexFromSrcCoord(x_coord);
+}
+
+int YIndex(
+ gfx::Size max_texture_size,
+ gfx::Size total_size,
+ bool has_border_texels,
+ int y_coord) {
+ TilingData tiling(max_texture_size, total_size, has_border_texels);
+ return tiling.TileYIndexFromSrcCoord(y_coord);
+}
+
+int MinBorderXIndex(
+ gfx::Size max_texture_size,
+ gfx::Size total_size,
+ bool has_border_texels,
+ int x_coord) {
+ TilingData tiling(max_texture_size, total_size, has_border_texels);
+ return tiling.FirstBorderTileXIndexFromSrcCoord(x_coord);
+}
+
+int MinBorderYIndex(
+ gfx::Size max_texture_size,
+ gfx::Size total_size,
+ bool has_border_texels,
+ int y_coord) {
+ TilingData tiling(max_texture_size, total_size, has_border_texels);
+ return tiling.FirstBorderTileYIndexFromSrcCoord(y_coord);
+}
+
+int MaxBorderXIndex(
+ gfx::Size max_texture_size,
+ gfx::Size total_size,
+ bool has_border_texels,
+ int x_coord) {
+ TilingData tiling(max_texture_size, total_size, has_border_texels);
+ return tiling.LastBorderTileXIndexFromSrcCoord(x_coord);
+}
+
+int MaxBorderYIndex(
+ gfx::Size max_texture_size,
+ gfx::Size total_size,
+ bool has_border_texels,
+ int y_coord) {
+ TilingData tiling(max_texture_size, total_size, has_border_texels);
+ return tiling.LastBorderTileYIndexFromSrcCoord(y_coord);
+}
+
+int PosX(
+ gfx::Size max_texture_size,
+ gfx::Size total_size,
+ bool has_border_texels,
+ int x_index) {
+ TilingData tiling(max_texture_size, total_size, has_border_texels);
+ return tiling.TilePositionX(x_index);
+}
+
+int PosY(
+ gfx::Size max_texture_size,
+ gfx::Size total_size,
+ bool has_border_texels,
+ int y_index) {
+ TilingData tiling(max_texture_size, total_size, has_border_texels);
+ return tiling.TilePositionY(y_index);
+}
+
+int SizeX(
+ gfx::Size max_texture_size,
+ gfx::Size total_size,
+ bool has_border_texels,
+ int x_index) {
+ TilingData tiling(max_texture_size, total_size, has_border_texels);
+ return tiling.TileSizeX(x_index);
+}
+
+int SizeY(
+ gfx::Size max_texture_size,
+ gfx::Size total_size,
+ bool has_border_texels,
+ int y_index) {
+ TilingData tiling(max_texture_size, total_size, has_border_texels);
+ return tiling.TileSizeY(y_index);
+}
+
+TEST(TilingDataTest, NumTiles_NoTiling) {
+ EXPECT_EQ(1, NumTiles(gfx::Size(16, 16), gfx::Size(16, 16), false));
+ EXPECT_EQ(1, NumTiles(gfx::Size(16, 16), gfx::Size(15, 15), true));
+ EXPECT_EQ(1, NumTiles(gfx::Size(16, 16), gfx::Size(16, 16), true));
+ EXPECT_EQ(1, NumTiles(gfx::Size(16, 16), gfx::Size(1, 16), false));
+ EXPECT_EQ(1, NumTiles(gfx::Size(15, 15), gfx::Size(15, 15), true));
+ EXPECT_EQ(1, NumTiles(gfx::Size(32, 16), gfx::Size(32, 16), false));
+ EXPECT_EQ(1, NumTiles(gfx::Size(32, 16), gfx::Size(32, 16), true));
+}
+
+TEST(TilingDataTest, NumTiles_TilingNoBorders) {
+ EXPECT_EQ(0, NumTiles(gfx::Size(0, 0), gfx::Size(0, 0), false));
+ EXPECT_EQ(0, NumTiles(gfx::Size(0, 0), gfx::Size(4, 0), false));
+ EXPECT_EQ(0, NumTiles(gfx::Size(0, 0), gfx::Size(0, 4), false));
+ EXPECT_EQ(0, NumTiles(gfx::Size(4, 4), gfx::Size(4, 0), false));
+ EXPECT_EQ(0, NumTiles(gfx::Size(4, 4), gfx::Size(0, 4), false));
+ EXPECT_EQ(0, NumTiles(gfx::Size(0, 0), gfx::Size(1, 1), false));
+
+ EXPECT_EQ(1, NumTiles(gfx::Size(1, 1), gfx::Size(1, 1), false));
+ EXPECT_EQ(2, NumTiles(gfx::Size(1, 1), gfx::Size(1, 2), false));
+ EXPECT_EQ(2, NumTiles(gfx::Size(1, 1), gfx::Size(2, 1), false));
+ EXPECT_EQ(1, NumTiles(gfx::Size(2, 2), gfx::Size(1, 1), false));
+ EXPECT_EQ(1, NumTiles(gfx::Size(2, 2), gfx::Size(1, 2), false));
+ EXPECT_EQ(1, NumTiles(gfx::Size(2, 2), gfx::Size(2, 1), false));
+ EXPECT_EQ(1, NumTiles(gfx::Size(2, 2), gfx::Size(2, 2), false));
+ EXPECT_EQ(1, NumTiles(gfx::Size(3, 3), gfx::Size(3, 3), false));
+
+ EXPECT_EQ(1, NumTiles(gfx::Size(4, 4), gfx::Size(1, 4), false));
+ EXPECT_EQ(1, NumTiles(gfx::Size(4, 4), gfx::Size(2, 4), false));
+ EXPECT_EQ(1, NumTiles(gfx::Size(4, 4), gfx::Size(3, 4), false));
+ EXPECT_EQ(1, NumTiles(gfx::Size(4, 4), gfx::Size(4, 4), false));
+ EXPECT_EQ(2, NumTiles(gfx::Size(4, 4), gfx::Size(5, 4), false));
+ EXPECT_EQ(2, NumTiles(gfx::Size(4, 4), gfx::Size(6, 4), false));
+ EXPECT_EQ(2, NumTiles(gfx::Size(4, 4), gfx::Size(7, 4), false));
+ EXPECT_EQ(2, NumTiles(gfx::Size(4, 4), gfx::Size(8, 4), false));
+ EXPECT_EQ(3, NumTiles(gfx::Size(4, 4), gfx::Size(9, 4), false));
+ EXPECT_EQ(3, NumTiles(gfx::Size(4, 4), gfx::Size(10, 4), false));
+ EXPECT_EQ(3, NumTiles(gfx::Size(4, 4), gfx::Size(11, 4), false));
+
+ EXPECT_EQ(1, NumTiles(gfx::Size(5, 5), gfx::Size(1, 5), false));
+ EXPECT_EQ(1, NumTiles(gfx::Size(5, 5), gfx::Size(2, 5), false));
+ EXPECT_EQ(1, NumTiles(gfx::Size(5, 5), gfx::Size(3, 5), false));
+ EXPECT_EQ(1, NumTiles(gfx::Size(5, 5), gfx::Size(4, 5), false));
+ EXPECT_EQ(1, NumTiles(gfx::Size(5, 5), gfx::Size(5, 5), false));
+ EXPECT_EQ(2, NumTiles(gfx::Size(5, 5), gfx::Size(6, 5), false));
+ EXPECT_EQ(2, NumTiles(gfx::Size(5, 5), gfx::Size(7, 5), false));
+ EXPECT_EQ(2, NumTiles(gfx::Size(5, 5), gfx::Size(8, 5), false));
+ EXPECT_EQ(2, NumTiles(gfx::Size(5, 5), gfx::Size(9, 5), false));
+ EXPECT_EQ(2, NumTiles(gfx::Size(5, 5), gfx::Size(10, 5), false));
+ EXPECT_EQ(3, NumTiles(gfx::Size(5, 5), gfx::Size(11, 5), false));
+
+ EXPECT_EQ(1, NumTiles(gfx::Size(16, 16), gfx::Size(16, 16), false));
+ EXPECT_EQ(1, NumTiles(gfx::Size(17, 17), gfx::Size(16, 16), false));
+ EXPECT_EQ(4, NumTiles(gfx::Size(15, 15), gfx::Size(16, 16), false));
+ EXPECT_EQ(4, NumTiles(gfx::Size(8, 8), gfx::Size(16, 16), false));
+ EXPECT_EQ(6, NumTiles(gfx::Size(8, 8), gfx::Size(17, 16), false));
+
+ EXPECT_EQ(8, NumTiles(gfx::Size(5, 8), gfx::Size(17, 16), false));
+}
+
+TEST(TilingDataTest, NumTiles_TilingWithBorders) {
+ EXPECT_EQ(0, NumTiles(gfx::Size(0, 0), gfx::Size(0, 0), true));
+ EXPECT_EQ(0, NumTiles(gfx::Size(0, 0), gfx::Size(4, 0), true));
+ EXPECT_EQ(0, NumTiles(gfx::Size(0, 0), gfx::Size(0, 4), true));
+ EXPECT_EQ(0, NumTiles(gfx::Size(4, 4), gfx::Size(4, 0), true));
+ EXPECT_EQ(0, NumTiles(gfx::Size(4, 4), gfx::Size(0, 4), true));
+ EXPECT_EQ(0, NumTiles(gfx::Size(0, 0), gfx::Size(1, 1), true));
+
+ EXPECT_EQ(1, NumTiles(gfx::Size(1, 1), gfx::Size(1, 1), true));
+ EXPECT_EQ(0, NumTiles(gfx::Size(1, 1), gfx::Size(1, 2), true));
+ EXPECT_EQ(0, NumTiles(gfx::Size(1, 1), gfx::Size(2, 1), true));
+ EXPECT_EQ(1, NumTiles(gfx::Size(2, 2), gfx::Size(1, 1), true));
+ EXPECT_EQ(1, NumTiles(gfx::Size(2, 2), gfx::Size(1, 2), true));
+ EXPECT_EQ(1, NumTiles(gfx::Size(2, 2), gfx::Size(2, 1), true));
+ EXPECT_EQ(1, NumTiles(gfx::Size(2, 2), gfx::Size(2, 2), true));
+
+ EXPECT_EQ(1, NumTiles(gfx::Size(3, 3), gfx::Size(1, 3), true));
+ EXPECT_EQ(1, NumTiles(gfx::Size(3, 3), gfx::Size(2, 3), true));
+ EXPECT_EQ(1, NumTiles(gfx::Size(3, 3), gfx::Size(3, 3), true));
+ EXPECT_EQ(2, NumTiles(gfx::Size(3, 3), gfx::Size(4, 3), true));
+ EXPECT_EQ(3, NumTiles(gfx::Size(3, 3), gfx::Size(5, 3), true));
+ EXPECT_EQ(4, NumTiles(gfx::Size(3, 3), gfx::Size(6, 3), true));
+ EXPECT_EQ(5, NumTiles(gfx::Size(3, 3), gfx::Size(7, 3), true));
+
+ EXPECT_EQ(1, NumTiles(gfx::Size(4, 4), gfx::Size(1, 4), true));
+ EXPECT_EQ(1, NumTiles(gfx::Size(4, 4), gfx::Size(2, 4), true));
+ EXPECT_EQ(1, NumTiles(gfx::Size(4, 4), gfx::Size(3, 4), true));
+ EXPECT_EQ(1, NumTiles(gfx::Size(4, 4), gfx::Size(4, 4), true));
+ EXPECT_EQ(2, NumTiles(gfx::Size(4, 4), gfx::Size(5, 4), true));
+ EXPECT_EQ(2, NumTiles(gfx::Size(4, 4), gfx::Size(6, 4), true));
+ EXPECT_EQ(3, NumTiles(gfx::Size(4, 4), gfx::Size(7, 4), true));
+ EXPECT_EQ(3, NumTiles(gfx::Size(4, 4), gfx::Size(8, 4), true));
+ EXPECT_EQ(4, NumTiles(gfx::Size(4, 4), gfx::Size(9, 4), true));
+ EXPECT_EQ(4, NumTiles(gfx::Size(4, 4), gfx::Size(10, 4), true));
+ EXPECT_EQ(5, NumTiles(gfx::Size(4, 4), gfx::Size(11, 4), true));
+
+ EXPECT_EQ(1, NumTiles(gfx::Size(5, 5), gfx::Size(1, 5), true));
+ EXPECT_EQ(1, NumTiles(gfx::Size(5, 5), gfx::Size(2, 5), true));
+ EXPECT_EQ(1, NumTiles(gfx::Size(5, 5), gfx::Size(3, 5), true));
+ EXPECT_EQ(1, NumTiles(gfx::Size(5, 5), gfx::Size(4, 5), true));
+ EXPECT_EQ(1, NumTiles(gfx::Size(5, 5), gfx::Size(5, 5), true));
+ EXPECT_EQ(2, NumTiles(gfx::Size(5, 5), gfx::Size(6, 5), true));
+ EXPECT_EQ(2, NumTiles(gfx::Size(5, 5), gfx::Size(7, 5), true));
+ EXPECT_EQ(2, NumTiles(gfx::Size(5, 5), gfx::Size(8, 5), true));
+ EXPECT_EQ(3, NumTiles(gfx::Size(5, 5), gfx::Size(9, 5), true));
+ EXPECT_EQ(3, NumTiles(gfx::Size(5, 5), gfx::Size(10, 5), true));
+ EXPECT_EQ(3, NumTiles(gfx::Size(5, 5), gfx::Size(11, 5), true));
+
+ EXPECT_EQ(30, NumTiles(gfx::Size(8, 5), gfx::Size(16, 32), true));
+}
+
+TEST(TilingDataTest, TileXIndexFromSrcCoord) {
+ EXPECT_EQ(0, XIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 0));
+ EXPECT_EQ(0, XIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 1));
+ EXPECT_EQ(0, XIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 2));
+ EXPECT_EQ(1, XIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 3));
+ EXPECT_EQ(1, XIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 4));
+ EXPECT_EQ(1, XIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 5));
+ EXPECT_EQ(2, XIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 6));
+ EXPECT_EQ(2, XIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 7));
+ EXPECT_EQ(2, XIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 8));
+ EXPECT_EQ(3, XIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 9));
+ EXPECT_EQ(3, XIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 10));
+ EXPECT_EQ(3, XIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 11));
+
+ EXPECT_EQ(0, XIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 0));
+ EXPECT_EQ(0, XIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 1));
+ EXPECT_EQ(1, XIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 2));
+ EXPECT_EQ(2, XIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 3));
+ EXPECT_EQ(3, XIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 4));
+ EXPECT_EQ(4, XIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 5));
+ EXPECT_EQ(5, XIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 6));
+ EXPECT_EQ(6, XIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 7));
+ EXPECT_EQ(7, XIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 8));
+ EXPECT_EQ(7, XIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 9));
+ EXPECT_EQ(7, XIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 10));
+ EXPECT_EQ(7, XIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 11));
+
+ EXPECT_EQ(0, XIndex(gfx::Size(1, 1), gfx::Size(1, 1), false, 0));
+ EXPECT_EQ(0, XIndex(gfx::Size(2, 2), gfx::Size(2, 2), false, 0));
+ EXPECT_EQ(0, XIndex(gfx::Size(2, 2), gfx::Size(2, 2), false, 1));
+ EXPECT_EQ(0, XIndex(gfx::Size(3, 3), gfx::Size(3, 3), false, 0));
+ EXPECT_EQ(0, XIndex(gfx::Size(3, 3), gfx::Size(3, 3), false, 1));
+ EXPECT_EQ(0, XIndex(gfx::Size(3, 3), gfx::Size(3, 3), false, 2));
+
+ EXPECT_EQ(0, XIndex(gfx::Size(3, 3), gfx::Size(4, 3), false, 0));
+ EXPECT_EQ(0, XIndex(gfx::Size(3, 3), gfx::Size(4, 3), false, 1));
+ EXPECT_EQ(0, XIndex(gfx::Size(3, 3), gfx::Size(4, 3), false, 2));
+ EXPECT_EQ(1, XIndex(gfx::Size(3, 3), gfx::Size(4, 3), false, 3));
+
+ EXPECT_EQ(0, XIndex(gfx::Size(1, 1), gfx::Size(1, 1), true, 0));
+ EXPECT_EQ(0, XIndex(gfx::Size(2, 2), gfx::Size(2, 2), true, 0));
+ EXPECT_EQ(0, XIndex(gfx::Size(2, 2), gfx::Size(2, 2), true, 1));
+ EXPECT_EQ(0, XIndex(gfx::Size(3, 3), gfx::Size(3, 3), true, 0));
+ EXPECT_EQ(0, XIndex(gfx::Size(3, 3), gfx::Size(3, 3), true, 1));
+ EXPECT_EQ(0, XIndex(gfx::Size(3, 3), gfx::Size(3, 3), true, 2));
+
+ EXPECT_EQ(0, XIndex(gfx::Size(3, 3), gfx::Size(4, 3), true, 0));
+ EXPECT_EQ(0, XIndex(gfx::Size(3, 3), gfx::Size(4, 3), true, 1));
+ EXPECT_EQ(1, XIndex(gfx::Size(3, 3), gfx::Size(4, 3), true, 2));
+ EXPECT_EQ(1, XIndex(gfx::Size(3, 3), gfx::Size(4, 3), true, 3));
+}
+
+TEST(TilingDataTest, FirstBorderTileXIndexFromSrcCoord) {
+ EXPECT_EQ(0, MinBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 0));
+ EXPECT_EQ(0, MinBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 1));
+ EXPECT_EQ(0, MinBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 2));
+ EXPECT_EQ(1, MinBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 3));
+ EXPECT_EQ(1, MinBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 4));
+ EXPECT_EQ(1, MinBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 5));
+ EXPECT_EQ(2, MinBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 6));
+ EXPECT_EQ(2, MinBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 7));
+ EXPECT_EQ(2, MinBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 8));
+ EXPECT_EQ(3, MinBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 9));
+ EXPECT_EQ(3, MinBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 10));
+ EXPECT_EQ(3, MinBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 11));
+
+ EXPECT_EQ(0, MinBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 0));
+ EXPECT_EQ(0, MinBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 1));
+ EXPECT_EQ(0, MinBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 2));
+ EXPECT_EQ(1, MinBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 3));
+ EXPECT_EQ(2, MinBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 4));
+ EXPECT_EQ(3, MinBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 5));
+ EXPECT_EQ(4, MinBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 6));
+ EXPECT_EQ(5, MinBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 7));
+ EXPECT_EQ(6, MinBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 8));
+ EXPECT_EQ(7, MinBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 9));
+ EXPECT_EQ(7, MinBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 10));
+ EXPECT_EQ(7, MinBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 11));
+
+ EXPECT_EQ(0, MinBorderXIndex(gfx::Size(1, 1), gfx::Size(1, 1), false, 0));
+ EXPECT_EQ(0, MinBorderXIndex(gfx::Size(2, 2), gfx::Size(2, 2), false, 0));
+ EXPECT_EQ(0, MinBorderXIndex(gfx::Size(2, 2), gfx::Size(2, 2), false, 1));
+ EXPECT_EQ(0, MinBorderXIndex(gfx::Size(3, 3), gfx::Size(3, 3), false, 0));
+ EXPECT_EQ(0, MinBorderXIndex(gfx::Size(3, 3), gfx::Size(3, 3), false, 1));
+ EXPECT_EQ(0, MinBorderXIndex(gfx::Size(3, 3), gfx::Size(3, 3), false, 2));
+
+ EXPECT_EQ(0, MinBorderXIndex(gfx::Size(3, 3), gfx::Size(4, 3), false, 0));
+ EXPECT_EQ(0, MinBorderXIndex(gfx::Size(3, 3), gfx::Size(4, 3), false, 1));
+ EXPECT_EQ(0, MinBorderXIndex(gfx::Size(3, 3), gfx::Size(4, 3), false, 2));
+ EXPECT_EQ(1, MinBorderXIndex(gfx::Size(3, 3), gfx::Size(4, 3), false, 3));
+
+ EXPECT_EQ(0, MinBorderXIndex(gfx::Size(1, 1), gfx::Size(1, 1), true, 0));
+ EXPECT_EQ(0, MinBorderXIndex(gfx::Size(2, 2), gfx::Size(2, 2), true, 0));
+ EXPECT_EQ(0, MinBorderXIndex(gfx::Size(2, 2), gfx::Size(2, 2), true, 1));
+ EXPECT_EQ(0, MinBorderXIndex(gfx::Size(3, 3), gfx::Size(3, 3), true, 0));
+ EXPECT_EQ(0, MinBorderXIndex(gfx::Size(3, 3), gfx::Size(3, 3), true, 1));
+ EXPECT_EQ(0, MinBorderXIndex(gfx::Size(3, 3), gfx::Size(3, 3), true, 2));
+
+ EXPECT_EQ(0, MinBorderXIndex(gfx::Size(3, 3), gfx::Size(4, 3), true, 0));
+ EXPECT_EQ(0, MinBorderXIndex(gfx::Size(3, 3), gfx::Size(4, 3), true, 1));
+ EXPECT_EQ(0, MinBorderXIndex(gfx::Size(3, 3), gfx::Size(4, 3), true, 2));
+ EXPECT_EQ(1, MinBorderXIndex(gfx::Size(3, 3), gfx::Size(4, 3), true, 3));
+}
+
+TEST(TilingDataTest, LastBorderTileXIndexFromSrcCoord) {
+ EXPECT_EQ(0, MaxBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 0));
+ EXPECT_EQ(0, MaxBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 1));
+ EXPECT_EQ(0, MaxBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 2));
+ EXPECT_EQ(1, MaxBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 3));
+ EXPECT_EQ(1, MaxBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 4));
+ EXPECT_EQ(1, MaxBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 5));
+ EXPECT_EQ(2, MaxBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 6));
+ EXPECT_EQ(2, MaxBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 7));
+ EXPECT_EQ(2, MaxBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 8));
+ EXPECT_EQ(3, MaxBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 9));
+ EXPECT_EQ(3, MaxBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 10));
+ EXPECT_EQ(3, MaxBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 11));
+
+ EXPECT_EQ(0, MaxBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 0));
+ EXPECT_EQ(1, MaxBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 1));
+ EXPECT_EQ(2, MaxBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 2));
+ EXPECT_EQ(3, MaxBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 3));
+ EXPECT_EQ(4, MaxBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 4));
+ EXPECT_EQ(5, MaxBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 5));
+ EXPECT_EQ(6, MaxBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 6));
+ EXPECT_EQ(7, MaxBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 7));
+ EXPECT_EQ(7, MaxBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 8));
+ EXPECT_EQ(7, MaxBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 9));
+ EXPECT_EQ(7, MaxBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 10));
+ EXPECT_EQ(7, MaxBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 11));
+
+ EXPECT_EQ(0, MaxBorderXIndex(gfx::Size(1, 1), gfx::Size(1, 1), false, 0));
+ EXPECT_EQ(0, MaxBorderXIndex(gfx::Size(2, 2), gfx::Size(2, 2), false, 0));
+ EXPECT_EQ(0, MaxBorderXIndex(gfx::Size(2, 2), gfx::Size(2, 2), false, 1));
+ EXPECT_EQ(0, MaxBorderXIndex(gfx::Size(3, 3), gfx::Size(3, 3), false, 0));
+ EXPECT_EQ(0, MaxBorderXIndex(gfx::Size(3, 3), gfx::Size(3, 3), false, 1));
+ EXPECT_EQ(0, MaxBorderXIndex(gfx::Size(3, 3), gfx::Size(3, 3), false, 2));
+
+ EXPECT_EQ(0, MaxBorderXIndex(gfx::Size(3, 3), gfx::Size(4, 3), false, 0));
+ EXPECT_EQ(0, MaxBorderXIndex(gfx::Size(3, 3), gfx::Size(4, 3), false, 1));
+ EXPECT_EQ(0, MaxBorderXIndex(gfx::Size(3, 3), gfx::Size(4, 3), false, 2));
+ EXPECT_EQ(1, MaxBorderXIndex(gfx::Size(3, 3), gfx::Size(4, 3), false, 3));
+
+ EXPECT_EQ(0, MaxBorderXIndex(gfx::Size(1, 1), gfx::Size(1, 1), true, 0));
+ EXPECT_EQ(0, MaxBorderXIndex(gfx::Size(2, 2), gfx::Size(2, 2), true, 0));
+ EXPECT_EQ(0, MaxBorderXIndex(gfx::Size(2, 2), gfx::Size(2, 2), true, 1));
+ EXPECT_EQ(0, MaxBorderXIndex(gfx::Size(3, 3), gfx::Size(3, 3), true, 0));
+ EXPECT_EQ(0, MaxBorderXIndex(gfx::Size(3, 3), gfx::Size(3, 3), true, 1));
+ EXPECT_EQ(0, MaxBorderXIndex(gfx::Size(3, 3), gfx::Size(3, 3), true, 2));
+
+ EXPECT_EQ(0, MaxBorderXIndex(gfx::Size(3, 3), gfx::Size(4, 3), true, 0));
+ EXPECT_EQ(1, MaxBorderXIndex(gfx::Size(3, 3), gfx::Size(4, 3), true, 1));
+ EXPECT_EQ(1, MaxBorderXIndex(gfx::Size(3, 3), gfx::Size(4, 3), true, 2));
+ EXPECT_EQ(1, MaxBorderXIndex(gfx::Size(3, 3), gfx::Size(4, 3), true, 3));
+}
+
+TEST(TilingDataTest, TileYIndexFromSrcCoord) {
+ EXPECT_EQ(0, YIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 0));
+ EXPECT_EQ(0, YIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 1));
+ EXPECT_EQ(0, YIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 2));
+ EXPECT_EQ(1, YIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 3));
+ EXPECT_EQ(1, YIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 4));
+ EXPECT_EQ(1, YIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 5));
+ EXPECT_EQ(2, YIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 6));
+ EXPECT_EQ(2, YIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 7));
+ EXPECT_EQ(2, YIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 8));
+ EXPECT_EQ(3, YIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 9));
+ EXPECT_EQ(3, YIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 10));
+ EXPECT_EQ(3, YIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 11));
+
+ EXPECT_EQ(0, YIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 0));
+ EXPECT_EQ(0, YIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 1));
+ EXPECT_EQ(1, YIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 2));
+ EXPECT_EQ(2, YIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 3));
+ EXPECT_EQ(3, YIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 4));
+ EXPECT_EQ(4, YIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 5));
+ EXPECT_EQ(5, YIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 6));
+ EXPECT_EQ(6, YIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 7));
+ EXPECT_EQ(7, YIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 8));
+ EXPECT_EQ(7, YIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 9));
+ EXPECT_EQ(7, YIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 10));
+ EXPECT_EQ(7, YIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 11));
+
+ EXPECT_EQ(0, YIndex(gfx::Size(1, 1), gfx::Size(1, 1), false, 0));
+ EXPECT_EQ(0, YIndex(gfx::Size(2, 2), gfx::Size(2, 2), false, 0));
+ EXPECT_EQ(0, YIndex(gfx::Size(2, 2), gfx::Size(2, 2), false, 1));
+ EXPECT_EQ(0, YIndex(gfx::Size(3, 3), gfx::Size(3, 3), false, 0));
+ EXPECT_EQ(0, YIndex(gfx::Size(3, 3), gfx::Size(3, 3), false, 1));
+ EXPECT_EQ(0, YIndex(gfx::Size(3, 3), gfx::Size(3, 3), false, 2));
+
+ EXPECT_EQ(0, YIndex(gfx::Size(3, 3), gfx::Size(3, 4), false, 0));
+ EXPECT_EQ(0, YIndex(gfx::Size(3, 3), gfx::Size(3, 4), false, 1));
+ EXPECT_EQ(0, YIndex(gfx::Size(3, 3), gfx::Size(3, 4), false, 2));
+ EXPECT_EQ(1, YIndex(gfx::Size(3, 3), gfx::Size(3, 4), false, 3));
+
+ EXPECT_EQ(0, YIndex(gfx::Size(1, 1), gfx::Size(1, 1), true, 0));
+ EXPECT_EQ(0, YIndex(gfx::Size(2, 2), gfx::Size(2, 2), true, 0));
+ EXPECT_EQ(0, YIndex(gfx::Size(2, 2), gfx::Size(2, 2), true, 1));
+ EXPECT_EQ(0, YIndex(gfx::Size(3, 3), gfx::Size(3, 3), true, 0));
+ EXPECT_EQ(0, YIndex(gfx::Size(3, 3), gfx::Size(3, 3), true, 1));
+ EXPECT_EQ(0, YIndex(gfx::Size(3, 3), gfx::Size(3, 3), true, 2));
+
+ EXPECT_EQ(0, YIndex(gfx::Size(3, 3), gfx::Size(3, 4), true, 0));
+ EXPECT_EQ(0, YIndex(gfx::Size(3, 3), gfx::Size(3, 4), true, 1));
+ EXPECT_EQ(1, YIndex(gfx::Size(3, 3), gfx::Size(3, 4), true, 2));
+ EXPECT_EQ(1, YIndex(gfx::Size(3, 3), gfx::Size(3, 4), true, 3));
+}
+
+TEST(TilingDataTest, FirstBorderTileYIndexFromSrcCoord) {
+ EXPECT_EQ(0, MinBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 0));
+ EXPECT_EQ(0, MinBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 1));
+ EXPECT_EQ(0, MinBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 2));
+ EXPECT_EQ(1, MinBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 3));
+ EXPECT_EQ(1, MinBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 4));
+ EXPECT_EQ(1, MinBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 5));
+ EXPECT_EQ(2, MinBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 6));
+ EXPECT_EQ(2, MinBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 7));
+ EXPECT_EQ(2, MinBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 8));
+ EXPECT_EQ(3, MinBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 9));
+ EXPECT_EQ(3, MinBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 10));
+ EXPECT_EQ(3, MinBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 11));
+
+ EXPECT_EQ(0, MinBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 0));
+ EXPECT_EQ(0, MinBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 1));
+ EXPECT_EQ(0, MinBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 2));
+ EXPECT_EQ(1, MinBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 3));
+ EXPECT_EQ(2, MinBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 4));
+ EXPECT_EQ(3, MinBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 5));
+ EXPECT_EQ(4, MinBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 6));
+ EXPECT_EQ(5, MinBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 7));
+ EXPECT_EQ(6, MinBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 8));
+ EXPECT_EQ(7, MinBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 9));
+ EXPECT_EQ(7, MinBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 10));
+ EXPECT_EQ(7, MinBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 11));
+
+ EXPECT_EQ(0, MinBorderYIndex(gfx::Size(1, 1), gfx::Size(1, 1), false, 0));
+ EXPECT_EQ(0, MinBorderYIndex(gfx::Size(2, 2), gfx::Size(2, 2), false, 0));
+ EXPECT_EQ(0, MinBorderYIndex(gfx::Size(2, 2), gfx::Size(2, 2), false, 1));
+ EXPECT_EQ(0, MinBorderYIndex(gfx::Size(3, 3), gfx::Size(3, 3), false, 0));
+ EXPECT_EQ(0, MinBorderYIndex(gfx::Size(3, 3), gfx::Size(3, 3), false, 1));
+ EXPECT_EQ(0, MinBorderYIndex(gfx::Size(3, 3), gfx::Size(3, 3), false, 2));
+
+ EXPECT_EQ(0, MinBorderYIndex(gfx::Size(3, 3), gfx::Size(3, 4), false, 0));
+ EXPECT_EQ(0, MinBorderYIndex(gfx::Size(3, 3), gfx::Size(3, 4), false, 1));
+ EXPECT_EQ(0, MinBorderYIndex(gfx::Size(3, 3), gfx::Size(3, 4), false, 2));
+ EXPECT_EQ(1, MinBorderYIndex(gfx::Size(3, 3), gfx::Size(3, 4), false, 3));
+
+ EXPECT_EQ(0, MinBorderYIndex(gfx::Size(1, 1), gfx::Size(1, 1), true, 0));
+ EXPECT_EQ(0, MinBorderYIndex(gfx::Size(2, 2), gfx::Size(2, 2), true, 0));
+ EXPECT_EQ(0, MinBorderYIndex(gfx::Size(2, 2), gfx::Size(2, 2), true, 1));
+ EXPECT_EQ(0, MinBorderYIndex(gfx::Size(3, 3), gfx::Size(3, 3), true, 0));
+ EXPECT_EQ(0, MinBorderYIndex(gfx::Size(3, 3), gfx::Size(3, 3), true, 1));
+ EXPECT_EQ(0, MinBorderYIndex(gfx::Size(3, 3), gfx::Size(3, 3), true, 2));
+
+ EXPECT_EQ(0, MinBorderYIndex(gfx::Size(3, 3), gfx::Size(3, 4), true, 0));
+ EXPECT_EQ(0, MinBorderYIndex(gfx::Size(3, 3), gfx::Size(3, 4), true, 1));
+ EXPECT_EQ(0, MinBorderYIndex(gfx::Size(3, 3), gfx::Size(3, 4), true, 2));
+ EXPECT_EQ(1, MinBorderYIndex(gfx::Size(3, 3), gfx::Size(3, 4), true, 3));
+}
+
+TEST(TilingDataTest, LastBorderTileYIndexFromSrcCoord) {
+ EXPECT_EQ(0, MaxBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 0));
+ EXPECT_EQ(0, MaxBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 1));
+ EXPECT_EQ(0, MaxBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 2));
+ EXPECT_EQ(1, MaxBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 3));
+ EXPECT_EQ(1, MaxBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 4));
+ EXPECT_EQ(1, MaxBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 5));
+ EXPECT_EQ(2, MaxBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 6));
+ EXPECT_EQ(2, MaxBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 7));
+ EXPECT_EQ(2, MaxBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 8));
+ EXPECT_EQ(3, MaxBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 9));
+ EXPECT_EQ(3, MaxBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 10));
+ EXPECT_EQ(3, MaxBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 11));
+
+ EXPECT_EQ(0, MaxBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 0));
+ EXPECT_EQ(1, MaxBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 1));
+ EXPECT_EQ(2, MaxBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 2));
+ EXPECT_EQ(3, MaxBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 3));
+ EXPECT_EQ(4, MaxBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 4));
+ EXPECT_EQ(5, MaxBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 5));
+ EXPECT_EQ(6, MaxBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 6));
+ EXPECT_EQ(7, MaxBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 7));
+ EXPECT_EQ(7, MaxBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 8));
+ EXPECT_EQ(7, MaxBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 9));
+ EXPECT_EQ(7, MaxBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 10));
+ EXPECT_EQ(7, MaxBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 11));
+
+ EXPECT_EQ(0, MaxBorderYIndex(gfx::Size(1, 1), gfx::Size(1, 1), false, 0));
+ EXPECT_EQ(0, MaxBorderYIndex(gfx::Size(2, 2), gfx::Size(2, 2), false, 0));
+ EXPECT_EQ(0, MaxBorderYIndex(gfx::Size(2, 2), gfx::Size(2, 2), false, 1));
+ EXPECT_EQ(0, MaxBorderYIndex(gfx::Size(3, 3), gfx::Size(3, 3), false, 0));
+ EXPECT_EQ(0, MaxBorderYIndex(gfx::Size(3, 3), gfx::Size(3, 3), false, 1));
+ EXPECT_EQ(0, MaxBorderYIndex(gfx::Size(3, 3), gfx::Size(3, 3), false, 2));
+
+ EXPECT_EQ(0, MaxBorderYIndex(gfx::Size(3, 3), gfx::Size(3, 4), false, 0));
+ EXPECT_EQ(0, MaxBorderYIndex(gfx::Size(3, 3), gfx::Size(3, 4), false, 1));
+ EXPECT_EQ(0, MaxBorderYIndex(gfx::Size(3, 3), gfx::Size(3, 4), false, 2));
+ EXPECT_EQ(1, MaxBorderYIndex(gfx::Size(3, 3), gfx::Size(3, 4), false, 3));
+
+ EXPECT_EQ(0, MaxBorderYIndex(gfx::Size(1, 1), gfx::Size(1, 1), true, 0));
+ EXPECT_EQ(0, MaxBorderYIndex(gfx::Size(2, 2), gfx::Size(2, 2), true, 0));
+ EXPECT_EQ(0, MaxBorderYIndex(gfx::Size(2, 2), gfx::Size(2, 2), true, 1));
+ EXPECT_EQ(0, MaxBorderYIndex(gfx::Size(3, 3), gfx::Size(3, 3), true, 0));
+ EXPECT_EQ(0, MaxBorderYIndex(gfx::Size(3, 3), gfx::Size(3, 3), true, 1));
+ EXPECT_EQ(0, MaxBorderYIndex(gfx::Size(3, 3), gfx::Size(3, 3), true, 2));
+
+ EXPECT_EQ(0, MaxBorderYIndex(gfx::Size(3, 3), gfx::Size(3, 4), true, 0));
+ EXPECT_EQ(1, MaxBorderYIndex(gfx::Size(3, 3), gfx::Size(3, 4), true, 1));
+ EXPECT_EQ(1, MaxBorderYIndex(gfx::Size(3, 3), gfx::Size(3, 4), true, 2));
+ EXPECT_EQ(1, MaxBorderYIndex(gfx::Size(3, 3), gfx::Size(3, 4), true, 3));
+}
+
+TEST(TilingDataTest, TileSizeX) {
+ EXPECT_EQ(5, SizeX(gfx::Size(5, 5), gfx::Size(5, 5), false, 0));
+ EXPECT_EQ(5, SizeX(gfx::Size(5, 5), gfx::Size(5, 5), true, 0));
+
+ EXPECT_EQ(5, SizeX(gfx::Size(5, 5), gfx::Size(6, 6), false, 0));
+ EXPECT_EQ(1, SizeX(gfx::Size(5, 5), gfx::Size(6, 6), false, 1));
+ EXPECT_EQ(4, SizeX(gfx::Size(5, 5), gfx::Size(6, 6), true, 0));
+ EXPECT_EQ(2, SizeX(gfx::Size(5, 5), gfx::Size(6, 6), true, 1));
+
+ EXPECT_EQ(5, SizeX(gfx::Size(5, 5), gfx::Size(8, 8), false, 0));
+ EXPECT_EQ(3, SizeX(gfx::Size(5, 5), gfx::Size(8, 8), false, 1));
+ EXPECT_EQ(4, SizeX(gfx::Size(5, 5), gfx::Size(8, 8), true, 0));
+ EXPECT_EQ(4, SizeX(gfx::Size(5, 5), gfx::Size(8, 8), true, 1));
+
+ EXPECT_EQ(5, SizeX(gfx::Size(5, 5), gfx::Size(10, 10), false, 0));
+ EXPECT_EQ(5, SizeX(gfx::Size(5, 5), gfx::Size(10, 10), false, 1));
+ EXPECT_EQ(4, SizeX(gfx::Size(5, 5), gfx::Size(10, 10), true, 0));
+ EXPECT_EQ(3, SizeX(gfx::Size(5, 5), gfx::Size(10, 10), true, 1));
+ EXPECT_EQ(3, SizeX(gfx::Size(5, 5), gfx::Size(10, 10), true, 2));
+
+ EXPECT_EQ(4, SizeX(gfx::Size(5, 5), gfx::Size(11, 11), true, 2));
+ EXPECT_EQ(3, SizeX(gfx::Size(5, 5), gfx::Size(12, 12), true, 2));
+
+ EXPECT_EQ(3, SizeX(gfx::Size(5, 9), gfx::Size(12, 17), true, 2));
+}
+
+TEST(TilingDataTest, TileSizeY) {
+ EXPECT_EQ(5, SizeY(gfx::Size(5, 5), gfx::Size(5, 5), false, 0));
+ EXPECT_EQ(5, SizeY(gfx::Size(5, 5), gfx::Size(5, 5), true, 0));
+
+ EXPECT_EQ(5, SizeY(gfx::Size(5, 5), gfx::Size(6, 6), false, 0));
+ EXPECT_EQ(1, SizeY(gfx::Size(5, 5), gfx::Size(6, 6), false, 1));
+ EXPECT_EQ(4, SizeY(gfx::Size(5, 5), gfx::Size(6, 6), true, 0));
+ EXPECT_EQ(2, SizeY(gfx::Size(5, 5), gfx::Size(6, 6), true, 1));
+
+ EXPECT_EQ(5, SizeY(gfx::Size(5, 5), gfx::Size(8, 8), false, 0));
+ EXPECT_EQ(3, SizeY(gfx::Size(5, 5), gfx::Size(8, 8), false, 1));
+ EXPECT_EQ(4, SizeY(gfx::Size(5, 5), gfx::Size(8, 8), true, 0));
+ EXPECT_EQ(4, SizeY(gfx::Size(5, 5), gfx::Size(8, 8), true, 1));
+
+ EXPECT_EQ(5, SizeY(gfx::Size(5, 5), gfx::Size(10, 10), false, 0));
+ EXPECT_EQ(5, SizeY(gfx::Size(5, 5), gfx::Size(10, 10), false, 1));
+ EXPECT_EQ(4, SizeY(gfx::Size(5, 5), gfx::Size(10, 10), true, 0));
+ EXPECT_EQ(3, SizeY(gfx::Size(5, 5), gfx::Size(10, 10), true, 1));
+ EXPECT_EQ(3, SizeY(gfx::Size(5, 5), gfx::Size(10, 10), true, 2));
+
+ EXPECT_EQ(4, SizeY(gfx::Size(5, 5), gfx::Size(11, 11), true, 2));
+ EXPECT_EQ(3, SizeY(gfx::Size(5, 5), gfx::Size(12, 12), true, 2));
+
+ EXPECT_EQ(3, SizeY(gfx::Size(9, 5), gfx::Size(17, 12), true, 2));
+}
+
+TEST(TilingDataTest, TileSizeX_and_TilePositionX) {
+ // Single tile cases:
+ EXPECT_EQ(1, SizeX(gfx::Size(3, 3), gfx::Size(1, 1), false, 0));
+ EXPECT_EQ(0, PosX(gfx::Size(3, 3), gfx::Size(1, 1), false, 0));
+ EXPECT_EQ(1, SizeX(gfx::Size(3, 3), gfx::Size(1, 100), false, 0));
+ EXPECT_EQ(0, PosX(gfx::Size(3, 3), gfx::Size(1, 100), false, 0));
+ EXPECT_EQ(3, SizeX(gfx::Size(3, 3), gfx::Size(3, 1), false, 0));
+ EXPECT_EQ(0, PosX(gfx::Size(3, 3), gfx::Size(3, 1), false, 0));
+ EXPECT_EQ(3, SizeX(gfx::Size(3, 3), gfx::Size(3, 100), false, 0));
+ EXPECT_EQ(0, PosX(gfx::Size(3, 3), gfx::Size(3, 100), false, 0));
+ EXPECT_EQ(1, SizeX(gfx::Size(3, 3), gfx::Size(1, 1), true, 0));
+ EXPECT_EQ(0, PosX(gfx::Size(3, 3), gfx::Size(1, 1), true, 0));
+ EXPECT_EQ(1, SizeX(gfx::Size(3, 3), gfx::Size(1, 100), true, 0));
+ EXPECT_EQ(0, PosX(gfx::Size(3, 3), gfx::Size(1, 100), true, 0));
+ EXPECT_EQ(3, SizeX(gfx::Size(3, 3), gfx::Size(3, 1), true, 0));
+ EXPECT_EQ(0, PosX(gfx::Size(3, 3), gfx::Size(3, 1), true, 0));
+ EXPECT_EQ(3, SizeX(gfx::Size(3, 3), gfx::Size(3, 100), true, 0));
+ EXPECT_EQ(0, PosX(gfx::Size(3, 3), gfx::Size(3, 100), true, 0));
+
+ // Multiple tiles:
+ // no border
+ // positions 0, 3
+ EXPECT_EQ(2, NumTiles(gfx::Size(3, 3), gfx::Size(6, 1), false));
+ EXPECT_EQ(3, SizeX(gfx::Size(3, 3), gfx::Size(6, 1), false, 0));
+ EXPECT_EQ(3, SizeX(gfx::Size(3, 3), gfx::Size(6, 1), false, 1));
+ EXPECT_EQ(0, PosX(gfx::Size(3, 3), gfx::Size(6, 1), false, 0));
+ EXPECT_EQ(3, PosX(gfx::Size(3, 3), gfx::Size(6, 1), false, 1));
+ EXPECT_EQ(3, SizeX(gfx::Size(3, 3), gfx::Size(6, 100), false, 0));
+ EXPECT_EQ(3, SizeX(gfx::Size(3, 3), gfx::Size(6, 100), false, 1));
+ EXPECT_EQ(0, PosX(gfx::Size(3, 3), gfx::Size(6, 100), false, 0));
+ EXPECT_EQ(3, PosX(gfx::Size(3, 3), gfx::Size(6, 100), false, 1));
+
+ // Multiple tiles:
+ // with border
+ // positions 0, 2, 3, 4
+ EXPECT_EQ(4, NumTiles(gfx::Size(3, 3), gfx::Size(6, 1), true));
+ EXPECT_EQ(2, SizeX(gfx::Size(3, 3), gfx::Size(6, 1), true, 0));
+ EXPECT_EQ(1, SizeX(gfx::Size(3, 3), gfx::Size(6, 1), true, 1));
+ EXPECT_EQ(1, SizeX(gfx::Size(3, 3), gfx::Size(6, 1), true, 2));
+ EXPECT_EQ(2, SizeX(gfx::Size(3, 3), gfx::Size(6, 1), true, 3));
+ EXPECT_EQ(0, PosX(gfx::Size(3, 3), gfx::Size(6, 1), true, 0));
+ EXPECT_EQ(2, PosX(gfx::Size(3, 3), gfx::Size(6, 1), true, 1));
+ EXPECT_EQ(3, PosX(gfx::Size(3, 3), gfx::Size(6, 1), true, 2));
+ EXPECT_EQ(4, PosX(gfx::Size(3, 3), gfx::Size(6, 1), true, 3));
+ EXPECT_EQ(2, SizeX(gfx::Size(3, 7), gfx::Size(6, 100), true, 0));
+ EXPECT_EQ(1, SizeX(gfx::Size(3, 7), gfx::Size(6, 100), true, 1));
+ EXPECT_EQ(1, SizeX(gfx::Size(3, 7), gfx::Size(6, 100), true, 2));
+ EXPECT_EQ(2, SizeX(gfx::Size(3, 7), gfx::Size(6, 100), true, 3));
+ EXPECT_EQ(0, PosX(gfx::Size(3, 7), gfx::Size(6, 100), true, 0));
+ EXPECT_EQ(2, PosX(gfx::Size(3, 7), gfx::Size(6, 100), true, 1));
+ EXPECT_EQ(3, PosX(gfx::Size(3, 7), gfx::Size(6, 100), true, 2));
+ EXPECT_EQ(4, PosX(gfx::Size(3, 7), gfx::Size(6, 100), true, 3));
+}
+
+TEST(TilingDataTest, TileSizeY_and_TilePositionY) {
+ // Single tile cases:
+ EXPECT_EQ(1, SizeY(gfx::Size(3, 3), gfx::Size(1, 1), false, 0));
+ EXPECT_EQ(0, PosY(gfx::Size(3, 3), gfx::Size(1, 1), false, 0));
+ EXPECT_EQ(1, SizeY(gfx::Size(3, 3), gfx::Size(100, 1), false, 0));
+ EXPECT_EQ(0, PosY(gfx::Size(3, 3), gfx::Size(100, 1), false, 0));
+ EXPECT_EQ(3, SizeY(gfx::Size(3, 3), gfx::Size(1, 3), false, 0));
+ EXPECT_EQ(0, PosY(gfx::Size(3, 3), gfx::Size(1, 3), false, 0));
+ EXPECT_EQ(3, SizeY(gfx::Size(3, 3), gfx::Size(100, 3), false, 0));
+ EXPECT_EQ(0, PosY(gfx::Size(3, 3), gfx::Size(100, 3), false, 0));
+ EXPECT_EQ(1, SizeY(gfx::Size(3, 3), gfx::Size(1, 1), true, 0));
+ EXPECT_EQ(0, PosY(gfx::Size(3, 3), gfx::Size(1, 1), true, 0));
+ EXPECT_EQ(1, SizeY(gfx::Size(3, 3), gfx::Size(100, 1), true, 0));
+ EXPECT_EQ(0, PosY(gfx::Size(3, 3), gfx::Size(100, 1), true, 0));
+ EXPECT_EQ(3, SizeY(gfx::Size(3, 3), gfx::Size(1, 3), true, 0));
+ EXPECT_EQ(0, PosY(gfx::Size(3, 3), gfx::Size(1, 3), true, 0));
+ EXPECT_EQ(3, SizeY(gfx::Size(3, 3), gfx::Size(100, 3), true, 0));
+ EXPECT_EQ(0, PosY(gfx::Size(3, 3), gfx::Size(100, 3), true, 0));
+
+ // Multiple tiles:
+ // no border
+ // positions 0, 3
+ EXPECT_EQ(2, NumTiles(gfx::Size(3, 3), gfx::Size(1, 6), false));
+ EXPECT_EQ(3, SizeY(gfx::Size(3, 3), gfx::Size(1, 6), false, 0));
+ EXPECT_EQ(3, SizeY(gfx::Size(3, 3), gfx::Size(1, 6), false, 1));
+ EXPECT_EQ(0, PosY(gfx::Size(3, 3), gfx::Size(1, 6), false, 0));
+ EXPECT_EQ(3, PosY(gfx::Size(3, 3), gfx::Size(1, 6), false, 1));
+ EXPECT_EQ(3, SizeY(gfx::Size(3, 3), gfx::Size(100, 6), false, 0));
+ EXPECT_EQ(3, SizeY(gfx::Size(3, 3), gfx::Size(100, 6), false, 1));
+ EXPECT_EQ(0, PosY(gfx::Size(3, 3), gfx::Size(100, 6), false, 0));
+ EXPECT_EQ(3, PosY(gfx::Size(3, 3), gfx::Size(100, 6), false, 1));
+
+ // Multiple tiles:
+ // with border
+ // positions 0, 2, 3, 4
+ EXPECT_EQ(4, NumTiles(gfx::Size(3, 3), gfx::Size(1, 6), true));
+ EXPECT_EQ(2, SizeY(gfx::Size(3, 3), gfx::Size(1, 6), true, 0));
+ EXPECT_EQ(1, SizeY(gfx::Size(3, 3), gfx::Size(1, 6), true, 1));
+ EXPECT_EQ(1, SizeY(gfx::Size(3, 3), gfx::Size(1, 6), true, 2));
+ EXPECT_EQ(2, SizeY(gfx::Size(3, 3), gfx::Size(1, 6), true, 3));
+ EXPECT_EQ(0, PosY(gfx::Size(3, 3), gfx::Size(1, 6), true, 0));
+ EXPECT_EQ(2, PosY(gfx::Size(3, 3), gfx::Size(1, 6), true, 1));
+ EXPECT_EQ(3, PosY(gfx::Size(3, 3), gfx::Size(1, 6), true, 2));
+ EXPECT_EQ(4, PosY(gfx::Size(3, 3), gfx::Size(1, 6), true, 3));
+ EXPECT_EQ(2, SizeY(gfx::Size(7, 3), gfx::Size(100, 6), true, 0));
+ EXPECT_EQ(1, SizeY(gfx::Size(7, 3), gfx::Size(100, 6), true, 1));
+ EXPECT_EQ(1, SizeY(gfx::Size(7, 3), gfx::Size(100, 6), true, 2));
+ EXPECT_EQ(2, SizeY(gfx::Size(7, 3), gfx::Size(100, 6), true, 3));
+ EXPECT_EQ(0, PosY(gfx::Size(7, 3), gfx::Size(100, 6), true, 0));
+ EXPECT_EQ(2, PosY(gfx::Size(7, 3), gfx::Size(100, 6), true, 1));
+ EXPECT_EQ(3, PosY(gfx::Size(7, 3), gfx::Size(100, 6), true, 2));
+ EXPECT_EQ(4, PosY(gfx::Size(7, 3), gfx::Size(100, 6), true, 3));
+}
+
+TEST(TilingDataTest, SetTotalSize) {
+ TilingData data(gfx::Size(5, 5), gfx::Size(5, 5), false);
+ EXPECT_EQ(5, data.total_size().width());
+ EXPECT_EQ(5, data.total_size().height());
+ EXPECT_EQ(1, data.num_tiles_x());
+ EXPECT_EQ(5, data.TileSizeX(0));
+ EXPECT_EQ(1, data.num_tiles_y());
+ EXPECT_EQ(5, data.TileSizeY(0));
+
+ data.SetTotalSize(gfx::Size(6, 5));
+ EXPECT_EQ(6, data.total_size().width());
+ EXPECT_EQ(5, data.total_size().height());
+ EXPECT_EQ(2, data.num_tiles_x());
+ EXPECT_EQ(5, data.TileSizeX(0));
+ EXPECT_EQ(1, data.TileSizeX(1));
+ EXPECT_EQ(1, data.num_tiles_y());
+ EXPECT_EQ(5, data.TileSizeY(0));
+
+ data.SetTotalSize(gfx::Size(5, 12));
+ EXPECT_EQ(5, data.total_size().width());
+ EXPECT_EQ(12, data.total_size().height());
+ EXPECT_EQ(1, data.num_tiles_x());
+ EXPECT_EQ(5, data.TileSizeX(0));
+ EXPECT_EQ(3, data.num_tiles_y());
+ EXPECT_EQ(5, data.TileSizeY(0));
+ EXPECT_EQ(5, data.TileSizeY(1));
+ EXPECT_EQ(2, data.TileSizeY(2));
+}
+
+TEST(TilingDataTest, SetMaxTextureSizeNoBorders) {
+ TilingData data(gfx::Size(8, 8), gfx::Size(16, 32), false);
+ EXPECT_EQ(2, data.num_tiles_x());
+ EXPECT_EQ(4, data.num_tiles_y());
+
+ data.SetMaxTextureSize(gfx::Size(32, 32));
+ EXPECT_EQ(gfx::Size(32, 32), data.max_texture_size());
+ EXPECT_EQ(1, data.num_tiles_x());
+ EXPECT_EQ(1, data.num_tiles_y());
+
+ data.SetMaxTextureSize(gfx::Size(2, 2));
+ EXPECT_EQ(gfx::Size(2, 2), data.max_texture_size());
+ EXPECT_EQ(8, data.num_tiles_x());
+ EXPECT_EQ(16, data.num_tiles_y());
+
+ data.SetMaxTextureSize(gfx::Size(5, 5));
+ EXPECT_EQ(gfx::Size(5, 5), data.max_texture_size());
+ EXPECT_EQ(4, data.num_tiles_x());
+ EXPECT_EQ(7, data.num_tiles_y());
+
+ data.SetMaxTextureSize(gfx::Size(8, 5));
+ EXPECT_EQ(gfx::Size(8, 5), data.max_texture_size());
+ EXPECT_EQ(2, data.num_tiles_x());
+ EXPECT_EQ(7, data.num_tiles_y());
+}
+
+TEST(TilingDataTest, SetMaxTextureSizeBorders) {
+ TilingData data(gfx::Size(8, 8), gfx::Size(16, 32), true);
+ EXPECT_EQ(3, data.num_tiles_x());
+ EXPECT_EQ(5, data.num_tiles_y());
+
+ data.SetMaxTextureSize(gfx::Size(32, 32));
+ EXPECT_EQ(gfx::Size(32, 32), data.max_texture_size());
+ EXPECT_EQ(1, data.num_tiles_x());
+ EXPECT_EQ(1, data.num_tiles_y());
+
+ data.SetMaxTextureSize(gfx::Size(2, 2));
+ EXPECT_EQ(gfx::Size(2, 2), data.max_texture_size());
+ EXPECT_EQ(0, data.num_tiles_x());
+ EXPECT_EQ(0, data.num_tiles_y());
+
+ data.SetMaxTextureSize(gfx::Size(5, 5));
+ EXPECT_EQ(gfx::Size(5, 5), data.max_texture_size());
+ EXPECT_EQ(5, data.num_tiles_x());
+ EXPECT_EQ(10, data.num_tiles_y());
+
+ data.SetMaxTextureSize(gfx::Size(8, 5));
+ EXPECT_EQ(gfx::Size(8, 5), data.max_texture_size());
+ EXPECT_EQ(3, data.num_tiles_x());
+ EXPECT_EQ(10, data.num_tiles_y());
+}
+
+TEST(TilingDataTest, Assignment) {
+ {
+ TilingData source(gfx::Size(8, 8), gfx::Size(16, 32), true);
+ TilingData dest = source;
+ EXPECT_EQ(source.border_texels(), dest.border_texels());
+ EXPECT_EQ(source.max_texture_size(), dest.max_texture_size());
+ EXPECT_EQ(source.num_tiles_x(), dest.num_tiles_x());
+ EXPECT_EQ(source.num_tiles_y(), dest.num_tiles_y());
+ EXPECT_EQ(source.total_size().width(), dest.total_size().width());
+ EXPECT_EQ(source.total_size().height(), dest.total_size().height());
+ }
+ {
+ TilingData source(gfx::Size(7, 3), gfx::Size(6, 100), false);
+ TilingData dest(source);
+ EXPECT_EQ(source.border_texels(), dest.border_texels());
+ EXPECT_EQ(source.max_texture_size(), dest.max_texture_size());
+ EXPECT_EQ(source.num_tiles_x(), dest.num_tiles_x());
+ EXPECT_EQ(source.num_tiles_y(), dest.num_tiles_y());
+ EXPECT_EQ(source.total_size().width(), dest.total_size().width());
+ EXPECT_EQ(source.total_size().height(), dest.total_size().height());
+ }
+}
+
+TEST(TilingDataTest, SetBorderTexels) {
+ TilingData data(gfx::Size(8, 8), gfx::Size(16, 32), false);
+ EXPECT_EQ(2, data.num_tiles_x());
+ EXPECT_EQ(4, data.num_tiles_y());
+
+ data.SetHasBorderTexels(true);
+ EXPECT_EQ(3, data.num_tiles_x());
+ EXPECT_EQ(5, data.num_tiles_y());
+
+ data.SetHasBorderTexels(true);
+ EXPECT_EQ(3, data.num_tiles_x());
+ EXPECT_EQ(5, data.num_tiles_y());
+
+ data.SetHasBorderTexels(false);
+ EXPECT_EQ(2, data.num_tiles_x());
+ EXPECT_EQ(4, data.num_tiles_y());
+}
+
+TEST(TilingDataTest, LargeBorders) {
+ TilingData data(gfx::Size(100, 80), gfx::Size(200, 145), 30);
+ EXPECT_EQ(30, data.border_texels());
+
+ EXPECT_EQ(70, data.TileSizeX(0));
+ EXPECT_EQ(40, data.TileSizeX(1));
+ EXPECT_EQ(40, data.TileSizeX(2));
+ EXPECT_EQ(50, data.TileSizeX(3));
+ EXPECT_EQ(4, data.num_tiles_x());
+
+ EXPECT_EQ(50, data.TileSizeY(0));
+ EXPECT_EQ(20, data.TileSizeY(1));
+ EXPECT_EQ(20, data.TileSizeY(2));
+ EXPECT_EQ(20, data.TileSizeY(3));
+ EXPECT_EQ(35, data.TileSizeY(4));
+ EXPECT_EQ(5, data.num_tiles_y());
+
+ EXPECT_RECT_EQ(gfx::Rect(0, 0, 70, 50), data.TileBounds(0, 0));
+ EXPECT_RECT_EQ(gfx::Rect(70, 50, 40, 20), data.TileBounds(1, 1));
+ EXPECT_RECT_EQ(gfx::Rect(110, 110, 40, 35), data.TileBounds(2, 4));
+ EXPECT_RECT_EQ(gfx::Rect(150, 70, 50, 20), data.TileBounds(3, 2));
+ EXPECT_RECT_EQ(gfx::Rect(150, 110, 50, 35), data.TileBounds(3, 4));
+
+ EXPECT_RECT_EQ(gfx::Rect(0, 0, 100, 80), data.TileBoundsWithBorder(0, 0));
+ EXPECT_RECT_EQ(gfx::Rect(40, 20, 100, 80), data.TileBoundsWithBorder(1, 1));
+ EXPECT_RECT_EQ(gfx::Rect(80, 80, 100, 65), data.TileBoundsWithBorder(2, 4));
+ EXPECT_RECT_EQ(gfx::Rect(120, 40, 80, 80), data.TileBoundsWithBorder(3, 2));
+ EXPECT_RECT_EQ(gfx::Rect(120, 80, 80, 65), data.TileBoundsWithBorder(3, 4));
+
+ EXPECT_EQ(0, data.TileXIndexFromSrcCoord(0));
+ EXPECT_EQ(0, data.TileXIndexFromSrcCoord(69));
+ EXPECT_EQ(1, data.TileXIndexFromSrcCoord(70));
+ EXPECT_EQ(1, data.TileXIndexFromSrcCoord(109));
+ EXPECT_EQ(2, data.TileXIndexFromSrcCoord(110));
+ EXPECT_EQ(2, data.TileXIndexFromSrcCoord(149));
+ EXPECT_EQ(3, data.TileXIndexFromSrcCoord(150));
+ EXPECT_EQ(3, data.TileXIndexFromSrcCoord(199));
+
+ EXPECT_EQ(0, data.TileYIndexFromSrcCoord(0));
+ EXPECT_EQ(0, data.TileYIndexFromSrcCoord(49));
+ EXPECT_EQ(1, data.TileYIndexFromSrcCoord(50));
+ EXPECT_EQ(1, data.TileYIndexFromSrcCoord(69));
+ EXPECT_EQ(2, data.TileYIndexFromSrcCoord(70));
+ EXPECT_EQ(2, data.TileYIndexFromSrcCoord(89));
+ EXPECT_EQ(3, data.TileYIndexFromSrcCoord(90));
+ EXPECT_EQ(3, data.TileYIndexFromSrcCoord(109));
+ EXPECT_EQ(4, data.TileYIndexFromSrcCoord(110));
+ EXPECT_EQ(4, data.TileYIndexFromSrcCoord(144));
+
+ EXPECT_EQ(0, data.FirstBorderTileXIndexFromSrcCoord(0));
+ EXPECT_EQ(0, data.FirstBorderTileXIndexFromSrcCoord(99));
+ EXPECT_EQ(1, data.FirstBorderTileXIndexFromSrcCoord(100));
+ EXPECT_EQ(1, data.FirstBorderTileXIndexFromSrcCoord(139));
+ EXPECT_EQ(2, data.FirstBorderTileXIndexFromSrcCoord(140));
+ EXPECT_EQ(2, data.FirstBorderTileXIndexFromSrcCoord(179));
+ EXPECT_EQ(3, data.FirstBorderTileXIndexFromSrcCoord(180));
+ EXPECT_EQ(3, data.FirstBorderTileXIndexFromSrcCoord(199));
+
+ EXPECT_EQ(0, data.FirstBorderTileYIndexFromSrcCoord(0));
+ EXPECT_EQ(0, data.FirstBorderTileYIndexFromSrcCoord(79));
+ EXPECT_EQ(1, data.FirstBorderTileYIndexFromSrcCoord(80));
+ EXPECT_EQ(1, data.FirstBorderTileYIndexFromSrcCoord(99));
+ EXPECT_EQ(2, data.FirstBorderTileYIndexFromSrcCoord(100));
+ EXPECT_EQ(2, data.FirstBorderTileYIndexFromSrcCoord(119));
+ EXPECT_EQ(3, data.FirstBorderTileYIndexFromSrcCoord(120));
+ EXPECT_EQ(3, data.FirstBorderTileYIndexFromSrcCoord(139));
+ EXPECT_EQ(4, data.FirstBorderTileYIndexFromSrcCoord(140));
+ EXPECT_EQ(4, data.FirstBorderTileYIndexFromSrcCoord(144));
+
+ EXPECT_EQ(0, data.LastBorderTileXIndexFromSrcCoord(0));
+ EXPECT_EQ(0, data.LastBorderTileXIndexFromSrcCoord(39));
+ EXPECT_EQ(1, data.LastBorderTileXIndexFromSrcCoord(40));
+ EXPECT_EQ(1, data.LastBorderTileXIndexFromSrcCoord(79));
+ EXPECT_EQ(2, data.LastBorderTileXIndexFromSrcCoord(80));
+ EXPECT_EQ(2, data.LastBorderTileXIndexFromSrcCoord(119));
+ EXPECT_EQ(3, data.LastBorderTileXIndexFromSrcCoord(120));
+ EXPECT_EQ(3, data.LastBorderTileXIndexFromSrcCoord(199));
+
+ EXPECT_EQ(0, data.LastBorderTileYIndexFromSrcCoord(0));
+ EXPECT_EQ(0, data.LastBorderTileYIndexFromSrcCoord(19));
+ EXPECT_EQ(1, data.LastBorderTileYIndexFromSrcCoord(20));
+ EXPECT_EQ(1, data.LastBorderTileYIndexFromSrcCoord(39));
+ EXPECT_EQ(2, data.LastBorderTileYIndexFromSrcCoord(40));
+ EXPECT_EQ(2, data.LastBorderTileYIndexFromSrcCoord(59));
+ EXPECT_EQ(3, data.LastBorderTileYIndexFromSrcCoord(60));
+ EXPECT_EQ(3, data.LastBorderTileYIndexFromSrcCoord(79));
+ EXPECT_EQ(4, data.LastBorderTileYIndexFromSrcCoord(80));
+ EXPECT_EQ(4, data.LastBorderTileYIndexFromSrcCoord(144));
+}
+
+void TestIterate(
+ const TilingData& data,
+ gfx::Rect rect,
+ int expect_left,
+ int expect_top,
+ int expect_right,
+ int expect_bottom) {
+
+ EXPECT_GE(expect_left, 0);
+ EXPECT_GE(expect_top, 0);
+ EXPECT_LT(expect_right, data.num_tiles_x());
+ EXPECT_LT(expect_bottom, data.num_tiles_y());
+
+ std::vector<std::pair<int, int> > original_expected;
+ for (int x = 0; x < data.num_tiles_x(); ++x) {
+ for (int y = 0; y < data.num_tiles_y(); ++y) {
+ gfx::Rect bounds = data.TileBoundsWithBorder(x, y);
+ if (x >= expect_left && x <= expect_right &&
+ y >= expect_top && y <= expect_bottom) {
+ EXPECT_TRUE(bounds.Intersects(rect));
+ original_expected.push_back(std::make_pair(x, y));
+ } else {
+ EXPECT_FALSE(bounds.Intersects(rect));
+ }
+ }
+ }
+
+ // Verify with vanilla iterator.
+ {
+ std::vector<std::pair<int, int> > expected = original_expected;
+ for (TilingData::Iterator iter(&data, rect); iter; ++iter) {
+ bool found = false;
+ for (size_t i = 0; i < expected.size(); ++i) {
+ if (expected[i] == iter.index()) {
+ expected[i] = expected.back();
+ expected.pop_back();
+ found = true;
+ break;
+ }
+ }
+ EXPECT_TRUE(found);
+ }
+ EXPECT_EQ(0u, expected.size());
+ }
+
+ // Make sure this also works with a difference iterator and an empty ignore.
+ {
+ std::vector<std::pair<int, int> > expected = original_expected;
+ for (TilingData::DifferenceIterator iter(&data, rect, gfx::Rect());
+ iter; ++iter) {
+ bool found = false;
+ for (size_t i = 0; i < expected.size(); ++i) {
+ if (expected[i] == iter.index()) {
+ expected[i] = expected.back();
+ expected.pop_back();
+ found = true;
+ break;
+ }
+ }
+ EXPECT_TRUE(found);
+ }
+ EXPECT_EQ(0u, expected.size());
+ }
+}
+
+TEST(TilingDataTest, IteratorNoBorderTexels) {
+ TilingData data(gfx::Size(10, 10), gfx::Size(40, 25), false);
+ // X border index by src coord: [0-10), [10-20), [20, 30), [30, 40)
+ // Y border index by src coord: [0-10), [10-20), [20, 25)
+ TestIterate(data, gfx::Rect(0, 0, 40, 25), 0, 0, 3, 2);
+ TestIterate(data, gfx::Rect(15, 15, 8, 8), 1, 1, 2, 2);
+
+ // Oversized.
+ TestIterate(data, gfx::Rect(-100, -100, 1000, 1000), 0, 0, 3, 2);
+ TestIterate(data, gfx::Rect(-100, 20, 1000, 1), 0, 2, 3, 2);
+ TestIterate(data, gfx::Rect(29, -100, 31, 1000), 2, 0, 3, 2);
+ // Nonintersecting.
+ TestIterate(data, gfx::Rect(60, 80, 100, 100), 0, 0, -1, -1);
+}
+
+TEST(TilingDataTest, IteratorOneBorderTexel) {
+ TilingData data(gfx::Size(10, 20), gfx::Size(25, 45), true);
+ // X border index by src coord: [0-10), [8-18), [16-25)
+ // Y border index by src coord: [0-20), [18-38), [36-45)
+ TestIterate(data, gfx::Rect(0, 0, 25, 45), 0, 0, 2, 2);
+ TestIterate(data, gfx::Rect(18, 19, 3, 17), 2, 0, 2, 1);
+ TestIterate(data, gfx::Rect(10, 20, 6, 16), 1, 1, 1, 1);
+ TestIterate(data, gfx::Rect(9, 19, 8, 18), 0, 0, 2, 2);
+
+ // Oversized.
+ TestIterate(data, gfx::Rect(-100, -100, 1000, 1000), 0, 0, 2, 2);
+ TestIterate(data, gfx::Rect(-100, 20, 1000, 1), 0, 1, 2, 1);
+ TestIterate(data, gfx::Rect(18, -100, 6, 1000), 2, 0, 2, 2);
+ // Nonintersecting.
+ TestIterate(data, gfx::Rect(60, 80, 100, 100), 0, 0, -1, -1);
+}
+
+TEST(TilingDataTest, IteratorManyBorderTexels) {
+ TilingData data(gfx::Size(50, 60), gfx::Size(65, 110), 20);
+ // X border index by src coord: [0-50), [10-60), [20-65)
+ // Y border index by src coord: [0-60), [20-80), [40-100), [60-110)
+ TestIterate(data, gfx::Rect(0, 0, 65, 110), 0, 0, 2, 3);
+ TestIterate(data, gfx::Rect(50, 60, 15, 65), 1, 1, 2, 3);
+ TestIterate(data, gfx::Rect(60, 30, 2, 10), 2, 0, 2, 1);
+
+ // Oversized.
+ TestIterate(data, gfx::Rect(-100, -100, 1000, 1000), 0, 0, 2, 3);
+ TestIterate(data, gfx::Rect(-100, 10, 1000, 10), 0, 0, 2, 0);
+ TestIterate(data, gfx::Rect(10, -100, 10, 1000), 0, 0, 1, 3);
+ // Nonintersecting.
+ TestIterate(data, gfx::Rect(65, 110, 100, 100), 0, 0, -1, -1);
+}
+
+TEST(TilingDataTest, IteratorOneTile) {
+ TilingData no_border(gfx::Size(1000, 1000), gfx::Size(30, 40), false);
+ TestIterate(no_border, gfx::Rect(0, 0, 30, 40), 0, 0, 0, 0);
+ TestIterate(no_border, gfx::Rect(10, 10, 20, 20), 0, 0, 0, 0);
+ TestIterate(no_border, gfx::Rect(30, 40, 100, 100), 0, 0, -1, -1);
+
+ TilingData one_border(gfx::Size(1000, 1000), gfx::Size(30, 40), true);
+ TestIterate(one_border, gfx::Rect(0, 0, 30, 40), 0, 0, 0, 0);
+ TestIterate(one_border, gfx::Rect(10, 10, 20, 20), 0, 0, 0, 0);
+ TestIterate(one_border, gfx::Rect(30, 40, 100, 100), 0, 0, -1, -1);
+
+ TilingData big_border(gfx::Size(1000, 1000), gfx::Size(30, 40), 50);
+ TestIterate(big_border, gfx::Rect(0, 0, 30, 40), 0, 0, 0, 0);
+ TestIterate(big_border, gfx::Rect(10, 10, 20, 20), 0, 0, 0, 0);
+ TestIterate(big_border, gfx::Rect(30, 40, 100, 100), 0, 0, -1, -1);
+}
+
+TEST(TilingDataTest, IteratorNoTiles) {
+ TilingData data(gfx::Size(100, 100), gfx::Size(), false);
+ TestIterate(data, gfx::Rect(0, 0, 100, 100), 0, 0, -1, -1);
+}
+
+void TestDiff(
+ const TilingData& data,
+ gfx::Rect consider,
+ gfx::Rect ignore,
+ size_t num_tiles) {
+
+ std::vector<std::pair<int, int> > expected;
+ for (int y = 0; y < data.num_tiles_y(); ++y) {
+ for (int x = 0; x < data.num_tiles_x(); ++x) {
+ gfx::Rect bounds = data.TileBoundsWithBorder(x, y);
+ if (bounds.Intersects(consider) && !bounds.Intersects(ignore))
+ expected.push_back(std::make_pair(x, y));
+ }
+ }
+
+ // Sanity check the test.
+ EXPECT_EQ(num_tiles, expected.size());
+
+ for (TilingData::DifferenceIterator iter(&data, consider, ignore);
+ iter; ++iter) {
+ bool found = false;
+ for (size_t i = 0; i < expected.size(); ++i) {
+ if (expected[i] == iter.index()) {
+ expected[i] = expected.back();
+ expected.pop_back();
+ found = true;
+ break;
+ }
+ }
+ EXPECT_TRUE(found);
+ }
+ EXPECT_EQ(0u, expected.size());
+}
+
+TEST(TilingDataTest, DifferenceIteratorIgnoreGeometry) {
+ // This test is checking that the iterator can handle different geometries of
+ // ignore rects relative to the consider rect. The consider rect indices
+ // themselves are mostly tested by the non-difference iterator tests, so the
+ // full rect is mostly used here for simplicity.
+
+ // X border index by src coord: [0-10), [10-20), [20, 30), [30, 40)
+ // Y border index by src coord: [0-10), [10-20), [20, 25)
+ TilingData data(gfx::Size(10, 10), gfx::Size(40, 25), false);
+
+ // Fully ignored
+ TestDiff(data, gfx::Rect(0, 0, 40, 25), gfx::Rect(0, 0, 40, 25), 0);
+ TestDiff(data, gfx::Rect(0, 0, 40, 25), gfx::Rect(-100, -100, 200, 200), 0);
+ TestDiff(data, gfx::Rect(0, 0, 40, 25), gfx::Rect(9, 9, 30, 15), 0);
+ TestDiff(data, gfx::Rect(15, 15, 8, 8), gfx::Rect(15, 15, 8, 8), 0);
+
+ // Fully un-ignored
+ TestDiff(data, gfx::Rect(0, 0, 40, 25), gfx::Rect(-30, -20, 8, 8), 12);
+ TestDiff(data, gfx::Rect(0, 0, 40, 25), gfx::Rect(), 12);
+
+ // Top left, remove 2x2 tiles
+ TestDiff(data, gfx::Rect(0, 0, 40, 25), gfx::Rect(0, 0, 20, 19), 8);
+ // Bottom right, remove 2x2 tiles
+ TestDiff(data, gfx::Rect(0, 0, 40, 25), gfx::Rect(20, 15, 20, 6), 8);
+ // Bottom left, remove 2x2 tiles
+ TestDiff(data, gfx::Rect(0, 0, 40, 25), gfx::Rect(0, 15, 20, 6), 8);
+ // Top right, remove 2x2 tiles
+ TestDiff(data, gfx::Rect(0, 0, 40, 25), gfx::Rect(20, 0, 20, 19), 8);
+ // Center, remove only one tile
+ TestDiff(data, gfx::Rect(0, 0, 40, 25), gfx::Rect(10, 10, 5, 5), 11);
+
+ // Left column, flush left, removing two columns
+ TestDiff(data, gfx::Rect(0, 0, 40, 25), gfx::Rect(0, 0, 11, 25), 6);
+ // Middle column, removing two columns
+ TestDiff(data, gfx::Rect(0, 0, 40, 25), gfx::Rect(11, 0, 11, 25), 6);
+ // Right column, flush right, removing one column
+ TestDiff(data, gfx::Rect(0, 0, 40, 25), gfx::Rect(30, 0, 2, 25), 9);
+
+ // Top row, flush top, removing one row
+ TestDiff(data, gfx::Rect(0, 0, 40, 25), gfx::Rect(0, 5, 40, 5), 8);
+ // Middle row, removing one row
+ TestDiff(data, gfx::Rect(0, 0, 40, 25), gfx::Rect(0, 13, 40, 5), 8);
+ // Bottom row, flush bottom, removing two rows
+ TestDiff(data, gfx::Rect(0, 0, 40, 25), gfx::Rect(0, 13, 40, 12), 4);
+
+ // Non-intersecting, but still touching two of the same tiles.
+ TestDiff(data, gfx::Rect(8, 0, 32, 25), gfx::Rect(0, 12, 5, 12), 10);
+
+ // Intersecting, but neither contains the other. 2x3 with one overlap.
+ TestDiff(data, gfx::Rect(5, 2, 20, 10), gfx::Rect(25, 15, 5, 10), 5);
+}
+
+TEST(TilingDataTest, DifferenceIteratorManyBorderTexels) {
+ // X border index by src coord: [0-50), [10-60), [20-65)
+ // Y border index by src coord: [0-60), [20-80), [40-100), [60-110)
+ TilingData data(gfx::Size(50, 60), gfx::Size(65, 110), 20);
+
+ // Ignore one column, three rows
+ TestDiff(data, gfx::Rect(0, 30, 55, 80), gfx::Rect(5, 30, 5, 15), 9);
+
+ // Knock out three columns, leaving only one.
+ TestDiff(data, gfx::Rect(10, 30, 55, 80), gfx::Rect(30, 59, 20, 1), 3);
+
+ // Overlap all tiles with ignore rect.
+ TestDiff(data, gfx::Rect(0, 0, 65, 110), gfx::Rect(30, 59, 1, 2), 0);
+}
+
+TEST(TilingDataTest, DifferenceIteratorOneTile) {
+ TilingData no_border(gfx::Size(1000, 1000), gfx::Size(30, 40), false);
+ TestDiff(no_border, gfx::Rect(0, 0, 30, 40), gfx::Rect(), 1);
+ TestDiff(no_border, gfx::Rect(5, 5, 100, 100), gfx::Rect(5, 5, 1, 1), 0);
+
+ TilingData one_border(gfx::Size(1000, 1000), gfx::Size(30, 40), true);
+ TestDiff(one_border, gfx::Rect(0, 0, 30, 40), gfx::Rect(), 1);
+ TestDiff(one_border, gfx::Rect(5, 5, 100, 100), gfx::Rect(5, 5, 1, 1), 0);
+
+ TilingData big_border(gfx::Size(1000, 1000), gfx::Size(30, 40), 50);
+ TestDiff(big_border, gfx::Rect(0, 0, 30, 40), gfx::Rect(), 1);
+ TestDiff(big_border, gfx::Rect(5, 5, 100, 100), gfx::Rect(5, 5, 1, 1), 0);
+}
+
+TEST(TilingDataTest, DifferenceIteratorNoTiles) {
+ TilingData data(gfx::Size(100, 100), gfx::Size(), false);
+ TestDiff(data, gfx::Rect(0, 0, 100, 100), gfx::Rect(0, 0, 5, 5), 0);
+}
+
+} // namespace
+} // namespace cc
diff --git a/chromium/cc/base/util.h b/chromium/cc/base/util.h
new file mode 100644
index 00000000000..1d716ae2a42
--- /dev/null
+++ b/chromium/cc/base/util.h
@@ -0,0 +1,29 @@
+// Copyright 2012 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.
+
+#ifndef CC_BASE_UTIL_H_
+#define CC_BASE_UTIL_H_
+
+#include <limits>
+
+#include "base/basictypes.h"
+
+namespace cc {
+
+template <typename T> T RoundUp(T n, T mul) {
+ COMPILE_ASSERT(std::numeric_limits<T>::is_integer, type_must_be_integral);
+ return (n > 0) ? ((n + mul - 1) / mul) * mul
+ : (n / mul) * mul;
+}
+
+template <typename T> T RoundDown(T n, T mul) {
+ COMPILE_ASSERT(std::numeric_limits<T>::is_integer, type_must_be_integral);
+ return (n > 0) ? (n / mul) * mul
+ : (n == 0) ? 0
+ : ((n - mul + 1) / mul) * mul;
+}
+
+} // namespace cc
+
+#endif // CC_BASE_UTIL_H_
diff --git a/chromium/cc/base/util_unittest.cc b/chromium/cc/base/util_unittest.cc
new file mode 100644
index 00000000000..6665a6a458d
--- /dev/null
+++ b/chromium/cc/base/util_unittest.cc
@@ -0,0 +1,67 @@
+// Copyright 2013 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 "cc/base/util.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace cc {
+namespace {
+
+TEST(UtilTest, RoundUp) {
+ for (int multiplier = 1; multiplier <= 10; ++multiplier) {
+ // Try attempts in descending order, so that we can
+ // determine the correct value before it's needed.
+ int correct;
+ for (int attempt = 5 * multiplier; attempt >= -5 * multiplier; --attempt) {
+ if ((attempt % multiplier) == 0)
+ correct = attempt;
+ EXPECT_EQ(correct, RoundUp(attempt, multiplier))
+ << "attempt=" << attempt << " multiplier=" << multiplier;
+ }
+ }
+
+ for (unsigned multiplier = 1; multiplier <= 10; ++multiplier) {
+ // Try attempts in descending order, so that we can
+ // determine the correct value before it's needed.
+ unsigned correct;
+ for (unsigned attempt = 5 * multiplier; attempt > 0; --attempt) {
+ if ((attempt % multiplier) == 0)
+ correct = attempt;
+ EXPECT_EQ(correct, RoundUp(attempt, multiplier))
+ << "attempt=" << attempt << " multiplier=" << multiplier;
+ }
+ EXPECT_EQ(0u, RoundUp(0u, multiplier))
+ << "attempt=0 multiplier=" << multiplier;
+ }
+}
+
+TEST(UtilTest, RoundDown) {
+ for (int multiplier = 1; multiplier <= 10; ++multiplier) {
+ // Try attempts in ascending order, so that we can
+ // determine the correct value before it's needed.
+ int correct;
+ for (int attempt = -5 * multiplier; attempt <= 5 * multiplier; ++attempt) {
+ if ((attempt % multiplier) == 0)
+ correct = attempt;
+ EXPECT_EQ(correct, RoundDown(attempt, multiplier))
+ << "attempt=" << attempt << " multiplier=" << multiplier;
+ }
+ }
+
+ for (unsigned multiplier = 1; multiplier <= 10; ++multiplier) {
+ // Try attempts in ascending order, so that we can
+ // determine the correct value before it's needed.
+ unsigned correct;
+ for (unsigned attempt = 0; attempt <= 5 * multiplier; ++attempt) {
+ if ((attempt % multiplier) == 0)
+ correct = attempt;
+ EXPECT_EQ(correct, RoundDown(attempt, multiplier))
+ << "attempt=" << attempt << " multiplier=" << multiplier;
+ }
+ }
+}
+
+} // namespace
+} // namespace cc