Bug 534425. Part 6: Let nsIWidgets expose a LayerManager to be used to render into the widget, instead of nsPaintEvent::renderingContext which is removed since it's no longer needed. Currently all widgets fall back to a default BasicLayerManager implementation. Also change nsPaintEvent::region to be an nsIntRegion, and get rid of nsPaintEvent::rect since it's redundant.

This commit is contained in:
Robert O'Callahan 2010-03-01 21:03:49 +13:00
parent d4e6525f53
commit 11a3d788af
29 changed files with 459 additions and 523 deletions

View File

@ -3313,6 +3313,9 @@ nsCanvasRenderingContext2D::DrawWindow(nsIDOMWindow* aWindow, float aX, float aY
if (flags & nsIDOMCanvasRenderingContext2D::DRAWWINDOW_DRAW_VIEW) {
renderDocFlags &= ~nsIPresShell::RENDER_IGNORE_VIEWPORT_SCROLLING;
}
if (flags & nsIDOMCanvasRenderingContext2D::DRAWWINDOW_USE_WIDGET_LAYERS) {
renderDocFlags |= nsIPresShell::RENDER_USE_WIDGET_LAYERS;
}
PRBool oldDisableValue = nsLayoutUtils::sDisableGetUsedXAssertions;
nsLayoutUtils::sDisableGetUsedXAssertions = oldDisableValue || skipFlush;

View File

@ -180,9 +180,13 @@ interface nsIDOMCanvasRenderingContext2D : nsISupports
// Don't flush pending layout notifications that could otherwise
// be batched up
const unsigned long DRAWWINDOW_DO_NOT_FLUSH = 0x02;
// Draw scrollbars and scroll the viewport if they are present
const unsigned long DRAWWINDOW_DRAW_VIEW = 0x04;
// Use the widget layer manager if available. This means hardware
// acceleration may be used, but it might actually be slower or
// lower quality than normal. It will however more accurately reflect
// the pixels rendered to the screen.
const unsigned long DRAWWINDOW_USE_WIDGET_LAYERS = 0x08;
/**
* Renders a region of a window into the canvas. The contents of

View File

@ -52,9 +52,7 @@ GRE_MODULE = 1
LIBXUL_LIBRARY = 1
ifeq (,$(filter-out WINCE WINNT,$(OS_ARCH)))
EXTRA_DSO_LIBS = gkgfx
endif
EXTRA_DSO_LIBS = gkgfx thebes
CPPSRCS = \
nsWebBrowserModule.cpp \

View File

@ -74,6 +74,8 @@
#include "nsIServiceManager.h"
#include "nsAutoPtr.h"
#include "nsFocusManager.h"
#include "Layers.h"
#include "gfxContext.h"
// for painting the background window
#include "nsIRenderingContext.h"
@ -90,6 +92,8 @@
// PSM2 includes
#include "nsISecureBrowserUI.h"
using namespace mozilla::layers;
static NS_DEFINE_IID(kWindowCID, NS_WINDOW_CID);
static NS_DEFINE_CID(kChildCID, NS_CHILD_CID);
static NS_DEFINE_CID(kLookAndFeelCID, NS_LOOKANDFEEL_CID);
@ -1667,11 +1671,12 @@ nsEventStatus nsWebBrowser::HandleEvent(nsGUIEvent *aEvent)
{
nsWebBrowser *browser = nsnull;
void *data = nsnull;
nsIWidget *widget = aEvent->widget;
if (!aEvent->widget)
if (!widget)
return nsEventStatus_eIgnore;
aEvent->widget->GetClientData(data);
widget->GetClientData(data);
if (!data)
return nsEventStatus_eIgnore;
@ -1680,39 +1685,30 @@ nsEventStatus nsWebBrowser::HandleEvent(nsGUIEvent *aEvent)
switch(aEvent->message) {
case NS_PAINT: {
nsPaintEvent *paintEvent = static_cast<nsPaintEvent *>(aEvent);
nsIRenderingContext *rc = paintEvent->renderingContext;
nscolor oldColor;
rc->GetColor(oldColor);
rc->SetColor(browser->mBackgroundColor);
nsCOMPtr<nsIDeviceContext> dx;
rc->GetDeviceContext(*getter_AddRefs(dx));
PRInt32 appUnitsPerDevPixel = dx->AppUnitsPerDevPixel();
LayerManager* layerManager = widget->GetLayerManager();
NS_ASSERTION(layerManager, "Must be in paint event");
nsIRegion *region = paintEvent->region;
if (region) {
nsRegionRectSet *rects = nsnull;
region->GetRects(&rects);
if (rects) {
for (PRUint32 i = 0; i < rects->mNumRects; ++i) {
nsRect r(rects->mRects[i].x*appUnitsPerDevPixel,
rects->mRects[i].y*appUnitsPerDevPixel,
rects->mRects[i].width*appUnitsPerDevPixel,
rects->mRects[i].height*appUnitsPerDevPixel);
rc->FillRect(r);
}
region->FreeRects(rects);
}
} else if (paintEvent->rect) {
nsRect r(paintEvent->rect->x*appUnitsPerDevPixel,
paintEvent->rect->y*appUnitsPerDevPixel,
paintEvent->rect->width*appUnitsPerDevPixel,
paintEvent->rect->height*appUnitsPerDevPixel);
rc->FillRect(r);
layerManager->BeginTransaction();
nsRefPtr<ThebesLayer> root = layerManager->CreateThebesLayer();
nsPaintEvent* paintEvent = static_cast<nsPaintEvent*>(aEvent);
nsIntRect dirtyRect = paintEvent->region.GetBounds();
if (root) {
root->SetVisibleRegion(dirtyRect);
layerManager->SetRoot(root);
}
rc->SetColor(oldColor);
layerManager->EndConstruction();
if (root) {
nsIntRegion toDraw;
gfxContext* ctx = root->BeginDrawing(&toDraw);
if (ctx) {
ctx->NewPath();
ctx->SetColor(gfxRGBA(browser->mBackgroundColor));
ctx->Rectangle(gfxRect(dirtyRect.x, dirtyRect.y, dirtyRect.width, dirtyRect.height));
ctx->Fill();
}
}
root->EndDrawing();
layerManager->EndTransaction();
return nsEventStatus_eConsumeDoDefault;
}

View File

@ -730,16 +730,36 @@ nsDisplayList::BuildLayer(nsDisplayListBuilder* aBuilder,
* root of the layer manager, drawing into the ThebesLayers.
*/
void nsDisplayList::Paint(nsDisplayListBuilder* aBuilder,
nsIRenderingContext* aCtx) const {
nsIRenderingContext* aCtx,
PRUint32 aFlags) const {
NS_ASSERTION(mDidComputeVisibility,
"Must call ComputeVisibility before calling Paint");
// To paint a display list, we construct a BasicLayerManager and
// a layer tree for it, and ask the BasicLayerManager to render.
nsRefPtr<LayerManager> layerManager = new BasicLayerManager();
if (!layerManager)
return;
layerManager->BeginTransactionWithTarget(aCtx->ThebesContext());
nsRefPtr<LayerManager> layerManager;
if (aFlags & PAINT_USE_WIDGET_LAYERS) {
nsIFrame* referenceFrame = aBuilder->ReferenceFrame();
NS_ASSERTION(referenceFrame == nsLayoutUtils::GetDisplayRootFrame(referenceFrame),
"Reference frame must be a display root for us to use the layer manager");
nsIWidget* window = referenceFrame->GetWindow();
if (window) {
layerManager = window->GetLayerManager();
}
}
if (!layerManager) {
if (!aCtx) {
NS_WARNING("Nowhere to paint into");
return;
}
layerManager = new BasicLayerManager(aCtx->ThebesContext());
if (!layerManager)
return;
}
if (aCtx) {
layerManager->BeginTransactionWithTarget(aCtx->ThebesContext());
} else {
layerManager->BeginTransaction();
}
nsAutoTArray<LayerItems,10> layers;
nsRefPtr<Layer> root = BuildLayer(aBuilder, layerManager, &layers);
@ -1829,7 +1849,7 @@ void nsDisplayTransform::Paint(nsDisplayListBuilder *aBuilder,
/* Now, send the paint call down.
*/
mStoredList.GetList()->Paint(aBuilder, aCtx);
mStoredList.GetList()->Paint(aBuilder, aCtx, nsDisplayList::PAINT_DEFAULT);
/* The AutoSaveRestore object will clean things up. */
}

View File

@ -550,6 +550,7 @@ public:
/**
* Actually paint this item to some rendering context.
* Content outside mVisibleRect need not be painted.
* aCtx must be set up as for nsDisplayList::Paint.
*/
virtual void Paint(nsDisplayListBuilder* aBuilder, nsIRenderingContext* aCtx) {}
/**
@ -848,9 +849,20 @@ public:
* rectangle in aDirtyRect is painted, which *must* be contained in the
* dirty rect used to construct the display list.
*
* If aFlags contains PAINT_USE_WIDGET_LAYERS and
* ShouldUseWidgetLayerManager() is set, then we will paint using
* the reference frame's widget's layer manager (and ctx may be null),
* otherwise we will use a temporary BasicLayerManager and ctx must
* not be null.
*
* ComputeVisibility must be called before Paint.
*/
void Paint(nsDisplayListBuilder* aBuilder, nsIRenderingContext* aCtx) const;
enum {
PAINT_DEFAULT = 0,
PAINT_USE_WIDGET_LAYERS = 0x01
};
void Paint(nsDisplayListBuilder* aBuilder, nsIRenderingContext* aCtx,
PRUint32 aFlags) const;
/**
* Get the bounds. Takes the union of the bounds of all children.
*/

View File

@ -824,6 +824,13 @@ public:
* clipping/scrolling/scrollbar painting due to scrolling in the viewport
* set RENDER_CARET to draw the caret if one would be visible
* (by default the caret is never drawn)
* set RENDER_USE_LAYER_MANAGER to force rendering to go through
* the layer manager for the window. This may be unexpectedly slow
* (if the layer manager must read back data from the GPU) or low-quality
* (if the layer manager reads back pixel data and scales it
* instead of rendering using the appropriate scaling). It may also
* slow everything down if the area rendered does not correspond to the
* normal visible area of the window.
* @param aBackgroundColor a background color to render onto
* @param aRenderedContext the gfxContext to render to. We render so that
* one CSS pixel in the source document is rendered to one unit in the current
@ -832,7 +839,8 @@ public:
enum {
RENDER_IS_UNTRUSTED = 0x01,
RENDER_IGNORE_VIEWPORT_SCROLLING = 0x02,
RENDER_CARET = 0x04
RENDER_CARET = 0x04,
RENDER_USE_WIDGET_LAYERS = 0x08
};
NS_IMETHOD RenderDocument(const nsRect& aRect, PRUint32 aFlags,
nscolor aBackgroundColor,

View File

@ -1192,7 +1192,11 @@ nsLayoutUtils::PaintFrame(nsIRenderingContext* aRenderingContext, nsIFrame* aFra
}
#endif
list.Paint(&builder, aRenderingContext);
PRUint32 flags = nsDisplayList::PAINT_DEFAULT;
if (aFlags & PAINT_WIDGET_LAYERS) {
flags |= nsDisplayList::PAINT_USE_WIDGET_LAYERS;
}
list.Paint(&builder, aRenderingContext, flags);
// Flush the list so we don't trigger the IsEmpty-on-destruction assertion
list.DeleteAll();
return NS_OK;

View File

@ -477,7 +477,8 @@ public:
enum {
PAINT_IN_TRANSFORM = 0x01,
PAINT_SYNC_DECODE_IMAGES = 0x02
PAINT_SYNC_DECODE_IMAGES = 0x02,
PAINT_WIDGET_LAYERS = 0x04
};
/**
@ -485,14 +486,35 @@ public:
* descendants to aRenderingContext.
* @param aRenderingContext a rendering context translated so that (0,0)
* is the origin of aFrame; for best results, (0,0) should transform
* to pixel-aligned coordinates
* to pixel-aligned coordinates. This can be null, in which case
* aFrame must be a "display root" (root frame for a root document,
* or the root of a popup) with an associated widget and we draw using
* the layer manager for the frame's widget.
* @param aDirtyRegion the region that must be painted, in the coordinates
* of aFrame
* @param aBackstop paint the dirty area with this color before drawing
* the actual content; pass NS_RGBA(0,0,0,0) to draw no background
* @param aFlags if PAINT_IN_TRANSFORM is set, then we assume
* this is inside a transform or SVG foreignObject. If
* PAINT_SYNC_DECODE_IMAGES is set, we force synchronous decode on all images.
* PAINT_SYNC_DECODE_IMAGES is set, we force synchronous decode on all
* images. If PAINT_WIDGET_LAYERS is set, aFrame must be a display root,
* and we will use the frame's widget's layer manager to paint
* even if aRenderingContext is non-null. This is useful if you want
* to force rendering to use the widget's layer manager for testing
* or speed. PAINT_WIDGET_LAYERS must be set if aRenderingContext is null.
*
* So there are three possible behaviours:
* 1) PAINT_WIDGET_LAYERS is set and aRenderingContext is null; we paint
* by calling BeginTransaction on the widget's layer manager
* 2) PAINT_WIDGET_LAYERS is set and aRenderingContext is non-null; we
* paint by calling BeginTransactionWithTarget on the widget's layer
* maanger
* 3) PAINT_WIDGET_LAYERS is not set and aRenderingContext is non-null;
* we paint by construct a BasicLayerManager and calling
* BeginTransactionWithTarget on it. This is desirable if we're doing
* something like drawWindow in a mode where what gets rendered doesn't
* necessarily correspond to what's visible in the window; we don't
* want to mess up the widget's layer tree.
*/
static nsresult PaintFrame(nsIRenderingContext* aRenderingContext, nsIFrame* aFrame,
const nsRegion& aDirtyRegion, nscolor aBackstop,

View File

@ -206,6 +206,8 @@
#include "nsContentCID.h"
static NS_DEFINE_IID(kRangeCID, NS_RANGE_CID);
using namespace mozilla::layers;
PRBool nsIPresShell::gIsAccessibilityActive = PR_FALSE;
CapturingContentInfo nsIPresShell::gCaptureInfo;
@ -784,12 +786,11 @@ public:
//nsIViewObserver interface
NS_IMETHOD Paint(nsIView *aView,
nsIRenderingContext* aRenderingContext,
const nsRegion& aDirtyRegion);
NS_IMETHOD PaintDefaultBackground(nsIView *aView,
nsIRenderingContext* aRenderingContext,
const nsRect& aDirtyRect);
NS_IMETHOD Paint(nsIView* aDisplayRoot,
nsIView* aViewToPaint,
nsIWidget* aWidget,
const nsRegion& aDirtyRegion,
PRBool aPaintDefaultBackground);
NS_IMETHOD ComputeRepaintRegionForCopy(nsIView* aRootView,
nsIView* aMovingView,
nsPoint aDelta,
@ -1287,7 +1288,7 @@ private:
* widget, otherwise the PresContext default background color. This color is
* only visible if the contents of the view as a whole are translucent.
*/
nscolor ComputeBackstopColor(nsIView* aView);
nscolor ComputeBackstopColor(nsIView* aDisplayRoot);
#ifdef DEBUG
// Ensure that every allocation from the PresArena is eventually freed.
@ -5279,7 +5280,11 @@ PresShell::RenderDocument(const nsRect& aRect, PRUint32 aFlags,
devCtx->CreateRenderingContextInstance(*getter_AddRefs(rc));
rc->Init(devCtx, aThebesContext);
list.Paint(&builder, rc);
PRUint32 flags = nsDisplayList::PAINT_DEFAULT;
if (aFlags & RENDER_USE_WIDGET_LAYERS) {
flags |= nsDisplayList::PAINT_USE_WIDGET_LAYERS;
}
list.Paint(&builder, rc, flags);
// Flush the list so we don't trigger the IsEmpty-on-destruction assertion
list.DeleteAll();
@ -5572,7 +5577,7 @@ PresShell::PaintRangePaintInfo(nsTArray<nsAutoPtr<RangePaintInfo> >* aItems,
aArea.MoveBy(-rangeInfo->mRootOffset.x, -rangeInfo->mRootOffset.y);
nsRegion visible(aArea);
rangeInfo->mList.ComputeVisibility(&rangeInfo->mBuilder, &visible, nsnull);
rangeInfo->mList.Paint(&rangeInfo->mBuilder, rc);
rangeInfo->mList.Paint(&rangeInfo->mBuilder, rc, nsDisplayList::PAINT_DEFAULT);
aArea.MoveBy(rangeInfo->mRootOffset.x, rangeInfo->mRootOffset.y);
}
@ -5716,9 +5721,9 @@ void PresShell::UpdateCanvasBackground()
}
}
nscolor PresShell::ComputeBackstopColor(nsIView* aView)
nscolor PresShell::ComputeBackstopColor(nsIView* aDisplayRoot)
{
nsIWidget* widget = aView->GetNearestWidget(nsnull);
nsIWidget* widget = aDisplayRoot->GetWidget();
if (widget && widget->GetTransparencyMode() != eTransparencyOpaque) {
// Within a transparent widget, so the backstop color must be
// totally transparent.
@ -5731,46 +5736,80 @@ nscolor PresShell::ComputeBackstopColor(nsIView* aView)
}
NS_IMETHODIMP
PresShell::Paint(nsIView* aView,
nsIRenderingContext* aRenderingContext,
const nsRegion& aDirtyRegion)
PresShell::Paint(nsIView* aDisplayRoot,
nsIView* aViewToPaint,
nsIWidget* aWidgetToPaint,
const nsRegion& aDirtyRegion,
PRBool aPaintDefaultBackground)
{
AUTO_LAYOUT_PHASE_ENTRY_POINT(GetPresContext(), Paint);
nsPresContext* presContext = GetPresContext();
AUTO_LAYOUT_PHASE_ENTRY_POINT(presContext, Paint);
NS_ASSERTION(!mIsDestroying, "painting a destroyed PresShell");
NS_ASSERTION(aView, "null view");
NS_ASSERTION(aDisplayRoot, "null view");
NS_ASSERTION(aViewToPaint, "null view");
NS_ASSERTION(aWidgetToPaint, "Can't paint without a widget");
nscolor bgcolor = ComputeBackstopColor(aView);
nscolor bgcolor = ComputeBackstopColor(aDisplayRoot);
nsIFrame* frame = static_cast<nsIFrame*>(aView->GetClientData());
if (frame) {
nsLayoutUtils::PaintFrame(aRenderingContext, frame, aDirtyRegion, bgcolor);
} else {
bgcolor = NS_ComposeColors(bgcolor, mCanvasBackgroundColor);
aRenderingContext->SetColor(bgcolor);
aRenderingContext->FillRect(aDirtyRegion.GetBounds());
nsIFrame* frame = aPaintDefaultBackground
? nsnull : static_cast<nsIFrame*>(aDisplayRoot->GetClientData());
if (frame && aViewToPaint == aDisplayRoot) {
// We can paint directly into the widget using its layer manager.
// When we get rid of child widgets, this will be the only path we
// need. (aPaintDefaultBackground will never be needed since the
// chrome can always paint a default background.)
nsLayoutUtils::PaintFrame(nsnull, frame, aDirtyRegion, bgcolor,
nsLayoutUtils::PAINT_WIDGET_LAYERS);
return NS_OK;
}
return NS_OK;
}
NS_IMETHODIMP
PresShell::PaintDefaultBackground(nsIView* aView,
nsIRenderingContext* aRenderingContext,
const nsRect& aDirtyRect)
{
AUTO_LAYOUT_PHASE_ENTRY_POINT(GetPresContext(), Paint);
LayerManager* layerManager = aWidgetToPaint->GetLayerManager();
NS_ASSERTION(layerManager, "Must be in paint event");
NS_ASSERTION(!mIsDestroying, "painting a destroyed PresShell");
NS_ASSERTION(aView, "null view");
layerManager->BeginTransaction();
nsRefPtr<ThebesLayer> root = layerManager->CreateThebesLayer();
nsIntRect dirtyRect = aDirtyRegion.GetBounds().
ToOutsidePixels(presContext->AppUnitsPerDevPixel());
if (root) {
root->SetVisibleRegion(dirtyRect);
layerManager->SetRoot(root);
}
layerManager->EndConstruction();
if (root) {
nsIntRegion toDraw;
gfxContext* ctx = root->BeginDrawing(&toDraw);
if (ctx) {
if (frame) {
// We're drawing into a child window. Don't pass
// nsLayoutUtils::PAINT_WIDGET_LAYERS, since that will draw into
// the widget for the display root.
nsIDeviceContext* devCtx = GetPresContext()->DeviceContext();
nsCOMPtr<nsIRenderingContext> rc;
nsresult rv = devCtx->CreateRenderingContextInstance(*getter_AddRefs(rc));
if (NS_SUCCEEDED(rv)) {
rc->Init(devCtx, ctx);
// Offset to add to aView coordinates to get aWidget coordinates
nsPoint offsetToRoot = aViewToPaint->GetOffsetTo(aDisplayRoot);
nsRegion dirtyRegion = aDirtyRegion;
dirtyRegion.MoveBy(offsetToRoot);
nsIRenderingContext::AutoPushTranslation
push(rc, -offsetToRoot.x, -offsetToRoot.y);
nsLayoutUtils::PaintFrame(rc, frame, dirtyRegion, bgcolor);
}
} else {
bgcolor = NS_ComposeColors(bgcolor, mCanvasBackgroundColor);
ctx->NewPath();
ctx->SetColor(gfxRGBA(bgcolor));
ctx->Rectangle(gfxRect(dirtyRect.x, dirtyRect.y, dirtyRect.width, dirtyRect.height));
ctx->Fill();
}
}
root->EndDrawing();
}
layerManager->EndTransaction();
// We must not look at the frame tree, so all we have to use is the canvas
// default color as set above.
nscolor bgcolor = NS_ComposeColors(ComputeBackstopColor(aView),
mCanvasBackgroundColor);
aRenderingContext->SetColor(bgcolor);
aRenderingContext->FillRect(aDirtyRect);
return NS_OK;
}

View File

@ -209,7 +209,7 @@ public:
{
nsIRenderingContext* ctx = aContext->GetRenderingContext(aTarget);
nsIRenderingContext::AutoPushTranslation push(ctx, -mOffset.x, -mOffset.y);
mInnerList->Paint(mBuilder, ctx);
mInnerList->Paint(mBuilder, ctx, nsDisplayList::PAINT_DEFAULT);
}
private:
@ -302,7 +302,7 @@ nsSVGIntegrationUtils::PaintFramesWithEffects(nsIRenderingContext* aCtx,
filterFrame->FilterPaint(&svgContext, aEffectsFrame, &paint, &r);
} else {
gfx->SetMatrix(savedCTM);
aInnerList->Paint(aBuilder, aCtx);
aInnerList->Paint(aBuilder, aCtx, nsDisplayList::PAINT_DEFAULT);
aCtx->Translate(userSpaceRect.x, userSpaceRect.y);
}

View File

@ -877,7 +877,8 @@ function InitCurrentCanvasWithSnapshot()
Math.ceil(gCurrentCanvas.width / scale),
Math.ceil(gCurrentCanvas.height / scale),
"rgb(255,255,255)",
ctx.DRAWWINDOW_DRAW_CARET);
ctx.DRAWWINDOW_DRAW_CARET |
ctx.DRAWWINDOW_USE_WIDGET_LAYERS);
ctx.restore();
}

View File

@ -47,8 +47,8 @@ class nsIRenderingContext;
class nsGUIEvent;
#define NS_IVIEWOBSERVER_IID \
{ 0xba1357b6, 0xe3c7, 0x426a, \
{ 0xb3, 0x68, 0xfe, 0xe8, 0x24, 0x8c, 0x08, 0x38 } }
{ 0xac43a985, 0xcae6, 0x499d, \
{ 0xae, 0x8f, 0x9c, 0x92, 0xec, 0x6f, 0x2c, 0x47 } }
class nsIViewObserver : public nsISupports
{
@ -59,36 +59,23 @@ public:
/* called when the observer needs to paint. This paints the entire
* frame subtree rooted at the view, including frame subtrees from
* subdocuments.
* @param aRenderingContext rendering context to paint to; the origin
* of the view is painted at (0,0) in the rendering context's current
* transform. For best results this should transform to pixel-aligned
* coordinates.
* @param aViewToPaint the view for the widget that is being painted
* @param aDirtyRegion the region to be painted, in the coordinates of
* aRootView
* aViewToPaint
* @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
* must *not* paint, or even examine, the frame subtree rooted at the
* view. (It is, however, safe to inspect the state of the view itself,
* and any associated widget.) The name illustrates the expected behavior,
* which is to paint some default background color over the dirty region.
* @return error status
*/
NS_IMETHOD Paint(nsIView* aRootView,
nsIRenderingContext* aRenderingContext,
const nsRegion& aDirtyRegion) = 0;
/* called when the observer needs to paint something, but the view
* tree is unstable, so it must *not* paint, or even examine, the
* frame subtree rooted at the view. (It is, however, safe to inspect
* the state of the view itself, and any associated widget.) The name
* illustrates the expected behavior, which is to paint some default
* background color over the dirty rect.
*
* @param aRenderingContext rendering context to paint to; the origin
* of the view is painted at (0,0) in the rendering context's current
* transform. For best results this should transform to pixel-aligned
* coordinates.
* @param aDirtyRect the rectangle to be painted, in the coordinates
* of aRootView
* @return error status
*/
NS_IMETHOD PaintDefaultBackground(nsIView* aRootView,
nsIRenderingContext* aRenderingContext,
const nsRect& aDirtyRect) = 0;
NS_IMETHOD Paint(nsIView* aDisplayRoot,
nsIView* aViewToPaint,
nsIWidget* aWidgetToPaint,
const nsRegion& aDirtyRegion,
PRBool aPaintDefaultBackground) = 0;
/* called when the observer needs to handle an event
* @param aView - where to start processing the event; the root view,

View File

@ -352,28 +352,20 @@ NS_IMETHODIMP nsViewManager::FlushDelayedResize()
return NS_OK;
}
static void ConvertNativeRegionToAppRegion(nsIRegion* aIn, nsRegion* aOut,
nsIDeviceContext* context)
static nsRegion ConvertDeviceRegionToAppRegion(const nsIntRegion& aIn,
nsIDeviceContext* aContext)
{
nsRegionRectSet* rects = nsnull;
aIn->GetRects(&rects);
if (!rects)
return;
PRInt32 p2a = aContext->AppUnitsPerDevPixel();
PRInt32 p2a = context->AppUnitsPerDevPixel();
PRUint32 i;
for (i = 0; i < rects->mNumRects; i++) {
const nsRegionRect& inR = rects->mRects[i];
nsRect outR;
outR.x = NSIntPixelsToAppUnits(inR.x, p2a);
outR.y = NSIntPixelsToAppUnits(inR.y, p2a);
outR.width = NSIntPixelsToAppUnits(inR.width, p2a);
outR.height = NSIntPixelsToAppUnits(inR.height, p2a);
aOut->Or(*aOut, outR);
nsRegion out;
nsIntRegionRectIterator iter(aIn);
for (;;) {
const nsIntRect* r = iter.Next();
if (!r)
break;
out.Or(out, r->ToAppUnits(p2a));
}
aIn->FreeRects(rects);
return out;
}
static nsView* GetDisplayRootFor(nsView* aView)
@ -392,12 +384,13 @@ static nsView* GetDisplayRootFor(nsView* aView)
/**
aRegion is given in device coordinates!!
aContext may be null, in which case layers should be used for
rendering.
*/
void nsViewManager::Refresh(nsView *aView, nsIRenderingContext *aContext,
nsIRegion *aRegion, PRUint32 aUpdateFlags)
void nsViewManager::Refresh(nsView *aView, nsIWidget *aWidget,
const nsIntRegion& aRegion,
PRUint32 aUpdateFlags)
{
NS_ASSERTION(aRegion != nsnull, "Null aRegion");
if (! IsRefreshEnabled())
return;
@ -406,10 +399,8 @@ void nsViewManager::Refresh(nsView *aView, nsIRenderingContext *aContext,
nsPoint vtowoffset = aView->ViewToWidgetOffset();
// damageRegion is the damaged area, in twips, relative to the view origin
nsRegion damageRegion;
// convert pixels-relative-to-widget-origin to twips-relative-to-widget-origin
ConvertNativeRegionToAppRegion(aRegion, &damageRegion, mContext);
// move it from widget coordinates into view coordinates
nsRegion damageRegion = ConvertDeviceRegionToAppRegion(aRegion, mContext);
// move region from widget coordinates into view coordinates
damageRegion.MoveBy(viewRect.TopLeft() - vtowoffset);
if (damageRegion.IsEmpty()) {
@ -432,36 +423,7 @@ void nsViewManager::Refresh(nsView *aView, nsIRenderingContext *aContext,
nsAutoScriptBlocker scriptBlocker;
SetPainting(PR_TRUE);
nsCOMPtr<nsIRenderingContext> localcx;
if (nsnull == aContext)
{
localcx = CreateRenderingContext(*aView);
//couldn't get rendering context. this is ok at init time atleast
if (nsnull == localcx) {
SetPainting(PR_FALSE);
return;
}
} else {
// plain assignment grabs another reference.
localcx = aContext;
}
PRInt32 p2a = mContext->AppUnitsPerDevPixel();
nsRefPtr<gfxContext> ctx = localcx->ThebesContext();
ctx->Save();
ctx->Translate(gfxPoint(gfxFloat(vtowoffset.x) / p2a,
gfxFloat(vtowoffset.y) / p2a));
ctx->Translate(gfxPoint(-gfxFloat(viewRect.x) / p2a,
-gfxFloat(viewRect.y) / p2a));
RenderViews(aView, *localcx, damageRegion);
ctx->Restore();
RenderViews(aView, aWidget, damageRegion);
SetPainting(PR_FALSE);
}
@ -475,25 +437,20 @@ void nsViewManager::Refresh(nsView *aView, nsIRenderingContext *aContext,
}
// aRC and aRegion are in view coordinates
void nsViewManager::RenderViews(nsView *aView, nsIRenderingContext& aRC,
void nsViewManager::RenderViews(nsView *aView, nsIWidget *aWidget,
const nsRegion& aRegion)
{
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)
return displayRootVM->RenderViews(aView, aRC, aRegion);
if (displayRootVM && displayRootVM != this) {
displayRootVM->RenderViews(aView, aWidget, aRegion);
return;
}
if (mObserver) {
nsPoint offsetToRoot = aView->GetOffsetTo(displayRoot);
nsRegion damageRegion(aRegion);
damageRegion.MoveBy(offsetToRoot);
aRC.PushState();
aRC.Translate(-offsetToRoot.x, -offsetToRoot.y);
mObserver->Paint(displayRoot, &aRC, damageRegion);
aRC.PopState();
mObserver->Paint(displayRoot, aView, aWidget, aRegion, PR_FALSE);
}
}
@ -839,21 +796,11 @@ NS_IMETHODIMP nsViewManager::DispatchEvent(nsGUIEvent *aEvent,
*aStatus = nsEventStatus_eConsumeNoDefault;
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.
nsCOMPtr<nsIRegion> region = event->region;
if (aEvent->message == NS_PAINT) {
if (!region) {
if (NS_FAILED(CreateRegion(getter_AddRefs(region))))
break;
const nsIntRect& damrect = *event->rect;
region->SetTo(damrect.x, damrect.y, damrect.width, damrect.height);
}
if (region->IsEmpty())
break;
}
// Refresh the view
if (IsRefreshEnabled()) {
@ -926,28 +873,16 @@ NS_IMETHODIMP nsViewManager::DispatchEvent(nsGUIEvent *aEvent,
}
if (view && aEvent->message == NS_PAINT) {
Refresh(view, event->renderingContext, region,
NS_VMREFRESH_DOUBLE_BUFFER);
Refresh(view, event->widget,
event->region, NS_VMREFRESH_DOUBLE_BUFFER);
}
}
} else if (aEvent->message == NS_PAINT) {
// 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.
nsIntRect damIntRect;
region->GetBoundingBox(&damIntRect.x, &damIntRect.y,
&damIntRect.width, &damIntRect.height);
nsRect damRect =
damIntRect.ToAppUnits(mContext->AppUnitsPerDevPixel());
nsCOMPtr<nsIRenderingContext> context = event->renderingContext;
if (!context)
context = CreateRenderingContext(*static_cast<nsView*>(aView));
if (context)
mObserver->PaintDefaultBackground(aView, context, damRect);
else
NS_WARNING("nsViewManager: no rc for default refresh");
nsRegion rgn = ConvertDeviceRegionToAppRegion(event->region, mContext);
mObserver->Paint(aView, aView, event->widget, rgn, PR_TRUE);
// Clients like the editor can trigger multiple
// reflows during what the user perceives as a single
@ -973,7 +908,7 @@ NS_IMETHODIMP nsViewManager::DispatchEvent(nsGUIEvent *aEvent,
// ScrollingView's viewable area. (See bug 97674 for this
// alternate patch.)
UpdateView(aView, damRect, NS_VMREFRESH_NO_SYNC);
UpdateView(aView, rgn.GetBounds(), NS_VMREFRESH_NO_SYNC);
}
break;
@ -1550,53 +1485,6 @@ NS_IMETHODIMP nsViewManager::GetDeviceContext(nsIDeviceContext *&aContext)
return NS_OK;
}
already_AddRefed<nsIRenderingContext>
nsViewManager::CreateRenderingContext(nsView &aView)
{
nsView *par = &aView;
nsIWidget* win;
nsIRenderingContext *cx = nsnull;
nscoord ax = 0, ay = 0;
do
{
win = par->GetWidget();
if (win)
break;
//get absolute coordinates of view, but don't
//add in view pos since the first thing you ever
//need to do when painting a view is to translate
//the rendering context by the views pos and other parts
//of the code do this for us...
if (par != &aView)
{
par->ConvertToParentCoords(&ax, &ay);
}
par = par->GetParent();
}
while (nsnull != par);
if (nsnull != win)
{
// XXXkt this has an origin at top-left of win ...
mContext->CreateRenderingContext(par, cx);
// XXXkt ... but the translation is between the origins of views
NS_ASSERTION(aView.ViewToWidgetOffset()
- aView.GetDimensions().TopLeft() ==
par->ViewToWidgetOffset()
- par->GetDimensions().TopLeft(),
"ViewToWidgetOffset not handled!");
if (nsnull != cx)
cx->Translate(ax, ay);
}
return cx;
}
void nsViewManager::TriggerRefresh(PRUint32 aUpdateFlags)
{
if (!IsRootVM()) {

View File

@ -179,7 +179,6 @@ private:
void CallWillPaintOnObservers();
void ReparentChildWidgets(nsIView* aView, nsIWidget *aNewWidget);
void ReparentWidgets(nsIView* aView, nsIView *aParent);
already_AddRefed<nsIRenderingContext> CreateRenderingContext(nsView &aView);
void UpdateWidgetArea(nsView *aWidgetView, nsIWidget* aWidget,
const nsRegion &aDamagedRegion,
nsView* aIgnoreWidgetView);
@ -188,9 +187,9 @@ private:
void TriggerRefresh(PRUint32 aUpdateFlags);
void Refresh(nsView *aView, nsIRenderingContext *aContext,
nsIRegion *region, PRUint32 aUpdateFlags);
void RenderViews(nsView *aRootView, nsIRenderingContext& aRC,
void Refresh(nsView *aView, nsIWidget *aWidget,
const nsIntRegion& aRegion, PRUint32 aUpdateFlags);
void RenderViews(nsView *aRootView, nsIWidget *aWidget,
const nsRegion& aRegion);
void InvalidateRectDifference(nsView *aView, const nsRect& aRect, const nsRect& aCutOut, PRUint32 aUpdateFlags);

View File

@ -59,7 +59,6 @@
#include "nsIVariant.h"
class nsIRenderingContext;
class nsIRegion;
class nsIMenuItem;
class nsIAccessible;
class nsIContent;
@ -636,17 +635,12 @@ class nsPaintEvent : public nsGUIEvent
{
public:
nsPaintEvent(PRBool isTrusted, PRUint32 msg, nsIWidget *w)
: nsGUIEvent(isTrusted, msg, w, NS_PAINT_EVENT),
renderingContext(nsnull), region(nsnull), rect(nsnull)
: nsGUIEvent(isTrusted, msg, w, NS_PAINT_EVENT)
{
}
/// Context to paint in.
nsIRenderingContext *renderingContext;
/// area to paint (should be used instead of rect)
nsIRegion *region;
/// x,y, width, height in pixels of area to paint
nsIntRect *rect;
// area that needs repainting
nsIntRegion region;
};
/**

View File

@ -66,6 +66,12 @@ class imgIContainer;
class gfxASurface;
class nsIContent;
namespace mozilla {
namespace layers {
class LayerManager;
}
}
/**
* Callback function that processes events.
*
@ -103,7 +109,7 @@ typedef nsEventStatus (* EVENT_CALLBACK)(nsGUIEvent *event);
#endif
#define NS_IWIDGET_IID \
{ 0x6bdb96ba, 0x1727, 0x40ae, \
{ 0x9383831, 0x1039, 0x010f9, \
{ 0x85, 0x55, 0x9c, 0x53, 0x4b, 0x95, 0x23, 0x98 } }
/*
@ -180,6 +186,7 @@ enum nsTopLevelWidgetZPlacement { // for PlaceBehind()
class nsIWidget : public nsISupports {
public:
typedef mozilla::layers::LayerManager LayerManager;
NS_DECLARE_STATIC_IID_ACCESSOR(NS_IWIDGET_IID)
@ -667,6 +674,14 @@ class nsIWidget : public nsISupports {
virtual nsIToolkit* GetToolkit() = 0;
/**
* Return the widget's LayerManager. The layer tree for that
* LayerManager is what gets rendered to the widget.
* The layer manager is guaranteed to be the same for the lifetime
* of the widget.
*/
virtual LayerManager* GetLayerManager() = 0;
/**
* Scroll a set of rectangles in this widget and (as simultaneously as
* possible) modify the specified child widgets.

View File

@ -55,6 +55,7 @@ CPPSRCS = nsWinWidgetFactory.cpp
EXTRA_DSO_LIBS = gkgfx \
thebes \
layers \
$(NULL)
LOCAL_INCLUDES = \

View File

@ -106,6 +106,7 @@ EXTRA_DSO_LDOPTS += \
$(call EXPAND_LIBNAME_PATH,gkgfx,$(DEPTH)/gfx/src) \
$(MOZ_COMPONENT_LIBS) \
-lthebes \
-llayers \
$(QCMS_LIBS) \
$(NULL)

View File

@ -179,7 +179,7 @@ PRUint32 nsChildView::sLastInputEventCount = 0;
+ (NSEvent*)makeNewCocoaEventWithType:(NSEventType)type fromEvent:(NSEvent*)theEvent;
- (BOOL)beginMaybeResetUnifiedToolbar:(nsIRegion*)aRegion context:(CGContextRef)aContext;
- (BOOL)beginMaybeResetUnifiedToolbar:(nsIntRegion*)aRegion context:(CGContextRef)aContext;
- (void)endMaybeResetUnifiedToolbar:(BOOL)aReset;
#if USE_CLICK_HOLD_CONTEXTMENU
@ -1669,7 +1669,6 @@ void nsChildView::Scroll(const nsIntPoint& aDelta,
// to do exactly what we need here.
nsIntRegion needsInvalidation;
needsInvalidation.Sub(allRects, destRegion);
nsIntRegionRectIterator iter(needsInvalidation);
const nsIntRect* invalidate;
for (nsIntRegionRectIterator iter(needsInvalidation);
(invalidate = iter.Next()) != nsnull;) {
@ -2453,11 +2452,11 @@ static BOOL DrawingAtWindowTop(CGContextRef aContext)
return ctm.ty >= [[[[NSView focusView] window] contentView] bounds].size.height;
}
- (BOOL)beginMaybeResetUnifiedToolbar:(nsIRegion*)aRegion context:(CGContextRef)aContext
- (BOOL)beginMaybeResetUnifiedToolbar:(nsIntRegion*)aRegion context:(CGContextRef)aContext
{
if (![[self window] isKindOfClass:[ToolbarWindow class]] ||
!DrawingAtWindowTop(aContext) ||
!aRegion->ContainsRect(0, 0, (int)[self bounds].size.width, 1))
!aRegion->Contains(nsIntRect(0, 0, (int)[self bounds].size.width, 1)))
return NO;
[(ToolbarWindow*)[self window] beginMaybeResetUnifiedToolbar];
@ -2512,15 +2511,8 @@ static BOOL DrawingAtWindowTop(CGContextRef aContext)
nsRefPtr<gfxContext> targetContext = new gfxContext(targetSurface);
nsCOMPtr<nsIRenderingContext> rc;
mGeckoChild->GetDeviceContext()->CreateRenderingContextInstance(*getter_AddRefs(rc));
rc->Init(mGeckoChild->GetDeviceContext(), targetContext);
// Build a region.
nsCOMPtr<nsIRegion> rgn(do_CreateInstance(kRegionCID));
if (!rgn)
return;
rgn->Init();
// Create the event so we can fill in its region
nsPaintEvent paintEvent(PR_TRUE, NS_PAINT, mGeckoChild);
const NSRect *rects;
NSInteger count, i;
@ -2529,10 +2521,12 @@ static BOOL DrawingAtWindowTop(CGContextRef aContext)
for (i = 0; i < count; ++i) {
// Add the rect to the region.
const NSRect& r = [self convertRect:rects[i] fromView:[NSView focusView]];
rgn->Union((PRInt32)r.origin.x, (PRInt32)r.origin.y, (PRInt32)r.size.width, (PRInt32)r.size.height);
paintEvent.region.Or(paintEvent.region,
nsIntRect(r.origin.x, r.origin.y, r.size.width, r.size.height));
}
} else {
rgn->Union(aRect.origin.x, aRect.origin.y, aRect.size.width, aRect.size.height);
paintEvent.region =
nsIntRect(aRect.origin.x, aRect.origin.y, aRect.size.width, aRect.size.height);
}
// Subtract child view rectangles from the region
@ -2542,36 +2536,31 @@ static BOOL DrawingAtWindowTop(CGContextRef aContext)
if (![view isKindOfClass:[ChildView class]] || [view isHidden])
continue;
NSRect frame = [view frame];
rgn->Subtract(frame.origin.x, frame.origin.y, frame.size.width, frame.size.height);
paintEvent.region.Sub(paintEvent.region,
nsIntRect(frame.origin.x, frame.origin.y, frame.size.width, frame.size.height));
}
// Set up the clip region.
nsRegionRectSet* rgnRects = nsnull;
rgn->GetRects(&rgnRects);
if (!rgnRects)
return;
for (PRUint32 i = 0; i < rgnRects->mNumRects; ++i) {
const nsRegionRect& rect = rgnRects->mRects[i];
targetContext->Rectangle(gfxRect(rect.x, rect.y, rect.width, rect.height));
nsIntRegionRectIterator iter(paintEvent.region);
targetContext->NewPath();
for (;;) {
const nsIntRect* r = iter.Next();
if (!r)
break;
targetContext->Rectangle(gfxRect(r->x, r->y, r->width, r->height));
}
rgn->FreeRects(rgnRects);
targetContext->Clip();
// bounding box of the dirty area
nsIntRect fullRect;
NSRectToGeckoRect(aRect, fullRect);
// Create the event and dispatch it.
nsPaintEvent paintEvent(PR_TRUE, NS_PAINT, mGeckoChild);
paintEvent.renderingContext = rc;
paintEvent.rect = &fullRect;
paintEvent.region = rgn;
BOOL resetUnifiedToolbar = [self beginMaybeResetUnifiedToolbar:rgn context:aContext];
BOOL resetUnifiedToolbar =
[self beginMaybeResetUnifiedToolbar:&paintEvent.region context:aContext];
nsAutoRetainCocoaObject kungFuDeathGrip(self);
PRBool painted = mGeckoChild->DispatchWindowEvent(paintEvent);
PRBool painted;
{
nsBaseWidget::AutoLayerManagerSetup setupLayerManager(mGeckoChild, targetContext);
painted = mGeckoChild->DispatchWindowEvent(paintEvent);
}
if (!painted && [self isOpaque]) {
// Gecko refused to draw, but we've claimed to be opaque, so we have to
// draw something--fill with white.
@ -2582,21 +2571,11 @@ static BOOL DrawingAtWindowTop(CGContextRef aContext)
[self endMaybeResetUnifiedToolbar:resetUnifiedToolbar];
if (!mGeckoChild)
return;
paintEvent.renderingContext = nsnull;
paintEvent.region = nsnull;
targetContext = nsnull;
targetSurface = nsnull;
// note that the cairo surface *MUST* be destroyed at this point,
// or bad things will happen (since we can't keep the cgContext around
// beyond this drawRect message handler)
#ifdef DEBUG_UPDATE
fprintf (stderr, " window coords: [%d %d %d %d]\n", fullRect.x, fullRect.y, fullRect.width, fullRect.height);
fprintf (stderr, "---- update done ----\n");
#if 0

View File

@ -247,6 +247,7 @@ public:
virtual void Scroll(const nsIntPoint& aDelta,
const nsTArray<nsIntRect>& aDestRects,
const nsTArray<Configuration>& aConfigurations);
virtual LayerManager* GetLayerManager();
NS_IMETHOD DispatchEvent(nsGUIEvent* event, nsEventStatus & aStatus) ;
NS_IMETHOD CaptureRollupEvents(nsIRollupListener * aListener, nsIMenuRollup * aMenuRollup,
PRBool aDoCapture, PRBool aConsumeRollupEvent);

View File

@ -71,6 +71,13 @@
#include "gfxPlatform.h"
#include "qcms.h"
namespace mozilla {
namespace layers {
class LayerManager;
}
}
using namespace mozilla::layers;
// defined in nsAppShell.mm
extern nsCocoaAppModalWindowList *gCocoaAppModalWindowList;
@ -908,6 +915,15 @@ nsCocoaWindow::Scroll(const nsIntPoint& aDelta,
}
}
LayerManager*
nsCocoaWindow::GetLayerManager()
{
if (mPopupContentView) {
return mPopupContentView->GetLayerManager();
}
return nsnull;
}
nsTransparencyMode nsCocoaWindow::GetTransparencyMode()
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;

View File

@ -48,7 +48,6 @@
#include "nsGTKToolkit.h"
#include "nsIDeviceContext.h"
#include "nsIRenderingContext.h"
#include "nsIRegion.h"
#include "nsIRollupListener.h"
#include "nsIMenuRollup.h"
#include "nsIDOMNode.h"
@ -2333,13 +2332,9 @@ nsWindow::OnExposeEvent(GtkWidget *aWidget, GdkEventExpose *aEvent)
if (!mGdkWindow || mIsFullyObscured || !mHasMappedToplevel)
return FALSE;
static NS_DEFINE_CID(kRegionCID, NS_REGION_CID);
nsCOMPtr<nsIRegion> updateRegion = do_CreateInstance(kRegionCID);
if (!updateRegion)
return FALSE;
updateRegion->Init();
nsPaintEvent event(PR_TRUE, NS_PAINT, this);
event.refPoint.x = aEvent->area.x;
event.refPoint.y = aEvent->area.y;
GdkRectangle *rects;
gint nrects;
@ -2360,7 +2355,7 @@ nsWindow::OnExposeEvent(GtkWidget *aWidget, GdkEventExpose *aEvent)
GdkRectangle *r;
GdkRectangle *r_end = rects + nrects;
for (r = rects; r < r_end; ++r) {
updateRegion->Union(r->x, r->y, r->width, r->height);
event.region.Or(event.region, nsIntRect(r->x, r->y, r->width, r->height));
LOGDRAW(("\t%d %d %d %d\n", r->x, r->y, r->width, r->height));
}
@ -2378,33 +2373,33 @@ nsWindow::OnExposeEvent(GtkWidget *aWidget, GdkEventExpose *aEvent)
kid->GetBounds(bounds);
for (PRUint32 i = 0; i < clipRects.Length(); ++i) {
nsIntRect r = clipRects[i] + bounds.TopLeft();
updateRegion->Subtract(r.x, r.y, r.width, r.height);
event.region.Sub(event.region, r);
}
}
children = children->next;
}
}
if (updateRegion->IsEmpty()) {
if (event.region.IsEmpty()) {
g_free(rects);
return TRUE;
}
#ifdef MOZ_DFB
nsCOMPtr<nsIRenderingContext> rc = getter_AddRefs(GetRenderingContext());
if (NS_UNLIKELY(!rc)) {
nsRefPtr<gfxContext> ctx = new gfxContext(GetThebesSurface());
if (NS_UNLIKELY(!ctx)) {
g_free(rects);
return FALSE;
}
// do double-buffering and clipping here
nsRefPtr<gfxContext> ctx = rc->ThebesContext();
// The context that we'll actually paint into. When we're double-
// buffering, this can be different from ctx.
nsRefPtr<gfxContext> paintCtx = ctx;
#ifdef MOZ_DFB
gfxPlatformGtk::GetPlatform()->SetGdkDrawable(ctx->OriginalSurface(),
GDK_DRAWABLE(mGdkWindow));
// clip to the update region
ctx->Save();
ctx->NewPath();
for (r = rects; r < r_end; ++r) {
ctx->Rectangle(gfxRect(r->x, r->y, r->width, r->height));
@ -2413,25 +2408,13 @@ nsWindow::OnExposeEvent(GtkWidget *aWidget, GdkEventExpose *aEvent)
#endif
#ifdef MOZ_X11
nsCOMPtr<nsIRenderingContext> rc = getter_AddRefs(GetRenderingContext());
if (NS_UNLIKELY(!rc)) {
g_free(rects);
return FALSE;
}
nsIntRect boundsRect;
nsIntRect boundsRect = event.region.GetBounds();
GdkPixmap* bufferPixmap = nsnull;
gfxIntSize bufferPixmapSize;
nsRefPtr<gfxASurface> bufferPixmapSurface;
updateRegion->GetBoundingBox(&boundsRect.x, &boundsRect.y,
&boundsRect.width, &boundsRect.height);
// do double-buffering and clipping here
nsRefPtr<gfxContext> ctx = rc->ThebesContext();
ctx->Save();
ctx->NewPath();
if (translucent) {
// Collapse update area to the bounding box. This is so we only have to
@ -2515,18 +2498,11 @@ nsWindow::OnExposeEvent(GtkWidget *aWidget, GdkEventExpose *aEvent)
GDK_DRAWABLE(bufferPixmap));
bufferPixmapSurface->SetDeviceOffset(gfxPoint(-boundsRect.x, -boundsRect.y));
nsCOMPtr<nsIRenderingContext> newRC;
nsresult rv = GetDeviceContext()->
CreateRenderingContextInstance(*getter_AddRefs(newRC));
if (NS_FAILED(rv)) {
bufferPixmapSurface = nsnull;
nsRefPtr<gfxContext> newCtx = new gfxContext(bufferPixmapSurface);
if (newCtx) {
paintCtx = newCtx.forget();
} else {
rv = newRC->Init(GetDeviceContext(), bufferPixmapSurface);
if (NS_FAILED(rv)) {
bufferPixmapSurface = nsnull;
} else {
rc = newRC;
}
bufferPixmapSurface = nsnull;
}
}
}
@ -2544,15 +2520,11 @@ nsWindow::OnExposeEvent(GtkWidget *aWidget, GdkEventExpose *aEvent)
#endif // MOZ_X11
nsPaintEvent event(PR_TRUE, NS_PAINT, this);
event.refPoint.x = aEvent->area.x;
event.refPoint.y = aEvent->area.y;
event.rect = nsnull;
event.region = updateRegion;
event.renderingContext = rc;
nsEventStatus status;
DispatchEvent(&event, status);
{
AutoLayerManagerSetup setupLayerManager(this, paintCtx);
DispatchEvent(&event, status);
}
#ifdef MOZ_X11
// DispatchEvent can Destroy us (bug 378273), avoid doing any paint
@ -2598,15 +2570,9 @@ nsWindow::OnExposeEvent(GtkWidget *aWidget, GdkEventExpose *aEvent)
// if we had to allocate a local pixmap, free it here
if (bufferPixmap && bufferPixmap != gBufferPixmap)
g_object_unref(G_OBJECT(bufferPixmap));
ctx->Restore();
}
#endif // MOZ_X11
#ifdef MOZ_DFB
ctx->Restore();
#endif
g_free(rects);
// check the return value!

View File

@ -1,4 +1,4 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
./* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* vim:expandtab:shiftwidth=4:tabstop=4:
*/
/* ***** BEGIN LICENSE BLOCK *****
@ -1012,23 +1012,18 @@ nsWindow::DoPaint(QPainter* aPainter, const QStyleOptionGraphicsItem* aOption)
nsRefPtr<gfxContext> ctx = new gfxContext(targetSurface);
nsCOMPtr<nsIRenderingContext> rc;
GetDeviceContext()->CreateRenderingContextInstance(*getter_AddRefs(rc));
if (NS_UNLIKELY(!rc))
return nsEventStatus_eIgnore;
rc->Init(GetDeviceContext(), ctx);
nsPaintEvent event(PR_TRUE, NS_PAINT, this);
nsIntRect rect(r.x(), r.y(), r.width(), r.height());
event.refPoint.x = r.x();
event.refPoint.y = r.y();
event.rect = &rect;
event.region = nsnull;
event.renderingContext = rc;
event.region = nsIntRegion(rect);
nsEventStatus status = DispatchEvent(&event);
nsEventStatus status;
{
AutoLayerManagerSetup setupLayerManager(this, ctx);
status = DispatchEvent(&event);
}
// DispatchEvent can Destroy us (bug 378273), avoid doing any paint
// operations below if that happened - it will lead to XError and exit().

View File

@ -402,7 +402,7 @@ protected:
static void SetupKeyModifiersSequence(nsTArray<KeyPair>* aArray, PRUint32 aModifiers);
nsresult SetWindowClipRegion(const nsTArray<nsIntRect>& aRects,
PRBool aIntersectWithExisting);
nsCOMPtr<nsIRegion> GetRegionToPaint(PRBool aForceFullRepaint,
nsIntRegion GetRegionToPaint(PRBool aForceFullRepaint,
PAINTSTRUCT ps, HDC aDC);
#if !defined(WINCE)
static void ActivateOtherWindowHelper(HWND aWnd);

View File

@ -133,44 +133,34 @@ IsRenderMode(gfxWindowsPlatform::RenderMode rmode)
return gfxWindowsPlatform::GetPlatform()->GetRenderMode() == rmode;
}
void
nsWindowGfx::AddRECTToRegion(const RECT& aRect, nsIRegion* aRegion)
{
aRegion->Union(aRect.left, aRect.top, aRect.right - aRect.left, aRect.bottom - aRect.top);
}
already_AddRefed<nsIRegion>
nsIntRegion
nsWindowGfx::ConvertHRGNToRegion(HRGN aRgn)
{
NS_ASSERTION(aRgn, "Don't pass NULL region here");
nsCOMPtr<nsIRegion> region = do_CreateInstance(kRegionCID);
if (!region)
return nsnull;
region->Init();
nsIntRegion rgn;
DWORD size = ::GetRegionData(aRgn, 0, NULL);
nsAutoTArray<PRUint8,100> buffer;
if (!buffer.SetLength(size))
return region.forget();
return rgn;
RGNDATA* data = reinterpret_cast<RGNDATA*>(buffer.Elements());
if (!::GetRegionData(aRgn, size, data))
return region.forget();
return rgn;
if (data->rdh.nCount > MAX_RECTS_IN_REGION) {
AddRECTToRegion(data->rdh.rcBound, region);
return region.forget();
rgn = ToIntRect(data->rdh.rcBound);
return rgn;
}
RECT* rects = reinterpret_cast<RECT*>(data->Buffer);
for (PRUint32 i = 0; i < data->rdh.nCount; ++i) {
RECT* r = rects + i;
AddRECTToRegion(*r, region);
rgn.Or(rgn, ToIntRect(*r));
}
return region.forget();
return rgn;
}
#ifdef CAIRO_HAS_DDRAW_SURFACE
@ -253,24 +243,17 @@ void nsWindow::SetUpForPaint(HDC aHDC)
// it's abstracted out because Windows XP/Vista/7 handles this for us, but
// we need to keep track of it our selves for Windows CE and Windows Mobile
nsCOMPtr<nsIRegion> nsWindow::GetRegionToPaint(PRBool aForceFullRepaint,
PAINTSTRUCT ps, HDC aDC)
nsIntRegion nsWindow::GetRegionToPaint(PRBool aForceFullRepaint,
PAINTSTRUCT ps, HDC aDC)
{
HRGN paintRgn = NULL;
nsCOMPtr<nsIRegion> paintRgnWin;
if (aForceFullRepaint) {
RECT paintRect;
::GetClientRect(mWnd, &paintRect);
paintRgn = ::CreateRectRgn(paintRect.left, paintRect.top,
paintRect.right, paintRect.bottom);
if (paintRgn) {
paintRgnWin = nsWindowGfx::ConvertHRGNToRegion(paintRgn);
::DeleteObject(paintRgn);
return paintRgnWin;
}
return nsIntRegion(nsWindowGfx::ToIntRect(paintRect));
}
#ifndef WINCE
paintRgn = ::CreateRectRgn(0, 0, 0, 0);
HRGN paintRgn = ::CreateRectRgn(0, 0, 0, 0);
if (paintRgn != NULL) {
int result = GetRandomRgn(aDC, paintRgn, SYSRGN);
if (result == 1) {
@ -278,12 +261,13 @@ nsCOMPtr<nsIRegion> nsWindow::GetRegionToPaint(PRBool aForceFullRepaint,
::MapWindowPoints(NULL, mWnd, &pt, 1);
::OffsetRgn(paintRgn, pt.x, pt.y);
}
paintRgnWin = nsWindowGfx::ConvertHRGNToRegion(paintRgn);
nsIntRegion rgn(nsWindowGfx::ConvertHRGNToRegion(paintRgn));
::DeleteObject(paintRgn);
return rgn;
}
#else
# ifdef WINCE_WINDOWS_MOBILE
paintRgn = ::CreateRectRgn(0, 0, 0, 0);
HRGN paintRgn = ::CreateRectRgn(0, 0, 0, 0);
if (paintRgn != NULL) {
int result = GetUpdateRgn(mWnd, paintRgn, FALSE);
if (result == 1) {
@ -291,18 +275,13 @@ nsCOMPtr<nsIRegion> nsWindow::GetRegionToPaint(PRBool aForceFullRepaint,
::MapWindowPoints(NULL, mWnd, &pt, 1);
::OffsetRgn(paintRgn, pt.x, pt.y);
}
paintRgnWin = nsWindowGfx::ConvertHRGNToRegion(paintRgn);
nsIntRegion rgn(nsWindowGfx::ConvertHRGNToRegion(paintRgn));
::DeleteObject(paintRgn);
return rgn;
}
# endif
paintRgn = ::CreateRectRgn(ps.rcPaint.left, ps.rcPaint.top,
ps.rcPaint.right, ps.rcPaint.bottom);
if (paintRgn) {
paintRgnWin = nsWindowGfx::ConvertHRGNToRegion(paintRgn);
::DeleteObject(paintRgn);
}
#endif
return paintRgnWin;
return nsIntRegion(nsWindowGfx::ToIntRect(ps.rcPaint));
}
#define WORDSSIZE(x) ((x).width * (x).height)
@ -416,25 +395,19 @@ PRBool nsWindow::OnPaint(HDC aDC)
mPaintDC = hDC;
}
// generate the event and call the event callback
nsPaintEvent event(PR_TRUE, NS_PAINT, this);
InitEvent(event);
#ifdef MOZ_XUL
PRBool forceRepaint = aDC || (eTransparencyTransparent == mTransparencyMode);
#else
PRBool forceRepaint = NULL != aDC;
#endif
nsCOMPtr<nsIRegion> paintRgnWin = GetRegionToPaint(forceRepaint, ps, hDC);
event.region = GetRegionToPaint(forceRepaint, ps, hDC);
if (paintRgnWin &&
!paintRgnWin->IsEmpty() &&
mEventCallback)
if (!event.region.IsEmpty() && mEventCallback)
{
// generate the event and call the event callback
nsPaintEvent event(PR_TRUE, NS_PAINT, this);
InitEvent(event);
event.region = paintRgnWin;
event.rect = nsnull;
// 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
@ -573,23 +546,11 @@ DDRAW_FAILED:
}
}
nsCOMPtr<nsIRenderingContext> rc;
nsresult rv = mContext->CreateRenderingContextInstance (*getter_AddRefs(rc));
if (NS_FAILED(rv)) {
NS_WARNING("CreateRenderingContextInstance failed");
return PR_FALSE;
{
AutoLayerManagerSetup setupLayerManager(this, thebesContext);
result = DispatchWindowEvent(&event, eventStatus);
}
rv = rc->Init(mContext, thebesContext);
if (NS_FAILED(rv)) {
NS_WARNING("RC::Init failed");
return PR_FALSE;
}
event.renderingContext = rc;
result = DispatchWindowEvent(&event, eventStatus);
event.renderingContext = nsnull;
#ifdef MOZ_XUL
if (IsRenderMode(gfxWindowsPlatform::RENDER_GDI) &&
eTransparencyTransparent == mTransparencyMode) {
@ -957,9 +918,7 @@ PRBool nsWindow::OnPaintImageDDraw16()
gfxIntSize surfaceSize;
nsRefPtr<gfxImageSurface> targetSurfaceImage;
nsRefPtr<gfxContext> thebesContext;
nsCOMPtr<nsIRenderingContext> rc;
nsEventStatus eventStatus = nsEventStatus_eIgnore;
PRInt32 brx, bry, brw, brh;
gfxIntSize newSize;
newSize.height = GetSystemMetrics(SM_CYSCREEN);
newSize.width = GetSystemMetrics(SM_CXSCREEN);
@ -967,18 +926,15 @@ PRBool nsWindow::OnPaintImageDDraw16()
HDC hDC = ::BeginPaint(mWnd, &ps);
mPaintDC = hDC;
nsCOMPtr<nsIRegion> paintRgnWin = GetRegionToPaint(PR_FALSE, ps, hDC);
nsIntRegion paintRgn = GetRegionToPaint(PR_FALSE, ps, hDC);
if (!paintRgnWin || paintRgnWin->IsEmpty() || !mEventCallback) {
if (paintRgn.IsEmpty() || !mEventCallback) {
result = PR_TRUE;
goto cleanup;
}
InitEvent(event);
event.region = paintRgnWin;
event.rect = nsnull;
if (!glpDD) {
if (!nsWindowGfx::InitDDraw()) {
NS_WARNING("DirectDraw init failed. Giving up.");
@ -1014,7 +970,10 @@ PRBool nsWindow::OnPaintImageDDraw16()
}
}
paintRgnWin->GetBoundingBox(&brx, &bry, &brw, &brh);
PRInt32 brx = paintRgn.GetBounds().x;
PRInt32 bry = paintRgn.GetBounds().y;
PRInt32 brw = paintRgn.GetBounds().width;
PRInt32 brh = paintRgn.GetBounds().height;
surfaceSize = gfxIntSize(brw, brh);
if (!EnsureSharedSurfaceSize(surfaceSize))
@ -1034,25 +993,15 @@ PRBool nsWindow::OnPaintImageDDraw16()
thebesContext->SetFlag(gfxContext::FLAG_DESTINED_FOR_SCREEN);
thebesContext->SetFlag(gfxContext::FLAG_SIMPLIFY_OPERATORS);
nsresult rv = mContext->CreateRenderingContextInstance (*getter_AddRefs(rc));
if (NS_FAILED(rv))
goto cleanup;
{
AutoLayerManagerSetup setupLayerManager(this, thebesContext);
event.region = paintRgn;
result = DispatchWindowEvent(&event, eventStatus);
}
rv = rc->Init(mContext, thebesContext);
if (NS_FAILED(rv))
goto cleanup;
event.renderingContext = rc;
PRBool res = DispatchWindowEvent(&event, eventStatus);
event.renderingContext = nsnull;
if (!res && eventStatus == nsEventStatus_eConsumeNoDefault)
if (!result && eventStatus == nsEventStatus_eConsumeNoDefault)
goto cleanup;
nsRegionRectSet *rects = nsnull;
RECT r;
paintRgnWin->GetRects(&rects);
HRESULT hr = glpDDSecondary->Lock(0, &gDDSDSecondary, DDLOCK_WAITNOTBUSY | DDLOCK_DISCARD, 0);
if (FAILED(hr))
goto cleanup;
@ -1070,14 +1019,15 @@ PRBool nsWindow::OnPaintImageDDraw16()
gDDSDSecondary.dwWidth * 2);
for (unsigned int i = 0; i < rects->mNumRects; i++) {
const nsIntRect* r;
for (nsIntRegionRectIterator iter(paintRgn);
(r = iter.Next()) != nsnull;) {
pixman_image_composite(PIXMAN_OP_SRC, srcPixmanImage, NULL, dstPixmanImage,
rects->mRects[i].x - brx, rects->mRects[i].y - bry,
0, 0,
rects->mRects[i].x, rects->mRects[i].y,
rects->mRects[i].width, rects->mRects[i].height);
}
r->x - brx, r->y - bry,
0, 0,
r->x, r->y,
r->width, r->height);
}
pixman_image_unref(dstPixmanImage);
pixman_image_unref(srcPixmanImage);
@ -1090,15 +1040,13 @@ PRBool nsWindow::OnPaintImageDDraw16()
if (FAILED(hr))
goto cleanup;
for (unsigned int i = 0; i < rects->mNumRects; i++) {
r.left = rects->mRects[i].x;
r.top = rects->mRects[i].y;
r.right = rects->mRects[i].width + rects->mRects[i].x;
r.bottom = rects->mRects[i].height + rects->mRects[i].y;
RECT renderRect = r;
for (nsIntRegionRectIterator iter(paintRgn);
(r = iter.Next()) != nsnull;) {
RECT wr = { r->x, r->y, r->XMost(), r->YMost() };
RECT renderRect = wr;
SetLastError(0); // See http://msdn.microsoft.com/en-us/library/dd145046%28VS.85%29.aspx
MapWindowPoints(mWnd, 0, (LPPOINT)&renderRect, 2);
hr = glpDDPrimary->Blt(&renderRect, glpDDSecondary, &r, 0, NULL);
hr = glpDDPrimary->Blt(&renderRect, glpDDSecondary, &wr, 0, NULL);
if (FAILED(hr)) {
NS_ERROR("this blt should never fail!");
printf("#### %s blt failed: %08lx", __FUNCTION__, hr);

View File

@ -56,8 +56,13 @@
class nsWindowGfx {
public:
static void AddRECTToRegion(const RECT& aRect, nsIRegion* aRegion);
static already_AddRefed<nsIRegion> ConvertHRGNToRegion(HRGN aRgn);
static nsIntRect ToIntRect(const RECT& aRect)
{
return nsIntRect(aRect.left, aRect.top,
aRect.right - aRect.left, aRect.bottom - aRect.top);
}
static nsIntRegion ConvertHRGNToRegion(HRGN aRgn);
static void OnSettingsChangeGfx(WPARAM wParam);
#if defined(CAIRO_HAS_DDRAW_SURFACE)

View File

@ -49,6 +49,7 @@
#include "nsIServiceManager.h"
#include "nsIPrefService.h"
#include "nsIPrefBranch2.h"
#include "BasicLayers.h"
#ifdef DEBUG
#include "nsIObserver.h"
@ -62,6 +63,8 @@ static PRBool debug_InSecureKeyboardInputMode = PR_FALSE;
static PRInt32 gNumWidgets;
#endif
using namespace mozilla::layers;
nsIContent* nsBaseWidget::mLastRollup = nsnull;
// nsBaseWidget
@ -629,6 +632,34 @@ NS_IMETHODIMP nsBaseWidget::MakeFullScreen(PRBool aFullScreen)
return NS_OK;
}
nsBaseWidget::AutoLayerManagerSetup::AutoLayerManagerSetup(
nsBaseWidget* aWidget, gfxContext* aTarget)
: mWidget(aWidget)
{
BasicLayerManager* manager =
static_cast<BasicLayerManager*>(mWidget->GetLayerManager());
if (manager) {
manager->SetDefaultTarget(aTarget);
}
}
nsBaseWidget::AutoLayerManagerSetup::~AutoLayerManagerSetup()
{
BasicLayerManager* manager =
static_cast<BasicLayerManager*>(mWidget->GetLayerManager());
if (manager) {
manager->SetDefaultTarget(nsnull);
}
}
LayerManager* nsBaseWidget::GetLayerManager()
{
if (!mLayerManager) {
mLayerManager = new BasicLayerManager(nsnull);
}
return mLayerManager;
}
//-------------------------------------------------------------------------
//
// Create a rendering context from this nsBaseWidget
@ -1331,20 +1362,6 @@ nsBaseWidget::debug_DumpPaintEvent(FILE * aFileOut,
aWidgetName.get(),
(void *) aWindowID);
if (aPaintEvent->rect)
{
fprintf(aFileOut,
"%3d,%-3d %3d,%-3d",
aPaintEvent->rect->x,
aPaintEvent->rect->y,
aPaintEvent->rect->width,
aPaintEvent->rect->height);
}
else
{
fprintf(aFileOut,"none");
}
fprintf(aFileOut,"\n");
}
//////////////////////////////////////////////////////////////

View File

@ -49,6 +49,7 @@
class nsIContent;
class nsAutoRollup;
class gfxContext;
/**
* Common widget implementation used as base class for native
@ -107,7 +108,8 @@ public:
NS_IMETHOD MakeFullScreen(PRBool aFullScreen);
virtual nsIRenderingContext* GetRenderingContext();
virtual nsIDeviceContext* GetDeviceContext();
virtual nsIToolkit* GetToolkit();
virtual nsIToolkit* GetToolkit();
virtual LayerManager* GetLayerManager();
virtual gfxASurface* GetThebesSurface();
NS_IMETHOD SetModal(PRBool aModal);
NS_IMETHOD SetWindowClass(const nsAString& xulWinType);
@ -141,6 +143,20 @@ public:
NS_IMETHOD OnDefaultButtonLoaded(const nsIntRect &aButtonRect) { return NS_ERROR_NOT_IMPLEMENTED; }
NS_IMETHOD OverrideSystemMouseScrollSpeed(PRInt32 aOriginalDelta, PRBool aIsHorizontal, PRInt32 &aOverriddenDelta);
/**
* Use this when GetLayerManager() returns a BasicLayerManager
* (nsBaseWidget::GetLayerManager() does). This sets up the widget's
* layer manager to temporarily render into aTarget.
*/
class AutoLayerManagerSetup {
public:
AutoLayerManagerSetup(nsBaseWidget* aWidget, gfxContext* aTarget);
~AutoLayerManagerSetup();
private:
nsBaseWidget* mWidget;
};
friend class AutoLayerManagerSetup;
protected:
virtual void ResolveIconName(const nsAString &aIconName,
@ -179,8 +195,9 @@ protected:
protected:
void* mClientData;
EVENT_CALLBACK mEventCallback;
nsIDeviceContext *mContext;
nsIToolkit *mToolkit;
nsIDeviceContext* mContext;
nsIToolkit* mToolkit;
nsRefPtr<LayerManager> mLayerManager;
nscolor mBackground;
nscolor mForeground;
nsCursor mCursor;