diff --git a/app/mobile.js b/app/mobile.js --- a/app/mobile.js +++ b/app/mobile.js @@ -48,18 +48,18 @@ pref("toolkit.screen.lock", false); pref("zoom.minPercent", 20); pref("zoom.maxPercent", 400); pref("toolkit.zoomManager.zoomValues", ".2,.3,.5,.67,.8,.9,1,1.1,1.2,1.33,1.5,1.7,2,2.4,3,4"); pref("zoom.dpiScale", 150); /* use custom widget for html:select */ pref("ui.use_native_popup_windows", true); -pref("javascript.options.showInConsole", false); -pref("browser.dom.window.dump.enabled", false); +pref("javascript.options.showInConsole", true); +pref("browser.dom.window.dump.enabled", true); /* cache prefs */ pref("browser.cache.disk.enable", false); pref("browser.cache.disk.capacity", 0); // kilobytes pref("browser.cache.memory.enable", true); pref("browser.cache.memory.capacity", 1024); // kilobytes diff --git a/chrome/content/BrowserView.js b/chrome/content/BrowserView.js --- a/chrome/content/BrowserView.js +++ b/chrome/content/BrowserView.js @@ -177,25 +177,27 @@ BrowserView.Util = { let html = cdoc.documentElement || {}; let w = Math.max(body.scrollWidth || 1, html.scrollWidth); let h = Math.max(body.scrollHeight || 1, html.scrollHeight); return [w, h]; }, getContentScrollOffset: function getContentScrollOffset(browser) { + dump("calling getBrowserDOMWindowUtils from getContentScrollOffset\n") let cwu = BrowserView.Util.getBrowserDOMWindowUtils(browser); let scrollX = {}; let scrollY = {}; cwu.getScrollXY(false, scrollX, scrollY); return new Point(scrollX.value, scrollY.value); }, getBrowserDOMWindowUtils: function getBrowserDOMWindowUtils(browser) { + dump("getBrowserDOMWindowUtils\n") return browser.contentWindow .QueryInterface(Ci.nsIInterfaceRequestor) .getInterface(Ci.nsIDOMWindowUtils); }, getNewBatchOperationState: function getNewBatchOperationState() { return { viewportSizeChanged: false, @@ -475,17 +477,17 @@ BrowserView.prototype = { let browserChanged = (oldBrowser !== browser); if (oldBrowser) { oldBrowser.setAttribute("type", "content"); oldBrowser.messageManager.sendAsyncMessage("Browser:Blur", {}); } this._browser = browser; - this._contentWindow = (browser) ? browser.contentWindow : null; + this._contentWindow = null;// XXX (browser) ? browser.contentWindow : null; this._browserViewportState = browserViewportState; if (browser) { browser.setAttribute("type", "content-primary"); browser.messageManager.sendAsyncMessage("Browser:Focus", {}); this.beginBatchOperation(); @@ -793,22 +795,16 @@ BrowserView.prototype = { this._applyViewportChanges(viewportSizeChanged, dirtyAll); }, _applyViewportChanges: function _applyViewportChanges(viewportSizeChanged, dirtyAll) { let bvs = this._browserViewportState; if (bvs) { BrowserView.Util.resizeContainerToViewport(this._container, bvs.viewportRect); - if (dirtyAll) { - // We're about to mark the entire viewport dirty, so we can clear any - // queued afterPaint events that will cause redundant draws - BrowserView.Util.getBrowserDOMWindowUtils(this._browser).clearMozAfterPaintEvents(); - } - let vr = this.getVisibleRect(); this._tileManager.viewportChangeHandler(bvs.viewportRect, BrowserView.Util.visibleRectToCriticalRect(vr, bvs), viewportSizeChanged, dirtyAll); let rects = vr.subtract(bvs.viewportRect); this._tileManager.clearRects(rects); diff --git a/chrome/content/TileManager.js.in b/chrome/content/TileManager.js.in --- a/chrome/content/TileManager.js.in +++ b/chrome/content/TileManager.js.in @@ -376,18 +376,21 @@ TileManager.prototype = { /** * Render a rect to the canvas under the given scale. We attempt to avoid a * drawWindow() by copying the image (via drawImage()) from cached tiles, we * may have. If we find that we're missing a necessary tile, we fall back on * drawWindow() directly to the destination canvas. */ renderRectToCanvas: function renderRectToCanvas(srcRect, destCanvas, scalex, scaley, drawMissing) { + let bv = this._browserView; let tc = this._tileCache; - let ctx = destCanvas.getContext("2d"); + + let ctx = bv._contentWindow ? destCanvas.getContext("2d") : destCanvas.MozGetIPCContext("2d"); +/* drawMissing = drawMissing == false ? false : true; if (!drawMissing) { let pat = ctx.createPattern(this._checkerboard, "repeat"); ctx.fillStyle = pat; ctx.fillRect(0, 0, destCanvas.width, destCanvas.height); } ctx.save(); ctx.scale(scalex, scaley); @@ -405,49 +408,44 @@ TileManager.prototype = { } END_FOREACH_IN_RECT return true; })(); ctx.restore(); - +*/ + + let completed = false; if (!completed) { - let bv = this._browserView; - bv.viewportToBrowserRect(srcRect); ctx.save(); bv.browserToViewportCanvasContext(ctx); ctx.scale(scalex, scaley); - ctx.drawWindow(bv._contentWindow, - srcRect.left, srcRect.top, srcRect.width, srcRect.height, - "white", - (ctx.DRAWWINDOW_DO_NOT_FLUSH | ctx.DRAWWINDOW_DRAW_CARET)); + if (bv._contentWindow) { + ctx.drawWindow(bv._contentWindow, + srcRect.left, srcRect.top, srcRect.width, srcRect.height, + "white", + (ctx.DRAWWINDOW_DO_NOT_FLUSH | ctx.DRAWWINDOW_DRAW_CARET)); + } else { + ctx.asyncDrawXULElement(bv._browser, + srcRect.left, srcRect.top, srcRect.width, srcRect.height, + "white", + (ctx.DRAWWINDOW_DO_NOT_FLUSH | ctx.DRAWWINDOW_DRAW_CARET)); + } ctx.restore(); } }, _showTile: function _showTile(tile) { if (tile.isDirty()) { -/* - let ctx = tile._canvas.getContext("2d"); - ctx.save(); - ctx.fillStyle = "rgba(0,255,0,.5)"; - ctx.translate(-tile.boundRect.left, -tile.boundRect.top); - ctx.fillRect(tile._dirtyTileCanvasRect.left, tile._dirtyTileCanvasRect.top, - tile._dirtyTileCanvasRect.width, tile._dirtyTileCanvasRect.height); - ctx.restore(); - window.setTimeout(function(bv) { - tile.render(bv); - }, 1000, this._browserView); - */ tile.render(this._browserView); } this._appendTileSafe(tile); }, _appendTileSafe: function _appendTileSafe(tile) { if (!tile.appended) { this._appendTile(tile); @@ -796,28 +794,40 @@ TileManager.Tile.prototype = { this.markDirty(); let rect = this._dirtyTileCanvasRect; let x = rect.left - this.boundRect.left; let y = rect.top - this.boundRect.top; browserView.viewportToBrowserRect(rect); - let ctx = this._canvas.getContext("2d"); + let ctx = browserView._contentWindow ? this._canvas.getContext("2d") : this._canvas.MozGetIPCContext("2d"); ctx.save(); ctx.translate(x, y); browserView.browserToViewportCanvasContext(ctx); - // We expand the rect to working around a gfx issue (bug 534054) - ctx.drawWindow(browserView._contentWindow, - rect.left , rect.top, - rect.right - rect.left + 1, rect.bottom - rect.top + 1, - "white", - (ctx.DRAWWINDOW_DRAW_CARET)); - + + if (browserView._contentWindow) { + // We expand the rect to working around a gfx issue (bug 534054) + ctx.drawWindow(browserView._contentWindow, + rect.left , rect.top, + rect.right - rect.left + 1, rect.bottom - rect.top + 1, + "white", + (ctx.DRAWWINDOW_DRAW_CARET)); + } else { + try { + ctx.asyncDrawXULElement(browserView._browser, + rect.left , rect.top, + rect.right - rect.left + 1, rect.bottom - rect.top + 1, + "white", + (ctx.DRAWWINDOW_DRAW_CARET)); + } catch (e) { + dump(e + "\n") + } + } ctx.restore(); this.unmarkDirty(); }, /** * Standard toString prints "Tile(, )", but if `more' flags true * then some extra information is printed. diff --git a/chrome/content/bindings/browser.xml b/chrome/content/bindings/browser.xml --- a/chrome/content/bindings/browser.xml +++ b/chrome/content/bindings/browser.xml @@ -404,17 +404,17 @@ null + onget="debugger; throw 'contentWindow: Not Remoteable'"/> diff --git a/chrome/content/browser.js b/chrome/content/browser.js --- a/chrome/content/browser.js +++ b/chrome/content/browser.js @@ -50,19 +50,16 @@ let Ci = Components.interfaces; let Cu = Components.utils; function getBrowser() { return Browser.selectedBrowser; } const kDefaultBrowserWidth = 800; -// how many milliseconds before the mousedown and the overlay of an element -const kTapOverlayTimeout = 200; - // Override sizeToContent in the main window. It breaks things (bug 565887) window.sizeToContent = function() { Components.utils.reportError("window.sizeToContent is not allowed in this window"); } #ifdef MOZ_CRASH_REPORTER XPCOMUtils.defineLazyServiceGetter(this, "CrashReporter", "@mozilla.org/xre/app-info;1", "nsICrashReporter"); @@ -425,20 +422,21 @@ var Browser = { let dpiScale = gPrefService.getIntPref("zoom.dpiScale") / 100; Browser.styles["viewport-width"].width = (w / dpiScale) + "px"; Browser.styles["viewport-height"].height = (h / dpiScale) + "px"; Browser.styles["window-width"].width = w + "px"; Browser.styles["window-height"].height = h + "px"; Browser.styles["toolbar-height"].height = toolbarHeight + "px"; - // Cause a resize of the viewport if the current browser holds a XUL document - let browser = Browser.selectedBrowser; - if (browser.contentDocument instanceof XULDocument) - BrowserView.Util.ensureMozScrolledAreaEvent(browser, w, h); + // XXX e10s + //// Cause a resize of the viewport if the current browser holds a XUL document + //let browser = Browser.selectedBrowser; + //if (browser.contentDocument instanceof XULDocument) + // BrowserView.Util.ensureMozScrolledAreaEvent(browser, w, h); // Tell the UI to resize the browser controls BrowserUI.sizeControls(w, h); // XXX During the launch, the resize of the window arrive after we add // the first tab, so we need to force the viewport state for this case // see bug 558840 let bvs = bv._browserViewportState; @@ -679,16 +677,18 @@ var Browser = { scrollContentToTop: function scrollContentToTop() { this.contentScrollboxScroller.scrollTo(0, 0); this.pageScrollboxScroller.scrollTo(0, 0); this._browserView.onAfterVisibleMove(); }, /** Let current browser's scrollbox know about where content has been panned. */ scrollBrowserToContent: function scrollBrowserToContent() { + dump("scrollBrowserToContent\n") + return; //XXX let browser = this.selectedBrowser; if (browser) { let scroll = Browser.getScrollboxPosition(Browser.contentScrollboxScroller); let windowUtils = BrowserView.Util.getBrowserDOMWindowUtils(browser); browser.contentWindow.scrollTo(scroll.x, scroll.y); } }, @@ -723,20 +723,20 @@ var Browser = { get selectedBrowser() { return this._selectedTab.browser; }, get tabs() { return this._tabs; }, - getTabForDocument: function(aDocument) { + getTabForWindow: function getTabForWindow(aWindowId) { let tabs = this._tabs; for (let i = 0; i < tabs.length; i++) { - if (tabs[i].browser.contentDocument == aDocument) + if (tabs[i].browser.contentWindowId == aWindowId) return tabs[i]; } return null; }, getTabForBrowser: function getTabForBrowser(aBrowser) { let tabs = this._tabs; for (let i = 0; i < tabs.length; i++) { @@ -830,17 +830,17 @@ var Browser = { // Lock the toolbar if the new tab is still loading if (this._selectedTab.isLoading()) BrowserUI.lockToolbar(); tab.ensureBrowserExists(); bv.beginBatchOperation(); - +dump("tab.bvs: " + tab.browserViewportState + "\n") bv.setBrowser(tab.browser, tab.browserViewportState); bv.forceContainerResize(); bv.updateDefaultZoom(); document.getElementById("tabs").selectedTab = tab.chromeTab; if (!isFirstTab) { // Update all of our UI to reflect the new tab's location @@ -1220,72 +1220,16 @@ var Browser = { if (!bv.isDefaultZoom()) { let zoomLevel = bv.getDefaultZoomLevel(); let [elementX, elementY] = this.transformClientToBrowser(cX, cY); let zoomRect = this._getZoomRectForPoint(elementX, elementY, zoomLevel); this.setVisibleRect(zoomRect); } }, - getContentClientRects: function getContentClientRects(contentElem) { - // XXX don't copy getBoundingContentRect - let browser = Browser._browserView.getBrowser(); - - if (!browser) - return null; - - let offset = BrowserView.Util.getContentScrollOffset(browser); - let nativeRects = contentElem.getClientRects(); - - // step out of iframes and frames, offsetting scroll values - let rect; - let cw = browser.contentWindow; - for (let frame = contentElem.ownerDocument.defaultView; frame != cw; frame = frame.parent) { - // adjust client coordinates' origin to be top left of iframe viewport - rect = frame.frameElement.getBoundingClientRect(); - let left = frame.getComputedStyle(frame.frameElement, "").borderLeftWidth; - let top = frame.getComputedStyle(frame.frameElement, "").borderTopWidth; - offset.add(rect.left + parseInt(left), rect.top + parseInt(top)); - } - - let result = []; - let r; - for (let i = nativeRects.length - 1; i >= 0; i--) { - r = nativeRects[i]; - result.push(new Rect(r.left + offset.x, r.top + offset.y, r.width, r.height)); - } - return result; - }, - - getBoundingContentRect: function getBoundingContentRect(contentElem) { - let document = contentElem.ownerDocument; - while(document.defaultView.frameElement) - document = document.defaultView.frameElement.ownerDocument; - - let tab = Browser.getTabForDocument(document); - if (!tab || !tab.browser) - return null; - - let browser = tab.browser; - let offset = BrowserView.Util.getContentScrollOffset(browser); - - let r = contentElem.getBoundingClientRect(); - - // step out of iframes and frames, offsetting scroll values - for (let frame = contentElem.ownerDocument.defaultView; frame != browser.contentWindow; frame = frame.parent) { - // adjust client coordinates' origin to be top left of iframe viewport - let rect = frame.frameElement.getBoundingClientRect(); - let left = frame.getComputedStyle(frame.frameElement, "").borderLeftWidth; - let top = frame.getComputedStyle(frame.frameElement, "").borderTopWidth; - offset.add(rect.left + parseInt(left), rect.top + parseInt(top)); - } - - return new Rect(r.left + offset.x, r.top + offset.y, r.width, r.height); - }, - /** * Transform x and y from client coordinates to BrowserView coordinates. */ clientToBrowserView: function clientToBrowserView(x, y) { let container = document.getElementById("tile-container"); let containerBCR = container.getBoundingClientRect(); let x0 = Math.round(containerBCR.left); @@ -1322,16 +1266,21 @@ var Browser = { return this.clientToBrowserView(cX, cY).map(this._browserView.viewportToBrowser); }, /** * @param x,y Browser coordinates * @return Element at position, null if no active browser or no element found */ elementFromPoint: function elementFromPoint(x, y) { + // TODO e10s: remove all chrome process references to elementFromPoint + // + dump("elementFromPoint called\n") + return null; + let browser = this._browserView.getBrowser(); if (!browser) return null; // browser's elementFromPoint expect browser-relative client coordinates. // subtract browser's scroll values to adjust let cwu = BrowserView.Util.getBrowserDOMWindowUtils(browser); let scrollX = {}, scrollY = {}; @@ -1408,31 +1357,24 @@ Browser.MainDragger = function MainDragg this.draggedFrame = null; this.contentScrollbox = null; }; Browser.MainDragger.prototype = { isDraggable: function isDraggable(target, scroller) { return true; }, dragStart: function dragStart(clientX, clientY, target, scroller) { - // Make sure pausing occurs before any early returns. - this.bv.pauseRendering(); - - // XXX shouldn't know about observer - // adding pause in pauseRendering isn't so great, because tiles will hardly ever prefetch while - // loading state is going (and already, the idle timer is bigger during loading so it doesn't fit - // into the aggressive flag). - this.bv._idleServiceObserver.pause(); - - let [x, y] = Browser.transformClientToBrowser(clientX, clientY); - let element = Browser.elementFromPoint(x, y); + this._nextRender = Date.now() + 500; + this._dragMoved = false; this.draggedFrame = null; this.contentScrollbox = null; + return; // XXX e10s + // Check if we are in a scrollable HTML element let htmlElement = element; if (htmlElement && htmlElement instanceof HTMLElement) { let win = htmlElement.ownerDocument.defaultView; for (; htmlElement; htmlElement = htmlElement.parentNode) { try { let cs = win.getComputedStyle(htmlElement, null); let overflowX = cs.getPropertyValue("overflow-x"); @@ -1475,60 +1417,73 @@ Browser.MainDragger.prototype = { }, dragStop: function dragStop(dx, dy, scroller) { this.draggedFrame = null; this.dragMove(Browser.snapSidebars(), 0, scroller); Browser.tryUnfloatToolbar(); - this.bv.resumeRendering(); - - // XXX shouldn't know about observer - this.bv._idleServiceObserver.resume(); + if (this._dragMoved) { + this.bv.resumeRendering(); + // XXX shouldn't know about observer + this.bv._tileManager.setPrefetch(true); + } }, dragMove: function dragMove(dx, dy, scroller) { let elem = this.draggedFrame; let doffset = new Point(dx, dy); let render = false; + if (!this._dragMoved) { + this._dragMoved = true; + this.bv.pauseRendering(); + // XXX shouldn't know about observer + // adding pause in pauseRendering isn't so great, because tiles will hardly ever prefetch while + // loading state is going (and already, the idle timer is bigger during loading so it doesn't fit + // into the aggressive flag). + this.bv._tileManager.setPrefetch(false); + } + // First calculate any panning to take sidebars out of view let panOffset = this._panControlsAwayOffset(doffset); - // do HTML overflow or XUL panning - if (this.contentScrollbox && !doffset.isZero()) { - this._panScrollbox(this.contentScrollbox, doffset); - render = true; - } - - // Do all iframe panning - if (elem) { - while (elem.frameElement && !doffset.isZero()) { - this._panFrame(elem, doffset); - elem = elem.frameElement; - render = true; - } - } + //// do HTML overflow or XUL panning + //if (this.contentScrollbox && !doffset.isZero()) { + // this._panScrollbox(this.contentScrollbox, doffset); + // render = true; + //} + // + //// Do all iframe panning + //if (elem) { + // while (elem.frameElement && !doffset.isZero()) { + // this._panFrame(elem, doffset); + // elem = elem.frameElement; + // render = true; + // } + //} // Do content panning this._panScroller(Browser.contentScrollboxScroller, doffset); // Any leftover panning in doffset would bring controls into view. Add to sidebar // away panning for the total scroll offset. doffset.add(panOffset); Browser.tryFloatToolbar(doffset.x, 0); this._panScroller(Browser.controlsScrollboxScroller, doffset); this._panScroller(Browser.pageScrollboxScroller, doffset); this.bv.onAfterVisibleMove(); - if (render) + if (Date.now() >= this._nextRender) { this.bv.renderNow(); - + this._nextRender = Date.now() + 500; + } + return !doffset.equals(dx, dy); }, /** * builds a minimal implementation of scrollBoxObject for div */ _createDivScrollBox: function(div) { let sbo = { @@ -1814,156 +1769,59 @@ function ContentCustomClicker(browserVie this._overlay = document.getElementById("content-overlay"); this._overlayTimeout = 0; this._width = 0; this._height = 0; } ContentCustomClicker.prototype = { /** Dispatch a mouse event with chrome client coordinates. */ - _dispatchMouseEvent: function _dispatchMouseEvent(element, name, cX, cY) { + _dispatchMouseEvent: function _dispatchMouseEvent(name, cX, cY) { let browser = this._browserView.getBrowser(); if (browser) { let [x, y] = Browser.transformClientToBrowser(cX, cY); - let cwu = BrowserView.Util.getBrowserDOMWindowUtils(browser); - let scrollX = {}, scrollY = {}; - cwu.getScrollXY(false, scrollX, scrollY); - - // the element can be out of the cX/cY point because of the touch radius - // ignore the redirection if the element is a HTMLHtmlElement (bug 562981) - let rect = Browser.getBoundingContentRect(element); - if (!rect.isEmpty() && !(element instanceof HTMLHtmlElement) && - ((x < rect.left || (x > rect.left + rect.width)) || (y < rect.top || (y > rect.top + rect.height)))) { - - let point = rect.center(); - x = point.x; - y = point.y; - } - - x = x - scrollX.value; - y = y - scrollY.value; - cwu.sendMouseEvent(name, x, y, 0, 1, 0, true); - } - }, - - /** Returns a node if selecting this node causes a focus. */ - _getFocusable: function _getFocusable(node) { - if (node && node.mozMatchesSelector("*:link,*:visited,*:link *,*:visited *,*[role=button],button,input,option,select,textarea,label")) - return node; - return null; - }, - - _showCanvas: function _showCanvas(cX, cY) { - // This code is sensitive to performance. Please profile changes you make to - // keep this running fast. - let bv = this._browserView; - let overlay = this._overlay; - let ctx = overlay.getContext("2d"); - let [elementX, elementY] = Browser.transformClientToBrowser(cX, cY); - let element = this._getFocusable(Browser.elementFromPoint(elementX, elementY)); - if (!element) - return; - - let rects = Browser.getContentClientRects(element); - let union = rects.reduce(function(a, b) { - return a.expandToContain(b); - }, new Rect(0, 0, 0, 0)).map(bv.browserToViewport); - - let vis = Browser.getVisibleRect(); - let canvasArea = vis.intersect(union); - this._ensureSize(canvasArea.width, canvasArea.height); - - ctx.save(); - ctx.translate(-canvasArea.left, -canvasArea.top); - bv.browserToViewportCanvasContext(ctx); - - overlay.style.left = canvasArea.left + "px"; - overlay.style.top = canvasArea.top + "px"; - ctx.fillStyle = "rgba(0, 145, 255, .5)"; - let rect; - let i; - for (i = rects.length - 1; i >= 0; i--) { - rect = rects[i]; - ctx.fillRect(rect.left, rect.top, rect.width, rect.height); - } - ctx.restore(); - overlay.style.display = "block"; - }, - - /** Stop highlighting current element. */ - _hideCanvas: function _hideCanvas() { - let overlay = this._overlay; - overlay.style.display = "none"; - overlay.getContext("2d").clearRect(0, 0, this._width, this._height); - - if (this._overlayTimeout) { - clearTimeout(this._overlayTimeout); - this._overlayTimeout = 0; - } - }, - - /** Make sure canvas is at least width x height. */ - _ensureSize: function _ensureSize(width, height) { - if (this._width <= width) { - this._width = width; - this._overlay.width = width; - } - if (this._height <= height) { - this._height = height; - this._overlay.height = height; + browser.messageManager.sendAsyncMessage(name, { x: x, y: y} ); } }, mouseDown: function mouseDown(cX, cY) { - if (!this._overlayTimeout) - this._overlayTimeout = setTimeout(function(self) { self._showCanvas(cX, cY); }, kTapOverlayTimeout, this); + // Ensure that the content process has gets an activate event + let browser = this._browserView.getBrowser(); + if (browser) { + let fl = browser.QueryInterface(Ci.nsIFrameLoaderOwner).frameLoader; + try { + fl.activateRemoteFrame(); + } catch (e) {} + } + this._dispatchMouseEvent("Browser:MouseDown", cX, cY); }, mouseUp: function mouseUp(cX, cY) { }, panBegin: function panBegin() { - this._hideCanvas(); + let browser = this._browserView.getBrowser(); + browser.messageManager.sendAsyncMessage("Browser:MouseCancel", {}); }, singleClick: function singleClick(cX, cY, modifiers) { - this._hideCanvas(); + this._dispatchMouseEvent("Browser:MouseUp", cX, cY); - let [elementX, elementY] = Browser.transformClientToBrowser(cX, cY); - let element = Browser.elementFromPoint(elementX, elementY); - if (modifiers == 0) { - if (element instanceof HTMLOptionElement) - element = element.parentNode; - - if (gPrefService.getBoolPref("formhelper.enabled")) { - if (FormHelper.canShowUIFor(element) && FormHelper.open(element)) - return; - } - else if (SelectHelper.canShowUIFor(element)) { - SelectHelper.show(element); - return; - } - - gFocusManager.setFocus(element, Ci.nsIFocusManager.FLAG_NOSCROLL); - - let self = this; - Util.executeSoon(function() { - self._dispatchMouseEvent(element, "mousedown", cX, cY); - self._dispatchMouseEvent(element, "mouseup", cX, cY); - }); - } - else if (modifiers == Ci.nsIDOMNSEvent.CONTROL_MASK) { - let uri = Util.getHrefForElement(element); - if (uri) - Browser.addTab(uri, false); - } + // TODO e10s: handle modifiers for clicks + // + // if (modifiers == Ci.nsIDOMNSEvent.CONTROL_MASK) { + // let uri = Util.getHrefForElement(element); + // if (uri) + // Browser.addTab(uri, false); + // } }, doubleClick: function doubleClick(cX1, cY1, cX2, cY2) { - this._hideCanvas(); + let browser = this._browserView.getBrowser(); + browser.messageManager.sendAsyncMessage("Browser:MouseCancel", {}); const kDoubleClickRadius = 32; let maxRadius = kDoubleClickRadius * Browser._browserView.getZoomLevel(); let isClickInRadius = (Math.abs(cX1 - cX2) < maxRadius && Math.abs(cY1 - cY2) < maxRadius); if (isClickInRadius && !Browser.zoomToPoint(cX1, cY1)) Browser.zoomFromPoint(cX1, cY1); }, @@ -2123,17 +1981,16 @@ function IdentityHandler() { this._staticStrings[this.IDENTITY_MODE_UNKNOWN] = { encryption_label: Elements.browserBundle.getString("identity.unencrypted2") }; this._cacheElements(); } IdentityHandler.prototype = { - // Mode strings used to control CSS display IDENTITY_MODE_IDENTIFIED : "verifiedIdentity", // High-quality identity information IDENTITY_MODE_DOMAIN_VERIFIED : "verifiedDomain", // Minimal SSL CA-signed domain verification IDENTITY_MODE_UNKNOWN : "unknownIdentity", // No trusted identity information // Cache the most recent SSLStatus and Location seen in checkIdentity _lastStatus : null, _lastLocation : null, @@ -2148,63 +2005,26 @@ IdentityHandler.prototype = { this._identityPopupContentHost = document.getElementById("identity-popup-content-host"); this._identityPopupContentOwner = document.getElementById("identity-popup-content-owner"); this._identityPopupContentSupp = document.getElementById("identity-popup-content-supplemental"); this._identityPopupContentVerif = document.getElementById("identity-popup-content-verifier"); this._identityPopupEncLabel = document.getElementById("identity-popup-encryption-label"); }, /** - * Helper to parse out the important parts of _lastStatus (of the SSL cert in - * particular) for use in constructing identity UI strings - */ - getIdentityData: function() { - var result = {}; - var status = this._lastStatus.QueryInterface(Ci.nsISSLStatus); - var cert = status.serverCert; - - // Human readable name of Subject - result.subjectOrg = cert.organization; - - // SubjectName fields, broken up for individual access - if (cert.subjectName) { - result.subjectNameFields = {}; - cert.subjectName.split(",").forEach(function(v) { - var field = v.split("="); - this[field[0]] = field[1]; - }, result.subjectNameFields); - - // Call out city, state, and country specifically - result.city = result.subjectNameFields.L; - result.state = result.subjectNameFields.ST; - result.country = result.subjectNameFields.C; - } - - // Human readable name of Certificate Authority - result.caOrg = cert.issuerOrganization || cert.issuerCommonName; - result.cert = cert; - - return result; - }, - - /** * Determine the identity of the page being displayed by examining its SSL cert * (if available) and, if necessary, update the UI to reflect this. */ checkIdentity: function() { let state = Browser.selectedTab.getIdentityState(); - let location = getBrowser().contentWindow.location; - let currentStatus = getBrowser().securityUI.QueryInterface(Ci.nsISSLStatusProvider).SSLStatus; + let location = getBrowser().currentURI; + let data = Browser.selectedTab.getIdentityData(); - this._lastStatus = currentStatus; - this._lastLocation = {}; - try { - // make a copy of the passed in location to avoid cycles - this._lastLocation = { host: location.host, hostname: location.hostname, port: location.port }; - } catch (ex) { } + this._lastIdentityData = data; + this._lastLocation = location.clone(); if (state & Ci.nsIWebProgressListener.STATE_IDENTITY_EV_TOPLEVEL) this.setMode(this.IDENTITY_MODE_IDENTIFIED); else if (state & Ci.nsIWebProgressListener.STATE_SECURE_HIGH) this.setMode(this.IDENTITY_MODE_DOMAIN_VERIFIED); else this.setMode(this.IDENTITY_MODE_UNKNOWN); }, @@ -2213,21 +2033,21 @@ IdentityHandler.prototype = { * Return the eTLD+1 version of the current hostname */ getEffectiveHost: function() { // Cache the eTLDService if this is our first time through if (!this._eTLDService) this._eTLDService = Cc["@mozilla.org/network/effective-tld-service;1"] .getService(Ci.nsIEffectiveTLDService); try { - return this._eTLDService.getBaseDomainFromHost(this._lastLocation.hostname); + return this._eTLDService.getBaseDomainFromHost(this._lastLocation.host); } catch (e) { // If something goes wrong (e.g. hostname is an IP address) just fail back // to the full domain. - return this._lastLocation.hostname; + return this._lastLocation.host; } }, /** * Update the UI to reflect the specified mode, which should be one of the * IDENTITY_MODE_* constants. */ setMode: function(newMode) { @@ -2242,47 +2062,39 @@ IdentityHandler.prototype = { /** * Set up the messages for the primary identity UI based on the specified mode, * and the details of the SSL cert, where applicable * * @param newMode The newly set identity mode. Should be one of the IDENTITY_MODE_* constants. */ setIdentityMessages: function(newMode) { let strings = Elements.browserBundle; + var iData = this._lastIdentityData; if (newMode == this.IDENTITY_MODE_DOMAIN_VERIFIED) { - var iData = this.getIdentityData(); - // We need a port number for all lookups. If one hasn't been specified, use // the https default - var lookupHost = this._lastLocation.host; + var lookupHost = this._lastLocation.hostPort; if (lookupHost.indexOf(':') < 0) lookupHost += ":443"; // Cache the override service the first time we need to check it if (!this._overrideService) this._overrideService = Cc["@mozilla.org/security/certoverride;1"].getService(Ci.nsICertOverrideService); // Verifier is either the CA Org, for a normal cert, or a special string // for certs that are trusted because of a security exception. var tooltip = strings.getFormattedString("identity.identified.verifier", [iData.caOrg]); - // Check whether this site is a security exception. XPConnect does the right - // thing here in terms of converting _lastLocation.port from string to int, but - // the overrideService doesn't like undefined ports, so make sure we have - // something in the default case (bug 432241). - if (this._overrideService.hasMatchingOverride(this._lastLocation.hostname, - (this._lastLocation.port || 443), - iData.cert, {}, {})) + if (iData.isException) tooltip = strings.getString("identity.identified.verified_by_you"); } else if (newMode == this.IDENTITY_MODE_IDENTIFIED) { // If it's identified, then we can populate the dialog with credentials - iData = this.getIdentityData(); tooltip = strings.getFormattedString("identity.identified.verifier", [iData.caOrg]); } else { tooltip = strings.getString("identity.unknown.tooltip"); } // Push the appropriate strings out to the UI @@ -2305,25 +2117,25 @@ IdentityHandler.prototype = { // Initialize the optional strings to empty values var supplemental = ""; var verifier = ""; let strings = Elements.browserBundle; if (newMode == this.IDENTITY_MODE_DOMAIN_VERIFIED) { - var iData = this.getIdentityData(); + var iData = this._lastIdentityData; var host = this.getEffectiveHost(); var owner = strings.getString("identity.ownerUnknown2"); verifier = this._identityBox.tooltipText; supplemental = ""; } else if (newMode == this.IDENTITY_MODE_IDENTIFIED) { // If it's identified, then we can populate the dialog with credentials - iData = this.getIdentityData(); + iData = this._lastIdentityData; host = this.getEffectiveHost(); owner = iData.subjectOrg; verifier = this._identityBox.tooltipText; // Build an appropriate supplemental block out of whatever location data we have if (iData.city) supplemental += iData.city + " "; if (iData.state && iData.country) @@ -2825,16 +2637,18 @@ ProgressController.prototype = { // Don't need to do anything if the data we use to update the UI hasn't changed if (this.state == aState && !this._hostChanged) return; this._hostChanged = false; this.state = aState; if (this._tab == Browser.selectedTab) { + this._tab._identityState = this.state; + this._tab._identityData = aWebProgress.identity; getIdentityHandler().checkIdentity(); } }, QueryInterface: function(aIID) { if (aIID.equals(Ci.nsIWebProgressListener) || aIID.equals(Ci.nsISupportsWeakReference) || aIID.equals(Ci.nsISupports)) @@ -2867,16 +2681,17 @@ ProgressController.prototype = { if (this._tab == Browser.selectedTab) BrowserUI.update(TOOLBARSTATE_LOADED); if (this.browser.currentURI.spec != "about:blank") this._tab.updateThumbnail(); }, _documentStop: function _documentStop() { + return; // XXX e10s scroll fixes if (this._tab == Browser.selectedTab) { // XXX Sometimes MozScrollSizeChange has not occurred, so the scroll pane will not // be resized yet. We are assuming this event is on the queue, so scroll the pane // "soon." Util.executeSoon(function() { let scroll = Browser.getScrollboxPosition(Browser.contentScrollboxScroller); if (scroll.isZero()) Browser.scrollContentToBrowser(); @@ -2986,16 +2801,18 @@ var OfflineApps = { }; function Tab() { this._id = null; this._browser = null; this._browserViewportState = null; this._state = null; this._listener = null; + this._identityState = null; + this._identityData = null; this._loading = false; this._chromeTab = null; this._resizeAndPaint = Util.bind(this._resizeAndPaint, this); // Set to 0 since new tabs that have not been viewed yet are good tabs to // toss if app needs more memory. this.lastSelected = 0; @@ -3112,19 +2929,24 @@ Tab.prototype = { if (doc instanceof XULDocument || doc.body instanceof HTMLFrameSetElement) { let [width, height] = BrowserView.Util.getBrowserDimensions(browser); BrowserView.Util.ensureMozScrolledAreaEvent(browser, width, height); } }, /** Returns tab's identity state for updating security UI. */ getIdentityState: function getIdentityState() { - return this._listener.state; + return this._identityState; }, + getIdentityData: function getIdentityData() { + // XXX combine this and identity state into one JSON object? + return this._identityData; + }, + startLoading: function startLoading() { if (this._loading) throw "Already Loading!"; this._loading = true; if (!this._loadingTimeout) { let bv = Browser._browserView; @@ -3190,17 +3012,17 @@ Tab.prototype = { if (this._browser) throw "Browser already exists"; // Create the browser using the current width the dynamically size the height let browser = this._browser = document.createElement("browser"); browser.setAttribute("style", "overflow: -moz-hidden-unscrollable; visibility: hidden;"); browser.setAttribute("type", "content"); - browser.setAttribute("remote", "false"); + browser.setAttribute("remote", "true"); // Append the browser to the document, which should start the page load document.getElementById("browsers").appendChild(browser); // stop about:blank from loading browser.stop(); // Attach a separate progress listener to the browser @@ -3214,16 +3036,18 @@ Tab.prototype = { _destroyBrowser: function _destroyBrowser() { if (this._browser) { var browser = this._browser; browser.removeProgressListener(this._listener); this._browser = null; this._listener = null; + this._identityState = null; + this._identityData = null; this._loading = false; try { // this will throw if we're not loading this._stopResizeAndPaint(); } catch(ex) {} Util.executeSoon(function() { document.getElementById("browsers").removeChild(browser); diff --git a/chrome/content/content.js b/chrome/content/content.js --- a/chrome/content/content.js +++ b/chrome/content/content.js @@ -674,19 +674,19 @@ FormNavigator.prototype = { } }; /** Can't think of a good description of this class. It probably does too much? */ function Content() { addMessageListener("Browser:Blur", this); addMessageListener("Browser:Focus", this); - addMessageListener("Browser:Mousedown", this); - addMessageListener("Browser:Mouseup", this); - addMessageListener("Browser:CancelMouse", this); + addMessageListener("Browser:MouseDown", this); + addMessageListener("Browser:MouseUp", this); + addMessageListener("Browser:MouseCancel", this); addMessageListener("Browser:SaveAs", this); this._coalescer = new Coalescer(); addEventListener("MozAfterPaint", this._coalescer, false); addEventListener("MozScrolledAreaChanged", this._coalescer, false); addEventListener("MozApplicationManifest", this._coalescer, false); addEventListener("scroll", this._coalescer, false); @@ -696,46 +696,48 @@ function Content() { this._contentFormManager = new ContentFormManager(); this._mousedownTimeout = new Util.Timeout(); } Content.prototype = { receiveMessage: function receiveMessage(aMessage) { let json = aMessage.json; + let x = json.x; + let y = json.y; switch (aMessage.name) { case "Browser:Blur": docShell.isOffScreenBrowser = false; this._selected = false; break; case "Browser:Focus": docShell.isOffScreenBrowser = true; this._selected = true; break; - case "Browser:Mousedown": + case "Browser:MouseDown": this._mousedownTimeout.once(kTapOverlayTimeout, function() { let element = elementFromPoint(x, y); gFocusManager.setFocus(element, Ci.nsIFocusManager.FLAG_NOSCROLL); }); break; - case "Browser:Mouseup": + case "Browser:MouseUp": this._mousedownTimeout.flush(); let element = elementFromPoint(x, y); if (!this._contentFormManager.formAssist(element)) { this._sendMouseEvent("mousedown", element, x, y); this._sendMouseEvent("mouseup", element, x, y); } break; - case "Browser:CancelMouse": + case "Browser:MouseCancel": this._mousedownTimeout.clear(); // XXX there must be a better way than this to cancel the mouseover/focus? this._sendMouseEvent("mouseup", null, -1000, -1000); try { content.document.activeElement.blur(); } catch(e) {} break;