diff --git a/content/canvas/src/nsCanvasRenderingContext2D.cpp b/content/canvas/src/nsCanvasRenderingContext2D.cpp --- a/content/canvas/src/nsCanvasRenderingContext2D.cpp +++ b/content/canvas/src/nsCanvasRenderingContext2D.cpp @@ -318,6 +318,7 @@ public: virtual ~nsCanvasRenderingContext2D(); nsresult Redraw(); + nsresult Redraw(const nsRect& r); // nsICanvasRenderingContextInternal NS_IMETHOD SetCanvasElement(nsICanvasElement* aParentCanvas); @@ -870,6 +871,20 @@ nsCanvasRenderingContext2D::Redraw() if (!mIsFrameInvalid) { mIsFrameInvalid = PR_TRUE; return mCanvasElement->InvalidateFrame(); + } + + return NS_OK; +} + +nsresult +nsCanvasRenderingContext2D::Redraw(const nsRect& r) +{ + if (!mCanvasElement) + return NS_OK; + + if (!mIsFrameInvalid) { + mIsFrameInvalid = PR_TRUE; + return mCanvasElement->InvalidateFrameSubrect(r); } return NS_OK; @@ -3419,7 +3434,17 @@ nsCanvasRenderingContext2D::DrawWindow(n mThebes->SetColor(gfxRGBA(1,1,1,1)); DirtyAllStyles(); - Redraw(); + // note that aX and aY are coordinates in the document that + // we're drawing; aX and aY are drawn to 0,0 in current user + // space. + gfxRect damageRect = mThebes->UserToDevice(gfxRect(0, 0, aW, aH)); + damageRect.RoundOut(); + + nsRect redrawRect(nsPresContext::CSSPixelsToAppUnits((PRInt32) damageRect.pos.x), + nsPresContext::CSSPixelsToAppUnits((PRInt32) damageRect.pos.y), + nsPresContext::CSSPixelsToAppUnits((PRInt32) damageRect.size.width), + nsPresContext::CSSPixelsToAppUnits((PRInt32) damageRect.size.height)); + Redraw(redrawRect); return rv; } diff --git a/content/html/content/src/nsHTMLCanvasElement.cpp b/content/html/content/src/nsHTMLCanvasElement.cpp --- a/content/html/content/src/nsHTMLCanvasElement.cpp +++ b/content/html/content/src/nsHTMLCanvasElement.cpp @@ -559,7 +559,28 @@ nsHTMLCanvasElement::InvalidateFrameSubr { nsIFrame *frame = GetPrimaryFrame(Flush_Frames); if (frame) { - frame->Invalidate(damageRect); + nsRect contentArea(frame->GetContentRect()); + nsRect realRect(damageRect); + + nsIntSize sz = GetWidthHeight(); + nsSize sizeAppUnits(nsPresContext::CSSPixelsToAppUnits(sz.width), + nsPresContext::CSSPixelsToAppUnits(sz.height)); + + if (contentArea.Size() != sizeAppUnits) { + // the canvas is CSS-scaled, so we need to scale the damage region + float sx = contentArea.width / (float) sizeAppUnits.width; + float sy = contentArea.height / (float) sizeAppUnits.height; + + realRect.x = NSToIntFloor(realRect.x * sx); + realRect.y = NSToIntFloor(realRect.y * sy); + realRect.width = NSToIntCeil(realRect.width * sx); + realRect.height = NSToIntCeil(realRect.height * sy); + } + + // account for border/padding + realRect.MoveBy(contentArea.TopLeft() - frame->GetPosition()); + + frame->Invalidate(realRect); } return NS_OK; diff --git a/layout/generic/nsHTMLCanvasFrame.cpp b/layout/generic/nsHTMLCanvasFrame.cpp --- a/layout/generic/nsHTMLCanvasFrame.cpp +++ b/layout/generic/nsHTMLCanvasFrame.cpp @@ -49,6 +49,7 @@ #include "nsTransform2D.h" +#include "gfxContext.h" class nsDisplayItemCanvas : public nsDisplayItem { public: @@ -224,6 +225,7 @@ nsHTMLCanvasFrame::PaintCanvas(nsIRender nsHTMLCanvasFrame::PaintCanvas(nsIRenderingContext& aRenderingContext, const nsRect& aDirtyRect, nsPoint aPt) { + nsPresContext *presContext = PresContext(); nsRect inner = GetInnerArea() + aPt; nsCOMPtr canvas(do_QueryInterface(GetContent())); @@ -234,34 +236,39 @@ nsHTMLCanvasFrame::PaintCanvas(nsIRender if (inner.width == 0 || inner.height == 0) return; - nsIntSize canvasSize = GetCanvasSize(); - nsSize sizeAppUnits(PresContext()->DevPixelsToAppUnits(canvasSize.width), - PresContext()->DevPixelsToAppUnits(canvasSize.height)); + nsIntSize sz = GetCanvasSize(); + nsSize sizeAppUnits(nsPresContext::CSSPixelsToAppUnits(sz.width), + nsPresContext::CSSPixelsToAppUnits(sz.height)); - // XXXvlad clip to aDirtyRect! + gfxContext *ctx = aRenderingContext.ThebesContext(); - if (inner.Size() != sizeAppUnits) - { - float sx = inner.width / (float) sizeAppUnits.width; - float sy = inner.height / (float) sizeAppUnits.height; + gfxFloat sx = 1.0; + gfxFloat sy = 1.0; - aRenderingContext.PushState(); - aRenderingContext.Translate(inner.x, inner.y); - aRenderingContext.Scale(sx, sy); + if (inner.Size() != sizeAppUnits) { + sx = inner.width / (gfxFloat) sizeAppUnits.width; + sy = inner.height / (gfxFloat) sizeAppUnits.height; + } - canvas->RenderContexts(aRenderingContext.ThebesContext()); + gfxRect dirty(presContext->AppUnitsToGfxUnits(aDirtyRect.x), + presContext->AppUnitsToGfxUnits(aDirtyRect.y), + presContext->AppUnitsToGfxUnits(aDirtyRect.width), + presContext->AppUnitsToGfxUnits(aDirtyRect.height)); + dirty.RoundOut(); - aRenderingContext.PopState(); - } else { - //nsIRenderingContext::AutoPushTranslation(&aRenderingContext, px, py); + ctx->Save(); - aRenderingContext.PushState(); - aRenderingContext.Translate(inner.x, inner.y); + ctx->NewPath(); + ctx->Rectangle(dirty); + ctx->Clip(); - canvas->RenderContexts(aRenderingContext.ThebesContext()); + ctx->Translate(gfxPoint(presContext->AppUnitsToGfxUnits(inner.x), + presContext->AppUnitsToGfxUnits(inner.y))); + ctx->Scale(sx, sy); - aRenderingContext.PopState(); - } + canvas->RenderContexts(ctx); + + ctx->Restore(); } NS_IMETHODIMP