summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ui/gfx/canvas.h9
-rw-r--r--ui/gfx/canvas_direct2d.cc6
-rw-r--r--ui/gfx/canvas_direct2d.h3
-rw-r--r--ui/gfx/canvas_skia.cc7
-rw-r--r--ui/gfx/canvas_skia.h3
-rw-r--r--ui/gfx/gfx.gyp3
-rw-r--r--ui/gfx/transform.h66
-rw-r--r--ui/gfx/transform_skia.cc102
-rw-r--r--ui/gfx/transform_skia.h54
-rw-r--r--views/events/event.cc10
-rw-r--r--views/events/event.h26
-rw-r--r--views/touchui/gesture_manager.cc16
-rw-r--r--views/view.cc180
-rw-r--r--views/view.h65
-rw-r--r--views/view_unittest.cc127
-rw-r--r--views/widget/root_view.cc20
-rw-r--r--views/widget/root_view.h8
17 files changed, 606 insertions, 99 deletions
diff --git a/ui/gfx/canvas.h b/ui/gfx/canvas.h
index 8c89d59..0149486 100644
--- a/ui/gfx/canvas.h
+++ b/ui/gfx/canvas.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -13,6 +13,10 @@
#include "skia/ext/platform_canvas.h"
#include "ui/gfx/native_widget_types.h"
+namespace ui {
+class Transform;
+}
+
namespace gfx {
class Brush;
@@ -208,6 +212,9 @@ class Canvas {
// returned by BeginPlatformPaint().
virtual void EndPlatformPaint() = 0;
+ // Apply transformation on the canvas.
+ virtual void Transform(const ui::Transform& transform) = 0;
+
// TODO(beng): remove this once we don't need to use any skia-specific methods
// through this interface.
// A quick and dirty way to obtain the underlying SkCanvas.
diff --git a/ui/gfx/canvas_direct2d.cc b/ui/gfx/canvas_direct2d.cc
index 61d3403..63e9bb9 100644
--- a/ui/gfx/canvas_direct2d.cc
+++ b/ui/gfx/canvas_direct2d.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -341,6 +341,10 @@ void CanvasDirect2D::EndPlatformPaint() {
interop_rt_.release();
}
+void CanvasDirect2D::Transform(const ui::Transform& transform) {
+ NOTIMPLEMENTED();
+}
+
CanvasSkia* CanvasDirect2D::AsCanvasSkia() {
return NULL;
}
diff --git a/ui/gfx/canvas_direct2d.h b/ui/gfx/canvas_direct2d.h
index d87fdf3..45452f5 100644
--- a/ui/gfx/canvas_direct2d.h
+++ b/ui/gfx/canvas_direct2d.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -77,6 +77,7 @@ class CanvasDirect2D : public Canvas {
int dest_x, int dest_y, int w, int h);
virtual gfx::NativeDrawingContext BeginPlatformPaint();
virtual void EndPlatformPaint();
+ virtual void Transform(const ui::Transform& transform);
virtual CanvasSkia* AsCanvasSkia();
virtual const CanvasSkia* AsCanvasSkia() const;
diff --git a/ui/gfx/canvas_skia.cc b/ui/gfx/canvas_skia.cc
index 99174d1..e61f0f2 100644
--- a/ui/gfx/canvas_skia.cc
+++ b/ui/gfx/canvas_skia.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -12,6 +12,7 @@
#include "ui/gfx/brush.h"
#include "ui/gfx/font.h"
#include "ui/gfx/rect.h"
+#include "ui/gfx/transform_skia.h"
#if defined(OS_WIN)
#include "ui/gfx/canvas_skia_paint.h"
@@ -330,6 +331,10 @@ void CanvasSkia::EndPlatformPaint() {
endPlatformPaint();
}
+void CanvasSkia::Transform(const ui::Transform& transform) {
+ concat(*reinterpret_cast<const ui::TransformSkia&>(transform).matrix_.get());
+}
+
CanvasSkia* CanvasSkia::AsCanvasSkia() {
return this;
}
diff --git a/ui/gfx/canvas_skia.h b/ui/gfx/canvas_skia.h
index be44687..854ce84 100644
--- a/ui/gfx/canvas_skia.h
+++ b/ui/gfx/canvas_skia.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -139,6 +139,7 @@ class CanvasSkia : public skia::PlatformCanvas,
int dest_x, int dest_y, int w, int h);
virtual gfx::NativeDrawingContext BeginPlatformPaint();
virtual void EndPlatformPaint();
+ virtual void Transform(const ui::Transform& transform);
virtual CanvasSkia* AsCanvasSkia();
virtual const CanvasSkia* AsCanvasSkia() const;
diff --git a/ui/gfx/gfx.gyp b/ui/gfx/gfx.gyp
index 12d368d..d72e24b 100644
--- a/ui/gfx/gfx.gyp
+++ b/ui/gfx/gfx.gyp
@@ -147,6 +147,9 @@
'skia_util.h',
'skia_utils_gtk.cc',
'skia_utils_gtk.h',
+ 'transform.h',
+ 'transform_skia.cc',
+ 'transform_skia.h',
],
'conditions': [
['OS=="win"', {
diff --git a/ui/gfx/transform.h b/ui/gfx/transform.h
new file mode 100644
index 0000000..d8f6899
--- /dev/null
+++ b/ui/gfx/transform.h
@@ -0,0 +1,66 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_GFX_TRANSFORM_H_
+#define UI_GFX_TRANSFORM_H_
+#pragma once
+
+namespace gfx {
+class Point;
+class Rect;
+}
+
+namespace ui {
+
+// Transformation interface.
+// Classes implement this interface to apply transformations (e.g. rotation,
+// scaling etc.) on UI components.
+class Transform {
+ public:
+ // Create an object that implements this interface (e.g. using skia
+ // transformation matrices).
+ static Transform* Create();
+
+ // Set the rotation of the transformation.
+ virtual void SetRotate(float degree) = 0;
+
+ // Set the scaling parameters.
+ virtual void SetScaleX(float x) = 0;
+ virtual void SetScaleY(float y) = 0;
+ virtual void SetScale(float x, float y) = 0;
+
+ // Set the translation parameters.
+ virtual void SetTranslateX(float x) = 0;
+ virtual void SetTranslateY(float y) = 0;
+ virtual void SetTranslate(float x, float y) = 0;
+
+ // Apply rotation on the current transformation.
+ virtual void ConcatRotate(float degree) = 0;
+
+ // Apply scaling on current transform.
+ virtual void ConcatScale(float x, float y) = 0;
+
+ // Apply translation on current transform.
+ virtual void ConcatTranslate(float x, float y) = 0;
+
+ // Apply a transformation on the current transformation
+ // (i.e. 'this = this * transform;')
+ virtual bool ConcatTransform(const Transform& transform) = 0;
+
+ // Does the transformation change anything?
+ virtual bool HasChange() const = 0;
+
+ // Apply the transformation on the point.
+ virtual bool TransformPoint(gfx::Point* point) = 0;
+
+ // Apply the reverse transformation on the point.
+ virtual bool TransformPointReverse(gfx::Point* point) = 0;
+
+ // Apply transformatino on the rectangle.
+ virtual bool TransformRect(gfx::Rect* rect) = 0;
+};
+
+} // namespace ui
+
+#endif // UI_GFX_TRANSFORM_H_
diff --git a/ui/gfx/transform_skia.cc b/ui/gfx/transform_skia.cc
new file mode 100644
index 0000000..50a7dcd
--- /dev/null
+++ b/ui/gfx/transform_skia.cc
@@ -0,0 +1,102 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/gfx/transform_skia.h"
+
+#include "third_party/skia/include/core/SkMatrix.h"
+#include "ui/gfx/canvas_skia.h"
+#include "ui/gfx/point.h"
+#include "ui/gfx/rect.h"
+#include "ui/gfx/skia_util.h"
+
+namespace ui {
+
+// static
+Transform* Transform::Create() {
+ return new TransformSkia();
+}
+
+TransformSkia::TransformSkia() {
+ matrix_.reset(new SkMatrix);
+ matrix_->reset();
+}
+
+void TransformSkia::SetRotate(float degree) {
+ matrix_->setRotate(SkFloatToScalar(degree));
+}
+
+void TransformSkia::SetScaleX(float x) {
+ matrix_->setScaleX(SkFloatToScalar(x));
+}
+
+void TransformSkia::SetScaleY(float y) {
+ matrix_->setScaleY(SkFloatToScalar(y));
+}
+
+void TransformSkia::SetScale(float x, float y) {
+ matrix_->setScale(SkFloatToScalar(x), SkFloatToScalar(y));
+}
+
+void TransformSkia::SetTranslateX(float x) {
+ matrix_->setTranslateX(SkFloatToScalar(x));
+}
+
+void TransformSkia::SetTranslateY(float y) {
+ matrix_->setTranslateY(SkFloatToScalar(y));
+}
+
+void TransformSkia::SetTranslate(float x, float y) {
+ matrix_->setTranslate(SkFloatToScalar(x), SkFloatToScalar(y));
+}
+
+void TransformSkia::ConcatRotate(float degree) {
+ matrix_->postRotate(SkFloatToScalar(degree));
+}
+
+void TransformSkia::ConcatScale(float x, float y) {
+ matrix_->postScale(SkFloatToScalar(x), SkFloatToScalar(y));
+}
+
+void TransformSkia::ConcatTranslate(float x, float y) {
+ matrix_->postTranslate(SkFloatToScalar(x), SkFloatToScalar(y));
+}
+
+bool TransformSkia::ConcatTransform(const Transform& transform) {
+ return matrix_->setConcat(*reinterpret_cast<const TransformSkia&>
+ (transform).matrix_.get(), *matrix_.get());
+}
+
+bool TransformSkia::HasChange() const {
+ return !matrix_->isIdentity();
+}
+
+bool TransformSkia::TransformPoint(gfx::Point* point) {
+ SkPoint skp;
+ matrix_->mapXY(SkIntToScalar(point->x()), SkIntToScalar(point->y()), &skp);
+ point->SetPoint(static_cast<int>(skp.fX), static_cast<int>(skp.fY));
+ return true;
+}
+
+bool TransformSkia::TransformPointReverse(gfx::Point* point) {
+ SkMatrix inverse;
+ // TODO(sad): Try to avoid trying to invert the matrix.
+ if (matrix_->invert(&inverse)) {
+ SkPoint skp;
+ inverse.mapXY(SkIntToScalar(point->x()), SkIntToScalar(point->y()), &skp);
+ point->SetPoint(static_cast<int>(skp.fX), static_cast<int>(skp.fY));
+ return true;
+ }
+ return false;
+}
+
+bool TransformSkia::TransformRect(gfx::Rect* rect) {
+ SkRect src = gfx::RectToSkRect(*rect);
+ if (!matrix_->mapRect(&src))
+ return false;
+ gfx::Rect xrect = gfx::SkRectToRect(src);
+ rect->SetRect(xrect.x(), xrect.y(), xrect.width(), xrect.height());
+ return true;
+}
+
+} // namespace ui
diff --git a/ui/gfx/transform_skia.h b/ui/gfx/transform_skia.h
new file mode 100644
index 0000000..1bd8188
--- /dev/null
+++ b/ui/gfx/transform_skia.h
@@ -0,0 +1,54 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_GFX_TRANSFORM_SKIA_H_
+#define UI_GFX_TRANSFORM_SKIA_H_
+#pragma once
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/scoped_ptr.h"
+#include "ui/gfx/transform.h"
+
+class SkMatrix;
+
+namespace gfx {
+class CanvasSkia;
+}
+
+namespace ui {
+
+// Transformation using skia transformation matrices.
+class TransformSkia : public Transform {
+ public:
+ TransformSkia();
+ virtual ~TransformSkia() {}
+
+ // Overridden from ui::Transform
+ virtual void SetRotate(float degree) OVERRIDE;
+ virtual void SetScaleX(float x) OVERRIDE;
+ virtual void SetScaleY(float y) OVERRIDE;
+ virtual void SetScale(float x, float y) OVERRIDE;
+ virtual void SetTranslateX(float x) OVERRIDE;
+ virtual void SetTranslateY(float y) OVERRIDE;
+ virtual void SetTranslate(float x, float y) OVERRIDE;
+ virtual void ConcatRotate(float degree) OVERRIDE;
+ virtual void ConcatScale(float x, float y) OVERRIDE;
+ virtual void ConcatTranslate(float x, float y) OVERRIDE;
+ virtual bool ConcatTransform(const Transform& transform) OVERRIDE;
+ virtual bool HasChange() const OVERRIDE;
+ virtual bool TransformPoint(gfx::Point* point) OVERRIDE;
+ virtual bool TransformPointReverse(gfx::Point* point) OVERRIDE;
+ virtual bool TransformRect(gfx::Rect* rect) OVERRIDE;
+
+ private:
+ friend class gfx::CanvasSkia;
+ scoped_ptr<SkMatrix> matrix_;
+
+ DISALLOW_COPY_AND_ASSIGN(TransformSkia);
+};
+
+} // namespace ui
+
+#endif // UI_GFX_TRANSFORM_SKIA_H_
diff --git a/views/events/event.cc b/views/events/event.cc
index 2a814bd..49fe29b 100644
--- a/views/events/event.cc
+++ b/views/events/event.cc
@@ -5,6 +5,7 @@
#include "views/events/event.h"
#include "views/view.h"
+#include "views/widget/root_view.h"
namespace views {
@@ -45,6 +46,15 @@ LocatedEvent::LocatedEvent(const LocatedEvent& model, View* from, View* to)
}
////////////////////////////////////////////////////////////////////////////////
+// LocatedEvent, private:
+
+LocatedEvent::LocatedEvent(const LocatedEvent& model, RootView* root)
+ : Event(model),
+ location_(model.location_) {
+ View::ConvertPointFromWidget(root, &location_);
+}
+
+////////////////////////////////////////////////////////////////////////////////
// KeyEvent, public:
KeyEvent::KeyEvent(ui::EventType type, ui::KeyboardCode key_code,
diff --git a/views/events/event.h b/views/events/event.h
index 5382573..83f8bbf 100644
--- a/views/events/event.h
+++ b/views/events/event.h
@@ -24,6 +24,7 @@ using ui::OSExchangeData;
namespace views {
+class RootView;
class View;
////////////////////////////////////////////////////////////////////////////////
@@ -145,6 +146,11 @@ class LocatedEvent : public Event {
int y() const { return location_.y(); }
const gfx::Point& location() const { return location_; }
+ protected:
+ // This constructor is to allow converting the location of an event from the
+ // widget's coordinate system to the RootView's coordinate system.
+ LocatedEvent(const LocatedEvent& model, RootView* root);
+
private:
gfx::Point location_;
};
@@ -211,6 +217,12 @@ class MouseEvent : public LocatedEvent {
}
private:
+ friend class RootView;
+
+ MouseEvent(const MouseEvent& model, RootView* root)
+ : LocatedEvent(model, root) {
+ }
+
DISALLOW_COPY_AND_ASSIGN(MouseEvent);
};
@@ -251,6 +263,13 @@ class TouchEvent : public LocatedEvent {
bool identity() const { return touch_id_; }
private:
+ friend class RootView;
+
+ TouchEvent(const TouchEvent& model, RootView* root)
+ : LocatedEvent(model, root),
+ touch_id_(model.touch_id_) {
+ }
+
// The identity (typically finger) of the touch starting at 0 and incrementing
// for each separable additional touch that the hardware can detect.
const int touch_id_;
@@ -308,6 +327,13 @@ class MouseWheelEvent : public LocatedEvent {
int offset() const { return offset_; }
private:
+ friend class RootView;
+
+ MouseWheelEvent(const MouseWheelEvent& model, RootView* root)
+ : LocatedEvent(model, root),
+ offset_(model.offset_) {
+ }
+
int offset_;
DISALLOW_COPY_AND_ASSIGN(MouseWheelEvent);
diff --git a/views/touchui/gesture_manager.cc b/views/touchui/gesture_manager.cc
index 2d6c7d0..2442469 100644
--- a/views/touchui/gesture_manager.cc
+++ b/views/touchui/gesture_manager.cc
@@ -30,9 +30,19 @@ bool GestureManager::ProcessTouchEventForGesture(const TouchEvent& event,
// appear in a subsequent CL. This interim version permits verifying that the
// event distribution code works by turning all touch inputs into
// mouse approximations.
+
+ // TODO(sad): Clean this up.
+ // This is currently only called where |source| is a RootView. Now, RootView
+ // expects the mouse-events in the widget's coordinate system, and not in the
+ // RV's coordinate system. But |event| is in the RV's coordinate system. So it
+ // is necessary to construct the synthetic event in the widget's coordinate
+ // system.
+ gfx::Point location = event.location();
+ View::ConvertPointToWidget(source, &location);
+
if (event.type() == ui::ET_TOUCH_PRESSED) {
DVLOG(1) << "GestureManager::ProcessTouchEventForGesture: TouchPressed";
- MouseEvent mouse_event(ui::ET_MOUSE_PRESSED, event.x(), event.y(),
+ MouseEvent mouse_event(ui::ET_MOUSE_PRESSED, location.x(), location.y(),
event.flags());
source->OnMousePressed(mouse_event);
return true;
@@ -40,7 +50,7 @@ bool GestureManager::ProcessTouchEventForGesture(const TouchEvent& event,
if (event.type() == ui::ET_TOUCH_RELEASED) {
DVLOG(1) << "GestureManager::ProcessTouchEventForGesture: TouchReleased";
- MouseEvent mouse_event(ui::ET_MOUSE_RELEASED, event.x(), event.y(),
+ MouseEvent mouse_event(ui::ET_MOUSE_RELEASED, location.x(), location.y(),
event.flags());
source->OnMouseReleased(mouse_event, false);
return true;
@@ -48,7 +58,7 @@ bool GestureManager::ProcessTouchEventForGesture(const TouchEvent& event,
if (event.type() == ui::ET_TOUCH_MOVED) {
DVLOG(1) << "GestureManager::ProcessTouchEventForGesture: TouchMotion";
- MouseEvent mouse_event(ui::ET_MOUSE_DRAGGED, event.x(), event.y(),
+ MouseEvent mouse_event(ui::ET_MOUSE_DRAGGED, location.x(), location.y(),
event.flags());
source->OnMouseDragged(mouse_event);
return true;
diff --git a/views/view.cc b/views/view.cc
index 8ffb77e..b36a3a4 100644
--- a/views/view.cc
+++ b/views/view.cc
@@ -10,12 +10,11 @@
#include "base/message_loop.h"
#include "base/scoped_ptr.h"
#include "base/utf_string_conversions.h"
-#include "third_party/skia/include/core/SkMatrix.h"
#include "third_party/skia/include/core/SkRect.h"
#include "ui/base/dragdrop/drag_drop_types.h"
#include "ui/gfx/canvas_skia.h"
#include "ui/gfx/path.h"
-#include "ui/gfx/skia_util.h"
+#include "ui/gfx/transform.h"
#include "views/background.h"
#include "views/layout/layout_manager.h"
#include "views/views_delegate.h"
@@ -61,8 +60,8 @@ View::View()
parent_(NULL),
is_visible_(true),
registered_for_visible_bounds_notification_(false),
- clip_x_(0),
- clip_y_(0),
+ clip_x_(0.0),
+ clip_y_(0.0),
needs_layout_(true),
flip_canvas_on_paint_for_rtl_ui_(false),
accelerator_registration_delayed_(false),
@@ -357,45 +356,66 @@ bool View::IsEnabled() const {
// Transformations -------------------------------------------------------------
-void View::SetRotation(double degree) {
+const ui::Transform& View::GetTransform() const {
+ static const ui::Transform* no_op = ui::Transform::Create();
+ if (transform_.get())
+ return *transform_.get();
+ return *no_op;
+}
+
+void View::SetRotation(float degree) {
+ InitTransform();
+ transform_->SetRotate(degree);
+}
+
+void View::SetScaleX(float x) {
InitTransform();
- transform_->setRotate(SkDoubleToScalar(degree),
- SkIntToScalar(0), SkIntToScalar(0));
+ transform_->SetScaleX(x);
}
-void View::SetScaleX(double x) {
+void View::SetScaleY(float y) {
InitTransform();
- transform_->setScaleX(SkDoubleToScalar(x));
+ transform_->SetScaleY(y);
}
-void View::SetScaleY(double y) {
+void View::SetScale(float x, float y) {
InitTransform();
- transform_->setScaleY(SkDoubleToScalar(y));
+ transform_->SetScale(x, y);
}
-void View::SetScale(double x, double y) {
+void View::SetTranslateX(float x) {
InitTransform();
- transform_->setScale(SkDoubleToScalar(x), SkDoubleToScalar(y));
+ transform_->SetTranslateX(x);
}
-void View::SetTranslateX(int x) {
+void View::SetTranslateY(float y) {
InitTransform();
- transform_->setTranslateX(SkIntToScalar(x));
+ transform_->SetTranslateY(y);
}
-void View::SetTranslateY(int y) {
+void View::SetTranslate(float x, float y) {
InitTransform();
- transform_->setTranslateY(SkIntToScalar(y));
+ transform_->SetTranslate(x, y);
}
-void View::SetTranslate(int x, int y) {
+void View::ConcatRotation(float degree) {
InitTransform();
- transform_->setTranslate(SkIntToScalar(x), SkIntToScalar(y));
+ transform_->ConcatRotate(degree);
+}
+
+void View::ConcatScale(float x, float y) {
+ InitTransform();
+ transform_->ConcatScale(x, y);
+}
+
+void View::ConcatTranslate(float x, float y) {
+ InitTransform();
+ transform_->ConcatTranslate(x, y);
}
void View::ResetTransform() {
transform_.reset(NULL);
- clip_x_ = clip_y_ = 0;
+ clip_x_ = clip_y_ = 0.0;
}
@@ -554,19 +574,15 @@ void View::ConvertPointToWidget(const View* src, gfx::Point* p) {
DCHECK(src);
DCHECK(p);
- gfx::Point offset;
- for (const View* v = src; v; v = v->parent()) {
- offset.set_x(offset.x() + v->GetMirroredX());
- offset.set_y(offset.y() + v->y());
- }
- p->SetPoint(p->x() + offset.x(), p->y() + offset.y());
+ src->ConvertPointForAncestor(NULL, p);
}
// static
void View::ConvertPointFromWidget(const View* dest, gfx::Point* p) {
- gfx::Point t;
- ConvertPointToWidget(dest, &t);
- p->SetPoint(p->x() - t.x(), p->y() - t.y());
+ DCHECK(dest);
+ DCHECK(p);
+
+ dest->ConvertPointFromAncestor(NULL, p);
}
// static
@@ -585,12 +601,55 @@ void View::ConvertPointToScreen(const View* src, gfx::Point* p) {
}
gfx::Rect View::ConvertRectToParent(const gfx::Rect& rect) const {
- if (!transform_.get() || transform_->isIdentity())
- return rect;
- SkRect src = gfx::RectToSkRect(rect);
- if (!transform_->mapRect(&src))
+ if (!transform_.get() || !transform_->HasChange())
return rect;
- return gfx::SkRectToRect(src);
+ gfx::Rect x_rect = rect;
+ transform_->TransformRect(&x_rect);
+ return x_rect;
+}
+
+bool View::ConvertPointForAncestor(const View* ancestor,
+ gfx::Point* point) const {
+ scoped_ptr<ui::Transform> trans(ui::Transform::Create());
+
+ // TODO(sad): Have some way of caching the transformation results.
+
+ const View* v = this;
+ for (; v && v != ancestor; v = v->parent()) {
+ if (v->GetTransform().HasChange()) {
+ if (!trans->ConcatTransform(v->GetTransform()))
+ return false;
+ }
+ trans->ConcatTranslate(static_cast<float>(v->GetMirroredX()),
+ static_cast<float>(v->y()));
+ }
+
+ if (trans->HasChange()) {
+ trans->TransformPoint(point);
+ }
+
+ return v == ancestor;
+}
+
+bool View::ConvertPointFromAncestor(const View* ancestor,
+ gfx::Point* point) const {
+ scoped_ptr<ui::Transform> trans(ui::Transform::Create());
+
+ const View* v = this;
+ for (; v && v != ancestor; v = v->parent()) {
+ if (v->GetTransform().HasChange()) {
+ if (!trans->ConcatTransform(v->GetTransform()))
+ return false;
+ }
+ trans->ConcatTranslate(static_cast<float>(v->GetMirroredX()),
+ static_cast<float>(v->y()));
+ }
+
+ if (trans->HasChange()) {
+ trans->TransformPointReverse(point);
+ }
+
+ return v == ancestor;
}
// Painting --------------------------------------------------------------------
@@ -627,13 +686,14 @@ void View::Paint(gfx::Canvas* canvas) {
// consideration whether or not the view uses a right-to-left layout so that
// we paint our view in its mirrored position if need be.
if (canvas->ClipRectInt(GetMirroredX(), y(),
- width() - clip_x_, height() - clip_y_)) {
+ width() - static_cast<int>(clip_x_),
+ height() - static_cast<int>(clip_y_))) {
// Non-empty clip, translate the graphics such that 0,0 corresponds to
// where this view is located (related to its parent).
canvas->TranslateInt(GetMirroredX(), y());
- if (transform_.get())
- canvas->AsCanvasSkia()->concat(*transform_.get());
+ if (transform_.get() && transform_->HasChange())
+ canvas->Transform(*transform_.get());
// If the View we are about to paint requested the canvas to be flipped, we
// should change the transform appropriately.
@@ -675,6 +735,11 @@ ThemeProvider* View::GetThemeProvider() const {
// Input -----------------------------------------------------------------------
View* View::GetViewForPoint(const gfx::Point& point) {
+ return GetEventHandlerForPoint(point, NULL);
+}
+
+View* View::GetEventHandlerForPoint(const gfx::Point& point,
+ gfx::Point* xpoint) {
// Walk the child Views recursively looking for the View that most
// tightly encloses the specified point.
for (int i = child_count() - 1; i >= 0; --i) {
@@ -685,8 +750,10 @@ View* View::GetViewForPoint(const gfx::Point& point) {
gfx::Point point_in_child_coords(point);
View::ConvertPointToView(this, child, &point_in_child_coords);
if (child->HitTest(point_in_child_coords))
- return child->GetViewForPoint(point_in_child_coords);
+ return child->GetEventHandlerForPoint(point_in_child_coords, xpoint);
}
+ if (xpoint)
+ xpoint->SetPoint(point.x(), point.y());
return this;
}
@@ -1323,10 +1390,8 @@ void View::RemoveDescendantToNotify(View* view) {
// Transformations -------------------------------------------------------------
void View::InitTransform() {
- if (!transform_.get()) {
- transform_.reset(new SkMatrix);
- transform_->reset();
- }
+ if (!transform_.get())
+ transform_.reset(ui::Transform::Create());
}
// Coordinate conversion -------------------------------------------------------
@@ -1340,27 +1405,9 @@ void View::ConvertPointToView(const View* src,
DCHECK(dst);
DCHECK(point);
- const View* v;
- gfx::Point offset;
-
- for (v = dst; v && v != src; v = v->parent())
- offset.SetPoint(offset.x() + v->GetMirroredX(), offset.y() + v->y());
-
- // The source was not found. The caller wants a conversion
- // from a view to a transitive parent.
- if (src && v == NULL && try_other_direction) {
- gfx::Point p;
- // note: try_other_direction is force to FALSE so we don't
- // end up in an infinite recursion should both src and dst
- // are not parented.
- ConvertPointToView(dst, src, &p, false);
- // since the src and dst are inverted, p should also be negated
- point->SetPoint(point->x() - p.x(), point->y() - p.y());
- } else {
- point->SetPoint(point->x() - offset.x(), point->y() - offset.y());
-
- // If src is NULL, sp is in the screen coordinate system
- if (src == NULL) {
+ if (src == NULL || src->Contains(dst)) {
+ dst->ConvertPointFromAncestor(src, point);
+ if (!src) {
const Widget* widget = dst->GetWidget();
if (widget) {
gfx::Rect b;
@@ -1368,6 +1415,13 @@ void View::ConvertPointToView(const View* src,
point->SetPoint(point->x() - b.x(), point->y() - b.y());
}
}
+ } else if (src && try_other_direction) {
+ if (!src->ConvertPointForAncestor(dst, point)) {
+ // |src| is not an ancestor of |dst|, and |dst| is not an ancestor of
+ // |src| either. At this stage, |point| is in the widget's coordinate
+ // system. So convert from the widget's to |dst|'s coordiante system now.
+ ConvertPointFromWidget(dst, point);
+ }
}
}
diff --git a/views/view.h b/views/view.h
index 490662d..eb7ff06 100644
--- a/views/view.h
+++ b/views/view.h
@@ -26,8 +26,6 @@
using ui::OSExchangeData;
-// TODO(sad): Use platform independent wrapper for transform matrix.
-class SkMatrix;
class ViewAccessibility;
namespace gfx {
@@ -38,6 +36,7 @@ class Path;
namespace ui {
class ThemeProvider;
+class Transform;
}
using ui::ThemeProvider;
@@ -331,25 +330,31 @@ class View : public AcceleratorTarget {
// Methods for setting transformations for a view (e.g. rotation, scaling).
- const SkMatrix* transform() { return transform_.get(); }
+ const ui::Transform& GetTransform() const;
// Clipping parameters. Clipping happens from the right and/or bottom. The
// clipping amount is in parent's coordinate system, as in, if the view is
// rotated, then the clipping will be applied after the rotation (and other
// transformations, if any).
- void set_clip_x(int x) { clip_x_ = x; }
- void set_clip_y(int y) { clip_y_ = y; }
- void set_clip(int x, int y) { clip_x_ = x; clip_y_ = y; }
+ void set_clip_x(float x) { clip_x_ = x; }
+ void set_clip_y(float y) { clip_y_ = y; }
+ void set_clip(float x, float y) { clip_x_ = x; clip_y_ = y; }
- void SetRotation(double degree);
+ void SetRotation(float degree);
- void SetScaleX(double x);
- void SetScaleY(double y);
- void SetScale(double x, double y);
+ void SetScaleX(float x);
+ void SetScaleY(float y);
+ void SetScale(float x, float y);
- void SetTranslateX(int x);
- void SetTranslateY(int y);
- void SetTranslate(int x, int y);
+ void SetTranslateX(float x);
+ void SetTranslateY(float y);
+ void SetTranslate(float x, float y);
+
+ // The following functions apply the transformations on top of the existing
+ // transform.
+ void ConcatRotation(float degree);
+ void ConcatScale(float x, float y);
+ void ConcatTranslate(float x, float y);
// Reset the transformation matrix.
void ResetTransform();
@@ -476,9 +481,9 @@ class View : public AcceleratorTarget {
// Convert a point from source coordinate system to dst coordinate system.
//
- // source is a parent or a child of dst, directly or transitively.
- // If source and dst are not in the same View hierarchy, the result is
- // undefined.
+ // |src| and |dst| needs to be in the same widget, but doesn't need to be in
+ // the same view hierarchy.
+ // If |src| and |dst| are not in the same widget, the result is undefined.
// Source can be NULL in which case it means the screen coordinate system
static void ConvertPointToView(const View* src,
const View* dst,
@@ -560,10 +565,18 @@ class View : public AcceleratorTarget {
}
// Input ---------------------------------------------------------------------
+ // The points (and mouse locations) in the following functions are in the
+ // view's coordinates, except for a RootView.
+ // TODO(sad): Remove
// Returns the deepest descendant that contains the specified point.
virtual View* GetViewForPoint(const gfx::Point& point);
+ // Returns the deepest descendant that contains the specified point, and the
+ // point in the returned view's coordinates.
+ virtual View* GetEventHandlerForPoint(const gfx::Point& point,
+ gfx::Point* xpoint);
+
// Return the cursor that should be used for this view or NULL if
// the default cursor should be used. The provided point is in the
// receiver's coordinate system. The caller is responsible for managing the
@@ -1227,16 +1240,28 @@ class View : public AcceleratorTarget {
// Initialize the transform matrix when necessary.
void InitTransform();
- // Coordinate conersion ------------------------------------------------------
+ // Coordinate conversion -----------------------------------------------------
// This is the actual implementation for ConvertPointToView()
// Attempts a parent -> child conversion and then a
// child -> parent conversion if try_other_direction is true
+ // Applies necessary transformations during the conversion.
static void ConvertPointToView(const View* src,
const View* dst,
gfx::Point* point,
bool try_other_direction);
+ // Convert a point in the view's coordinate to an ancestor view's coordinate
+ // system using necessary transformations. Returns whether the point was
+ // successfully converted to the ancestor's coordinate system.
+ bool ConvertPointForAncestor(const View* ancestor, gfx::Point* point) const;
+
+ // Convert a point in the ancestor's coordinate system to the view's
+ // coordinate system using necessary transformations. Returns whether the
+ // point was successfully from the ancestor's coordinate system to the view's
+ // coordinate system.
+ bool ConvertPointFromAncestor(const View* ancestor, gfx::Point* point) const;
+
// Input ---------------------------------------------------------------------
// RootView invokes these. These in turn invoke the appropriate OnMouseXXX
@@ -1328,12 +1353,12 @@ class View : public AcceleratorTarget {
// Transformations -----------------------------------------------------------
// The transformation matrix (rotation, translate, scale).
- scoped_ptr<SkMatrix> transform_;
+ scoped_ptr<ui::Transform> transform_;
// Clipping parameters. skia transformation matrix does not give us clipping.
// So we do it ourselves.
- int clip_x_;
- int clip_y_;
+ float clip_x_;
+ float clip_y_;
// Layout --------------------------------------------------------------------
diff --git a/views/view_unittest.cc b/views/view_unittest.cc
index 0d30b6c..74aadd5 100644
--- a/views/view_unittest.cc
+++ b/views/view_unittest.cc
@@ -1587,6 +1587,133 @@ TEST_F(ViewTest, TransformPaint) {
widget->CloseNow();
}
+TEST_F(ViewTest, TransformEvent) {
+ TestView* v1 = new TestView();
+ v1->SetBounds(0, 0, 500, 300);
+
+ TestView* v2 = new TestView();
+ v2->SetBounds(100, 100, 200, 100);
+
+ Widget* widget = CreateWidget();
+#if defined(OS_WIN)
+ WidgetWin* window_win = static_cast<WidgetWin*>(widget);
+ window_win->set_window_style(WS_OVERLAPPEDWINDOW);
+ window_win->Init(NULL, gfx::Rect(50, 50, 650, 650));
+#endif
+ RootView* root = widget->GetRootView();
+
+ root->AddChildView(v1);
+ v1->AddChildView(v2);
+
+ // At this moment, |v2| occupies (100, 100) to (300, 200) in |root|.
+
+ // Rotate |v1| counter-clockwise.
+ v1->SetRotation(-90.0);
+ v1->SetTranslateY(500);
+
+ // |v2| now occupies (100, 200) to (200, 400) in |root|.
+ v1->Reset();
+ v2->Reset();
+
+ MouseEvent pressed(ui::ET_MOUSE_PRESSED,
+ 110, 210,
+ ui::EF_LEFT_BUTTON_DOWN);
+ root->OnMousePressed(pressed);
+ EXPECT_EQ(0, v1->last_mouse_event_type_);
+ EXPECT_EQ(ui::ET_MOUSE_PRESSED, v2->last_mouse_event_type_);
+ EXPECT_EQ(190, v2->location_.x());
+ EXPECT_EQ(10, v2->location_.y());
+
+ MouseEvent released(ui::ET_MOUSE_RELEASED, 0, 0, 0);
+ root->OnMouseReleased(released, false);
+
+ // Now rotate |v2| inside |v1| clockwise.
+ v2->SetRotation(90.0);
+ v2->SetTranslateX(100);
+
+ // Now, |v2| occupies (100, 100) to (200, 300) in |v1|, and (100, 300) to
+ // (300, 400) in |root|.
+
+ v1->Reset();
+ v2->Reset();
+
+ MouseEvent p2(ui::ET_MOUSE_PRESSED,
+ 110, 320,
+ ui::EF_LEFT_BUTTON_DOWN);
+ root->OnMousePressed(p2);
+ EXPECT_EQ(0, v1->last_mouse_event_type_);
+ EXPECT_EQ(ui::ET_MOUSE_PRESSED, v2->last_mouse_event_type_);
+ EXPECT_EQ(10, v2->location_.x());
+ EXPECT_EQ(20, v2->location_.y());
+
+ root->OnMouseReleased(released, false);
+
+ v1->ResetTransform();
+ v2->ResetTransform();
+
+ TestView* v3 = new TestView();
+ v3->SetBounds(10, 10, 20, 30);
+ v2->AddChildView(v3);
+
+ // Rotate |v3| clockwise with respect to |v2|.
+ v3->SetRotation(90.0);
+ v3->SetTranslateX(30);
+
+ // Scale |v2| with respect to |v1| along both axis.
+ v2->SetScale(0.8, 0.5);
+
+ // |v3| occupies (108, 105) to (132, 115) in |root|.
+
+ v1->Reset();
+ v2->Reset();
+ v3->Reset();
+
+ MouseEvent p3(ui::ET_MOUSE_PRESSED,
+ 112, 110,
+ ui::EF_LEFT_BUTTON_DOWN);
+ root->OnMousePressed(p3);
+
+ EXPECT_EQ(ui::ET_MOUSE_PRESSED, v3->last_mouse_event_type_);
+ EXPECT_EQ(10, v3->location_.x());
+ EXPECT_EQ(25, v3->location_.y());
+
+ root->OnMouseReleased(released, false);
+
+ v1->ResetTransform();
+ v2->ResetTransform();
+ v3->ResetTransform();
+
+ v1->Reset();
+ v2->Reset();
+ v3->Reset();
+
+ // Rotate |v3| clockwise with respect to |v2|, and scale it along both axis.
+ v3->SetRotation(90.0);
+ v3->SetTranslateX(30);
+ // Rotation sets some scaling transformation. Using SetScale would overwrite
+ // that and pollute the rotation. So combine the scaling with the existing
+ // transforamtion.
+ v3->ConcatScale(0.8, 0.5);
+
+ // Translate |v2| with respect to |v1|.
+ v2->SetTranslate(10, 10);
+
+ // |v3| now occupies (120, 120) to (144, 130) in |root|.
+
+ MouseEvent p4(ui::ET_MOUSE_PRESSED,
+ 124, 125,
+ ui::EF_LEFT_BUTTON_DOWN);
+ root->OnMousePressed(p4);
+
+ EXPECT_EQ(ui::ET_MOUSE_PRESSED, v3->last_mouse_event_type_);
+ EXPECT_EQ(10, v3->location_.x());
+ EXPECT_EQ(25, v3->location_.y());
+
+ root->OnMouseReleased(released, false);
+
+ widget->CloseNow();
+}
+
////////////////////////////////////////////////////////////////////////////////
// OnVisibleBoundsChanged()
diff --git a/views/widget/root_view.cc b/views/widget/root_view.cc
index d7b9007..4919bf4 100644
--- a/views/widget/root_view.cc
+++ b/views/widget/root_view.cc
@@ -116,7 +116,8 @@ bool RootView::ProcessKeyEvent(const KeyEvent& event) {
return consumed;
}
-bool RootView::ProcessMouseWheelEvent(const MouseWheelEvent& e) {
+bool RootView::ProcessMouseWheelEvent(const MouseWheelEvent& event) {
+ MouseWheelEvent e(event, this);
View* v;
bool consumed = false;
View* focused_view = GetFocusManager()->GetFocusedView();
@@ -181,7 +182,9 @@ Widget* RootView::GetWidget() {
return const_cast<Widget*>(const_cast<const RootView*>(this)->GetWidget());
}
-bool RootView::OnMousePressed(const MouseEvent& e) {
+bool RootView::OnMousePressed(const MouseEvent& event) {
+ MouseEvent e(event, this);
+
// This function does not normally handle non-client messages except for
// non-client double-clicks. Actually, all double-clicks are special as the
// are formed from a single-click followed by a double-click event. When the
@@ -265,7 +268,8 @@ bool RootView::OnMousePressed(const MouseEvent& e) {
return hit_disabled_view;
}
-bool RootView::OnMouseDragged(const MouseEvent& e) {
+bool RootView::OnMouseDragged(const MouseEvent& event) {
+ MouseEvent e(event, this);
UpdateCursor(e);
if (mouse_pressed_handler_) {
@@ -279,7 +283,8 @@ bool RootView::OnMouseDragged(const MouseEvent& e) {
return false;
}
-void RootView::OnMouseReleased(const MouseEvent& e, bool canceled) {
+void RootView::OnMouseReleased(const MouseEvent& event, bool canceled) {
+ MouseEvent e(event, this);
UpdateCursor(e);
if (mouse_pressed_handler_) {
@@ -296,7 +301,8 @@ void RootView::OnMouseReleased(const MouseEvent& e, bool canceled) {
}
}
-void RootView::OnMouseMoved(const MouseEvent& e) {
+void RootView::OnMouseMoved(const MouseEvent& event) {
+ MouseEvent e(event, this);
View* v = GetViewForPoint(e.location());
// Find the first enabled view, or the existing move handler, whichever comes
// first. The check for the existing handler is because if a view becomes
@@ -344,7 +350,9 @@ void RootView::SetMouseHandler(View *new_mh) {
}
#if defined(TOUCH_UI)
-View::TouchStatus RootView::OnTouchEvent(const TouchEvent& e) {
+View::TouchStatus RootView::OnTouchEvent(const TouchEvent& event) {
+ TouchEvent e(event, this);
+
// If touch_pressed_handler_ is non null, we are currently processing
// a touch down on the screen situation. In that case we send the
// event to touch_pressed_handler_
diff --git a/views/widget/root_view.h b/views/widget/root_view.h
index df74ede..e38c686 100644
--- a/views/widget/root_view.h
+++ b/views/widget/root_view.h
@@ -149,10 +149,14 @@ class RootView : public View,
// Update the cursor given a mouse event. This is called by non mouse_move
// event handlers to honor the cursor desired by views located under the
- // cursor during drag operations.
+ // cursor during drag operations. The location of the mouse should be in the
+ // current coordinate system (i.e. any necessary transformation should be
+ // applied to the point prior to calling this).
void UpdateCursor(const MouseEvent& e);
- // Updates the last_mouse_* fields from e.
+ // Updates the last_mouse_* fields from e. The location of the mouse should be
+ // in the current coordinate system (i.e. any necessary transformation should
+ // be applied to the point prior to calling this).
void SetMouseLocationAndFlags(const MouseEvent& e);
//////////////////////////////////////////////////////////////////////////////