Skip to content

Commit

Permalink
Bug 563878. Part 12. Change the view observer interface and overhaul …
Browse files Browse the repository at this point in the history
…painting in view/. r=mats f=roc
  • Loading branch information
tnikkel committed Jul 19, 2010
1 parent 3317cb6 commit b364da1
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 65 deletions.
30 changes: 13 additions & 17 deletions layout/base/nsPresShell.cpp
Expand Up @@ -817,6 +817,7 @@ class PresShell : public nsIPresShell, public nsIViewObserver,
nsIView* aViewToPaint,
nsIWidget* aWidget,
const nsRegion& aDirtyRegion,
const nsIntRegion& aIntDirtyRegion,
PRBool aPaintDefaultBackground,
PRBool aWillSendDidPaint);
NS_IMETHOD HandleEvent(nsIView* aView,
Expand Down Expand Up @@ -5828,7 +5829,7 @@ static void DrawThebesLayer(ThebesLayer* aLayer,
if (NS_SUCCEEDED(rv)) {
rc->Init(devCtx, aContext);
nsIRenderingContext::AutoPushTranslation
push(rc, -params->mOffsetToWidget.x, -params->mOffsetToWidget.y);
push(rc, params->mOffsetToWidget.x, params->mOffsetToWidget.y);
nsLayoutUtils::PaintFrame(rc, frame, *params->mDirtyRegion,
params->mBackgroundColor,
nsLayoutUtils::PAINT_WIDGET_LAYERS);
Expand All @@ -5844,12 +5845,13 @@ static void DrawThebesLayer(ThebesLayer* aLayer,
}

NS_IMETHODIMP
PresShell::Paint(nsIView* aDisplayRoot,
nsIView* aViewToPaint,
nsIWidget* aWidgetToPaint,
const nsRegion& aDirtyRegion,
PRBool aPaintDefaultBackground,
PRBool aWillSendDidPaint)
PresShell::Paint(nsIView* aDisplayRoot,
nsIView* aViewToPaint,
nsIWidget* aWidgetToPaint,
const nsRegion& aDirtyRegion,
const nsIntRegion& aIntDirtyRegion,
PRBool aPaintDefaultBackground,
PRBool aWillSendDidPaint)
{
#ifdef NS_FUNCTION_TIMER
NS_TIME_FUNCTION_DECLARE_DOCURL;
Expand Down Expand Up @@ -5893,34 +5895,28 @@ PresShell::Paint(nsIView* aDisplayRoot,
return NS_OK;
}

nsPoint offsetToRoot = aViewToPaint->GetOffsetTo(aDisplayRoot);
nsRegion dirtyRegion = aDirtyRegion;
dirtyRegion.MoveBy(offsetToRoot);

if (frame) {
// Defer invalidates that are triggered during painting, and discard
// invalidates of areas that are already being repainted.
frame->BeginDeferringInvalidatesForDisplayRoot(dirtyRegion);
frame->BeginDeferringInvalidatesForDisplayRoot(aDirtyRegion);
}

LayerManager* layerManager = aWidgetToPaint->GetLayerManager();
NS_ASSERTION(layerManager, "Must be in paint event");

layerManager->BeginTransaction();
nsRefPtr<ThebesLayer> root = layerManager->CreateThebesLayer();
nsIntRect dirtyRect = aDirtyRegion.GetBounds().
ToOutsidePixels(presContext->AppUnitsPerDevPixel());
if (root) {
root->SetVisibleRegion(dirtyRect);
root->SetVisibleRegion(aIntDirtyRegion);
layerManager->SetRoot(root);
}
if (!frame) {
bgcolor = NS_ComposeColors(bgcolor, mCanvasBackgroundColor);
}
PaintParams params =
{ frame,
offsetToRoot - aViewToPaint->ViewToWidgetOffset(),
&dirtyRegion,
aDisplayRoot->GetOffsetToWidget(aWidgetToPaint),
&aDirtyRegion,
bgcolor };
layerManager->EndTransaction(DrawThebesLayer, &params);

Expand Down
26 changes: 16 additions & 10 deletions view/public/nsIViewObserver.h
Expand Up @@ -47,8 +47,8 @@ class nsIRenderingContext;
class nsGUIEvent;

#define NS_IVIEWOBSERVER_IID \
{ 0x8e69db48, 0x9d01, 0x4c0a, \
{ 0xb9, 0xea, 0xa4, 0x4b, 0xc5, 0x89, 0xc8, 0x63 } }
{ 0xc5dfb460, 0x50fb, 0x483e, \
{ 0xb4, 0x22, 0x19, 0xb7, 0x20, 0x4f, 0xe2, 0xdc } }

class nsIViewObserver : public nsISupports
{
Expand All @@ -57,11 +57,16 @@ class nsIViewObserver : public nsISupports
NS_DECLARE_STATIC_IID_ACCESSOR(NS_IVIEWOBSERVER_IID)

/* called when the observer needs to paint. This paints the entire
* frame subtree rooted at the view, including frame subtrees from
* frame subtree rooted at aViewToPaint, including frame subtrees from
* subdocuments.
* @param aViewToPaint the view for the widget that is being painted
* @param aDirtyRegion the region to be painted, in the coordinates of
* @param aWidgetToPaint the widget that is being painted, the widget of
* aViewToPaint
* @param aDirtyRegion the region to be painted, in appunits of aDisplayRoot
* and relative to aDisplayRoot
* @param aIntDirtyRegion the region to be painted, in dev pixels, in the
* coordinates of aWidgetToPaint. This conveys the same information as
* aDirtyRegion but in a different format.
* @param aPaintDefaultBackground just paint the default background,
* don't try to paint any content. This is set when the observer
* needs to paint something, but the view tree is unstable, so it
Expand All @@ -71,12 +76,13 @@ class nsIViewObserver : public nsISupports
* which is to paint some default background color over the dirty region.
* @return error status
*/
NS_IMETHOD Paint(nsIView* aDisplayRoot,
nsIView* aViewToPaint,
nsIWidget* aWidgetToPaint,
const nsRegion& aDirtyRegion,
PRBool aPaintDefaultBackground,
PRBool aWillSendDidPaint) = 0;
NS_IMETHOD Paint(nsIView* aDisplayRoot,
nsIView* aViewToPaint,
nsIWidget* aWidgetToPaint,
const nsRegion& aDirtyRegion,
const nsIntRegion& aIntDirtyRegion,
PRBool aPaintDefaultBackground,
PRBool aWillSendDidPaint) = 0;

/* called when the observer needs to handle an event
* @param aView - where to start processing the event; the root view,
Expand Down
87 changes: 50 additions & 37 deletions view/src/nsViewManager.cpp
Expand Up @@ -341,19 +341,17 @@ NS_IMETHODIMP nsViewManager::FlushDelayedResize()
return NS_OK;
}

static nsRegion ConvertDeviceRegionToAppRegion(const nsIntRegion& aIn,
nsIDeviceContext* aContext)
// Convert aIn from being relative to and in appunits of aFromView, to being
// relative to and in appunits of aToView.
static nsRegion ConvertRegionBetweenViews(const nsRegion& aIn,
nsView* aFromView,
nsView* aToView)
{
PRInt32 p2a = aContext->AppUnitsPerDevPixel();

nsRegion out;
nsIntRegionRectIterator iter(aIn);
for (;;) {
const nsIntRect* r = iter.Next();
if (!r)
break;
out.Or(out, r->ToAppUnits(p2a));
}
nsRegion out = aIn;
out.MoveBy(aFromView->GetOffsetTo(aToView));
out = out.ConvertAppUnitsRoundOut(
aFromView->GetViewManager()->AppUnitsPerDevPixel(),
aToView->GetViewManager()->AppUnitsPerDevPixel());
return out;
}

Expand All @@ -380,20 +378,21 @@ void nsViewManager::Refresh(nsView *aView, nsIWidget *aWidget,
const nsIntRegion& aRegion,
PRUint32 aUpdateFlags)
{
NS_ASSERTION(aView == nsView::GetViewFor(aWidget), "view widget mismatch");
NS_ASSERTION(aView->GetViewManager() == this, "wrong view manager");

if (! IsRefreshEnabled())
return;

nsRect viewRect;
aView->GetDimensions(viewRect);
nsPoint vtowoffset = aView->ViewToWidgetOffset();

// damageRegion is the damaged area, in twips, relative to the view origin
nsRegion damageRegion = ConvertDeviceRegionToAppRegion(aRegion, mContext);
nsRegion damageRegion = aRegion.ToAppUnits(AppUnitsPerDevPixel());
// move region from widget coordinates into view coordinates
damageRegion.MoveBy(viewRect.TopLeft() - vtowoffset);
damageRegion.MoveBy(-aView->ViewToWidgetOffset());

if (damageRegion.IsEmpty()) {
#ifdef DEBUG_roc
nsRect viewRect;
aView->GetDimensions(viewRect);
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,
Expand All @@ -412,7 +411,7 @@ void nsViewManager::Refresh(nsView *aView, nsIWidget *aWidget,
nsAutoScriptBlocker scriptBlocker;
SetPainting(PR_TRUE);

RenderViews(aView, aWidget, damageRegion);
RenderViews(aView, aWidget, damageRegion, aRegion, PR_FALSE, PR_FALSE);

SetPainting(PR_FALSE);
}
Expand All @@ -427,19 +426,26 @@ void nsViewManager::Refresh(nsView *aView, nsIWidget *aWidget,

// aRC and aRegion are in view coordinates
void nsViewManager::RenderViews(nsView *aView, nsIWidget *aWidget,
const nsRegion& aRegion)
const nsRegion& aRegion,
const nsIntRegion& aIntRegion,
PRBool aPaintDefaultBackground,
PRBool aWillSendDidPaint)
{
nsView* displayRoot = GetDisplayRootFor(aView);
// Make sure we call Paint from the view manager that owns displayRoot.
// (Bug 485275)
nsViewManager* displayRootVM = displayRoot->GetViewManager();
if (displayRootVM && displayRootVM != this) {
displayRootVM->RenderViews(aView, aWidget, aRegion);
displayRootVM->
RenderViews(aView, aWidget, aRegion, aIntRegion, aPaintDefaultBackground,
aWillSendDidPaint);
return;
}

if (mObserver) {
mObserver->Paint(displayRoot, aView, aWidget, aRegion, PR_FALSE, PR_FALSE);
nsRegion region = ConvertRegionBetweenViews(aRegion, aView, displayRoot);
mObserver->Paint(displayRoot, aView, aWidget, region, aIntRegion,
aPaintDefaultBackground, aWillSendDidPaint);
}
}

Expand Down Expand Up @@ -471,11 +477,10 @@ void nsViewManager::ProcessPendingUpdates(nsView* aView, PRBool aDoInvalidate)
nsView* nearestViewWithWidget = aView;
while (!nearestViewWithWidget->HasWidget() &&
nearestViewWithWidget->GetParent()) {
nearestViewWithWidget =
static_cast<nsView*>(nearestViewWithWidget->GetParent());
nearestViewWithWidget = nearestViewWithWidget->GetParent();
}
nsRegion r = *dirtyRegion;
r.MoveBy(aView->GetOffsetTo(nearestViewWithWidget));
nsRegion r =
ConvertRegionBetweenViews(*dirtyRegion, aView, nearestViewWithWidget);
nsViewManager* widgetVM = nearestViewWithWidget->GetViewManager();
widgetVM->
UpdateWidgetArea(nearestViewWithWidget,
Expand Down Expand Up @@ -538,6 +543,9 @@ nsViewManager::UpdateWidgetArea(nsView *aWidgetView, nsIWidget* aWidget,
const nsRegion &aDamagedRegion,
nsView* aIgnoreWidgetView)
{
NS_ASSERTION(aWidgetView->GetViewManager() == this,
"UpdateWidgetArea called on view we don't own");

#if 0
nsRect dbgBounds = aDamagedRegion.GetBounds();
printf("UpdateWidgetArea view:%X (%d) widget:%X region: %d, %d, %d, %d\n",
Expand Down Expand Up @@ -607,11 +615,9 @@ nsViewManager::UpdateWidgetArea(nsView *aWidgetView, nsIWidget* aWidget,
// manager trees
nsViewManager* viewManager = view->GetViewManager();
if (viewManager->RootViewManager() == RootViewManager()) {
// get the damage region into view's coordinate system
nsRegion damage = intersection;

nsPoint offset = view->GetOffsetTo(aWidgetView);
damage.MoveBy(-offset);
// get the damage region into view's coordinate system and appunits
nsRegion damage =
ConvertRegionBetweenViews(intersection, aWidgetView, view);

// Update the child and it's children
viewManager->
Expand Down Expand Up @@ -714,6 +720,9 @@ void nsViewManager::UpdateViews(nsView *aView, PRUint32 aUpdateFlags)
NS_IMETHODIMP nsViewManager::DispatchEvent(nsGUIEvent *aEvent,
nsIView* aView, nsEventStatus *aStatus)
{
NS_ASSERTION(!aView || static_cast<nsView*>(aView)->GetViewManager() == this,
"wrong view manager");

*aStatus = nsEventStatus_eIgnore;

switch(aEvent->message)
Expand Down Expand Up @@ -754,8 +763,12 @@ NS_IMETHODIMP nsViewManager::DispatchEvent(nsGUIEvent *aEvent,
if (aEvent->message == NS_PAINT && event->region.IsEmpty())
break;

// The rect is in device units, and it's in the coordinate space of its
// associated window.
NS_ASSERTION(static_cast<nsView*>(aView) ==
nsView::GetViewFor(event->widget),
"view/widget mismatch");

// The region is in device units, and it's in the coordinate space of
// its associated widget.

// Refresh the view
if (IsRefreshEnabled()) {
Expand Down Expand Up @@ -834,10 +847,10 @@ NS_IMETHODIMP nsViewManager::DispatchEvent(nsGUIEvent *aEvent,
// since we got an NS_PAINT event, we need to
// draw something so we don't get blank areas,
// unless there's no widget or it's transparent.
nsRegion rgn = ConvertDeviceRegionToAppRegion(event->region, mContext);
mObserver->Paint(aView, aView, event->widget, rgn, PR_TRUE,
event->willSendDidPaint);

nsRegion rgn = event->region.ToAppUnits(AppUnitsPerDevPixel());
rgn.MoveBy(-aView->ViewToWidgetOffset());
RenderViews(static_cast<nsView*>(aView), event->widget, rgn,
event->region, PR_TRUE, event->willSendDidPaint);
// Clients like the editor can trigger multiple
// reflows during what the user perceives as a single
// edit operation, so it disables view manager
Expand Down
6 changes: 5 additions & 1 deletion view/src/nsViewManager.h
Expand Up @@ -184,10 +184,14 @@ class nsViewManager : public nsIViewManager {

void TriggerRefresh(PRUint32 aUpdateFlags);

// aView is the view for aWidget and aRegion is relative to aWidget.
void Refresh(nsView *aView, nsIWidget *aWidget,
const nsIntRegion& aRegion, PRUint32 aUpdateFlags);
// aRootView is the view for aWidget, aRegion is relative to aRootView, and
// aIntRegion is relative to aWidget.
void RenderViews(nsView *aRootView, nsIWidget *aWidget,
const nsRegion& aRegion);
const nsRegion& aRegion, const nsIntRegion& aIntRegion,
PRBool aPaintDefaultBackground, PRBool aWillSendDidPaint);

void InvalidateRectDifference(nsView *aView, const nsRect& aRect, const nsRect& aCutOut, PRUint32 aUpdateFlags);
void InvalidateHorizontalBandDifference(nsView *aView, const nsRect& aRect, const nsRect& aCutOut,
Expand Down

0 comments on commit b364da1

Please sign in to comment.