From 4e17ceefdbd1a18fad562ddcda904d8ba78ff059 Mon Sep 17 00:00:00 2001 From: Eric Seidel Date: Thu, 23 Jul 2015 11:11:09 -0700 Subject: [PATCH] Add support for Canvas.setMatrix and getTotalMatrix Part of fixing issue #138. R=abarth@google.com --- sky/engine/bindings/scripts/dart_types.py | 1 + sky/engine/core/painting/Canvas.cpp | 72 +++++++++++++++++------ sky/engine/core/painting/Canvas.h | 5 +- sky/engine/core/painting/Canvas.idl | 5 +- sky/engine/tonic/float32_list.cc | 6 ++ sky/engine/tonic/float32_list.h | 17 ++++++ sky/tests/painting/canvas-expected.txt | 6 ++ sky/tests/painting/canvas.dart | 26 ++++++++ 8 files changed, 119 insertions(+), 19 deletions(-) create mode 100644 sky/tests/painting/canvas-expected.txt create mode 100644 sky/tests/painting/canvas.dart diff --git a/sky/engine/bindings/scripts/dart_types.py b/sky/engine/bindings/scripts/dart_types.py index ad6901134..a00c0da16 100644 --- a/sky/engine/bindings/scripts/dart_types.py +++ b/sky/engine/bindings/scripts/dart_types.py @@ -646,6 +646,7 @@ DART_SET_RETURN_VALUE = { 'ArrayBuffer': 'Dart_SetReturnValue(args, DartUtilities::arrayBufferToDart({cpp_value}))', 'TypedList': 'Dart_SetReturnValue(args, DartUtilities::arrayBufferViewToDart({cpp_value}))', 'Color': 'DartConverter::SetReturnValue(args, {cpp_value})', + 'Float32List': 'DartConverter::SetReturnValue(args, {cpp_value})', } diff --git a/sky/engine/core/painting/Canvas.cpp b/sky/engine/core/painting/Canvas.cpp index 296ac9ca4..39df62a65 100644 --- a/sky/engine/core/painting/Canvas.cpp +++ b/sky/engine/core/painting/Canvas.cpp @@ -75,29 +75,67 @@ void Canvas::skew(float sx, float sy) m_canvas->skew(sx, sy); } -void Canvas::concat(const Float32List& matrix4) +// Mappings from SkMatrix-index to input-index. +static const int kSkMatrixIndexToMatrix4Index[] = { + 0, 4, 12, + 1, 5, 13, + 3, 7, 15, +}; + +SkMatrix toSkMatrix(const Float32List& matrix4, ExceptionState& es) +{ + ASSERT(matrix4.data()); + SkMatrix sk_matrix; + if (matrix4.num_elements() != 16) { + es.ThrowTypeError("Incorrect number of elements in matrix."); + return sk_matrix; + } + + for (intptr_t i = 0; i < 9; ++i) + sk_matrix[i] = matrix4[kSkMatrixIndexToMatrix4Index[i]]; + return sk_matrix; +} + +Float32List toMatrix4(const SkMatrix& sk_matrix) +{ + Float32List matrix4(Dart_NewTypedData(Dart_TypedData_kFloat32, 16)); + for (intptr_t i = 0; i < 9; ++i) + matrix4[kSkMatrixIndexToMatrix4Index[i]] = sk_matrix[i]; + matrix4[10] = 1.0; // Identity along the z axis. + return matrix4; +} + +void Canvas::concat(const Float32List& matrix4, ExceptionState& es) { if (!m_canvas) + return es.ThrowTypeError("No canvas"); + + SkMatrix sk_matrix = toSkMatrix(matrix4, es); + if (es.had_exception()) return; - ASSERT(matrix4.data()); - - // TODO(mpcomplete): how can we raise an error in this case? - if (matrix4.num_elements() != 16) - return; - - SkMatrix sk_matrix; - // Mappings from SkMatrix-index to input-index. - static const int kMappings[] = { - 0, 4, 12, - 1, 5, 13, - 3, 7, 15, - }; - for (intptr_t i = 0; i < 9; ++i) - sk_matrix[i] = matrix4.data()[kMappings[i]]; - m_canvas->concat(sk_matrix); } +void Canvas::setMatrix(const Float32List& matrix4, ExceptionState& es) +{ + if (!m_canvas) + return es.ThrowTypeError("No canvas"); + + SkMatrix sk_matrix = toSkMatrix(matrix4, es); + if (es.had_exception()) + return; + m_canvas->setMatrix(sk_matrix); +} + +Float32List Canvas::getTotalMatrix() const +{ + // Maybe we should throw an exception instead of returning an empty matrix? + SkMatrix sk_matrix; + if (m_canvas) + sk_matrix = m_canvas->getTotalMatrix(); + return toMatrix4(sk_matrix); +} + void Canvas::clipRect(const Rect& rect) { if (!m_canvas) diff --git a/sky/engine/core/painting/Canvas.h b/sky/engine/core/painting/Canvas.h index 5cba6cf55..75a144bc4 100644 --- a/sky/engine/core/painting/Canvas.h +++ b/sky/engine/core/painting/Canvas.h @@ -68,7 +68,10 @@ public: void scale(float sx, float sy); void rotate(float radians); void skew(float sx, float sy); - void concat(const Float32List& matrix4); + void concat(const Float32List& matrix4, ExceptionState&); + + void setMatrix(const Float32List& matrix4, ExceptionState&); + Float32List getTotalMatrix() const; void clipRect(const Rect& rect); void clipRRect(const RRect* rrect); diff --git a/sky/engine/core/painting/Canvas.idl b/sky/engine/core/painting/Canvas.idl index 618af6741..83f75743d 100644 --- a/sky/engine/core/painting/Canvas.idl +++ b/sky/engine/core/painting/Canvas.idl @@ -16,7 +16,10 @@ void scale(float sx, float sy); void rotate(float radians); void skew(float sx, float sy); - void concat(Float32List matrix4); + [RaisesException] void concat(Float32List matrix4); + + [RaisesException] void setMatrix(Float32List matrix4); + Float32List getTotalMatrix(); void clipRect(Rect rect); void clipRRect(RRect rrect); diff --git a/sky/engine/tonic/float32_list.cc b/sky/engine/tonic/float32_list.cc index 43eb37070..2ca962dd7 100644 --- a/sky/engine/tonic/float32_list.cc +++ b/sky/engine/tonic/float32_list.cc @@ -43,4 +43,10 @@ Float32List DartConverter::FromArgumentsWithNullCheck( return result; } +void DartConverter::SetReturnValue(Dart_NativeArguments args, + Float32List val) { + Dart_SetReturnValue(args, val.dart_handle()); +} + + } // namespace blink diff --git a/sky/engine/tonic/float32_list.h b/sky/engine/tonic/float32_list.h index be9503ba3..98b037a80 100644 --- a/sky/engine/tonic/float32_list.h +++ b/sky/engine/tonic/float32_list.h @@ -21,8 +21,23 @@ class Float32List { Float32List(Float32List&& other); ~Float32List(); + float& at(intptr_t i) + { + CHECK(i < num_elements_); + return data_[i]; + } + const float& at(intptr_t i) const + { + CHECK(i < num_elements_); + return data_[i]; + } + + float& operator[](intptr_t i) { return at(i); } + const float& operator[](intptr_t i) const { return at(i); } + const float* data() const { return data_; } intptr_t num_elements() const { return num_elements_; } + Dart_Handle dart_handle() const { return dart_handle_; } private: float* data_; @@ -34,6 +49,8 @@ class Float32List { template <> struct DartConverter { + static void SetReturnValue(Dart_NativeArguments args, Float32List val); + static Float32List FromArgumentsWithNullCheck(Dart_NativeArguments args, int index, Dart_Handle& exception); diff --git a/sky/tests/painting/canvas-expected.txt b/sky/tests/painting/canvas-expected.txt new file mode 100644 index 000000000..ac43fca24 --- /dev/null +++ b/sky/tests/painting/canvas-expected.txt @@ -0,0 +1,6 @@ +unittest-suite-wait-for-done +PASS: matrix access should work + +All 1 tests passed. +unittest-suite-success +DONE diff --git a/sky/tests/painting/canvas.dart b/sky/tests/painting/canvas.dart new file mode 100644 index 000000000..23c9c27ed --- /dev/null +++ b/sky/tests/painting/canvas.dart @@ -0,0 +1,26 @@ +import "../resources/dom_utils.dart"; +import "../resources/third_party/unittest/unittest.dart"; +import "../resources/unit.dart"; + +import "dart:sky"; +import 'package:vector_math/vector_math.dart'; + +void main() { + initUnit(); + + PictureRecorder recorder = new PictureRecorder(); + Canvas canvas = new Canvas(recorder, new Rect.fromLTRB(0.0, 0.0, 100.0, 100.0)); + + test("matrix access should work", () { + // Matrix equality doesn't work! + // https://github.com/google/vector_math.dart/issues/147 + expect(canvas.getTotalMatrix(), equals(new Matrix4.identity().storage)); + Matrix4 matrix = new Matrix4.identity(); + // Round-tripping through getTotalMatrix will lose the z value + // So only scale to 1x in the z direction. + matrix.scale(2.0, 2.0, 1.0); + canvas.setMatrix(matrix.storage); + expect(canvas.getTotalMatrix(), equals(matrix.storage)); + }); + +}