summaryrefslogtreecommitdiff
path: root/Source/WebCore/Modules/modern-media-controls/gesture-recognizers/gesture-recognizer.js
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebCore/Modules/modern-media-controls/gesture-recognizers/gesture-recognizer.js')
-rw-r--r--Source/WebCore/Modules/modern-media-controls/gesture-recognizers/gesture-recognizer.js379
1 files changed, 379 insertions, 0 deletions
diff --git a/Source/WebCore/Modules/modern-media-controls/gesture-recognizers/gesture-recognizer.js b/Source/WebCore/Modules/modern-media-controls/gesture-recognizers/gesture-recognizer.js
new file mode 100644
index 000000000..c1ec8572a
--- /dev/null
+++ b/Source/WebCore/Modules/modern-media-controls/gesture-recognizers/gesture-recognizer.js
@@ -0,0 +1,379 @@
+
+class GestureRecognizer
+{
+
+ constructor(target = null, delegate = null)
+ {
+ this._targetTouches = [];
+
+ this.modifierKeys = {
+ alt : false,
+ ctrl : false,
+ meta : false,
+ shift : false
+ };
+
+ this._state = GestureRecognizer.States.Possible;
+ this._enabled = true;
+
+ this.target = target;
+ this.delegate = delegate;
+ }
+
+ // Public
+
+ get state()
+ {
+ return this._state;
+ }
+
+ set state(state)
+ {
+ if (this._state === state && state !== GestureRecognizer.States.Changed)
+ return;
+
+ this._state = state;
+ if (this.delegate && typeof this.delegate.gestureRecognizerStateDidChange === "function")
+ this.delegate.gestureRecognizerStateDidChange(this);
+ }
+
+ get target()
+ {
+ return this._target;
+ }
+
+ set target(target)
+ {
+ if (!target || this._target === target)
+ return;
+
+ this._target = target;
+ this._initRecognizer();
+ }
+
+ get numberOfTouches()
+ {
+ return this._targetTouches.length;
+ }
+
+ get enabled()
+ {
+ return this._enabled;
+ }
+
+ set enabled(enabled)
+ {
+ if (this._enabled === enabled)
+ return;
+
+ this._enabled = enabled;
+
+ if (!enabled) {
+ if (this.numberOfTouches === 0) {
+ this._removeTrackingListeners();
+ this.reset();
+ } else
+ this.enterCancelledState();
+ }
+
+ this._updateBaseListeners();
+ }
+
+ reset()
+ {
+ // Implemented by subclasses.
+ }
+
+ locationInElement(element)
+ {
+ const p = new DOMPoint;
+ const touches = this._targetTouches;
+ const count = touches.length;
+ for (let i = 0; i < count; ++i) {
+ const touch = touches[i];
+ p.x += touch.pageX;
+ p.y += touch.pageY;
+ }
+ p.x /= count;
+ p.y /= count;
+
+ if (!element)
+ return p;
+
+ // FIXME: are WebKitPoint and DOMPoint interchangeable?
+ const wkPoint = window.webkitConvertPointFromPageToNode(element, new WebKitPoint(p.x, p.y));
+ return new DOMPoint(wkPoint.x, wkPoint.y);
+ }
+
+ locationInClient()
+ {
+ const p = new DOMPoint;
+ const touches = this._targetTouches;
+ const count = touches.length;
+ for (let i = 0; i < count; ++i) {
+ const touch = touches[i];
+ p.x += touch.clientX;
+ p.y += touch.clientY;
+ }
+ p.x /= count;
+ p.y /= count;
+
+ return p;
+ }
+
+ locationOfTouchInElement(touchIndex, element)
+ {
+ const touch = this._targetTouches[touchIndex];
+ if (!touch)
+ return new DOMPoint;
+
+ const touchLocation = new DOMPoint(touch.pageX, touch.pageY);
+ if (!element)
+ return touchLocation;
+
+ // FIXME: are WebKitPoint and DOMPoint interchangeable?
+ const wkPoint = window.webkitConvertPointFromPageToNode(element, new WebKitPoint(touchLocation.x, touchLocation.y));
+ return new DOMPoint(wkPoint.x, wkPoint.y);
+ }
+
+ touchesBegan(event)
+ {
+ if (event.currentTarget !== this._target)
+ return;
+
+ window.addEventListener(GestureRecognizer.Events.TouchMove, this, true);
+ window.addEventListener(GestureRecognizer.Events.TouchEnd, this, true);
+ window.addEventListener(GestureRecognizer.Events.TouchCancel, this, true);
+ this.enterPossibleState();
+ }
+
+ touchesMoved(event)
+ {
+ // Implemented by subclasses.
+ }
+
+ touchesEnded(event)
+ {
+ // Implemented by subclasses.
+ }
+
+ touchesCancelled(event)
+ {
+ // Implemented by subclasses.
+ }
+
+ gestureBegan(event)
+ {
+ if (event.currentTarget !== this._target)
+ return;
+
+ window.addEventListener(GestureRecognizer.Events.GestureChange, this, true);
+ window.addEventListener(GestureRecognizer.Events.GestureEnd, this, true);
+ this.enterPossibleState();
+ }
+
+ gestureChanged(event)
+ {
+ // Implemented by subclasses.
+ }
+
+ gestureEnded(event)
+ {
+ // Implemented by subclasses.
+ }
+
+ enterPossibleState()
+ {
+ this.state = GestureRecognizer.States.Possible;
+ }
+
+ enterBeganState()
+ {
+ if (this.delegate && typeof this.delegate.gestureRecognizerShouldBegin === "function" && !this.delegate.gestureRecognizerShouldBegin(this)) {
+ this.enterFailedState();
+ return;
+ }
+ this.state = GestureRecognizer.States.Began;
+ }
+
+ enterEndedState()
+ {
+ this.state = GestureRecognizer.States.Ended;
+ this._removeTrackingListeners();
+ this.reset();
+ }
+
+ enterCancelledState()
+ {
+ this.state = GestureRecognizer.States.Cancelled;
+ this._removeTrackingListeners();
+ this.reset();
+ }
+
+ enterFailedState()
+ {
+ this.state = GestureRecognizer.States.Failed;
+ this._removeTrackingListeners();
+ this.reset();
+ }
+
+ enterChangedState()
+ {
+ this.state = GestureRecognizer.States.Changed;
+ }
+
+ enterRecognizedState()
+ {
+ this.state = GestureRecognizer.States.Recognized;
+ }
+
+ // Protected
+
+ handleEvent(event)
+ {
+ this._updateTargetTouches(event);
+ this._updateKeyboardModifiers(event);
+
+ switch (event.type) {
+ case GestureRecognizer.Events.TouchStart:
+ this.touchesBegan(event);
+ break;
+ case GestureRecognizer.Events.TouchMove:
+ this.touchesMoved(event);
+ break;
+ case GestureRecognizer.Events.TouchEnd:
+ this.touchesEnded(event);
+ break;
+ case GestureRecognizer.Events.TouchCancel:
+ this.touchesCancelled(event);
+ break;
+ case GestureRecognizer.Events.GestureStart:
+ this.gestureBegan(event);
+ break;
+ case GestureRecognizer.Events.GestureChange:
+ this.gestureChanged(event);
+ break;
+ case GestureRecognizer.Events.GestureEnd:
+ this.gestureEnded(event);
+ break;
+ }
+ }
+
+ // Private
+
+ _initRecognizer()
+ {
+ this.reset();
+ this.state = GestureRecognizer.States.Possible;
+
+ this._updateBaseListeners();
+ }
+
+ _updateBaseListeners()
+ {
+ if (!this._target)
+ return;
+
+ if (this._enabled) {
+ this._target.addEventListener(GestureRecognizer.Events.TouchStart, this);
+ if (GestureRecognizer.SupportsGestures)
+ this._target.addEventListener(GestureRecognizer.Events.GestureStart, this);
+ } else {
+ this._target.removeEventListener(GestureRecognizer.Events.TouchStart, this);
+ if (GestureRecognizer.SupportsGestures)
+ this._target.removeEventListener(GestureRecognizer.Events.GestureStart, this);
+ }
+ }
+
+ _removeTrackingListeners()
+ {
+ window.removeEventListener(GestureRecognizer.Events.TouchMove, this, true);
+ window.removeEventListener(GestureRecognizer.Events.TouchEnd, this, true);
+ window.removeEventListener(GestureRecognizer.Events.GestureChange, this, true);
+ window.removeEventListener(GestureRecognizer.Events.GestureEnd, this, true);
+ }
+
+ _updateTargetTouches(event)
+ {
+ if (!GestureRecognizer.SupportsTouches) {
+ if (event.type === GestureRecognizer.Events.TouchEnd)
+ this._targetTouches = [];
+ else
+ this._targetTouches = [event];
+ return;
+ }
+
+ if (!(event instanceof TouchEvent))
+ return;
+
+ // With a touchstart event, event.targetTouches is accurate so
+ // we simply add all of those.
+ if (event.type === GestureRecognizer.Events.TouchStart) {
+ this._targetTouches = [];
+ let touches = event.targetTouches;
+ for (let i = 0, count = touches.length; i < count; ++i)
+ this._targetTouches.push(touches[i]);
+ return;
+ }
+
+ // With a touchmove event, the target is window so event.targetTouches is
+ // inaccurate so we add all touches that we knew about previously.
+ if (event.type === GestureRecognizer.Events.TouchMove) {
+ let targetIdentifiers = this._targetTouches.map(function(touch) {
+ return touch.identifier;
+ });
+
+ this._targetTouches = [];
+ let touches = event.touches;
+ for (let i = 0, count = touches.length; i < count; ++i) {
+ let touch = touches[i];
+ if (targetIdentifiers.indexOf(touch.identifier) !== -1)
+ this._targetTouches.push(touch);
+ }
+ return;
+ }
+
+ // With a touchend or touchcancel event, we only keep the existing touches
+ // that are also found in event.touches.
+ let allTouches = event.touches;
+ let existingIdentifiers = [];
+ for (let i = 0, count = allTouches.length; i < count; ++i)
+ existingIdentifiers.push(allTouches[i].identifier);
+
+ this._targetTouches = this._targetTouches.filter(function(touch) {
+ return existingIdentifiers.indexOf(touch.identifier) !== -1;
+ });
+ }
+
+ _updateKeyboardModifiers(event)
+ {
+ this.modifierKeys.alt = event.altKey;
+ this.modifierKeys.ctrl = event.ctrlKey;
+ this.modifierKeys.meta = event.metaKey;
+ this.modifierKeys.shift = event.shiftKey;
+ }
+
+}
+
+GestureRecognizer.SupportsTouches = "createTouch" in document;
+GestureRecognizer.SupportsGestures = !!window.GestureEvent;
+
+GestureRecognizer.States = {
+ Possible : "possible",
+ Began : "began",
+ Changed : "changed",
+ Ended : "ended",
+ Cancelled : "cancelled",
+ Failed : "failed",
+ Recognized : "ended"
+};
+
+GestureRecognizer.Events = {
+ TouchStart : GestureRecognizer.SupportsTouches ? "touchstart" : "mousedown",
+ TouchMove : GestureRecognizer.SupportsTouches ? "touchmove" : "mousemove",
+ TouchEnd : GestureRecognizer.SupportsTouches ? "touchend" : "mouseup",
+ TouchCancel : "touchcancel",
+ GestureStart : "gesturestart",
+ GestureChange : "gesturechange",
+ GestureEnd : "gestureend"
+};