Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / cc / base / math_util.cc
index b492404..5b01da9 100644 (file)
@@ -8,6 +8,7 @@
 #include <cmath>
 #include <limits>
 
+#include "base/debug/trace_event_argument.h"
 #include "base/values.h"
 #include "ui/gfx/quad_f.h"
 #include "ui/gfx/rect.h"
@@ -41,6 +42,15 @@ static HomogeneousCoordinate ProjectHomogeneousPoint(
   return result;
 }
 
+static HomogeneousCoordinate ProjectHomogeneousPoint(
+    const gfx::Transform& transform,
+    const gfx::PointF& p,
+    bool* clipped) {
+  HomogeneousCoordinate h = ProjectHomogeneousPoint(transform, p);
+  *clipped = h.w() <= 0;
+  return h;
+}
+
 static HomogeneousCoordinate MapHomogeneousPoint(
     const gfx::Transform& transform,
     const gfx::Point3F& p) {
@@ -101,14 +111,19 @@ static inline void AddVertexToClippedQuad(const gfx::PointF& new_vertex,
   (*num_vertices_in_clipped_quad)++;
 }
 
+static inline void AddVertexToClippedQuad3d(const gfx::Point3F& new_vertex,
+                                            gfx::Point3F 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::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)));
 }
@@ -116,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.
@@ -146,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)));
@@ -159,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.
@@ -174,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],
@@ -243,6 +291,76 @@ void MathUtil::MapClippedQuad(const gfx::Transform& transform,
   DCHECK_LE(*num_vertices_in_clipped_quad, 8);
 }
 
+bool MathUtil::MapClippedQuad3d(const gfx::Transform& transform,
+                                const gfx::QuadF& src_quad,
+                                gfx::Point3F 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()) {
+    AddVertexToClippedQuad3d(
+        h1.CartesianPoint3d(), clipped_quad, num_vertices_in_clipped_quad);
+  }
+
+  if (h1.ShouldBeClipped() ^ h2.ShouldBeClipped()) {
+    AddVertexToClippedQuad3d(
+        ComputeClippedPointForEdge(h1, h2).CartesianPoint3d(),
+        clipped_quad,
+        num_vertices_in_clipped_quad);
+  }
+
+  if (!h2.ShouldBeClipped()) {
+    AddVertexToClippedQuad3d(
+        h2.CartesianPoint3d(), clipped_quad, num_vertices_in_clipped_quad);
+  }
+
+  if (h2.ShouldBeClipped() ^ h3.ShouldBeClipped()) {
+    AddVertexToClippedQuad3d(
+        ComputeClippedPointForEdge(h2, h3).CartesianPoint3d(),
+        clipped_quad,
+        num_vertices_in_clipped_quad);
+  }
+
+  if (!h3.ShouldBeClipped()) {
+    AddVertexToClippedQuad3d(
+        h3.CartesianPoint3d(), clipped_quad, num_vertices_in_clipped_quad);
+  }
+
+  if (h3.ShouldBeClipped() ^ h4.ShouldBeClipped()) {
+    AddVertexToClippedQuad3d(
+        ComputeClippedPointForEdge(h3, h4).CartesianPoint3d(),
+        clipped_quad,
+        num_vertices_in_clipped_quad);
+  }
+
+  if (!h4.ShouldBeClipped()) {
+    AddVertexToClippedQuad3d(
+        h4.CartesianPoint3d(), clipped_quad, num_vertices_in_clipped_quad);
+  }
+
+  if (h4.ShouldBeClipped() ^ h1.ShouldBeClipped()) {
+    AddVertexToClippedQuad3d(
+        ComputeClippedPointForEdge(h4, h1).CartesianPoint3d(),
+        clipped_quad,
+        num_vertices_in_clipped_quad);
+  }
+
+  DCHECK_LE(*num_vertices_in_clipped_quad, 8);
+  return (*num_vertices_in_clipped_quad >= 4);
+}
+
 gfx::RectF MathUtil::ComputeEnclosingRectOfVertices(
     const gfx::PointF vertices[],
     int num_vertices) {
@@ -349,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;
   }
@@ -376,6 +493,47 @@ gfx::QuadF MathUtil::MapQuad(const gfx::Transform& transform,
                     h4.CartesianPoint2d());
 }
 
