Commit 90a5d8bc authored by Raine Makelainen's avatar Raine Makelainen

Merge branch 'jb13614' into 'master'

Jb13614

Contains multiple commits:

1) Sync utils from Metro (gecko), needed bits

2) Sync SelectionPrototype/SelectionHandler from Metro (gecko)

3) Add line height info to messages

4) Snap selection to word when selecting non editable content

5) Reposition selection markers upon content reflow

6) Fix performance warnings by using Object.create instead of __proto__

7) Add selected text and search uri to the message data

8) Minor clean up commit that add empty message for "Content:SelectionSwap" topic

See merge request !29
parents 0c793e91 4a887038
......@@ -98,7 +98,9 @@ EmbedLiteSearchEngine.prototype = {
case "setdefault": {
var engine = Services.search.getEngineByName(data.name);
if (engine) {
// Update currentEngine as well when default search engine is updated.
Services.search.defaultEngine = engine;
Services.search.currentEngine = engine;
}
break;
}
......
......@@ -6,6 +6,7 @@ jsscripts_manifest_DATA = \
SelectHelper.js \
SelectAsyncHelper.js \
SelectionHandler.js \
SelectionPrototype.js \
Util.js \
ContextMenuHandler.js \
$(NULL)
......
This diff is collapsed.
This diff is collapsed.
......@@ -6,11 +6,14 @@ let Util = {
/*
* General purpose utilities
*/
getWindowUtils: function getWindowUtils(aWindow) {
return aWindow.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
},
fuzzyEquals: function fuzzyEquals(a, b) {
return (Math.abs(a - b) < 0.999);
},
// Recursively find all documents, including root document.
getAllDocuments: function getAllDocuments(doc, resultSoFar) {
resultSoFar = resultSoFar || [doc];
......@@ -185,6 +188,46 @@ let Util = {
aElement instanceof Ci.nsIDOMHTMLTextAreaElement);
},
/**
* Checks whether aElement's content can be edited either if it(or any of its
* parents) has "contenteditable" attribute set to "true" or aElement's
* ownerDocument is in design mode.
*/
isEditableContent: function isEditableContent(aElement) {
return !!aElement && (aElement.isContentEditable ||
this.isOwnerDocumentInDesignMode(aElement));
},
isEditable: function isEditable(aElement) {
if (!aElement) {
return false;
}
if (this.isTextInput(aElement) || this.isEditableContent(aElement)) {
return true;
}
// If a body element is editable and the body is the child of an
// iframe or div we can assume this is an advanced HTML editor
if ((aElement instanceof Ci.nsIDOMHTMLIFrameElement ||
aElement instanceof Ci.nsIDOMHTMLDivElement) &&
aElement.contentDocument &&
this.isEditableContent(aElement.contentDocument.body)) {
return true;
}
return false;
},
/**
* Checks whether aElement's owner document has design mode turned on.
*/
isOwnerDocumentInDesignMode: function(aElement) {
return !!aElement && !!aElement.ownerDocument &&
aElement.ownerDocument.designMode == "on";
},
isMultilineInput: function isMultilineInput(aElement) {
return (aElement instanceof Ci.nsIDOMHTMLTextAreaElement);
},
......@@ -406,6 +449,44 @@ let Util = {
//Services.obs.notifyObservers(download, "dl-start", null);
},
/*
* aViewHeight - the height of the viewable area in the browser
* aRect - a bounding rectangle of a selection or element.
*
* return - number of pixels for the browser to be shifted up by such
* that aRect is centered vertically within aViewHeight.
*/
centerElementInView: function centerElementInView(aViewHeight, aRect) {
// If the bottom of the target bounds is higher than the new height,
// there's no need to adjust. It will be above the keyboard.
if (aRect.bottom <= aViewHeight) {
return 0;
}
// height of the target element
let targetHeight = aRect.bottom - aRect.top;
// height of the browser view.
let viewBottom = content.innerHeight;
// If the target is shorter than the new content height, we can go ahead
// and center it.
if (targetHeight <= aViewHeight) {
// Try to center the element vertically in the new content area, but
// don't position such that the bottom of the browser view moves above
// the top of the chrome. We purposely do not resize the browser window
// by making it taller when trying to center elements that are near the
// lower bounds. This would trigger reflow which can cause content to
// shift around.
let splitMargin = Math.round((aViewHeight - targetHeight) * .5);
let distanceToPageBounds = viewBottom - aRect.bottom;
let distanceFromChromeTop = aRect.bottom - aViewHeight;
let distanceToCenter =
distanceFromChromeTop + Math.min(distanceToPageBounds, splitMargin);
return distanceToCenter;
}
},
/*
* Local system utilities
*/
......
......@@ -36,10 +36,6 @@ var gScreenHeight = 0;
const kEmbedStateActive = 0x00000001; // :active pseudoclass for elements
function fuzzyEquals(a, b) {
return (Math.abs(a - b) < 0.999);
}
function EmbedHelper() {
this.contentDocumentIsDisplayed = true;
// Reasonable default. Will be read from preferences.
......@@ -502,7 +498,7 @@ EmbedHelper.prototype = {
rect.h = fixedCurrentViewport.height;
// Are we really zooming.
aAllowZoom = !fuzzyEquals(rect.w, this._viewportData.cssCompositedRect.width)
aAllowZoom = !Util.fuzzyEquals(rect.w, this._viewportData.cssCompositedRect.width)
if (aAllowZoom) {
var winid = Services.embedlite.getIDByWindow(content);
......@@ -675,12 +671,75 @@ EmbedHelper.prototype = {
oldVpHeight = oldVpHeight / scaleFactor;
vpHeight = vpHeight / scaleFactor;
this.vkbOpen = fuzzyEquals(oldVpHeight - vpHeight, this.vkbOpenCompositionMetrics.bottomMargin / 2);
this.vkbOpen = Util.fuzzyEquals(oldVpHeight - vpHeight, this.vkbOpenCompositionMetrics.bottomMargin / 2);
return this.vkbOpen;
}
return false;
},
virtualKeyboardHeight: function() {
return this.isVirtualKeyboardOpen() ? (this.vkbOpenCompositionMetrics.bottomMargin / content.devicePixelRatio) : 0
},
/******************************************************
* General utilities
*/
/*
* Retrieve the total offset from the window's origin to the sub frame
* element including frame and scroll offsets. The resulting offset is
* such that:
* sub frame coords + offset = root frame position
*/
getCurrentWindowAndOffset: function(x, y) {
// If the element at the given point belongs to another document (such
// as an iframe's subdocument), the element in the calling document's
// DOM (e.g. the iframe) is returned.
let utils = Util.getWindowUtils(content);
let element = utils.elementFromPoint(x, y, true, false);
let offset = { x:0, y:0 };
while (element && (element instanceof HTMLIFrameElement ||
element instanceof HTMLFrameElement)) {
// get the child frame position in client coordinates
let rect = element.getBoundingClientRect();
// calculate offsets for digging down into sub frames
// using elementFromPoint:
// Get the content scroll offset in the child frame
let scrollOffset = ContentScroll.getScrollOffset(element.contentDocument.defaultView);
// subtract frame and scroll offset from our elementFromPoint coordinates
x -= rect.left + scrollOffset.x;
y -= rect.top + scrollOffset.y;
// calculate offsets we'll use to translate to client coords:
// add frame client offset to our total offset result
offset.x += rect.left;
offset.y += rect.top;
// get the frame's nsIDOMWindowUtils
utils = element.contentDocument
.defaultView
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils);
// retrieve the target element in the sub frame at x, y
element = utils.elementFromPoint(x, y, true, false);
}
if (!element)
return {};
return {
element: element,
contentWindow: element.ownerDocument.defaultView,
offset: offset,
utils: utils
};
},
_dumpViewport: function() {
dump("--------------- Viewport data ----------------------- \n")
this._dumpObject(this._viewportData)
......@@ -863,6 +922,77 @@ var ViewportHandler = {
},
};
// Ported from Metro code base. SHA1 554eff3a212d474f5a883
let ContentScroll = {
// The most recent offset set by APZC for the root scroll frame
_scrollOffset: { x: 0, y: 0 },
init: function() {
addMessageListener("Content:SetWindowSize", this);
addEventListener("pagehide", this, false);
addEventListener("MozScrolledAreaChanged", this, false);
},
getScrollOffset: function(aWindow) {
let cwu = aWindow.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
let scrollX = {}, scrollY = {};
cwu.getScrollXY(false, scrollX, scrollY);
return { x: scrollX.value, y: scrollY.value };
},
getScrollOffsetForElement: function(aElement) {
if (aElement.parentNode == aElement.ownerDocument)
return this.getScrollOffset(aElement.ownerDocument.defaultView);
return { x: aElement.scrollLeft, y: aElement.scrollTop };
},
receiveMessage: function(aMessage) {
let json = aMessage.json;
switch (aMessage.name) {
case "Content:SetWindowSize": {
let cwu = content.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
cwu.setCSSViewport(json.width, json.height);
sendAsyncMessage("Content:SetWindowSize:Complete", {});
break;
}
}
},
handleEvent: function(aEvent) {
switch (aEvent.type) {
case "pagehide":
this._scrollOffset = { x: 0, y: 0 };
break;
case "MozScrolledAreaChanged": {
let doc = aEvent.originalTarget;
if (content != doc.defaultView) // We are only interested in root scroll pane changes
return;
sendAsyncMessage("MozScrolledAreaChanged", {
width: aEvent.width,
height: aEvent.height,
left: aEvent.x + content.scrollX
});
// Send event only after painting to make sure content views in the parent process have
// been updated.
addEventListener("MozAfterPaint", function afterPaint() {
removeEventListener("MozAfterPaint", afterPaint, false);
sendAsyncMessage("Content:UpdateDisplayPort");
}, false);
break;
}
}
}
};
this.ContentScroll = ContentScroll;
ContentScroll.init();
/**
* An object which represents the page's preferred viewport properties:
* width (int): The CSS viewport width in px.
......@@ -917,6 +1047,7 @@ ViewportMetadata.prototype = {
Services.scriptloader.loadSubScript("chrome://embedlite/content/Util.js");
Services.scriptloader.loadSubScript("chrome://embedlite/content/ContextMenuHandler.js");
Services.scriptloader.loadSubScript("chrome://embedlite/content/SelectionPrototype.js");
Services.scriptloader.loadSubScript("chrome://embedlite/content/SelectionHandler.js");
globalObject = new EmbedHelper();
......
......@@ -68,6 +68,7 @@ ln -s $(pwd)/jsscripts/TelURIParser.jsm $TARGET_DIR/chrome/embedlite/content/Tel
ln -s $(pwd)/jsscripts/SelectHelper.js $TARGET_DIR/chrome/embedlite/content/SelectHelper.js;
ln -s $(pwd)/jsscripts/SelectAsyncHelper.js $TARGET_DIR/chrome/embedlite/content/SelectAsyncHelper.js;
ln -s $(pwd)/jsscripts/SelectionHandler.js $TARGET_DIR/chrome/embedlite/content/SelectionHandler.js;
ln -s $(pwd)/jsscripts/SelectionPrototype.js $TARGET_DIR/chrome/embedlite/content/SelectionPrototype.js;
ln -s $(pwd)/jsscripts/Util.js $TARGET_DIR/chrome/embedlite/content/Util.js;
ln -s $(pwd)/jsscripts/ContextMenuHandler.js $TARGET_DIR/chrome/embedlite/content/ContextMenuHandler.js;
ln -s $(pwd)/search-engines/google.xml $TARGET_DIR/chrome/embedlite/content/google.xml;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment