rounding changes in nsNativeThemeGTK::DrawWidgetBackground,

rename aClipRect to aDirtyRect in nsITheme::DrawWidgetBackground. b=444837 r=roc
This commit is contained in:
Karl Tomlinson 2008-07-25 11:01:59 +12:00
Родитель 516ed839ce
Коммит 0ed708d923
7 изменённых файлов: 94 добавлений и 119 удалений

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

@ -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.

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

@ -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,

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

@ -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<gfxContext> thebesCtx = aContext->ThebesContext();
if (!thebesCtx)
return NS_ERROR_FAILURE;
gfxQuartzNativeDrawing nativeDrawing(thebesCtx, nativeClipRect);
gfxQuartzNativeDrawing nativeDrawing(thebesCtx, nativeDirtyRect);
CGContextRef cgContext = nativeDrawing.BeginNativeDrawing();
if (cgContext == nsnull) {

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

@ -23,6 +23,7 @@
* Brian Ryner <bryner@brianryner.com> (Original Author)
* Michael Ventnor <m.ventnor@gmail.com>
* Teune van Steeg <t.vansteeg@gmail.com>
* Karl Tomlinson <karlt+@karlt.net>, 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;
@ -776,24 +745,74 @@ nsNativeThemeGTK::DrawWidgetBackground(nsIRenderingContext* aContext,
&flags))
return NS_OK;
nsCOMPtr<nsIDeviceContext> dctx = nsnull;
aContext->GetDeviceContext(*getter_AddRefs(dctx));
PRInt32 p2a = dctx->AppUnitsPerDevPixel();
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;
// This is the rectangle that will actually be drawn, in appunits
nsRect drawingRect(aClipRect);
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()),
drawingRect.width, drawingRect.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);
}
if (!safeState) {
gdk_flush();

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

@ -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);

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

@ -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<gfxContext> 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<gfxContext> ctx = aContext->ThebesContext();
gfxWindowsNativeDrawing nativeDrawing(ctx, cr, GetWidgetNativeDrawingFlags(aWidgetType));
gfxWindowsNativeDrawing nativeDrawing(ctx, dr, GetWidgetNativeDrawingFlags(aWidgetType));
RENDER_AGAIN:

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

@ -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,