diff --git a/chrome/content/InputHandler.js b/chrome/content/InputHandler.js --- a/chrome/content/InputHandler.js +++ b/chrome/content/InputHandler.js @@ -450,26 +450,25 @@ function KineticData(owner) { function KineticData(owner) { this._owner = owner; this.kineticHandle = -1; this.reset(); } KineticData.prototype = { reset: function reset() { + dump("kineticData.reset()\n"); if (this.kineticHandle != -1) { window.clearTimeout(this.kineticHandle); this.kineticHandle = -1; } this.stepSize = 30; this.decelloration = 0.004; - this.momentumBufferSize = 3; this.momentumBuffer = []; - this.momentumBufferIndex = 0; this.lastTime = 0; this.duration = 0; this.dirX = 0; this.dirY = 0; this.step = 0; this.stepStart = 0; this.startX = 0; this.startY = 0; @@ -478,27 +477,42 @@ KineticData.prototype = { startKinetic: function startKinetic(sX, sY) { let dx = 0; let dy = 0; let dt = 0; if (this.initialVel != 0) return true; - if (!this.momentumBuffer) + dump("kinetic buffer:\n"); + let mb = this.momentumBuffer; + let mblen = this.momentumBuffer.length; + + if (mblen < 2) return false; - for (let i = 0; i < this.momentumBufferSize; i++) { - let me = this.momentumBuffer[(this.momentumBufferIndex + i) % this.momentumBufferSize]; - if (!me) - return false; + let sX = mb[0].sx; + let sY = mb[0].sy; - dx += me.dx; - dy += me.dy; + dump(mb[0].toSource() + "\n"); + + for (let i = 1; i < mblen; i++) { + let me = mb[i]; + + dump(" - " + me.toSource() + "\n"); + + dump((sX - me.sx) + " = " + sX + " - " + me.sx + "\n"); + dump((sY - me.sy) + " = " + sY + " - " + me.sy + "\n"); + + dx += (sX - me.sx); + dy += (sY - me.sy); dt += me.dt; + + sX = me.sx; + sY = me.sy; } if (dt <= 0) return false; let dist = Math.sqrt(dx*dx+dy*dy); let vel = dist/dt; if (vel < 1) return false; @@ -579,63 +593,99 @@ KineticData.prototype = { let w = document.getElementById("browser-controls").getBoundingClientRect().width; if (rightVis >= 0.6666) ws.panBy(w, 0, true); else ws.panBy(-rightVis * w, 0, true); } }, - addData: function addData(dx, dy) { - if (dx == 0 && dy == 0) - return; - + addData: function addData(sX, sY) { let t = Date.now(); let dt = this.lastTime ? t - this.lastTime : 0; + let mbLength = this.momentumBuffer.length; + if (mbLength > 0) { + let mbLast = this.momentumBuffer[mbLength - 1]; + if (mbLast.sx == sX && mbLast.sy == sY) + return; + } + this.lastTime = t; - this.momentumBuffer[this.momentumBufferIndex] = { 'dx': dx, 'dy': dy, 'dt': dt }; - this.momentumBufferIndex++; - this.momentumBufferIndex %= this.momentumBufferSize; + this.momentumBuffer.push({'dt': dt, 'sx' : sX, 'sy' : sY}); } }; function ContentPanningModule(owner, browserCanvas, useKinetic) { this._owner = owner; if (useKinetic !== undefined) this._useKinetic = useKinetic; this._browserCanvas = browserCanvas; - this._dragData = new DragData(this, 20, 200); + this._dragData = new DragData(this, 10, 200); this._kineticData = new KineticData(this); } ContentPanningModule.prototype = { _owner: null, _dragData: null, _useKinetic: true, _kineticData: null, handleEvent: function handleEvent(aEvent) { // exit early for events outside displayed content area if (aEvent.target !== this._browserCanvas) return; + dump(aEvent.type + " " + aEvent.screenX + ", " + aEvent.screenY + "\n"); + + switch (aEvent.type) { case "mousedown": this._onMouseDown(aEvent); break; case "mousemove": this._onMouseMove(aEvent); break; case "mouseup": this._onMouseUp(aEvent); break; } }, + + + + /* returns true if we go ahead and start a drag */ + detectEarlyDrag: function detectEarlyDrag() { + let dragData = this._dragData; + + if (dragData.dragging) + return; + + dump("detectEarlyDrag:\n"); + + let mb = this._kineticData.momentumBuffer; + if (mb.length < 2) + return; + + let mbFirst = mb[0]; + let mbLast = mb[mb.length - 1]; + + let dx = mbFirst.sx - mbLast.sx; + let dy = mbFirst.sy - mbLast.sy; + + if (dragData.dragStartTimeout != -1) { + if ((dx*dx + dy*dy) > (dragData._dragRadius * dragData._dragRadius)) { + dragData.clearDragStartTimeout(); + dragData._owner._dragStart(mbFirst.sx, mbFirst.sy); + dump(" - starting drag\n"); + } + } + }, + /* If someone else grabs events ahead of us, cancel any pending * timeouts we may have. */ cancelPending: function cancelPending() { let dragData = this._dragData; // stop scrolling, pass last coordinate we used this._kineticData.endKinetic(dragData.sX, dragData.sY); @@ -663,18 +713,20 @@ ContentPanningModule.prototype = { let dragData = this._dragData; this._owner.ungrab(this); [sX, sY] = dragData.lockMouseMove(sX, sY); if (this._useKinetic) { // start kinetic scrolling here for canvas only + try { if (!this._kineticData.startKinetic(sX, sY)) this._kineticData.endKinetic(sX, sY); + } catch (ex){ dump(ex +"\n"); } dragData.reset(); } else { ws.dragStop(); // flush any paints that might be left so that our next pan will be fast Browser.canvasBrowser.endPanning(); } }, @@ -721,24 +773,22 @@ ContentPanningModule.prototype = { // if we never received a mouseDown, we need to go ahead and set this data if (!dragData.sX) dragData.setDragPosition(aEvent.screenX, aEvent.screenY); let [sX, sY] = dragData.lockMouseMove(aEvent.screenX, aEvent.screenY); // even if we haven't started dragging yet, we should queue up the // mousemoves in case we do start - if (this._useKinetic) { - // update our kinetic data - let dx = dragData.sX - sX; - let dy = dragData.sY - sY; - this._kineticData.addData(-dx, -dy); - } + if (this._useKinetic) + this._kineticData.addData(sX, sY); - dragData.detectEarlyDrag(sX, sY); + this.detectEarlyDrag(); + + //dragData.detectEarlyDrag(sX, sY); if (dragData.dragging) this._dragMove(sX, sY); }, }; /** * Mouse click handlers