зеркало из https://github.com/mozilla/gecko-dev.git
Bug 480958. Update viewport dimensions as per MozScrolledAreaChanged. r=mfinkle
This commit is contained in:
Родитель
962da0c7ca
Коммит
9900b8fc86
|
@ -171,6 +171,10 @@ BrowserView.Util = {
|
||||||
return browser.__BrowserView__vps;
|
return browser.__BrowserView__vps;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calling this is likely to cause a reflow of the browser's document. Use
|
||||||
|
* wisely.
|
||||||
|
*/
|
||||||
getBrowserDimensions: function getBrowserDimensions(browser) {
|
getBrowserDimensions: function getBrowserDimensions(browser) {
|
||||||
let cdoc = browser.contentDocument;
|
let cdoc = browser.contentDocument;
|
||||||
if (cdoc instanceof SVGDocument) {
|
if (cdoc instanceof SVGDocument) {
|
||||||
|
@ -235,7 +239,7 @@ BrowserView.prototype = {
|
||||||
this._contentWindow = null;
|
this._contentWindow = null;
|
||||||
this._renderMode = 0;
|
this._renderMode = 0;
|
||||||
this._offscreenDepth = 0;
|
this._offscreenDepth = 0;
|
||||||
|
|
||||||
let cacheSize = kBrowserViewCacheSize;
|
let cacheSize = kBrowserViewCacheSize;
|
||||||
try {
|
try {
|
||||||
cacheSize = gPrefService.getIntPref("tile.cache.size");
|
cacheSize = gPrefService.getIntPref("tile.cache.size");
|
||||||
|
@ -262,6 +266,7 @@ BrowserView.prototype = {
|
||||||
|
|
||||||
this._tileManager = new TileManager(this._appendTile, this._removeTile, this, cacheSize);
|
this._tileManager = new TileManager(this._appendTile, this._removeTile, this, cacheSize);
|
||||||
this._visibleRectFactory = visibleRectFactory;
|
this._visibleRectFactory = visibleRectFactory;
|
||||||
|
this._suppressZoomToPage = false;
|
||||||
|
|
||||||
this._idleServiceObserver = new BrowserView.IdleServiceObserver(this);
|
this._idleServiceObserver = new BrowserView.IdleServiceObserver(this);
|
||||||
this._idleService = Cc["@mozilla.org/widget/idleservice;1"].getService(Ci.nsIIdleService);
|
this._idleService = Cc["@mozilla.org/widget/idleservice;1"].getService(Ci.nsIIdleService);
|
||||||
|
@ -282,9 +287,16 @@ BrowserView.prototype = {
|
||||||
if (!bvs)
|
if (!bvs)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (!causedByZoom)
|
||||||
|
this._suppressZoomToPage = false;
|
||||||
|
|
||||||
|
let oldwidth = bvs.viewportRect.right;
|
||||||
|
let oldheight = bvs.viewportRect.bottom;
|
||||||
bvs.viewportRect.right = width;
|
bvs.viewportRect.right = width;
|
||||||
bvs.viewportRect.bottom = height;
|
bvs.viewportRect.bottom = height;
|
||||||
|
|
||||||
|
let sizeChanged = (oldwidth != width || oldheight != height);
|
||||||
|
|
||||||
// XXX we might not want the user's page to disappear from under them
|
// 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
|
// at this point, which could happen if the container gets resized such
|
||||||
// that visible rect becomes entirely outside of viewport rect. might
|
// that visible rect becomes entirely outside of viewport rect. might
|
||||||
|
@ -292,19 +304,33 @@ BrowserView.prototype = {
|
||||||
// then again, we could also argue this is the responsibility of the
|
// then again, we could also argue this is the responsibility of the
|
||||||
// caller who would do such a thing...
|
// caller who would do such a thing...
|
||||||
|
|
||||||
this._viewportChanged(true, !!causedByZoom);
|
this._viewportChanged(sizeChanged, sizeChanged && !!causedByZoom);
|
||||||
},
|
},
|
||||||
|
|
||||||
setZoomLevel: function setZoomLevel(zl) {
|
/**
|
||||||
|
* @return [width, height]
|
||||||
|
*/
|
||||||
|
getViewportDimensions: function getViewportDimensions() {
|
||||||
let bvs = this._browserViewportState;
|
let bvs = this._browserViewportState;
|
||||||
|
|
||||||
|
if (!bvs)
|
||||||
|
throw "Cannot get viewport dimensions when no browser is set";
|
||||||
|
|
||||||
|
return [bvs.viewportRect.right, bvs.viewportRect.bottom];
|
||||||
|
},
|
||||||
|
|
||||||
|
setZoomLevel: function setZoomLevel(zoomLevel) {
|
||||||
|
let bvs = this._browserViewportState;
|
||||||
|
|
||||||
if (!bvs)
|
if (!bvs)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
let newZL = BrowserView.Util.clampZoomLevel(zl);
|
let newZoomLevel = BrowserView.Util.clampZoomLevel(zoomLevel);
|
||||||
if (newZL != bvs.zoomLevel) {
|
|
||||||
|
if (newZoomLevel != bvs.zoomLevel) {
|
||||||
let browserW = this.viewportToBrowser(bvs.viewportRect.right);
|
let browserW = this.viewportToBrowser(bvs.viewportRect.right);
|
||||||
let browserH = this.viewportToBrowser(bvs.viewportRect.bottom);
|
let browserH = this.viewportToBrowser(bvs.viewportRect.bottom);
|
||||||
bvs.zoomLevel = newZL; // side-effect: now scale factor in transformations is newZL
|
bvs.zoomLevel = newZoomLevel; // side-effect: now scale factor in transformations is newZoomLevel
|
||||||
this.setViewportDimensions(this.browserToViewport(browserW),
|
this.setViewportDimensions(this.browserToViewport(browserW),
|
||||||
this.browserToViewport(browserH),
|
this.browserToViewport(browserH),
|
||||||
true);
|
true);
|
||||||
|
@ -439,19 +465,17 @@ BrowserView.prototype = {
|
||||||
throw "Cannot set non-null browser with null BrowserViewportState";
|
throw "Cannot set non-null browser with null BrowserViewportState";
|
||||||
}
|
}
|
||||||
|
|
||||||
let browserChanged = (this._browser !== browser);
|
let oldBrowser = this._browser;
|
||||||
|
|
||||||
if (this._browser) {
|
let browserChanged = (oldBrowser !== browser);
|
||||||
this._browser.removeEventListener("MozAfterPaint", this.handleMozAfterPaint, false);
|
|
||||||
this._browser.removeEventListener("scroll", this.handlePageScroll, false);
|
|
||||||
|
|
||||||
// !!! --- RESIZE HACK BEGIN -----
|
if (oldBrowser) {
|
||||||
// change to the real event type and perhaps refactor the handler function name
|
oldBrowser.removeEventListener("MozAfterPaint", this.handleMozAfterPaint, false);
|
||||||
this._browser.removeEventListener("FakeMozAfterSizeChange", this.handleMozAfterSizeChange, false);
|
oldBrowser.removeEventListener("scroll", this.handlePageScroll, false);
|
||||||
// !!! --- RESIZE HACK END -------
|
oldBrowser.removeEventListener("MozScrolledAreaChanged", this.handleMozScrolledAreaChanged, false);
|
||||||
|
|
||||||
this._browser.setAttribute("type", "content");
|
oldBrowser.setAttribute("type", "content");
|
||||||
this._browser.docShell.isOffScreenBrowser = false;
|
oldBrowser.docShell.isOffScreenBrowser = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
this._browser = browser;
|
this._browser = browser;
|
||||||
|
@ -465,11 +489,7 @@ BrowserView.prototype = {
|
||||||
|
|
||||||
browser.addEventListener("MozAfterPaint", this.handleMozAfterPaint, false);
|
browser.addEventListener("MozAfterPaint", this.handleMozAfterPaint, false);
|
||||||
browser.addEventListener("scroll", this.handlePageScroll, false);
|
browser.addEventListener("scroll", this.handlePageScroll, false);
|
||||||
|
browser.addEventListener("MozScrolledAreaChanged", this.handleMozScrolledAreaChanged, 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) {
|
if (doZoom) {
|
||||||
browser.docShell.isOffScreenBrowser = true;
|
browser.docShell.isOffScreenBrowser = true;
|
||||||
|
@ -527,28 +547,31 @@ BrowserView.prototype = {
|
||||||
this.onAfterVisibleMove();
|
this.onAfterVisibleMove();
|
||||||
},
|
},
|
||||||
|
|
||||||
// !!! --- RESIZE HACK BEGIN -----
|
handleMozScrolledAreaChanged: function handleMozScrolledAreaChanged(ev) {
|
||||||
simulateMozAfterSizeChange: function simulateMozAfterSizeChange() {
|
if (ev.target != this._browser.contentDocument)
|
||||||
let [w, h] = BrowserView.Util.getBrowserDimensions(this._browser);
|
return;
|
||||||
let ev = document.createEvent("MouseEvents");
|
|
||||||
ev.initMouseEvent("FakeMozAfterSizeChange", false, false, window, 0, w, h, 0, 0, false, false, false, false, 0, null);
|
|
||||||
this._browser.dispatchEvent(ev);
|
|
||||||
},
|
|
||||||
// !!! --- RESIZE HACK END -------
|
|
||||||
|
|
||||||
handleMozAfterSizeChange: function handleMozAfterSizeChange(ev) {
|
let { x: scrollX, y: scrollY } = BrowserView.Util.getContentScrollOffset(this._browser);
|
||||||
// !!! --- RESIZE HACK BEGIN -----
|
|
||||||
// get the correct properties off of the event, these are wrong because
|
let x = ev.x + scrollX;
|
||||||
// we're using a MouseEvent, as it has an X and Y prop of some sort and
|
let y = ev.y + scrollY;
|
||||||
// we piggyback on that.
|
let w = ev.width;
|
||||||
let w = ev.screenX;
|
let h = ev.height;
|
||||||
let h = ev.screenY;
|
|
||||||
// !!! --- RESIZE HACK END -------
|
// Adjust width and height from the incoming event properties so that we
|
||||||
this.setViewportDimensions(this.browserToViewport(w), this.browserToViewport(h));
|
// ignore changes to width and height contributed by growth in page
|
||||||
|
// quadrants other than x > 0 && y > 0.
|
||||||
|
if (x < 0) w += x;
|
||||||
|
if (y < 0) h += y;
|
||||||
|
|
||||||
|
this.setViewportDimensions(this.browserToViewport(w),
|
||||||
|
this.browserToViewport(h));
|
||||||
},
|
},
|
||||||
|
|
||||||
zoomToPage: function zoomToPage() {
|
zoomToPage: function zoomToPage() {
|
||||||
this.setZoomLevel(this.getZoomForPage());
|
// See invalidateEntireView() for why we might be suppressing this zoom.
|
||||||
|
if (!this._suppressZoomToPage)
|
||||||
|
this.setZoomLevel(this.getZoomForPage());
|
||||||
},
|
},
|
||||||
|
|
||||||
getZoomForPage: function getZoomForPage() {
|
getZoomForPage: function getZoomForPage() {
|
||||||
|
@ -559,7 +582,9 @@ BrowserView.prototype = {
|
||||||
if (Util.contentIsHandheld(browser))
|
if (Util.contentIsHandheld(browser))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
let [w, h] = BrowserView.Util.getBrowserDimensions(browser);
|
let bvs = this._browserViewportState; // browser exists, so bvs must as well
|
||||||
|
let w = this.viewportToBrowser(bvs.viewportRect.right);
|
||||||
|
let h = this.viewportToBrowser(bvs.viewportRect.bottom);
|
||||||
return BrowserView.Util.pageZoomLevel(this.getVisibleRect(), w, h);
|
return BrowserView.Util.pageZoomLevel(this.getVisibleRect(), w, h);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -578,6 +603,55 @@ BrowserView.prototype = {
|
||||||
this.setZoomLevel(bvs.zoomLevel + zoomDelta);
|
this.setZoomLevel(bvs.zoomLevel + zoomDelta);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
//
|
||||||
|
// MozAfterPaint events do not guarantee to inform us of all
|
||||||
|
// invalidated paints (See
|
||||||
|
// https://developer.mozilla.org/en/Gecko-Specific_DOM_Events#Important_notes
|
||||||
|
// for details on what the event *does* guarantee). This is only an
|
||||||
|
// issue when the same current <browser> is used to navigate to a
|
||||||
|
// new page. Unless a zoom was issued during the page transition
|
||||||
|
// (e.g. a call to zoomToPage() or something of that nature), we
|
||||||
|
// aren't guaranteed that we've actually invalidated the entire
|
||||||
|
// page. We don't want to leave bits of the previous page in the
|
||||||
|
// view of the new one, so this method exists as a way for Browser
|
||||||
|
// to inform us that the page is changing, and that we really ought
|
||||||
|
// to invalidate everything. Ideally, we wouldn't have to rely on
|
||||||
|
// this being called, and we would get proper invalidates for the
|
||||||
|
// whole page no matter what is or is not visible.
|
||||||
|
//
|
||||||
|
// Note that calling this function isn't necessary in almost all
|
||||||
|
// cases, but should be done for correctness. Most of the time, one
|
||||||
|
// of the following two conditions is satisfied. Either
|
||||||
|
//
|
||||||
|
// (1) Pages have different widths so the Browser calls a
|
||||||
|
// zoomToPage() which forces a dirtyAll, or
|
||||||
|
// (2) MozAfterPaint does indeed inform us of dirtyRects covering
|
||||||
|
// the entire page (everything that could possibly become
|
||||||
|
// visible).
|
||||||
|
//
|
||||||
|
// Since calling this method means "everything is wrong and the
|
||||||
|
// <browser> is about to start giving you new data via MozAfterPaint
|
||||||
|
// and MozScrolledAreaChanged", we also supress any zoomToPage()
|
||||||
|
// that might be called until the next time setViewportDimensions()
|
||||||
|
// is called (which will probably be caused by an incoming
|
||||||
|
// MozScrolledAreaChanged event, or via someone very eagerly setting
|
||||||
|
// it manually so that they can zoom to that manual "page" width).
|
||||||
|
//
|
||||||
|
/**
|
||||||
|
* Invalidates the entire page by throwing away any cached graphical
|
||||||
|
* portions of the view and refusing to allow a zoomToPage() until
|
||||||
|
* the next explicit update of the viewport dimensions.
|
||||||
|
*
|
||||||
|
* This method should be called when the <browser> last set by
|
||||||
|
* setBrowser() is about to navigate to a new page.
|
||||||
|
*/
|
||||||
|
invalidateEntireView: function invalidateEntireView() {
|
||||||
|
if (this._browserViewportState) {
|
||||||
|
this._viewportChanged(false, true, true);
|
||||||
|
this._suppressZoomToPage = true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render a rectangle within the browser viewport to the destination canvas
|
* Render a rectangle within the browser viewport to the destination canvas
|
||||||
* under the given scale.
|
* under the given scale.
|
||||||
|
|
|
@ -151,18 +151,95 @@ TileManager.prototype = {
|
||||||
dirtyAll) {
|
dirtyAll) {
|
||||||
let tc = this._tileCache;
|
let tc = this._tileCache;
|
||||||
|
|
||||||
tc.iBound = Math.ceil(viewportRect.right / kTileWidth);
|
let iBoundOld = tc.iBound;
|
||||||
tc.jBound = Math.ceil(viewportRect.bottom / kTileHeight);
|
let jBoundOld = tc.jBound;
|
||||||
|
let iBound = tc.iBound = Math.ceil(viewportRect.right / kTileWidth) - 1;
|
||||||
|
let jBound = tc.jBound = Math.ceil(viewportRect.bottom / kTileHeight) - 1;
|
||||||
|
|
||||||
if (criticalRect.isEmpty() || !criticalRect.equals(this._criticalRect)) {
|
if (criticalRect.isEmpty() || !criticalRect.equals(this._criticalRect)) {
|
||||||
this.beginCriticalMove(criticalRect);
|
this.beginCriticalMove(criticalRect);
|
||||||
this.endCriticalMove(criticalRect, !boundsSizeChanged);
|
this.endCriticalMove(criticalRect, !(dirtyAll || boundsSizeChanged));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (boundsSizeChanged) {
|
|
||||||
// TODO fastpath if !dirtyAll
|
if (dirtyAll) {
|
||||||
this.dirtyRects([viewportRect.clone()], true);
|
this.dirtyRects([viewportRect.clone()], true);
|
||||||
|
} else if (boundsSizeChanged) {
|
||||||
|
|
||||||
|
//
|
||||||
|
// This is a special case. The bounds size changed, but we are
|
||||||
|
// told that not everything is dirty (so mayhap content grew or
|
||||||
|
// shrank vertically or horizontally). We might have old tiles
|
||||||
|
// around in those areas just due to the fact that they haven't
|
||||||
|
// been yet evicted, so we patrol the new regions in search of
|
||||||
|
// any such leftover tiles and mark those we find as dirty.
|
||||||
|
//
|
||||||
|
// The two dirty rects below mark dirty any renegade tiles in
|
||||||
|
// the newly annexed grid regions as per the following diagram
|
||||||
|
// of the "new" viewport.
|
||||||
|
//
|
||||||
|
// +------------+------+
|
||||||
|
// |old | A |
|
||||||
|
// |viewport | |
|
||||||
|
// | | |
|
||||||
|
// | | |
|
||||||
|
// | | |
|
||||||
|
// +------------+ |
|
||||||
|
// | B | |
|
||||||
|
// | | |
|
||||||
|
// +------------+------+
|
||||||
|
//
|
||||||
|
// The first rectangle covers annexed region A, the second
|
||||||
|
// rectangle covers annexed region B.
|
||||||
|
//
|
||||||
|
// XXXrf If the tiles are large, then we are creating some
|
||||||
|
// redundant work here by invalidating the entire tile that
|
||||||
|
// the old viewport boundary crossed (note markDirty() being
|
||||||
|
// called with no rectangle parameter). The rectangular area
|
||||||
|
// within the tile lying beyond the old boundary is certainly
|
||||||
|
// dirty, but not the area before. Moreover, since we mark
|
||||||
|
// dirty entire tiles that may cross into the old viewport,
|
||||||
|
// they might, in particular, cross into the critical rect
|
||||||
|
// (which is anyhwere in the old viewport), so we call a
|
||||||
|
// criticalRectPaint() for such cleanup. We do all this more
|
||||||
|
// or less because we don't have much of a notion of "the old
|
||||||
|
// viewport" here except for in the sense that we know the
|
||||||
|
// index bounds on the tilecache grid from before (and the new
|
||||||
|
// index bounds now).
|
||||||
|
//
|
||||||
|
|
||||||
|
let t, l, b, r, rect;
|
||||||
|
let rects = [];
|
||||||
|
|
||||||
|
if (iBoundOld <= iBound) {
|
||||||
|
l = iBoundOld * kTileWidth;
|
||||||
|
t = 0;
|
||||||
|
r = (iBound + 1) * kTileWidth;
|
||||||
|
b = (jBound + 1) * kTileHeight;
|
||||||
|
|
||||||
|
rect = new Rect(l, t, r - l, b - t);
|
||||||
|
rect.restrictTo(viewportRect);
|
||||||
|
|
||||||
|
if (!rect.isEmpty())
|
||||||
|
rects.push(rect);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (jBoundOld <= jBound) {
|
||||||
|
l = 0;
|
||||||
|
t = jBoundOld * kTileHeight;
|
||||||
|
r = (iBound + 1) * kTileWidth;
|
||||||
|
b = (jBound + 1) * kTileHeight;
|
||||||
|
|
||||||
|
rect = new Rect(l, t, r - l, b - t);
|
||||||
|
rect.restrictTo(viewportRect);
|
||||||
|
|
||||||
|
if (!rect.isEmpty())
|
||||||
|
rects.push(rect);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.dirtyRects(rects, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
dirtyRects: function dirtyRects(rects, doCriticalRender) {
|
dirtyRects: function dirtyRects(rects, doCriticalRender) {
|
||||||
|
|
|
@ -2444,10 +2444,6 @@ Tab.prototype = {
|
||||||
let bv = Browser._browserView;
|
let bv = Browser._browserView;
|
||||||
|
|
||||||
if (this == Browser.selectedTab) {
|
if (this == Browser.selectedTab) {
|
||||||
// !!! --- RESIZE HACK BEGIN -----
|
|
||||||
bv.simulateMozAfterSizeChange();
|
|
||||||
// !!! --- RESIZE HACK END -----
|
|
||||||
|
|
||||||
let restoringPage = (this._state != null);
|
let restoringPage = (this._state != null);
|
||||||
|
|
||||||
if (!this._browserViewportState.zoomChanged && !restoringPage) {
|
if (!this._browserViewportState.zoomChanged && !restoringPage) {
|
||||||
|
@ -2485,6 +2481,7 @@ Tab.prototype = {
|
||||||
|
|
||||||
if (!this._loadingTimeout) {
|
if (!this._loadingTimeout) {
|
||||||
Browser._browserView.beginBatchOperation();
|
Browser._browserView.beginBatchOperation();
|
||||||
|
Browser._browserView.invalidateEntireView();
|
||||||
this._loadingTimeout = setTimeout(Util.bind(this._resizeAndPaint, this), 2000);
|
this._loadingTimeout = setTimeout(Util.bind(this._resizeAndPaint, this), 2000);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
Загрузка…
Ссылка в новой задаче