diff --git a/gfx/public/nsITheme.h b/gfx/public/nsITheme.h index 31cfb11b729..cf3ca744871 100644 --- a/gfx/public/nsITheme.h +++ b/gfx/public/nsITheme.h @@ -83,7 +83,7 @@ public: nsIFrame* aFrame, PRUint8 aWidgetType, const nsRect& aRect, - const nsRect& aClipRect)=0; + const nsRect& aDirtyRect)=0; /** * Get the computed CSS border for the widget, in pixels. diff --git a/widget/src/cocoa/nsNativeThemeCocoa.h b/widget/src/cocoa/nsNativeThemeCocoa.h index a046a4be0a1..a8746e4ca3f 100644 --- a/widget/src/cocoa/nsNativeThemeCocoa.h +++ b/widget/src/cocoa/nsNativeThemeCocoa.h @@ -64,7 +64,7 @@ public: nsIFrame* aFrame, PRUint8 aWidgetType, const nsRect& aRect, - const nsRect& aClipRect); + const nsRect& aDirtyRect); NS_IMETHOD GetWidgetBorder(nsIDeviceContext* aContext, nsIFrame* aFrame, PRUint8 aWidgetType, diff --git a/widget/src/cocoa/nsNativeThemeCocoa.mm b/widget/src/cocoa/nsNativeThemeCocoa.mm index 6fcd993429d..4c627dd746a 100644 --- a/widget/src/cocoa/nsNativeThemeCocoa.mm +++ b/widget/src/cocoa/nsNativeThemeCocoa.mm @@ -984,7 +984,7 @@ nsNativeThemeCocoa::GetParentScrollbarFrame(nsIFrame *aFrame) NS_IMETHODIMP nsNativeThemeCocoa::DrawWidgetBackground(nsIRenderingContext* aContext, nsIFrame* aFrame, PRUint8 aWidgetType, const nsRect& aRect, - const nsRect& aClipRect) + const nsRect& aDirtyRect) { NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; @@ -993,16 +993,16 @@ nsNativeThemeCocoa::DrawWidgetBackground(nsIRenderingContext* aContext, nsIFrame aContext->GetDeviceContext(*getter_AddRefs(dctx)); PRInt32 p2a = dctx->AppUnitsPerDevPixel(); - gfxRect nativeClipRect(aClipRect.x, aClipRect.y, aClipRect.width, aClipRect.height); + gfxRect nativeDirtyRect(aDirtyRect.x, aDirtyRect.y, aDirtyRect.width, aDirtyRect.height); gfxRect nativeWidgetRect(aRect.x, aRect.y, aRect.width, aRect.height); nativeWidgetRect.ScaleInverse(gfxFloat(p2a)); - nativeClipRect.ScaleInverse(gfxFloat(p2a)); + nativeDirtyRect.ScaleInverse(gfxFloat(p2a)); nsRefPtr thebesCtx = aContext->ThebesContext(); if (!thebesCtx) return NS_ERROR_FAILURE; - gfxQuartzNativeDrawing nativeDrawing(thebesCtx, nativeClipRect); + gfxQuartzNativeDrawing nativeDrawing(thebesCtx, nativeDirtyRect); CGContextRef cgContext = nativeDrawing.BeginNativeDrawing(); if (cgContext == nsnull) { diff --git a/widget/src/gtk2/nsNativeThemeGTK.cpp b/widget/src/gtk2/nsNativeThemeGTK.cpp index 1a0c3bf51f9..b925de1049e 100644 --- a/widget/src/gtk2/nsNativeThemeGTK.cpp +++ b/widget/src/gtk2/nsNativeThemeGTK.cpp @@ -23,6 +23,7 @@ * Brian Ryner (Original Author) * Michael Ventnor * Teune van Steeg + * Karl Tomlinson , Mozilla Corporation * * 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 @@ -662,7 +663,7 @@ ThemeRenderer::NativeDraw(Screen* screen, Drawable drawable, Visual* visual, if (gdkPixmap) { g_object_ref(G_OBJECT(gdkPixmap)); } else { - // XXX gtk+2.10 has gdk_pixmap_foreign_new_for_screen which would not + // XXX gtk+-2.10 has gdk_pixmap_foreign_new_for_screen which would not // use XGetGeometry. gdkPixmap = gdk_pixmap_foreign_new_for_display(gdkDpy, drawable); if (!gdkPixmap) @@ -729,44 +730,12 @@ GetExtraSizeForWidget(PRUint8 aWidgetType, nsIntMargin* aExtra) } } -static GdkRectangle -ConvertToGdkRect(const nsRect &aRect, PRInt32 aP2A) -{ - GdkRectangle gdk_rect; - gdk_rect.x = NSAppUnitsToIntPixels(aRect.x, aP2A); - gdk_rect.y = NSAppUnitsToIntPixels(aRect.y, aP2A); - gdk_rect.width = NSAppUnitsToIntPixels(aRect.XMost(), aP2A) - gdk_rect.x; - gdk_rect.height = NSAppUnitsToIntPixels(aRect.YMost(), aP2A) - gdk_rect.y; - return gdk_rect; -} - -static GdkRectangle -ConvertGfxToGdkRect(const gfxRect &aRect, const gfxPoint &aTranslation) -{ - GdkRectangle gdk_rect; - gdk_rect.x = NSToIntRound(aRect.X()) - NSToIntRound(aTranslation.x); - gdk_rect.y = NSToIntRound(aRect.Y()) - NSToIntRound(aTranslation.y); - gdk_rect.width = NSToIntRound(aRect.Width()); - gdk_rect.height = NSToIntRound(aRect.Height()); - return gdk_rect; -} - -static gfxRect -ConvertToGfxRect(const nsRect &aRect, PRInt32 aP2A) -{ - gfxRect rect(NSAppUnitsToFloatPixels(aRect.x, aP2A), - NSAppUnitsToFloatPixels(aRect.y, aP2A), - NSAppUnitsToFloatPixels(aRect.width, aP2A), - NSAppUnitsToFloatPixels(aRect.height, aP2A)); - return rect; -} - NS_IMETHODIMP nsNativeThemeGTK::DrawWidgetBackground(nsIRenderingContext* aContext, nsIFrame* aFrame, PRUint8 aWidgetType, const nsRect& aRect, - const nsRect& aClipRect) + const nsRect& aDirtyRect) { GtkWidgetState state; GtkThemeWidgetType gtkWidgetType; @@ -775,25 +744,75 @@ nsNativeThemeGTK::DrawWidgetBackground(nsIRenderingContext* aContext, if (!GetGtkWidgetAndState(aWidgetType, aFrame, gtkWidgetType, &state, &flags)) return NS_OK; - - nsCOMPtr dctx = nsnull; - aContext->GetDeviceContext(*getter_AddRefs(dctx)); - PRInt32 p2a = dctx->AppUnitsPerDevPixel(); - // This is the rectangle that will actually be drawn, in appunits - nsRect drawingRect(aClipRect); + gfxContext* ctx = aContext->ThebesContext(); + nsPresContext *presContext = aFrame->PresContext(); + + gfxRect rect = presContext->AppUnitsToGfxUnits(aRect); + gfxRect dirtyRect = presContext->AppUnitsToGfxUnits(aDirtyRect); + + // Align to device pixels where sensible + // to provide crisper and faster drawing. + // Don't snap if it's a non-unit scale factor. We're going to have to take + // slow paths then in any case. + PRBool snapXY = ctx->UserToDevicePixelSnapped(rect); + if (snapXY) { + // Leave rect in device coords but make dirtyRect consistent. + dirtyRect = ctx->UserToDevice(dirtyRect); + } + + // Translate the dirty rect so that it is wrt the widget top-left. + dirtyRect.MoveBy(-rect.pos); + // Round out the dirty rect to gdk pixels to ensure that gtk draws + // enough pixels for interpolation to device pixels. + dirtyRect.RoundOut(); + + // GTK themes can only draw an integer number of pixels + // (even when not snapped). + nsIntRect widgetRect(0, 0, NS_lround(rect.Width()), NS_lround(rect.Height())); + + // This is the rectangle that will actually be drawn, in gdk pixels + nsIntRect drawingRect(PRInt32(dirtyRect.X()), + PRInt32(dirtyRect.Y()), + PRInt32(dirtyRect.Width()), + PRInt32(dirtyRect.Height())); + if (!drawingRect.IntersectRect(widgetRect, drawingRect)) + return NS_OK; + nsIntMargin extraSize; - GetExtraSizeForWidget(aWidgetType, &extraSize); - // inflate drawing rect to account for the overdraw - nsMargin extraSizeAppUnits(NSIntPixelsToAppUnits(extraSize.left, p2a), - NSIntPixelsToAppUnits(extraSize.top, p2a), - NSIntPixelsToAppUnits(extraSize.right, p2a), - NSIntPixelsToAppUnits(extraSize.bottom, p2a)); - drawingRect.Inflate(extraSizeAppUnits); + // The margin should be applied to the widget rect rather than the dirty + // rect but nsCSSRendering::PaintBackgroundWithSC has already intersected + // the dirty rect with the uninflated widget rect. + if (GetExtraSizeForWidget(aWidgetType, &extraSize)) { + drawingRect.Inflate(extraSize); + } + // gdk rectangles are wrt the drawing rect. + + // The gdk_clip is just advisory here, meanining "you don't + // need to draw outside this rect if you don't feel like it!" + GdkRectangle gdk_clip = {0, 0, drawingRect.width, drawingRect.height}; + + GdkRectangle gdk_rect = {-drawingRect.x, -drawingRect.y, + widgetRect.width, widgetRect.height}; + + ThemeRenderer renderer(state, gtkWidgetType, flags, direction, + gdk_rect, gdk_clip); + + // We require the use of the default screen and visual + // because I'm afraid that otherwise the GTK theme may explode. + // Some themes (e.g. Clearlooks) just don't clip properly to any + // clip rect we provide, so we cannot advertise support for clipping within + // the widget bounds. + PRUint32 rendererFlags = gfxXlibNativeRenderer::DRAW_SUPPORTS_OFFSET; + // translate everything so (0,0) is the top left of the drawingRect - nsIRenderingContext::AutoPushTranslation - autoTranslation(aContext, drawingRect.x, drawingRect.y); + gfxContextAutoSaveRestore autoSR(ctx); + if (snapXY) { + // Rects are in device coords. + ctx->IdentityMatrix(); + } + ctx->Translate(rect.pos + gfxPoint(drawingRect.x, drawingRect.y)); NS_ASSERTION(!IsWidgetTypeDisabled(mDisabledWidgetTypes, aWidgetType), "Trying to render an unsafe widget!"); @@ -805,53 +824,9 @@ nsNativeThemeGTK::DrawWidgetBackground(nsIRenderingContext* aContext, oldHandler = XSetErrorHandler(NativeThemeErrorHandler); } - gfxContext* ctx = aContext->ThebesContext(); - gfxMatrix current = ctx->CurrentMatrix(); - - // We require the use of the default screen and visual - // because I'm afraid that otherwise the GTK theme may explode. - // Some themes (e.g. Clearlooks) just don't clip properly to any - // clip rect we provide, so we cannot advertise support for clipping within the - // widget bounds. The gdk_clip is just advisory here, meanining "you don't - // need to draw outside this rect if you don't feel like it!" - GdkRectangle gdk_rect, gdk_clip; - gfxRect gfx_rect = ConvertToGfxRect(aRect - drawingRect.TopLeft(), p2a); - gfxRect gfx_clip = ConvertToGfxRect(drawingRect - drawingRect.TopLeft(), p2a); - if (ctx->UserToDevicePixelSnapped(gfx_rect) && - ctx->UserToDevicePixelSnapped(gfx_clip)) { - gfxPoint currentTranslation = current.GetTranslation(); - gdk_rect = ConvertGfxToGdkRect(gfx_rect, currentTranslation); - gdk_clip = ConvertGfxToGdkRect(gfx_clip, currentTranslation); - } - else { - gdk_rect = ConvertToGdkRect(aRect - drawingRect.TopLeft(), p2a); - gdk_clip = ConvertToGdkRect(drawingRect - drawingRect.TopLeft(), p2a); - } - ThemeRenderer renderer(state, gtkWidgetType, flags, direction, gdk_rect, gdk_clip); - - // XXXbz do we really want to round here, then snap, then round again? - gfxRect rect(0, 0, NSAppUnitsToIntPixels(drawingRect.width, p2a), - NSAppUnitsToIntPixels(drawingRect.height, p2a)); - - PRUint32 rendererFlags = gfxXlibNativeRenderer::DRAW_SUPPORTS_OFFSET; - // Don't snap if it's a non-unit scale factor. We're going to have to take - // slow paths then in any case. - PRBool snapXY = ctx->UserToDevicePixelSnapped(rect) && - !current.HasNonTranslation(); - if (snapXY) { - gfxMatrix translation; - translation.Translate(rect.TopLeft()); - ctx->SetMatrix(translation); - renderer.Draw(gdk_x11_get_default_xdisplay(), ctx, - NSToCoordRound(rect.Width()), NSToCoordRound(rect.Height()), - rendererFlags, nsnull); - ctx->SetMatrix(current); - } else { - renderer.Draw(gdk_x11_get_default_xdisplay(), ctx, - NSToIntCeil(NSAppUnitsToFloatPixels(drawingRect.width, p2a)), - NSToIntCeil(NSAppUnitsToFloatPixels(drawingRect.height, p2a)), - rendererFlags, nsnull); - } + renderer.Draw(gdk_x11_get_default_xdisplay(), ctx, + drawingRect.width, drawingRect.height, + rendererFlags, nsnull); if (!safeState) { gdk_flush(); diff --git a/widget/src/gtk2/nsNativeThemeGTK.h b/widget/src/gtk2/nsNativeThemeGTK.h index e37eda5cb6d..291b0bc651d 100644 --- a/widget/src/gtk2/nsNativeThemeGTK.h +++ b/widget/src/gtk2/nsNativeThemeGTK.h @@ -57,7 +57,7 @@ public: NS_IMETHOD DrawWidgetBackground(nsIRenderingContext* aContext, nsIFrame* aFrame, PRUint8 aWidgetType, const nsRect& aRect, - const nsRect& aClipRect); + const nsRect& aDirtyRect); NS_IMETHOD GetWidgetBorder(nsIDeviceContext* aContext, nsIFrame* aFrame, PRUint8 aWidgetType, nsMargin* aResult); diff --git a/widget/src/windows/nsNativeThemeWin.cpp b/widget/src/windows/nsNativeThemeWin.cpp index 1d535f369d0..b91228389b3 100644 --- a/widget/src/windows/nsNativeThemeWin.cpp +++ b/widget/src/windows/nsNativeThemeWin.cpp @@ -956,11 +956,11 @@ nsNativeThemeWin::DrawWidgetBackground(nsIRenderingContext* aContext, nsIFrame* aFrame, PRUint8 aWidgetType, const nsRect& aRect, - const nsRect& aClipRect) + const nsRect& aDirtyRect) { HANDLE theme = GetTheme(aWidgetType); if (!theme) - return ClassicDrawWidgetBackground(aContext, aFrame, aWidgetType, aRect, aClipRect); + return ClassicDrawWidgetBackground(aContext, aFrame, aWidgetType, aRect, aDirtyRect); if (!nsUXThemeData::drawThemeBG) return NS_ERROR_FAILURE; @@ -976,10 +976,10 @@ nsNativeThemeWin::DrawWidgetBackground(nsIRenderingContext* aContext, RECT widgetRect; RECT clipRect; gfxRect tr(aRect.x, aRect.y, aRect.width, aRect.height), - cr(aClipRect.x, aClipRect.y, aClipRect.width, aClipRect.height); + dr(aDirtyRect.x, aDirtyRect.y, aDirtyRect.width, aDirtyRect.height); tr.ScaleInverse(p2a); - cr.ScaleInverse(p2a); + dr.ScaleInverse(p2a); /* See GetWidgetOverflow */ if (aWidgetType == NS_THEME_DROPDOWN_BUTTON && @@ -989,14 +989,14 @@ nsNativeThemeWin::DrawWidgetBackground(nsIRenderingContext* aContext, tr.size.width += 1.0; tr.size.height += 2.0; - cr.pos.y -= 1.0; - cr.size.width += 1.0; - cr.size.height += 2.0; + dr.pos.y -= 1.0; + dr.size.width += 1.0; + dr.size.height += 2.0; } nsRefPtr ctx = aContext->ThebesContext(); - gfxWindowsNativeDrawing nativeDrawing(ctx, cr, GetWidgetNativeDrawingFlags(aWidgetType)); + gfxWindowsNativeDrawing nativeDrawing(ctx, dr, GetWidgetNativeDrawingFlags(aWidgetType)); RENDER_AGAIN: @@ -1005,13 +1005,13 @@ RENDER_AGAIN: return NS_ERROR_FAILURE; nativeDrawing.TransformToNativeRect(tr, widgetRect); - nativeDrawing.TransformToNativeRect(cr, clipRect); + nativeDrawing.TransformToNativeRect(dr, clipRect); #if 0 { fprintf (stderr, "xform: %f %f %f %f [%f %f]\n", m.xx, m.yx, m.xy, m.yy, m.x0, m.y0); - fprintf (stderr, "tr: [%d %d %d %d]\ncr: [%d %d %d %d]\noff: [%f %f]\n", - tr.x, tr.y, tr.width, tr.height, cr.x, cr.y, cr.width, cr.height, + fprintf (stderr, "tr: [%d %d %d %d]\ndr: [%d %d %d %d]\noff: [%f %f]\n", + tr.x, tr.y, tr.width, tr.height, dr.x, dr.y, dr.width, dr.height, offset.x, offset.y); } #endif @@ -2384,7 +2384,7 @@ nsresult nsNativeThemeWin::ClassicDrawWidgetBackground(nsIRenderingContext* aCon nsIFrame* aFrame, PRUint8 aWidgetType, const nsRect& aRect, - const nsRect& aClipRect) + const nsRect& aDirtyRect) { PRInt32 part, state; PRBool focused; @@ -2398,14 +2398,14 @@ nsresult nsNativeThemeWin::ClassicDrawWidgetBackground(nsIRenderingContext* aCon gfxFloat p2a = gfxFloat(dc->AppUnitsPerDevPixel()); RECT widgetRect; gfxRect tr(aRect.x, aRect.y, aRect.width, aRect.height), - cr(aClipRect.x, aClipRect.y, aClipRect.width, aClipRect.height); + dr(aDirtyRect.x, aDirtyRect.y, aDirtyRect.width, aDirtyRect.height); tr.ScaleInverse(p2a); - cr.ScaleInverse(p2a); + dr.ScaleInverse(p2a); nsRefPtr ctx = aContext->ThebesContext(); - gfxWindowsNativeDrawing nativeDrawing(ctx, cr, GetWidgetNativeDrawingFlags(aWidgetType)); + gfxWindowsNativeDrawing nativeDrawing(ctx, dr, GetWidgetNativeDrawingFlags(aWidgetType)); RENDER_AGAIN: diff --git a/widget/src/windows/nsNativeThemeWin.h b/widget/src/windows/nsNativeThemeWin.h index 36b52e3f0e5..b0e7993af3b 100644 --- a/widget/src/windows/nsNativeThemeWin.h +++ b/widget/src/windows/nsNativeThemeWin.h @@ -53,7 +53,7 @@ public: nsIFrame* aFrame, PRUint8 aWidgetType, const nsRect& aRect, - const nsRect& aClipRect); + const nsRect& aDirtyRect); NS_IMETHOD GetWidgetBorder(nsIDeviceContext* aContext, nsIFrame* aFrame,