Bug 339889. Propagate invalidation through the frame hierarchy to topmost widgets. r+sr=bzbarsky

This commit is contained in:
roc+%cs.cmu.edu 2006-06-08 01:11:43 +00:00
Родитель 6ff46c21cf
Коммит 597d8bc582
12 изменённых файлов: 192 добавлений и 38 удалений

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

@ -2151,6 +2151,16 @@ nsListControlFrame::GetType() const
return nsLayoutAtoms::listControlFrame;
}
void
nsListControlFrame::InvalidateInternal(const nsRect& aDamageRect,
nscoord aX, nscoord aY, nsIFrame* aForChild,
PRBool aImmediate)
{
if (!IsInDropDownMode())
return nsHTMLScrollFrame::InvalidateInternal(aDamageRect, aX, aY, aForChild, aImmediate);
InvalidateRoot(aDamageRect, aX, aY, aImmediate);
}
#ifdef DEBUG
NS_IMETHODIMP
nsListControlFrame::GetFrameName(nsAString& aResult) const

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

@ -119,6 +119,10 @@ public:
*/
virtual nsIAtom* GetType() const;
virtual void InvalidateInternal(const nsRect& aDamageRect,
nscoord aX, nscoord aY, nsIFrame* aForChild,
PRBool aImmediate);
#ifdef DEBUG
// nsIFrameDebug
NS_IMETHOD GetFrameName(nsAString& aResult) const;

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

@ -480,6 +480,28 @@ nsBlockFrame::GetType() const
return nsLayoutAtoms::blockFrame;
}
void
nsBlockFrame::InvalidateInternal(const nsRect& aDamageRect,
nscoord aX, nscoord aY, nsIFrame* aForChild,
PRBool aImmediate)
{
// Optimize by suppressing invalidation of areas that are clipped out
// with CSS 'clip'.
const nsStyleDisplay* disp = GetStyleDisplay();
nsRect absPosClipRect;
if (GetAbsPosClipRect(disp, &absPosClipRect)) {
// Restrict the invalidated area to abs-pos clip rect
// abs-pos clipping clips everything in the frame
nsRect r;
if (r.IntersectRect(aDamageRect, absPosClipRect - nsPoint(aX, aY))) {
nsBlockFrameSuper::InvalidateInternal(r, aX, aY, aForChild, aImmediate);
}
return;
}
nsBlockFrameSuper::InvalidateInternal(aDamageRect, aX, aY, aForChild, aImmediate);
}
/////////////////////////////////////////////////////////////////////////////
// Child frame enumeration

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

@ -165,6 +165,9 @@ public:
NS_IMETHOD BuildDisplayList(nsDisplayListBuilder* aBuilder,
const nsRect& aDirtyRect,
const nsDisplayListSet& aLists);
virtual void InvalidateInternal(const nsRect& aDamageRect,
nscoord aX, nscoord aY, nsIFrame* aForChild,
PRBool aImmediate);
virtual nsIAtom* GetType() const;
#ifdef DEBUG
NS_IMETHOD List(FILE* out, PRInt32 aIndent) const;

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

