diff options
author | danakj <danakj@chromium.org> | 2014-08-25 16:36:47 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2014-08-25 23:39:37 +0000 |
commit | c8357ff51ba8458cc04848fa4ec4452d2660b160 (patch) | |
tree | 8134ae00fa47b848c6e917f70f7aced7ea400d9d | |
parent | 38c3ae72c9743dbe172779477917bf24bc25ab97 (diff) | |
download | chromium_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.cc | 73 | ||||
-rw-r--r-- | cc/base/math_util.h | 6 | ||||
-rw-r--r-- | cc/base/math_util_unittest.cc | 73 | ||||
-rw-r--r-- | cc/trees/occlusion_tracker.cc | 25 |
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; |