Bug 191474. Make GTK paint in one pass, pass a region to paint up from GTK to the view manager. r+sr=blizzard

This commit is contained in:
roc+%cs.cmu.edu 2003-03-25 02:58:10 +00:00
parent 7636f6f4e2
commit d6fd7c0ac4
18 changed files with 285 additions and 315 deletions

View File

@ -110,7 +110,8 @@ class NS_GFX nsRegion
public:
nsRegion ();
nsRegion () { Init(); }
nsRegion (const nsRectFast& aRect) { Init(); Copy(aRect); }
~nsRegion () { SetToElements (0); }
nsRegion& Copy (const nsRegion& aRegion);
@ -173,14 +174,13 @@ public:
}
PRBool GetBoundRect (nsRect& aBound) const
nsRect GetBounds () const
{
aBound = mBoundRect;
return !mBoundRect.IsEmpty ();
return mBoundRect;
}
void Offset (PRInt32 aXOffset, PRInt32 aYOffset);
void Empty ()
void MoveBy (PRInt32 aXOffset, PRInt32 aYOffset);
void SetEmpty ()
{
SetToElements (0);
mBoundRect.SetRect (0, 0, 0, 0);
@ -197,6 +197,8 @@ private:
RgnRect mRectListHead;
nsRectFast mBoundRect;
void Init ();
void InsertBefore (RgnRect* aNewRect, RgnRect* aRelativeRect)
{
aNewRect->prev = aRelativeRect->prev;

View File

@ -411,7 +411,7 @@ void nsImageGTK::UpdateCachedImage()
}
}
mUpdateRegion.Empty();
mUpdateRegion.SetEmpty();
mPendingUpdate = PR_FALSE;
mFlags = nsImageUpdateFlags_kBitsChanged; // this should be 0'd out by Draw()
}

View File

