Bug 339548. Part 3: Introduce native widget clip region API.

This commit is contained in:
Robert O'Callahan 2009-07-22 12:44:55 +12:00
Родитель ae3ec428cc
Коммит 319a670036
12 изменённых файлов: 276 добавлений и 28 удалений

Просмотреть файл

@ -542,7 +542,8 @@ void nsViewManager::AddCoveringWidgetsToOpaqueRegion(nsRegion &aRgn, nsIDeviceCo
// We may be required to paint behind them
aRgn.SetEmpty();
nsIWidget* widget = aRootView->GetNearestWidget(nsnull);
nsPoint offsetToWidget;
nsIWidget* widget = aRootView->GetNearestWidget(&offsetToWidget);
if (!widget) {
return;
}
@ -557,24 +558,19 @@ void nsViewManager::AddCoveringWidgetsToOpaqueRegion(nsRegion &aRgn, nsIDeviceCo
PRBool widgetVisible;
childWidget->IsVisible(widgetVisible);
if (widgetVisible) {
nsTArray<nsIntRect> clipRects;
childWidget->GetWindowClipRegion(&clipRects);
nsView* view = nsView::GetViewFor(childWidget);
if (view && view->GetVisibility() == nsViewVisibility_kShow
&& !view->GetFloating()) {
nsRect bounds = view->GetBounds();
if (bounds.width > 0 && bounds.height > 0) {
nsView* viewParent = view->GetParent();
while (viewParent && viewParent != aRootView) {
viewParent->ConvertToParentCoords(&bounds.x, &bounds.y);
viewParent = viewParent->GetParent();
}
// maybe we couldn't get the view into the coordinate
// system of aRootView (maybe it's not a descendant
// view of aRootView?); if so, don't use it
if (viewParent) {
aRgn.Or(aRgn, bounds);
}
nsIntRect bounds;
childWidget->GetBounds(bounds);
for (PRUint32 i = 0; i < clipRects.Length(); ++i) {
nsIntRect r = clipRects[i] + bounds.TopLeft();
nsRect rr = r.ToAppUnits(mContext->AppUnitsPerDevPixel()) -
offsetToWidget;
aRgn.Or(aRgn, rr);
}
}
}
@ -831,8 +827,17 @@ nsViewManager::UpdateWidgetArea(nsView *aWidgetView, const nsRegion &aDamagedReg
nsPoint offset = view->GetOffsetTo(aWidgetView);
damage.MoveBy(-offset);
UpdateWidgetArea(view, damage, aIgnoreWidgetView);
children.Or(children, view->GetDimensions() + offset);
children.SimplifyInward(20);
nsIntRect bounds;
childWidget->GetBounds(bounds);
nsTArray<nsIntRect> clipRects;
childWidget->GetWindowClipRegion(&clipRects);
for (PRUint32 i = 0; i < clipRects.Length(); ++i) {
nsRect rr = (clipRects[i] + bounds.TopLeft()).
ToAppUnits(mContext->AppUnitsPerDevPixel());
children.Or(children, rr - aWidgetView->ViewToWidgetOffset());
children.SimplifyInward(20);
}
}
}
}

Просмотреть файл

@ -49,6 +49,7 @@
#include "nsITheme.h"
#include "nsNativeWidget.h"
#include "nsWidgetInitData.h"
#include "nsTArray.h"
// forward declarations
class nsIAppShell;
@ -100,10 +101,9 @@ typedef nsEventStatus (* EVENT_CALLBACK)(nsGUIEvent *event);
#define NS_NATIVE_TSF_DISPLAY_ATTR_MGR 102
#endif
// {a395289d-b344-42c3-ae7e-34d64282b6e0}
#define NS_IWIDGET_IID \
{ 0xa395289d, 0xb344, 0x42c3, \
{ 0xae, 0x7e, 0x34, 0xd6, 0x42, 0x82, 0xb6, 0xe0 } }
{ 0x8f0869be, 0x6a53, 0x4f21, \
{ 0xa9, 0x64, 0x90, 0xd9, 0x26, 0x04, 0x05, 0xa3 } }
/*
* Window shadow styles
@ -608,6 +608,37 @@ class nsIWidget : public nsISupports {
*/
virtual nsTransparencyMode GetTransparencyMode() = 0;
/**
* This represents a command to set the bounds and clip region of
* a child widget.
*/
struct Configuration {
nsIWidget* mChild;
nsIntRect mBounds;
nsTArray<nsIntRect> mClipRegion;
};
/**
* Sets the clip region of each mChild (which must actually be a child
* of this widget) to the union of the pixel rects given in
* mClipRegion, all relative to the top-left of the child
* widget. Clip regions are not implemented on all platforms and only
* need to actually work for children that are plugins.
*
* Also sets the bounds of each child to mBounds.
*
* This will invalidate areas of the children that have changed, but
* does not need to invalidate any part of this widget.
*/
virtual nsresult ConfigureChildren(const nsTArray<Configuration>& aConfigurations) = 0;
/**
* Appends to aRects the rectangles constituting this widget's clip
* region. If this widget is not clipped, appends a single rectangle
* (0, 0, bounds.width, bounds.height).
*/
virtual void GetWindowClipRegion(nsTArray<nsIntRect>* aRects) = 0;
/**
* Set the shadow style of the window.
*/

Просмотреть файл

@ -349,6 +349,7 @@ public:
NS_IMETHOD Validate();
virtual void* GetNativeData(PRUint32 aDataType);
virtual nsresult ConfigureChildren(const nsTArray<Configuration>& aConfigurations);
NS_IMETHOD Scroll(PRInt32 aDx, PRInt32 aDy, nsIntRect *aClipRect);
virtual nsIntPoint WidgetToScreenOffset();
NS_IMETHOD BeginResizingChildren(void);
@ -416,6 +417,11 @@ public:
static PRBool DoHasPendingInputEvent();
static PRUint32 GetCurrentInputEventCount();
static void UpdateCurrentInputEventCount();
static void ApplyConfiguration(nsIWidget* aExpectedParent,
const nsIWidget::Configuration& aConfiguration,
PRBool aRepaint);
protected:
PRBool ReportDestroyEvent();

Просмотреть файл

@ -1258,13 +1258,27 @@ NS_IMETHODIMP nsChildView::GetPluginClipRect(nsIntRect& outClipRect, nsIntPoint&
outClipRect.x = NSToIntRound(clipOrigin.x);
outClipRect.y = NSToIntRound(clipOrigin.y);
// need to convert view's origin to window coordinates.
// then, encode as "SetOrigin" ready values.
outOrigin.x = -NSToIntRound(viewOrigin.x);
outOrigin.y = -NSToIntRound(viewOrigin.y);
PRBool isVisible;
IsVisible(isVisible);
if (isVisible && [mView window] != nil) {
outClipRect.width = NSToIntRound(visibleBounds.origin.x + visibleBounds.size.width) - NSToIntRound(visibleBounds.origin.x);
outClipRect.height = NSToIntRound(visibleBounds.origin.y + visibleBounds.size.height) - NSToIntRound(visibleBounds.origin.y);
if (mClipRects) {
nsIntRect clipBounds;
for (PRUint32 i = 0; i < mClipRectCount; ++i) {
clipBounds.UnionRect(clipBounds, mClipRects[i]);
}
outClipRect.IntersectRect(outClipRect, clipBounds - outOrigin);
}
// XXXroc should this be !outClipRect.IsEmpty()?
outWidgetVisible = PR_TRUE;
}
else {
@ -1273,11 +1287,6 @@ NS_IMETHODIMP nsChildView::GetPluginClipRect(nsIntRect& outClipRect, nsIntPoint&
outWidgetVisible = PR_FALSE;
}
// need to convert view's origin to window coordinates.
// then, encode as "SetOrigin" ready values.
outOrigin.x = -NSToIntRound(viewOrigin.x);
outOrigin.y = -NSToIntRound(viewOrigin.y);
return NS_OK;
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
@ -1688,6 +1697,36 @@ NS_IMETHODIMP nsChildView::Update()
#pragma mark -
void nsChildView::ApplyConfiguration(nsIWidget* aExpectedParent,
const nsIWidget::Configuration& aConfiguration,
PRBool aRepaint)
{
#ifdef DEBUG
nsWindowType kidType;
aConfiguration.mChild->GetWindowType(kidType);
#endif
NS_ASSERTION(kidType == eWindowType_child,
"Configured widget is not a child type");
NS_ASSERTION(aConfiguration.mChild->GetParent() == aExpectedParent,
"Configured widget is not a child of the right widget");
aConfiguration.mChild->Resize(
aConfiguration.mBounds.x, aConfiguration.mBounds.y,
aConfiguration.mBounds.width, aConfiguration.mBounds.height,
aRepaint);
// On Mac we don't use the clip region here, we just store it
// in case GetPluginClipRect needs it.
static_cast<nsChildView*>(aConfiguration.mChild)->
StoreWindowClipRegion(aConfiguration.mClipRegion);
}
nsresult nsChildView::ConfigureChildren(const nsTArray<Configuration>& aConfigurations)
{
for (PRUint32 i = 0; i < aConfigurations.Length(); ++i) {
nsChildView::ApplyConfiguration(this, aConfigurations[i], PR_TRUE);
}
return NS_OK;
}
// Scroll the bits of a view and its children
// FIXME: I'm sure the invalidating can be optimized, just no time now.
NS_IMETHODIMP nsChildView::Scroll(PRInt32 aDx, PRInt32 aDy, nsIntRect *aClipRect)

Просмотреть файл

@ -226,6 +226,7 @@ public:
NS_IMETHOD Invalidate(const nsIntRect &aRect, PRBool aIsSynchronous);
NS_IMETHOD Invalidate(PRBool aIsSynchronous);
NS_IMETHOD Update();
virtual nsresult ConfigureChildren(const nsTArray<Configuration>& aConfigurations);
NS_IMETHOD Scroll(PRInt32 aDx, PRInt32 aDy, nsIntRect *alCipRect) { return NS_OK; }
NS_IMETHOD BeginResizingChildren(void) { return NS_OK; }
NS_IMETHOD EndResizingChildren(void) { return NS_OK; }

Просмотреть файл

@ -810,6 +810,15 @@ NS_IMETHODIMP nsCocoaWindow::Show(PRBool bState)
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
}
nsresult
nsCocoaWindow::ConfigureChildren(const nsTArray<Configuration>& aConfigurations)
{
for (PRUint32 i = 0; i < aConfigurations.Length(); ++i) {
nsChildView::ApplyConfiguration(this, aConfigurations[i], PR_TRUE);
}
return NS_OK;
}
void nsCocoaWindow::MakeBackgroundTransparent(PRBool aTransparent)
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;

Просмотреть файл

@ -67,6 +67,7 @@
#include "gtk2xtbin.h"
#endif /* MOZ_X11 */
#include <gdk/gdkkeysyms.h>
#include <gtk/gtkprivate.h>
#include "nsWidgetAtoms.h"
@ -3898,6 +3899,9 @@ nsWindow::NativeCreate(nsIWidget *aParent,
gtk_container_add(GTK_CONTAINER(mShell), GTK_WIDGET(mContainer));
gtk_widget_realize(GTK_WIDGET(mContainer));
// Don't let GTK mess with the shapes of our GdkWindows
GTK_PRIVATE_SET_FLAG(GTK_WIDGET(mContainer), GTK_HAS_SHAPE_MASK);
// make sure this is the focus widget in the container
gtk_window_set_focus(GTK_WINDOW(mShell), GTK_WIDGET(mContainer));
@ -3925,6 +3929,9 @@ nsWindow::NativeCreate(nsIWidget *aParent,
gtk_container_add(parentGtkContainer, GTK_WIDGET(mContainer));
gtk_widget_realize(GTK_WIDGET(mContainer));
// Don't let GTK mess with the shapes of our GdkWindows
GTK_PRIVATE_SET_FLAG(GTK_WIDGET(mContainer), GTK_HAS_SHAPE_MASK);
mDrawingarea = moz_drawingarea_new(nsnull, mContainer, visual);
}
else {
@ -4396,6 +4403,50 @@ nsWindow::GetTransparencyMode()
return mIsTransparent ? eTransparencyTransparent : eTransparencyOpaque;
}
nsresult
nsWindow::ConfigureChildren(const nsTArray<Configuration>& aConfigurations)
{
for (PRUint32 i = 0; i < aConfigurations.Length(); ++i) {
const Configuration& configuration = aConfigurations[i];
nsWindow* w = static_cast<nsWindow*>(configuration.mChild);
NS_ASSERTION(w->GetParent() == this,
"Configured widget is not a child");
nsresult rv = w->SetWindowClipRegion(configuration.mClipRegion);
NS_ENSURE_SUCCESS(rv, rv);
if (w->mBounds.Size() != configuration.mBounds.Size()) {
w->Resize(configuration.mBounds.x, configuration.mBounds.y,
configuration.mBounds.width, configuration.mBounds.height,
PR_TRUE);
} else if (w->mBounds.TopLeft() != configuration.mBounds.TopLeft()) {
w->Move(configuration.mBounds.x, configuration.mBounds.y);
}
}
return NS_OK;
}
nsresult
nsWindow::SetWindowClipRegion(const nsTArray<nsIntRect>& aRects)
{
StoreWindowClipRegion(aRects);
if (!mDrawingarea)
return NS_OK;
GdkRegion *region = gdk_region_new();
if (!region)
return NS_ERROR_OUT_OF_MEMORY;
for (PRUint32 i = 0; i < aRects.Length(); ++i) {
const nsIntRect& r = aRects[i];
GdkRectangle rect = { r.x, r.y, r.width, r.height };
gdk_region_union_with_rect(region, &rect);
}
gdk_window_shape_combine_region(mDrawingarea->clip_window, region, 0, 0);
gdk_region_destroy(region);
return NS_OK;
}
void
nsWindow::ResizeTransparencyBitmap(PRInt32 aNewWidth, PRInt32 aNewHeight)
{

Просмотреть файл

@ -415,6 +415,7 @@ public:
void ApplyTransparencyBitmap();
virtual void SetTransparencyMode(nsTransparencyMode aMode);
virtual nsTransparencyMode GetTransparencyMode();
virtual nsresult ConfigureChildren(const nsTArray<Configuration>& aConfigurations);
nsresult UpdateTranslucentWindowAlphaInternal(const nsIntRect& aRect,
PRUint8* aAlphas, PRInt32 aStride);
@ -466,6 +467,7 @@ private:
void SetDefaultIcon(void);
void InitButtonEvent(nsMouseEvent &aEvent, GdkEventButton *aGdkEvent);
PRBool DispatchCommandEvent(nsIAtom* aCommand);
nsresult SetWindowClipRegion(const nsTArray<nsIntRect>& aRects);
GtkWidget *mShell;
MozContainer *mContainer;

Просмотреть файл

@ -5492,6 +5492,79 @@ nsWindow::SetupKeyModifiersSequence(nsTArray<KeyPair>* aArray, PRUint32 aModifie
}
}
nsresult
nsWindow::ConfigureChildren(const nsTArray<Configuration>& aConfigurations)
{
// XXXroc we could use BeginDeferWindowPos/DeferWindowPos/EndDeferWindowPos
// here, if that helps in some situations. So far I haven't seen a
// need.
for (PRUint32 i = 0; i < aConfigurations.Length(); ++i) {
const Configuration& configuration = aConfigurations[i];
nsWindow* w = static_cast<nsWindow*>(configuration.mChild);
NS_ASSERTION(w->GetParent() == this,
"Configured widget is not a child");
#ifdef WINCE
// MSDN says we should do on WinCE this before moving or resizing the window
// See http://msdn.microsoft.com/en-us/library/aa930600.aspx
// We put the region back just below, anyway.
::SetWindowRgn(w->mWnd, NULL, TRUE);
#endif
w->Resize(configuration.mBounds.x, configuration.mBounds.y,
configuration.mBounds.width, configuration.mBounds.height,
PR_TRUE);
nsresult rv = w->SetWindowClipRegion(configuration.mClipRegion, PR_FALSE);
NS_ENSURE_SUCCESS(rv, rv);
}
return NS_OK;
}
static HRGN
CreateHRGNFromArray(const nsTArray<nsIntRect>& aRects)
{
PRInt32 size = sizeof(RGNDATAHEADER) + sizeof(RECT)*aRects.Length();
nsAutoTArray<PRUint8,100> buf;
if (!buf.SetLength(size))
return NULL;
RGNDATA* data = reinterpret_cast<RGNDATA*>(buf.Elements());
RECT* rects = reinterpret_cast<RECT*>(data->Buffer);
data->rdh.dwSize = sizeof(data->rdh);
data->rdh.iType = RDH_RECTANGLES;
data->rdh.nCount = aRects.Length();
nsIntRect bounds;
for (PRUint32 i = 0; i < aRects.Length(); ++i) {
const nsIntRect& r = aRects[i];
bounds.UnionRect(bounds, r);
::SetRect(&rects[i], r.x, r.y, r.XMost(), r.YMost());
}
::SetRect(&data->rdh.rcBound, bounds.x, bounds.y, bounds.XMost(), bounds.YMost());
return ::ExtCreateRegion(NULL, buf.Length(), data);
}
nsresult
nsWindow::SetWindowClipRegion(const nsTArray<nsIntRect>& aRects,
PRBool aIntersectWithExisting)
{
HRGN dest = CreateHRGNFromArray(aRects);
if (!dest)
return NS_ERROR_OUT_OF_MEMORY;
if (aIntersectWithExisting) {
HRGN current = ::CreateRectRgn(0, 0, 0, 0);
if (current) {
if (::GetWindowRgn(mWnd, current) != 0 /*ERROR*/) {
::CombineRgn(dest, dest, current, RGN_AND);
}
::DeleteObject(current);
}
}
if (!::SetWindowRgn(mWnd, dest, TRUE)) {
::DeleteObject(dest);
return NS_ERROR_FAILURE;
}
return NS_OK;
}
// WM_DESTROY event handler
void nsWindow::OnDestroy()
{

Просмотреть файл

@ -140,6 +140,7 @@ public:
NS_IMETHOD SetCursor(imgIContainer* aCursor,
PRUint32 aHotspotX, PRUint32 aHotspotY);
NS_IMETHOD SetCursor(nsCursor aCursor);
virtual nsresult ConfigureChildren(const nsTArray<Configuration>& aConfigurations);
NS_IMETHOD MakeFullScreen(PRBool aFullScreen);
NS_IMETHOD HideWindowChrome(PRBool aShouldHide);
NS_IMETHOD Validate();
@ -389,6 +390,8 @@ protected:
void StopFlashing();
static PRBool IsTopLevelMouseExit(HWND aWnd);
static void SetupKeyModifiersSequence(nsTArray<KeyPair>* aArray, PRUint32 aModifiers);
nsresult SetWindowClipRegion(const nsTArray<nsIntRect>& aRects,
PRBool aIntersectWithExisting);
#ifdef ACCESSIBILITY
static STDMETHODIMP_(LRESULT) LresultFromObject(REFIID riid, WPARAM wParam, LPUNKNOWN pAcc);

Просмотреть файл

@ -101,6 +101,7 @@ nsBaseWidget::nsBaseWidget()
, mOnDestroyCalled(PR_FALSE)
, mBounds(0,0,0,0)
, mOriginalBounds(nsnull)
, mClipRectCount(0)
, mZIndex(0)
, mSizeMode(nsSizeMode_Normal)
{
@ -560,6 +561,26 @@ nsTransparencyMode nsBaseWidget::GetTransparencyMode() {
return eTransparencyOpaque;
}
void
nsBaseWidget::StoreWindowClipRegion(const nsTArray<nsIntRect>& aRects)
{
mClipRectCount = aRects.Length();
mClipRects = new nsIntRect[mClipRectCount];
if (mClipRects) {
memcpy(mClipRects, aRects.Elements(), sizeof(nsIntRect)*mClipRectCount);
}
}
void
nsBaseWidget::GetWindowClipRegion(nsTArray<nsIntRect>* aRects)
{
if (mClipRects) {
aRects->AppendElements(mClipRects.get(), mClipRectCount);
} else {
aRects->AppendElement(nsIntRect(0, 0, mBounds.width, mBounds.height));
}
}
//-------------------------------------------------------------------------
//
// Set window shadow style

Просмотреть файл

@ -46,6 +46,7 @@
#include "nsString.h"
#include "nsCOMPtr.h"
#include "nsGUIEvent.h"
#include "nsAutoPtr.h"
class nsIContent;
class nsAutoRollup;
@ -104,6 +105,7 @@ public:
NS_IMETHOD SetWindowType(nsWindowType aWindowType);
virtual void SetTransparencyMode(nsTransparencyMode aMode);
virtual nsTransparencyMode GetTransparencyMode();
virtual void GetWindowClipRegion(nsTArray<nsIntRect>* aRects);
NS_IMETHOD SetWindowShadowStyle(PRInt32 aStyle);
NS_IMETHOD HideWindowChrome(PRBool aShouldHide);
NS_IMETHOD MakeFullScreen(PRBool aFullScreen);
@ -169,6 +171,8 @@ protected:
const nsAString& aUnmodifiedCharacters)
{ return NS_ERROR_UNEXPECTED; }
void StoreWindowClipRegion(const nsTArray<nsIntRect>& aRects);
protected:
void* mClientData;
EVENT_CALLBACK mEventCallback;
@ -183,6 +187,9 @@ protected:
PRPackedBool mOnDestroyCalled;
nsIntRect mBounds;
nsIntRect* mOriginalBounds;
// When this pointer is null, the widget is not clipped
nsAutoArrayPtr<nsIntRect> mClipRects;
PRInt32 mClipRectCount;
PRInt32 mZIndex;
nsSizeMode mSizeMode;