@ -954,12 +954,36 @@ nsFrame::DisplayBorderBackgroundOutline(nsDisplayListBuilder* aBuilder,
return DisplayOutlineUnconditional(aBuilder, aLists);
}
PRBool
nsIFrame::GetAbsPosClipRect(const nsStyleDisplay* aDisp, nsRect* aRect)
{
NS_PRECONDITION(aRect, "Must have aRect out parameter");
if (!aDisp->IsAbsolutelyPositioned() ||
!(aDisp->mClipFlags & NS_STYLE_CLIP_RECT))
return PR_FALSE;
// Start with the 'auto' values and then factor in user specified values
aRect->SetRect(nsPoint(0, 0), GetSize());
if (0 == (NS_STYLE_CLIP_TOP_AUTO & aDisp->mClipFlags)) {
aRect->y += aDisp->mClip.y;
}
if (0 == (NS_STYLE_CLIP_LEFT_AUTO & aDisp->mClipFlags)) {
aRect->x += aDisp->mClip.x;
}
if (0 == (NS_STYLE_CLIP_RIGHT_AUTO & aDisp->mClipFlags)) {
aRect->width = aDisp->mClip.width;
}
if (0 == (NS_STYLE_CLIP_BOTTOM_AUTO & aDisp->mClipFlags)) {
aRect->height = aDisp->mClip.height;
}
return PR_TRUE;
}
static PRBool ApplyAbsPosClipping(nsDisplayListBuilder* aBuilder,
const nsStyleDisplay* aDisp, nsIFrame* aFrame,
nsRect* aRect) {
// REVIEW: from nsContainerFrame.cpp SyncFrameViewGeometryDependentProperties
if (!aDisp->IsAbsolutelyPositioned() ||
!(aDisp->mClipFlags & NS_STYLE_CLIP_RECT))
if (!aFrame->GetAbsPosClipRect(aDisp, aRect))
return PR_FALSE;
// A moving frame should not be allowed to clip a non-moving frame.
@ -976,21 +1000,7 @@ static PRBool ApplyAbsPosClipping(nsDisplayListBuilder* aBuilder,
GetFirstChild(nsLayoutAtoms::fixedList) &&
aBuilder->IsMovingFrame(aFrame))
return PR_FALSE;
// Start with the 'auto' values and then factor in user specified values
aRect->SetRect(aBuilder->ToReferenceFrame(aFrame), aFrame->GetSize());
if (0 == (NS_STYLE_CLIP_TOP_AUTO & aDisp->mClipFlags)) {
aRect->y += aDisp->mClip.y;
}
if (0 == (NS_STYLE_CLIP_LEFT_AUTO & aDisp->mClipFlags)) {
aRect->x += aDisp->mClip.x;
}
if (0 == (NS_STYLE_CLIP_RIGHT_AUTO & aDisp->mClipFlags)) {
aRect->width = aDisp->mClip.width;
}
if (0 == (NS_STYLE_CLIP_BOTTOM_AUTO & aDisp->mClipFlags)) {
aRect->height = aDisp->mClip.height;
}
return PR_TRUE;
}
@ -3127,7 +3137,7 @@ nsIFrame::IsLeaf() const
void
nsIFrame::Invalidate(const nsRect& aDamageRect,
PRBool aImmediate) const
PRBool aImmediate)
{
if (aDamageRect.IsEmpty()) {
return;
@ -3142,23 +3152,26 @@ nsIFrame::Invalidate(const nsRect& aDamageRect,
if (suppressed)
return;
}
nsRect damageRect(aDamageRect);
PRUint32 flags = aImmediate ? NS_VMREFRESH_IMMEDIATE : NS_VMREFRESH_NO_SYNC;
if (HasView()) {
nsIView* view = GetView();
view->GetViewManager()->UpdateView(view, damageRect, flags);
} else {
nsRect rect(damageRect);
nsPoint offset;
nsIView *view;
GetOffsetFromView(offset, &view);
NS_ASSERTION(view, "no view");
rect += offset;
view->GetViewManager()->UpdateView(view, rect, flags);
}
InvalidateInternal(aDamageRect, 0, 0, nsnull, aImmediate);
}
void
nsIFrame::InvalidateInternal(const nsRect& aDamageRect, nscoord aX, nscoord aY,
nsIFrame* aForChild, PRBool aImmediate)
{
GetParent()->
InvalidateInternal(aDamageRect, aX + mRect.x, aY + mRect.y, this, aImmediate);
}
void
nsIFrame::InvalidateRoot(const nsRect& aDamageRect,
nscoord aX, nscoord aY, PRBool aImmediate)
{
PRUint32 flags = aImmediate ? NS_VMREFRESH_IMMEDIATE : NS_VMREFRESH_NO_SYNC;
nsIView* view = GetView();
NS_ASSERTION(view, "This can only be called on frames with views");
view->GetViewManager()->UpdateView(view, aDamageRect + nsPoint(aX, aY), flags);
}
static nsRect ComputeOutlineRect(const nsIFrame* aFrame, PRBool* aAnyOutline,

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

@ -1379,6 +1379,27 @@ nsGfxScrollFrameInner::BuildDisplayList(nsDisplayListBuilder* aBuilder,
return NS_OK;
}
void
nsGfxScrollFrameInner::InvalidateInternal(const nsRect& aDamageRect,
nscoord aX, nscoord aY, nsIFrame* aForChild,
PRBool aImmediate)
{
nsPoint pt = mOuter->GetPosition();
if (aForChild == mScrolledFrame) {
// restrict aDamageRect to the scrollable view's bounds
nsRect r;
if (r.IntersectRect(aDamageRect, mScrollableView->View()->GetBounds() - nsPoint(aX, aY))) {
mOuter->GetParent()->
InvalidateInternal(r, aX + pt.x, aY + pt.y, mOuter, aImmediate);
}
return;
}
mOuter->GetParent()->
InvalidateInternal(aDamageRect, aX + pt.x, aY + pt.y, mOuter, aImmediate);
}
PRBool
nsGfxScrollFrameInner::NeedsClipWidget() const
{

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

@ -88,6 +88,9 @@ public:
const nsRect& aDirtyRect,
const nsDisplayListSet& aLists);
virtual void InvalidateInternal(const nsRect& aDamageRect, nscoord aX, nscoord aY,
nsIFrame* aForChild, PRBool aImmediate);
// nsIScrollPositionListener
NS_IMETHOD ScrollPositionWillChange(nsIScrollableView* aScrollable, nscoord aX, nscoord aY);
@ -266,6 +269,12 @@ public:
return mInner.GetScrolledFrame()->GetView();
}
virtual void InvalidateInternal(const nsRect& aDamageRect,
nscoord aX, nscoord aY, nsIFrame* aForChild,
PRBool aImmediate) {
return mInner.InvalidateInternal(aDamageRect, aX, aY, aForChild, aImmediate);
}
virtual PRBool NeedsView() { return PR_TRUE; }
virtual PRBool DoesClipChildren() { return PR_TRUE; }
@ -401,6 +410,12 @@ public:
return mInner.GetScrolledFrame()->GetView();
}
virtual void InvalidateInternal(const nsRect& aDamageRect,
nscoord aX, nscoord aY, nsIFrame* aForChild,
PRBool aImmediate) {
return mInner.InvalidateInternal(aDamageRect, aX, aY, aForChild, aImmediate);
}
virtual PRBool NeedsView() { return PR_TRUE; }
virtual PRBool DoesClipChildren() { return PR_TRUE; }

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