@ -225,7 +225,7 @@ NS_IMETHODIMP nsRenderingContextGTK::LockDrawingSurface(PRInt32 aX, PRInt32 aY,
PushState();
return mSurface->Lock(aX, aY, aWidth, aHeight,
aBits, aStride, aWidthBytes, aFlags);
aBits, aStride, aWidthBytes, aFlags);
}
NS_IMETHODIMP nsRenderingContextGTK::UnlockDrawingSurface(void)
@ -415,22 +415,13 @@ NS_IMETHODIMP nsRenderingContextGTK::GetClipRect(nsRect &aRect, PRBool &aClipVal
}
#ifdef DEBUG
#undef TRACE_SET_CLIP
// #define TRACE_SET_CLIP
#endif
#ifdef TRACE_SET_CLIP
static char *
nsClipCombine_to_string(nsClipCombine aCombine)
{
#ifdef TRACE_SET_CLIP
printf("nsRenderingContextGTK::SetClipRect(x=%d,y=%d,w=%d,h=%d,%s)\n",
trect.x,
trect.y,
trect.width,
trect.height,
nsClipCombine_to_string(aCombine));
#endif // TRACE_SET_CLIP
switch(aCombine)
{
case nsClipCombine_kIntersect:
@ -793,8 +784,12 @@ NS_IMETHODIMP nsRenderingContextGTK::CreateDrawingSurface(const nsRect &aBounds,
if (surf)
{
NS_ADDREF(surf);
PushState();
mClipRegion = nsnull;
UpdateGC();
rv = surf->Init(mGC, aBounds.width, aBounds.height, aSurfFlags);
rv = surf->Init(mGC, aBounds.width, aBounds.height, aSurfFlags);
PRBool empty;
PopState(empty);
} else {
rv = NS_ERROR_FAILURE;
}
@ -877,7 +872,7 @@ NS_IMETHODIMP nsRenderingContextGTK::DrawPolyline(const nsPoint aPoints[], PRInt
g_return_val_if_fail(mSurface != NULL, NS_ERROR_FAILURE);
GdkPoint *pts = new GdkPoint[aNumPoints];
for (i = 0; i < aNumPoints; i++)
for (i = 0; i < aNumPoints; i++)
{
nsPoint p = aPoints[i];
mTranMatrix->TransformCoord(&p.x,&p.y);
@ -1023,13 +1018,13 @@ NS_IMETHODIMP nsRenderingContextGTK::DrawPolygon(const nsPoint aPoints[], PRInt3
g_return_val_if_fail(mSurface != NULL, NS_ERROR_FAILURE);
GdkPoint *pts = new GdkPoint[aNumPoints];
for (PRInt32 i = 0; i < aNumPoints; i++)
for (PRInt32 i = 0; i < aNumPoints; i++)
{
nsPoint p = aPoints[i];
mTranMatrix->TransformCoord(&p.x,&p.y);
pts[i].x = p.x;
mTranMatrix->TransformCoord(&p.x,&p.y);
pts[i].x = p.x;
pts[i].y = p.y;
}
}
UpdateGC();
@ -1046,13 +1041,13 @@ NS_IMETHODIMP nsRenderingContextGTK::FillPolygon(const nsPoint aPoints[], PRInt3
g_return_val_if_fail(mSurface != NULL, NS_ERROR_FAILURE);
GdkPoint *pts = new GdkPoint[aNumPoints];
for (PRInt32 i = 0; i < aNumPoints; i++)
for (PRInt32 i = 0; i < aNumPoints; i++)
{
nsPoint p = aPoints[i];
mTranMatrix->TransformCoord(&p.x,&p.y);
pts[i].x = p.x;
mTranMatrix->TransformCoord(&p.x,&p.y);
pts[i].x = p.x;
pts[i].y = p.y;
}
}
UpdateGC();

View File

@ -152,10 +152,7 @@ inline void nsRegion::RgnRect::operator delete (void* aRect, size_t)
gRectPool.Free (NS_STATIC_CAST (RgnRect*, aRect));
}
nsRegion::nsRegion ()
void nsRegion::Init()
{
mRectListHead.prev = mRectListHead.next = &mRectListHead;
mCurRect = &mRectListHead;
@ -477,7 +474,7 @@ nsRegion& nsRegion::Copy (const nsRegion& aRegion)
return *this;
if (aRegion.mRectCount == 0)
Empty ();
SetEmpty ();
else
{
SetToElements (aRegion.mRectCount);
@ -504,7 +501,7 @@ nsRegion& nsRegion::Copy (const nsRegion& aRegion)
nsRegion& nsRegion::Copy (const nsRectFast& aRect)
{
if (aRect.IsEmpty ())
Empty ();
SetEmpty ();
else
{
SetToElements (1);
@ -522,7 +519,7 @@ nsRegion& nsRegion::And (const nsRegion& aRgn1, const nsRegion& aRgn2)
Copy (aRgn1);
else
if (aRgn1.mRectCount == 0 || aRgn2.mRectCount == 0) // If either region is empty then result is empty
Empty ();
SetEmpty ();
else
{
nsRectFast TmpRect;
@ -534,7 +531,7 @@ nsRegion& nsRegion::And (const nsRegion& aRgn1, const nsRegion& aRgn2)
} else
{
if (!aRgn1.mBoundRect.Intersects (aRgn2.mBoundRect)) // Regions do not intersect
Empty ();
SetEmpty ();
else
{
// Region is simple rectangle and it fully overlays other region
@ -624,7 +621,7 @@ nsRegion& nsRegion::And (const nsRegion& aRegion, const nsRectFast& aRect)
{
// If either region or rectangle is empty then result is empty
if (aRegion.mRectCount == 0 || aRect.IsEmpty ())
Empty ();
SetEmpty ();
else // Intersect region with rectangle
{
nsRectFast TmpRect;
@ -636,7 +633,7 @@ nsRegion& nsRegion::And (const nsRegion& aRegion, const nsRectFast& aRect)
} else // Intersect complex region with rectangle
{
if (!aRect.Intersects (aRegion.mBoundRect)) // Rectangle does not intersect region
Empty ();
SetEmpty ();
else
{
if (aRect.Contains (aRegion.mBoundRect)) // Rectangle fully overlays region
@ -747,7 +744,7 @@ nsRegion& nsRegion::Or (const nsRegion& aRegion, const nsRectFast& aRect)
nsRegion& nsRegion::Xor (const nsRegion& aRgn1, const nsRegion& aRgn2)
{
if (&aRgn1 == &aRgn2) // Xor with self
Empty ();
SetEmpty ();
else
if (aRgn1.mRectCount == 0) // Region empty. Result is equal to other region
Copy (aRgn2);
@ -832,10 +829,10 @@ nsRegion& nsRegion::Xor (const nsRegion& aRegion, const nsRectFast& aRect)
nsRegion& nsRegion::Sub (const nsRegion& aRgn1, const nsRegion& aRgn2)
{
if (&aRgn1 == &aRgn2) // Sub from self
Empty ();
SetEmpty ();
else
if (aRgn1.mRectCount == 0) // If source is empty then result is empty, too
Empty ();
SetEmpty ();
else
if (aRgn2.mRectCount == 0) // Nothing to subtract
Copy (aRgn1);
@ -857,7 +854,7 @@ nsRegion& nsRegion::Sub (const nsRegion& aRgn1, const nsRegion& aRgn2)
nsRegion& nsRegion::Sub (const nsRegion& aRegion, const nsRectFast& aRect)
{
if (aRegion.mRectCount == 0) // If source is empty then result is empty, too
Empty ();
SetEmpty ();
else
if (aRect.IsEmpty ()) // Nothing to subtract
Copy (aRegion);
@ -868,7 +865,7 @@ nsRegion& nsRegion::Sub (const nsRegion& aRegion, const nsRectFast& aRect)
else
{
if (aRect.Contains (aRegion.mBoundRect)) // Rectangle fully overlays region
Empty ();
SetEmpty ();
else
{
aRegion.SubRect (aRect, *this);
@ -891,7 +888,7 @@ void nsRegion::SubRegion (const nsRegion& aRegion, nsRegion& aResult) const
if (aRegion.mRectCount == 1) // Subtract simple rectangle
{
if (aRegion.mBoundRect.Contains (mBoundRect))
aResult.Empty ();
aResult.SetEmpty ();
else
SubRect (*aRegion.mRectListHead.next, aResult);
} else
@ -1127,7 +1124,7 @@ PRBool nsRegion::IsEqual (const nsRegion& aRegion) const
}
void nsRegion::Offset (PRInt32 aXOffset, PRInt32 aYOffset)
void nsRegion::MoveBy (PRInt32 aXOffset, PRInt32 aYOffset)
{
if (aXOffset || aYOffset)
{

View File

@ -24,7 +24,7 @@
nsresult nsRegionImpl::Init (void)
{
mRegion.Empty ();
mRegion.SetEmpty ();
return NS_OK;
}
@ -85,8 +85,7 @@ PRBool nsRegionImpl::IsEqual (const nsIRegion &aRegion)
void nsRegionImpl::GetBoundingBox (PRInt32 *aX, PRInt32 *aY, PRInt32 *aWidth, PRInt32 *aHeight)
{
nsRect BoundRect;
mRegion.GetBoundRect (BoundRect);
nsRect BoundRect = mRegion.GetBounds();
*aX = BoundRect.x;
*aY = BoundRect.y;
*aWidth = BoundRect.width;
@ -95,7 +94,7 @@ void nsRegionImpl::GetBoundingBox (PRInt32 *aX, PRInt32 *aY, PRInt32 *aWidth, PR
void nsRegionImpl::Offset (PRInt32 aXOffset, PRInt32 aYOffset)
{
mRegion.Offset (aXOffset, aYOffset);
mRegion.MoveBy (aXOffset, aYOffset);
}
PRBool nsRegionImpl::ContainsRect (PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight)

View File

@ -627,19 +627,66 @@ PRBool DoDoubleBuffering(void)
return doDoublebuffering;
}
static void ConvertNativeRegionToAppRegion(nsIRegion* aIn, nsRegion* aOut,
nsIDeviceContext* context)
{
nsRegionRectSet* rects = nsnull;
aIn->GetRects(&rects);
if (!rects)
return;
float p2t;
context->GetDevUnitsToAppUnits(p2t);
PRUint32 i;
for (i = 0; i < rects->mNumRects; i++) {
const nsRegionRect& inR = rects->mRects[i];
nsRect outR(inR.x, inR.y, inR.width, inR.height);
outR.ScaleRoundOut(p2t);
aOut->Or(*aOut, outR);
}
aIn->FreeRects(rects);
}
/**
aRegion is given in device coordinates!!
*/
void nsViewManager::Refresh(nsView *aView, nsIRenderingContext *aContext, nsIRegion *aRegion, PRUint32 aUpdateFlags)
void nsViewManager::Refresh(nsView *aView, nsIRenderingContext *aContext,
nsIRegion *aRegion, PRUint32 aUpdateFlags)
{
nsCOMPtr<nsIRenderingContext> localcx;
nsDrawingSurface ds = nsnull;
NS_ASSERTION(aRegion != nsnull, "Null aRegion");
if (PR_FALSE == mRefreshEnabled)
return;
nsRect viewRect;
aView->GetDimensions(viewRect);
// move the view rect into widget pixel coordinates
nsRect viewRectInPixels = viewRect;
viewRectInPixels.MoveTo(0, 0);
float t2p;
mContext->GetAppUnitsToDevUnits(t2p);
viewRectInPixels.ScaleRoundOut(t2p);
// Get the damaged area into app coordinates (twips), but the origin is
// still the widget origin
nsRegion damageRegion;
ConvertNativeRegionToAppRegion(aRegion, &damageRegion, mContext);
damageRegion.MoveBy(viewRect.x, viewRect.y);
// Clip it to the view; shouldn't be necessary, but do it for sanity
damageRegion.And(damageRegion, viewRect);
if (damageRegion.IsEmpty()) {
#ifdef DEBUG_roc
nsRect damageRect = damageRegion.GetBounds();
printf("XXX Damage rectangle (%d,%d,%d,%d) does not intersect the widget's view (%d,%d,%d,%d)!\n",
damageRect.x, damageRect.y, damageRect.width, damageRect.height,
viewRect.x, viewRect.y, viewRect.width, viewRect.height);
#endif
return;
}
#ifdef NS_VM_PERF_METRICS
MOZ_TIMER_DEBUGLOG(("Reset nsViewManager::Refresh(region), this=%p\n", this));
MOZ_TIMER_RESET(mWatch);
@ -648,12 +695,11 @@ void nsViewManager::Refresh(nsView *aView, nsIRenderingContext *aContext, nsIReg
MOZ_TIMER_START(mWatch);
#endif
NS_ASSERTION(!(PR_TRUE == mPainting), "recursive painting not permitted");
NS_ASSERTION(!mPainting, "recursive painting not permitted");
if (mPainting) {
mRecursiveRefreshPending = PR_TRUE;
return;
}
mPainting = PR_TRUE;
//printf("refreshing region...\n");
@ -662,9 +708,8 @@ void nsViewManager::Refresh(nsView *aView, nsIRenderingContext *aContext, nsIReg
if (mTransCnt > 0)
aUpdateFlags |= NS_VMREFRESH_DOUBLE_BUFFER;
if (!DoDoubleBuffering()) {
if (!DoDoubleBuffering())
aUpdateFlags &= ~NS_VMREFRESH_DOUBLE_BUFFER;
}
// check if the rendering context wants double-buffering or not
if (aContext) {
@ -679,6 +724,9 @@ void nsViewManager::Refresh(nsView *aView, nsIRenderingContext *aContext, nsIReg
aUpdateFlags &= ~NS_VMREFRESH_DOUBLE_BUFFER;
}
nsCOMPtr<nsIRenderingContext> localcx;
nsDrawingSurface ds = nsnull;
if (nsnull == aContext)
{
localcx = getter_AddRefs(CreateRenderingContext(*aView));
@ -706,76 +754,48 @@ void nsViewManager::Refresh(nsView *aView, nsIRenderingContext *aContext, nsIReg
}
}
nsRect damageRectInPixels;
aRegion->GetBoundingBox(&damageRectInPixels.x, &damageRectInPixels.y,
&damageRectInPixels.width, &damageRectInPixels.height);
nsRect damageRect = damageRegion.GetBounds();
nsRect damageRectInPixels = damageRect;
damageRectInPixels.ScaleRoundOut(t2p);
if (aUpdateFlags & NS_VMREFRESH_DOUBLE_BUFFER)
{
nsRect maxWidgetSize;
GetMaxWidgetBounds(maxWidgetSize);
if NS_FAILED(localcx->GetBackbuffer(nsRect(0, 0, damageRectInPixels.width, damageRectInPixels.height), maxWidgetSize, ds)) {
nsRect r(0, 0, damageRectInPixels.width, damageRectInPixels.height);
if (NS_FAILED(localcx->GetBackbuffer(r, maxWidgetSize, ds))) {
//Failed to get backbuffer so turn off double buffering
aUpdateFlags &= ~NS_VMREFRESH_DOUBLE_BUFFER;
}
}
nsRect viewRect;
aView->GetDimensions(viewRect);
if ((aUpdateFlags & NS_VMREFRESH_DOUBLE_BUFFER) && ds) {
// backbuffer's (0,0) is mapped to damageRect.x, damageRect.y
localcx->Translate(-damageRect.x, -damageRect.y);
aRegion->Offset(-damageRectInPixels.x, -damageRectInPixels.y);
}
nsRect damageRect;
nsRect paintRect;
float p2t;
mContext->GetDevUnitsToAppUnits(p2t);
damageRect.x = NSToIntRound(damageRectInPixels.x * p2t);
damageRect.y = NSToIntRound(damageRectInPixels.y * p2t);
damageRect.width = NSToIntRound(damageRectInPixels.width * p2t);
damageRect.height = NSToIntRound(damageRectInPixels.height * p2t);
// move the view rect into widget coordinates
viewRect.x = 0;
viewRect.y = 0;
PRBool result;
// Note that nsIRenderingContext::SetClipRegion always works in pixel coordinates,
// and nsIRenderingContext::SetClipRect always works in app coordinates. Stupid huh?
// Also, SetClipRegion doesn't subject its argument to the current transform, but
// SetClipRect does.
localcx->SetClipRegion(*aRegion, nsClipCombine_kReplace, result);
localcx->SetClipRect(damageRect, nsClipCombine_kIntersect, result);
if (paintRect.IntersectRect(damageRect, viewRect)) {
// painting will be done in aView's coordinates, so shift them back to widget coordinates
localcx->Translate(-viewRect.x, -viewRect.y);
RenderViews(aView, *localcx, damageRegion, result);
localcx->Translate(viewRect.x, viewRect.y);
if ((aUpdateFlags & NS_VMREFRESH_DOUBLE_BUFFER) && ds) {
// backbuffer's (0,0) is mapped to damageRect.x, damageRect.y
localcx->Translate(-damageRect.x, -damageRect.y);
aRegion->Offset(-damageRectInPixels.x, -damageRectInPixels.y);
}
PRBool result;
// Note that nsIRenderingContext::SetClipRegion always works in pixel coordinates,
// and nsIRenderingContext::SetClipRect always works in app coordinates. Stupid huh?
if ((aUpdateFlags & NS_VMREFRESH_DOUBLE_BUFFER) && ds) {
// Setup the region relative to the destination's coordinates
aRegion->Offset(damageRectInPixels.x, damageRectInPixels.y);
localcx->SetClipRegion(*aRegion, nsClipCombine_kReplace, result);
localcx->SetClipRect(paintRect, nsClipCombine_kIntersect, result);
// pass in a damage rectangle in aView's coordinates.
nsRect r = paintRect;
nsRect dims;
aView->GetDimensions(dims);
r.x += dims.x;
r.y += dims.y;
// painting will be done in aView's coordinates, so shift them back to widget coordinates
localcx->Translate(-dims.x, -dims.y);
RenderViews(aView, *localcx, r, result);
localcx->Translate(dims.x, dims.y);
if ((aUpdateFlags & NS_VMREFRESH_DOUBLE_BUFFER) && ds) {
// Setup the region relative to the destination's coordinates
aRegion->Offset(damageRectInPixels.x, damageRectInPixels.y);
localcx->SetClipRegion(*aRegion, nsClipCombine_kReplace, result);
localcx->Translate(damageRect.x, damageRect.y);
localcx->SetClipRect(paintRect, nsClipCombine_kIntersect, result);
localcx->CopyOffScreenBits(ds, 0, 0, damageRectInPixels, NS_COPYBITS_USE_SOURCE_CLIP_REGION);
}
} else {
#ifdef DEBUG_roc
printf("XXX Damage rectangle (%d,%d,%d,%d) does not intersect the widget's view (%d,%d,%d,%d)!\n",
damageRect.x, damageRect.y, damageRect.width, damageRect.height,
viewRect.x, viewRect.y, viewRect.width, viewRect.height);
#endif
localcx->Translate(damageRect.x, damageRect.y);
localcx->SetClipRect(damageRect, nsClipCombine_kIntersect, result);
localcx->CopyOffScreenBits(ds, 0, 0, damageRectInPixels, NS_COPYBITS_USE_SOURCE_CLIP_REGION);
}
mPainting = PR_FALSE;
@ -1036,7 +1056,7 @@ void nsViewManager::AddCoveringWidgetsToOpaqueRegion(nsRegion &aRgn, nsIDeviceCo
//
// NB: we must NOT add widgets that correspond to floating views!
// We may be required to paint behind them
aRgn.Empty();
aRgn.SetEmpty();
nsCOMPtr<nsIWidget> widget;
GetWidgetForView(aRootView, getter_AddRefs(widget));
@ -1090,16 +1110,17 @@ void nsViewManager::AddCoveringWidgetsToOpaqueRegion(nsRegion &aRgn, nsIDeviceCo
} while (NS_SUCCEEDED(children->Next()));
}
void nsViewManager::RenderViews(nsView *aRootView, nsIRenderingContext& aRC, const nsRect& aRect, PRBool &aResult)
void nsViewManager::RenderViews(nsView *aRootView, nsIRenderingContext& aRC,
const nsRegion& aRegion, PRBool &aResult)
{
BuildDisplayList(aRootView, aRect, PR_FALSE, PR_FALSE);
BuildDisplayList(aRootView, aRegion.GetBounds(), PR_FALSE, PR_FALSE);
PRBool anyRendered;
nsRect finalTransparentRect;
nsRegion opaqueRgn;
AddCoveringWidgetsToOpaqueRegion(opaqueRgn, mContext, aRootView);
OptimizeDisplayList(aRect, finalTransparentRect, opaqueRgn);
OptimizeDisplayList(aRegion, finalTransparentRect, opaqueRgn);
#ifdef DEBUG_roc
// ShowDisplayList(mDisplayListCount);
@ -1123,6 +1144,12 @@ void nsViewManager::RenderViews(nsView *aRootView, nsIRenderingContext& aRC, con
PRInt32 index = 0;
nsRect fakeClipRect;
OptimizeDisplayListClipping(PR_FALSE, fakeClipRect, index, anyRendered);
#ifdef DEBUG_roc
printf("*** mTranslucentArea=%d,%d,%d,%d\n", mTranslucentArea.x, mTranslucentArea.y,
mTranslucentArea.width, mTranslucentArea.height);
printf("*** gOffscreenSize=%d,%d\n", gOffScreenSize.width, gOffScreenSize.height);
#endif
// We keep a list of all the rendering contexts whose clip rects
// need to be updated.
@ -1133,7 +1160,7 @@ void nsViewManager::RenderViews(nsView *aRootView, nsIRenderingContext& aRC, con
// create blending buffers, if necessary.
if (mTranslucentViewCount > 0) {
nsresult rv = CreateBlendingBuffers(aRC);
NS_ASSERTION((rv == NS_OK), "not enough memory to blend");
NS_ASSERTION(NS_SUCCEEDED(rv), "not enough memory to blend");
if (NS_FAILED(rv)) {
// fall back by just rendering with transparency.
mTranslucentViewCount = 0;
@ -1155,8 +1182,8 @@ void nsViewManager::RenderViews(nsView *aRootView, nsIRenderingContext& aRC, con
mOffScreenCX->FillRect(nsRect(0, 0, gOffScreenSize.width, gOffScreenSize.height));
}
// DEBUGGING: fill in complete offscreen image in green, to see if we've got a blending bug.
//mOffScreenCX->SetColor(NS_RGB(0, 255, 0));
//mOffScreenCX->FillRect(nsRect(0, 0, gOffScreenSize.width, gOffScreenSize.height));
// mOffScreenCX->SetColor(NS_RGB(0, 255, 0));
// mOffScreenCX->FillRect(nsRect(0, 0, gOffScreenSize.width, gOffScreenSize.height));
}
// draw all views in the display list, from back to front.
@ -1192,13 +1219,13 @@ void nsViewManager::RenderViews(nsView *aRootView, nsIRenderingContext& aRC, con
// Must flush back when no clipping is in effect.
if (mTranslucentViewCount > 0) {
// DEBUG: is this getting through?
// mOffScreenCX->SetColor(NS_RGB(0, 0, 0));
// mOffScreenCX->DrawRect(nsRect(0, 0, mTranslucentArea.width, mTranslucentArea.height));
// mOffScreenCX->SetColor(NS_RGB(177, 177, 0));
// mOffScreenCX->FillRect(nsRect(1, 1, mTranslucentArea.width-2, mTranslucentArea.height-2));
aRC.CopyOffScreenBits(gOffScreen, 0, 0, mTranslucentArea,
NS_COPYBITS_XFORM_DEST_VALUES |
NS_COPYBITS_TO_BACK_BUFFER);
// DEBUG: what rectangle are we blitting?
// aRC.SetColor(NS_RGB(0, 0, 0));
// aRC.SetColor(NS_RGB(0, 177, 177));
// aRC.DrawRect(mTranslucentArea);
}
@ -1278,6 +1305,7 @@ void nsViewManager::RenderDisplayListElement(DisplayListElement2* element, nsIRe
if (NS_FAILED(rv)) {
NS_WARNING("Blend failed!");
// let's paint SOMETHING. Paint opaquely
damageRect.MoveBy(-viewX, -viewY);
PaintView(view, *mOffScreenCX, viewX, viewY, damageRect);
}
}
@ -1750,75 +1778,63 @@ NS_IMETHODIMP nsViewManager::DispatchEvent(nsGUIEvent *aEvent, nsEventStatus *aS
{
nsView *view = nsView::GetViewFor(aEvent->widget);
if (nsnull != view)
{
// Do an immediate refresh
if (nsnull != mContext)
{
// The rect is in device units, and it's in the coordinate space of its
// associated window.
nsRect& damrect = *((nsPaintEvent*)aEvent)->rect;
if (!view || !mContext)
break;
if (damrect.width > 0 && damrect.height > 0)
{
PRUint32 updateFlags = NS_VMREFRESH_DOUBLE_BUFFER;
PRBool doDefault = PR_TRUE;
// The rect is in device units, and it's in the coordinate space of its
// associated window.
nsCOMPtr<nsIRegion> region = ((nsPaintEvent*)aEvent)->region;
if (!region) {
if (NS_FAILED(CreateRegion(getter_AddRefs(region))))
break;
// printf("refreshing: view: %x, %d, %d, %d, %d\n", view, damrect.x, damrect.y, damrect.width, damrect.height);
// Refresh the view
if (mRefreshEnabled) {
nsCOMPtr<nsIRegion> rgn;
nsresult rv = CreateRegion(getter_AddRefs(rgn));
if (NS_SUCCEEDED(rv)) {
// Eventually we would like the platform paint event to include a region
// we can use. This could improve paint performance when the invalid area
// is more complicated than a rectangle. Right now the event's region field
// just contains garbage on some platforms so we can't trust it at all.
// When that gets fixed, we can just change the code right here.
rgn->SetTo(damrect.x, damrect.y, damrect.width, damrect.height);
Refresh(view, ((nsPaintEvent*)aEvent)->renderingContext, rgn, updateFlags);
doDefault = PR_FALSE;
}
}
const nsRect& damrect = *((nsPaintEvent*)aEvent)->rect;
region->SetTo(damrect.x, damrect.y, damrect.width, damrect.height);
}
if (region->IsEmpty())
break;
// since we got an NS_PAINT event, we need to
// draw something so we don't get blank areas.
if (doDefault) {
float p2t;
mContext->GetDevUnitsToAppUnits(p2t);
damrect.ScaleRoundOut(p2t);
DefaultRefresh(view, &damrect);
// Clients like the editor can trigger multiple
// reflows during what the user perceives as a single
// edit operation, so it disables view manager
// refreshing until the edit operation is complete
// so that users don't see the intermediate steps.
//
// Unfortunately some of these reflows can trigger
// nsScrollPortView and nsScrollingView Scroll() calls
// which in most cases force an immediate BitBlt and
// synchronous paint to happen even if the view manager's
// refresh is disabled. (Bug 97674)
//
// Calling UpdateView() here, is neccessary to add
// the exposed region specified in the synchronous paint
// event to the view's damaged region so that it gets
// painted properly when refresh is enabled.
//
// Note that calling UpdateView() here was deemed
// to have the least impact on performance, since the
// other alternative was to make Scroll() post an
// async paint event for the *entire* ScrollPort or
// ScrollingView's viewable area. (See bug 97674 for this
// alternate patch.)
UpdateView(view, damrect, NS_VMREFRESH_NO_SYNC);
}
}
}
*aStatus = nsEventStatus_eConsumeNoDefault;
}
// Refresh the view
if (mRefreshEnabled) {
Refresh(view, ((nsPaintEvent*)aEvent)->renderingContext, region,
NS_VMREFRESH_DOUBLE_BUFFER);
} else {
// since we got an NS_PAINT event, we need to
// draw something so we don't get blank areas.
nsRect damRect;
region->GetBoundingBox(&damRect.x, &damRect.y, &damRect.width, &damRect.height);
float p2t;
mContext->GetDevUnitsToAppUnits(p2t);
damRect.ScaleRoundOut(p2t);
DefaultRefresh(view, &damRect);
// Clients like the editor can trigger multiple
// reflows during what the user perceives as a single
// edit operation, so it disables view manager
// refreshing until the edit operation is complete
// so that users don't see the intermediate steps.
//
// Unfortunately some of these reflows can trigger
// nsScrollPortView and nsScrollingView Scroll() calls
// which in most cases force an immediate BitBlt and
// synchronous paint to happen even if the view manager's
// refresh is disabled. (Bug 97674)
//
// Calling UpdateView() here, is neccessary to add
// the exposed region specified in the synchronous paint
// event to the view's damaged region so that it gets
// painted properly when refresh is enabled.
//
// Note that calling UpdateView() here was deemed
// to have the least impact on performance, since the
// other alternative was to make Scroll() post an
// async paint event for the *entire* ScrollPort or
// ScrollingView's viewable area. (See bug 97674 for this
// alternate patch.)
UpdateView(view, damRect, NS_VMREFRESH_NO_SYNC);
}
break;
}
@ -2619,7 +2635,7 @@ NS_IMETHODIMP nsViewManager::SetViewChildClipRegion(nsIView *aView, const nsRegi
// and it is set to no more than the bounds of the view.
if (aRegion != nsnull) {
newClipFlag = PR_TRUE;
aRegion->GetBoundRect(newClipRect);
newClipRect = aRegion->GetBounds();
if (IsClipView(view)) {
nsRect dims;
view->GetDimensions(dims);
@ -2801,7 +2817,7 @@ PRBool nsViewManager::CanScrollWithBitBlt(nsView* aView)
v->ConvertToParentCoords(&deltaX, &deltaY);
v = v->GetParent();
}
opaqueRegion.Offset(-deltaX, -deltaY);
opaqueRegion.MoveBy(-deltaX, -deltaY);
}
}
@ -2811,7 +2827,7 @@ PRBool nsViewManager::CanScrollWithBitBlt(nsView* aView)
// (Of course it's possible that aView's parent is actually in front of aView (if aView has a negative
// z-index) but if so, this code still does the right thing. Yay for the display list based approach!)
OptimizeDisplayList(r, finalTransparentRect, opaqueRegion);
OptimizeDisplayList(nsRegion(r), finalTransparentRect, opaqueRegion);
PRBool anyUnscrolledViews = PR_FALSE;
PRBool anyUnblittableViews = PR_FALSE;
@ -3287,7 +3303,7 @@ NS_IMETHODIMP nsViewManager::Display(nsIView* aView, nscoord aX, nscoord aY, con
// Paint the view. The clipping rect was set above set don't clip again.
//aView->Paint(*localcx, trect, NS_VIEW_FLAG_CLIP_SET, result);
RenderViews(view, *localcx, trect, result);
RenderViews(view, *localcx, nsRegion(trect), result);
NS_RELEASE(localcx);
@ -3662,23 +3678,22 @@ void nsViewManager::ReapplyClipInstructions(PRBool aHaveClip, nsRect& aClipRect,
Usually this will be empty, but nothing really prevents someone
from creating a set of views that are (for example) all transparent.
*/
nsresult nsViewManager::OptimizeDisplayList(const nsRect& aDamageRect, nsRect& aFinalTransparentRect,
nsresult nsViewManager::OptimizeDisplayList(const nsRegion& aDamageRegion,
nsRect& aFinalTransparentRect,
nsRegion &aOpaqueRegion)
{
aFinalTransparentRect = aDamageRect;
PRInt32 count = mDisplayListCount;
for (PRInt32 i = count - 1; i >= 0; i--) {
DisplayListElement2* element = NS_STATIC_CAST(DisplayListElement2*, mDisplayList.ElementAt(i));
if (element->mFlags & VIEW_RENDERED) {
nsRegion tmpRgn;
tmpRgn.Copy(element->mBounds);
tmpRgn.Sub(tmpRgn, aOpaqueRegion);
tmpRgn.Sub(element->mBounds, aOpaqueRegion);
tmpRgn.And(tmpRgn, aDamageRegion);
if (tmpRgn.IsEmpty()) {
element->mFlags &= ~VIEW_RENDERED;
} else {
tmpRgn.GetBoundRect(element->mBounds);
element->mBounds = tmpRgn.GetBounds();
// a view is opaque if it is neither transparent nor transluscent
if (!(element->mFlags & (VIEW_TRANSPARENT | VIEW_TRANSLUCENT))) {
@ -3689,9 +3704,8 @@ nsresult nsViewManager::OptimizeDisplayList(const nsRect& aDamageRect, nsRect& a
}
nsRegion tmpRgn;
tmpRgn.Copy(aDamageRect);
tmpRgn.Sub(tmpRgn, aOpaqueRegion);
tmpRgn.GetBoundRect(aFinalTransparentRect);
tmpRgn.Sub(aDamageRegion, aOpaqueRegion);
aFinalTransparentRect = tmpRgn.GetBounds();
return NS_OK;
}

View File

@ -252,7 +252,7 @@ private:
void Refresh(nsView *aView, nsIRenderingContext *aContext,
nsIRegion *region, PRUint32 aUpdateFlags);
void DefaultRefresh(nsView* aView, const nsRect* aRect);
void RenderViews(nsView *aRootView, nsIRenderingContext& aRC, const nsRect& aRect,
void RenderViews(nsView *aRootView, nsIRenderingContext& aRC, const nsRegion& aRegion,
PRBool &aResult);
void RenderDisplayListElement(DisplayListElement2* element, nsIRenderingContext &aRC);
@ -276,7 +276,8 @@ private:
PRBool AddToDisplayList(nsView *aView, DisplayZTreeNode* &aParent, nsRect &aClipRect,
nsRect& aDirtyRect, PRUint32 aFlags, nscoord aAbsX, nscoord aAbsY, PRBool aAssumeIntersection);
void ReapplyClipInstructions(PRBool aHaveClip, nsRect& aClipRect, PRInt32& aIndex);
nsresult OptimizeDisplayList(const nsRect& aDamageRect, nsRect& aFinalTransparentRect, nsRegion& aOpaqueRgn);
nsresult OptimizeDisplayList(const nsRegion& aDirtyRegion,
nsRect& aFinalTransparentRect, nsRegion& aOpaqueRgn);
// Remove redundant PUSH/POP_CLIP pairs.
void ComputeViewOffset(nsView *aView, nsPoint *aOrigin);

View File

@ -2645,6 +2645,7 @@ PRBool nsWindow::OnPaint(nsRect &r)
nsPaintEvent event;
InitEvent(event, NS_PAINT);
event.region = nsnull;
event.rect = &r;
event.eventStructType = NS_PAINT_EVENT;

View File

@ -1562,6 +1562,7 @@ nsChildView::UpdateWidget(nsRect& aRect, nsIRenderingContext* aContext)
paintEvent.nativeMsg = NULL;
paintEvent.renderingContext = aContext; // nsPaintEvent
paintEvent.rect = &aRect;
paintEvent.region = nsnull;
// offscreen drawing is pointless.
if (paintEvent.rect->x < 0)

View File

@ -156,7 +156,7 @@ nsGtkUtils::gdk_keyboard_get_modifiers()
nsGtkUtils::gdk_window_flash(GdkWindow * aGdkWindow,
unsigned int aTimes,
unsigned long aInterval,
GdkRectangle * aArea)
GdkRegion * aRegion)
{
gint x;
gint y;
@ -185,18 +185,8 @@ nsGtkUtils::gdk_window_flash(GdkWindow * aGdkWindow,
gdk_gc_set_function(gc,GDK_XOR);
gdk_gc_set_subwindow(gc,GDK_INCLUDE_INFERIORS);
/*
* If an area is given, use that. Notice how out of whack coordinates
* and dimentsions are not checked!!!
*/
if (aArea)
{
x += aArea->x;
y += aArea->y;
width = aArea->width;
height = aArea->height;
}
gdk_region_offset(aRegion, x, y);
gdk_gc_set_clip_region(gc, aRegion);
/*
* Need to do this twice so that the XOR effect can replace
@ -218,5 +208,7 @@ nsGtkUtils::gdk_window_flash(GdkWindow * aGdkWindow,
}
gdk_gc_destroy(gc);
gdk_region_offset(aRegion, -x, -y);
}
//////////////////////////////////////////////////////////////////

View File

@ -94,7 +94,7 @@ struct nsGtkUtils
static void gdk_window_flash(GdkWindow * aGdkWindow,
unsigned int aTimes,
unsigned long aInterval,
GdkRectangle * aArea);
GdkRegion * aArea);
};
#endif // __nsGtkEventHandler.h

View File

@ -792,71 +792,56 @@ nsWindow::UnqueueDraw ()
}
void
nsWindow::DoPaint (PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight,
nsIRegion *aClipRegion)
nsWindow::DoPaint (nsIRegion *aClipRegion)
{
//Don't dispatch paint event if widget's height or width is 0
if ((mBounds.width == 0) || (mBounds.height == 0)) {
return;
}
if (!mEventCallback)
return;
if (mEventCallback) {
nsPaintEvent event;
nsRect rect(aX, aY, aWidth, aHeight);
nsPaintEvent event;
event.message = NS_PAINT;
event.widget = (nsWidget *)this;
event.eventStructType = NS_PAINT_EVENT;
event.point.x = aX;
event.point.y = aY;
event.time = GDK_CURRENT_TIME; // No time in EXPOSE events
event.rect = &rect;
event.region = nsnull;
event.renderingContext = GetRenderingContext();
if (event.renderingContext) {
event.message = NS_PAINT;
event.widget = (nsWidget *)this;
event.eventStructType = NS_PAINT_EVENT;
event.point.x = 0;
event.point.y = 0;
event.time = GDK_CURRENT_TIME; // No time in EXPOSE events
nsRect boundsRect;
aClipRegion->GetBoundingBox(&boundsRect.x, &boundsRect.y, &boundsRect.width, &boundsRect.height);
event.rect = &boundsRect;
event.region = aClipRegion;
// Don't paint anything if our window isn't visible.
if (!mSuperWin || mSuperWin->visibility == GDK_VISIBILITY_FULLY_OBSCURED)
return;
event.renderingContext = GetRenderingContext();
if (!event.renderingContext)
return;
#ifdef DEBUG
if (WANT_PAINT_FLASHING)
{
GdkWindow *gw = GetRenderWindow(GTK_OBJECT(mSuperWin));
if (gw)
{
GdkRectangle ar;
GdkRectangle * area = (GdkRectangle*) NULL;
if (event.rect)
{
ar.x = event.rect->x;
ar.y = event.rect->y;
ar.width = event.rect->width;
ar.height = event.rect->height;
area = &ar;
}
nsGtkUtils::gdk_window_flash(gw,1,100000,area);
}
}
// Check the pref _before_ checking caps lock, because checking
// caps lock requires a server round-trip.
if (debug_GetCachedBoolPref("nglayout.debug.paint_dumping") && CAPS_LOCK_IS_ON)
debug_DumpPaintEvent(stdout, this, &event,
debug_GetName(GTK_OBJECT(mSuperWin)),
(PRInt32) debug_GetRenderXID(GTK_OBJECT(mSuperWin)));
#endif // DEBUG
DispatchWindowEvent(&event);
NS_RELEASE(event.renderingContext);
GdkWindow *gw = GetRenderWindow(GTK_OBJECT(mSuperWin));
if (WANT_PAINT_FLASHING && gw)
{
GdkRegion *region;
aClipRegion->GetNativeRegion(*(void**)&region);
nsGtkUtils::gdk_window_flash(gw,1,100000,region);
}
}
// Check the pref _before_ checking caps lock, because checking
// caps lock requires a server round-trip.
if (debug_GetCachedBoolPref("nglayout.debug.paint_dumping") && CAPS_LOCK_IS_ON)
debug_DumpPaintEvent(stdout, this, &event,
debug_GetName(GTK_OBJECT(mSuperWin)),
(PRInt32) debug_GetRenderXID(GTK_OBJECT(mSuperWin)));
#endif // DEBUG
DispatchWindowEvent(&event);
NS_RELEASE(event.renderingContext);
}
static NS_DEFINE_CID(kRegionCID, NS_REGION_CID);
NS_IMETHODIMP nsWindow::Update(void)
{
if (!mSuperWin) // XXX ???
@ -866,40 +851,16 @@ NS_IMETHODIMP nsWindow::Update(void)
UnqueueDraw();
if (!mUpdateArea->IsEmpty()) {
PRUint32 numRects;
mUpdateArea->GetNumRects(&numRects);
// if we have 1 or more than 10 rects, just paint the bounding box otherwise
// lets paint each rect by itself
if (numRects != 1 && numRects < 10) {
nsRegionRectSet *regionRectSet = nsnull;
if (NS_FAILED(mUpdateArea->GetRects(&regionRectSet)))
return NS_ERROR_FAILURE;
PRUint32 len;
PRUint32 i;
len = regionRectSet->mRectsLen;
for (i=0;i<len;++i) {
nsRegionRect *r = &(regionRectSet->mRects[i]);
DoPaint (r->x, r->y, r->width, r->height, mUpdateArea);
}
mUpdateArea->FreeRects(regionRectSet);
mUpdateArea->SetTo(0, 0, 0, 0);
return NS_OK;
} else {
PRInt32 x, y, w, h;
mUpdateArea->GetBoundingBox(&x, &y, &w, &h);
DoPaint (x, y, w, h, mUpdateArea);
// Watch out for updates occuring during DoPaint. We must clear
// mUpdateArea before we go into DoPaint.
nsCOMPtr<nsIRegion> updateArea = mUpdateArea;
mUpdateArea = do_CreateInstance(kRegionCID);
if (mUpdateArea) {
mUpdateArea->Init();
mUpdateArea->SetTo(0, 0, 0, 0);
}
DoPaint(updateArea);
} else {
// g_print("nsWidget::Update(this=%p): avoided update of empty area\n", this);
}

View File

@ -126,8 +126,7 @@ public:
void QueueDraw();
void UnqueueDraw();
void DoPaint(PRInt32 x, PRInt32 y, PRInt32 width, PRInt32 height,
nsIRegion *aClipRegion);
void DoPaint(nsIRegion *aClipRegion);
static gboolean UpdateIdle (gpointer data);
// get the toplevel window for this widget
virtual GtkWindow *GetTopLevelWindow(void);

View File

@ -82,6 +82,7 @@ nsCommonWidget::InitPaintEvent(nsPaintEvent &aEvent)
aEvent.eventStructType = NS_PAINT_EVENT;
aEvent.message = NS_PAINT;
aEvent.widget = NS_STATIC_CAST(nsIWidget *, this);
aEvent.region = nsnull;
}
void

View File

@ -1677,12 +1677,13 @@ void nsWindow::UpdateWidget(nsRect& aRect, nsIRenderingContext* aContext)
// initialize the paint event
nsPaintEvent paintEvent;
paintEvent.eventStructType = NS_PAINT_EVENT; // nsEvent
paintEvent.message = NS_PAINT;
paintEvent.widget = this; // nsGUIEvent
paintEvent.nativeMsg = NULL;
paintEvent.renderingContext = aContext; // nsPaintEvent
paintEvent.rect = &aRect;
paintEvent.eventStructType = NS_PAINT_EVENT; // nsEvent
paintEvent.message = NS_PAINT;
paintEvent.widget = this; // nsGUIEvent
paintEvent.nativeMsg = NULL;
paintEvent.renderingContext = aContext; // nsPaintEvent
paintEvent.rect = &aRect;
paintEvent.region = nsnull;
// draw the widget
StartDraw(aContext);

View File

@ -2788,6 +2788,7 @@ PRBool nsWindow::OnPaint()
rect.width = rcl.xRight - rcl.xLeft;
rect.height = rcl.yTop - rcl.yBottom;
event.rect = &rect;
event.region = nsnull;
event.eventStructType = NS_PAINT_EVENT;
#ifdef NS_DEBUG

View File

@ -849,6 +849,7 @@ void nsWindow::RawDrawFunc( PtWidget_t * pWidget, PhTile_t * damage )
pWin->InitEvent(pev, NS_PAINT);
pev.eventStructType = NS_PAINT_EVENT;
pev.region = nsnull;
pev.renderingContext = nsnull;
pev.renderingContext = pWin->GetRenderingContext();
for( dmg = new_damage; dmg; dmg = dmg->next ) {
@ -866,6 +867,7 @@ void nsWindow::RawDrawFunc( PtWidget_t * pWidget, PhTile_t * damage )
pev.point.x = nsDmg.x;
pev.point.y = nsDmg.y;
pev.rect = &nsDmg;
pev.region = nsnull;
if( pev.renderingContext ) {
nsIRegion *ClipRegion = pWin->GetRegion( );

View File

@ -5202,8 +5202,11 @@ PRBool nsWindow::OnPaint()
ps.rcPaint.top,
ps.rcPaint.right - ps.rcPaint.left,
ps.rcPaint.bottom - ps.rcPaint.top);
event.rect = &rect;
event.eventStructType = NS_PAINT_EVENT;
event.region = nsnull;
event.rect = &rect;
// Should probably pass in a real region here, using GetRandomRgn
// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/gdi/clipping_4q0e.asp
#ifdef NS_DEBUG
debug_DumpPaintEvent(stdout,