+gfx::QuadF MathUtil::MapQuad3d(const gfx::Transform& transform,
+                               const gfx::QuadF& q,
+                               gfx::Point3F* p,
+                               bool* clipped) {
+  if (transform.IsIdentityOrTranslation()) {
+    gfx::QuadF mapped_quad(q);
+    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);
+    p[2] = gfx::Point3F(mapped_quad.p3().x(), mapped_quad.p3().y(), 0.0f);
+    p[3] = gfx::Point3F(mapped_quad.p4().x(), mapped_quad.p4().y(), 0.0f);
+    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.
+  p[0] = h1.CartesianPoint3d();
+  p[1] = h2.CartesianPoint3d();
+  p[2] = h3.CartesianPoint3d();
+  p[3] = h4.CartesianPoint3d();
+
+  return gfx::QuadF(h1.CartesianPoint2d(),
+                    h2.CartesianPoint2d(),
+                    h3.CartesianPoint2d(),
+                    h4.CartesianPoint2d());
+}
+
 gfx::PointF MathUtil::MapPoint(const gfx::Transform& transform,
                                const gfx::PointF& p,
                                bool* clipped) {
@@ -444,28 +602,27 @@ gfx::QuadF MathUtil::ProjectQuad(const gfx::Transform& transform,
 gfx::PointF MathUtil::ProjectPoint(const gfx::Transform& transform,
                                    const 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;
-
+  HomogeneousCoordinate h = ProjectHomogeneousPoint(transform, p, clipped);
   // 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 return value will be invalid if 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::ProjectPoint3D(const gfx::Transform& transform,
+                                      const gfx::PointF& p,
+                                      bool* clipped) {
+  HomogeneousCoordinate h = ProjectHomogeneousPoint(transform, p, clipped);
+  if (!h.w())
+    return gfx::Point3F();
+  return h.CartesianPoint3d();
+}
+
 gfx::RectF MathUtil::ScaleRectProportional(const gfx::RectF& input_outer_rect,
                                            const gfx::RectF& scale_outer_rect,
                                            const gfx::RectF& scale_inner_rect) {
@@ -486,13 +643,17 @@ gfx::RectF MathUtil::ScaleRectProportional(const gfx::RectF& input_outer_rect,
   return output_inner_rect;
 }
 
+static inline bool NearlyZero(double value) {
+  return std::abs(value) < std::numeric_limits<double>::epsilon();
+}
+
 static inline float ScaleOnAxis(double a, double b, double c) {
-  if (!b && !c)
-    return a;
-  if (!a && !c)
-    return b;
-  if (!a && !b)
-    return c;
+  if (NearlyZero(b) && NearlyZero(c))
+    return std::abs(a);
+  if (NearlyZero(a) && NearlyZero(c))
+    return std::abs(b);
+  if (NearlyZero(a) && NearlyZero(b))
+    return std::abs(c);
 
   // Do the sqrt as a double to not lose precision.
   return static_cast<float>(std::sqrt(a * a + b * b + c * c));
@@ -535,13 +696,6 @@ scoped_ptr<base::Value> MathUtil::AsValue(const gfx::Size& s) {
   return res.PassAs<base::Value>();
 }
 
-scoped_ptr<base::Value> MathUtil::AsValue(const 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(const gfx::Rect& r) {
   scoped_ptr<base::ListValue> res(new base::ListValue());
   res->AppendInteger(r.x());
@@ -579,15 +733,53 @@ scoped_ptr<base::Value> MathUtil::AsValue(const gfx::PointF& pt) {
   return res.PassAs<base::Value>();
 }
 
-scoped_ptr<base::Value> MathUtil::AsValue(const gfx::Vector2d& v) {
-  scoped_ptr<base::ListValue> res(new base::ListValue());
+void MathUtil::AddToTracedValue(const gfx::Size& s,
+                                base::debug::TracedValue* res) {
+  res->SetDouble("width", s.width());
+  res->SetDouble("height", s.height());
+}
+
+void MathUtil::AddToTracedValue(const gfx::SizeF& s,
+                                base::debug::TracedValue* res) {
+  res->SetDouble("width", s.width());
+  res->SetDouble("height", s.height());
+}
+
+void MathUtil::AddToTracedValue(const gfx::Rect& r,
+                                base::debug::TracedValue* res) {
+  res->AppendInteger(r.x());
+  res->AppendInteger(r.y());
+  res->AppendInteger(r.width());
+  res->AppendInteger(r.height());
+}
+
+void MathUtil::AddToTracedValue(const gfx::PointF& pt,
+                                base::debug::TracedValue* res) {
+  res->AppendDouble(pt.x());
+  res->AppendDouble(pt.y());
+}
+
+void MathUtil::AddToTracedValue(const gfx::Point3F& pt,
+                                base::debug::TracedValue* res) {
+  res->AppendDouble(pt.x());
+  res->AppendDouble(pt.y());
+  res->AppendDouble(pt.z());
+}
+
+void MathUtil::AddToTracedValue(const gfx::Vector2d& v,
+                                base::debug::TracedValue* res) {
   res->AppendInteger(v.x());
   res->AppendInteger(v.y());
-  return res.PassAs<base::Value>();
 }
 
-scoped_ptr<base::Value> MathUtil::AsValue(const gfx::QuadF& q) {
-  scoped_ptr<base::ListValue> res(new base::ListValue());
+void MathUtil::AddToTracedValue(const gfx::Vector2dF& v,
+                                base::debug::TracedValue* res) {
+  res->AppendDouble(v.x());
+  res->AppendDouble(v.y());
+}
+
+void MathUtil::AddToTracedValue(const gfx::QuadF& q,
+                                base::debug::TracedValue* res) {
   res->AppendDouble(q.p1().x());
   res->AppendDouble(q.p1().y());
   res->AppendDouble(q.p2().x());
@@ -596,47 +788,41 @@ scoped_ptr<base::Value> MathUtil::AsValue(const gfx::QuadF& q) {
   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());
+void MathUtil::AddToTracedValue(const gfx::RectF& rect,
+                                base::debug::TracedValue* res) {
   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());
+void MathUtil::AddToTracedValue(const gfx::Transform& transform,
+                                base::debug::TracedValue* res) {
   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::AsValue(const gfx::BoxF& box) {
-  scoped_ptr<base::ListValue> res(new base::ListValue());
+void MathUtil::AddToTracedValue(const gfx::BoxF& box,
+                                base::debug::TracedValue* res) {
   res->AppendInteger(box.x());
   res->AppendInteger(box.y());
   res->AppendInteger(box.z());
   res->AppendInteger(box.width());
   res->AppendInteger(box.height());
   res->AppendInteger(box.depth());
-  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())));
+double MathUtil::AsDoubleSafely(double value) {
+  return 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())));
+float MathUtil::AsFloatSafely(float value) {
+  return std::min(value, std::numeric_limits<float>::max());
 }
 
 }  // namespace cc