зеркало из https://github.com/mozilla/gecko-dev.git
Bug 862054 - Get rid of ElementTouchHelper and our custom elementFromPoint function. r=mbrubeck
This commit is contained in:
Родитель
ce05f3ebe2
Коммит
6e28ade960
|
@ -46,161 +46,6 @@ const kReferenceDpi = 240; // standard "pixel" size used in some preferences
|
|||
|
||||
const kStateActive = 0x00000001; // :active pseudoclass for elements
|
||||
|
||||
/*
|
||||
* ElementTouchHelper
|
||||
*
|
||||
* Assists users by watching for mouse clicks in content and redirect
|
||||
* them to the best found target.
|
||||
*/
|
||||
const ElementTouchHelper = {
|
||||
get radius() {
|
||||
let prefs = Services.prefs;
|
||||
delete this.radius;
|
||||
return this.radius = { "top": prefs.getIntPref("ui.touch.radius.topmm"),
|
||||
"right": prefs.getIntPref("ui.touch.radius.rightmm"),
|
||||
"bottom": prefs.getIntPref("ui.touch.radius.bottommm"),
|
||||
"left": prefs.getIntPref("ui.touch.radius.leftmm")
|
||||
};
|
||||
},
|
||||
|
||||
get weight() {
|
||||
delete this.weight;
|
||||
return this.weight = { "visited": Services.prefs.getIntPref("ui.touch.radius.visitedWeight")
|
||||
};
|
||||
},
|
||||
|
||||
/* Retrieve the closest element to a point by looking at borders position */
|
||||
getClosest: function getClosest(aWindowUtils, aX, aY) {
|
||||
if (!this.dpiRatio)
|
||||
this.dpiRatio = aWindowUtils.displayDPI / kReferenceDpi;
|
||||
|
||||
let dpiRatio = this.dpiRatio;
|
||||
|
||||
let target = aWindowUtils.elementFromPoint(aX, aY,
|
||||
true, /* ignore root scroll frame*/
|
||||
false); /* don't flush layout */
|
||||
|
||||
// return early if the click is just over a clickable element
|
||||
if (this._isElementClickable(target))
|
||||
return target;
|
||||
|
||||
let nodes = aWindowUtils.nodesFromRect(aX, aY, this.radius.top * dpiRatio,
|
||||
this.radius.right * dpiRatio,
|
||||
this.radius.bottom * dpiRatio,
|
||||
this.radius.left * dpiRatio, true, false);
|
||||
|
||||
let threshold = Number.POSITIVE_INFINITY;
|
||||
for (let i = 0; i < nodes.length; i++) {
|
||||
let current = nodes[i];
|
||||
if (!current.mozMatchesSelector || !this._isElementClickable(current))
|
||||
continue;
|
||||
|
||||
let rect = current.getBoundingClientRect();
|
||||
let distance = this._computeDistanceFromRect(aX, aY, rect);
|
||||
|
||||
// increase a little bit the weight for already visited items
|
||||
if (current && current.mozMatchesSelector("*:visited"))
|
||||
distance *= (this.weight.visited / 100);
|
||||
|
||||
if (distance < threshold) {
|
||||
target = current;
|
||||
threshold = distance;
|
||||
}
|
||||
}
|
||||
|
||||
return target;
|
||||
},
|
||||
|
||||
_isElementClickable: function _isElementClickable(aElement) {
|
||||
const selector = "a,:link,:visited,[role=button],button,input,select,textarea,label";
|
||||
for (let elem = aElement; elem; elem = elem.parentNode) {
|
||||
if (this._hasMouseListener(elem))
|
||||
return true;
|
||||
if (elem.mozMatchesSelector && elem.mozMatchesSelector(selector))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
_computeDistanceFromRect: function _computeDistanceFromRect(aX, aY, aRect) {
|
||||
let x = 0, y = 0;
|
||||
let xmost = aRect.left + aRect.width;
|
||||
let ymost = aRect.top + aRect.height;
|
||||
|
||||
// compute horizontal distance from left/right border depending if X is
|
||||
// before/inside/after the element's rectangle
|
||||
if (aRect.left < aX && aX < xmost)
|
||||
x = Math.min(xmost - aX, aX - aRect.left);
|
||||
else if (aX < aRect.left)
|
||||
x = aRect.left - aX;
|
||||
else if (aX > xmost)
|
||||
x = aX - xmost;
|
||||
|
||||
// compute vertical distance from top/bottom border depending if Y is
|
||||
// above/inside/below the element's rectangle
|
||||
if (aRect.top < aY && aY < ymost)
|
||||
y = Math.min(ymost - aY, aY - aRect.top);
|
||||
else if (aY < aRect.top)
|
||||
y = aRect.top - aY;
|
||||
if (aY > ymost)
|
||||
y = aY - ymost;
|
||||
|
||||
return Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
|
||||
},
|
||||
|
||||
_els: Cc["@mozilla.org/eventlistenerservice;1"].getService(Ci.nsIEventListenerService),
|
||||
_clickableEvents: ["mousedown", "mouseup", "click"],
|
||||
_hasMouseListener: function _hasMouseListener(aElement) {
|
||||
let els = this._els;
|
||||
let listeners = els.getListenerInfoFor(aElement, {});
|
||||
for (let i = 0; i < listeners.length; i++) {
|
||||
if (this._clickableEvents.indexOf(listeners[i].type) != -1)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Global functions
|
||||
*/
|
||||
|
||||
/*
|
||||
* elementFromPoint - find the closes element at a point. searches
|
||||
* sub-frames.
|
||||
*
|
||||
* @param aX, aY browser coordinates
|
||||
* @return
|
||||
* element - element at the position, or null if no active browser or
|
||||
* element was found.
|
||||
* frameX - x position within the subframe element was found. aX if no
|
||||
* sub-frame was found.
|
||||
* frameY - y position within the subframe element was found. aY if no
|
||||
* sub-frame was found.
|
||||
*/
|
||||
function elementFromPoint(aX, aY) {
|
||||
// browser's elementFromPoint expect browser-relative client coordinates.
|
||||
// subtract browser's scroll values to adjust
|
||||
let cwu = Util.getWindowUtils(content);
|
||||
let elem = ElementTouchHelper.getClosest(cwu, aX, aY);
|
||||
|
||||
// step through layers of IFRAMEs and FRAMES to find innermost element
|
||||
while (elem && (elem instanceof HTMLIFrameElement ||
|
||||
elem instanceof HTMLFrameElement)) {
|
||||
// adjust client coordinates' origin to be top left of iframe viewport
|
||||
let rect = elem.getBoundingClientRect();
|
||||
aX -= rect.left;
|
||||
aY -= rect.top;
|
||||
let windowUtils = elem.contentDocument
|
||||
.defaultView
|
||||
.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindowUtils);
|
||||
elem = ElementTouchHelper.getClosest(windowUtils, aX, aY);
|
||||
}
|
||||
return { element: elem, frameX: aX, frameY: aY };
|
||||
}
|
||||
|
||||
/*
|
||||
* getBoundingContentRect
|
||||
*
|
||||
|
@ -349,8 +194,7 @@ let Content = {
|
|||
break;
|
||||
|
||||
case "touchstart":
|
||||
let touch = aEvent.changedTouches[0];
|
||||
this._onTouchStart(touch.clientX, touch.clientY);
|
||||
this._onTouchStart(aEvent);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
@ -403,10 +247,8 @@ let Content = {
|
|||
* Event handlers
|
||||
*/
|
||||
|
||||
_onTouchStart: function _onTouchStart(x, y) {
|
||||
let { element } = elementFromPoint(x, y);
|
||||
if (!element)
|
||||
return;
|
||||
_onTouchStart: function _onTouchStart(aEvent) {
|
||||
let element = aEvent.target;
|
||||
|
||||
// There is no need to have a feedback for disabled element
|
||||
let isDisabled = element instanceof HTMLOptionElement ?
|
||||
|
@ -419,11 +261,9 @@ let Content = {
|
|||
},
|
||||
|
||||
_onClickCapture: function _onClickCapture(aEvent) {
|
||||
ContextMenuHandler.reset();
|
||||
let element = aEvent.target;
|
||||
|
||||
let { element: element } = elementFromPoint(aEvent.clientX, aEvent.clientY);
|
||||
if (!element)
|
||||
return;
|
||||
ContextMenuHandler.reset();
|
||||
|
||||
// Only show autocomplete after the item is clicked
|
||||
if (!this.lastClickElement || this.lastClickElement != element) {
|
||||
|
|
Загрузка…
Ссылка в новой задаче