@ -6,7 +6,7 @@
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
* http://www.mozilla.org/MPL/I
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
@ -1212,14 +1212,33 @@ public:
/**
* Invalidate part of the frame by asking the view manager to repaint.
* aDamageRect is allowed to extend outside the frame's bounds. We'll do the right
* thing. But it must be within the bounds of the view enclosing this frame.
* thing.
* We deliberately don't have an Invalidate() method that defaults to the frame's bounds.
* We want all callers to *think* about what has changed in the frame and what area might
* need to be repainted.
*
* @param aDamageRect is in the frame's local coordinate space
*/
void Invalidate(const nsRect& aDamageRect, PRBool aImmediate = PR_FALSE) const;
void Invalidate(const nsRect& aDamageRect, PRBool aImmediate = PR_FALSE);
/**
* Helper function that can be overridden by frame classes. The rectangle
* (plus aOffsetX/aOffsetY) is relative to this frame.
*
* The offset is given as two coords rather than as an nsPoint because
* gcc optimizes it better that way, in particular in the default
* implementation that passes the area to the parent frame becomes a tail
* call.
*
* The default implementation will crash if the frame has no parent so
* frames without parents MUST* override.
*
* @param aForChild if the invalidation is coming from a child frame, this
* is the frame; otherwise, this is null.
*/
virtual void InvalidateInternal(const nsRect& aDamageRect,
nscoord aOffsetX, nscoord aOffsetY,
nsIFrame* aForChild, PRBool aImmediate);
/**
* Computes a rect that includes this frame, all its descendant
@ -1477,6 +1496,14 @@ NS_PTR_TO_INT32(frame->GetProperty(nsLayoutAtoms::embeddingLevel))
*/
virtual PRBool SupportsVisibilityHidden() { return PR_TRUE; }
/**
* Returns PR_TRUE if the frame is absolutely positioned and has a clip
* rect set via the 'clip' property. If true, then we also set aRect
* to the computed clip rect coordinates relative to this frame's origin.
* aRect must not be null!
*/
PRBool GetAbsPosClipRect(const nsStyleDisplay* aDisp, nsRect* aRect);
/**
* Check if this frame is focusable and in the current tab order.
* Tabbable is indicated by a nonnegative tabindex & is a subset of focusable.
@ -1640,6 +1667,15 @@ protected:
nsIFrame* mParent;
nsIFrame* mNextSibling; // singly-linked list of frames
nsFrameState mState;
// Helpers
/**
* For frames that have top-level windows (top-level viewports,
* comboboxes, menupoups) this function will invalidate the window.
*/
void InvalidateRoot(const nsRect& aDamageRect,
nscoord aOffsetX, nscoord aOffsetY,
PRBool aImmediate);
private:
NS_IMETHOD_(nsrefcnt) AddRef(void) = 0;

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

