diff --git a/src/tool/Tool.js b/src/tool/Tool.js
index 0508b19b..6def20f0 100644
--- a/src/tool/Tool.js
+++ b/src/tool/Tool.js
@@ -286,7 +286,7 @@ var Tool = PaperScopeItem.extend(/** @lends Tool# */{
      *     least one event handler was called and none of the called handlers
      *     wants to enforce the default.
      */
-    _handleEvent: function(type, event, point) {
+    _handleEvent: function(type, event, point, mouse) {
         // Update global reference to this scope.
         paper = this._scope;
         var minDistance = this.minDistance,
@@ -303,11 +303,7 @@ var Tool = PaperScopeItem.extend(/** @lends Tool# */{
             matchMaxDistance = false,
             called = false, // Has at least one handler been called?
             enforced = false, // Does a handler want to enforce the default?
-            tool = this,
-            mouse = {};
-        // Create a simple lookup object to quickly check for different
-        // mouse event types.
-        mouse[type.substr(5)] = true;
+            tool = this;
 
         function update(start, minDistance, maxDistance) {
             var toolPoint = tool._point,
diff --git a/src/view/View.js b/src/view/View.js
index a3a1a8ca..106e933f 100644
--- a/src/view/View.js
+++ b/src/view/View.js
@@ -698,7 +698,8 @@ new function() { // Injection scope for mouse events on the browser
 
     var prevFocus,
         tempFocus,
-        mouseDown = false;
+        dragging = false, // mousedown that started on a view.
+        mouseDown = false; // mouesdown anywhere.
 
     function getView(event) {
         // Get the view from the current event target.
@@ -782,7 +783,7 @@ new function() { // Injection scope for mouse events on the browser
         // Get the view from the event, and store a reference to the view that
         // should receive keyboard input.
         var view = View._focused = getView(event);
-        mouseDown = true;
+        dragging = true;
         view._handleEvent('mousedown', event);
     };
 
@@ -792,13 +793,12 @@ new function() { // Injection scope for mouse events on the browser
             // See if we can get the view from the current event target, and
             // handle the mouse move over it.
             var target = getView(event);
-            if (target) {
+            if (target && view !== target) {
                 // Temporarily focus this view without making it sticky, so Key
                 // events are handled too during the mouse over.
-                // If we switch view, fire one last mousemove in the old view,
+                // As we switch view, fire one last mousemove in the old view,
                 // to give items the change to receive a mouseleave, etc.
-                if (view !== target)
-                    handleMouseMove(view, event);
+                handleMouseMove(view, event);
                 prevFocus = view;
                 view = View._focused = tempFocus = target;
             } else if (tempFocus && tempFocus === view) {
@@ -811,11 +811,18 @@ new function() { // Injection scope for mouse events on the browser
             handleMouseMove(view, event);
     };
 
+    docEvents[mousedown] = function(event) {
+        // In order to not switch views during scroll dragging on touch devices,
+        // we need to know if the mouse was clicked anywhere on the document
+        // (see docEvents[mousemove]) The rest happens in viewEvents[mousedown].
+        mouseDown = true;
+    };
+
     docEvents[mouseup] = function(event) {
         var view = View._focused;
-        if (view && mouseDown)
+        if (view && dragging)
             view._handleEvent('mouseup', event);
-        mouseDown = false;
+        mouseDown = dragging = false;
     };
 
     DomEvent.add(document, docEvents);
@@ -938,7 +945,8 @@ new function() { // Injection scope for mouse events on the browser
         clickItem,
         clickTime,
         dblClick,
-        overView;
+        overView,
+        wasInView = false;
 
     return {
         _viewEvents: viewEvents,
@@ -954,7 +962,7 @@ new function() { // Injection scope for mouse events on the browser
             // it to a mousedrag.
             // NOTE: emitEvent(), as well as Tool#_handleEvent() fall back to
             // mousemove if the objects don't respond to mousedrag.
-            if (type === 'mousemove' && mouseDown)
+            if (type === 'mousemove' && dragging)
                 type = 'mousedrag';
             // Before handling events, process removeOn() calls for cleanup.
             if (project)
@@ -963,14 +971,16 @@ new function() { // Injection scope for mouse events on the browser
                 point = this.getEventPoint(event);
             // Run the hit-test on items first, but only if we're required to do
             // so for this given mouse event, see #_countItemEvent().
-            var hit = handleItems && this._project.hitTest(point, {
+            var inView = this.getBounds().contains(point),
+                hit = inView && handleItems && this._project.hitTest(point, {
                     tolerance: 0,
                     fill: true,
                     stroke: true
                 }),
                 item = hit && hit.item || undefined,
-                inView = this.getBounds().contains(point),
-                wasInView = this === overView,
+                // Keep track if view event should be handled, so we can use it
+                // to decide if tool._handleEvent() shall be called after.
+                handle = false,
                 stopped = false,
                 mouse = {};
             // Create a simple lookup object to quickly check for different
@@ -981,9 +991,8 @@ new function() { // Injection scope for mouse events on the browser
             // Handle mousemove first, even if this is not actually a mousemove
             // event but the mouse has moved since the last event, but do not
             // allow it to stop the other events in that case.
-            var nativeMove = mouse.move || mouse.drag;
-                moveType = nativeMove && type
-                    || lastPoint && !lastPoint.equals(point) && 'mousemove';
+            var nativeMove = mouse.move || mouse.drag,
+                moveType = nativeMove && type || 'mousemove';
             if (moveType) {
                 // Handle mouseenter / leave between items, as well as views.
                 if (item !== overItem) {
@@ -997,14 +1006,25 @@ new function() { // Injection scope for mouse events on the browser
                     emitEvent(this, inView ? 'mouseenter' : 'mouseleave', event,
                             point);
                     overView = inView ? this : null;
+                    handle = nativeMove; // To include the leaving move.
                 }
-                if (inView || mouse.drag && !lastPoint.equals(point))
+                if (inView || mouse.drag && !lastPoint.equals(point)) {
                     stopped = emitEvents(this, item, moveType, event, point,
                             lastPoint);
+                    handle = nativeMove;
+                }
+                wasInView = inView;
             }
-            if (!nativeMove) {
-               // Now handle mousedown / mouseup
+            // Now handle mousedown / mouseup
+            if (!nativeMove &&
+                    // We emit mousedown only when in the view, and mouseup
+                    // regardless, as long as the mousedown event was inside.
+                    (handle = mouse.down && inView || mouse.up && !!downPoint)) {
                 stopped = emitEvents(this, item, type, event, point, downPoint);
+                // Clear wasInView so we're not accidentally handling mousedrag
+                // events that started outside the view as mousemove events on
+                // the view (needed to handle touch scrolling correctly).
+                wasInView = false;
                 if (mouse.down) {
                     // See if we're clicking again on the same item, within the
                     // double-click time. Firefox uses 300ms as the max time
@@ -1034,8 +1054,7 @@ new function() { // Injection scope for mouse events on the browser
             // to only be fired if we're inside the view or if we just left it.
             // Prevent default if at least one handler was called, and none of
             // them enforces default, to prevent scrolling on touch devices.
-            if (tool && (mouse.move || inView || wasInView)
-                    && tool._handleEvent(type, event, point)
+            if (handle && tool && tool._handleEvent(type, event, point, mouse)
                     || called && !enforced)
                 event.preventDefault();
             // In the end we always call update(), which only updates the view