Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(128)

Unified Diff: ui/gfx/transform_util.cc

Issue 23444049: Implement transform snapping for gfx::Transforms. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 7 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « ui/gfx/transform_util.h ('k') | ui/gfx/transform_util_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: ui/gfx/transform_util.cc
diff --git a/ui/gfx/transform_util.cc b/ui/gfx/transform_util.cc
index 90c8b56e5547937f76686bfa6934064e74207112..f9ddb32f9bfe8e434f6bf385744eeb1805e56aa8 100644
--- a/ui/gfx/transform_util.cc
+++ b/ui/gfx/transform_util.cc
@@ -6,12 +6,21 @@
#include <cmath>
+#include "base/logging.h"
#include "ui/gfx/point.h"
+#include "ui/gfx/point3_f.h"
+#include "ui/gfx/rect_f.h"
namespace gfx {
namespace {
+const float NEAR_INT_ESPILON = 1e-10;
danakj 2013/09/10 20:29:51 kNearIntEpsilon I will also note this is at least
avallee 2013/09/10 21:30:13 I'll unify with what's in transform.cc.
Ian Vollick 2013/09/11 12:19:48 This is a bummer, for sure. Is it possible to shar
+
+bool NearInteger(float f) {
+ return (abs(f-round(f)) < NEAR_INT_ESPILON);
danakj 2013/09/10 20:29:51 std::abs std::round
avallee 2013/09/10 21:30:13 Done.
Ian Vollick 2013/09/11 12:19:48 I think we want the relative error, not the absolu
+}
+
double Length3(double v[3]) {
return std::sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
}
@@ -264,20 +273,11 @@ bool DecomposeTransform(DecomposedTransform* decomp,
return true;
}
-// Taken from http://www.w3.org/TR/css3-transforms/.
-Transform ComposeTransform(const DecomposedTransform& decomp) {
- SkMatrix44 matrix(SkMatrix44::kIdentity_Constructor);
- for (int i = 0; i < 4; i++)
- matrix.setDouble(3, i, decomp.perspective[i]);
-
- matrix.preTranslate(SkDoubleToMScalar(decomp.translate[0]),
- SkDoubleToMScalar(decomp.translate[1]),
- SkDoubleToMScalar(decomp.translate[2]));
-
- double x = decomp.quaternion[0];
- double y = decomp.quaternion[1];
- double z = decomp.quaternion[2];
- double w = decomp.quaternion[3];
+SkMatrix44 QuaternionToRotationMatrix(const double (& quaternion)[4]) {
+ double x = quaternion[0];
+ double y = quaternion[1];
+ double z = quaternion[2];
+ double w = quaternion[3];
SkMatrix44 rotation_matrix(SkMatrix44::kUninitialized_Constructor);
rotation_matrix.set3x3(1.0 - 2.0 * (y * y + z * z),
@@ -290,33 +290,130 @@ Transform ComposeTransform(const DecomposedTransform& decomp) {
2.0 * (y * z - x * w),
1.0 - 2.0 * (x * x + y * y));
- matrix.preConcat(rotation_matrix);
+ return rotation_matrix;
+}
+
+void ApplyPerspectiveTranslation(SkMatrix44* matrix,
+ const DecomposedTransform& decomp) {
+ for (int i = 0; i < 4; i++)
+ matrix->setDouble(3, i, decomp.perspective[i]);
+
+ matrix->preTranslate(SkDoubleToMScalar(decomp.translate[0]),
+ SkDoubleToMScalar(decomp.translate[1]),
+ SkDoubleToMScalar(decomp.translate[2]));
+}
+void ApplySkewScale(SkMatrix44* matrix,
+ const DecomposedTransform& decomp) {
SkMatrix44 temp(SkMatrix44::kIdentity_Constructor);
if (decomp.skew[2]) {
temp.setDouble(1, 2, decomp.skew[2]);
- matrix.preConcat(temp);
+ matrix->preConcat(temp);
}
if (decomp.skew[1]) {
temp.setDouble(1, 2, 0);
temp.setDouble(0, 2, decomp.skew[1]);
- matrix.preConcat(temp);
+ matrix->preConcat(temp);
}
if (decomp.skew[0]) {
temp.setDouble(0, 2, 0);
temp.setDouble(0, 1, decomp.skew[0]);
- matrix.preConcat(temp);
+ matrix->preConcat(temp);
}
- matrix.preScale(SkDoubleToMScalar(decomp.scale[0]),
- SkDoubleToMScalar(decomp.scale[1]),
- SkDoubleToMScalar(decomp.scale[2]));
+ matrix->preScale(SkDoubleToMScalar(decomp.scale[0]),
+ SkDoubleToMScalar(decomp.scale[1]),
+ SkDoubleToMScalar(decomp.scale[2]));
+}
+
+// Taken from http://www.w3.org/TR/css3-transforms/.
+Transform ComposeTransform(const DecomposedTransform& decomp) {
+ SkMatrix44 matrix(SkMatrix44::kIdentity_Constructor);
+ ApplyPerspectiveTranslation(&matrix, decomp);
+
+ matrix.preConcat(QuaternionToRotationMatrix(decomp.quaternion));
+
+ ApplySkewScale(&matrix, decomp);
Transform to_return;
to_return.matrix() = matrix;
return to_return;
}
+Transform ComposeWithRotation(const DecomposedTransform& decomp,
+ const SkMatrix44& rotation_matrix) {
+ SkMatrix44 matrix(SkMatrix44::kIdentity_Constructor);
+ ApplyPerspectiveTranslation(&matrix, decomp);
+ matrix.preConcat(rotation_matrix);
+
+ ApplySkewScale(&matrix, decomp);
+
+ Transform to_return;
+ to_return.matrix() = matrix;
+ return to_return;
+}
+
+bool CheckTansformPoint(const PointF& point, const Transform& transform_a,
+ const Transform& transform_b) {
+ Point3F point_a, point_b;
+ point_a = point_b = Point3F(point.x(), point.y(), 0.0);
danakj 2013/09/10 20:29:51 0.f
avallee 2013/09/10 21:30:13 Done.
+
+ // Can't use TransformRect here since it would give us the axis-aligned
+ // bounding rect of the 4 points in the initial rectable which is not what we
+ // want.
+ bool invertible = true;
danakj 2013/09/10 20:29:51 true || anything = true. did you mean false?
avallee 2013/09/10 21:30:13 Meant and_equals.
+ invertible |= transform_a.TransformPointReverse(&point_a);
+ invertible |= transform_b.TransformPointReverse(&point_b);
+ DCHECK(invertible) << "Non-invertible transform, cannot snap.";
+
+ if (!(NearInteger(point_b.x()) && NearInteger(point_b.y()))) {
+ // Integers should get mapped back into integer points.
+ return false;
+ }
+
+ if ((point_b-point_a).Length() > 1.0) {
danakj 2013/09/10 20:29:51 spaces around operators
avallee 2013/09/10 21:30:13 Done.
+ // The changed distance should not be more than 1 pixel.
+ return false;
+ }
+ return true;
+}
+
+bool SnapRotation(DecomposedTransform* out, const DecomposedTransform& in,
+ const RectF& viewport) {
+
+ // Create snapped rotation.
+ SkMatrix44 rotation_matrix = QuaternionToRotationMatrix(in.quaternion);
+ for (int i = 0; i < 3; ++i) {
+ for (int j = 0; j < 3; ++j) {
+ SkMScalar value = rotation_matrix.get(i, j);
+ // Snap values to -1, 0 or 1.
+ if (value < -0.5) {
danakj 2013/09/10 20:29:51 treat SkMScalar as a float. so compare to -0.5f. s
avallee 2013/09/10 21:30:13 uOn 2013/09/10 20:29:51, danakj wrote:
+ value = -1.0;
+ } else if (value > 0.5) {
+ value = 1.0;
+ } else {
+ value = 0.0;
+ }
+ rotation_matrix.set(i, j, value);
+ }
+ }
+
+ // Get full tranforms
+ Transform original = ComposeTransform(in);
+ Transform snapped = ComposeWithRotation(in, rotation_matrix);
+
+ // Verify that viewport is not moved unnaturally.
+
+ bool snappable = CheckTansformPoint(viewport.origin(), original, snapped) &&
+ CheckTansformPoint(viewport.top_right(), original, snapped) &&
+ CheckTansformPoint(viewport.bottom_left(), original, snapped) &&
+ CheckTansformPoint(viewport.bottom_right(), original, snapped);
+ if (snappable) {
+ DecomposeTransform(out, snapped);
+ }
+ return snappable;
+}
+
} // namespace ui
« no previous file with comments | « ui/gfx/transform_util.h ('k') | ui/gfx/transform_util_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698