Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / cc / base / math_util.cc
index 8abfa90..7f6178d 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,8 +111,22 @@ static inline void AddVertexToClippedQuad(const gfx::PointF& new_vertex,
   (*num_vertices_in_clipped_quad)++;
 }
 
-gfx::Rect MathUtil::MapClippedRect(const gfx::Transform& transform,
-                                   const gfx::Rect& src_rect) {
+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))));
+  }
   return gfx::ToEnclosingRect(MapClippedRect(transform, gfx::RectF(src_rect)));
 }
 
@@ -136,6 +160,19 @@ gfx::RectF MathUtil::MapClippedRect(const gfx::Transform& transform,
   return ComputeEnclosingClippedRect(hc0, hc1, hc2, hc3);
 }
 
+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))));
+  }
+  return gfx::ToEnclosingRect(
+      ProjectClippedRect(transform, gfx::RectF(src_rect)));
+}
+
 gfx::RectF MathUtil::ProjectClippedRect(const gfx::Transform& transform,
                                         const gfx::RectF& src_rect) {
   if (transform.IsIdentityOrTranslation()) {
@@ -223,6 +260,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) {
@@ -356,6 +463,48 @@ 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(SkMScalarToFloat(transform.matrix().get(0, 3)),
+                       SkMScalarToFloat(transform.matrix().get(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) {
@@ -424,28 +573,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) {
@@ -466,13 +614,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));
@@ -508,14 +660,7 @@ gfx::Vector2dF MathUtil::ProjectVector(const gfx::Vector2dF& source,
                         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(const gfx::SizeF& s) {
+scoped_ptr<base::Value> MathUtil::AsValue(const gfx::Size& s) {
   scoped_ptr<base::DictionaryValue> res(new base::DictionaryValue());
   res->SetDouble("width", s.width());
   res->SetDouble("height", s.height());
@@ -559,8 +704,53 @@ scoped_ptr<base::Value> MathUtil::AsValue(const gfx::PointF& pt) {
   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::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());
+}
+
+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());
@@ -569,47 +759,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