mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Commit the Fennec tile testapp from Stuart for testing
This commit is contained in:
parent
d125f2e7bb
commit
ecb4b6a7b9
11
toolkit/content/tests/fennec-tile-testapp/application.ini
Normal file
11
toolkit/content/tests/fennec-tile-testapp/application.ini
Normal file
@ -0,0 +1,11 @@
|
||||
[App]
|
||||
Vendor=venderr
|
||||
Name=tile
|
||||
Version=1.0
|
||||
BuildID=20060101
|
||||
Copyright=Copyright (c) 2006 Mark Finkle
|
||||
ID=xulapp@starkravingfinkle.org
|
||||
|
||||
[Gecko]
|
||||
MinVersion=1.8
|
||||
MaxVersion=1.9.2.*
|
@ -0,0 +1 @@
|
||||
content tile file:content/
|
@ -0,0 +1,736 @@
|
||||
// -*- Mode: js2; tab-width: 2; indent-tabs-mode: nil; js2-basic-offset: 2; js2-skip-preprocessor-directives: t; -*-
|
||||
/*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla Mobile Browser.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2008
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Roy Frostig <rfrostig@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
let Ci = Components.interfaces;
|
||||
|
||||
// --- REMOVE ---
|
||||
let noop = function() {};
|
||||
let 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) {
|
||||
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);
|
||||
|
||||
return [w, h];
|
||||
}
|
||||
|
||||
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}';
|
||||
}
|
||||
|
||||
};
|
||||
|
@ -0,0 +1,359 @@
|
||||
let 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);
|
||||
*************************************************************/
|
||||
};
|
||||
let ws = {
|
||||
beginUpdateBatch: noop,
|
||||
panTo: noop,
|
||||
endUpdateBatch: noop
|
||||
};
|
||||
let Ci = Components.interfaces;
|
||||
let bv = null;
|
||||
let 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
|
||||
.QueryInterface(Components.interfaces.nsIScrollBoxObject);
|
||||
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() {
|
||||
let x = {};
|
||||
let y = {};
|
||||
this._scrollbox.getPosition(x, y);
|
||||
return [x.value, y.value];
|
||||
},
|
||||
|
||||
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 = {};
|
||||
let y = {};
|
||||
let w = {};
|
||||
let h = {};
|
||||
scrollbox.getPosition(x, y);
|
||||
scrollbox.getScrolledSize(w, h);
|
||||
|
||||
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.value + dx, 0);
|
||||
let newY = Math.max(y.value + dy, 0);
|
||||
|
||||
if (newX < w.value || newY < h.value) {
|
||||
// clip dx and dy to prevent us from going below 0
|
||||
dx = Math.max(dx, -x.value);
|
||||
dy = Math.max(dy, -y.value);
|
||||
|
||||
bv.onBeforeScroll(x.value, y.value, 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();
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,15 @@
|
||||
<?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>
|
469
toolkit/content/tests/fennec-tile-testapp/chrome/content/foo.xul
Normal file
469
toolkit/content/tests/fennec-tile-testapp/chrome/content/foo.xul
Normal file
@ -0,0 +1,469 @@
|
||||
<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 = {};
|
||||
let h = {};
|
||||
scrollbox.getScrolledSize(w, h);
|
||||
let container = document.getElementById("tile_container");
|
||||
let [x, y] = getScrollboxPosition();
|
||||
let [w, h] = [w.value, h.value];
|
||||
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 each (let ijstr in ijstrs) {
|
||||
let [i, j] = ijstr.split(',').map(function (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 = {};
|
||||
let y = {};
|
||||
let w = {};
|
||||
let h = {};
|
||||
scrollbox.getPosition(x, y);
|
||||
scrollbox.getScrolledSize(w, h);
|
||||
|
||||
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.value + dx, 0);
|
||||
let newY = Math.max(y.value + dy, 0);
|
||||
|
||||
if (newX < w.value || newY < h.value) {
|
||||
// clip dx and dy to prevent us from going below 0
|
||||
dx = Math.max(dx, -x.value);
|
||||
dy = Math.max(dy, -y.value);
|
||||
|
||||
let oldx = x.value;
|
||||
let oldy = y.value;
|
||||
|
||||
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
|
||||
.QueryInterface(Components.interfaces.nsIScrollBoxObject);
|
||||
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() {
|
||||
let x = {};
|
||||
let y = {};
|
||||
scrollbox.getPosition(x, y);
|
||||
return [x.value, y.value];
|
||||
}
|
||||
|
||||
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" style="width: 1024px; height: 614px"/> -->
|
||||
<browser id="googlenews" src="http://news.google.com/" type="content" style="width: 1024px; height: 614px"/>
|
||||
</html:div>
|
||||
</html:div>
|
||||
</box>
|
||||
|
||||
</window>
|
@ -0,0 +1,7 @@
|
||||
<?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>
|
@ -0,0 +1,15 @@
|
||||
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);
|
@ -0,0 +1 @@
|
||||
<!ENTITY tile.label "Your localized menuitem">
|
@ -0,0 +1,3 @@
|
||||
helloMessage=Hello World!
|
||||
helloMessageTitle=Hello
|
||||
prefMessage=Int Pref Value: %d
|
@ -0,0 +1,5 @@
|
||||
/* This is just an example. You shouldn't do this. */
|
||||
#tile-hello
|
||||
{
|
||||
color: red ! important;
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
pref("toolkit.defaultChromeURI", "chrome://tile/content/foo.xul");
|
||||
pref("javascript.options.jit.chrome", true);
|
||||
pref("javascript.options.jit.content", false);
|
||||
pref("browser.dom.window.dump.enabled", true);
|
17
toolkit/content/tests/fennec-tile-testapp/install.rdf
Normal file
17
toolkit/content/tests/fennec-tile-testapp/install.rdf
Normal file
@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:em="http://www.mozilla.org/2004/em-rdf#">
|
||||
<Description about="urn:mozilla:install-manifest">
|
||||
<em:id>tile@roy</em:id>
|
||||
<em:name>tile</em:name>
|
||||
<em:version>1.0</em:version>
|
||||
<em:creator>Roy</em:creator>
|
||||
<em:targetApplication>
|
||||
<Description>
|
||||
<em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id> <!-- firefox -->
|
||||
<em:minVersion>1.5</em:minVersion>
|
||||
<em:maxVersion>3.5.*</em:maxVersion>
|
||||
</Description>
|
||||
</em:targetApplication>
|
||||
</Description>
|
||||
</RDF>
|
104
toolkit/content/tests/fennec-tile-testapp/logread.py
Normal file
104
toolkit/content/tests/fennec-tile-testapp/logread.py
Normal file
@ -0,0 +1,104 @@
|
||||
#!/usr/bin/python
|
||||
import re, sys
|
||||
|
||||
interesting_re = re.compile("(js_Execute|CallHook) ([^ ]+) ([^ ]+ )?([^ ]+ms)")
|
||||
class Entry:
|
||||
def __init__(self, kind, depth, file, linenum, func, timetaken):
|
||||
self.kind = kind
|
||||
self.depth = depth
|
||||
self.file = file
|
||||
self.linenum = linenum
|
||||
self.func = func
|
||||
self.timetaken = timetaken
|
||||
self.calls = 0
|
||||
self.duration = 0
|
||||
|
||||
def __str__(self):
|
||||
return " ".join(map(str,[self.kind, self.depth, self.file, self.linenum, self.func, self.timetaken]))
|
||||
|
||||
def id(self):
|
||||
if self.kind == "js_Execute":
|
||||
return self.file
|
||||
else:
|
||||
if self.file and self.linenum:
|
||||
strout = "%s:%d" % (self.file, self.linenum)
|
||||
if self.func:
|
||||
strout = "%s %s" % (self.func, strout)
|
||||
return strout
|
||||
elif self.func:
|
||||
return self.func
|
||||
else:
|
||||
print("No clue what my id is:"+self)
|
||||
|
||||
def call(self, timetaken):
|
||||
self.calls += 1
|
||||
self.duration += timetaken
|
||||
|
||||
def parse_line(line):
|
||||
m = interesting_re.search(line)
|
||||
if not m:
|
||||
return None
|
||||
|
||||
ms_index = line.find("ms")
|
||||
depth = m.start() - ms_index - 3
|
||||
kind = m.group(1)
|
||||
func = None
|
||||
file = None
|
||||
linenum = None
|
||||
if kind == "CallHook":
|
||||
func = m.group(2)
|
||||
file = m.group(3)
|
||||
colpos = file.rfind(":")
|
||||
(file,linenum) = file[:colpos], file[colpos+1:-1]
|
||||
if linenum == "0":
|
||||
linenum = None
|
||||
else:
|
||||
linenum = int(linenum)
|
||||
offset = 1
|
||||
else:
|
||||
file = m.group(3)
|
||||
|
||||
timetaken = None
|
||||
try:
|
||||
timetaken = float(m.group(4)[:-2])
|
||||
except:
|
||||
return None
|
||||
return Entry(kind, depth, file, linenum, func, timetaken)
|
||||
|
||||
def compare(x,y):
|
||||
diff = x[1].calls - y[1].calls
|
||||
if diff == 0:
|
||||
return int(x[1].duration - y[1].duration)
|
||||
elif diff > 0:
|
||||
return 1
|
||||
elif diff < 0:
|
||||
return -1
|
||||
|
||||
def frequency(ls):
|
||||
dict = {}
|
||||
for item in ls:
|
||||
id = item.id()
|
||||
stat = None
|
||||
if not id in dict:
|
||||
stat = dict[id] = item
|
||||
else:
|
||||
stat = dict[id]
|
||||
stat.call(item.timetaken)
|
||||
|
||||
ls = dict.items()
|
||||
ls.sort(compare)
|
||||
ls = filter(lambda (_,item): item.duration > 20, ls)
|
||||
# ls = filter(lambda (_,item): item.file and item.file.find("browser.js") != -1 and item.linenum <= 1223 and item.linenum >1067, ls)
|
||||
for key, item in ls:
|
||||
print(item.calls,key, str(item.duration)+"ms")
|
||||
|
||||
def go():
|
||||
file = sys.argv[1]
|
||||
|
||||
ls = filter(lambda x: x != None, map(parse_line, open(file).readlines()))
|
||||
|
||||
frequency(ls)
|
||||
print ls[0]
|
||||
|
||||
go()
|
||||
|
Loading…
Reference in New Issue
Block a user