summaryrefslogtreecommitdiffstats
path: root/toolkit/content/tests/fennec-tile-testapp/chrome
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/content/tests/fennec-tile-testapp/chrome')
-rw-r--r--toolkit/content/tests/fennec-tile-testapp/chrome/chrome.manifest1
-rw-r--r--toolkit/content/tests/fennec-tile-testapp/chrome/content/BrowserView.js694
-rw-r--r--toolkit/content/tests/fennec-tile-testapp/chrome/content/FooScript.js352
-rw-r--r--toolkit/content/tests/fennec-tile-testapp/chrome/content/TileManager.js1018
-rw-r--r--toolkit/content/tests/fennec-tile-testapp/chrome/content/WidgetStack.js1438
-rw-r--r--toolkit/content/tests/fennec-tile-testapp/chrome/content/firefoxOverlay.xul15
-rw-r--r--toolkit/content/tests/fennec-tile-testapp/chrome/content/foo.xul460
-rw-r--r--toolkit/content/tests/fennec-tile-testapp/chrome/content/main.xul7
-rw-r--r--toolkit/content/tests/fennec-tile-testapp/chrome/content/overlay.js15
-rw-r--r--toolkit/content/tests/fennec-tile-testapp/chrome/locale/en-US/tile.dtd1
-rw-r--r--toolkit/content/tests/fennec-tile-testapp/chrome/locale/en-US/tile.properties3
-rw-r--r--toolkit/content/tests/fennec-tile-testapp/chrome/skin/overlay.css5
12 files changed, 0 insertions, 4009 deletions
diff --git a/toolkit/content/tests/fennec-tile-testapp/chrome/chrome.manifest b/toolkit/content/tests/fennec-tile-testapp/chrome/chrome.manifest
deleted file mode 100644
index 118354c81..000000000
--- a/toolkit/content/tests/fennec-tile-testapp/chrome/chrome.manifest
+++ /dev/null
@@ -1 +0,0 @@
-content tile file:content/
diff --git a/toolkit/content/tests/fennec-tile-testapp/chrome/content/BrowserView.js b/toolkit/content/tests/fennec-tile-testapp/chrome/content/BrowserView.js
deleted file mode 100644
index c498810df..000000000
--- a/toolkit/content/tests/fennec-tile-testapp/chrome/content/BrowserView.js
+++ /dev/null
@@ -1,694 +0,0 @@
-// -*- tab-width: 2; indent-tabs-mode: nil; js-indent-level: 2 -*-
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-var Ci = Components.interfaces;
-
-// --- REMOVE ---
-var noop = function() {};
-var endl = '\n';
-// --------------
-
-function BrowserView(container, visibleRect) {
- bindAll(this);
- this.init(container, visibleRect);
-}
-
-/**
- * A BrowserView maintains state of the viewport (browser, zoom level,
- * dimensions) and the visible rectangle into the viewport, for every
- * browser it is given (cf setBrowser()). In updates to the viewport state,
- * a BrowserView (using its TileManager) renders parts of the page quasi-
- * intelligently, with guarantees of having rendered and appended all of the
- * visible browser content (aka the "critical rectangle").
- *
- * State is characterized in large part by two rectangles (and an implicit third):
- * - Viewport: Always rooted at the origin, ie with (left, top) at (0, 0). The
- * width and height (right and bottom) of this rectangle are that of the
- * current viewport, which corresponds more or less to the transformed
- * browser content (scaled by zoom level).
- * - Visible: Corresponds to the client's viewing rectangle in viewport
- * coordinates. Has (top, left) corresponding to position, and width & height
- * corresponding to the clients viewing dimensions. Take note that the top
- * and left of the visible rect are per-browser state, but that the width
- * and height persist across setBrowser() calls. This is best explained by
- * a simple example: user views browser A, pans to position (x0, y0), switches
- * to browser B, where she finds herself at position (x1, y1), tilts her
- * device so that visible rectangle's width and height change, and switches
- * back to browser A. She expects to come back to position (x0, y0), but her
- * device remains tilted.
- * - Critical (the implicit one): The critical rectangle is the (possibly null)
- * intersection of the visible and viewport rectangles. That is, it is that
- * region of the viewport which is visible to the user. We care about this
- * because it tells us which region must be rendered as soon as it is dirtied.
- * The critical rectangle is mostly state that we do not keep in BrowserView
- * but that our TileManager maintains.
- *
- * Example rectangle state configurations:
- *
- *
- * +-------------------------------+
- * |A |
- * | |
- * | |
- * | |
- * | +----------------+ |
- * | |B,C | |
- * | | | |
- * | | | |
- * | | | |
- * | +----------------+ |
- * | |
- * | |
- * | |
- * | |
- * | |
- * +-------------------------------+
- *
- *
- * A = viewport ; at (0, 0)
- * B = visible ; at (x, y) where x > 0, y > 0
- * C = critical ; at (x, y)
- *
- *
- *
- * +-------------------------------+
- * |A |
- * | |
- * | |
- * | |
- * +----+-----------+ |
- * |B .C | |
- * | . | |
- * | . | |
- * | . | |
- * +----+-----------+ |
- * | |
- * | |
- * | |
- * | |
- * | |
- * +-------------------------------+
- *
- *
- * A = viewport ; at (0, 0)
- * B = visible ; at (x, y) where x < 0, y > 0
- * C = critical ; at (0, y)
- *
- *
- * Maintaining per-browser state is a little bit of a hack involving attaching
- * an object as the obfuscated dynamic JS property of the browser object, that
- * hopefully no one but us will touch. See getViewportStateFromBrowser() for
- * the property name.
- */
-BrowserView.prototype = (
-function() {
-
- // -----------------------------------------------------------
- // Privates
- //
-
- const kZoomLevelMin = 0.2;
- const kZoomLevelMax = 4.0;
- const kZoomLevelPrecision = 10000;
-
- function visibleRectToCriticalRect(visibleRect, browserViewportState) {
- return visibleRect.intersect(browserViewportState.viewportRect);
- }
-
- function clampZoomLevel(zl) {
- let bounded = Math.min(Math.max(kZoomLevelMin, zl), kZoomLevelMax);
- return Math.round(bounded * kZoomLevelPrecision) / kZoomLevelPrecision;
- }
-
- function pageZoomLevel(visibleRect, browserW, browserH) {
- return clampZoomLevel(visibleRect.width / browserW);
- }
-
- function seenBrowser(browser) {
- return !!(browser.__BrowserView__vps);
- }
-
- function initBrowserState(browser, visibleRect) {
- let [browserW, browserH] = getBrowserDimensions(browser);
-
- let zoomLevel = pageZoomLevel(visibleRect, browserW, browserH);
- let viewportRect = (new wsRect(0, 0, browserW, browserH)).scale(zoomLevel, zoomLevel);
-
- dump('--- initing browser to ---' + endl);
- browser.__BrowserView__vps = new BrowserView.BrowserViewportState(viewportRect,
- visibleRect.x,
- visibleRect.y,
- zoomLevel);
- dump(browser.__BrowserView__vps.toString() + endl);
- dump('--------------------------' + endl);
- }
-
- function getViewportStateFromBrowser(browser) {
- return browser.__BrowserView__vps;
- }
-
- function getBrowserDimensions(browser) {
- return [browser.scrollWidth, browser.scrollHeight];
- }
-
- function getContentScrollValues(browser) {
- let cwu = getBrowserDOMWindowUtils(browser);
- let scrollX = {};
- let scrollY = {};
- cwu.getScrollXY(false, scrollX, scrollY);
-
- return [scrollX.value, scrollY.value];
- }
-
- function getBrowserDOMWindowUtils(browser) {
- return browser.contentWindow
- .QueryInterface(Ci.nsIInterfaceRequestor)
- .getInterface(Ci.nsIDOMWindowUtils);
- }
-
- function getNewBatchOperationState() {
- return {
- viewportSizeChanged: false,
- dirtyAll: false
- };
- }
-
- function clampViewportWH(width, height, visibleRect) {
- let minW = visibleRect.width;
- let minH = visibleRect.height;
- return [Math.max(width, minW), Math.max(height, minH)];
- }
-
- function initContainer(container, visibleRect) {
- container.style.width = visibleRect.width + 'px';
- container.style.height = visibleRect.height + 'px';
- container.style.overflow = '-moz-hidden-unscrollable';
- }
-
- function resizeContainerToViewport(container, viewportRect) {
- container.style.width = viewportRect.width + 'px';
- container.style.height = viewportRect.height + 'px';
- }
-
- // !!! --- RESIZE HACK BEGIN -----
- function simulateMozAfterSizeChange(browser, width, height) {
- let ev = document.createElement("MouseEvents");
- ev.initEvent("FakeMozAfterSizeChange", false, false, window, 0, width, height);
- browser.dispatchEvent(ev);
- }
- // !!! --- RESIZE HACK END -------
-
- // --- Change of coordinates functions --- //
-
-
- // The following returned object becomes BrowserView.prototype
- return {
-
- // -----------------------------------------------------------
- // Public instance methods
- //
-
- init: function init(container, visibleRect) {
- this._batchOps = [];
- this._container = container;
- this._browserViewportState = null;
- this._renderMode = 0;
- this._tileManager = new TileManager(this._appendTile, this._removeTile, this);
- this.setVisibleRect(visibleRect);
-
- // !!! --- RESIZE HACK BEGIN -----
- // remove this eventually
- this._resizeHack = {
- maxSeenW: 0,
- maxSeenH: 0
- };
- // !!! --- RESIZE HACK END -------
- },
-
- setVisibleRect: function setVisibleRect(r) {
- let bvs = this._browserViewportState;
- let vr = this._visibleRect;
-
- if (!vr)
- this._visibleRect = vr = r.clone();
- else
- vr.copyFrom(r);
-
- if (bvs) {
- bvs.visibleX = vr.left;
- bvs.visibleY = vr.top;
-
- // reclamp minimally to the new visible rect
- // this.setViewportDimensions(bvs.viewportRect.right, bvs.viewportRect.bottom);
- } else
- this._viewportChanged(false, false);
- },
-
- getVisibleRect: function getVisibleRect() {
- return this._visibleRect.clone();
- },
-
- getVisibleRectX: function getVisibleRectX() { return this._visibleRect.x; },
- getVisibleRectY: function getVisibleRectY() { return this._visibleRect.y; },
- getVisibleRectWidth: function getVisibleRectWidth() { return this._visibleRect.width; },
- getVisibleRectHeight: function getVisibleRectHeight() { return this._visibleRect.height; },
-
- setViewportDimensions: function setViewportDimensions(width, height, causedByZoom) {
- let bvs = this._browserViewportState;
- let vis = this._visibleRect;
-
- if (!bvs)
- return;
-
- // [width, height] = clampViewportWH(width, height, vis);
- bvs.viewportRect.right = width;
- bvs.viewportRect.bottom = height;
-
- // XXX we might not want the user's page to disappear from under them
- // at this point, which could happen if the container gets resized such
- // that visible rect becomes entirely outside of viewport rect. might
- // be wise to define what UX should be in this case, like a move occurs.
- // then again, we could also argue this is the responsibility of the
- // caller who would do such a thing...
-
- this._viewportChanged(true, !!causedByZoom);
- },
-
- setZoomLevel: function setZoomLevel(zl) {
- let bvs = this._browserViewportState;
-
- if (!bvs)
- return;
-
- let newZL = clampZoomLevel(zl);
-
- if (newZL != bvs.zoomLevel) {
- let browserW = this.viewportToBrowser(bvs.viewportRect.right);
- let browserH = this.viewportToBrowser(bvs.viewportRect.bottom);
- bvs.zoomLevel = newZL; // side-effect: now scale factor in transformations is newZL
- this.setViewportDimensions(this.browserToViewport(browserW),
- this.browserToViewport(browserH));
- }
- },
-
- getZoomLevel: function getZoomLevel() {
- let bvs = this._browserViewportState;
- if (!bvs)
- return undefined;
-
- return bvs.zoomLevel;
- },
-
- beginBatchOperation: function beginBatchOperation() {
- this._batchOps.push(getNewBatchOperationState());
- this.pauseRendering();
- },
-
- commitBatchOperation: function commitBatchOperation() {
- let bops = this._batchOps;
-
- if (bops.length == 0)
- return;
-
- let opState = bops.pop();
- this._viewportChanged(opState.viewportSizeChanged, opState.dirtyAll);
- this.resumeRendering();
- },
-
- discardBatchOperation: function discardBatchOperation() {
- let bops = this._batchOps;
- bops.pop();
- this.resumeRendering();
- },
-
- discardAllBatchOperations: function discardAllBatchOperations() {
- let bops = this._batchOps;
- while (bops.length > 0)
- this.discardBatchOperation();
- },
-
- moveVisibleBy: function moveVisibleBy(dx, dy) {
- let vr = this._visibleRect;
- let vs = this._browserViewportState;
-
- this.onBeforeVisibleMove(dx, dy);
- this.onAfterVisibleMove(dx, dy);
- },
-
- moveVisibleTo: function moveVisibleTo(x, y) {
- let visibleRect = this._visibleRect;
- let dx = x - visibleRect.x;
- let dy = y - visibleRect.y;
- this.moveBy(dx, dy);
- },
-
- /**
- * Calls to this function need to be one-to-one with calls to
- * resumeRendering()
- */
- pauseRendering: function pauseRendering() {
- this._renderMode++;
- },
-
- /**
- * Calls to this function need to be one-to-one with calls to
- * pauseRendering()
- */
- resumeRendering: function resumeRendering(renderNow) {
- if (this._renderMode > 0)
- this._renderMode--;
-
- if (renderNow || this._renderMode == 0)
- this._tileManager.criticalRectPaint();
- },
-
- isRendering: function isRendering() {
- return (this._renderMode == 0);
- },
-
- /**
- * @param dx Guess delta to destination x coordinate
- * @param dy Guess delta to destination y coordinate
- */
- onBeforeVisibleMove: function onBeforeVisibleMove(dx, dy) {
- let vs = this._browserViewportState;
- let vr = this._visibleRect;
-
- let destCR = visibleRectToCriticalRect(vr.clone().translate(dx, dy), vs);
-
- this._tileManager.beginCriticalMove(destCR);
- },
-
- /**
- * @param dx Actual delta to destination x coordinate
- * @param dy Actual delta to destination y coordinate
- */
- onAfterVisibleMove: function onAfterVisibleMove(dx, dy) {
- let vs = this._browserViewportState;
- let vr = this._visibleRect;
-
- vr.translate(dx, dy);
- vs.visibleX = vr.left;
- vs.visibleY = vr.top;
-
- let cr = visibleRectToCriticalRect(vr, vs);
-
- this._tileManager.endCriticalMove(cr, this.isRendering());
- },
-
- setBrowser: function setBrowser(browser, skipZoom) {
- let currentBrowser = this._browser;
-
- let browserChanged = (currentBrowser !== browser);
-
- if (currentBrowser) {
- currentBrowser.removeEventListener("MozAfterPaint", this.handleMozAfterPaint, false);
-
- // !!! --- RESIZE HACK BEGIN -----
- // change to the real event type and perhaps refactor the handler function name
- currentBrowser.removeEventListener("FakeMozAfterSizeChange", this.handleMozAfterSizeChange, false);
- // !!! --- RESIZE HACK END -------
-
- this.discardAllBatchOperations();
-
- currentBrowser.setAttribute("type", "content");
- currentBrowser.docShell.isOffScreenBrowser = false;
- }
-
- this._restoreBrowser(browser);
-
- browser.setAttribute("type", "content-primary");
-
- this.beginBatchOperation();
-
- browser.addEventListener("MozAfterPaint", this.handleMozAfterPaint, false);
-
- // !!! --- RESIZE HACK BEGIN -----
- // change to the real event type and perhaps refactor the handler function name
- browser.addEventListener("FakeMozAfterSizeChange", this.handleMozAfterSizeChange, false);
- // !!! --- RESIZE HACK END -------
-
- if (!skipZoom) {
- browser.docShell.isOffScreenBrowser = true;
- this.zoomToPage();
- }
-
- this._viewportChanged(browserChanged, browserChanged);
-
- this.commitBatchOperation();
- },
-
- handleMozAfterPaint: function handleMozAfterPaint(ev) {
- let browser = this._browser;
- let tm = this._tileManager;
- let vs = this._browserViewportState;
-
- let [scrollX, scrollY] = getContentScrollValues(browser);
- let clientRects = ev.clientRects;
-
- // !!! --- RESIZE HACK BEGIN -----
- // remove this, cf explanation in loop below
- let hack = this._resizeHack;
- let hackSizeChanged = false;
- // !!! --- RESIZE HACK END -------
-
- let rects = [];
- // loop backwards to avoid xpconnect penalty for .length
- for (let i = clientRects.length - 1; i >= 0; --i) {
- let e = clientRects.item(i);
- let r = new wsRect(e.left + scrollX,
- e.top + scrollY,
- e.width, e.height);
-
- this.browserToViewportRect(r);
- r.round();
-
- if (r.right < 0 || r.bottom < 0)
- continue;
-
- // !!! --- RESIZE HACK BEGIN -----
- // remove this. this is where we make 'lazy' calculations
- // that hint at a browser size change and fake the size change
- // event dispach
- if (r.right > hack.maxW) {
- hack.maxW = rect.right;
- hackSizeChanged = true;
- }
- if (r.bottom > hack.maxH) {
- hack.maxH = rect.bottom;
- hackSizeChanged = true;
- }
- // !!! --- RESIZE HACK END -------
-
- r.restrictTo(vs.viewportRect);
- rects.push(r);
- }
-
- // !!! --- RESIZE HACK BEGIN -----
- // remove this, cf explanation in loop above
- if (hackSizeChanged)
- simulateMozAfterSizeChange(browser, hack.maxW, hack.maxH);
- // !!! --- RESIZE HACK END -------
-
- tm.dirtyRects(rects, this.isRendering());
- },
-
- handleMozAfterSizeChange: function handleMozAfterPaint(ev) {
- // !!! --- RESIZE HACK BEGIN -----
- // get the correct properties off of the event, these are wrong because
- // we're using a MouseEvent since it has an X and Y prop of some sort and
- // we piggyback on that.
- let w = ev.screenX;
- let h = ev.screenY;
- // !!! --- RESIZE HACK END -------
-
- this.setViewportDimensions(w, h);
- },
-
- zoomToPage: function zoomToPage() {
- let browser = this._browser;
-
- if (!browser)
- return;
-
- let [w, h] = getBrowserDimensions(browser);
- this.setZoomLevel(pageZoomLevel(this._visibleRect, w, h));
- },
-
- zoom: function zoom(aDirection) {
- if (aDirection == 0)
- return;
-
- var zoomDelta = 0.05; // 1/20
- if (aDirection >= 0)
- zoomDelta *= -1;
-
- this.zoomLevel = this._zoomLevel + zoomDelta;
- },
-
- viewportToBrowser: function viewportToBrowser(x) {
- let bvs = this._browserViewportState;
-
- if (!bvs)
- throw "No browser is set";
-
- return x / bvs.zoomLevel;
- },
-
- browserToViewport: function browserToViewport(x) {
- let bvs = this._browserViewportState;
-
- if (!bvs)
- throw "No browser is set";
-
- return x * bvs.zoomLevel;
- },
-
- viewportToBrowserRect: function viewportToBrowserRect(rect) {
- let f = this.viewportToBrowser(1.0);
- return rect.scale(f, f);
- },
-
- browserToViewportRect: function browserToViewportRect(rect) {
- let f = this.browserToViewport(1.0);
- return rect.scale(f, f);
- },
-
- browserToViewportCanvasContext: function browserToViewportCanvasContext(ctx) {
- let f = this.browserToViewport(1.0);
- ctx.scale(f, f);
- },
-
-
- // -----------------------------------------------------------
- // Private instance methods
- //
-
- _restoreBrowser: function _restoreBrowser(browser) {
- let vr = this._visibleRect;
-
- if (!seenBrowser(browser))
- initBrowserState(browser, vr);
-
- let bvs = getViewportStateFromBrowser(browser);
-
- this._contentWindow = browser.contentWindow;
- this._browser = browser;
- this._browserViewportState = bvs;
- vr.left = bvs.visibleX;
- vr.top = bvs.visibleY;
- this._tileManager.setBrowser(browser);
- },
-
- _viewportChanged: function _viewportChanged(viewportSizeChanged, dirtyAll) {
- let bops = this._batchOps;
-
- if (bops.length > 0) {
- let opState = bops[bops.length - 1];
-
- if (viewportSizeChanged)
- opState.viewportSizeChanged = viewportSizeChanged;
-
- if (dirtyAll)
- opState.dirtyAll = dirtyAll;
-
- return;
- }
-
- let bvs = this._browserViewportState;
- let vis = this._visibleRect;
-
- // !!! --- RESIZE HACK BEGIN -----
- // We want to uncomment this for perf, but we can't with the hack in place
- // because the mozAfterPaint gives us rects that we use to create the
- // fake mozAfterResize event, so we can't just clear things.
- /*
- if (dirtyAll) {
- // We're about to mark the entire viewport dirty, so we can clear any
- // queued afterPaint events that will cause redundant draws
- getBrowserDOMWindowUtils(this._browser).clearMozAfterPaintEvents();
- }
- */
- // !!! --- RESIZE HACK END -------
-
- if (bvs) {
- resizeContainerToViewport(this._container, bvs.viewportRect);
-
- this._tileManager.viewportChangeHandler(bvs.viewportRect,
- visibleRectToCriticalRect(vis, bvs),
- viewportSizeChanged,
- dirtyAll);
- }
- },
-
- _appendTile: function _appendTile(tile) {
- let canvas = tile.getContentImage();
-
- /*
- canvas.style.position = "absolute";
- canvas.style.left = tile.x + "px";
- canvas.style.top = tile.y + "px";
- */
-
- canvas.setAttribute("style", "position: absolute; left: " + tile.boundRect.left + "px; " + "top: " + tile.boundRect.top + "px;");
-
- this._container.appendChild(canvas);
-
- // dump('++ ' + tile.toString(true) + endl);
- },
-
- _removeTile: function _removeTile(tile) {
- let canvas = tile.getContentImage();
-
- this._container.removeChild(canvas);
-
- // dump('-- ' + tile.toString(true) + endl);
- }
-
- };
-
-}
-)();
-
-
-// -----------------------------------------------------------
-// Helper structures
-//
-
-BrowserView.BrowserViewportState = function(viewportRect,
- visibleX,
- visibleY,
- zoomLevel) {
-
- this.init(viewportRect, visibleX, visibleY, zoomLevel);
-};
-
-BrowserView.BrowserViewportState.prototype = {
-
- init: function init(viewportRect, visibleX, visibleY, zoomLevel) {
- this.viewportRect = viewportRect;
- this.visibleX = visibleX;
- this.visibleY = visibleY;
- this.zoomLevel = zoomLevel;
- },
-
- clone: function clone() {
- return new BrowserView.BrowserViewportState(this.viewportRect,
- this.visibleX,
- this.visibleY,
- this.zoomLevel);
- },
-
- toString: function toString() {
- let props = ['\tviewportRect=' + this.viewportRect.toString(),
- '\tvisibleX=' + this.visibleX,
- '\tvisibleY=' + this.visibleY,
- '\tzoomLevel=' + this.zoomLevel];
-
- return '[BrowserViewportState] {\n' + props.join(',\n') + '\n}';
- }
-
-};
-
diff --git a/toolkit/content/tests/fennec-tile-testapp/chrome/content/FooScript.js b/toolkit/content/tests/fennec-tile-testapp/chrome/content/FooScript.js
deleted file mode 100644
index 49cbbed66..000000000
--- a/toolkit/content/tests/fennec-tile-testapp/chrome/content/FooScript.js
+++ /dev/null
@@ -1,352 +0,0 @@
-var noop = function() {};
-Browser = {
- updateViewportSize: noop
- /** ***********************************************************
- function
- let browser = document.getElementById("googlenews");
- let cdoc = browser.contentDocument;
-
- // These might not exist yet depending on page load state
- var body = cdoc.body || {};
- var html = cdoc.documentElement || {};
-
- var w = Math.max(body.scrollWidth || 0, html.scrollWidth);
- var h = Math.max(body.scrollHeight || 0, html.scrollHeight);
-
- window.tileManager.viewportHandler(new wsRect(0, 0, w, h),
- window.innerWidth,
- new wsRect(0, 0, window.innerWidth, window.innerHeight),
- false);
- *************************************************************/
-};
-var ws = {
- beginUpdateBatch: noop,
- panTo: noop,
- endUpdateBatch: noop
-};
-var Ci = Components.interfaces;
-var bv = null;
-var endl = "\n";
-
-
-function BrowserView() {
- this.init();
- bindAll(this);
-}
-
-BrowserView.prototype = {
-
- // --- PROPERTIES ---
- // public:
- // init()
- // getViewportInnerBoundsRect(dx, dy)
- // tileManager
- // scrollbox
- //
- // private:
- // _scrollbox
- // _leftbar
- // _rightbar
- // _topbar
- // _browser
- // _tileManager
- // _viewportRect
- // _viewportInnerBoundsRect
- //
-
- get tileManager() { return this._tileManager; },
- get scrollbox() { return this._scrollbox; },
-
- init: function init() {
- let scrollbox = document.getElementById("scrollbox").boxObject;
- this._scrollbox = scrollbox;
-
- let leftbar = document.getElementById("left_sidebar");
- let rightbar = document.getElementById("right_sidebar");
- let topbar = document.getElementById("top_urlbar");
- this._leftbar = leftbar;
- this._rightbar = rightbar;
- this._topbar = topbar;
-
- scrollbox.scrollTo(Math.round(leftbar.getBoundingClientRect().right), 0);
-
- let tileContainer = document.getElementById("tile_container");
- tileContainer.addEventListener("mousedown", onMouseDown, true);
- tileContainer.addEventListener("mouseup", onMouseUp, true);
- tileContainer.addEventListener("mousemove", onMouseMove, true);
- this._tileContainer = tileContainer;
-
- let tileManager = new TileManager(this.appendTile, this.removeTile, window.innerWidth);
- this._tileManager = tileManager;
-
- let browser = document.getElementById("googlenews");
- this.setCurrentBrowser(browser, false); // sets this._browser
-
- let cdoc = browser.contentDocument;
-
- // These might not exist yet depending on page load state
- let body = cdoc.body || {};
- let html = cdoc.documentElement || {};
-
- let w = Math.max(body.scrollWidth || 0, html.scrollWidth);
- let h = Math.max(body.scrollHeight || 0, html.scrollHeight);
-
- let viewportRect = new wsRect(0, 0, w, h);
- this._viewportRect = viewportRect;
-
- let viewportInnerBoundsRect = this.getViewportInnerBoundsRect();
- this._viewportInnerBoundsRect = viewportInnerBoundsRect;
-
- tileManager.viewportHandler(viewportRect,
- window.innerWidth,
- viewportInnerBoundsRect,
- true);
- },
-
- resizeTileContainer: function resizeTileContainer() {
-
- },
-
- scrollboxToViewportRect: function scrollboxToViewportRect(rect, clip) {
- let leftbar = this._leftbar.getBoundingClientRect();
- let rightbar = this._rightbar.getBoundingClientRect();
- let topbar = this._topbar.getBoundingClientRect();
-
- let xtrans = -leftbar.width;
- let ytrans = -topbar.height;
- let x = rect.x + xtrans;
- let y = rect.y + ytrans;
-
- // XXX we're cheating --- this is not really a clip, but its the only
- // way this function is used
- rect.x = (clip) ? Math.max(x, 0) : x;
- rect.y = (clip) ? Math.max(y, 0) : y;
-
- return rect;
- },
-
- getScrollboxPosition: function getScrollboxPosition() {
- return [this._scrollbox.positionX, this._scrollbox.positionY];
- },
-
- getViewportInnerBoundsRect: function getViewportInnerBoundsRect(dx, dy) {
- if (!dx) dx = 0;
- if (!dy) dy = 0;
-
- let w = window.innerWidth;
- let h = window.innerHeight;
-
- let leftbar = this._leftbar.getBoundingClientRect();
- let rightbar = this._rightbar.getBoundingClientRect();
- let topbar = this._topbar.getBoundingClientRect();
-
- let leftinner = Math.max(leftbar.right - dx, 0);
- let rightinner = Math.min(rightbar.left - dx, w);
- let topinner = Math.max(topbar.bottom - dy, 0);
-
- let [x, y] = this.getScrollboxPosition();
-
- return this.scrollboxToViewportRect(new wsRect(x + dx, y + dy, rightinner - leftinner, h - topinner),
- true);
- },
-
- appendTile: function appendTile(tile) {
- let canvas = tile.contentImage;
-
- canvas.style.position = "absolute";
- canvas.style.left = tile.x + "px";
- canvas.style.top = tile.y + "px";
-
- let tileContainer = document.getElementById("tile_container");
- tileContainer.appendChild(canvas);
-
- dump('++ ' + tile.toString() + endl);
- },
-
- removeTile: function removeTile(tile) {
- let canvas = tile.contentImage;
-
- let tileContainer = document.getElementById("tile_container");
- tileContainer.removeChild(canvas);
-
- dump('-- ' + tile.toString() + endl);
- },
-
- scrollBy: function scrollBy(dx, dy) {
- // TODO
- this.onBeforeScroll();
- this.onAfterScroll();
- },
-
- // x: current x
- // y: current y
- // dx: delta to get to x from current x
- // dy: delta to get to y from current y
- onBeforeScroll: function onBeforeScroll(x, y, dx, dy) {
- this.tileManager.onBeforeScroll(this.getViewportInnerBoundsRect(dx, dy));
-
- // shouldn't update margin if it doesn't need to be changed
- let sidebars = document.getElementsByClassName("sidebar");
- for (let i = 0; i < sidebars.length; i++) {
- let sidebar = sidebars[i];
- sidebar.style.margin = (y + dy) + "px 0px 0px 0px";
- }
-
- let urlbar = document.getElementById("top_urlbar");
- urlbar.style.margin = "0px 0px 0px " + (x + dx) + "px";
- },
-
- onAfterScroll: function onAfterScroll(x, y, dx, dy) {
- this.tileManager.onAfterScroll(this.getViewportInnerBoundsRect());
- },
-
- setCurrentBrowser: function setCurrentBrowser(browser, skipZoom) {
- let currentBrowser = this._browser;
- if (currentBrowser) {
- // backup state
- currentBrowser.mZoomLevel = this.zoomLevel;
- currentBrowser.mPanX = ws._viewingRect.x;
- currentBrowser.mPanY = ws._viewingRect.y;
-
- // stop monitor paint events for this browser
- currentBrowser.removeEventListener("MozAfterPaint", this.handleMozAfterPaint, false);
- currentBrowser.setAttribute("type", "content");
- currentBrowser.docShell.isOffScreenBrowser = false;
- }
-
- browser.setAttribute("type", "content-primary");
- if (!skipZoom)
- browser.docShell.isOffScreenBrowser = true;
-
- // start monitoring paint events for this browser
- browser.addEventListener("MozAfterPaint", this.handleMozAfterPaint, false);
-
- this._browser = browser;
-
- // endLoading(and startLoading in most cases) calls zoom anyway
- if (!skipZoom) {
- this.zoomToPage();
- }
-
- if ("mZoomLevel" in browser) {
- // restore last state
- ws.beginUpdateBatch();
- ws.panTo(browser.mPanX, browser.mPanY);
- this.zoomLevel = browser.mZoomLevel;
- ws.endUpdateBatch(true);
-
- // drop the cache
- delete browser.mZoomLevel;
- delete browser.mPanX;
- delete browser.mPanY;
- }
-
- this.tileManager.browser = browser;
- },
-
- handleMozAfterPaint: function handleMozAfterPaint(ev) {
- this.tileManager.handleMozAfterPaint(ev);
- },
-
- zoomToPage: function zoomToPage() {
- /** ******************************************************
- let needToPanToTop = this._needToPanToTop;
- // Ensure pages are panned at the top before zooming/painting
- // combine the initial pan + zoom into a transaction
- if (needToPanToTop) {
- ws.beginUpdateBatch();
- this._needToPanToTop = false;
- ws.panTo(0, -BrowserUI.toolbarH);
- }
- // Adjust the zoomLevel to fit the page contents in our window width
- let [contentW, ] = this._contentAreaDimensions;
- let fakeW = this._fakeWidth;
-
- if (contentW > fakeW)
- this.zoomLevel = fakeW / contentW;
-
- if (needToPanToTop)
- ws.endUpdateBatch();
- ********************************************************/
- }
-
-};
-
-
-function onResize(e) {
- let browser = document.getElementById("googlenews");
- let cdoc = browser.contentDocument;
-
- // These might not exist yet depending on page load state
- var body = cdoc.body || {};
- var html = cdoc.documentElement || {};
-
- var w = Math.max(body.scrollWidth || 0, html.scrollWidth);
- var h = Math.max(body.scrollHeight || 0, html.scrollHeight);
-
- if (bv)
- bv.tileManager.viewportHandler(new wsRect(0, 0, w, h),
- window.innerWidth,
- bv.getViewportInnerBoundsRect(),
- true);
-}
-
-function onMouseDown(e) {
- window._isDragging = true;
- window._dragStart = {x: e.clientX, y: e.clientY};
-
- bv.tileManager.startPanning();
-}
-
-function onMouseUp() {
- window._isDragging = false;
-
- bv.tileManager.endPanning();
-}
-
-function onMouseMove(e) {
- if (window._isDragging) {
- let scrollbox = bv.scrollbox;
-
- let x = scrollbox.positionX;
- let y = scrollbox.positionY;
- let w = scrollbox.scrolledWidth;
- let h = scrollbox.scrolledHeight;
-
- let dx = window._dragStart.x - e.clientX;
- let dy = window._dragStart.y - e.clientY;
-
- // XXX if max(x, 0) > scrollwidth we shouldn't do anything (same for y/height)
- let newX = Math.max(x + dx, 0);
- let newY = Math.max(y + dy, 0);
-
- if (newX < w || newY < h) {
- // clip dx and dy to prevent us from going below 0
- dx = Math.max(dx, -x);
- dy = Math.max(dy, -y);
-
- bv.onBeforeScroll(x, y, dx, dy);
-
- /* dump("==========scroll==========" + endl);
- dump("delta: " + dx + "," + dy + endl);
- let xx = {};
- let yy = {};
- scrollbox.getPosition(xx, yy);
- dump(xx.value + "," + yy.value + endl);*/
-
- scrollbox.scrollBy(dx, dy);
-
- /* scrollbox.getPosition(xx, yy);
- dump(xx.value + "," + yy.value + endl);
- dump("==========================" + endl);*/
-
- bv.onAfterScroll();
- }
- }
-
- window._dragStart = {x: e.clientX, y: e.clientY};
-}
-
-function onLoad() {
- bv = new BrowserView();
-}
diff --git a/toolkit/content/tests/fennec-tile-testapp/chrome/content/TileManager.js b/toolkit/content/tests/fennec-tile-testapp/chrome/content/TileManager.js
deleted file mode 100644
index 52beb6e36..000000000
--- a/toolkit/content/tests/fennec-tile-testapp/chrome/content/TileManager.js
+++ /dev/null
@@ -1,1018 +0,0 @@
-// -*- tab-width: 2; indent-tabs-mode: nil; js-indent-level: 2 -*-
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-const kXHTMLNamespaceURI = "http://www.w3.org/1999/xhtml";
-
-// base-2 exponent for width, height of a single tile.
-const kTileExponentWidth = 7;
-const kTileExponentHeight = 7;
-const kTileWidth = Math.pow(2, kTileExponentWidth); // 2^7 = 128
-const kTileHeight = Math.pow(2, kTileExponentHeight); // 2^7 = 128
-const kLazyRoundTimeCap = 500; // millis
-
-
-function bind(f, thisObj) {
- return function() {
- return f.apply(thisObj, arguments);
- };
-}
-
-function bindSome(instance, methodNames) {
- for (let methodName of methodNames)
- if (methodName in instance)
- instance[methodName] = bind(instance[methodName], instance);
-}
-
-function bindAll(instance) {
- for (let key in instance)
- if (instance[key] instanceof Function)
- instance[key] = bind(instance[key], instance);
-}
-
-
-/**
- * The Tile Manager!
- *
- * @param appendTile The function the tile manager should call in order to
- * "display" a tile (e.g. append it to the DOM). The argument to this
- * function is a TileManager.Tile object.
- * @param removeTile The function the tile manager should call in order to
- * "undisplay" a tile (e.g. remove it from the DOM). The argument to this
- * function is a TileManager.Tile object.
- * @param fakeWidth The width of the widest possible visible rectangle, e.g.
- * the width of the screen. This is used in setting the zoomLevel.
- */
-function TileManager(appendTile, removeTile, browserView) {
- // backref to the BrowserView object that owns us
- this._browserView = browserView;
-
- // callbacks to append / remove a tile to / from the parent
- this._appendTile = appendTile;
- this._removeTile = removeTile;
-
- // tile cache holds tile objects and pools them under a given capacity
- let self = this;
- this._tileCache = new TileManager.TileCache(function(tile) { self._removeTileSafe(tile); },
- -1, -1, 110);
-
- // Rectangle within the viewport that is visible to the user. It is "critical"
- // in the sense that it must be rendered as soon as it becomes dirty
- this._criticalRect = null;
-
- // Current <browser> DOM element, holding the content we wish to render.
- // This is null when no browser is attached
- this._browser = null;
-
- // if we have an outstanding paint timeout, its value is stored here
- // for cancelling when we end page loads
- // this._drawTimeout = 0;
- this._pageLoadResizerTimeout = 0;
-
- // timeout of the non-visible-tiles-crawler to cache renders from the browser
- this._idleTileCrawlerTimeout = 0;
-
- // object that keeps state on our current lazyload crawl
- this._crawler = null;
-
- // the max right coordinate we've seen from paint events
- // while we were loading a page. If we see something that's bigger than
- // our width, we'll trigger a page zoom.
- this._pageLoadMaxRight = 0;
- this._pageLoadMaxBottom = 0;
-
- // Tells us to pan to top before first draw
- this._needToPanToTop = false;
-}
-
-TileManager.prototype = {
-
- setBrowser: function setBrowser(b) { this._browser = b; },
-
- // This is the callback fired by our client whenever the viewport
- // changed somehow (or didn't change but someone asked it to update).
- viewportChangeHandler: function viewportChangeHandler(viewportRect,
- criticalRect,
- boundsSizeChanged,
- dirtyAll) {
- // !!! --- DEBUG BEGIN -----
- dump("***vphandler***\n");
- dump(viewportRect.toString() + "\n");
- dump(criticalRect.toString() + "\n");
- dump(boundsSizeChanged + "\n");
- dump(dirtyAll + "\n***************\n");
- // !!! --- DEBUG END -------
-
- let tc = this._tileCache;
-
- tc.iBound = Math.ceil(viewportRect.right / kTileWidth);
- tc.jBound = Math.ceil(viewportRect.bottom / kTileHeight);
-
- if (!criticalRect || !criticalRect.equals(this._criticalRect)) {
- this.beginCriticalMove(criticalRect);
- this.endCriticalMove(criticalRect, !boundsSizeChanged);
- }
-
- if (boundsSizeChanged) {
- // TODO fastpath if !dirtyAll
- this.dirtyRects([viewportRect.clone()], true);
- }
- },
-
- dirtyRects: function dirtyRects(rects, doCriticalRender) {
- let criticalIsDirty = false;
- let criticalRect = this._criticalRect;
-
- for (let rect of rects) {
- this._tileCache.forEachIntersectingRect(rect, false, this._dirtyTile, this);
-
- if (criticalRect && rect.intersects(criticalRect))
- criticalIsDirty = true;
- }
-
- if (criticalIsDirty && doCriticalRender)
- this.criticalRectPaint();
- },
-
- criticalRectPaint: function criticalRectPaint() {
- let cr = this._criticalRect;
-
- if (cr) {
- let [ctrx, ctry] = cr.centerRounded();
- this.recenterEvictionQueue(ctrx, ctry);
- this._renderAppendHoldRect(cr);
- }
- },
-
- beginCriticalMove2: function beginCriticalMove(destCriticalRect) {
- let start = Date.now();
- function appendNonDirtyTile(tile) {
- if (!tile.isDirty())
- this._appendTileSafe(tile);
- }
-
- if (destCriticalRect)
- this._tileCache.forEachIntersectingRect(destCriticalRect, false, appendNonDirtyTile, this);
- let end = Date.now();
- dump("start: " + (end-start) + "\n")
- },
-
- beginCriticalMove: function beginCriticalMove(destCriticalRect) {
- /*
- function appendNonDirtyTile(tile) {
- if (!tile.isDirty())
- this._appendTileSafe(tile);
- }
- */
-
- let start = Date.now();
-
- if (destCriticalRect) {
-
- let rect = destCriticalRect;
-
- let create = false;
-
- // this._tileCache.forEachIntersectingRect(destCriticalRect, false, appendNonDirtyTile, this);
- let visited = {};
- let evictGuard = null;
- if (create) {
- evictGuard = function evictGuard(tile) {
- return !visited[tile.toString()];
- };
- }
-
- let starti = rect.left >> kTileExponentWidth;
- let endi = rect.right >> kTileExponentWidth;
-
- let startj = rect.top >> kTileExponentHeight;
- let endj = rect.bottom >> kTileExponentHeight;
-
- let tile = null;
- let tc = this._tileCache;
-
- for (var j = startj; j <= endj; ++j) {
- for (var i = starti; i <= endi; ++i) {
-
- // 'this' for getTile needs to be tc
-
- // tile = this.getTile(i, j, create, evictGuard);
- // if (!tc.inBounds(i, j)) {
- if (0 <= i && 0 <= j && i <= tc.iBound && j <= tc.jBound) {
- // return null;
- break;
- }
-
- tile = null;
-
- // if (tc._isOccupied(i, j)) {
- if (tc._tiles[i] && tc._tiles[i][j]) {
- tile = tc._tiles[i][j];
- } else if (create) {
- // NOTE: create is false here
- tile = tc._createTile(i, j, evictionGuard);
- if (tile) tile.markDirty();
- }
-
- if (tile) {
- visited[tile.toString()] = true;
- // fn.call(thisObj, tile);
- // function appendNonDirtyTile(tile) {
- // if (!tile.isDirty())
- if (!tile._dirtyTileCanvas) {
- // this._appendTileSafe(tile);
- if (!tile._appended) {
- let astart = Date.now();
- this._appendTile(tile);
- tile._appended = true;
- let aend = Date.now();
- dump("append: " + (aend - astart) + "\n");
- }
- }
- // }
- }
- }
- }
- }
-
- let end = Date.now();
- dump("start: " + (end-start) + "\n")
- },
-
- endCriticalMove: function endCriticalMove(destCriticalRect, doCriticalPaint) {
- let start = Date.now();
-
- let tc = this._tileCache;
- let cr = this._criticalRect;
-
- let dcr = destCriticalRect.clone();
-
- let f = function releaseOldTile(tile) {
- // release old tile
- if (!tile.boundRect.intersects(dcr))
- tc.releaseTile(tile);
- }
-
- if (cr)
- tc.forEachIntersectingRect(cr, false, f, this);
-
- this._holdRect(destCriticalRect);
-
- if (cr)
- cr.copyFrom(destCriticalRect);
- else
- this._criticalRect = cr = destCriticalRect;
-
- let crpstart = Date.now();
- if (doCriticalPaint)
- this.criticalRectPaint();
- dump(" crp: " + (Date.now() - crpstart) + "\n");
-
- let end = Date.now();
- dump("end: " + (end - start) + "\n");
- },
-
- restartLazyCrawl: function restartLazyCrawl(startRectOrQueue) {
- if (!startRectOrQueue || startRectOrQueue instanceof Array) {
- this._crawler = new TileManager.CrawlIterator(this._tileCache);
-
- if (startRectOrQueue) {
- let len = startRectOrQueue.length;
- for (let k = 0; k < len; ++k)
- this._crawler.enqueue(startRectOrQueue[k].i, startRectOrQueue[k].j);
- }
- } else {
- this._crawler = new TileManager.CrawlIterator(this._tileCache, startRectOrQueue);
- }
-
- if (!this._idleTileCrawlerTimeout)
- this._idleTileCrawlerTimeout = setTimeout(this._idleTileCrawler, 2000, this);
- },
-
- stopLazyCrawl: function stopLazyCrawl() {
- this._idleTileCrawlerTimeout = 0;
- this._crawler = null;
-
- let cr = this._criticalRect;
- if (cr) {
- let [ctrx, ctry] = cr.centerRounded();
- this.recenterEvictionQueue(ctrx, ctry);
- }
- },
-
- recenterEvictionQueue: function recenterEvictionQueue(ctrx, ctry) {
- let ctri = ctrx >> kTileExponentWidth;
- let ctrj = ctry >> kTileExponentHeight;
-
- function evictFarTiles(a, b) {
- let dista = Math.max(Math.abs(a.i - ctri), Math.abs(a.j - ctrj));
- let distb = Math.max(Math.abs(b.i - ctri), Math.abs(b.j - ctrj));
- return dista - distb;
- }
-
- this._tileCache.sortEvictionQueue(evictFarTiles);
- },
-
- _renderTile: function _renderTile(tile) {
- if (tile.isDirty())
- tile.render(this._browser, this._browserView);
- },
-
- _appendTileSafe: function _appendTileSafe(tile) {
- if (!tile._appended) {
- this._appendTile(tile);
- tile._appended = true;
- }
- },
-
- _removeTileSafe: function _removeTileSafe(tile) {
- if (tile._appended) {
- this._removeTile(tile);
- tile._appended = false;
- }
- },
-
- _dirtyTile: function _dirtyTile(tile) {
- if (!this._criticalRect || !tile.boundRect.intersects(this._criticalRect))
- this._removeTileSafe(tile);
-
- tile.markDirty();
-
- if (this._crawler)
- this._crawler.enqueue(tile.i, tile.j);
- },
-
- _holdRect: function _holdRect(rect) {
- this._tileCache.holdTilesIntersectingRect(rect);
- },
-
- _releaseRect: function _releaseRect(rect) {
- this._tileCache.releaseTilesIntersectingRect(rect);
- },
-
- _renderAppendHoldRect: function _renderAppendHoldRect(rect) {
- function renderAppendHoldTile(tile) {
- if (tile.isDirty())
- this._renderTile(tile);
-
- this._appendTileSafe(tile);
- this._tileCache.holdTile(tile);
- }
-
- this._tileCache.forEachIntersectingRect(rect, true, renderAppendHoldTile, this);
- },
-
- _idleTileCrawler: function _idleTileCrawler(self) {
- if (!self) self = this;
- dump('crawl pass.\n');
- let itered = 0, rendered = 0;
-
- let start = Date.now();
- let comeAgain = true;
-
- while ((Date.now() - start) <= kLazyRoundTimeCap) {
- let tile = self._crawler.next();
-
- if (!tile) {
- comeAgain = false;
- break;
- }
-
- if (tile.isDirty()) {
- self._renderTile(tile);
- ++rendered;
- }
- ++itered;
- }
-
- dump('crawl itered:' + itered + ' rendered:' + rendered + '\n');
-
- if (comeAgain) {
- self._idleTileCrawlerTimeout = setTimeout(self._idleTileCrawler, 2000, self);
- } else {
- self.stopLazyCrawl();
- dump('crawl end\n');
- }
- }
-
-};
-
-
-/**
- * The tile cache used by the tile manager to hold and index all
- * tiles. Also responsible for pooling tiles and maintaining the
- * number of tiles under given capacity.
- *
- * @param onBeforeTileDetach callback set by the TileManager to call before
- * we must "detach" a tile from a tileholder due to needing it elsewhere or
- * having to discard it on capacity decrease
- * @param capacity the initial capacity of the tile cache, i.e. the max number
- * of tiles the cache can have allocated
- */
-TileManager.TileCache = function TileCache(onBeforeTileDetach, iBound, jBound, capacity) {
- if (arguments.length <= 3 || capacity < 0)
- capacity = Infinity;
-
- // We track all pooled tiles in a 2D array (row, column) ordered as
- // they "appear on screen". The array is a grid that functions for
- // storage of the tiles and as a lookup map. Each array entry is
- // a reference to the tile occupying that space ("tileholder"). Entries
- // are not unique, so a tile could be referenced by multiple array entries,
- // i.e. a tile could "span" many tile placeholders (e.g. if we merge
- // neighbouring tiles).
- this._tiles = [];
-
- // holds the same tiles that _tiles holds, but as contiguous array
- // elements, for pooling tiles for reuse under finite capacity
- this._tilePool = (capacity == Infinity) ? new Array() : new Array(capacity);
-
- this._capacity = capacity;
- this._nTiles = 0;
- this._numFree = 0;
-
- this._onBeforeTileDetach = onBeforeTileDetach;
-
- this.iBound = iBound;
- this.jBound = jBound;
-};
-
-TileManager.TileCache.prototype = {
-
- get size() { return this._nTiles; },
- get numFree() { return this._numFree; },
-
- // A comparison function that will compare all free tiles as greater
- // than all non-free tiles. Useful because, for instance, to shrink
- // the tile pool when capacity is lowered, we want to remove all tiles
- // at the new cap and beyond, favoring removal of free tiles first.
- evictionCmp: function freeTilesLast(a, b) {
- if (a.free == b.free) return (a.j == b.j) ? b.i - a.i : b.j - a.j;
- return (a.free) ? 1 : -1;
- },
-
- getCapacity: function getCapacity() { return this._capacity; },
-
- setCapacity: function setCapacity(newCap, skipEvictionQueueSort) {
- if (newCap < 0)
- throw "Cannot set a negative tile cache capacity";
-
- if (newCap == Infinity) {
- this._capacity = Infinity;
- return;
- } else if (this._capacity == Infinity) {
- // pretend we had a finite capacity all along and proceed normally
- this._capacity = this._tilePool.length;
- }
-
- let rem = null;
-
- if (newCap < this._capacity) {
- // This case is obnoxious. We're decreasing our capacity which means
- // we may have to get rid of tiles. Depending on our eviction comparator,
- // we probably try to get rid free tiles first, but we might have to throw
- // out some nonfree ones too. Note that "throwing out" means the cache
- // won't keep them, and they'll get GC'ed as soon as all other refholders
- // let go of their refs to the tile.
- if (!skipEvictionQueueSort)
- this.sortEvictionQueue();
-
- rem = this._tilePool.splice(newCap, this._tilePool.length);
-
- } else {
- // This case is win. Extend our tile pool array with new empty space.
- this._tilePool.push.apply(this._tilePool, new Array(newCap - this._capacity));
- }
-
- // update state in the case that we threw things out.
- let nTilesDeleted = this._nTiles - newCap;
- if (nTilesDeleted > 0) {
- let nFreeDeleted = 0;
- for (let k = 0; k < nTilesDeleted; ++k) {
- if (rem[k].free)
- nFreeDeleted++;
-
- this._detachTile(rem[k].i, rem[k].j);
- }
-
- this._nTiles -= nTilesDeleted;
- this._numFree -= nFreeDeleted;
- }
-
- this._capacity = newCap;
- },
-
- _isOccupied: function _isOccupied(i, j) {
- return !!(this._tiles[i] && this._tiles[i][j]);
- },
-
- _detachTile: function _detachTile(i, j) {
- let tile = null;
- if (this._isOccupied(i, j)) {
- tile = this._tiles[i][j];
-
- if (this._onBeforeTileDetach)
- this._onBeforeTileDetach(tile);
-
- this.releaseTile(tile);
- delete this._tiles[i][j];
- }
- return tile;
- },
-
- _reassignTile: function _reassignTile(tile, i, j) {
- this._detachTile(tile.i, tile.j); // detach
- tile.init(i, j); // re-init
- this._tiles[i][j] = tile; // attach
- return tile;
- },
-
- _evictTile: function _evictTile(evictionGuard) {
- let k = this._nTiles - 1;
- let pool = this._tilePool;
- let victim = null;
-
- for (; k >= 0; --k) {
- if (pool[k].free &&
- (!evictionGuard || evictionGuard(pool[k])))
- {
- victim = pool[k];
- break;
- }
- }
-
- return victim;
- },
-
- _createTile: function _createTile(i, j, evictionGuard) {
- if (!this._tiles[i])
- this._tiles[i] = [];
-
- let tile = null;
-
- if (this._nTiles < this._capacity) {
- // either capacity is infinite, or we still have room to allocate more
- tile = new TileManager.Tile(i, j);
- this._tiles[i][j] = tile;
- this._tilePool[this._nTiles++] = tile;
- this._numFree++;
-
- } else {
- // assert: nTiles == capacity
- dump("\nevicting\n");
- tile = this._evictTile(evictionGuard);
- if (tile)
- this._reassignTile(tile, i, j);
- }
-
- return tile;
- },
-
- inBounds: function inBounds(i, j) {
- return 0 <= i && 0 <= j && i <= this.iBound && j <= this.jBound;
- },
-
- sortEvictionQueue: function sortEvictionQueue(cmp) {
- if (!cmp) cmp = this.evictionCmp;
- this._tilePool.sort(cmp);
- },
-
- /**
- * Get a tile by its indices
- *
- * @param i Column
- * @param j Row
- * @param create Flag true if the tile should be created in case there is no
- * tile at (i, j)
- * @param reuseCondition Boolean-valued function to restrict conditions under
- * which an old tile may be reused for creating this one. This can happen if
- * the cache has reached its capacity and must reuse existing tiles in order to
- * create this one. The function is given a Tile object as its argument and
- * returns true if the tile is OK for reuse. This argument has no effect if the
- * create argument is false.
- */
- getTile: function getTile(i, j, create, evictionGuard) {
- if (!this.inBounds(i, j))
- return null;
-
- let tile = null;
-
- if (this._isOccupied(i, j)) {
- tile = this._tiles[i][j];
- } else if (create) {
- tile = this._createTile(i, j, evictionGuard);
- if (tile) tile.markDirty();
- }
-
- return tile;
- },
-
- /**
- * Look up (possibly creating) a tile from its viewport coordinates.
- *
- * @param x
- * @param y
- * @param create Flag true if the tile should be created in case it doesn't
- * already exist at the tileholder corresponding to (x, y)
- */
- tileFromPoint: function tileFromPoint(x, y, create) {
- let i = x >> kTileExponentWidth;
- let j = y >> kTileExponentHeight;
-
- return this.getTile(i, j, create);
- },
-
- /**
- * Hold a tile (i.e. mark it non-free). Returns true if the operation
- * actually did something, false elsewise.
- */
- holdTile: function holdTile(tile) {
- if (tile && tile.free) {
- tile._hold();
- this._numFree--;
- return true;
- }
- return false;
- },
-
- /**
- * Release a tile (i.e. mark it free). Returns true if the operation
- * actually did something, false elsewise.
- */
- releaseTile: function releaseTile(tile) {
- if (tile && !tile.free) {
- tile._release();
- this._numFree++;
- return true;
- }
- return false;
- },
-
- // XXX the following two functions will iterate through duplicate tiles
- // once we begin to merge tiles.
- /**
- * Fetch all tiles that share at least one point with this rect. If `create'
- * is true then any tileless tileholders will have tiles created for them.
- */
- tilesIntersectingRect: function tilesIntersectingRect(rect, create) {
- let dx = (rect.right % kTileWidth) - (rect.left % kTileWidth);
- let dy = (rect.bottom % kTileHeight) - (rect.top % kTileHeight);
- let tiles = [];
-
- for (let y = rect.top; y <= rect.bottom - dy; y += kTileHeight) {
- for (let x = rect.left; x <= rect.right - dx; x += kTileWidth) {
- let tile = this.tileFromPoint(x, y, create);
- if (tile)
- tiles.push(tile);
- }
- }
-
- return tiles;
- },
-
- forEachIntersectingRect: function forEachIntersectingRect(rect, create, fn, thisObj) {
- let visited = {};
- let evictGuard = null;
- if (create) {
- evictGuard = function evictGuard(tile) {
- return !visited[tile.toString()];
- };
- }
-
- let starti = rect.left >> kTileExponentWidth;
- let endi = rect.right >> kTileExponentWidth;
-
- let startj = rect.top >> kTileExponentHeight;
- let endj = rect.bottom >> kTileExponentHeight;
-
- let tile = null;
- for (var j = startj; j <= endj; ++j) {
- for (var i = starti; i <= endi; ++i) {
- tile = this.getTile(i, j, create, evictGuard);
- if (tile) {
- visited[tile.toString()] = true;
- fn.call(thisObj, tile);
- }
- }
- }
- },
-
- holdTilesIntersectingRect: function holdTilesIntersectingRect(rect) {
- this.forEachIntersectingRect(rect, false, this.holdTile, this);
- },
-
- releaseTilesIntersectingRect: function releaseTilesIntersectingRect(rect) {
- this.forEachIntersectingRect(rect, false, this.releaseTile, this);
- }
-
-};
-
-
-
-TileManager.Tile = function Tile(i, j) {
- // canvas element is where we keep paint data from browser for this tile
- this._canvas = document.createElementNS(kXHTMLNamespaceURI, "canvas");
- this._canvas.setAttribute("width", String(kTileWidth));
- this._canvas.setAttribute("height", String(kTileHeight));
- this._canvas.setAttribute("moz-opaque", "true");
- // this._canvas.style.border = "1px solid red";
-
- this.init(i, j); // defines more properties, cf below
-};
-
-TileManager.Tile.prototype = {
-
- // essentially, this is part of constructor code, but since we reuse tiles
- // in the tile cache, this is here so that we can reinitialize tiles when we
- // reuse them
- init: function init(i, j) {
- if (!this.boundRect)
- this.boundRect = new wsRect(i * kTileWidth, j * kTileHeight, kTileWidth, kTileHeight);
- else
- this.boundRect.setRect(i * kTileWidth, j * kTileHeight, kTileWidth, kTileHeight);
-
- // indices!
- this.i = i;
- this.j = j;
-
- // flags true if we need to repaint our own local canvas
- this._dirtyTileCanvas = false;
-
- // keep a dirty rectangle (i.e. only part of the tile is dirty)
- this._dirtyTileCanvasRect = null;
-
- // flag used by TileManager to avoid re-appending tiles that have already
- // been appended
- this._appended = false;
-
- // We keep tile objects around after their use for later reuse, so this
- // flags true for an unused pooled tile. We don't actually care about
- // this from within the Tile prototype, it is here for the cache to use.
- this.free = true;
- },
-
- // viewport coordinates
- get x() { return this.boundRect.left; },
- get y() { return this.boundRect.top; },
-
- // the actual canvas that holds the most recently rendered image of this
- // canvas
- getContentImage: function getContentImage() { return this._canvas; },
-
- isDirty: function isDirty() { return this._dirtyTileCanvas; },
-
- /**
- * Mark this entire tile as dirty (i.e. the whole tile needs to be rendered
- * on next render).
- */
- markDirty: function markDirty() { this.updateDirtyRegion(); },
-
- unmarkDirty: function unmarkDirty() {
- this._dirtyTileCanvasRect = null;
- this._dirtyTileCanvas = false;
- },
-
- /**
- * This will mark dirty at least everything in dirtyRect (which must be
- * specified in canvas coordinates). If dirtyRect is not given then
- * the entire tile is marked dirty.
- */
- updateDirtyRegion: function updateDirtyRegion(dirtyRect) {
- if (!dirtyRect) {
-
- if (!this._dirtyTileCanvasRect)
- this._dirtyTileCanvasRect = this.boundRect.clone();
- else
- this._dirtyTileCanvasRect.copyFrom(this.boundRect);
-
- } else if (!this._dirtyTileCanvasRect) {
- this._dirtyTileCanvasRect = dirtyRect.intersect(this.boundRect);
- } else if (dirtyRect.intersects(this.boundRect)) {
- this._dirtyTileCanvasRect.expandToContain(dirtyRect.intersect(this.boundRect));
- }
-
- // TODO if after the above, the dirty rectangle is large enough,
- // mark the whole tile dirty.
-
- if (this._dirtyTileCanvasRect)
- this._dirtyTileCanvas = true;
- },
-
- /**
- * Actually draw the browser content into the dirty region of this
- * tile. This requires us to actually draw with the
- * nsIDOMCanvasRenderingContext2D object's drawWindow method, which
- * we expect to be a relatively heavy operation.
- *
- * You likely want to check if the tile isDirty() before asking it
- * to render, as this will cause the entire tile to re-render in the
- * case that it is not dirty.
- */
- render: function render(browser, browserView) {
- if (!this.isDirty())
- this.markDirty();
-
- let rect = this._dirtyTileCanvasRect;
-
- let x = rect.left - this.boundRect.left;
- let y = rect.top - this.boundRect.top;
-
- // content process is not being scaled, so don't scale our rect either
- // browserView.viewportToBrowserRect(rect);
- // rect.round(); // snap outward to get whole "pixel" (in browser coords)
-
- let ctx = this._canvas.getContext("2d");
- ctx.save();
-
- browserView.browserToViewportCanvasContext(ctx);
-
- ctx.translate(x, y);
-
- let cw = browserView._contentWindow;
- // let cw = browser.contentWindow;
- ctx.asyncDrawXULElement(browserView._browser,
- rect.left, rect.top,
- rect.right - rect.left, rect.bottom - rect.top,
- "grey",
- (ctx.DRAWWINDOW_DO_NOT_FLUSH | ctx.DRAWWINDOW_DRAW_CARET));
-
- ctx.restore();
-
- this.unmarkDirty();
- },
-
- toString: function toString(more) {
- if (more) {
- return 'Tile(' + [this.i,
- this.j,
- "dirty=" + this.isDirty(),
- "boundRect=" + this.boundRect].join(', ')
- + ')';
- }
-
- return 'Tile(' + this.i + ', ' + this.j + ')';
- },
-
- _hold: function hold() { this.free = false; },
- _release: function release() { this.free = true; }
-
-};
-
-
-/**
- * A CrawlIterator is in charge of creating and returning subsequent tiles "crawled"
- * over as we render tiles lazily. It supports iterator semantics so you can use
- * CrawlIterator objects in for..in loops.
- *
- * Currently the CrawlIterator is built to expand a rectangle iteratively and return
- * subsequent tiles that intersect the boundary of the rectangle. Each expansion of
- * the rectangle is one unit of tile dimensions in each direction. This is repeated
- * until all tiles from elsewhere have been reused (assuming the cache has finite
- * capacity) in this crawl, so that we don't start reusing tiles from the beginning
- * of our crawl. Afterward, the CrawlIterator enters a state where it operates as a
- * FIFO queue, and calls to next() simply dequeue elements, which must be added with
- * enqueue().
- *
- * @param tileCache The TileCache over whose tiles this CrawlIterator will crawl
- * @param startRect [optional] The rectangle that we grow in the first (rectangle
- * expansion) iteration state.
- */
-TileManager.CrawlIterator = function CrawlIterator(tileCache, startRect) {
- this._tileCache = tileCache;
- this._stepRect = startRect;
-
- // used to remember tiles that we've reused during this crawl
- this._visited = {};
-
- // filters the tiles we've already reused once from being considered victims
- // for reuse when we ask the tile cache to create a new tile
- let visited = this._visited;
- this._notVisited = function(tile) { return !visited[tile]; };
-
- // a generator that generates tile indices corresponding to tiles intersecting
- // the boundary of an expanding rectangle
- this._crawlIndices = !startRect ? null : (function indicesGenerator(rect, tc) {
- let outOfBounds = false;
- while (!outOfBounds) {
- // expand rect
- rect.left -= kTileWidth;
- rect.right += kTileWidth;
- rect.top -= kTileHeight;
- rect.bottom += kTileHeight;
-
- let dx = (rect.right % kTileWidth) - (rect.left % kTileWidth);
- let dy = (rect.bottom % kTileHeight) - (rect.top % kTileHeight);
-
- outOfBounds = true;
-
- // top, bottom borders
- for (let y of [rect.top, rect.bottom]) {
- for (let x = rect.left; x <= rect.right - dx; x += kTileWidth) {
- let i = x >> kTileExponentWidth;
- let j = y >> kTileExponentHeight;
- if (tc.inBounds(i, j)) {
- outOfBounds = false;
- yield [i, j];
- }
- }
- }
-
- // left, right borders
- for (let x of [rect.left, rect.right]) {
- for (let y = rect.top; y <= rect.bottom - dy; y += kTileHeight) {
- let i = x >> kTileExponentWidth;
- let j = y >> kTileExponentHeight;
- if (tc.inBounds(i, j)) {
- outOfBounds = false;
- yield [i, j];
- }
- }
- }
- }
- })(this._stepRect, this._tileCache), // instantiate the generator
-
- // after we finish the rectangle iteration state, we enter the FIFO queue state
- this._queueState = !startRect;
- this._queue = [];
-
- // used to prevent tiles from being enqueued twice --- "patience, we'll get to
- // it in a moment"
- this._enqueued = {};
-};
-
-TileManager.CrawlIterator.prototype = {
- __iterator__: function*() {
- while (true) {
- let tile = this.next();
- if (!tile) break;
- yield tile;
- }
- },
-
- becomeQueue: function becomeQueue() {
- this._queueState = true;
- },
-
- unbecomeQueue: function unbecomeQueue() {
- this._queueState = false;
- },
-
- next: function next() {
- if (this._queueState)
- return this.dequeue();
-
- let tile = null;
-
- if (this._crawlIndices) {
- try {
- let [i, j] = this._crawlIndices.next();
- tile = this._tileCache.getTile(i, j, true, this._notVisited);
- } catch (e) {
- if (!(e instanceof StopIteration))
- throw e;
- }
- }
-
- if (tile) {
- this._visited[tile] = true;
- } else {
- this.becomeQueue();
- return this.next();
- }
-
- return tile;
- },
-
- dequeue: function dequeue() {
- let tile = null;
- do {
- let idx = this._queue.shift();
- if (!idx)
- return null;
-
- delete this._enqueued[idx];
- let [i, j] = this._unstrIndices(idx);
- tile = this._tileCache.getTile(i, j, false);
-
- } while (!tile);
-
- return tile;
- },
-
- enqueue: function enqueue(i, j) {
- let idx = this._strIndices(i, j);
- if (!this._enqueued[idx]) {
- this._queue.push(idx);
- this._enqueued[idx] = true;
- }
- },
-
- _strIndices: function _strIndices(i, j) {
- return i + "," + j;
- },
-
- _unstrIndices: function _unstrIndices(str) {
- return str.split(',');
- }
-
-};
diff --git a/toolkit/content/tests/fennec-tile-testapp/chrome/content/WidgetStack.js b/toolkit/content/tests/fennec-tile-testapp/chrome/content/WidgetStack.js
deleted file mode 100644
index 69288e725..000000000
--- a/toolkit/content/tests/fennec-tile-testapp/chrome/content/WidgetStack.js
+++ /dev/null
@@ -1,1438 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-var gWsDoLog = false;
-var gWsLogDiv = null;
-
-function logbase() {
- if (!gWsDoLog)
- return;
-
- if (gWsLogDiv == null && "console" in window) {
- console.log.apply(console, arguments);
- } else {
- var s = "";
- for (var i = 0; i < arguments.length; i++) {
- s += arguments[i] + " ";
- }
- s += "\n";
- if (gWsLogDiv) {
- gWsLogDiv.appendChild(document.createElementNS("http://www.w3.org/1999/xhtml", "br"));
- gWsLogDiv.appendChild(document.createTextNode(s));
- }
-
- dump(s);
- }
-}
-
-function dumpJSStack(stopAtNamedFunction) {
- let caller = Components.stack.caller;
- dump("\tStack: " + caller.name);
- while ((caller = caller.caller)) {
- dump(" <- " + caller.name);
- if (stopAtNamedFunction && caller.name != "anonymous")
- break;
- }
- dump("\n");
-}
-
-function log() {
- // logbase.apply(window, arguments);
-}
-
-function log2() {
- // logbase.apply(window, arguments);
-}
-
-var reportError = log;
-
-/*
- * wsBorder class
- *
- * Simple container for top,left,bottom,right "border" values
- */
-function wsBorder(t, l, b, r) {
- this.setBorder(t, l, b, r);
-}
-
-wsBorder.prototype = {
-
- setBorder: function (t, l, b, r) {
- this.top = t;
- this.left = l;
- this.bottom = b;
- this.right = r;
- },
-
- toString: function () {
- return "[l:" + this.left + ",t:" + this.top + ",r:" + this.right + ",b:" + this.bottom + "]";
- }
-};
-
-/*
- * wsRect class
- *
- * Rectangle class, with both x/y/w/h and t/l/b/r accessors.
- */
-function wsRect(x, y, w, h) {
- this.left = x;
- this.top = y;
- this.right = x+w;
- this.bottom = y+h;
-}
-
-wsRect.prototype = {
-
- get x() { return this.left; },
- get y() { return this.top; },
- get width() { return this.right - this.left; },
- get height() { return this.bottom - this.top; },
- set x(v) {
- let diff = this.left - v;
- this.left = v;
- this.right -= diff;
- },
- set y(v) {
- let diff = this.top - v;
- this.top = v;
- this.bottom -= diff;
- },
- set width(v) { this.right = this.left + v; },
- set height(v) { this.bottom = this.top + v; },
-
- setRect: function(x, y, w, h) {
- this.left = x;
- this.top = y;
- this.right = x+w;
- this.bottom = y+h;
-
- return this;
- },
-
- setBounds: function(t, l, b, r) {
- this.top = t;
- this.left = l;
- this.bottom = b;
- this.right = r;
-
- return this;
- },
-
- equals: function equals(r) {
- return (r != null &&
- this.top == r.top &&
- this.left == r.left &&
- this.bottom == r.bottom &&
- this.right == r.right);
- },
-
- clone: function clone() {
- return new wsRect(this.left, this.top, this.right - this.left, this.bottom - this.top);
- },
-
- center: function center() {
- return [this.left + (this.right - this.left) / 2,
- this.top + (this.bottom - this.top) / 2];
- },
-
- centerRounded: function centerRounded() {
- return this.center().map(Math.round);
- },
-
- copyFrom: function(r) {
- this.top = r.top;
- this.left = r.left;
- this.bottom = r.bottom;
- this.right = r.right;
-
- return this;
- },
-
- copyFromTLBR: function(r) {
- this.left = r.left;
- this.top = r.top;
- this.right = r.right;
- this.bottom = r.bottom;
-
- return this;
- },
-
- translate: function(x, y) {
- this.left += x;
- this.right += x;
- this.top += y;
- this.bottom += y;
-
- return this;
- },
-
- // return a new wsRect that is the union of that one and this one
- union: function(rect) {
- let l = Math.min(this.left, rect.left);
- let r = Math.max(this.right, rect.right);
- let t = Math.min(this.top, rect.top);
- let b = Math.max(this.bottom, rect.bottom);
-
- return new wsRect(l, t, r-l, b-t);
- },
-
- toString: function() {
- return "[" + this.x + "," + this.y + "," + this.width + "," + this.height + "]";
- },
-
- expandBy: function(b) {
- this.left += b.left;
- this.right += b.right;
- this.top += b.top;
- this.bottom += b.bottom;
- return this;
- },
-
- contains: function(other) {
- return !!(other.left >= this.left &&
- other.right <= this.right &&
- other.top >= this.top &&
- other.bottom <= this.bottom);
- },
-
- intersect: function(r2) {
- let xmost1 = this.right;
- let xmost2 = r2.right;
-
- let x = Math.max(this.left, r2.left);
-
- let temp = Math.min(xmost1, xmost2);
- if (temp <= x)
- return null;
-
- let width = temp - x;
-
- let ymost1 = this.bottom;
- let ymost2 = r2.bottom;
- let y = Math.max(this.top, r2.top);
-
- temp = Math.min(ymost1, ymost2);
- if (temp <= y)
- return null;
-
- let height = temp - y;
-
- return new wsRect(x, y, width, height);
- },
-
- intersects: function(other) {
- let xok = (other.left > this.left && other.left < this.right) ||
- (other.right > this.left && other.right < this.right) ||
- (other.left <= this.left && other.right >= this.right);
- let yok = (other.top > this.top && other.top < this.bottom) ||
- (other.bottom > this.top && other.bottom < this.bottom) ||
- (other.top <= this.top && other.bottom >= this.bottom);
- return xok && yok;
- },
-
- /**
- * Similar to (and most code stolen from) intersect(). A restriction
- * is an intersection, but this modifies the receiving object instead
- * of returning a new rect.
- */
- restrictTo: function restrictTo(r2) {
- let xmost1 = this.right;
- let xmost2 = r2.right;
-
- let x = Math.max(this.left, r2.left);
-
- let temp = Math.min(xmost1, xmost2);
- if (temp <= x)
- throw "Intersection is empty but rects cannot be empty";
-
- let width = temp - x;
-
- let ymost1 = this.bottom;
- let ymost2 = r2.bottom;
- let y = Math.max(this.top, r2.top);
-
- temp = Math.min(ymost1, ymost2);
- if (temp <= y)
- throw "Intersection is empty but rects cannot be empty";
-
- let height = temp - y;
-
- return this.setRect(x, y, width, height);
- },
-
- /**
- * Similar to (and most code stolen from) union(). An extension is a
- * union (in our sense of the term, not the common set-theoretic sense),
- * but this modifies the receiving object instead of returning a new rect.
- * Effectively, this rectangle is expanded minimally to contain all of the
- * other rect. "Expanded minimally" means that the rect may shrink if
- * given a strict subset rect as the argument.
- */
- expandToContain: function extendTo(rect) {
- let l = Math.min(this.left, rect.left);
- let r = Math.max(this.right, rect.right);
- let t = Math.min(this.top, rect.top);
- let b = Math.max(this.bottom, rect.bottom);
-
- return this.setRect(l, t, r-l, b-t);
- },
-
- round: function round(scale) {
- if (!scale) scale = 1;
-
- this.left = Math.floor(this.left * scale) / scale;
- this.top = Math.floor(this.top * scale) / scale;
- this.right = Math.ceil(this.right * scale) / scale;
- this.bottom = Math.ceil(this.bottom * scale) / scale;
-
- return this;
- },
-
- scale: function scale(xscl, yscl) {
- this.left *= xscl;
- this.right *= xscl;
- this.top *= yscl;
- this.bottom *= yscl;
-
- return this;
- }
-};
-
-/*
- * The "Widget Stack"
- *
- * Manages a <xul:stack>'s children, allowing them to be dragged around
- * the stack, subject to specified constraints. Optionally supports
- * one widget designated as the viewport, which can be panned over a virtual
- * area without needing to draw that area entirely. The viewport widget
- * is designated by a 'viewport' attribute on the child element.
- *
- * Widgets are subject to various constraints, specified in xul via the
- * 'constraint' attribute. Current constraints are:
- * ignore-x: When panning, ignore any changes to the widget's x position
- * ignore-y: When panning, ignore any changes to the widget's y position
- * vp-relative: This widget's position should be claculated relative to
- * the viewport widget. It will always keep the same offset from that
- * widget as initially laid out, regardless of changes to the viewport
- * bounds.
- * frozen: This widget is in a fixed position and should never pan.
- */
-function WidgetStack(el, ew, eh) {
- this.init(el, ew, eh);
-}
-
-WidgetStack.prototype = {
- // the <stack> element
- _el: null,
-
- // object indexed by widget id, with state struct for each object (see _addNewWidget)
- _widgetState: null,
-
- // any barriers
- _barriers: null,
-
- // If a viewport widget is present, this will point to its state object;
- // otherwise null.
- _viewport: null,
-
- // a wsRect; the inner bounds of the viewport content
- _viewportBounds: null,
- // a wsBorder; the overflow area to the side of the bounds where our
- // viewport-relative widgets go
- _viewportOverflow: null,
-
- // a wsRect; the viewportBounds expanded by the viewportOverflow
- _pannableBounds: null,
- get pannableBounds() {
- if (!this._pannableBounds) {
- this._pannableBounds = this._viewportBounds.clone()
- .expandBy(this._viewportOverflow);
- }
- return this._pannableBounds.clone();
- },
-
- // a wsRect; the currently visible part of pannableBounds.
- _viewingRect: null,
-
- // the amount of current global offset applied to all widgets (whether
- // static or not). Set via offsetAll(). Can be used to push things
- // out of the way for overlaying some other UI.
- globalOffsetX: 0,
- globalOffsetY: 0,
-
- // if true (default), panning is constrained to the pannable bounds.
- _constrainToViewport: true,
-
- _viewportUpdateInterval: -1,
- _viewportUpdateTimeout: -1,
-
- _viewportUpdateHandler: null,
- _panHandler: null,
-
- _dragState: null,
-
- _skipViewportUpdates: 0,
- _forceViewportUpdate: false,
-
- //
- // init:
- // el: the <stack> element whose children are to be managed
- //
- init: function (el, ew, eh) {
- this._el = el;
- this._widgetState = {};
- this._barriers = [];
-
- let rect = this._el.getBoundingClientRect();
- let width = rect.width;
- let height = rect.height;
-
- if (ew != undefined && eh != undefined) {
- width = ew;
- height = eh;
- }
-
- this._viewportOverflow = new wsBorder(0, 0, 0, 0);
-
- this._viewingRect = new wsRect(0, 0, width, height);
-
- // listen for DOMNodeInserted/DOMNodeRemoved/DOMAttrModified
- let children = this._el.childNodes;
- for (let i = 0; i < children.length; i++) {
- let c = this._el.childNodes[i];
- if (c.tagName == "spacer")
- this._addNewBarrierFromSpacer(c);
- else
- this._addNewWidget(c);
- }
-
- // this also updates the viewportOverflow and pannableBounds
- this._updateWidgets();
-
- if (this._viewport) {
- this._viewportBounds = new wsRect(0, 0, this._viewport.rect.width, this._viewport.rect.height);
- } else {
- this._viewportBounds = new wsRect(0, 0, 0, 0);
- }
- },
-
- // moveWidgetBy: move the widget with the given id by x,y. Should
- // not be used on vp-relative or otherwise frozen widgets (using it
- // on the x coordinate for x-ignore widgets and similarily for y is
- // ok, as long as the other coordinate remains 0.)
- moveWidgetBy: function (wid, x, y) {
- let state = this._getState(wid);
-
- state.rect.x += x;
- state.rect.y += y;
-
- this._commitState(state);
- },
-
- // panBy: pan the entire set of widgets by the given x and y amounts.
- // This does the same thing as if the user dragged by the given amount.
- // If this is called with an outstanding drag, weirdness might happen,
- // but it also might work, so not disabling that.
- //
- // if ignoreBarriers is true, then barriers are ignored for the pan.
- panBy: function panBy(dx, dy, ignoreBarriers) {
- dx = Math.round(dx);
- dy = Math.round(dy);
-
- if (dx == 0 && dy == 0)
- return false;
-
- let needsDragWrap = !this._dragging;
-
- if (needsDragWrap)
- this.dragStart(0, 0);
-
- let panned = this._panBy(dx, dy, ignoreBarriers);
-
- if (needsDragWrap)
- this.dragStop();
-
- return panned;
- },
-
- // panTo: pan the entire set of widgets so that the given x,y
- // coordinates are in the upper left of the stack. If either is
- // null or undefined, only move the other axis
- panTo: function panTo(x, y) {
- if (x == undefined || x == null)
- x = this._viewingRect.x;
- if (y == undefined || y == null)
- y = this._viewingRect.y;
- this.panBy(x - this._viewingRect.x, y - this._viewingRect.y, true);
- },
-
- // freeze: set a widget as frozen. A frozen widget won't be moved
- // in the stack -- its x,y position will still be tracked in the
- // state, but the left/top attributes won't be overwritten. Call unfreeze
- // to move the widget back to where the ws thinks it should be.
- freeze: function (wid) {
- let state = this._getState(wid);
-
- state.frozen = true;
- },
-
- unfreeze: function (wid) {
- let state = this._getState(wid);
- if (!state.frozen)
- return;
-
- state.frozen = false;
- this._commitState(state);
- },
-
- // moveFrozenTo: move a frozen widget with id wid to x, y in the stack.
- // can only be used on frozen widgets
- moveFrozenTo: function (wid, x, y) {
- let state = this._getState(wid);
- if (!state.frozen)
- throw "moveFrozenTo on non-frozen widget " + wid;
-
- state.widget.setAttribute("left", x);
- state.widget.setAttribute("top", y);
- },
-
- // moveUnfrozenTo: move an unfrozen, pannable widget with id wid to x, y in
- // the stack. should only be used on unfrozen widgets when a dynamic change
- // in position needs to be made. we basically remove, adjust and re-add
- // the widget
- moveUnfrozenTo: function (wid, x, y) {
- delete this._widgetState[wid];
- let widget = document.getElementById(wid);
- if (x) widget.setAttribute("left", x);
- if (y) widget.setAttribute("top", y);
- this._addNewWidget(widget);
- this._updateWidgets();
- },
-
- // we're relying on viewportBounds and viewingRect having the same origin
- get viewportVisibleRect () {
- let rect = this._viewportBounds.intersect(this._viewingRect);
- if (!rect)
- rect = new wsRect(0, 0, 0, 0);
- return rect;
- },
-
- isWidgetFrozen: function isWidgetFrozen(wid) {
- return this._getState(wid).frozen;
- },
-
- // isWidgetVisible: return true if any portion of widget with id wid is
- // visible; otherwise return false.
- isWidgetVisible: function (wid) {
- let state = this._getState(wid);
- let visibleStackRect = new wsRect(0, 0, this._viewingRect.width, this._viewingRect.height);
-
- return visibleStackRect.intersects(state.rect);
- },
-
- // getWidgetVisibility: returns the percentage that the widget is visible
- getWidgetVisibility: function (wid) {
- let state = this._getState(wid);
- let visibleStackRect = new wsRect(0, 0, this._viewingRect.width, this._viewingRect.height);
-
- let visibleRect = visibleStackRect.intersect(state.rect);
- if (visibleRect)
- return [visibleRect.width / state.rect.width, visibleRect.height / state.rect.height]
-
- return [0, 0];
- },
-
- // offsetAll: add an offset to all widgets
- offsetAll: function (x, y) {
- this.globalOffsetX += x;
- this.globalOffsetY += y;
-
- for (let wid in this._widgetState) {
- let state = this._widgetState[wid];
- state.rect.x += x;
- state.rect.y += y;
-
- this._commitState(state);
- }
- },
-
- // setViewportBounds
- // nb: an object containing top, left, bottom, right properties
- // OR
- // width, height: integer values; origin assumed to be 0,0
- // OR
- // top, left, bottom, right: integer values
- //
- // Set the bounds of the viewport area; that is, set the size of the
- // actual content that the viewport widget will be providing a view
- // over. For example, in the case of a 100x100 viewport showing a
- // view into a 100x500 webpage, the viewport bounds would be
- // { top: 0, left: 0, bottom: 500, right: 100 }.
- //
- // setViewportBounds will move all the viewport-relative widgets into
- // place based on the new viewport bounds.
- setViewportBounds: function setViewportBounds() {
- let oldBounds = this._viewportBounds.clone();
-
- if (arguments.length == 1) {
- this._viewportBounds.copyFromTLBR(arguments[0]);
- } else if (arguments.length == 2) {
- this._viewportBounds.setRect(0, 0, arguments[0], arguments[1]);
- } else if (arguments.length == 4) {
- this._viewportBounds.setBounds(arguments[0],
- arguments[1],
- arguments[2],
- arguments[3]);
- } else {
- throw "Invalid number of arguments to setViewportBounds";
- }
-
- let vp = this._viewport;
-
- let dleft = this._viewportBounds.left - oldBounds.left;
- let dright = this._viewportBounds.right - oldBounds.right;
- let dtop = this._viewportBounds.top - oldBounds.top;
- let dbottom = this._viewportBounds.bottom - oldBounds.bottom;
-
- // log2("setViewportBounds dltrb", dleft, dtop, dright, dbottom);
-
- // move all vp-relative widgets to be the right offset from the bounds again
- for (let wid in this._widgetState) {
- let state = this._widgetState[wid];
- if (state.vpRelative) {
- // log2("vpRelative widget", state.id, state.rect.x, dleft, dright);
- if (state.vpOffsetXBefore) {
- state.rect.x += dleft;
- } else {
- state.rect.x += dright;
- }
-
- if (state.vpOffsetYBefore) {
- state.rect.y += dtop;
- } else {
- state.rect.y += dbottom;
- }
-
- // log2("vpRelative widget", state.id, state.rect.x, dleft, dright);
- this._commitState(state);
- }
- }
-
- for (let bid in this._barriers) {
- let barrier = this._barriers[bid];
-
- // log2("setViewportBounds: looking at barrier", bid, barrier.vpRelative, barrier.type);
-
- if (barrier.vpRelative) {
- if (barrier.type == "vertical") {
- let q = "v barrier moving from " + barrier.x + " to ";
- if (barrier.vpOffsetXBefore) {
- barrier.x += dleft;
- } else {
- barrier.x += dright;
- }
- // log2(q += barrier.x);
- } else if (barrier.type == "horizontal") {
- let q = "h barrier moving from " + barrier.y + " to ";
- if (barrier.vpOffsetYBefore) {
- barrier.y += dtop;
- } else {
- barrier.y += dbottom;
- }
- // log2(q += barrier.y);
- }
- }
- }
-
- // clear the pannable bounds cache to make sure it gets rebuilt
- this._pannableBounds = null;
-
- // now let's make sure that the viewing rect and inner bounds are still valid
- this._adjustViewingRect();
-
- this._viewportUpdate(0, 0, true);
- },
-
- // setViewportHandler
- // uh: A function object
- //
- // The given function object is called at the end of every drag and viewport
- // bounds change, passing in the new rect that's to be displayed in the
- // viewport.
- //
- setViewportHandler: function (uh) {
- this._viewportUpdateHandler = uh;
- },
-
- // setPanHandler
- // uh: A function object
- //
- // The given functin object is called whenever elements pan; it provides
- // the new area of the pannable bounds that's visible in the stack.
- setPanHandler: function (uh) {
- this._panHandler = uh;
- },
-
- // dragStart: start a drag, with the current coordinates being clientX,clientY
- dragStart: function dragStart(clientX, clientY) {
- log("(dragStart)", clientX, clientY);
-
- if (this._dragState) {
- reportError("dragStart with drag already in progress? what?");
- this._dragState = null;
- }
-
- this._dragState = { };
-
- let t = Date.now();
-
- this._dragState.barrierState = [];
-
- this._dragState.startTime = t;
- // outer x, that is outer from the viewport coordinates. In stack-relative coords.
- this._dragState.outerStartX = clientX;
- this._dragState.outerStartY = clientY;
-
- this._dragCoordsFromClient(clientX, clientY, t);
-
- this._dragState.outerLastUpdateDX = 0;
- this._dragState.outerLastUpdateDY = 0;
-
- if (this._viewport) {
- // create a copy of these so that we can compute
- // deltas correctly to update the viewport
- this._viewport.dragStartRect = this._viewport.rect.clone();
- }
-
- this._dragState.dragging = true;
- },
-
- _viewportDragUpdate: function viewportDragUpdate() {
- let vws = this._viewport;
- this._viewportUpdate((vws.dragStartRect.x - vws.rect.x),
- (vws.dragStartRect.y - vws.rect.y));
- },
-
- // dragStop: stop any drag in progress
- dragStop: function dragStop() {
- log("(dragStop)");
-
- if (!this._dragging)
- return;
-
- if (this._viewportUpdateTimeout != -1)
- clearTimeout(this._viewportUpdateTimeout);
-
- this._viewportDragUpdate();
-
- this._dragState = null;
- },
-
- // dragMove: process a mouse move to clientX,clientY for an ongoing drag
- dragMove: function dragMove(clientX, clientY) {
- if (!this._dragging)
- return false;
-
- this._dragCoordsFromClient(clientX, clientY);
-
- let panned = this._dragUpdate();
-
- if (this._viewportUpdateInterval != -1) {
- if (this._viewportUpdateTimeout != -1)
- clearTimeout(this._viewportUpdateTimeout);
- let self = this;
- this._viewportUpdateTimeout = setTimeout(function () { self._viewportDragUpdate(); }, this._viewportUpdateInterval);
- }
-
- return panned;
- },
-
- // dragBy: process a mouse move by dx,dy for an ongoing drag
- dragBy: function dragBy(dx, dy) {
- return this.dragMove(this._dragState.outerCurX + dx, this._dragState.outerCurY + dy);
- },
-
- // updateSize: tell the WidgetStack to update its size, because it
- // was either resized or some other event took place.
- updateSize: function updateSize(width, height) {
- if (width == undefined || height == undefined) {
- let rect = this._el.getBoundingClientRect();
- width = rect.width;
- height = rect.height;
- }
-
- // update widget rects and viewportOverflow, since the resize might have
- // caused them to change (widgets first, since the viewportOverflow depends
- // on them).
-
- // XXX these methods aren't working correctly yet, but they aren't strictly
- // necessary in Fennec's default config
- // for (let wid in this._widgetState) {
- // let s = this._widgetState[wid];
- // this._updateWidgetRect(s);
- // }
- // this._updateViewportOverflow();
-
- this._viewingRect.width = width;
- this._viewingRect.height = height;
-
- // Wrap this call in a batch to ensure that we always call the
- // viewportUpdateHandler, even if _adjustViewingRect doesn't trigger a pan.
- // If it does, the batch also ensures that we don't call the handler twice.
- this.beginUpdateBatch();
- this._adjustViewingRect();
- this.endUpdateBatch();
- },
-
- beginUpdateBatch: function startUpdate() {
- if (!this._skipViewportUpdates) {
- this._startViewportBoundsString = this._viewportBounds.toString();
- this._forceViewportUpdate = false;
- }
- this._skipViewportUpdates++;
- },
-
- endUpdateBatch: function endUpdate(aForceRedraw) {
- if (!this._skipViewportUpdates)
- throw new Error("Unbalanced call to endUpdateBatch");
-
- this._forceViewportUpdate = this._forceViewportUpdate || aForceRedraw;
-
- this._skipViewportUpdates--;
- if (this._skipViewportUpdates)
- return;
-
- let boundsSizeChanged =
- this._startViewportBoundsString != this._viewportBounds.toString();
- this._callViewportUpdateHandler(boundsSizeChanged || this._forceViewportUpdate);
- },
-
- //
- // Internal code
- //
-
- _updateWidgetRect: function(state) {
- // don't need to support updating the viewport rect at the moment
- // (we'd need to duplicate the vptarget* code from _addNewWidget if we did)
- if (state == this._viewport)
- return;
-
- let w = state.widget;
- let x = w.getAttribute("left") || 0;
- let y = w.getAttribute("top") || 0;
- let rect = w.getBoundingClientRect();
- state.rect = new wsRect(parseInt(x), parseInt(y),
- rect.right - rect.left,
- rect.bottom - rect.top);
- if (w.hasAttribute("widgetwidth") && w.hasAttribute("widgetheight")) {
- state.rect.width = parseInt(w.getAttribute("widgetwidth"));
- state.rect.height = parseInt(w.getAttribute("widgetheight"));
- }
- },
-
- _dumpRects: function () {
- dump("WidgetStack:\n");
- dump("\tthis._viewportBounds: " + this._viewportBounds + "\n");
- dump("\tthis._viewingRect: " + this._viewingRect + "\n");
- dump("\tthis._viewport.viewportInnerBounds: " + this._viewport.viewportInnerBounds + "\n");
- dump("\tthis._viewport.rect: " + this._viewport.rect + "\n");
- dump("\tthis._viewportOverflow: " + this._viewportOverflow + "\n");
- dump("\tthis.pannableBounds: " + this.pannableBounds + "\n");
- },
-
- // Ensures that _viewingRect is within _pannableBounds (call this when either
- // one is resized)
- _adjustViewingRect: function _adjustViewingRect() {
- let vr = this._viewingRect;
- let pb = this.pannableBounds;
-
- if (pb.contains(vr))
- return; // nothing to do here
-
- // don't bother adjusting _viewingRect if it can't fit into
- // _pannableBounds
- if (vr.height > pb.height || vr.width > pb.width)
- return;
-
- let panX = 0, panY = 0;
- if (vr.right > pb.right)
- panX = pb.right - vr.right;
- else if (vr.left < pb.left)
- panX = pb.left - vr.left;
-
- if (vr.bottom > pb.bottom)
- panY = pb.bottom - vr.bottom;
- else if (vr.top < pb.top)
- panY = pb.top - vr.top;
-
- this.panBy(panX, panY, true);
- },
-
- _getState: function (wid) {
- let w = this._widgetState[wid];
- if (!w)
- throw "Unknown widget id '" + wid + "'; widget not in stack";
- return w;
- },
-
- get _dragging() {
- return this._dragState && this._dragState.dragging;
- },
-
- _viewportUpdate: function _viewportUpdate(dX, dY, boundsChanged) {
- if (!this._viewport)
- return;
-
- this._viewportUpdateTimeout = -1;
-
- let vws = this._viewport;
- let vwib = vws.viewportInnerBounds;
- let vpb = this._viewportBounds;
-
- // recover the amount the inner bounds moved by the amount the viewport
- // widget moved, but don't include offsets that we're making up from previous
- // drags that didn't affect viewportInnerBounds
- let [ignoreX, ignoreY] = this._offsets || [0, 0];
- let rx = dX - ignoreX;
- let ry = dY - ignoreY;
-
- [dX, dY] = this._rectTranslateConstrain(rx, ry, vwib, vpb);
-
- // record the offsets that correspond to the amount of the drag we're ignoring
- // to ensure the viewportInnerBounds remains within the viewportBounds
- this._offsets = [dX - rx, dY - ry];
-
- // adjust the viewportInnerBounds, and snap the viewport back
- vwib.translate(dX, dY);
- vws.rect.translate(dX, dY);
- this._commitState(vws);
-
- // update this so that we can call this function again during the same drag
- // and get the right values.
- vws.dragStartRect = vws.rect.clone();
-
- this._callViewportUpdateHandler(boundsChanged);
- },
-
- _callViewportUpdateHandler: function _callViewportUpdateHandler(boundsChanged) {
- if (!this._viewport || !this._viewportUpdateHandler || this._skipViewportUpdates)
- return;
-
- let vwb = this._viewportBounds.clone();
-
- let vwib = this._viewport.viewportInnerBounds.clone();
-
- let vis = this.viewportVisibleRect;
-
- vwib.left += this._viewport.offsetLeft;
- vwib.top += this._viewport.offsetTop;
- vwib.right += this._viewport.offsetRight;
- vwib.bottom += this._viewport.offsetBottom;
-
- this._viewportUpdateHandler.apply(window, [vwb, vwib, vis, boundsChanged]);
- },
-
- _dragCoordsFromClient: function (cx, cy, t) {
- this._dragState.curTime = t ? t : Date.now();
- this._dragState.outerCurX = cx;
- this._dragState.outerCurY = cy;
-
- let dx = this._dragState.outerCurX - this._dragState.outerStartX;
- let dy = this._dragState.outerCurY - this._dragState.outerStartY;
- this._dragState.outerDX = dx;
- this._dragState.outerDY = dy;
- },
-
- _panHandleBarriers: function (dx, dy) {
- // XXX unless the barriers are sorted by position, this will break
- // with multiple barriers that are near enough to eachother that a
- // drag could cross more than one.
-
- let vr = this._viewingRect;
-
- // XXX this just stops at the first horizontal and vertical barrier it finds
-
- // barrier_[xy] is the barrier that was used to get to the final
- // barrier_d[xy] value. if null, no barrier, and dx/dy shouldn't
- // be replaced with barrier_d[xy].
- let barrier_y = null, barrier_x = null;
- let barrier_dy = 0, barrier_dx = 0;
-
- for (let i = 0; i < this._barriers.length; i++) {
- let b = this._barriers[i];
-
- // log2("barrier", i, b.type, b.x, b.y);
-
- if (dx != 0 && b.type == "vertical") {
- if (barrier_x != null) {
- delete this._dragState.barrierState[i];
- continue;
- }
-
- let alreadyKnownDistance = this._dragState.barrierState[i] || 0;
-
- // log2("alreadyKnownDistance", alreadyKnownDistance);
-
- let dbx = 0;
-
- // 100 <= 100 && 100-(-5) > 100
-
- if ((vr.left <= b.x && vr.left+dx > b.x) ||
- (vr.left >= b.x && vr.left+dx < b.x))
- {
- dbx = b.x - vr.left;
- } else if ((vr.right <= b.x && vr.right+dx > b.x) ||
- (vr.right >= b.x && vr.right+dx < b.x))
- {
- dbx = b.x - vr.right;
- } else {
- delete this._dragState.barrierState[i];
- continue;
- }
-
- let leftoverDistance = dbx - dx;
-
- // log2("initial dbx", dbx, leftoverDistance);
-
- let dist = Math.abs(leftoverDistance + alreadyKnownDistance) - b.size;
-
- if (dist >= 0) {
- if (dx < 0)
- dbx -= dist;
- else
- dbx += dist;
- delete this._dragState.barrierState[i];
- } else {
- dbx = 0;
- this._dragState.barrierState[i] = leftoverDistance + alreadyKnownDistance;
- }
-
- // log2("final dbx", dbx, "state", this._dragState.barrierState[i]);
-
- if (Math.abs(barrier_dx) <= Math.abs(dbx)) {
- barrier_x = b;
- barrier_dx = dbx;
-
- // log2("new barrier_dx", barrier_dx);
- }
- }
-
- if (dy != 0 && b.type == "horizontal") {
- if (barrier_y != null) {
- delete this._dragState.barrierState[i];
- continue;
- }
-
- let alreadyKnownDistance = this._dragState.barrierState[i] || 0;
-
- // log2("alreadyKnownDistance", alreadyKnownDistance);
-
- let dby = 0;
-
- // 100 <= 100 && 100-(-5) > 100
-
- if ((vr.top <= b.y && vr.top+dy > b.y) ||
- (vr.top >= b.y && vr.top+dy < b.y))
- {
- dby = b.y - vr.top;
- } else if ((vr.bottom <= b.y && vr.bottom+dy > b.y) ||
- (vr.bottom >= b.y && vr.bottom+dy < b.y))
- {
- dby = b.y - vr.bottom;
- } else {
- delete this._dragState.barrierState[i];
- continue;
- }
-
- let leftoverDistance = dby - dy;
-
- // log2("initial dby", dby, leftoverDistance);
-
- let dist = Math.abs(leftoverDistance + alreadyKnownDistance) - b.size;
-
- if (dist >= 0) {
- if (dy < 0)
- dby -= dist;
- else
- dby += dist;
- delete this._dragState.barrierState[i];
- } else {
- dby = 0;
- this._dragState.barrierState[i] = leftoverDistance + alreadyKnownDistance;
- }
-
- // log2("final dby", dby, "state", this._dragState.barrierState[i]);
-
- if (Math.abs(barrier_dy) <= Math.abs(dby)) {
- barrier_y = b;
- barrier_dy = dby;
-
- // log2("new barrier_dy", barrier_dy);
- }
- }
- }
-
- if (barrier_x) {
- // log2("did barrier_x", barrier_x, "barrier_dx", barrier_dx);
- dx = barrier_dx;
- }
-
- if (barrier_y) {
- dy = barrier_dy;
- }
-
- return [dx, dy];
- },
-
- _panBy: function _panBy(dx, dy, ignoreBarriers) {
- let vr = this._viewingRect;
-
- // check if any barriers would be crossed by this pan, and take them
- // into account. do this first.
- if (!ignoreBarriers)
- [dx, dy] = this._panHandleBarriers(dx, dy);
-
- // constrain the full drag of the viewingRect to the pannableBounds.
- // note that the viewingRect needs to move in the opposite
- // direction of the pan, so we fiddle with the signs here (as you
- // pan to the upper left, more of the bottom right becomes visible,
- // so the viewing rect moves to the bottom right of the virtual surface).
- [dx, dy] = this._rectTranslateConstrain(dx, dy, vr, this.pannableBounds);
-
- // If the net result is that we don't have any room to move, then
- // just return.
- if (dx == 0 && dy == 0)
- return false;
-
- // the viewingRect moves opposite of the actual pan direction, see above
- vr.x += dx;
- vr.y += dy;
-
- // Go through each widget and move it by dx,dy. Frozen widgets
- // will be ignored in commitState.
- // The widget rects are in real stack space though, so we need to subtract
- // our (now negated) dx, dy from their coordinates.
- for (let wid in this._widgetState) {
- let state = this._widgetState[wid];
- if (!state.ignoreX)
- state.rect.x -= dx;
- if (!state.ignoreY)
- state.rect.y -= dy;
-
- this._commitState(state);
- }
-
- /* Do not call panhandler during pans within a transaction.
- * Those pans always end-up covering up the checkerboard and
- * do not require sliding out the location bar
- */
- if (!this._skipViewportUpdates && this._panHandler)
- this._panHandler.apply(window, [vr.clone(), dx, dy]);
-
- return true;
- },
-
- _dragUpdate: function _dragUpdate() {
- let dx = this._dragState.outerLastUpdateDX - this._dragState.outerDX;
- let dy = this._dragState.outerLastUpdateDY - this._dragState.outerDY;
-
- this._dragState.outerLastUpdateDX = this._dragState.outerDX;
- this._dragState.outerLastUpdateDY = this._dragState.outerDY;
-
- return this.panBy(dx, dy);
- },
-
- //
- // widget addition/removal
- //
- _addNewWidget: function (w) {
- let wid = w.getAttribute("id");
- if (!wid) {
- reportError("WidgetStack: child widget without id!");
- return;
- }
-
- if (w.getAttribute("hidden") == "true")
- return;
-
- let state = {
- widget: w,
- id: wid,
-
- viewport: false,
- ignoreX: false,
- ignoreY: false,
- sticky: false,
- frozen: false,
- vpRelative: false,
-
- offsetLeft: 0,
- offsetTop: 0,
- offsetRight: 0,
- offsetBottom: 0
- };
-
- this._updateWidgetRect(state);
-
- if (w.hasAttribute("constraint")) {
- let cs = w.getAttribute("constraint").split(",");
- for (let s of cs) {
- if (s == "ignore-x")
- state.ignoreX = true;
- else if (s == "ignore-y")
- state.ignoreY = true;
- else if (s == "sticky")
- state.sticky = true;
- else if (s == "frozen") {
- state.frozen = true;
- } else if (s == "vp-relative")
- state.vpRelative = true;
- }
- }
-
- if (w.hasAttribute("viewport")) {
- if (this._viewport)
- reportError("WidgetStack: more than one viewport canvas in stack!");
-
- this._viewport = state;
- state.viewport = true;
-
- if (w.hasAttribute("vptargetx") && w.hasAttribute("vptargety") &&
- w.hasAttribute("vptargetw") && w.hasAttribute("vptargeth"))
- {
- let wx = parseInt(w.getAttribute("vptargetx"));
- let wy = parseInt(w.getAttribute("vptargety"));
- let ww = parseInt(w.getAttribute("vptargetw"));
- let wh = parseInt(w.getAttribute("vptargeth"));
-
- state.offsetLeft = state.rect.left - wx;
- state.offsetTop = state.rect.top - wy;
- state.offsetRight = state.rect.right - (wx + ww);
- state.offsetBottom = state.rect.bottom - (wy + wh);
-
- state.rect = new wsRect(wx, wy, ww, wh);
- }
-
- // initialize inner bounds to top-left
- state.viewportInnerBounds = new wsRect(0, 0, state.rect.width, state.rect.height);
- }
-
- this._widgetState[wid] = state;
-
- log ("(New widget: " + wid + (state.viewport ? " [viewport]" : "") + " at: " + state.rect + ")");
- },
-
- _removeWidget: function (w) {
- let wid = w.getAttribute("id");
- delete this._widgetState[wid];
- this._updateWidgets();
- },
-
- // updateWidgets:
- // Go through all the widgets and figure out their viewport-relative offsets.
- // If the widget goes to the left or above the viewport widget, then
- // vpOffsetXBefore or vpOffsetYBefore is set.
- // See setViewportBounds for use of vpOffset* state variables, and for how
- // the actual x and y coords of each widget are calculated based on their offsets
- // and the viewport bounds.
- _updateWidgets: function () {
- let vp = this._viewport;
-
- let ofRect = this._viewingRect.clone();
-
- for (let wid in this._widgetState) {
- let state = this._widgetState[wid];
- if (vp && state.vpRelative) {
- // compute the vpOffset from 0,0 assuming that the viewport rect is 0,0
- if (state.rect.left >= vp.rect.right) {
- state.vpOffsetXBefore = false;
- state.vpOffsetX = state.rect.left - vp.rect.width;
- } else {
- state.vpOffsetXBefore = true;
- state.vpOffsetX = state.rect.left - vp.rect.left;
- }
-
- if (state.rect.top >= vp.rect.bottom) {
- state.vpOffsetYBefore = false;
- state.vpOffsetY = state.rect.top - vp.rect.height;
- } else {
- state.vpOffsetYBefore = true;
- state.vpOffsetY = state.rect.top - vp.rect.top;
- }
-
- log("widget", state.id, "offset", state.vpOffsetX, state.vpOffsetXBefore ? "b" : "a", state.vpOffsetY, state.vpOffsetYBefore ? "b" : "a", "rect", state.rect);
- }
- }
-
- this._updateViewportOverflow();
- },
-
- // updates the viewportOverflow/pannableBounds
- _updateViewportOverflow: function() {
- let vp = this._viewport;
- if (!vp)
- return;
-
- let ofRect = new wsRect(0, 0, this._viewingRect.width, this._viewingRect.height);
-
- for (let wid in this._widgetState) {
- let state = this._widgetState[wid];
- if (vp && state.vpRelative) {
- ofRect.left = Math.min(ofRect.left, state.rect.left);
- ofRect.top = Math.min(ofRect.top, state.rect.top);
- ofRect.right = Math.max(ofRect.right, state.rect.right);
- ofRect.bottom = Math.max(ofRect.bottom, state.rect.bottom);
- }
- }
-
- // prevent the viewportOverflow from having positive top/left or negative
- // bottom/right values, which would otherwise happen if there aren't widgets
- // beyond each of those edges
- this._viewportOverflow = new wsBorder(
- /* top*/ Math.round(Math.min(ofRect.top, 0)),
- /* left*/ Math.round(Math.min(ofRect.left, 0)),
- /* bottom*/ Math.round(Math.max(ofRect.bottom - vp.rect.height, 0)),
- /* right*/ Math.round(Math.max(ofRect.right - vp.rect.width, 0))
- );
-
- // clear the _pannableBounds cache, since it depends on the
- // viewportOverflow
- this._pannableBounds = null;
- },
-
- _widgetBounds: function () {
- let r = new wsRect(0, 0, 0, 0);
-
- for (let wid in this._widgetState) {
- let state = this._widgetState[wid];
- r = r.union(state.rect);
- }
-
- return r;
- },
-
- _commitState: function (state) {
- // if the widget is frozen, don't actually update its left/top;
- // presumably the caller is managing those directly for now.
- if (state.frozen)
- return;
- let w = state.widget;
- let l = state.rect.x + state.offsetLeft;
- let t = state.rect.y + state.offsetTop;
-
- // cache left/top to avoid calling setAttribute unnessesarily
- if (state._left != l) {
- state._left = l;
- w.setAttribute("left", l);
- }
-
- if (state._top != t) {
- state._top = t;
- w.setAttribute("top", t);
- }
- },
-
- // constrain translate of rect by dx dy to bounds; return dx dy that can
- // be used to bring rect up to the edge of bounds if we'd go over.
- _rectTranslateConstrain: function (dx, dy, rect, bounds) {
- let newX, newY;
-
- // If the rect is larger than the bounds, allow it to increase its overlap
- let woverflow = rect.width > bounds.width;
- let hoverflow = rect.height > bounds.height;
- if (woverflow || hoverflow) {
- let intersection = rect.intersect(bounds);
- let newIntersection = rect.clone().translate(dx, dy).intersect(bounds);
- if (woverflow)
- newX = (newIntersection.width > intersection.width) ? rect.x + dx : rect.x;
- if (hoverflow)
- newY = (newIntersection.height > intersection.height) ? rect.y + dy : rect.y;
- }
-
- // Common case, rect fits within the bounds
- // clamp new X to within [bounds.left, bounds.right - rect.width],
- // new Y to within [bounds.top, bounds.bottom - rect.height]
- if (isNaN(newX))
- newX = Math.min(Math.max(bounds.left, rect.x + dx), bounds.right - rect.width);
- if (isNaN(newY))
- newY = Math.min(Math.max(bounds.top, rect.y + dy), bounds.bottom - rect.height);
-
- return [newX - rect.x, newY - rect.y];
- },
-
- // add a new barrier from a <spacer>
- _addNewBarrierFromSpacer: function (el) {
- let t = el.getAttribute("barriertype");
-
- // XXX implement these at some point
- // t != "lr" && t != "rl" &&
- // t != "tb" && t != "bt" &&
-
- if (t != "horizontal" &&
- t != "vertical")
- {
- throw "Invalid barrier type: " + t;
- }
-
- let x, y;
-
- let barrier = {};
- let vp = this._viewport;
-
- barrier.type = t;
-
- if (el.getAttribute("left"))
- barrier.x = parseInt(el.getAttribute("left"));
- else if (el.getAttribute("top"))
- barrier.y = parseInt(el.getAttribute("top"));
- else
- throw "Barrier without top or left attribute";
-
- if (el.getAttribute("size"))
- barrier.size = parseInt(el.getAttribute("size"));
- else
- barrier.size = 10;
-
- if (el.hasAttribute("constraint")) {
- let cs = el.getAttribute("constraint").split(",");
- for (let s of cs) {
- if (s == "ignore-x")
- barrier.ignoreX = true;
- else if (s == "ignore-y")
- barrier.ignoreY = true;
- else if (s == "sticky")
- barrier.sticky = true;
- else if (s == "frozen") {
- barrier.frozen = true;
- } else if (s == "vp-relative")
- barrier.vpRelative = true;
- }
- }
-
- if (barrier.vpRelative) {
- if (barrier.type == "vertical") {
- if (barrier.x >= vp.rect.right) {
- barrier.vpOffsetXBefore = false;
- barrier.vpOffsetX = barrier.x - vp.rect.right;
- } else {
- barrier.vpOffsetXBefore = true;
- barrier.vpOffsetX = barrier.x - vp.rect.left;
- }
- } else if (barrier.type == "horizontal") {
- if (barrier.y >= vp.rect.bottom) {
- barrier.vpOffsetYBefore = false;
- barrier.vpOffsetY = barrier.y - vp.rect.bottom;
- } else {
- barrier.vpOffsetYBefore = true;
- barrier.vpOffsetY = barrier.y - vp.rect.top;
- }
-
- // log2("h barrier relative", barrier.vpOffsetYBefore, barrier.vpOffsetY);
- }
- }
-
- this._barriers.push(barrier);
- }
-};
diff --git a/toolkit/content/tests/fennec-tile-testapp/chrome/content/firefoxOverlay.xul b/toolkit/content/tests/fennec-tile-testapp/chrome/content/firefoxOverlay.xul
deleted file mode 100644
index 612f8bb9f..000000000
--- a/toolkit/content/tests/fennec-tile-testapp/chrome/content/firefoxOverlay.xul
+++ /dev/null
@@ -1,15 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<?xml-stylesheet href="chrome://tile/skin/overlay.css" type="text/css"?>
-<!DOCTYPE overlay SYSTEM "chrome://tile/locale/tile.dtd">
-<overlay id="tile-overlay"
- xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
- <script src="overlay.js"/>
- <stringbundleset id="stringbundleset">
- <stringbundle id="tile-strings" src="chrome://tile/locale/tile.properties"/>
- </stringbundleset>
-
- <menupopup id="menu_ToolsPopup">
- <menuitem id="tile-hello" label="&tile.label;"
- oncommand="tile.onMenuItemCommand(event);"/>
- </menupopup>
-</overlay>
diff --git a/toolkit/content/tests/fennec-tile-testapp/chrome/content/foo.xul b/toolkit/content/tests/fennec-tile-testapp/chrome/content/foo.xul
deleted file mode 100644
index cdc01658a..000000000
--- a/toolkit/content/tests/fennec-tile-testapp/chrome/content/foo.xul
+++ /dev/null
@@ -1,460 +0,0 @@
-<window
- xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
- xmlns:html="http://www.w3.org/1999/xhtml"
- onload="onAlmostLoad();"
- style="background-color:white;"
- width="800"
- height="480"
- onresize="onResize();"
- onkeypress="onKeyPress(event);">
-
-<script type="application/javascript" src="WidgetStack.js"/>
-<script type="application/javascript" src="TileManager.js"/>
-<script type="application/javascript" src="BrowserView.js"/>
-<script type="application/javascript">
-<![CDATA[
-
-// We do not endorse the use of globals, but this is just a closed lab
-// environment. What could possibly go wrong? ...
-let bv = null;
-let scrollbox = null;
-let leftbar = null;
-let rightbar = null;
-let topbar = null;
-
-function debug() {
- let w = scrollbox.scrolledWidth;
- let h = scrollbox.scrolledHeight;
- let container = document.getElementById("tile_container");
- let [x, y] = getScrollboxPosition();
- if (bv) {
- dump('----------------------DEBUG!-------------------------\n');
- dump(bv._browserViewportState.toString() + endl);
-
- dump(endl);
-
- let cr = bv._tileManager._criticalRect;
- dump('criticalRect from BV: ' + (cr ? cr.toString() : null) + endl);
- dump('visibleRect from BV : ' + bv._visibleRect.toString() + endl);
- dump('visibleRect from foo: ' + scrollboxToViewportRect(getVisibleRect()) + endl);
-
- dump(endl);
-
- dump('container width,height from BV: ' + bv._container.style.width + ', '
- + bv._container.style.height + endl);
- dump('container width,height via DOM: ' + container.style.width + ', '
- + container.style.height + endl);
-
- dump(endl);
-
- dump('scrollbox position : ' + x + ', ' + y + endl);
- dump('scrollbox scrolledsize: ' + w + ', ' + h + endl);
-
- dump(endl);
-
- dump('tilecache capacity: ' + bv._tileManager._tileCache.getCapacity() + endl);
- dump('tilecache size : ' + bv._tileManager._tileCache.size + endl);
- dump('tilecache numFree : ' + bv._tileManager._tileCache.numFree + endl);
- dump('tilecache iBound : ' + bv._tileManager._tileCache.iBound + endl);
- dump('tilecache jBound : ' + bv._tileManager._tileCache.jBound + endl);
- dump('tilecache _lru : ' + bv._tileManager._tileCache._lru + endl);
-
- dump('-----------------------------------------------------\n');
- }
-}
-
-function debugTile(i, j) {
- let tc = bv._tileManager._tileCache;
- let t = tc.getTile(i, j);
-
- dump('------ DEBUGGING TILE (' + i + ',' + j + ') --------\n');
-
- dump('in bounds: ' + tc.inBounds(i, j) + endl);
- dump('occupied : ' + tc._isOccupied(i, j) + endl);
- if (t)
- {
- dump('toString : ' + t.toString(true) + endl);
- dump('free : ' + t.free + endl);
- dump('dirtyRect: ' + t._dirtyTileCanvasRect + endl);
-
- let len = tc._tilePool.length;
- for (let k = 0; k < len; ++k)
- if (tc._tilePool[k] === t)
- dump('found in tilePool at index ' + k + endl);
- }
-
- dump('------------------------------------\n');
-}
-
-function onKeyPress(e) {
- const a = 97; // debug all critical tiles
- const c = 99; // set tilecache capacity
- const d = 100; // debug dump
- const f = 102; // run noop() through forEachIntersectingRect (for timing)
- const i = 105; // toggle info click mode
- const l = 108; // restart lazy crawl
- const m = 109; // fix mouseout
- const t = 116; // debug given list of tiles separated by space
-
- switch (e.charCode) {
- case d:
- debug();
-
- break;
- case l:
- bv._tileManager.restartLazyCrawl(bv._tileManager._criticalRect);
-
- break;
- case c:
- let cap = parseInt(window.prompt('new capacity'));
- bv._tileManager._tileCache.setCapacity(cap);
-
- break;
- case f:
- let noop = function noop() { for (let i = 0; i < 10; ++i); };
- bv._tileManager._tileCache.forEachIntersectingRect(bv._tileManager._criticalRect,
- false, noop, window);
-
- break;
- case t:
- let ijstrs = window.prompt('row,col plz').split(' ');
- for (let ijstr of ijstrs) {
- let [i, j] = ijstr.split(',').map(x => parseInt(x));
- debugTile(i, j);
- }
-
- break;
- case a:
- let cr = bv._tileManager._criticalRect;
- dump('>>>>>> critical rect is ' + (cr ? cr.toString() : cr) + endl);
- if (cr) {
- let starti = cr.left >> kTileExponentWidth;
- let endi = cr.right >> kTileExponentWidth;
-
- let startj = cr.top >> kTileExponentHeight;
- let endj = cr.bottom >> kTileExponentHeight;
-
- for (var jj = startj; jj <= endj; ++jj)
- for (var ii = starti; ii <= endi; ++ii)
- debugTile(ii, jj);
- }
-
- break;
- case i:
- window.infoMode = !window.infoMode;
- break;
- case m:
- onMouseUp();
- break;
- default:
- break;
- }
-}
-
-function onResize(e) {
- if (bv) {
- bv.beginBatchOperation();
- bv.setVisibleRect(scrollboxToViewportRect(getVisibleRect()));
- bv.zoomToPage();
- bv.commitBatchOperation();
- }
-}
-
-function onMouseDown(e) {
- if (window.infoMode) {
- let [basex, basey] = getScrollboxPosition();
- let [x, y] = scrollboxToViewportXY(basex + e.clientX, basey + e.clientY);
- let i = x >> kTileExponentWidth;
- let j = y >> kTileExponentHeight;
-
- debugTile(i, j);
- }
-
- window._isDragging = true;
- window._dragStart = {x: e.clientX, y: e.clientY};
-
- bv.pauseRendering();
-}
-
-function onMouseUp() {
- window._isDragging = false;
- bv.resumeRendering();
-}
-
-function onMouseMove(e) {
- if (window._isDragging) {
- let x = scrollbox.positionX;
- let y = scrollbox.positionY;
- let w = scrollbox.scrolledWidth;
- let h = scrollbox.scrolledHeight;
-
- let dx = window._dragStart.x - e.clientX;
- let dy = window._dragStart.y - e.clientY;
-
- // XXX if max(x, 0) > scrollwidth we shouldn't do anything (same for y/height)
- let newX = Math.max(x + dx, 0);
- let newY = Math.max(y + dy, 0);
-
- if (newX < w || newY < h) {
- // clip dx and dy to prevent us from going below 0
- dx = Math.max(dx, -x);
- dy = Math.max(dy, -y);
-
- let oldx = x;
- let oldy = y;
-
- bv.onBeforeVisibleMove(dx, dy);
-
- updateBars(oldx, oldy, dx, dy);
- scrollbox.scrollBy(dx, dy);
-
- let [newx, newy] = getScrollboxPosition();
- let realdx = newx - oldx;
- let realdy = newy - oldy;
-
- updateBars(oldx, oldy, realdx, realdy);
- bv.onAfterVisibleMove(realdx, realdy);
- }
- window._dragStart = {x: e.clientX, y: e.clientY};
- }
-}
-
-function onAlmostLoad() {
- window._isDragging = false;
- window.infoMode = false;
- window.setTimeout(onLoad, 1500);
-}
-
-function onLoad() {
- // ----------------------------------------------------
- scrollbox = document.getElementById("scrollbox").boxObject;
- leftbar = document.getElementById("left_sidebar");
- rightbar = document.getElementById("right_sidebar");
- topbar = document.getElementById("top_urlbar");
- // ----------------------------------------------------
-
- let initX = Math.round(leftbar.getBoundingClientRect().right);
- dump('scrolling to ' + initX + endl);
- scrollbox.scrollTo(initX, 0);
- let [x, y] = getScrollboxPosition();
- dump(' scrolled to ' + x + ',' + y + endl);
-
- let container = document.getElementById("tile_container");
- container.addEventListener("mousedown", onMouseDown, true);
- container.addEventListener("mouseup", onMouseUp, true);
- container.addEventListener("mousemove", onMouseMove, true);
-
- bv = new BrowserView(container, scrollboxToViewportRect(getVisibleRect()));
-
- let browser = document.getElementById("googlenews");
- bv.setBrowser(browser, false);
-}
-
-function updateBars(x, y, dx, dy) {
-return;
- // shouldn't update margin if it doesn't need to be changed
- let sidebars = document.getElementsByClassName("sidebar");
- for (let i = 0; i < sidebars.length; i++) {
- let sidebar = sidebars[i];
- sidebar.style.margin = (y + dy) + "px 0px 0px 0px";
- }
-
- let urlbar = document.getElementById("top_urlbar");
- urlbar.style.margin = "0px 0px 0px " + (x + dx) + "px";
-}
-
-function viewportToScrollboxXY(x, y) {
- return scrollboxToViewportXY(x, y, -1);
-}
-
-function scrollboxToViewportXY(x, y) {
- if (!x) x = 0;
- if (!y) y = 0;
-
- // shield your eyes!
- let direction = (arguments.length >= 3) ? arguments[2] : 1;
-
- let leftbarcr = leftbar.getBoundingClientRect();
- let rightbarcr = rightbar.getBoundingClientRect();
- let topbarcr = topbar.getBoundingClientRect();
-
- let xtrans = direction * (-leftbarcr.width);
- let ytrans = direction * (-topbarcr.height);
- x += xtrans;
- y += ytrans;
-
- return [x, y];
-}
-
-function scrollboxToBrowserXY(browserView, x, y) {
- [x, y] = scrollboxToViewportXY(x, y);
- return [browserView.viewportToBrowser(x),
- browserView.viewportToBrowser(y)];
-}
-
-function scrollboxToViewportRect(rect) {
- let leftbarcr = leftbar.getBoundingClientRect();
- let topbarcr = topbar.getBoundingClientRect();
-
- let xtrans = -leftbarcr.width;
- let ytrans = -topbarcr.height;
-
- rect.translate(xtrans, ytrans);
-
- return rect;
-}
-
-function getScrollboxPosition() {
- return [scrollbox.positionX, scrollbox.positionY];
-}
-
-function getContentScrollValues(browser) {
- let cwu = getBrowserDOMWindowUtils(browser);
- let scrollX = {};
- let scrollY = {};
- cwu.getScrollXY(false, scrollX, scrollY);
-
- return [scrollX.value, scrollY.value];
-}
-
-function getBrowserDOMWindowUtils(browser) {
- return browser.contentWindow
- .QueryInterface(Ci.nsIInterfaceRequestor)
- .getInterface(Ci.nsIDOMWindowUtils);
-}
-
-function getBrowserClientRect(browser, el) {
- let [scrollX, scrollY] = getContentScrollValues(browser);
- let r = el.getBoundingClientRect();
-
- return new wsRect(r.left + scrollX,
- r.top + scrollY,
- r.width, r.height);
-}
-
-function scrollToElement(browser, el) {
- var elRect = getPagePosition(browser, el);
- bv.browserToViewportRect(elRect);
- elRect.round();
- this.scrollTo(elRect.x, elRect.y);
-}
-
-function zoomToElement(aElement) {
- const margin = 15;
-
- let elRect = getBrowserClientRect(browser, aElement);
- let elWidth = elRect.width;
- let vrWidth = bv.visibleRect.width;
- /* Try to set zoom-level such that once zoomed element is as wide
- * as the visible rect */
- let zoomLevel = vrtWidth / (elWidth + (2 * margin));
-
- bv.beginBatchOperation();
-
- bv.setZoomLevel(zoomLevel);
-
- /* If zoomLevel ends up clamped to less than asked for, calculate
- * how many more screen pixels will fit horizontally in addition to
- * element's width. This ensures that more of the webpage is
- * showing instead of the navbar. Bug 480595. */
- let xpadding = Math.max(margin, vrWidth - bv.browserToViewport(elWidth));
-
- // XXX TODO these arguments are wrong, we still have to transform the coordinates
- // from viewport to scrollbox before sending them to scrollTo
- this.scrollTo(Math.floor(Math.max(bv.browserToViewport(elRect.x) - xpadding, 0)),
- Math.floor(Math.max(bv.browserToViewport(elRect.y) - margin, 0)));
-
- bv.commitBatchOperation();
-}
-
-function zoomFromElement(browser, aElement) {
- let elRect = getBrowserClientRect(browser, aElement);
-
- bv.beginBatchOperation();
-
- // pan to the element
- // don't bother with x since we're zooming all the way out
- bv.zoomToPage();
-
- // XXX have this center the element on the page
- // XXX TODO these arguments are wrong, we still have to transform the coordinates
- // from viewport to scrollbox before sending them to scrollTo
- this.scrollTo(0, Math.floor(Math.max(0, bv.browserToViewport(elRect.y))));
-
- bv.commitBatchOperation();
-}
-
-/**
- * Retrieve the content element for a given point in client coordinates
- * (relative to the top left corner of the chrome window).
- */
-function elementFromPoint(browser, browserView, x, y) {
- [x, y] = scrollboxToBrowserXY(browserView, x, y);
- let cwu = getBrowserDOMWindowUtils(browser);
- return cwu.elementFromPoint(x, y,
- true, /* ignore root scroll frame*/
- false); /* don't flush layout */
-}
-
-/* ensures that a given content element is visible */
-function ensureElementIsVisible(browser, aElement) {
- let elRect = getBrowserClientRect(browser, aElement);
-
- bv.browserToViewportRect(elRect);
-
- let curRect = bv.visibleRect;
- let newx = curRect.x;
- let newy = curRect.y;
-
- if (elRect.x < curRect.x || elRect.width > curRect.width) {
- newx = elRect.x;
- } else if (elRect.x + elRect.width > curRect.x + curRect.width) {
- newx = elRect.x - curRect.width + elRect.width;
- }
-
- if (elRect.y < curRect.y || elRect.height > curRect.height) {
- newy = elRect.y;
- } else if (elRect.y + elRect.height > curRect.y + curRect.height) {
- newy = elRect.y - curRect.height + elRect.height;
- }
-
- // XXX TODO these arguments are wrong, we still have to transform the coordinates
- // from viewport to scrollbox before sending them to scrollTo
- this.scrollTo(newx, newy);
-}
-
-// this is a mehful way of getting the visible rect in scrollbox coordinates
-// that we use in this here lab environment and hopefully nowhere in real fennec
-function getVisibleRect() {
- let w = window.innerWidth;
- let h = window.innerHeight;
-
- let [x, y] = getScrollboxPosition();
-
- return new wsRect(x, y, w, h);
-}
-
-]]>
-</script>
-
-<scrollbox id="scrollbox" style="-moz-box-orient: vertical; overflow: scroll;" flex="1">
- <hbox id="top_urlbar" style="background-color: pink"><textbox flex="1"/></hbox>
- <hbox style="position: relative">
- <vbox id="left_sidebar" class="sidebar" style="background-color: red"><button label="left sidebar"/></vbox>
- <box>
- <html:div id="tile_container" style="position: relative; width: 800px; height: 480px; overflow: -moz-hidden-unscrollable;"/>
- </box>
- <vbox id="right_sidebar" class="sidebar" style="background-color: blue"><button label="right sidebar"/></vbox>
- </hbox>
-</scrollbox>
-
- <box>
- <html:div style="position: relative; overflow: hidden; max-width: 0px; max-height: 0px; visibility: hidden;">
- <html:div id="browsers" style="position: absolute;">
- <!-- <browser id="googlenews" src="http://www.webhamster.com/" type="content" remote="true" style="width: 1024px; height: 614px"/> -->
- <iframe id="googlenews" src="http://news.google.com/" type="content" remote="true" style="width: 1024px; height: 614px"/>
- </html:div>
- </html:div>
- </box>
-
-</window>
diff --git a/toolkit/content/tests/fennec-tile-testapp/chrome/content/main.xul b/toolkit/content/tests/fennec-tile-testapp/chrome/content/main.xul
deleted file mode 100644
index f829b3f4a..000000000
--- a/toolkit/content/tests/fennec-tile-testapp/chrome/content/main.xul
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0"?>
-<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
-
-<window id="main" title="My App" width="300" height="300"
-xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
- <caption label="Hello World"/>
-</window>
diff --git a/toolkit/content/tests/fennec-tile-testapp/chrome/content/overlay.js b/toolkit/content/tests/fennec-tile-testapp/chrome/content/overlay.js
deleted file mode 100644
index 8dd09af00..000000000
--- a/toolkit/content/tests/fennec-tile-testapp/chrome/content/overlay.js
+++ /dev/null
@@ -1,15 +0,0 @@
-var tile = {
- onLoad: function() {
- // initialization code
- this.initialized = true;
- this.strings = document.getElementById("tile-strings");
- },
- onMenuItemCommand: function(e) {
- var promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
- .getService(Components.interfaces.nsIPromptService);
- promptService.alert(window, this.strings.getString("helloMessageTitle"),
- this.strings.getString("helloMessage"));
- },
-
-};
-window.addEventListener("load", function(e) { tile.onLoad(e); }, false);
diff --git a/toolkit/content/tests/fennec-tile-testapp/chrome/locale/en-US/tile.dtd b/toolkit/content/tests/fennec-tile-testapp/chrome/locale/en-US/tile.dtd
deleted file mode 100644
index 8cffbce35..000000000
--- a/toolkit/content/tests/fennec-tile-testapp/chrome/locale/en-US/tile.dtd
+++ /dev/null
@@ -1 +0,0 @@
-<!ENTITY tile.label "Your localized menuitem">
diff --git a/toolkit/content/tests/fennec-tile-testapp/chrome/locale/en-US/tile.properties b/toolkit/content/tests/fennec-tile-testapp/chrome/locale/en-US/tile.properties
deleted file mode 100644
index 72062a4f0..000000000
--- a/toolkit/content/tests/fennec-tile-testapp/chrome/locale/en-US/tile.properties
+++ /dev/null
@@ -1,3 +0,0 @@
-helloMessage=Hello World!
-helloMessageTitle=Hello
-prefMessage=Int Pref Value: %d
diff --git a/toolkit/content/tests/fennec-tile-testapp/chrome/skin/overlay.css b/toolkit/content/tests/fennec-tile-testapp/chrome/skin/overlay.css
deleted file mode 100644
index 98718057f..000000000
--- a/toolkit/content/tests/fennec-tile-testapp/chrome/skin/overlay.css
+++ /dev/null
@@ -1,5 +0,0 @@
-/* This is just an example. You shouldn't do this. */
-#tile-hello
-{
- color: red ! important;
-}