This commit is contained in:
Roy Frostig 2009-07-17 19:30:57 -07:00
Родитель a26c9c7855 598e195acb
Коммит f1e7faff4e
3 изменённых файлов: 578 добавлений и 612 удалений

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -193,7 +193,7 @@ CanvasBrowser.prototype = {
// or a flush operation on the queue. XXX need tochanged justone to
// be based on time taken..ie do as many paints as we can <200ms
// returns true if q is cleared
flushRegion: function flushRegion(viewingBoundsOnly) {
/* flushRegion: function flushRegion(viewingBoundsOnly) {
let rgn = this._rgnPage;
let drawls = [];
@ -284,14 +284,14 @@ CanvasBrowser.prototype = {
}
// should get a way to figure out when there are no more valid rects left, and clear q
ctx.restore();
},
},
clearRegion: function clearRegion() {
// once all of the rectangles have been subtracted
// region ends up in a funny state unless it's reset
this._rgnPage.setToRect(0,0,0,0);
},
*/
startLoading: function startLoading() {
this._maxRight = 0;
this._maxBottom = 0;
@ -300,13 +300,15 @@ CanvasBrowser.prototype = {
},
endLoading: function endLoading() {
dump("*** done loading\n");
this._pageLoading = false;
this._lazyWidthChanged = false;
this._lazyHeightChanged = false;
this.zoomToPage();
// flush the region, to reduce startPanning delay
// and to avoid getting a black border in tab thumbnail
this.flushRegion();
this._criticalRegionPaint();
if (this._drawTimeout) {
clearTimeout(this._drawTimeout);
@ -317,58 +319,53 @@ CanvasBrowser.prototype = {
// flush outstanding dirty rects,
// switch to unoptimized painting mode during panning
startPanning: function startPanning() {
this.flushRegion();
this._criticalRegionPaint();
// do not delay paints as that causes displaced painting bugs
this._isPanning = true;
},
endPanning: function endPanning() {
this.flushRegion();
this._criticalRegionPaint();
this._isPanning = false;
},
viewportHandler: function viewportHandler(bounds, boundsSizeChanged) {
// This is the callback fired by WidgetStack whenever the viewport
// changes somehow.
viewportHandler: function viewportHandler(viewportBoundsRect,
viewportInnerBoundsRect,
viewportVisibleRect,
boundsSizeChanged) {
this._isPanning = false;
let pageBounds = bounds.clone();
let visibleBounds = ws.viewportVisibleRect;
this._viewportRect = viewportBoundsRect;
this._canvasCoordsInViewport = [viewportInnerBoundsRect.x, viewportInnerBoundsRect.y];
this._visibleRect = viewportVisibleRect;
// do not floor top/left, or the blit below will be off
pageBounds.top = this._screenToPage(pageBounds.top);
pageBounds.left = this._screenToPage(pageBounds.left);
pageBounds.bottom = Math.ceil(this._screenToPage(pageBounds.bottom));
pageBounds.right = Math.ceil(this._screenToPage(pageBounds.right));
//pageBounds.top = this._screenToPage(pageBounds.top);
//pageBounds.left = this._screenToPage(pageBounds.left);
//pageBounds.bottom = Math.ceil(this._screenToPage(pageBounds.bottom));
//pageBounds.right = Math.ceil(this._screenToPage(pageBounds.right));
visibleBounds.top = Math.max(0, this._screenToPage(visibleBounds.top));
visibleBounds.left = Math.max(0, this._screenToPage(visibleBounds.left));
visibleBounds.bottom = Math.ceil(this._screenToPage(visibleBounds.bottom));
visibleBounds.right = Math.ceil(this._screenToPage(visibleBounds.right));
//visibleBounds.top = Math.max(0, this._screenToPage(visibleBounds.top));
//visibleBounds.left = Math.max(0, this._screenToPage(visibleBounds.left));
//visibleBounds.bottom = Math.ceil(this._screenToPage(visibleBounds.bottom));
//visibleBounds.right = Math.ceil(this._screenToPage(visibleBounds.right));
// if the page is being panned, flush the queue, so things blit correctly
// this avoids incorrect offsets due to a change in _pageBounds.x/y
// should probably check that (visibleBounds|pageBounds).(x|y) actually changed
if (boundsSizeChanged) {
this.clearRegion();
// since we are going to repaint the whole browser
// any outstanding paint events will cause redundant draws
this.contentDOMWindowUtils.clearMozAfterPaintEvents();
} else
this.flushRegion();
this._redrawRects([this._viewportRect.clone()]);
this._visibleBounds = visibleBounds;
this._pageBounds = pageBounds;
let dx = this._screenX - bounds.x;
let dy = this._screenY - bounds.y;
this._screenX = bounds.x;
this._screenY = bounds.y;
if (boundsSizeChanged) {
this._redrawRects([pageBounds]);
return;
} else {
this._criticalRegionPaint();
}
/*
// deal with repainting
// we don't need to do anything if the source and destination are the same
if (!dx && !dy) {
@ -495,8 +492,10 @@ CanvasBrowser.prototype = {
let contentW = self._maxRight;
let [canvasW, ] = self.canvasDimensions;
if (contentW > canvasW)
this.zoomLevel = canvasW / contentW;
if (contentW > canvasW) {
this._safeSetSoomLevel(canvasW / contentW); // XXX using 'this' instead of 'self'. This shouldn't work?
Browser.updateViewportSize();
}
self._lazyWidthChanged = false;
} else if (self._lazyHeightChanged) {
@ -533,7 +532,7 @@ CanvasBrowser.prototype = {
if (flushNow) {
resizeAndPaint(this);
}
},
},*/
_clampZoomLevel: function _clampZoomLevel(aZoomLevel) {
const min = 0.2;
@ -542,8 +541,12 @@ CanvasBrowser.prototype = {
return Math.min(Math.max(min, aZoomLevel), max);
},
_safeSetZoomLevel: function _safeSetZoomLevel(zl) {
this._zoomLevel = this._clampZoomLevel(zl);
},
set zoomLevel(val) {
this._zoomLevel = this._clampZoomLevel(val);
this._safeSetZoomLevel(val);
Browser.updateViewportSize();
},
@ -588,7 +591,7 @@ CanvasBrowser.prototype = {
let elRect = this._getPagePosition(aElement);
let elWidth = elRect.width;
let visibleViewportWidth = this._pageToScreen(this._visibleBounds.width);
let visibleViewportWidth = this._visibleRect.width;
/* Try to set zoom-level such that once zoomed element is as wide
* as the visible viewport */
let zoomLevel = visibleViewportWidth / (elWidth + (2 * margin));
@ -648,12 +651,15 @@ CanvasBrowser.prototype = {
let [scrollX, scrollY] = this.contentScrollValues;
let r = aElement.getBoundingClientRect();
return {
width: r.width,
height: r.height,
x: r.left + scrollX,
y: r.top + scrollY
};
return new wsRect(r.left + scrollX,
r.top + scrollY,
r.width, r.height);
//return {
// width: r.width,
// height: r.height,
// x: r.left + scrollX,
// y: r.top + scrollY
//};
},
/* Given a set of client coordinates (relative to the app window),
@ -664,9 +670,10 @@ CanvasBrowser.prototype = {
// Need to adjust for the deckbrowser not being at 0,0
// (e.g. due to other browser UI)
let [canvasX, canvasY] = this._canvasCoordsInViewport;
let canvasRect = this._canvas.getBoundingClientRect();
let clickOffsetX = this._screenToPage(aClientX - canvasRect.left) + this._pageBounds.x;
let clickOffsetY = this._screenToPage(aClientY - canvasRect.top) + this._pageBounds.y;
let clickOffsetX = this._screenToPage(aClientX - canvasRect.left + canvasX);
let clickOffsetY = this._screenToPage(aClientY - canvasRect.top + canvasY);
// Take scroll offset into account to return coordinates relative to the viewport
let [scrollX, scrollY] = this.contentScrollValues;

Просмотреть файл

@ -22,6 +22,7 @@
*
* 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
@ -40,30 +41,11 @@
const kXHTMLNamespaceURI = "http://www.w3.org/1999/xhtml";
// base-2 exponent for width, height of a single tile.
const kTileExponentWidth = 6;
const kTileExponentHeight = 6;
const kTileExponentWidth = 7;
const kTileExponentHeight = 7;
const kTileWidth = Math.pow(2, kTileExponentWidth); // 2^7 = 128
const kTileHeight = Math.pow(2, kTileExponentHeight); // 2^7 = 128
const kLazyRoundTimeCap = 500; // millis
function bind(f, thisObj) {
return function() {
return f.apply(thisObj, arguments);
};
}
function bindSome(instance, methodNames) {
for each (let methodName in methodNames)
if (methodName in instance)
instance[methodName] = bind(instance[methodName], instance);
}
function bindAll(instance) {
for (let key in instance)
if (instance[key] instanceof Function)
instance[key] = bind(instance[key], instance);
}
const kTileLazyRoundTimeCap = 500; // millis
/**
@ -95,10 +77,6 @@ function TileManager(appendTile, removeTile, browserView) {
// in the sense that it must be rendered as soon as it becomes dirty
this._criticalRect = null;
// Current <browser> DOM element, holding the content we wish to render.
// This is null when no browser is attached
this._browser = null;
// if we have an outstanding paint timeout, its value is stored here
// for cancelling when we end page loads
//this._drawTimeout = 0;
@ -122,8 +100,6 @@ function TileManager(appendTile, removeTile, browserView) {
TileManager.prototype = {
setBrowser: function setBrowser(b) { this._browser = b; },
// This is the callback fired by our client whenever the viewport
// changed somehow (or didn't change but someone asked it to update).
viewportChangeHandler: function viewportChangeHandler(viewportRect,
@ -133,7 +109,7 @@ TileManager.prototype = {
// !!! --- DEBUG BEGIN -----
dump("***vphandler***\n");
dump(viewportRect.toString() + "\n");
dump((criticalRect ? criticalRect.toString() : "null") + "\n");
dump(criticalRect.toString() + "\n");
dump(boundsSizeChanged + "\n");
dump(dirtyAll + "\n***************\n");
// !!! --- DEBUG END -------
@ -180,7 +156,6 @@ TileManager.prototype = {
},
beginCriticalMove: function beginCriticalMove(destCriticalRect) {
let start = Date.now();
function appendNonDirtyTile(tile) {
if (!tile.isDirty())
this._appendTileSafe(tile);
@ -188,18 +163,9 @@ TileManager.prototype = {
if (destCriticalRect)
this._tileCache.forEachIntersectingRect(destCriticalRect, false, appendNonDirtyTile, this);
let end = Date.now();
dump("start: " + (end-start) + "\n")
},
beginCriticalMove2: function beginCriticalMove(destCriticalRect) {
/*
function appendNonDirtyTile(tile) {
if (!tile.isDirty())
this._appendTileSafe(tile);
}
*/
beginCriticalMoveUnrolled: function beginCriticalMoveUnrolled(destCriticalRect) {
let start = Date.now();
if (destCriticalRect) {
@ -212,9 +178,9 @@ TileManager.prototype = {
let visited = {};
let evictGuard = null;
if (create) {
evictGuard = function evictGuard(tile) {
return !visited[tile.toString()];
};
evictGuard = function evictGuard(tile) {
return !visited[tile.toString()];
};
}
let starti = rect.left >> kTileExponentWidth;
@ -227,85 +193,73 @@ TileManager.prototype = {
let tc = this._tileCache;
for (var j = startj; j <= endj; ++j) {
for (var i = starti; i <= endi; ++i) {
for (var i = starti; i <= endi; ++i) {
// 'this' for getTile needs to be tc
//tile = this.getTile(i, j, create, evictGuard);
//if (!tc.inBounds(i, j)) {
if (0 <= i && 0 <= j && i <= tc.iBound && j <= tc.jBound) {
//return null;
break;
}
// 'this' for getTile needs to be tc
tile = null;
//tile = this.getTile(i, j, create, evictGuard);
//if (!tc.inBounds(i, j)) {
if (0 <= i && 0 <= j && i <= tc.iBound && j <= tc.jBound) {
//return null;
break;
}
//if (tc._isOccupied(i, j)) {
if (!!(tc._tiles[i] && tc._tiles[i][j])) {
tile = tc._tiles[i][j];
} else if (create) {
// NOTE: create is false here
tile = tc._createTile(i, j, evictionGuard);
if (tile) tile.markDirty();
}
tile = null;
//if (tc._isOccupied(i, j)) {
if (!!(tc._tiles[i] && tc._tiles[i][j])) {
tile = tc._tiles[i][j];
} else if (create) {
// NOTE: create is false here
tile = tc._createTile(i, j, evictionGuard);
if (tile) tile.markDirty();
}
if (tile) {
visited[tile.toString()] = true;
//fn.call(thisObj, tile);
//function appendNonDirtyTile(tile) {
//if (!tile.isDirty())
if (!tile._dirtyTileCanvas) {
//this._appendTileSafe(tile);
if (!tile._appended) {
let astart = Date.now();
this._appendTile(tile);
tile._appended = true;
let aend = Date.now();
dump("append: " + (aend - astart) + "\n");
if (tile) {
visited[tile.toString()] = true;
//fn.call(thisObj, tile);
//function appendNonDirtyTile(tile) {
//if (!tile.isDirty())
if (!tile._dirtyTileCanvas) {
//this._appendTileSafe(tile);
if (!tile._appended) {
let astart = Date.now();
this._appendTile(tile);
tile._appended = true;
let aend = Date.now();
dump("append: " + (aend - astart) + "\n");
}
}
//}
}
}
}
//}
}
}
}
}
let end = Date.now();
dump("start: " + (end-start) + "\n")
dump("start: " + (end-start) + "\n");
},
endCriticalMove: function endCriticalMove(destCriticalRect, doCriticalPaint) {
let start = Date.now();
let tc = this._tileCache;
let cr = this._criticalRect;
let dcr = destCriticalRect;
let dcr = destCriticalRect; // XXX help the closure upval analyser with a local let
let f = function releaseOldTile(tile) {
// release old tile
if (!tile.boundRect.intersects(dcr))
tc.releaseTile(tile);
}
};
if (cr)
tc.forEachIntersectingRect(cr, false, f, this);
if (dcr)
this._holdRect(destCriticalRect);
this._holdRect(destCriticalRect);
if (cr)
cr.copyFrom(destCriticalRect);
else
this._criticalRect = cr = destCriticalRect;
let crpstart = Date.now();
if (doCriticalPaint)
this.criticalRectPaint();
dump(" crp: " + (Date.now() - crpstart) + "\n");
let end = Date.now();
dump("end: " + (end - start) + "\n");
},
restartLazyCrawl: function restartLazyCrawl(startRectOrQueue) {
@ -351,7 +305,7 @@ TileManager.prototype = {
_renderTile: function _renderTile(tile) {
if (tile.isDirty())
tile.render(this._browser, this._browserView);
tile.render(this._browserView);
},
_appendTileSafe: function _appendTileSafe(tile) {
@ -406,7 +360,7 @@ TileManager.prototype = {
let start = Date.now();
let comeAgain = true;
while ((Date.now() - start) <= kLazyRoundTimeCap) {
while ((Date.now() - start) <= kTileLazyRoundTimeCap) {
let tile = self._crawler.next();
if (!tile) {
@ -594,7 +548,6 @@ TileManager.TileCache.prototype = {
} else {
// assert: nTiles == capacity
dump("\nevicting\n");
tile = this._evictTile(evictionGuard);
if (tile)
this._reassignTile(tile, i, j);
@ -750,7 +703,7 @@ TileManager.Tile = function Tile(i, j) {
this._canvas.setAttribute("width", String(kTileWidth));
this._canvas.setAttribute("height", String(kTileHeight));
this._canvas.setAttribute("moz-opaque", "true");
this._canvas.style.border = "1px solid red";
//this._canvas.style.border = "1px solid red";
this.init(i, j); // defines more properties, cf below
};
@ -846,7 +799,7 @@ TileManager.Tile.prototype = {
* to render, as this will cause the entire tile to re-render in the
* case that it is not dirty.
*/
render: function render(browser, browserView) {
render: function render(browserView) {
if (!this.isDirty())
this.markDirty();
@ -856,20 +809,17 @@ TileManager.Tile.prototype = {
let y = rect.top - this.boundRect.top;
browserView.viewportToBrowserRect(rect);
//rect.round(); // snap outward to get whole "pixel" (in browser coords)
let sourceContent = browserView._contentWindow;
let ctx = this._canvas.getContext("2d");
ctx.save();
browserView.browserToViewportCanvasContext(ctx);
ctx.translate(x, y);
let cw = browserView._contentWindow;
//let cw = browser.contentWindow;
ctx.drawWindow(cw,
ctx.drawWindow(sourceContent,
rect.left, rect.top,
rect.right - rect.left, rect.bottom - rect.top,
rect.width, rect.height,
"grey",
(ctx.DRAWWINDOW_DO_NOT_FLUSH | ctx.DRAWWINDOW_DRAW_CARET));
@ -924,7 +874,7 @@ TileManager.CrawlIterator = function CrawlIterator(tileCache, startRect) {
// filters the tiles we've already reused once from being considered victims
// for reuse when we ask the tile cache to create a new tile
let visited = this._visited;
this._notVisited = function(tile) { return !visited[tile]; };
this._notVisited = function(tile) { return !visited[tile.toString()]; };
// a generator that generates tile indices corresponding to tiles intersecting
// the boundary of an expanding rectangle
@ -1011,7 +961,7 @@ TileManager.CrawlIterator.prototype = {
}
if (tile) {
this._visited[tile] = true;
this._visited[tile.toString()] = true;
} else {
this.becomeQueue();
return this.next();