added method to nsIView to get offset from nearest window.

added method to nsIView to get nearest scroll offset.
killed AdjustChildWidgets in nsIView.
lots of painting fixes.
added support for scrolling subviews.
added beginning of back-to-front compositing pass.
views, views with widgets and views with specific clips will now have their
outlines rendered in different colors. to turn this off see the top of nsView.cpp.
This commit is contained in:
michaelp 1998-06-16 17:05:42 +00:00
parent c7cc87a6a1
commit 97da4a6f90
6 changed files with 304 additions and 117 deletions

View File

@ -360,12 +360,20 @@ public:
virtual nsIFrame * GetFrame() = 0;
/**
* Move child widgets around by (dx, dy). deltas are in widget
* coordinate space.
* @param aDx x delta
* @param aDy y delta
* Get the nearest widget in this view or a parent of this view and
* the offset from the view that contains the widget to this view
* @param aDx out parameter for x offset
* @param aDy out parameter for y offset
* @return widget (if there is one) closest to view
*/
virtual void AdjustChildWidgets(nscoord aDx, nscoord aDy) = 0;
virtual nsIWidget * GetOffsetFromWidget(nscoord *aDx, nscoord *aDy) = 0;
/**
* Get the visible offset of scrollable view (if any) that contains this view
* @param aDx out parameter for x offset
* @param aDy out parameter for y offset
*/
virtual void GetScrollOffset(nscoord *aDx, nscoord *aDy) = 0;
/**
* Output debug info to FILE
@ -394,4 +402,9 @@ public:
//during event propagation, see if sibling views can handle the event
#define NS_VIEW_FLAG_CHECK_SIBLINGS 0x0010
//passed down through the class hierarchy
//to indicate that the clip is set by an
//outer class
#define NS_VIEW_FLAG_CLIP_SET 0x0020
#endif

View File

@ -53,8 +53,14 @@ void ScrollBarView :: SetPosition(nscoord x, nscoord y)
{
nsIPresContext *px = mViewManager->GetPresContext();
float scale = px->GetTwipsToPixels();
nscoord parx = 0, pary = 0;
nsIWidget *pwidget = nsnull;
pwidget = GetOffsetFromWidget(&parx, &pary);
NS_IF_RELEASE(pwidget);
mWindow->Move(NS_TO_INT_ROUND(x * scale), NS_TO_INT_ROUND(y * scale));
mWindow->Move(NS_TO_INT_ROUND((x + parx) * scale),
NS_TO_INT_ROUND((y + pary) * scale));
NS_RELEASE(px);
}
@ -245,17 +251,52 @@ void nsScrollingView :: SetDimensions(nscoord width, nscoord height)
NS_RELEASE(cx);
}
void nsScrollingView :: SetPosition(nscoord aX, nscoord aY)
{
nsIPresContext *px = mViewManager->GetPresContext();
nsIWidget *thiswin = GetWidget();
if (nsnull == thiswin)
thiswin = GetOffsetFromWidget(nsnull, nsnull);
if (nsnull != thiswin)
thiswin->BeginResizingChildren();
nsView::SetPosition(aX, aY);
AdjustChildWidgets(this, this, 0, 0, px->GetTwipsToPixels());
if (nsnull != thiswin)
{
thiswin->EndResizingChildren();
NS_RELEASE(thiswin);
}
NS_RELEASE(px);
}
PRBool nsScrollingView :: Paint(nsIRenderingContext& rc, const nsRect& rect,
PRUint32 aPaintFlags, nsIView *aBackstop)
{
PRBool retval;
PRBool clipres = PR_FALSE;
rc.PushState();
rc.Translate(-mOffsetX, -mOffsetY);
retval = nsView::Paint(rc, rect, aPaintFlags, aBackstop);
rc.PopState();
return retval;
if (mVis == nsViewVisibility_kShow)
clipres = rc.SetClipRect(mBounds, nsClipCombine_kIntersect);
if (clipres == PR_FALSE)
{
rc.Translate(-mOffsetX, -mOffsetY);
clipres = nsView::Paint(rc, rect, aPaintFlags | NS_VIEW_FLAG_CLIP_SET, aBackstop);
}
clipres = rc.PopState();
if ((clipres == PR_FALSE) && (mVis == nsViewVisibility_kShow) && (nsnull == mWindow))
clipres = rc.SetClipRect(mBounds, nsClipCombine_kSubtract);
return clipres;
}
nsEventStatus nsScrollingView :: HandleEvent(nsGUIEvent *aEvent, PRUint32 aEventFlags)
@ -316,6 +357,9 @@ nsEventStatus nsScrollingView :: HandleEvent(nsGUIEvent *aEvent, PRUint32 aEvent
nsIWidget *thiswin = GetWidget();
if (nsnull == thiswin)
thiswin = GetOffsetFromWidget(nsnull, nsnull);
if (nsnull != thiswin)
thiswin->BeginResizingChildren();
@ -328,7 +372,7 @@ nsEventStatus nsScrollingView :: HandleEvent(nsGUIEvent *aEvent, PRUint32 aEvent
if (dy != 0)
{
AdjustChildWidgets(0, dy);
AdjustChildWidgets(this, this, 0, 0, px->GetTwipsToPixels());
if (nsnull != mWindow)
mWindow->Scroll(0, dy, &clip);
@ -381,6 +425,9 @@ nsEventStatus nsScrollingView :: HandleEvent(nsGUIEvent *aEvent, PRUint32 aEvent
nsIWidget *thiswin = GetWidget();
if (nsnull == thiswin)
thiswin = GetOffsetFromWidget(nsnull, nsnull);
if (nsnull != thiswin)
thiswin->BeginResizingChildren();
@ -393,7 +440,7 @@ nsEventStatus nsScrollingView :: HandleEvent(nsGUIEvent *aEvent, PRUint32 aEvent
if (dx != 0)
{
AdjustChildWidgets(dx, 0);
AdjustChildWidgets(this, this, 0, 0, px->GetTwipsToPixels());
if (nsnull != mWindow)
mWindow->Scroll(dx, 0, &clip);
@ -538,7 +585,7 @@ void nsScrollingView :: ComputeContainerSize()
NS_IF_RELEASE(scrollv);
if ((dx != 0) || (dy != 0))
AdjustChildWidgets(dx, dy);
AdjustChildWidgets(this, this, 0, 0, px->GetTwipsToPixels());
NS_RELEASE(px);
NS_RELEASE(scrollview);
@ -598,34 +645,92 @@ void nsScrollingView :: GetVisibleOffset(nscoord *aOffsetX, nscoord *aOffsetY)
*aOffsetY = mOffsetY;
}
void nsScrollingView :: AdjustChildWidgets(nscoord aDx, nscoord aDy)
void nsScrollingView :: AdjustChildWidgets(nsScrollingView *aScrolling, nsIView *aView, nscoord aDx, nscoord aDy, float scale)
{
PRInt32 numkids = GetChildCount();
PRInt32 numkids = aView->GetChildCount();
nsIScrollableView *scroller;
nscoord offx, offy;
PRBool isscroll = PR_FALSE;
static NS_DEFINE_IID(kscroller, NS_ISCROLLABLEVIEW_IID);
if (aScrolling == aView)
{
nsIWidget *widget = aScrolling->GetOffsetFromWidget(&aDx, &aDy);
nsIView *parview = aScrolling->GetParent();
while (nsnull != parview)
{
nsIWidget *parwidget = parview->GetWidget();
if (NS_OK == parview->QueryInterface(kscroller, (void **)&scroller))
{
scroller->GetVisibleOffset(&offx, &offy);
aDx -= offx;
aDy -= offy;
NS_RELEASE(scroller);
}
if (parwidget == widget)
{
NS_IF_RELEASE(parwidget);
break;
}
NS_IF_RELEASE(parwidget);
parview = parview->GetParent();
}
NS_IF_RELEASE(widget);
}
aView->GetPosition(&offx, &offy);
aDx += offx;
aDy += offy;
if (NS_OK == aView->QueryInterface(kscroller, (void **)&scroller))
{
scroller->GetVisibleOffset(&offx, &offy);
aDx -= offx;
aDy -= offy;
NS_RELEASE(scroller);
isscroll = PR_TRUE;
}
for (PRInt32 cnt = 0; cnt < numkids; cnt++)
{
nsIView *kid = GetChild(cnt);
nsIView *kid = aView->GetChild(cnt);
nsIWidget *win = kid->GetWidget();
if ((kid != mVScrollBarView) && (kid != mHScrollBarView))
if (nsnull != win)
{
nsIWidget *win = kid->GetWidget();
nsRect bounds;
if (nsnull != win)
{
nsRect bounds;
win->BeginResizingChildren();
kid->GetBounds(bounds);
win->BeginResizingChildren();
win->GetBounds(bounds);
win->Move(bounds.x + aDx, bounds.y + aDy);
}
if (!isscroll ||
(isscroll &&
(kid != ((nsScrollingView *)aView)->mVScrollBarView) &&
(kid != ((nsScrollingView *)aView)->mHScrollBarView)))
win->Move(NS_TO_INT_ROUND((bounds.x + aDx) * scale), NS_TO_INT_ROUND((bounds.y + aDy) * scale));
else
win->Move(NS_TO_INT_ROUND((bounds.x + aDx + offx) * scale), NS_TO_INT_ROUND((bounds.y + aDy + offy) * scale));
}
kid->AdjustChildWidgets(aDx, aDy);
AdjustChildWidgets(aScrolling, kid, aDx, aDy, scale);
if (nsnull != win)
{
win->EndResizingChildren();
NS_RELEASE(win);
}
if (nsnull != win)
{
win->EndResizingChildren();
NS_RELEASE(win);
}
}
}

View File

@ -49,8 +49,9 @@ public:
//overrides
virtual void SetDimensions(nscoord width, nscoord height);
virtual void SetPosition(nscoord aX, nscoord aY);
virtual nsEventStatus HandleEvent(nsGUIEvent *aEvent, PRUint32 aEventFlags);
virtual void AdjustChildWidgets(nscoord aDx, nscoord aDy);
virtual void AdjustChildWidgets(nsScrollingView *aScrolling, nsIView *aView, nscoord aDx, nscoord aDy, float aScale);
virtual PRBool Paint(nsIRenderingContext& rc, const nsRect& rect,
PRUint32 aPaintFlags, nsIView *aBackstop = nsnull);

View File

@ -34,6 +34,9 @@
static NS_DEFINE_IID(kIViewIID, NS_IVIEW_IID);
#define SHOW_VIEW_BORDERS
//#define HIDE_ALL_WIDGETS
//
// Main events handler
//
@ -142,34 +145,6 @@ nsEventStatus PR_CALLBACK HandleEvent(nsGUIEvent *aEvent)
return result;
}
// this should be added to nsView. maybe
nsIWidget * GetWindowTemp(nsIView *aView, nscoord *aDx, nscoord *aDy)
{
nsIWidget *window = nsnull;
nsIView *ancestor = aView;
while (nsnull != ancestor)
{
if (nsnull != (window = ancestor->GetWidget()))
return window;
ancestor = ancestor->GetParent();
if ((nsnull != aDx) && (nsnull != aDy))
{
nscoord offx, offy;
ancestor->GetPosition(&offx, &offy);
*aDx += offx;
*aDy += offy;
}
}
return nsnull;
}
nsView :: nsView()
{
mVis = nsViewVisibility_kShow;
@ -353,7 +328,7 @@ nsresult nsView :: Init(nsIViewManager* aManager,
mWindow->Create(aNative, trect, ::HandleEvent, dx, nsnull, aWidgetInitData);
else
{
nsIWidget *parent = GetWindowTemp(aParent, nsnull, nsnull);
nsIWidget *parent = GetOffsetFromWidget(nsnull, nsnull);
mWindow->Create(parent, trect, ::HandleEvent, dx, nsnull, aWidgetInitData);
NS_IF_RELEASE(parent);
}
@ -390,35 +365,42 @@ PRBool nsView :: Paint(nsIRenderingContext& rc, const nsRect& rect,
{
nsIView *pRoot = mViewManager->GetRootView();
PRBool clipres = PR_FALSE;
PRBool clipwasset = PR_FALSE;
rc.PushState();
if ((mClip.mLeft != mClip.mRight) && (mClip.mTop != mClip.mBottom))
if (aPaintFlags & NS_VIEW_FLAG_CLIP_SET)
{
nsRect crect;
crect.x = mClip.mLeft + mBounds.x;
crect.y = mClip.mTop + mBounds.y;
crect.width = mClip.mRight - mClip.mLeft;
crect.height = mClip.mBottom - mClip.mTop;
clipres = rc.SetClipRect(crect, nsClipCombine_kIntersect);
clipwasset = PR_TRUE;
aPaintFlags &= ~NS_VIEW_FLAG_CLIP_SET;
}
else if (mVis == nsViewVisibility_kShow)
{
if ((mClip.mLeft != mClip.mRight) && (mClip.mTop != mClip.mBottom))
{
nsRect crect;
crect.x = mClip.mLeft + mBounds.x;
crect.y = mClip.mTop + mBounds.y;
crect.width = mClip.mRight - mClip.mLeft;
crect.height = mClip.mBottom - mClip.mTop;
clipres = rc.SetClipRect(crect, nsClipCombine_kIntersect);
}
else if (this != pRoot)
clipres = rc.SetClipRect(mBounds, nsClipCombine_kIntersect);
}
if (nsnull != mXForm)
{
nsTransform2D *pXForm = rc.GetCurrentTransform();
pXForm->Concatenate(mXForm);
}
else if (this != pRoot)
clipres = rc.SetClipRect(mBounds, nsClipCombine_kIntersect);
if (clipres == PR_FALSE)
{
rc.Translate(mBounds.x, mBounds.y);
//XXX maybe we should set this before we set the clip? MMP
if (nsnull != mXForm)
{
nsTransform2D *pXForm = rc.GetCurrentTransform();
pXForm->Concatenate(mXForm);
}
PRInt32 numkids = GetChildCount();
for (PRInt32 cnt = 0; cnt < numkids; cnt++)
@ -430,6 +412,10 @@ PRBool nsView :: Paint(nsIRenderingContext& rc, const nsRect& rect,
nsRect kidRect;
kid->GetBounds(kidRect);
nsRect damageArea;
// nsRect damageArea = rect;
// damageArea.x -= mBounds.x;
// damageArea.y -= mBounds.y;
// PRBool overlap = damageArea.IntersectRect(damageArea, kidRect);
PRBool overlap = damageArea.IntersectRect(rect, kidRect);
if (overlap == PR_TRUE)
@ -445,13 +431,64 @@ PRBool nsView :: Paint(nsIRenderingContext& rc, const nsRect& rect,
}
}
if ((clipres == PR_FALSE) && (mVis == nsViewVisibility_kShow) && (nsnull != mFrame))
if ((clipres == PR_FALSE) && (mVis == nsViewVisibility_kShow))
{
nsIPresContext *cx = mViewManager->GetPresContext();
rc.PushState();
mFrame->Paint(*cx, rc, rect);
rc.PopState();
NS_RELEASE(cx);
float opacity = GetOpacity();
if (opacity > 0.0f)
{
rc.PushState();
#if 0
if (HasTransparency() || (opacity < 1.0f))
{
nsRect crect;
PRBool goodclip = rc.GetClipRect(crect);
//walk down rendering only views within this clip
rc.SetClipRect(crect, nsClipCombine_kReplace);
}
#endif
if (nsnull != mFrame)
{
nsIPresContext *cx = mViewManager->GetPresContext();
mFrame->Paint(*cx, rc, rect);
NS_RELEASE(cx);
}
#ifdef SHOW_VIEW_BORDERS
{
nscoord x, y, w, h;
if ((mClip.mLeft != mClip.mRight) && (mClip.mTop != mClip.mBottom))
{
x = mClip.mLeft;
y = mClip.mTop;
w = mClip.mRight - mClip.mLeft;
h = mClip.mBottom - mClip.mTop;
rc.SetColor(NS_RGB(255, 255, 0));
}
else
{
x = y = 0;
w = mBounds.width;
h = mBounds.height;
if (nsnull != mWindow)
rc.SetColor(NS_RGB(0, 255, 0));
else
rc.SetColor(NS_RGB(0, 0, 255));
}
rc.DrawRect(x, y, w, h);
}
#endif
rc.PopState();
}
}
}
@ -459,13 +496,14 @@ PRBool nsView :: Paint(nsIRenderingContext& rc, const nsRect& rect,
//state from the stack but doesn't change the state of the underlying graphics
//context. MMP
rc.PopState();
clipres = rc.PopState();
//now we need to exclude this view from the rest of the
//paint process. only do this if this view is actually
//visible and if there is no widget (like a scrollbar) here.
if ((clipres == PR_FALSE) && (mVis == nsViewVisibility_kShow) && (nsnull == mWindow))
// if ((clipres == PR_FALSE) && (mVis == nsViewVisibility_kShow))
if (!clipwasset && (clipres == PR_FALSE) && (mVis == nsViewVisibility_kShow) && (nsnull == mWindow))
{
if ((mClip.mLeft != mClip.mRight) && (mClip.mTop != mClip.mBottom))
{
@ -524,7 +562,7 @@ nsEventStatus nsView :: HandleEvent(nsGUIEvent *event, PRUint32 aEventFlags)
nsIPresContext *cx = mViewManager->GetPresContext();
nscoord xoff, yoff;
mViewManager->GetWindowOffsets(&xoff, &yoff);
GetScrollOffset(&xoff, &yoff);
event->point.x += xoff;
event->point.y += yoff;
@ -629,17 +667,12 @@ void nsView :: SetPosition(nscoord x, nscoord y)
nsIPresContext *px = mViewManager->GetPresContext();
nscoord offx, offy, parx = 0, pary = 0;
float scale = px->GetTwipsToPixels();
nsIView *par = GetParent();
nsIWidget *pwidget = nsnull;
mViewManager->GetWindowOffsets(&offx, &offy);
GetScrollOffset(&offx, &offy);
if (nsnull != par)
{
nsIWidget *pwidget = nsnull;
pwidget = GetWindowTemp(par, &parx, &pary);
NS_IF_RELEASE(pwidget);
}
pwidget = GetOffsetFromWidget(&parx, &pary);
NS_IF_RELEASE(pwidget);
mWindow->Move(NS_TO_INT_ROUND((x + parx + offx) * scale),
NS_TO_INT_ROUND((y + pary + offy) * scale));
@ -735,9 +768,11 @@ void nsView :: SetVisibility(nsViewVisibility aVisibility)
if (nsnull != mWindow)
{
#ifndef HIDE_ALL_WIDGETS
if (mVis == nsViewVisibility_kShow)
mWindow->Show(PR_TRUE);
else
#endif
mWindow->Show(PR_FALSE);
}
}
@ -947,30 +982,52 @@ void nsView :: List(FILE* out, PRInt32 aIndent) const
fputs(">\n", out);
}
void nsView :: AdjustChildWidgets(nscoord aDx, nscoord aDy)
nsIWidget * nsView :: GetOffsetFromWidget(nscoord *aDx, nscoord *aDy)
{
PRInt32 numkids = GetChildCount();
nsIWidget *window = nsnull;
nsIView *ancestor = GetParent();
for (PRInt32 cnt = 0; cnt < numkids; cnt++)
while (nsnull != ancestor)
{
nsIView *kid = GetChild(cnt);
nsIWidget *win = kid->GetWidget();
if (nsnull != (window = ancestor->GetWidget()))
return window;
if (nsnull != win)
if ((nsnull != aDx) && (nsnull != aDy))
{
nsRect bounds;
nscoord offx, offy;
win->BeginResizingChildren();
win->GetBounds(bounds);
win->Move(bounds.x + aDx, bounds.y + aDy);
ancestor->GetPosition(&offx, &offy);
*aDx += offx;
*aDy += offy;
}
kid->AdjustChildWidgets(aDx, aDy);
if (nsnull != win)
{
win->EndResizingChildren();
NS_RELEASE(win);
}
ancestor = ancestor->GetParent();
}
return nsnull;
}
void nsView :: GetScrollOffset(nscoord *aDx, nscoord *aDy)
{
nsIWidget *window = nsnull;
nsIView *ancestor = GetParent();
while (nsnull != ancestor)
{
nsIScrollableView *sview;
static NS_DEFINE_IID(kscroller, NS_ISCROLLABLEVIEW_IID);
if (NS_OK == ancestor->QueryInterface(kscroller, (void **)&sview))
{
sview->GetVisibleOffset(aDx, aDy);
NS_RELEASE(sview);
return;
}
ancestor = ancestor->GetParent();
}
*aDx = *aDy = 0;
}

View File

@ -90,7 +90,8 @@ public:
virtual void List(FILE* out = stdout, PRInt32 aIndent = 0) const;
virtual void SetFrame(nsIFrame *aFrame);
virtual nsIFrame * GetFrame();
virtual void AdjustChildWidgets(nscoord aDx, nscoord aDy);
virtual nsIWidget * GetOffsetFromWidget(nscoord *aDx, nscoord *aDy);
virtual void GetScrollOffset(nscoord *aDx, nscoord *aDy);
protected:
//

View File

@ -31,6 +31,7 @@ static const PRBool gsDebug = PR_FALSE;
#define UPDATE_QUANTUM 1000 / 40
//#define USE_DIRTY_RECT
//#define NO_DOUBLE_BUFFER
static void vm_timer_callback(nsITimer *aTimer, void *aClosure)
{
@ -288,6 +289,10 @@ void nsViewManager :: Refresh(nsIView *aView, nsIRenderingContext *aContext, nsI
if (mTransCnt > 0)
aUpdateFlags |= NS_VMREFRESH_DOUBLE_BUFFER;
#ifdef NO_DOUBLE_BUFFER
aUpdateFlags &= ~NS_VMREFRESH_DOUBLE_BUFFER;
#endif
if (nsnull == aContext)
{
localcx = CreateRenderingContext(*aView);
@ -351,6 +356,10 @@ void nsViewManager :: Refresh(nsIView *aView, nsIRenderingContext *aContext, nsR
if (mTransCnt > 0)
aUpdateFlags |= NS_VMREFRESH_DOUBLE_BUFFER;
#ifdef NO_DOUBLE_BUFFER
aUpdateFlags &= ~NS_VMREFRESH_DOUBLE_BUFFER;
#endif
if (nsnull == aContext)
{
localcx = CreateRenderingContext(*aView);
@ -448,6 +457,7 @@ void nsViewManager :: UpdateView(nsIView *aView, nsIRegion *aRegion, PRUint32 aU
nsRect trect;
aView->GetBounds(trect);
trect.x = trect.y = 0;
UpdateView(aView, trect, aUpdateFlags);
}
}