summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordanakj <danakj@chromium.org>2014-08-25 16:36:47 -0700
committerCommit bot <commit-bot@chromium.org>2014-08-25 23:39:37 +0000
commitc8357ff51ba8458cc04848fa4ec4452d2660b160 (patch)
tree8134ae00fa47b848c6e917f70f7aced7ea400d9d
parent38c3ae72c9743dbe172779477917bf24bc25ab97 (diff)
downloadchromium_src-c8357ff51ba8458cc04848fa4ec4452d2660b160.zip
chromium_src-c8357ff51ba8458cc04848fa4ec4452d2660b160.tar.gz
chromium_src-c8357ff51ba8458cc04848fa4ec4452d2660b160.tar.bz2
cc: Stop converting Rect to QuadF to map to an enclosed rect.
Occlusion tracker converts Rects to QuadF, then does MapClippedQuad, then BoundingBox(), then ToEnclosedRect(). Instead, add methods to MathUtil that mirror the {Map,Project}EnclosingClippedRect methods but for an enclosed rect instead, that work only when the transform preserves 2d axis alignment. In the common case, this avoids converting the integers to floats just to convert back to ints using the costly safe conversion methods. R=enne Review URL: https://codereview.chromium.org/495873002 Cr-Commit-Position: refs/heads/master@{#291785}
-rw-r--r--cc/base/math_util.cc73
-rw-r--r--cc/base/math_util.h6
-rw-r--r--cc/base/math_util_unittest.cc73
-rw-r--r--cc/trees/occlusion_tracker.cc25
4 files changed, 138 insertions, 39 deletions
diff --git a/cc/base/math_util.cc b/cc/base/math_util.cc
index 7f6178d..5b01da9 100644
--- a/cc/base/math_util.cc
+++ b/cc/base/math_util.cc
@@ -121,11 +121,9 @@ static inline void AddVertexToClippedQuad3d(const gfx::Point3F& new_vertex,
gfx::Rect MathUtil::MapEnclosingClippedRect(const gfx::Transform& transform,
const gfx::Rect& src_rect) {
if (transform.IsIdentityOrIntegerTranslation()) {
- return src_rect +
- gfx::Vector2d(
- static_cast<int>(SkMScalarToFloat(transform.matrix().get(0, 3))),
- static_cast<int>(
- SkMScalarToFloat(transform.matrix().get(1, 3))));
+ gfx::Vector2d offset(static_cast<int>(transform.matrix().getFloat(0, 3)),
+ static_cast<int>(transform.matrix().getFloat(1, 3)));
+ return src_rect + offset;
}
return gfx::ToEnclosingRect(MapClippedRect(transform, gfx::RectF(src_rect)));
}
@@ -133,9 +131,9 @@ gfx::Rect MathUtil::MapEnclosingClippedRect(const gfx::Transform& transform,
gfx::RectF MathUtil::MapClippedRect(const gfx::Transform& transform,
const gfx::RectF& src_rect) {
if (transform.IsIdentityOrTranslation()) {
- return src_rect +
- gfx::Vector2dF(SkMScalarToFloat(transform.matrix().get(0, 3)),
- SkMScalarToFloat(transform.matrix().get(1, 3)));
+ gfx::Vector2dF offset(transform.matrix().getFloat(0, 3),
+ transform.matrix().getFloat(1, 3));
+ return src_rect + offset;
}
// Apply the transform, but retain the result in homogeneous coordinates.
@@ -163,11 +161,9 @@ gfx::RectF MathUtil::MapClippedRect(const gfx::Transform& transform,
gfx::Rect MathUtil::ProjectEnclosingClippedRect(const gfx::Transform& transform,
const gfx::Rect& src_rect) {
if (transform.IsIdentityOrIntegerTranslation()) {
- return src_rect +
- gfx::Vector2d(
- static_cast<int>(SkMScalarToFloat(transform.matrix().get(0, 3))),
- static_cast<int>(
- SkMScalarToFloat(transform.matrix().get(1, 3))));
+ gfx::Vector2d offset(static_cast<int>(transform.matrix().getFloat(0, 3)),
+ static_cast<int>(transform.matrix().getFloat(1, 3)));
+ return src_rect + offset;
}
return gfx::ToEnclosingRect(
ProjectClippedRect(transform, gfx::RectF(src_rect)));
@@ -176,9 +172,9 @@ gfx::Rect MathUtil::ProjectEnclosingClippedRect(const gfx::Transform& transform,
gfx::RectF MathUtil::ProjectClippedRect(const gfx::Transform& transform,
const gfx::RectF& src_rect) {
if (transform.IsIdentityOrTranslation()) {
- return src_rect +
- gfx::Vector2dF(SkMScalarToFloat(transform.matrix().get(0, 3)),
- SkMScalarToFloat(transform.matrix().get(1, 3)));
+ gfx::Vector2dF offset(transform.matrix().getFloat(0, 3),
+ transform.matrix().getFloat(1, 3));
+ return src_rect + offset;
}
// Perform the projection, but retain the result in homogeneous coordinates.
@@ -191,6 +187,41 @@ gfx::RectF MathUtil::ProjectClippedRect(const gfx::Transform& transform,
return ComputeEnclosingClippedRect(h1, h2, h3, h4);
}
+gfx::Rect MathUtil::MapEnclosedRectWith2dAxisAlignedTransform(
+ const gfx::Transform& transform,
+ const gfx::Rect& rect) {
+ DCHECK(transform.Preserves2dAxisAlignment());
+
+ if (transform.IsIdentityOrIntegerTranslation()) {
+ gfx::Vector2d offset(static_cast<int>(transform.matrix().getFloat(0, 3)),
+ static_cast<int>(transform.matrix().getFloat(1, 3)));
+ return rect + offset;
+ }
+ if (transform.IsIdentityOrTranslation()) {
+ gfx::Vector2dF offset(transform.matrix().getFloat(0, 3),
+ transform.matrix().getFloat(1, 3));
+ return gfx::ToEnclosedRect(rect + offset);
+ }
+
+ SkMScalar quad[2 * 2]; // input: 2 x 2D points
+ quad[0] = rect.x();
+ quad[1] = rect.y();
+ quad[2] = rect.right();
+ quad[3] = rect.bottom();
+
+ SkMScalar result[4 * 2]; // output: 2 x 4D homogeneous points
+ transform.matrix().map2(quad, 2, result);
+
+ HomogeneousCoordinate hc0(result[0], result[1], result[2], result[3]);
+ HomogeneousCoordinate hc1(result[4], result[5], result[6], result[7]);
+ DCHECK(!hc0.ShouldBeClipped());
+ DCHECK(!hc1.ShouldBeClipped());
+
+ gfx::PointF top_left(hc0.CartesianPoint2d());
+ gfx::PointF bottom_right(hc1.CartesianPoint2d());
+ return gfx::ToEnclosedRect(gfx::BoundingRect(top_left, bottom_right));
+}
+
void MathUtil::MapClippedQuad(const gfx::Transform& transform,
const gfx::QuadF& src_quad,
gfx::PointF clipped_quad[8],
@@ -436,9 +467,8 @@ gfx::QuadF MathUtil::MapQuad(const gfx::Transform& transform,
bool* clipped) {
if (transform.IsIdentityOrTranslation()) {
gfx::QuadF mapped_quad(q);
- mapped_quad +=
- gfx::Vector2dF(SkMScalarToFloat(transform.matrix().get(0, 3)),
- SkMScalarToFloat(transform.matrix().get(1, 3)));
+ mapped_quad += gfx::Vector2dF(transform.matrix().getFloat(0, 3),
+ transform.matrix().getFloat(1, 3));
*clipped = false;
return mapped_quad;
}
@@ -469,9 +499,8 @@ gfx::QuadF MathUtil::MapQuad3d(const gfx::Transform& transform,
bool* clipped) {
if (transform.IsIdentityOrTranslation()) {
gfx::QuadF mapped_quad(q);
- mapped_quad +=
- gfx::Vector2dF(SkMScalarToFloat(transform.matrix().get(0, 3)),
- SkMScalarToFloat(transform.matrix().get(1, 3)));
+ mapped_quad += gfx::Vector2dF(transform.matrix().getFloat(0, 3),
+ transform.matrix().getFloat(1, 3));
*clipped = false;
p[0] = gfx::Point3F(mapped_quad.p1().x(), mapped_quad.p1().y(), 0.0f);
p[1] = gfx::Point3F(mapped_quad.p2().x(), mapped_quad.p2().y(), 0.0f);
diff --git a/cc/base/math_util.h b/cc/base/math_util.h
index 486a654..eaaf924 100644
--- a/cc/base/math_util.h
+++ b/cc/base/math_util.h
@@ -115,6 +115,12 @@ class CC_EXPORT MathUtil {
static gfx::RectF ProjectClippedRect(const gfx::Transform& transform,
const gfx::RectF& rect);
+ // This function is only valid when the transform preserves 2d axis
+ // alignment and the resulting rect will not be clipped.
+ static gfx::Rect MapEnclosedRectWith2dAxisAlignedTransform(
+ const gfx::Transform& transform,
+ const gfx::Rect& 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,
diff --git a/cc/base/math_util_unittest.cc b/cc/base/math_util_unittest.cc
index 6e276c2..fb8c27f 100644
--- a/cc/base/math_util_unittest.cc
+++ b/cc/base/math_util_unittest.cc
@@ -120,5 +120,78 @@ TEST(MathUtilTest, VectorProjection) {
projected_vector.y() / target_vector.y());
}
+TEST(MathUtilTest, MapEnclosedRectWith2dAxisAlignedTransform) {
+ gfx::Rect input(1, 2, 3, 4);
+ gfx::Rect output;
+ gfx::Transform transform;
+
+ // Identity.
+ output =
+ MathUtil::MapEnclosedRectWith2dAxisAlignedTransform(transform, input);
+ EXPECT_EQ(input, output);
+
+ // Integer translate.
+ transform.Translate(2.0, 3.0);
+ output =
+ MathUtil::MapEnclosedRectWith2dAxisAlignedTransform(transform, input);
+ EXPECT_EQ(gfx::Rect(3, 5, 3, 4), output);
+
+ // Non-integer translate.
+ transform.Translate(0.5, 0.5);
+ output =
+ MathUtil::MapEnclosedRectWith2dAxisAlignedTransform(transform, input);
+ EXPECT_EQ(gfx::Rect(4, 6, 2, 3), output);
+
+ // Scale.
+ transform = gfx::Transform();
+ transform.Scale(2.0, 3.0);
+ output =
+ MathUtil::MapEnclosedRectWith2dAxisAlignedTransform(transform, input);
+ EXPECT_EQ(gfx::Rect(2, 6, 6, 12), output);
+
+ // Rotate Z.
+ transform = gfx::Transform();
+ transform.Translate(1.0, 2.0);
+ transform.RotateAboutZAxis(90.0);
+ transform.Translate(-1.0, -2.0);
+ output =
+ MathUtil::MapEnclosedRectWith2dAxisAlignedTransform(transform, input);
+ EXPECT_EQ(gfx::Rect(-3, 2, 4, 3), output);
+
+ // Rotate X.
+ transform = gfx::Transform();
+ transform.RotateAboutXAxis(90.0);
+ output =
+ MathUtil::MapEnclosedRectWith2dAxisAlignedTransform(transform, input);
+ EXPECT_TRUE(output.IsEmpty());
+
+ transform = gfx::Transform();
+ transform.RotateAboutXAxis(180.0);
+ output =
+ MathUtil::MapEnclosedRectWith2dAxisAlignedTransform(transform, input);
+ EXPECT_EQ(gfx::Rect(1, -6, 3, 4), output);
+
+ // Rotate Y.
+ transform = gfx::Transform();
+ transform.RotateAboutYAxis(90.0);
+ output =
+ MathUtil::MapEnclosedRectWith2dAxisAlignedTransform(transform, input);
+ EXPECT_TRUE(output.IsEmpty());
+
+ transform = gfx::Transform();
+ transform.RotateAboutYAxis(180.0);
+ output =
+ MathUtil::MapEnclosedRectWith2dAxisAlignedTransform(transform, input);
+ EXPECT_EQ(gfx::Rect(-4, 2, 3, 4), output);
+
+ // Translate Z.
+ transform = gfx::Transform();
+ transform.ApplyPerspectiveDepth(10.0);
+ transform.Translate3d(0.0, 0.0, 5.0);
+ output =
+ MathUtil::MapEnclosedRectWith2dAxisAlignedTransform(transform, input);
+ EXPECT_EQ(gfx::Rect(2, 4, 6, 8), output);
+}
+
} // namespace
} // namespace cc
diff --git a/cc/trees/occlusion_tracker.cc b/cc/trees/occlusion_tracker.cc
index d68633b..f233e07 100644
--- a/cc/trees/occlusion_tracker.cc
+++ b/cc/trees/occlusion_tracker.cc
@@ -84,12 +84,9 @@ static SimpleEnclosedRegion TransformSurfaceOpaqueRegion(
SimpleEnclosedRegion transformed_region;
for (size_t i = 0; i < region.GetRegionComplexity(); ++i) {
- bool clipped;
- gfx::QuadF transformed_quad =
- MathUtil::MapQuad(transform, gfx::QuadF(region.GetRect(i)), &clipped);
gfx::Rect transformed_rect =
- gfx::ToEnclosedRect(transformed_quad.BoundingBox());
- DCHECK(!clipped); // We only map if the transform preserves axis alignment.
+ MathUtil::MapEnclosedRectWith2dAxisAlignedTransform(transform,
+ region.GetRect(i));
if (have_clip_rect)
transformed_rect.Intersect(clip_rect_in_new_target);
transformed_region.Union(transformed_rect);
@@ -432,14 +429,9 @@ void OcclusionTracker<LayerType>::MarkOccludedBehindLayer(
}
for (size_t i = 0; i < opaque_contents.GetRegionComplexity(); ++i) {
- bool clipped;
- gfx::QuadF transformed_quad =
- MathUtil::MapQuad(layer->draw_transform(),
- gfx::QuadF(opaque_contents.GetRect(i)),
- &clipped);
gfx::Rect transformed_rect =
- gfx::ToEnclosedRect(transformed_quad.BoundingBox());
- DCHECK(!clipped); // We only map if the transform preserves axis alignment.
+ MathUtil::MapEnclosedRectWith2dAxisAlignedTransform(
+ layer->draw_transform(), opaque_contents.GetRect(i));
transformed_rect.Intersect(clip_rect_in_target);
if (transformed_rect.width() < minimum_tracking_size_.width() &&
transformed_rect.height() < minimum_tracking_size_.height())
@@ -450,6 +442,7 @@ void OcclusionTracker<LayerType>::MarkOccludedBehindLayer(
continue;
// Save the occluding area in screen space for debug visualization.
+ bool clipped;
gfx::QuadF screen_space_quad = MathUtil::MapQuad(
layer->render_target()->render_surface()->screen_space_transform(),
gfx::QuadF(transformed_rect), &clipped);
@@ -469,11 +462,9 @@ void OcclusionTracker<LayerType>::MarkOccludedBehindLayer(
for (Region::Iterator non_opaque_content_rects(non_opaque_contents);
non_opaque_content_rects.has_rect();
non_opaque_content_rects.next()) {
- // We've already checked for clipping in the MapQuad call above, these calls
- // should not clip anything further.
- gfx::Rect transformed_rect = gfx::ToEnclosedRect(
- MathUtil::MapClippedRect(layer->draw_transform(),
- gfx::RectF(non_opaque_content_rects.rect())));
+ gfx::Rect transformed_rect =
+ MathUtil::MapEnclosedRectWith2dAxisAlignedTransform(
+ layer->draw_transform(), non_opaque_content_rects.rect());
transformed_rect.Intersect(clip_rect_in_target);
if (transformed_rect.IsEmpty())
continue;