@ -333,6 +333,20 @@ ViewportFrame::IsContainingBlock() const
return PR_TRUE;
}
void
ViewportFrame::InvalidateInternal(const nsRect& aDamageRect,
nscoord aX, nscoord aY, nsIFrame* aForChild,
PRBool aImmediate)
{
nsIFrame* parent = nsLayoutUtils::GetCrossDocParentFrame(this);
if (parent) {
nsPoint pt = GetOffsetTo(parent);
parent->InvalidateInternal(aDamageRect, aX + pt.x, aY + pt.y, this, aImmediate);
return;
}
InvalidateRoot(aDamageRect, aX, aY, aImmediate);
}
#ifdef DEBUG
NS_IMETHODIMP
ViewportFrame::GetFrameName(nsAString& aResult) const

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

@ -107,6 +107,10 @@ public:
virtual PRBool IsContainingBlock() const;
virtual void InvalidateInternal(const nsRect& aDamageRect,
nscoord aX, nscoord aY, nsIFrame* aForChild,
PRBool aImmediate);
#ifdef DEBUG
NS_IMETHOD GetFrameName(nsAString& aResult) const;
#endif

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

@ -242,6 +242,14 @@ nsMenuPopupFrame::CreateWidgetForView(nsIView* aView)
return NS_OK;
}
void
nsMenuPopupFrame::InvalidateInternal(const nsRect& aDamageRect,
nscoord aX, nscoord aY, nsIFrame* aForChild,
PRBool aImmediate)
{
InvalidateRoot(aDamageRect, aX, aY, aImmediate);
}
NS_IMETHODIMP
nsMenuPopupFrame::MarkStyleChange(nsBoxLayoutState& aState)
{

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

@ -154,6 +154,10 @@ public:
virtual void Destroy();
virtual void InvalidateInternal(const nsRect& aDamageRect,
nscoord aX, nscoord aY, nsIFrame* aForChild,
PRBool aImmediate);
virtual nsresult CreateWidgetForView(nsIView* aView);
NS_IMETHOD MarkStyleChange(nsBoxLayoutState& aState);