diff --git a/layout/forms/nsListControlFrame.cpp b/layout/forms/nsListControlFrame.cpp index 84f9826ec522..a96edd76854d 100644 --- a/layout/forms/nsListControlFrame.cpp +++ b/layout/forms/nsListControlFrame.cpp @@ -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 diff --git a/layout/forms/nsListControlFrame.h b/layout/forms/nsListControlFrame.h index cf5639213db9..3672bf0f9dd8 100644 --- a/layout/forms/nsListControlFrame.h +++ b/layout/forms/nsListControlFrame.h @@ -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; diff --git a/layout/generic/nsBlockFrame.cpp b/layout/generic/nsBlockFrame.cpp index 7a4768ff73f0..774a1299056a 100644 --- a/layout/generic/nsBlockFrame.cpp +++ b/layout/generic/nsBlockFrame.cpp @@ -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 diff --git a/layout/generic/nsBlockFrame.h b/layout/generic/nsBlockFrame.h index 944887db3c03..bb8b72b6478d 100644 --- a/layout/generic/nsBlockFrame.h +++ b/layout/generic/nsBlockFrame.h @@ -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; diff --git a/layout/generic/nsFrame.cpp b/layout/generic/nsFrame.cpp index a82e584b5b66..18af1ec571dc 100644 --- a/layout/generic/nsFrame.cpp +++ b/layout/generic/nsFrame.cpp @@ -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, diff --git a/layout/generic/nsGfxScrollFrame.cpp b/layout/generic/nsGfxScrollFrame.cpp index e64f2156ae38..9b4d4ad501c8 100644 --- a/layout/generic/nsGfxScrollFrame.cpp +++ b/layout/generic/nsGfxScrollFrame.cpp @@ -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 { diff --git a/layout/generic/nsGfxScrollFrame.h b/layout/generic/nsGfxScrollFrame.h index 972e1f35b8ab..10e5f31945e7 100644 --- a/layout/generic/nsGfxScrollFrame.h +++ b/layout/generic/nsGfxScrollFrame.h @@ -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; } diff --git a/layout/generic/nsIFrame.h b/layout/generic/nsIFrame.h index 0f778db43dbd..16d125413d1c 100644 --- a/layout/generic/nsIFrame.h +++ b/layout/generic/nsIFrame.h @@ -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; diff --git a/layout/generic/nsViewportFrame.cpp b/layout/generic/nsViewportFrame.cpp index 27fc99e96395..25b3176d239f 100644 --- a/layout/generic/nsViewportFrame.cpp +++ b/layout/generic/nsViewportFrame.cpp @@ -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 diff --git a/layout/generic/nsViewportFrame.h b/layout/generic/nsViewportFrame.h index f145726d9f10..48b1af4a61bd 100644 --- a/layout/generic/nsViewportFrame.h +++ b/layout/generic/nsViewportFrame.h @@ -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 diff --git a/layout/xul/base/src/nsMenuPopupFrame.cpp b/layout/xul/base/src/nsMenuPopupFrame.cpp index 07a1d8450010..d9efcd6854f2 100644 --- a/layout/xul/base/src/nsMenuPopupFrame.cpp +++ b/layout/xul/base/src/nsMenuPopupFrame.cpp @@ -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) { diff --git a/layout/xul/base/src/nsMenuPopupFrame.h b/layout/xul/base/src/nsMenuPopupFrame.h index 33491ce9b3e8..76e78f0665a4 100644 --- a/layout/xul/base/src/nsMenuPopupFrame.h +++ b/layout/xul/base/src/nsMenuPopupFrame.h @@ -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);