diff --git a/content/canvas/public/nsICanvasElement.h b/content/canvas/public/nsICanvasElement.h index b61c741806b0..c8e61bb70cd1 100644 --- a/content/canvas/public/nsICanvasElement.h +++ b/content/canvas/public/nsICanvasElement.h @@ -39,10 +39,10 @@ #define nsICanvasElement_h___ #include "nsISupports.h" -#include "nsRect.h" class gfxContext; class nsIFrame; +struct gfxRect; // {C234660C-BD06-493e-8583-939A5A158B37} #define NS_ICANVASELEMENT_IID \ @@ -91,9 +91,9 @@ public: /* * Ask the canvas frame to invalidate a portion of the frame; damageRect - * is relative to the origin of the canvas frame. + * is relative to the origin of the canvas frame in CSS pixels. */ - NS_IMETHOD InvalidateFrameSubrect (const nsRect& damageRect) = 0; + NS_IMETHOD InvalidateFrameSubrect (const gfxRect& damageRect) = 0; /* * Get the number of contexts in this canvas, and request a context at diff --git a/content/canvas/src/nsCanvasRenderingContext2D.cpp b/content/canvas/src/nsCanvasRenderingContext2D.cpp index e73f6f461f1e..f865ef28a91f 100644 --- a/content/canvas/src/nsCanvasRenderingContext2D.cpp +++ b/content/canvas/src/nsCanvasRenderingContext2D.cpp @@ -318,6 +318,8 @@ public: virtual ~nsCanvasRenderingContext2D(); nsresult Redraw(); + // this rect is in CSS pixels + nsresult Redraw(const gfxRect& r); // nsICanvasRenderingContextInternal NS_IMETHOD SetCanvasElement(nsICanvasElement* aParentCanvas); @@ -889,6 +891,20 @@ nsCanvasRenderingContext2D::Redraw() return NS_OK; } +nsresult +nsCanvasRenderingContext2D::Redraw(const gfxRect& r) +{ + if (!mCanvasElement) + return NS_OK; + + if (!mIsFrameInvalid) { + mIsFrameInvalid = PR_TRUE; + return mCanvasElement->InvalidateFrameSubrect(r); + } + + return NS_OK; +} + NS_IMETHODIMP nsCanvasRenderingContext2D::SetDimensions(PRInt32 width, PRInt32 height) { @@ -3433,7 +3449,13 @@ nsCanvasRenderingContext2D::DrawWindow(nsIDOMWindow* aWindow, float aX, float aY 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(); + + Redraw(damageRect); return rv; } diff --git a/content/html/content/src/nsHTMLCanvasElement.cpp b/content/html/content/src/nsHTMLCanvasElement.cpp index 2971d962593f..1db2e90301cd 100644 --- a/content/html/content/src/nsHTMLCanvasElement.cpp +++ b/content/html/content/src/nsHTMLCanvasElement.cpp @@ -92,7 +92,7 @@ public: virtual PRBool IsWriteOnly(); virtual void SetWriteOnly(); NS_IMETHOD InvalidateFrame (); - NS_IMETHOD InvalidateFrameSubrect (const nsRect& damageRect); + NS_IMETHOD InvalidateFrameSubrect (const gfxRect& damageRect); virtual PRInt32 CountContexts(); virtual nsICanvasRenderingContextInternal *GetContextAtIndex (PRInt32 index); virtual PRBool GetIsOpaque(); @@ -555,11 +555,29 @@ nsHTMLCanvasElement::InvalidateFrame() } NS_IMETHODIMP -nsHTMLCanvasElement::InvalidateFrameSubrect(const nsRect& damageRect) +nsHTMLCanvasElement::InvalidateFrameSubrect(const gfxRect& damageRect) { nsIFrame *frame = GetPrimaryFrame(Flush_Frames); if (frame) { - frame->Invalidate(damageRect); + nsRect contentArea(frame->GetContentRect()); + nsIntSize size = GetWidthHeight(); + + // damageRect and size are in CSS pixels; contentArea is in appunits + // We want a rect in appunits; so avoid doing pixels-to-appunits and + // vice versa conversion here. + gfxRect realRect(damageRect); + realRect.Scale(contentArea.width / gfxFloat(size.width), + contentArea.height / gfxFloat(size.height)); + realRect.RoundOut(); + + // then make it a nsRect + nsRect invalRect(realRect.X(), realRect.Y(), + realRect.Width(), realRect.Height()); + + // account for border/padding + invalRect.MoveBy(contentArea.TopLeft() - frame->GetPosition()); + + frame->Invalidate(invalRect); } return NS_OK; diff --git a/layout/generic/nsHTMLCanvasFrame.cpp b/layout/generic/nsHTMLCanvasFrame.cpp index 17427c56589e..6af9bb91e9d9 100644 --- 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 @@ void nsHTMLCanvasFrame::PaintCanvas(nsIRenderingContext& aRenderingContext, const nsRect& aDirtyRect, nsPoint aPt) { + nsPresContext *presContext = PresContext(); nsRect inner = GetInnerArea() + aPt; nsCOMPtr canvas(do_QueryInterface(GetContent())); @@ -234,34 +236,24 @@ nsHTMLCanvasFrame::PaintCanvas(nsIRenderingContext& aRenderingContext, if (inner.width == 0 || inner.height == 0) return; - nsIntSize canvasSize = GetCanvasSize(); - nsSize sizeAppUnits(PresContext()->DevPixelsToAppUnits(canvasSize.width), - PresContext()->DevPixelsToAppUnits(canvasSize.height)); + nsIntSize sizeCSSPixels = GetCanvasSize(); + nsSize sizeAppUnits(nsPresContext::CSSPixelsToAppUnits(sizeCSSPixels.width), + nsPresContext::CSSPixelsToAppUnits(sizeCSSPixels.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 = inner.width / (gfxFloat) sizeAppUnits.width; + gfxFloat sy = inner.height / (gfxFloat) sizeAppUnits.height; - aRenderingContext.PushState(); - aRenderingContext.Translate(inner.x, inner.y); - aRenderingContext.Scale(sx, sy); + ctx->Save(); - canvas->RenderContexts(aRenderingContext.ThebesContext()); + ctx->Translate(gfxPoint(presContext->AppUnitsToGfxUnits(inner.x), + presContext->AppUnitsToGfxUnits(inner.y))); + ctx->Scale(sx, sy); - aRenderingContext.PopState(); - } else { - //nsIRenderingContext::AutoPushTranslation(&aRenderingContext, px, py); + canvas->RenderContexts(ctx); - aRenderingContext.PushState(); - aRenderingContext.Translate(inner.x, inner.y); - - canvas->RenderContexts(aRenderingContext.ThebesContext()); - - aRenderingContext.PopState(); - } + ctx->Restore(); } NS_IMETHODIMP