diff --git a/browser/components/wintaskbar/WindowsPreviewPerTab.jsm b/browser/components/wintaskbar/WindowsPreviewPerTab.jsm index b66f597e1db..1f264c1ce9a 100644 --- a/browser/components/wintaskbar/WindowsPreviewPerTab.jsm +++ b/browser/components/wintaskbar/WindowsPreviewPerTab.jsm @@ -132,6 +132,19 @@ function getFaviconAsImage(iconurl, callback) { _imageFromURI(faviconSvc.defaultFavicon, callback); } +// Snaps the given rectangle to be pixel-aligned at the given scale +function snapRectAtScale(r, scale) { + let x = Math.floor(r.x * scale); + let y = Math.floor(r.y * scale); + let width = Math.ceil((r.x + r.width) * scale) - x; + let height = Math.ceil((r.y + r.height) * scale) - y; + + r.x = x / scale; + r.y = y / scale; + r.width = width / scale; + r.height = height / scale; +} + //////////////////////////////////////////////////////////////////////////////// //// PreviewController @@ -172,6 +185,13 @@ function PreviewController(win, tab) { dirtyRegion.init(); return dirtyRegion; }); + + XPCOMUtils.defineLazyGetter(this, "winutils", + function () { + let win = tab.linkedBrowser.contentWindow; + return win.QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIDOMWindowUtils); + }); } PreviewController.prototype = { @@ -214,6 +234,12 @@ PreviewController.prototype = { this.canvasPreview.height = 0; }, + get zoom() { + // We use this property instead of the fullZoom property because this + // accurately reflects the actual zoom factor used when drawing. + return this.winutils.screenPixelsPerCSSPixel; + }, + // Updates the controller's canvas with the parts of the that need // to be redrawn. updateCanvasPreview: function () { @@ -223,23 +249,30 @@ PreviewController.prototype = { if (bx.width != this.canvasPreview.width || bx.height != this.canvasPreview.height) { // Invalidate the entire area and repaint - this.onTabPaint({left:0, top:0, width:bx.width, height:bx.height}); + this.onTabPaint({left:0, top:0, right:win.innerWidth, bottom:win.innerHeight}); this.canvasPreview.width = bx.width; this.canvasPreview.height = bx.height; } // Draw dirty regions let ctx = this.canvasPreview.getContext("2d"); + let scale = this.zoom; + let flags = this.canvasPreviewFlags; - // width/height are occasionally bogus and too large for drawWindow - // so we clip to the canvas region - this.dirtyRegion.intersectRect(0, 0, bx.width, bx.height); + // The dirty region may include parts that are offscreen so we clip to the + // canvas area. + this.dirtyRegion.intersectRect(0, 0, win.innerWidth, win.innerHeight); this.dirtyRects.forEach(function (r) { + // We need to snap the rectangle to be pixel aligned in the destination + // coordinate space. Otherwise natively themed widgets might not draw. + snapRectAtScale(r, scale); let x = r.x; let y = r.y; let width = r.width; let height = r.height; + ctx.save(); + ctx.scale(scale, scale); ctx.translate(x, y); ctx.drawWindow(win, x, y, width, height, "white", flags); ctx.restore(); @@ -252,16 +285,11 @@ PreviewController.prototype = { }, onTabPaint: function (rect) { - // Ignore spurious dirty rects - if (!rect.width || !rect.height) - return; - - let r = { x: Math.floor(rect.left), - y: Math.floor(rect.top), - width: Math.ceil(rect.width), - height: Math.ceil(rect.height) - }; - this.dirtyRegion.unionRect(r.x, r.y, r.width, r.height); + let x = Math.floor(rect.left), + y = Math.floor(rect.top), + width = Math.ceil(rect.right) - x, + height = Math.ceil(rect.bottom) - y; + this.dirtyRegion.unionRect(x, y, width, height); }, updateTitleAndTooltip: function () { diff --git a/gfx/thebes/gfxContext.cpp b/gfx/thebes/gfxContext.cpp index eb4d6cddee7..5c488f44319 100644 --- a/gfx/thebes/gfxContext.cpp +++ b/gfx/thebes/gfxContext.cpp @@ -405,11 +405,15 @@ gfxContext::UserToDevicePixelSnapped(gfxRect& rect, PRBool ignoreScale) const // if we're not at 1.0 scale, don't snap, unless we're // ignoring the scale. If we're not -just- a scale, // never snap. + const gfxFloat epsilon = 0.0000001; +#define WITHIN_E(a,b) (fabs((a)-(b)) < epsilon) cairo_matrix_t mat; cairo_get_matrix(mCairo, &mat); if (!ignoreScale && - (mat.xx != 1.0 || mat.yy != 1.0 || mat.xy != 0.0 || mat.yx != 0.0)) + (!WITHIN_E(mat.xx,1.0) || !WITHIN_E(mat.yy,1.0) || + !WITHIN_E(mat.xy,0.0) || !WITHIN_E(mat.yx,0.0))) return PR_FALSE; +#undef WITHIN_E gfxPoint p1 = UserToDevice(rect.pos); gfxPoint p2 = UserToDevice(rect.pos + gfxSize(rect.size.width, 0.0));