mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
[mq]: tileman
This commit is contained in:
parent
3de71cc1d1
commit
00ca6f826b
748
mobile/chrome/content/BrowserView.js
Normal file
748
mobile/chrome/content/BrowserView.js
Normal file
@ -0,0 +1,748 @@
|
||||
// -*- 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) 2009
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Roy Frostig <rfrostig@mozilla.com>
|
||||
* Stuart Parmenter <stuart@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;
|
||||
|
||||
|
||||
function BrowserView(container, visibleRect) {
|
||||
Util.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 BrowserView.Util.getViewportStateFromBrowser()
|
||||
* for the property name.
|
||||
*/
|
||||
const kBrowserViewZoomLevelMin = 0.2;
|
||||
const kBrowserViewZoomLevelMax = 4.0;
|
||||
const kBrowserViewZoomLevelPrecision = 10000;
|
||||
|
||||
|
||||
// -----------------------------------------------------------
|
||||
// Util/convenience functions.
|
||||
//
|
||||
// These are mostly for use by BrowserView itself, but if you find them handy anywhere
|
||||
// else, feel free.
|
||||
//
|
||||
|
||||
BrowserView.Util = {
|
||||
visibleRectToCriticalRect: function visibleRectToCriticalRect(visibleRect, browserViewportState) {
|
||||
return visibleRect.intersect(browserViewportState.viewportRect);
|
||||
},
|
||||
|
||||
clampZoomLevel: function clampZoomLevel(zl) {
|
||||
let bounded = Math.min(Math.max(kBrowserViewZoomLevelMin, zl), kBrowserViewZoomLevelMax);
|
||||
return Math.round(bounded * kBrowserViewZoomLevelPrecision) / kBrowserViewZoomLevelPrecision;
|
||||
},
|
||||
|
||||
pageZoomLevel: function pageZoomLevel(visibleRect, browserW, browserH) {
|
||||
return BrowserView.Util.clampZoomLevel(visibleRect.width / browserW);
|
||||
},
|
||||
|
||||
seenBrowser: function seenBrowser(browser) {
|
||||
return !!(browser.__BrowserView__vps);
|
||||
},
|
||||
|
||||
initBrowserState: function initBrowserState(browser, visibleRect) {
|
||||
let [browserW, browserH] = BrowserView.Util.getBrowserDimensions(browser);
|
||||
|
||||
let zoomLevel = BrowserView.Util.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);
|
||||
},
|
||||
|
||||
getViewportStateFromBrowser: function getViewportStateFromBrowser(browser) {
|
||||
return browser.__BrowserView__vps;
|
||||
},
|
||||
|
||||
getBrowserDimensions: 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];
|
||||
},
|
||||
|
||||
getContentScrollValues: function getContentScrollValues(browser) {
|
||||
let cwu = BrowserView.Util.getBrowserDOMWindowUtils(browser);
|
||||
let scrollX = {};
|
||||
let scrollY = {};
|
||||
cwu.getScrollXY(false, scrollX, scrollY);
|
||||
|
||||
return [scrollX.value, scrollY.value];
|
||||
},
|
||||
|
||||
getBrowserDOMWindowUtils: function getBrowserDOMWindowUtils(browser) {
|
||||
return browser.contentWindow
|
||||
.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindowUtils);
|
||||
},
|
||||
|
||||
getNewBatchOperationState: function getNewBatchOperationState() {
|
||||
return {
|
||||
viewportSizeChanged: false,
|
||||
dirtyAll: false
|
||||
};
|
||||
},
|
||||
|
||||
clampViewportWH: function clampViewportWH(width, height, visibleRect) {
|
||||
let minW = visibleRect.width;
|
||||
let minH = visibleRect.height;
|
||||
return [Math.max(width, minW), Math.max(height, minH)];
|
||||
},
|
||||
|
||||
initContainer: function initContainer(container, visibleRect) {
|
||||
container.style.width = visibleRect.width + 'px';
|
||||
container.style.height = visibleRect.height + 'px';
|
||||
container.style.overflow = '-moz-hidden-unscrollable';
|
||||
},
|
||||
|
||||
resizeContainerToViewport: function resizeContainerToViewport(container, viewportRect) {
|
||||
container.style.width = viewportRect.width + 'px';
|
||||
container.style.height = viewportRect.height + 'px';
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
BrowserView.prototype = {
|
||||
|
||||
// -----------------------------------------------------------
|
||||
// Public instance methods
|
||||
//
|
||||
|
||||
init: function init(container, visibleRect) {
|
||||
this._batchOps = [];
|
||||
this._container = container;
|
||||
this._browser = null;
|
||||
this._browserViewportState = null;
|
||||
this._contentWindow = 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] = BrowserView.Util.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(BrowserView.Util.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 = BrowserView.Util.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 = BrowserView.Util.visibleRectToCriticalRect(vr, vs);
|
||||
|
||||
this._tileManager.endCriticalMove(cr, this.isRendering());
|
||||
},
|
||||
|
||||
setBrowser: function setBrowser(browser, doZoom) {
|
||||
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);
|
||||
|
||||
if (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 (doZoom) {
|
||||
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] = BrowserView.Util.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)
|
||||
this.simulateMozAfterSizeChange(browser, hack.maxW, hack.maxH);
|
||||
// !!! --- RESIZE HACK END -------
|
||||
|
||||
tm.dirtyRects(rects, this.isRendering());
|
||||
},
|
||||
|
||||
// !!! --- RESIZE HACK BEGIN -----
|
||||
simulateMozAfterSizeChange: function simulateMozAfterSizeChange(browser, width, height) {
|
||||
//let ev = document.createElement("MouseEvents");
|
||||
//ev.initEvent("FakeMozAfterSizeChange", false, false, window, 0, width, height);
|
||||
//browser.dispatchEvent(ev);
|
||||
this.handleMozAfterSizeChange({screenX: width, screenY: height});
|
||||
},
|
||||
// !!! --- RESIZE HACK END -------
|
||||
|
||||
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] = BrowserView.Util.getBrowserDimensions(browser);
|
||||
this.setZoomLevel(BrowserView.Util.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 bvs = null;
|
||||
|
||||
if (browser) {
|
||||
let vr = this._visibleRect;
|
||||
|
||||
if (!BrowserView.Util.seenBrowser(browser))
|
||||
BrowserView.Util.initBrowserState(browser, vr);
|
||||
|
||||
bvs = BrowserView.Util.getViewportStateFromBrowser(browser);
|
||||
|
||||
vr.left = bvs.visibleX;
|
||||
vr.top = bvs.visibleY;
|
||||
}
|
||||
|
||||
this._browser = browser;
|
||||
this._contentWindow = (browser) ? browser.contentWindow : null;
|
||||
this._browserViewportState = bvs;
|
||||
},
|
||||
|
||||
_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
|
||||
BrowserView.Util.getBrowserDOMWindowUtils(this._browser).clearMozAfterPaintEvents();
|
||||
}
|
||||
*/
|
||||
// !!! --- RESIZE HACK END -------
|
||||
|
||||
if (bvs) {
|
||||
BrowserView.Util.resizeContainerToViewport(this._container, bvs.viewportRect);
|
||||
|
||||
this._tileManager.viewportChangeHandler(bvs.viewportRect,
|
||||
BrowserView.Util.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";
|
||||
//
|
||||
// XXX The above causes a trace abort, and this function is called back in the tight
|
||||
// render-heavy loop in TileManager, so even though what we do below isn't so proper
|
||||
// and takes longer on the Platform/C++ emd, it's better than causing a trace abort
|
||||
// in our tight loop. :/
|
||||
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
|
||||
//
|
||||
|
||||
/**
|
||||
* A BrowserViewportState maintains viewport state information that is unique to each
|
||||
* browser. It does not hold *all* viewport state maintained by BrowserView. For
|
||||
* instance, it does not maintain width and height of the visible rectangle (but it
|
||||
* does keep the top and left coordinates (cf visibleX, visibleY)), since those are not
|
||||
* characteristic of the current browser in view.
|
||||
*/
|
||||
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}';
|
||||
}
|
||||
|
||||
};
|
||||
|
1005
mobile/chrome/content/TileManager.js
Normal file
1005
mobile/chrome/content/TileManager.js
Normal file
File diff suppressed because it is too large
Load Diff
@ -95,25 +95,15 @@ function wsBorder(t, l, b, r) {
|
||||
|
||||
wsBorder.prototype = {
|
||||
|
||||
get left() { return this._l; },
|
||||
get right() { return this._r; },
|
||||
get top() { return this._t; },
|
||||
get bottom() { return this._b; },
|
||||
|
||||
set left(v) { this._l = v; },
|
||||
set right(v) { this._r = v; },
|
||||
set top(v) { this._t = v; },
|
||||
set bottom(v) { this._b = v; },
|
||||
|
||||
setBorder: function (t, l, b, r) {
|
||||
this._t = t;
|
||||
this._l = l;
|
||||
this._b = b;
|
||||
this._r = r;
|
||||
this.top = t;
|
||||
this.left = l;
|
||||
this.bottom = b;
|
||||
this.right = r;
|
||||
},
|
||||
|
||||
toString: function () {
|
||||
return "[l:" + this._l + ",t:" + this._t + ",r:" + this._r + ",b:" + this._b + "]";
|
||||
return "[l:" + this.left + ",t:" + this.top + ",r:" + this.right + ",b:" + this.bottom + "]";
|
||||
}
|
||||
};
|
||||
|
||||
@ -123,93 +113,103 @@ wsBorder.prototype = {
|
||||
* Rectangle class, with both x/y/w/h and t/l/b/r accessors.
|
||||
*/
|
||||
function wsRect(x, y, w, h) {
|
||||
this.setRect(x, y, w, h);
|
||||
this.left = x;
|
||||
this.top = y;
|
||||
this.right = x+w;
|
||||
this.bottom = y+h;
|
||||
}
|
||||
|
||||
wsRect.prototype = {
|
||||
|
||||
get x() { return this._l; },
|
||||
get y() { return this._t; },
|
||||
get width() { return this._r - this._l; },
|
||||
get height() { return this._b - this._t; },
|
||||
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._l - v;
|
||||
this._l = v;
|
||||
this._r -= diff;
|
||||
let diff = this.left - v;
|
||||
this.left = v;
|
||||
this.right -= diff;
|
||||
},
|
||||
set y(v) {
|
||||
let diff = this._t - v;
|
||||
this._t = v;
|
||||
this._b -= diff;
|
||||
let diff = this.top - v;
|
||||
this.top = v;
|
||||
this.bottom -= diff;
|
||||
},
|
||||
set width(v) { this._r = this._l + v; },
|
||||
set height(v) { this._b = this._t + v; },
|
||||
|
||||
get left() { return this._l; },
|
||||
get right() { return this._r; },
|
||||
get top() { return this._t; },
|
||||
get bottom() { return this._b; },
|
||||
|
||||
set left(v) { this._l = v; },
|
||||
set right(v) { this._r = v; },
|
||||
set top(v) { this._t = v; },
|
||||
set bottom(v) { this._b = v; },
|
||||
set width(v) { this.right = this.left + v; },
|
||||
set height(v) { this.bottom = this.top + v; },
|
||||
|
||||
setRect: function(x, y, w, h) {
|
||||
this._l = x;
|
||||
this._t = y;
|
||||
this._r = x+w;
|
||||
this._b = y+h;
|
||||
this.left = x;
|
||||
this.top = y;
|
||||
this.right = x+w;
|
||||
this.bottom = y+h;
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
setBounds: function(t, l, b, r) {
|
||||
this._t = t;
|
||||
this._l = l;
|
||||
this._b = b;
|
||||
this._r = r;
|
||||
this.top = t;
|
||||
this.left = l;
|
||||
this.bottom = b;
|
||||
this.right = r;
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
clone: function() {
|
||||
return new wsRect(this._l, this._t, this.width, this.height);
|
||||
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._t = r._t;
|
||||
this._l = r._l;
|
||||
this._b = r._b;
|
||||
this._r = r._r;
|
||||
this.top = r.top;
|
||||
this.left = r.left;
|
||||
this.bottom = r.bottom;
|
||||
this.right = r.right;
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
copyFromTLBR: function(r) {
|
||||
this._l = r.left;
|
||||
this._t = r.top;
|
||||
this._r = r.right;
|
||||
this._b = r.bottom;
|
||||
this.left = r.left;
|
||||
this.top = r.top;
|
||||
this.right = r.right;
|
||||
this.bottom = r.bottom;
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
translate: function(x, y) {
|
||||
this._l += x;
|
||||
this._r += x;
|
||||
this._t += y;
|
||||
this._b += 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._l, rect._l);
|
||||
let r = Math.max(this._r, rect._r);
|
||||
let t = Math.min(this._t, rect._t);
|
||||
let b = Math.max(this._b, rect._b);
|
||||
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);
|
||||
},
|
||||
@ -219,25 +219,25 @@ wsRect.prototype = {
|
||||
},
|
||||
|
||||
expandBy: function(b) {
|
||||
this._l += b.left;
|
||||
this._r += b.right;
|
||||
this._t += b.top;
|
||||
this._b += b.bottom;
|
||||
this.left += b.left;
|
||||
this.right += b.right;
|
||||
this.top += b.top;
|
||||
this.bottom += b.bottom;
|
||||
return this;
|
||||
},
|
||||
|
||||
contains: function(other) {
|
||||
return !!(other._l >= this._l &&
|
||||
other._r <= this._r &&
|
||||
other._t >= this._t &&
|
||||
other._b <= this._b);
|
||||
return !!(other.left >= this.left &&
|
||||
other.right <= this.right &&
|
||||
other.top >= this.top &&
|
||||
other.bottom <= this.bottom);
|
||||
},
|
||||
|
||||
intersect: function(r2) {
|
||||
let xmost1 = this._r;
|
||||
let xmost2 = r2._r;
|
||||
let xmost1 = this.right;
|
||||
let xmost2 = r2.right;
|
||||
|
||||
let x = Math.max(this._l, r2._l);
|
||||
let x = Math.max(this.left, r2.left);
|
||||
|
||||
let temp = Math.min(xmost1, xmost2);
|
||||
if (temp <= x)
|
||||
@ -245,9 +245,9 @@ wsRect.prototype = {
|
||||
|
||||
let width = temp - x;
|
||||
|
||||
let ymost1 = this._b;
|
||||
let ymost2 = r2._b;
|
||||
let y = Math.max(this._t, r2._t);
|
||||
let ymost1 = this.bottom;
|
||||
let ymost2 = r2.bottom;
|
||||
let y = Math.max(this.top, r2.top);
|
||||
|
||||
temp = Math.min(ymost1, ymost2);
|
||||
if (temp <= y)
|
||||
@ -259,12 +259,12 @@ wsRect.prototype = {
|
||||
},
|
||||
|
||||
intersects: function(other) {
|
||||
let xok = (other._l > this._l && other._l < this._r) ||
|
||||
(other._r > this._l && other._r < this._r) ||
|
||||
(other._l <= this._l && other._r >= this._r);
|
||||
let yok = (other._t > this._t && other._t < this._b) ||
|
||||
(other._b > this._t && other._b < this._b) ||
|
||||
(other._t <= this._t && other._b >= this._b);
|
||||
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;
|
||||
},
|
||||
|
||||
@ -274,10 +274,10 @@ wsRect.prototype = {
|
||||
* of returning a new rect.
|
||||
*/
|
||||
restrictTo: function restrictTo(r2) {
|
||||
let xmost1 = this._r;
|
||||
let xmost2 = r2._r;
|
||||
let xmost1 = this.right;
|
||||
let xmost2 = r2.right;
|
||||
|
||||
let x = Math.max(this._l, r2._l);
|
||||
let x = Math.max(this.left, r2.left);
|
||||
|
||||
let temp = Math.min(xmost1, xmost2);
|
||||
if (temp <= x)
|
||||
@ -285,9 +285,9 @@ wsRect.prototype = {
|
||||
|
||||
let width = temp - x;
|
||||
|
||||
let ymost1 = this._b;
|
||||
let ymost2 = r2._b;
|
||||
let y = Math.max(this._t, r2._t);
|
||||
let ymost1 = this.bottom;
|
||||
let ymost2 = r2.bottom;
|
||||
let y = Math.max(this.top, r2.top);
|
||||
|
||||
temp = Math.min(ymost1, ymost2);
|
||||
if (temp <= y)
|
||||
@ -307,10 +307,10 @@ wsRect.prototype = {
|
||||
* given a strict subset rect as the argument.
|
||||
*/
|
||||
expandToContain: function extendTo(rect) {
|
||||
let l = Math.min(this._l, rect._l);
|
||||
let r = Math.max(this._r, rect._r);
|
||||
let t = Math.min(this._t, rect._t);
|
||||
let b = Math.max(this._b, rect._b);
|
||||
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);
|
||||
},
|
||||
@ -318,17 +318,19 @@ wsRect.prototype = {
|
||||
round: function round(scale) {
|
||||
if (!scale) scale = 1;
|
||||
|
||||
this._l = Math.floor(this._l * scale) / scale;
|
||||
this._t = Math.floor(this._t * scale) / scale;
|
||||
this._r = Math.ceil(this._r * scale) / scale;
|
||||
this._b = Math.ceil(this._b * scale) / scale;
|
||||
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._l *= xscl;
|
||||
this._r *= xscl;
|
||||
this._t *= yscl;
|
||||
this._b *= yscl;
|
||||
this.left *= xscl;
|
||||
this.right *= xscl;
|
||||
this.top *= yscl;
|
||||
this.bottom *= yscl;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
469
mobile/chrome/content/foo.xul
Normal file
469
mobile/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/x-javascript" src="WidgetStack.js"/>
|
||||
<script type="application/x-javascript" src="TileManager.js"/>
|
||||
<script type="application/x-javascript;version=1.8" src="BrowserView.js"/>
|
||||
<script type="application/x-javascript;version=1.8">
|
||||
<![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://slashdot.org/" type="content" style="width: 1024px; height: 614px"/>
|
||||
</html:div>
|
||||
</html:div>
|
||||
</box>
|
||||
|
||||
</window>
|
Loading…
Reference in New Issue
Block a user