mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 639689. Part 4: Optimize Redraw by creating custom RedrawUser, which avoids having to do user->device rectangle transformation if we've already invalidated the full canvas. Also, if the last batch of canvas drawing operations contained many operations causing us to invalidate the full canvas, assume that the next batch will also contain many operations and invalidate the full canvas in the first operation of the batch, r=joe
This commit is contained in:
parent
3dd0479a61
commit
6efae32538
@ -411,8 +411,10 @@ public:
|
||||
LayerManager *aManager);
|
||||
void MarkContextClean();
|
||||
NS_IMETHOD SetIsIPC(PRBool isIPC);
|
||||
// this rect is in CSS pixels
|
||||
// this rect is in canvas device space
|
||||
NS_IMETHOD Redraw(const gfxRect &r);
|
||||
// this rect is in mThebes's current user space
|
||||
NS_IMETHOD RedrawUser(const gfxRect &r);
|
||||
|
||||
// nsISupports interface + CC
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
@ -503,7 +505,13 @@ protected:
|
||||
* Flag to avoid duplicate calls to InvalidateFrame. Set to true whenever
|
||||
* Redraw is called, reset to false when Render is called.
|
||||
*/
|
||||
PRBool mIsEntireFrameInvalid;
|
||||
PRPackedBool mIsEntireFrameInvalid;
|
||||
/**
|
||||
* When this is set, the first call to Redraw(gfxRect) should set
|
||||
* mIsEntireFrameInvalid since we expect it will be followed by
|
||||
* many more Redraw calls.
|
||||
*/
|
||||
PRPackedBool mPredictManyRedrawCalls;
|
||||
|
||||
/**
|
||||
* Number of times we've invalidated before calling redraw
|
||||
@ -603,7 +611,7 @@ protected:
|
||||
* Draws the current path in the given style. Takes care of
|
||||
* any shadow drawing and will use intermediate surfaces as needed.
|
||||
*
|
||||
* If dirtyRect is given, it will contain the device-space dirty
|
||||
* If dirtyRect is given, it will contain the user-space dirty
|
||||
* rectangle of the draw operation.
|
||||
*/
|
||||
nsresult DrawPath(Style style, gfxRect *dirtyRect = nsnull);
|
||||
@ -821,7 +829,8 @@ nsCanvasRenderingContext2D::nsCanvasRenderingContext2D()
|
||||
: mValid(PR_FALSE), mOpaque(PR_FALSE), mResetLayer(PR_TRUE)
|
||||
, mIPC(PR_FALSE)
|
||||
, mCanvasElement(nsnull)
|
||||
, mSaveCount(0), mIsEntireFrameInvalid(PR_FALSE), mInvalidateCount(0)
|
||||
, mSaveCount(0), mIsEntireFrameInvalid(PR_FALSE)
|
||||
, mPredictManyRedrawCalls(PR_FALSE), mInvalidateCount(0)
|
||||
, mLastStyle(STYLE_MAX), mStyleStack(20)
|
||||
{
|
||||
sNumLivingContexts++;
|
||||
@ -851,6 +860,7 @@ nsCanvasRenderingContext2D::Reset()
|
||||
mThebes = nsnull;
|
||||
mValid = PR_FALSE;
|
||||
mIsEntireFrameInvalid = PR_FALSE;
|
||||
mPredictManyRedrawCalls = PR_FALSE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -1014,6 +1024,10 @@ nsCanvasRenderingContext2D::ApplyStyle(Style aWhichStyle,
|
||||
nsresult
|
||||
nsCanvasRenderingContext2D::Redraw()
|
||||
{
|
||||
if (mIsEntireFrameInvalid)
|
||||
return NS_OK;
|
||||
mIsEntireFrameInvalid = PR_TRUE;
|
||||
|
||||
if (!mCanvasElement) {
|
||||
NS_ASSERTION(mDocShell, "Redraw with no canvas element or docshell!");
|
||||
return NS_OK;
|
||||
@ -1023,11 +1037,6 @@ nsCanvasRenderingContext2D::Redraw()
|
||||
nsSVGEffects::InvalidateDirectRenderingObservers(HTMLCanvasElement());
|
||||
#endif
|
||||
|
||||
if (mIsEntireFrameInvalid)
|
||||
return NS_OK;
|
||||
|
||||
mIsEntireFrameInvalid = PR_TRUE;
|
||||
|
||||
HTMLCanvasElement()->InvalidateFrame();
|
||||
|
||||
return NS_OK;
|
||||
@ -1036,9 +1045,16 @@ nsCanvasRenderingContext2D::Redraw()
|
||||
NS_IMETHODIMP
|
||||
nsCanvasRenderingContext2D::Redraw(const gfxRect& r)
|
||||
{
|
||||
++mInvalidateCount;
|
||||
|
||||
if (mIsEntireFrameInvalid)
|
||||
return NS_OK;
|
||||
|
||||
if (mPredictManyRedrawCalls ||
|
||||
mInvalidateCount > kCanvasMaxInvalidateCount) {
|
||||
return Redraw();
|
||||
}
|
||||
|
||||
if (!mCanvasElement) {
|
||||
NS_ASSERTION(mDocShell, "Redraw with no canvas element or docshell!");
|
||||
return NS_OK;
|
||||
@ -1048,14 +1064,22 @@ nsCanvasRenderingContext2D::Redraw(const gfxRect& r)
|
||||
nsSVGEffects::InvalidateDirectRenderingObservers(HTMLCanvasElement());
|
||||
#endif
|
||||
|
||||
if (++mInvalidateCount > kCanvasMaxInvalidateCount)
|
||||
return Redraw();
|
||||
|
||||
HTMLCanvasElement()->InvalidateFrame(&r);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsCanvasRenderingContext2D::RedrawUser(const gfxRect& r)
|
||||
{
|
||||
if (mIsEntireFrameInvalid) {
|
||||
++mInvalidateCount;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return Redraw(mThebes->UserToDevice(r));
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsCanvasRenderingContext2D::SetDimensions(PRInt32 width, PRInt32 height)
|
||||
{
|
||||
@ -1914,8 +1938,6 @@ nsCanvasRenderingContext2D::DrawPath(Style style, gfxRect *dirtyRect)
|
||||
// just use the clip extents
|
||||
*dirtyRect = mThebes->GetClipExtents();
|
||||
}
|
||||
|
||||
*dirtyRect = mThebes->UserToDevice(*dirtyRect);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
@ -1939,8 +1961,7 @@ nsCanvasRenderingContext2D::ClearRect(float x, float y, float w, float h)
|
||||
mThebes->Rectangle(gfxRect(x, y, w, h));
|
||||
mThebes->Fill();
|
||||
|
||||
gfxRect dirty = mThebes->UserToDevice(mThebes->GetUserPathExtent());
|
||||
return Redraw(dirty);
|
||||
return RedrawUser(mThebes->GetUserPathExtent());
|
||||
}
|
||||
|
||||
nsresult
|
||||
@ -1959,7 +1980,7 @@ nsCanvasRenderingContext2D::DrawRect(const gfxRect& rect, Style style)
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
return Redraw(dirty);
|
||||
return RedrawUser(dirty);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
@ -1999,7 +2020,7 @@ nsCanvasRenderingContext2D::Fill()
|
||||
nsresult rv = DrawPath(STYLE_FILL, &dirty);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
return Redraw(dirty);
|
||||
return RedrawUser(dirty);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
@ -2009,7 +2030,7 @@ nsCanvasRenderingContext2D::Stroke()
|
||||
nsresult rv = DrawPath(STYLE_STROKE, &dirty);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
return Redraw(dirty);
|
||||
return RedrawUser(dirty);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
@ -2848,7 +2869,7 @@ nsCanvasRenderingContext2D::DrawOrMeasureText(const nsAString& aRawText,
|
||||
mThebes->Paint(CurrentState().StyleIsColor(STYLE_FILL) ? 1.0 : CurrentState().globalAlpha);
|
||||
|
||||
if (aOp == nsCanvasRenderingContext2D::TEXT_DRAW_OPERATION_FILL && !doDrawShadow)
|
||||
return Redraw(mThebes->UserToDevice(boundingBox));
|
||||
return RedrawUser(boundingBox);
|
||||
|
||||
return Redraw();
|
||||
}
|
||||
@ -3511,10 +3532,7 @@ nsCanvasRenderingContext2D::DrawImage(nsIDOMElement *imgElt, float a1,
|
||||
mThebes->Paint(CurrentState().globalAlpha);
|
||||
}
|
||||
|
||||
if (!mIsEntireFrameInvalid) {
|
||||
gfxRect dirty = mThebes->UserToDevice(clip);
|
||||
Redraw(dirty);
|
||||
}
|
||||
RedrawUser(clip);
|
||||
}
|
||||
|
||||
FINISH:
|
||||
@ -3669,9 +3687,7 @@ nsCanvasRenderingContext2D::DrawWindow(nsIDOMWindow* aWindow, float aX, float aY
|
||||
// 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));
|
||||
|
||||
Redraw(damageRect);
|
||||
RedrawUser(gfxRect(0, 0, aW, aH));
|
||||
|
||||
return rv;
|
||||
}
|
||||
@ -4107,6 +4123,9 @@ nsCanvasRenderingContext2D::GetCanvasLayer(CanvasLayer *aOldLayer,
|
||||
void
|
||||
nsCanvasRenderingContext2D::MarkContextClean()
|
||||
{
|
||||
if (mInvalidateCount > 0) {
|
||||
mPredictManyRedrawCalls = mInvalidateCount > kCanvasMaxInvalidateCount;
|
||||
}
|
||||
mIsEntireFrameInvalid = PR_FALSE;
|
||||
mInvalidateCount = 0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user