Bug 450930. Fire a DOM event when painting so that content and chrome can track what's being repainted. r=smaug,sr=dbaron

This commit is contained in:
Robert O'Callahan
2008-09-18 21:47:21 +12:00
parent ccc61e0fb2
commit bee2844b64
58 changed files with 818 additions and 150 deletions

View File

@@ -444,19 +444,19 @@ nsContentUtils::InitializeEventTable() {
{ &nsGkAtoms::ondragleave, { NS_DRAGDROP_LEAVE_SYNTH, EventNameType_HTMLXUL }}, { &nsGkAtoms::ondragleave, { NS_DRAGDROP_LEAVE_SYNTH, EventNameType_HTMLXUL }},
{ &nsGkAtoms::ondrop, { NS_DRAGDROP_DROP, EventNameType_HTMLXUL }}, { &nsGkAtoms::ondrop, { NS_DRAGDROP_DROP, EventNameType_HTMLXUL }},
{ &nsGkAtoms::onoverflow, { NS_SCROLLPORT_OVERFLOW, EventNameType_XUL }}, { &nsGkAtoms::onoverflow, { NS_SCROLLPORT_OVERFLOW, EventNameType_XUL }},
{ &nsGkAtoms::onunderflow, { NS_SCROLLPORT_UNDERFLOW, EventNameType_XUL }} { &nsGkAtoms::onunderflow, { NS_SCROLLPORT_UNDERFLOW, EventNameType_XUL }},
#ifdef MOZ_SVG #ifdef MOZ_SVG
,{ &nsGkAtoms::onSVGLoad, { NS_SVG_LOAD, EventNameType_None }}, { &nsGkAtoms::onSVGLoad, { NS_SVG_LOAD, EventNameType_None }},
{ &nsGkAtoms::onSVGUnload, { NS_SVG_UNLOAD, EventNameType_None }}, { &nsGkAtoms::onSVGUnload, { NS_SVG_UNLOAD, EventNameType_None }},
{ &nsGkAtoms::onSVGAbort, { NS_SVG_ABORT, EventNameType_None }}, { &nsGkAtoms::onSVGAbort, { NS_SVG_ABORT, EventNameType_None }},
{ &nsGkAtoms::onSVGError, { NS_SVG_ERROR, EventNameType_None }}, { &nsGkAtoms::onSVGError, { NS_SVG_ERROR, EventNameType_None }},
{ &nsGkAtoms::onSVGResize, { NS_SVG_RESIZE, EventNameType_None }}, { &nsGkAtoms::onSVGResize, { NS_SVG_RESIZE, EventNameType_None }},
{ &nsGkAtoms::onSVGScroll, { NS_SVG_SCROLL, EventNameType_None }}, { &nsGkAtoms::onSVGScroll, { NS_SVG_SCROLL, EventNameType_None }},
{ &nsGkAtoms::onSVGZoom, { NS_SVG_ZOOM, EventNameType_None }}, { &nsGkAtoms::onSVGZoom, { NS_SVG_ZOOM, EventNameType_None }},
{ &nsGkAtoms::onzoom, { NS_SVG_ZOOM, EventNameType_SVGSVG }} { &nsGkAtoms::onzoom, { NS_SVG_ZOOM, EventNameType_SVGSVG }},
#endif // MOZ_SVG #endif // MOZ_SVG
#ifdef MOZ_MEDIA #ifdef MOZ_MEDIA
,{ &nsGkAtoms::onloadstart, { NS_LOADSTART, EventNameType_HTML }}, { &nsGkAtoms::onloadstart, { NS_LOADSTART, EventNameType_HTML }},
{ &nsGkAtoms::onprogress, { NS_PROGRESS, EventNameType_HTML }}, { &nsGkAtoms::onprogress, { NS_PROGRESS, EventNameType_HTML }},
{ &nsGkAtoms::onloadedmetadata, { NS_LOADEDMETADATA, EventNameType_HTML }}, { &nsGkAtoms::onloadedmetadata, { NS_LOADEDMETADATA, EventNameType_HTML }},
{ &nsGkAtoms::onloadedfirstframe, { NS_LOADEDFIRSTFRAME, EventNameType_HTML }}, { &nsGkAtoms::onloadedfirstframe, { NS_LOADEDFIRSTFRAME, EventNameType_HTML }},
@@ -477,6 +477,7 @@ nsContentUtils::InitializeEventTable() {
{ &nsGkAtoms::ondurationchange, { NS_DURATIONCHANGE, EventNameType_HTML }}, { &nsGkAtoms::ondurationchange, { NS_DURATIONCHANGE, EventNameType_HTML }},
{ &nsGkAtoms::onvolumechange, { NS_VOLUMECHANGE, EventNameType_HTML }}, { &nsGkAtoms::onvolumechange, { NS_VOLUMECHANGE, EventNameType_HTML }},
#endif //MOZ_MEDIA #endif //MOZ_MEDIA
{ &nsGkAtoms::onMozAfterPaint, { NS_AFTERPAINT, EventNameType_None }}
}; };
sEventTable = new nsDataHashtable<nsISupportsHashKey, EventNameMapping>; sEventTable = new nsDataHashtable<nsISupportsHashKey, EventNameMapping>;

View File

@@ -1289,28 +1289,6 @@ GetContainingBlockForClientRect(nsIFrame* aFrame)
return aFrame; return aFrame;
} }
static double
RoundFloat(double aValue)
{
return floor(aValue + 0.5);
}
static void
SetClientRect(const nsRect& aLayoutRect, nsPresContext* aPresContext,
nsClientRect* aRect)
{
double scale = 65536.0;
// Round to the nearest 1/scale units. We choose scale so it can be represented
// exactly by machine floating point.
double scaleInv = 1/scale;
double t2pScaled = scale/aPresContext->AppUnitsPerCSSPixel();
double x = RoundFloat(aLayoutRect.x*t2pScaled)*scaleInv;
double y = RoundFloat(aLayoutRect.y*t2pScaled)*scaleInv;
aRect->SetRect(x, y,
RoundFloat(aLayoutRect.XMost()*t2pScaled)*scaleInv - x,
RoundFloat(aLayoutRect.YMost()*t2pScaled)*scaleInv - y);
}
NS_IMETHODIMP NS_IMETHODIMP
nsNSElementTearoff::GetBoundingClientRect(nsIDOMClientRect** aResult) nsNSElementTearoff::GetBoundingClientRect(nsIDOMClientRect** aResult)
{ {
@@ -1330,7 +1308,7 @@ nsNSElementTearoff::GetBoundingClientRect(nsIDOMClientRect** aResult)
nsPresContext* presContext = frame->PresContext(); nsPresContext* presContext = frame->PresContext();
nsRect r = nsLayoutUtils::GetAllInFlowRectsUnion(frame, nsRect r = nsLayoutUtils::GetAllInFlowRectsUnion(frame,
GetContainingBlockForClientRect(frame)); GetContainingBlockForClientRect(frame));
SetClientRect(r, presContext, rect); rect->SetLayoutRect(r, presContext);
return NS_OK; return NS_OK;
} }
@@ -1350,7 +1328,7 @@ struct RectListBuilder : public nsLayoutUtils::RectCallback {
return; return;
} }
SetClientRect(aRect, mPresContext, rect); rect->SetLayoutRect(aRect, mPresContext);
mRectList->Append(rect); mRectList->Append(rect);
} }
}; };

View File

@@ -641,6 +641,7 @@ GK_ATOM(onmousemove, "onmousemove")
GK_ATOM(onmouseout, "onmouseout") GK_ATOM(onmouseout, "onmouseout")
GK_ATOM(onmouseover, "onmouseover") GK_ATOM(onmouseover, "onmouseover")
GK_ATOM(onmouseup, "onmouseup") GK_ATOM(onmouseup, "onmouseup")
GK_ATOM(onMozAfterPaint, "onMozAfterPaint")
GK_ATOM(onMozMousePixelScroll, "onMozMousePixelScroll") GK_ATOM(onMozMousePixelScroll, "onMozMousePixelScroll")
GK_ATOM(ononline, "ononline") GK_ATOM(ononline, "ononline")
GK_ATOM(onoffline, "onoffline") GK_ATOM(onoffline, "onoffline")

View File

@@ -110,4 +110,6 @@ nsresult
NS_NewDOMMessageEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext, class nsEvent* aEvent); NS_NewDOMMessageEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext, class nsEvent* aEvent);
nsresult nsresult
NS_NewDOMProgressEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext, class nsEvent* aEvent); NS_NewDOMProgressEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext, class nsEvent* aEvent);
nsresult
NS_NewDOMNotifyPaintEvent(nsIDOMEvent** aResult, nsPresContext* aPresContext, class nsNotifyPaintEvent* aEvent);
#endif // nsIPrivateDOMEvent_h__ #endif // nsIPrivateDOMEvent_h__

View File

@@ -94,6 +94,7 @@ CPPSRCS = \
nsQueryContentEventHandler.cpp \ nsQueryContentEventHandler.cpp \
nsDOMProgressEvent.cpp \ nsDOMProgressEvent.cpp \
nsDOMDataTransfer.cpp \ nsDOMDataTransfer.cpp \
nsDOMNotifyPaintEvent.cpp \
$(NULL) $(NULL)
# we don't want the shared lib, but we want to force the creation of a static lib. # we don't want the shared lib, but we want to force the creation of a static lib.

View File

@@ -71,20 +71,19 @@ static const char* const sEventNames[] = {
"DOMAttrModified", "DOMCharacterDataModified", "DOMAttrModified", "DOMCharacterDataModified",
"DOMActivate", "DOMFocusIn", "DOMFocusOut", "DOMActivate", "DOMFocusIn", "DOMFocusOut",
"pageshow", "pagehide", "DOMMouseScroll", "MozMousePixelScroll", "pageshow", "pagehide", "DOMMouseScroll", "MozMousePixelScroll",
"offline", "online", "copy", "cut", "paste" "offline", "online", "copy", "cut", "paste",
#ifdef MOZ_SVG #ifdef MOZ_SVG
,
"SVGLoad", "SVGUnload", "SVGAbort", "SVGError", "SVGResize", "SVGScroll", "SVGLoad", "SVGUnload", "SVGAbort", "SVGError", "SVGResize", "SVGScroll",
"SVGZoom" "SVGZoom",
#endif // MOZ_SVG #endif // MOZ_SVG
#ifdef MOZ_MEDIA #ifdef MOZ_MEDIA
,
"loadstart", "progress", "loadedmetadata", "loadedfirstframe", "loadstart", "progress", "loadedmetadata", "loadedfirstframe",
"emptied", "stalled", "play", "pause", "emptied", "stalled", "play", "pause",
"waiting", "seeking", "seeked", "timeupdate", "ended", "dataunavailable", "waiting", "seeking", "seeked", "timeupdate", "ended", "dataunavailable",
"canshowcurrentframe", "canplay", "canplaythrough", "ratechange", "canshowcurrentframe", "canplay", "canplaythrough", "ratechange",
"durationchange", "volumechange" "durationchange", "volumechange",
#endif // MOZ_MEDIA #endif // MOZ_MEDIA
"MozAfterPaint"
}; };
static char *sPopupAllowedEvents; static char *sPopupAllowedEvents;
@@ -648,6 +647,11 @@ nsDOMEvent::SetEventType(const nsAString& aEventTypeArg)
mEvent->message = NS_MEDIA_ERROR; mEvent->message = NS_MEDIA_ERROR;
} }
#endif // MOZ_MEDIA #endif // MOZ_MEDIA
else if (mEvent->eventStructType == NS_NOTIFYPAINT_EVENT) {
if (atom == nsGkAtoms::onMozAfterPaint)
mEvent->message = NS_AFTERPAINT;
}
if (mEvent->message == NS_USER_DEFINED_EVENT) if (mEvent->message == NS_USER_DEFINED_EVENT)
mEvent->userType = atom; mEvent->userType = atom;
@@ -961,6 +965,14 @@ NS_METHOD nsDOMEvent::DuplicatePrivateData()
static_cast<nsXULCommandEvent*>(mEvent)->sourceEvent; static_cast<nsXULCommandEvent*>(mEvent)->sourceEvent;
break; break;
} }
case NS_NOTIFYPAINT_EVENT:
{
nsNotifyPaintEvent* event = static_cast<nsNotifyPaintEvent*>(mEvent);
newEvent =
new nsNotifyPaintEvent(PR_FALSE, msg,
event->sameDocRegion, event->crossDocRegion);
break;
}
default: default:
{ {
NS_WARNING("Unknown event type!!!"); NS_WARNING("Unknown event type!!!");
@@ -1465,6 +1477,8 @@ const char* nsDOMEvent::GetEventName(PRUint32 aEventType)
case NS_VOLUMECHANGE: case NS_VOLUMECHANGE:
return sEventNames[eDOMEvents_volumechange]; return sEventNames[eDOMEvents_volumechange];
#endif #endif
case NS_AFTERPAINT:
return sEventNames[eDOMEvents_afterpaint];
default: default:
break; break;
} }

View File

@@ -129,19 +129,17 @@ public:
eDOMEvents_online, eDOMEvents_online,
eDOMEvents_copy, eDOMEvents_copy,
eDOMEvents_cut, eDOMEvents_cut,
eDOMEvents_paste eDOMEvents_paste,
#ifdef MOZ_SVG #ifdef MOZ_SVG
,
eDOMEvents_SVGLoad, eDOMEvents_SVGLoad,
eDOMEvents_SVGUnload, eDOMEvents_SVGUnload,
eDOMEvents_SVGAbort, eDOMEvents_SVGAbort,
eDOMEvents_SVGError, eDOMEvents_SVGError,
eDOMEvents_SVGResize, eDOMEvents_SVGResize,
eDOMEvents_SVGScroll, eDOMEvents_SVGScroll,
eDOMEvents_SVGZoom eDOMEvents_SVGZoom,
#endif // MOZ_SVG #endif // MOZ_SVG
#ifdef MOZ_MEDIA #ifdef MOZ_MEDIA
,
eDOMEvents_loadstart, eDOMEvents_loadstart,
eDOMEvents_progress, eDOMEvents_progress,
eDOMEvents_loadedmetadata, eDOMEvents_loadedmetadata,
@@ -161,8 +159,9 @@ public:
eDOMEvents_canplaythrough, eDOMEvents_canplaythrough,
eDOMEvents_ratechange, eDOMEvents_ratechange,
eDOMEvents_durationchange, eDOMEvents_durationchange,
eDOMEvents_volumechange eDOMEvents_volumechange,
#endif #endif
eDOMEvents_afterpaint
}; };
nsDOMEvent(nsPresContext* aPresContext, nsEvent* aEvent); nsDOMEvent(nsPresContext* aPresContext, nsEvent* aEvent);

View File

@@ -0,0 +1,139 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* 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/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Mozilla Corporation
* Portions created by the Initial Developer are Copyright (C) 2008
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Robert O'Callahan <robert@ocallahan.org>
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsDOMNotifyPaintEvent.h"
#include "nsContentUtils.h"
#include "nsClientRect.h"
nsDOMNotifyPaintEvent::nsDOMNotifyPaintEvent(nsPresContext* aPresContext,
nsNotifyPaintEvent* aEvent)
: nsDOMEvent(aPresContext, aEvent ? aEvent :
new nsNotifyPaintEvent(PR_FALSE, 0, nsRegion(), nsRegion()))
{
if (aEvent) {
mEventIsInternal = PR_FALSE;
}
else
{
mEventIsInternal = PR_TRUE;
mEvent->time = PR_Now();
}
}
nsDOMNotifyPaintEvent::~nsDOMNotifyPaintEvent()
{
if (mEventIsInternal) {
if (mEvent->eventStructType == NS_NOTIFYPAINT_EVENT) {
delete static_cast<nsNotifyPaintEvent*>(mEvent);
mEvent = nsnull;
}
}
}
NS_INTERFACE_MAP_BEGIN(nsDOMNotifyPaintEvent)
NS_INTERFACE_MAP_ENTRY(nsIDOMNotifyPaintEvent)
NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(NotifyPaintEvent)
NS_INTERFACE_MAP_END_INHERITING(nsDOMEvent)
NS_IMPL_ADDREF_INHERITED(nsDOMNotifyPaintEvent, nsDOMEvent)
NS_IMPL_RELEASE_INHERITED(nsDOMNotifyPaintEvent, nsDOMEvent)
nsRegion
nsDOMNotifyPaintEvent::GetRegion()
{
nsNotifyPaintEvent* event = static_cast<nsNotifyPaintEvent*>(mEvent);
nsRegion r;
if (nsContentUtils::IsCallerTrustedForRead()) {
r.Or(event->sameDocRegion, event->crossDocRegion);
} else {
r = event->sameDocRegion;
}
return r;
}
NS_IMETHODIMP
nsDOMNotifyPaintEvent::GetBoundingClientRect(nsIDOMClientRect** aResult)
{
// Weak ref, since we addref it below
nsClientRect* rect = new nsClientRect();
if (!rect)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(*aResult = rect);
if (!mPresContext)
return NS_OK;
rect->SetLayoutRect(GetRegion().GetBounds(), mPresContext);
return NS_OK;
}
NS_IMETHODIMP
nsDOMNotifyPaintEvent::GetClientRects(nsIDOMClientRectList** aResult)
{
nsRefPtr<nsClientRectList> rectList = new nsClientRectList();
if (!rectList)
return NS_ERROR_OUT_OF_MEMORY;
nsRegion r = GetRegion();
nsRegionRectIterator iter(r);
for (const nsRect* rgnRect = iter.Next(); rgnRect; rgnRect = iter.Next()) {
nsRefPtr<nsClientRect> rect = new nsClientRect();
if (!rect)
return NS_ERROR_OUT_OF_MEMORY;
rect->SetLayoutRect(*rgnRect, mPresContext);
rectList->Append(rect);
}
*aResult = rectList.forget().get();
return NS_OK;
}
nsresult NS_NewDOMNotifyPaintEvent(nsIDOMEvent** aInstancePtrResult,
nsPresContext* aPresContext,
nsNotifyPaintEvent *aEvent)
{
nsDOMNotifyPaintEvent* it =
new nsDOMNotifyPaintEvent(aPresContext, aEvent);
if (nsnull == it) {
return NS_ERROR_OUT_OF_MEMORY;
}
return CallQueryInterface(it, aInstancePtrResult);
}

View File

@@ -0,0 +1,64 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* 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/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Mozilla Corporation
* Portions created by the Initial Developer are Copyright (C) 2008
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Robert O'Callahan <robert@ocallahan.org>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef nsDOMNotifyPaintEvent_h_
#define nsDOMNotifyPaintEvent_h_
#include "nsIDOMNotifyPaintEvent.h"
#include "nsDOMEvent.h"
class nsDOMNotifyPaintEvent : public nsIDOMNotifyPaintEvent,
public nsDOMEvent
{
public:
nsDOMNotifyPaintEvent(nsPresContext* aPresContext,
nsNotifyPaintEvent* aEvent);
virtual ~nsDOMNotifyPaintEvent();
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSIDOMNOTIFYPAINTEVENT
// Forward to base class
NS_FORWARD_TO_NSDOMEVENT
private:
nsRegion GetRegion();
};
#endif // nsDOMNotifyPaintEvent_h_

View File

@@ -611,6 +611,10 @@ nsEventDispatcher::CreateEvent(nsPresContext* aPresContext,
case NS_COMMAND_EVENT: case NS_COMMAND_EVENT:
return NS_NewDOMCommandEvent(aDOMEvent, aPresContext, return NS_NewDOMCommandEvent(aDOMEvent, aPresContext,
static_cast<nsCommandEvent*>(aEvent)); static_cast<nsCommandEvent*>(aEvent));
case NS_NOTIFYPAINT_EVENT:
return NS_NewDOMNotifyPaintEvent(aDOMEvent, aPresContext,
static_cast<nsNotifyPaintEvent*>
(aEvent));
} }
// For all other types of events, create a vanilla event object. // For all other types of events, create a vanilla event object.
@@ -667,6 +671,8 @@ nsEventDispatcher::CreateEvent(nsPresContext* aPresContext,
return NS_NewDOMMessageEvent(aDOMEvent, aPresContext, nsnull); return NS_NewDOMMessageEvent(aDOMEvent, aPresContext, nsnull);
if (aEventType.LowerCaseEqualsLiteral("progressevent")) if (aEventType.LowerCaseEqualsLiteral("progressevent"))
return NS_NewDOMProgressEvent(aDOMEvent, aPresContext, nsnull); return NS_NewDOMProgressEvent(aDOMEvent, aPresContext, nsnull);
if (aEventType.LowerCaseEqualsLiteral("notifypaintevent"))
return NS_NewDOMNotifyPaintEvent(aDOMEvent, aPresContext, nsnull);
return NS_ERROR_DOM_NOT_SUPPORTED_ERR; return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
} }

View File

@@ -78,6 +78,7 @@ REQUIRES = xpcom \
EXPORTS = \ EXPORTS = \
nsImageMapUtils.h \ nsImageMapUtils.h \
nsClientRect.h \
$(NULL) $(NULL)
CPPSRCS = \ CPPSRCS = \

View File

@@ -40,6 +40,8 @@
#include "nsContentUtils.h" #include "nsContentUtils.h"
#include "nsDOMClassInfoID.h" #include "nsDOMClassInfoID.h"
#include "nsPresContext.h"
NS_INTERFACE_TABLE_HEAD(nsClientRect) NS_INTERFACE_TABLE_HEAD(nsClientRect)
NS_INTERFACE_TABLE1(nsClientRect, nsIDOMClientRect) NS_INTERFACE_TABLE1(nsClientRect, nsIDOMClientRect)
NS_INTERFACE_TABLE_TO_MAP_SEGUE NS_INTERFACE_TABLE_TO_MAP_SEGUE
@@ -124,3 +126,23 @@ nsClientRectList::Item(PRUint32 aIndex, nsIDOMClientRect** aReturn)
NS_IF_ADDREF(*aReturn = mArray.ObjectAt(aIndex)); NS_IF_ADDREF(*aReturn = mArray.ObjectAt(aIndex));
return NS_OK; return NS_OK;
} }
static double
RoundFloat(double aValue)
{
return floor(aValue + 0.5);
}
void
nsClientRect::SetLayoutRect(const nsRect& aLayoutRect, nsPresContext* aPresContext)
{
double scale = 65536.0;
// Round to the nearest 1/scale units. We choose scale so it can be represented
// exactly by machine floating point.
double scaleInv = 1/scale;
double t2pScaled = scale/aPresContext->AppUnitsPerCSSPixel();
double x = RoundFloat(aLayoutRect.x*t2pScaled)*scaleInv;
double y = RoundFloat(aLayoutRect.y*t2pScaled)*scaleInv;
SetRect(x, y, RoundFloat(aLayoutRect.XMost()*t2pScaled)*scaleInv - x,
RoundFloat(aLayoutRect.YMost()*t2pScaled)*scaleInv - y);
}

View File

@@ -42,6 +42,9 @@
#include "nsIDOMClientRect.h" #include "nsIDOMClientRect.h"
#include "nsIDOMClientRectList.h" #include "nsIDOMClientRectList.h"
#include "nsCOMArray.h" #include "nsCOMArray.h"
#include "nsRect.h"
class nsPresContext;
class nsClientRect : public nsIDOMClientRect class nsClientRect : public nsIDOMClientRect
{ {
@@ -56,6 +59,8 @@ public:
NS_DECL_NSIDOMCLIENTRECT NS_DECL_NSIDOMCLIENTRECT
void SetLayoutRect(const nsRect& aLayoutRect, nsPresContext* aPresContext);
protected: protected:
float mX, mY, mWidth, mHeight; float mX, mY, mWidth, mHeight;
}; };

View File

@@ -552,7 +552,7 @@ nsHTMLCanvasElement::InvalidateFrame()
if (frame) { if (frame) {
nsRect r = frame->GetRect(); nsRect r = frame->GetRect();
r.x = r.y = 0; r.x = r.y = 0;
frame->Invalidate(r, PR_FALSE); frame->Invalidate(r);
} }
return NS_OK; return NS_OK;
@@ -563,7 +563,7 @@ nsHTMLCanvasElement::InvalidateFrameSubrect(const nsRect& damageRect)
{ {
nsIFrame *frame = GetPrimaryFrame(Flush_Frames); nsIFrame *frame = GetPrimaryFrame(Flush_Frames);
if (frame) { if (frame) {
frame->Invalidate(damageRect, PR_FALSE); frame->Invalidate(damageRect);
} }
return NS_OK; return NS_OK;

View File

@@ -140,7 +140,7 @@ void nsVideoDecoder::Invalidate()
} }
} }
nsRect r(nsPoint(0,0), frame->GetSize()); nsRect r(nsPoint(0,0), frame->GetSize());
frame->Invalidate(r, PR_FALSE); frame->Invalidate(r);
} }
static void ProgressCallback(nsITimer* aTimer, void* aClosure) static void ProgressCallback(nsITimer* aTimer, void* aClosure)

View File

@@ -76,6 +76,7 @@ XPIDLSRCS = \
nsIDOMPageTransitionEvent.idl \ nsIDOMPageTransitionEvent.idl \
nsIDOMCommandEvent.idl \ nsIDOMCommandEvent.idl \
nsIDOMMessageEvent.idl \ nsIDOMMessageEvent.idl \
nsIDOMNotifyPaintEvent.idl \
$(NULL) $(NULL)
include $(topsrcdir)/config/rules.mk include $(topsrcdir)/config/rules.mk

View File

@@ -0,0 +1,67 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* 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/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Mozilla Corporation
* Portions created by the Initial Developer are Copyright (C) 2008
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Robert O'Callahan <robert@ocallahan.org>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsIDOMEvent.idl"
/**
* The nsIDOMNotifyPaintEvent interface is used for the MozDOMAfterPaint
* event, which fires at a window when painting has happened in
* that window.
*/
[scriptable, uuid(dec5582e-5cea-412f-bf98-6b27480fb46a)]
interface nsIDOMNotifyPaintEvent : nsIDOMEvent
{
/**
* Get a list of rectangles which are affected. The rectangles are in CSS pixels
* relative to the viewport origin.
* If the caller is not trusted (e.g., regular Web content) then only painting
* caused by the current document is reported; in particular, painting in subdocuments
* is not reported.
*/
readonly attribute nsIDOMClientRectList clientRects;
/**
* Get the bounding box of the rectangles which are affected. The rectangle
* is in CSS pixels relative to the viewport origin.
* If the caller is not trusted (e.g., regular Web content) then only painting
* caused by the current document is reported; in particular, painting in subdocuments
* is not reported.
*/
readonly attribute nsIDOMClientRect boundingClientRect;
};

View File

@@ -451,6 +451,8 @@ enum nsDOMClassInfoID {
eDOMClassInfo_DataTransfer_id, eDOMClassInfo_DataTransfer_id,
eDOMClassInfo_NotifyPaintEvent_id,
// This one better be the last one in this list // This one better be the last one in this list
eDOMClassInfoIDCount eDOMClassInfoIDCount
}; };

View File

@@ -242,6 +242,7 @@
#include "nsIDOMXULCommandEvent.h" #include "nsIDOMXULCommandEvent.h"
#include "nsIDOMPageTransitionEvent.h" #include "nsIDOMPageTransitionEvent.h"
#include "nsIDOMMessageEvent.h" #include "nsIDOMMessageEvent.h"
#include "nsIDOMNotifyPaintEvent.h"
#include "nsIDOMNSDocumentStyle.h" #include "nsIDOMNSDocumentStyle.h"
#include "nsIDOMDocumentRange.h" #include "nsIDOMDocumentRange.h"
#include "nsIDOMDocumentTraversal.h" #include "nsIDOMDocumentTraversal.h"
@@ -1290,6 +1291,8 @@ static nsDOMClassInfoData sClassInfoData[] = {
NS_DEFINE_CLASSINFO_DATA(DataTransfer, nsDOMGenericSH, NS_DEFINE_CLASSINFO_DATA(DataTransfer, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS) DOM_DEFAULT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(NotifyPaintEvent, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
}; };
// Objects that shuld be constructable through |new Name();| // Objects that shuld be constructable through |new Name();|
@@ -3529,6 +3532,11 @@ nsDOMClassInfo::Init()
DOM_CLASSINFO_MAP_ENTRY(nsIDOMNSDataTransfer) DOM_CLASSINFO_MAP_ENTRY(nsIDOMNSDataTransfer)
DOM_CLASSINFO_MAP_END DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN(NotifyPaintEvent, nsIDOMNotifyPaintEvent)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMNotifyPaintEvent)
DOM_CLASSINFO_EVENT_MAP_ENTRIES
DOM_CLASSINFO_MAP_END
#ifdef NS_DEBUG #ifdef NS_DEBUG
{ {
PRUint32 i = NS_ARRAY_LENGTH(sClassInfoData); PRUint32 i = NS_ARRAY_LENGTH(sClassInfoData);

View File

@@ -178,7 +178,7 @@ nsDOMWindowUtils::Redraw(PRUint32 aCount, PRUint32 *aDurationOut)
PRIntervalTime iStart = PR_IntervalNow(); PRIntervalTime iStart = PR_IntervalNow();
for (PRUint32 i = 0; i < aCount; i++) for (PRUint32 i = 0; i < aCount; i++)
rootFrame->Invalidate(r, PR_TRUE); rootFrame->InvalidateWithFlags(r, nsIFrame::INVALIDATE_IMMEDIATE);
#if defined(MOZ_X11) && defined(MOZ_WIDGET_GTK2) #if defined(MOZ_X11) && defined(MOZ_WIDGET_GTK2)
XSync(GDK_DISPLAY(), False); XSync(GDK_DISPLAY(), False);

View File

@@ -1278,7 +1278,7 @@ void nsCaret::InvalidateRects(const nsRect &aRect, const nsRect &aHook,
NS_ASSERTION(aFrame, "Must have a frame to invalidate"); NS_ASSERTION(aFrame, "Must have a frame to invalidate");
nsRect rect; nsRect rect;
rect.UnionRect(aRect, aHook); rect.UnionRect(aRect, aHook);
aFrame->Invalidate(rect, PR_FALSE); aFrame->Invalidate(rect);
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------

View File

@@ -257,5 +257,5 @@ nsImageLoader::RedrawDirtyFrame(const nsRect* aDamageRect)
#endif #endif
mFrame->Invalidate(bounds, PR_FALSE); mFrame->Invalidate(bounds);
} }

View File

@@ -82,6 +82,7 @@
#include "nsCSSRuleProcessor.h" #include "nsCSSRuleProcessor.h"
#include "nsStyleChangeList.h" #include "nsStyleChangeList.h"
#include "nsRuleNode.h" #include "nsRuleNode.h"
#include "nsEventDispatcher.h"
#ifdef IBMBIDI #ifdef IBMBIDI
#include "nsBidiPresUtils.h" #include "nsBidiPresUtils.h"
@@ -1569,3 +1570,54 @@ nsPresContext::HasAuthorSpecifiedRules(nsIFrame *aFrame, PRUint32 ruleTypeMask)
return nsRuleNode:: return nsRuleNode::
HasAuthorSpecifiedRules(aFrame->GetStyleContext(), ruleTypeMask); HasAuthorSpecifiedRules(aFrame->GetStyleContext(), ruleTypeMask);
} }
void
nsPresContext::FireDOMPaintEvent()
{
nsCOMPtr<nsIDocShell> docShell(do_QueryReferent(mContainer));
if (!docShell)
return;
nsCOMPtr<nsPIDOMWindow> ourWindow = do_GetInterface(docShell);
nsISupports* eventTarget = ourWindow;
if (mSameDocDirtyRegion.IsEmpty() && !IsChrome()) {
// Don't tell the window about this event, it should not know that
// something happened in a subdocument. Tell only the chrome event handler.
// (Events sent to the window get propagated to the chrome event handler
// automatically.)
eventTarget = ourWindow->GetChromeEventHandler();
}
// Events sent to the window get propagated to the chrome event handler
// automatically.
nsNotifyPaintEvent event(PR_TRUE, NS_AFTERPAINT, mSameDocDirtyRegion,
mCrossDocDirtyRegion);
// Empty our regions now in case dispatching the event causes more damage
// (hopefully it won't, or we're likely to get an infinite loop! At least
// it won't be blocking app execution though).
mSameDocDirtyRegion.SetEmpty();
mCrossDocDirtyRegion.SetEmpty();
// Even if we're not telling the window about the event (so eventTarget is
// the chrome event handler, not the window), the window is still
// logically the event target.
event.target = do_QueryInterface(ourWindow);
nsEventDispatcher::Dispatch(eventTarget, this, &event);
}
void
nsPresContext::NotifyInvalidation(const nsRect& aRect, PRBool aIsCrossDoc)
{
if (aRect.IsEmpty())
return;
if (mSameDocDirtyRegion.IsEmpty() && mCrossDocDirtyRegion.IsEmpty()) {
// No event is pending. Dispatch one now.
nsCOMPtr<nsIRunnable> ev =
new nsRunnableMethod<nsPresContext>(this,
&nsPresContext::FireDOMPaintEvent);
NS_DispatchToCurrentThread(ev);
}
nsRegion* r = aIsCrossDoc ? &mCrossDocDirtyRegion : &mSameDocDirtyRegion;
r->Or(*r, aRect);
r->SimplifyOutward(10);
}

View File

@@ -65,6 +65,7 @@
#include "nsChangeHint.h" #include "nsChangeHint.h"
// This also pulls in gfxTypes.h, which we cannot include directly. // This also pulls in gfxTypes.h, which we cannot include directly.
#include "gfxRect.h" #include "gfxRect.h"
#include "nsRegion.h"
class nsImageLoader; class nsImageLoader;
#ifdef IBMBIDI #ifdef IBMBIDI
class nsBidiPresUtils; class nsBidiPresUtils;
@@ -778,6 +779,9 @@ public:
PRBool SupressingResizeReflow() const { return mSupressResizeReflow; } PRBool SupressingResizeReflow() const { return mSupressResizeReflow; }
void NotifyInvalidation(const nsRect& aRect, PRBool aIsCrossDoc);
void FireDOMPaintEvent();
protected: protected:
friend class nsRunnableMethod<nsPresContext>; friend class nsRunnableMethod<nsPresContext>;
NS_HIDDEN_(void) ThemeChangedInternal(); NS_HIDDEN_(void) ThemeChangedInternal();
@@ -838,6 +842,9 @@ protected:
nsPropertyTable mPropertyTable; nsPropertyTable mPropertyTable;
nsRegion mSameDocDirtyRegion;
nsRegion mCrossDocDirtyRegion;
nsLanguageSpecificTransformType mLanguageSpecificTransformType; nsLanguageSpecificTransformType mLanguageSpecificTransformType;
PRInt32 mFontScaler; PRInt32 mFontScaler;
nscoord mMinimumFontSize; nscoord mMinimumFontSize;

View File

@@ -4312,7 +4312,7 @@ PresShell::UnsuppressAndInvalidate()
if (rootFrame) { if (rootFrame) {
// let's assume that outline on a root frame is not supported // let's assume that outline on a root frame is not supported
nsRect rect(nsPoint(0, 0), rootFrame->GetSize()); nsRect rect(nsPoint(0, 0), rootFrame->GetSize());
rootFrame->Invalidate(rect, PR_FALSE); rootFrame->Invalidate(rect);
} }
// This makes sure to get the same thing that nsPresContext::EnsureVisible() // This makes sure to get the same thing that nsPresContext::EnsureVisible()

View File

@@ -92,6 +92,7 @@ _TEST_FILES = \
test_bug423523.html \ test_bug423523.html \
test_bug445810.html \ test_bug445810.html \
test_bug449781.html \ test_bug449781.html \
test_bug450930.xhtml \
$(NULL) $(NULL)
# test_bug396024.html is currently disabled because it interacts badly with # test_bug396024.html is currently disabled because it interacts badly with
# the "You can't print-preview while the page is loading" dialog. # the "You can't print-preview while the page is loading" dialog.

View File

@@ -0,0 +1,211 @@
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:svg="http://www.w3.org/2000/svg">
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=450930
-->
<head>
<title>Test for Bug 450930</title>
<script type="text/javascript" src="/MochiKit/packed.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=450930">Mozilla Bug 450930</a>
<div id="display">
<div id="d" style="width:400px; height:200px;"></div>
<iframe id="iframe" style="width:400px; height:200px;"
src="data:text/html,&lt;div id='d'&gt;Hello&lt;/div&gt;&lt;div style='margin-top:500px' id='d2'&gt;Hello&lt;/div>"></iframe>
<svg:svg style="width:410px; height:210px;" id="svg">
<svg:foreignObject width="100%" height="100%">
<iframe id="iframe2" style="width:400px; height:200px;"
src="data:text/html,&lt;div id='d'&gt;Hello&lt;/div&gt;&lt;div style='margin-top:500px' id='d2'&gt;Hello&lt;/div>"></iframe>
</svg:foreignObject>
</svg:svg>
</div>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="text/javascript"><![CDATA[
/** Test for Bug 450930 **/
SimpleTest.waitForExplicitFinish();
function flash(doc, name) {
var d = doc.getElementById(name);
d.style.backgroundColor = d.style.backgroundColor == "blue" ? "yellow" : "blue";
}
function le(v1, v2, s) {
ok(v1 <= v2, s + " (" + v1 + "," + v2 + ")");
}
function checkContains(r1, r2, s) {
le(r1.left, r2.left, "Left edges out" + s);
le(r2.right, r1.right, "Right edges out" + s);
le(r1.top, r2.top, "Top edges out" + s);
le(r2.bottom, r1.bottom, "Bottom edges out" + s);
}
function isRect(r1, r2) {
return r1.left == r2.left && r1.right == r2.right &&
r1.top == r2.top && r1.bottom == r2.bottom;
}
function isRectInList(r, list) {
for (var i = 0; i < list.length; ++i) {
if (isRect(r, list[i]))
return true;
}
return false;
}
function doesRectContain(r1, r2) {
return r1.left <= r2.left && r2.right <= r1.right &&
r1.top <= r2.top && r2.bottom <= r1.bottom;
}
function rectToString(r) {
return "(" + r.left + "," + r.top + "," + r.right + "," + r.bottom + ")";
}
function doesRectContainListElement(r, list) {
dump("Incoming rect: " + rectToString(r) + "\n");
for (var i = 0; i < list.length; ++i) {
dump("List rect " + i + ": " + rectToString(list[i]));
if (doesRectContain(r, list[i])) {
dump(" FOUND\n");
return true;
}
dump("\n");
}
dump("NOT FOUND\n");
return false;
}
function checkGotSubdoc(list, container) {
var r = container.getBoundingClientRect();
return doesRectContainListElement(r, list);
}
function runTest1() {
// test basic functionality
var iterations = 0;
var foundExactRect = false;
function listener(event) {
var r = event.boundingClientRect;
var bounds = document.getElementById('d').getBoundingClientRect();
checkContains(r, bounds, "");
if (isRectInList(bounds, event.clientRects)) {
foundExactRect = true;
}
window.removeEventListener("MozAfterPaint", listener, false);
++iterations;
if (iterations < 4) {
setTimeout(triggerPaint, 100);
} else {
ok(foundExactRect, "Found exact rect");
runNext();
}
}
function triggerPaint() {
window.addEventListener("MozAfterPaint", listener, false);
flash(document, 'd');
}
triggerPaint();
}
function runTest2(frameID, containerID) {
// test reporting of painting in subdocuments
var fired = false;
var gotSubdocPrivileged = false;
var gotSubdocNonprivileged = false;
var iframe = document.getElementById(frameID);
var container = document.getElementById(containerID);
function listener(event) {
fired = true;
if (checkGotSubdoc(event.clientRects, container))
gotSubdocNonprivileged = true;
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
if (checkGotSubdoc(event.clientRects, container))
gotSubdocPrivileged = true;
}
function check() {
ok(fired, "Event fired (" + frameID + ")");
ok(gotSubdocPrivileged, "Didn't get subdoc invalidation while we were privileged (" + frameID + ")");
ok(!gotSubdocNonprivileged, "Got subdoc invalidation while we were not privileged (" + frameID + ")");
window.removeEventListener("MozAfterPaint", listener, false);
runNext();
}
function triggerPaint() {
window.addEventListener("MozAfterPaint", listener, false);
setTimeout(check, 100);
document.body.offsetTop;
flash(iframe.contentDocument, 'd');
// make sure an event fires; since we're not using a chrome event handler, even though we
// can get privileges we wouldn't get the event
flash(document, 'd');
}
triggerPaint();
}
function runTest3() {
// test reporting of painting of scrolled-out-of-view areas
var gotScrolledOutInMainDoc = false;
var gotScrolledOutInSubdoc = false;
var iframe = document.getElementById("iframe");
function listener(event) {
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
if (checkGotSubdoc(event.clientRects, iframe))
gotScrolledOutInMainDoc = true;
}
function IFRAMEListener(event) {
if (doesRectContainListElement(
iframe.contentDocument.getElementById("d2").getBoundingClientRect(), event.clientRects))
gotScrolledOutInSubdoc = true;
}
function check() {
ok(!gotScrolledOutInMainDoc, "scrolled-out invalidation should not propagate to main doc");
ok(gotScrolledOutInSubdoc, "scrolled-out invalidation should notify in subdoc");
window.removeEventListener("MozAfterPaint", listener, false);
iframe.contentWindow.removeEventListener("MozAfterPaint", IFRAMEListener, false);
runNext();
}
function triggerPaint() {
window.addEventListener("MozAfterPaint", listener, false);
iframe.contentWindow.addEventListener("MozAfterPaint", IFRAMEListener, false);
setTimeout(check, 100);
flash(iframe.contentDocument, 'd2');
}
triggerPaint();
}
var test = 0;
var tests = [runTest1,
function() { runTest2("iframe", "iframe") },
function() { runTest2("iframe2", "svg") },
runTest3];
function runNext() {
if (test < tests.length) {
++test;
tests[test - 1]();
} else {
SimpleTest.finish();
}
}
window.onload = runNext();
]]></script>
</pre>
</body>
</html>

View File

@@ -360,7 +360,7 @@ nsComboboxControlFrame::SetFocus(PRBool aOn, PRBool aRepaint)
// This is needed on a temporary basis. It causes the focus // This is needed on a temporary basis. It causes the focus
// rect to be drawn. This is much faster than ReResolvingStyle // rect to be drawn. This is much faster than ReResolvingStyle
// Bug 32920 // Bug 32920
Invalidate(nsRect(0,0,mRect.width,mRect.height), PR_FALSE); Invalidate(nsRect(0,0,mRect.width,mRect.height));
// Make sure the content area gets updated for where the dropdown was // Make sure the content area gets updated for where the dropdown was
// This is only needed for embedding, the focus may go to // This is only needed for embedding, the focus may go to

View File

@@ -165,7 +165,7 @@ NS_IMETHODIMP
nsGfxCheckboxControlFrame::OnChecked(nsPresContext* aPresContext, nsGfxCheckboxControlFrame::OnChecked(nsPresContext* aPresContext,
PRBool aChecked) PRBool aChecked)
{ {
Invalidate(GetOverflowRect(), PR_FALSE); InvalidateOverflowRect();
return NS_OK; return NS_OK;
} }

View File

@@ -216,7 +216,7 @@ NS_IMETHODIMP
nsGfxRadioControlFrame::OnChecked(nsPresContext* aPresContext, nsGfxRadioControlFrame::OnChecked(nsPresContext* aPresContext,
PRBool aChecked) PRBool aChecked)
{ {
Invalidate(GetOverflowRect(), PR_FALSE); InvalidateOverflowRect();
return NS_OK; return NS_OK;
} }

View File

@@ -1818,11 +1818,13 @@ nsListControlFrame::IsContainingBlock() const
void void
nsListControlFrame::InvalidateInternal(const nsRect& aDamageRect, nsListControlFrame::InvalidateInternal(const nsRect& aDamageRect,
nscoord aX, nscoord aY, nsIFrame* aForChild, nscoord aX, nscoord aY, nsIFrame* aForChild,
PRBool aImmediate) PRUint32 aFlags)
{ {
if (!IsInDropDownMode()) if (!IsInDropDownMode()) {
nsHTMLScrollFrame::InvalidateInternal(aDamageRect, aX, aY, this, aImmediate); nsHTMLScrollFrame::InvalidateInternal(aDamageRect, aX, aY, this, aFlags);
InvalidateRoot(aDamageRect, aX, aY, aImmediate); return;
}
InvalidateRoot(aDamageRect + nsPoint(aX, aY), aFlags);
} }
#ifdef DEBUG #ifdef DEBUG

View File

@@ -131,7 +131,7 @@ public:
virtual void InvalidateInternal(const nsRect& aDamageRect, virtual void InvalidateInternal(const nsRect& aDamageRect,
nscoord aX, nscoord aY, nsIFrame* aForChild, nscoord aX, nscoord aY, nsIFrame* aForChild,
PRBool aImmediate); PRUint32 aFlags);
#ifdef DEBUG #ifdef DEBUG
// nsIFrameDebug // nsIFrameDebug

View File

@@ -484,7 +484,7 @@ nsBlockFrame::GetType() const
void void
nsBlockFrame::InvalidateInternal(const nsRect& aDamageRect, nsBlockFrame::InvalidateInternal(const nsRect& aDamageRect,
nscoord aX, nscoord aY, nsIFrame* aForChild, nscoord aX, nscoord aY, nsIFrame* aForChild,
PRBool aImmediate) PRUint32 aFlags)
{ {
// Optimize by suppressing invalidation of areas that are clipped out // Optimize by suppressing invalidation of areas that are clipped out
// with CSS 'clip'. // with CSS 'clip'.
@@ -495,12 +495,12 @@ nsBlockFrame::InvalidateInternal(const nsRect& aDamageRect,
// abs-pos clipping clips everything in the frame // abs-pos clipping clips everything in the frame
nsRect r; nsRect r;
if (r.IntersectRect(aDamageRect, absPosClipRect - nsPoint(aX, aY))) { if (r.IntersectRect(aDamageRect, absPosClipRect - nsPoint(aX, aY))) {
nsBlockFrameSuper::InvalidateInternal(r, aX, aY, this, aImmediate); nsBlockFrameSuper::InvalidateInternal(r, aX, aY, this, aFlags);
} }
return; return;
} }
nsBlockFrameSuper::InvalidateInternal(aDamageRect, aX, aY, this, aImmediate); nsBlockFrameSuper::InvalidateInternal(aDamageRect, aX, aY, this, aFlags);
} }
nscoord nscoord

View File

@@ -187,7 +187,7 @@ public:
const nsDisplayListSet& aLists); const nsDisplayListSet& aLists);
virtual void InvalidateInternal(const nsRect& aDamageRect, virtual void InvalidateInternal(const nsRect& aDamageRect,
nscoord aX, nscoord aY, nsIFrame* aForChild, nscoord aX, nscoord aY, nsIFrame* aForChild,
PRBool aImmediate); PRUint32 aFlags);
virtual nsIAtom* GetType() const; virtual nsIAtom* GetType() const;
virtual PRBool IsFrameOfType(PRUint32 aFlags) const virtual PRBool IsFrameOfType(PRUint32 aFlags) const
{ {

View File

@@ -1467,7 +1467,7 @@ NS_IMETHODIMP nsBulletFrame::OnDataAvailable(imgIRequest *aRequest,
// The image has changed. // The image has changed.
// Invalidate the entire content area. Maybe it's not optimal but it's simple and // Invalidate the entire content area. Maybe it's not optimal but it's simple and
// always correct, and I'll be a stunned mullet if it ever matters for performance // always correct, and I'll be a stunned mullet if it ever matters for performance
Invalidate(nsRect(0, 0, mRect.width, mRect.height), PR_FALSE); Invalidate(nsRect(0, 0, mRect.width, mRect.height));
return NS_OK; return NS_OK;
} }
@@ -1497,7 +1497,7 @@ NS_IMETHODIMP nsBulletFrame::FrameChanged(imgIContainer *aContainer,
{ {
// Invalidate the entire content area. Maybe it's not optimal but it's simple and // Invalidate the entire content area. Maybe it's not optimal but it's simple and
// always correct. // always correct.
Invalidate(nsRect(0, 0, mRect.width, mRect.height), PR_FALSE); Invalidate(nsRect(0, 0, mRect.width, mRect.height));
return NS_OK; return NS_OK;
} }

View File

@@ -3634,8 +3634,7 @@ nsIFrame::IsLeaf() const
} }
void void
nsIFrame::Invalidate(const nsRect& aDamageRect, nsIFrame::InvalidateWithFlags(const nsRect& aDamageRect, PRUint32 aFlags)
PRBool aImmediate)
{ {
if (aDamageRect.IsEmpty()) { if (aDamageRect.IsEmpty()) {
return; return;
@@ -3651,7 +3650,7 @@ nsIFrame::Invalidate(const nsRect& aDamageRect,
return; return;
} }
InvalidateInternal(aDamageRect, 0, 0, nsnull, aImmediate); InvalidateInternal(aDamageRect, 0, 0, nsnull, aFlags);
} }
/** /**
@@ -3667,7 +3666,7 @@ nsIFrame::Invalidate(const nsRect& aDamageRect,
*/ */
void void
nsIFrame::InvalidateInternalAfterResize(const nsRect& aDamageRect, nscoord aX, nsIFrame::InvalidateInternalAfterResize(const nsRect& aDamageRect, nscoord aX,
nscoord aY, PRBool aImmediate) nscoord aY, PRUint32 aFlags)
{ {
/* If we're a transformed frame, then we need to apply our transform to the /* If we're a transformed frame, then we need to apply our transform to the
* damage rectangle so that the redraw correctly redraws the transformed * damage rectangle so that the redraw correctly redraws the transformed
@@ -3692,16 +3691,16 @@ nsIFrame::InvalidateInternalAfterResize(const nsRect& aDamageRect, nscoord aX,
(aDamageRect, this, nsPoint(-aX, -aY)), aDamageRect); (aDamageRect, this, nsPoint(-aX, -aY)), aDamageRect);
GetParent()-> GetParent()->
InvalidateInternal(newDamageRect, aX + mRect.x, aY + mRect.y, this, InvalidateInternal(newDamageRect, aX + mRect.x, aY + mRect.y, this,
aImmediate); aFlags);
} }
else else
GetParent()-> GetParent()->
InvalidateInternal(aDamageRect, aX + mRect.x, aY + mRect.y, this, aImmediate); InvalidateInternal(aDamageRect, aX + mRect.x, aY + mRect.y, this, aFlags);
} }
void void
nsIFrame::InvalidateInternal(const nsRect& aDamageRect, nscoord aX, nscoord aY, nsIFrame::InvalidateInternal(const nsRect& aDamageRect, nscoord aX, nscoord aY,
nsIFrame* aForChild, PRBool aImmediate) nsIFrame* aForChild, PRUint32 aFlags)
{ {
#ifdef MOZ_SVG #ifdef MOZ_SVG
if (nsSVGIntegrationUtils::UsingEffectsForFrame(this)) { if (nsSVGIntegrationUtils::UsingEffectsForFrame(this)) {
@@ -3711,12 +3710,12 @@ nsIFrame::InvalidateInternal(const nsRect& aDamageRect, nscoord aX, nscoord aY,
* zero. Thus we'll pretend that the entire time this was in our own * zero. Thus we'll pretend that the entire time this was in our own
* local coordinate space and do any remaining processing. * local coordinate space and do any remaining processing.
*/ */
InvalidateInternalAfterResize(r, 0, 0, aImmediate); InvalidateInternalAfterResize(r, 0, 0, aFlags);
return; return;
} }
#endif #endif
InvalidateInternalAfterResize(aDamageRect, aX, aY, aImmediate); InvalidateInternalAfterResize(aDamageRect, aX, aY, aFlags);
} }
gfxMatrix gfxMatrix
@@ -3800,13 +3799,16 @@ nsIFrame::InvalidateOverflowRect()
} }
void void
nsIFrame::InvalidateRoot(const nsRect& aDamageRect, nsIFrame::InvalidateRoot(const nsRect& aDamageRect, PRUint32 aFlags)
nscoord aX, nscoord aY, PRBool aImmediate)
{ {
PRUint32 flags = aImmediate ? NS_VMREFRESH_IMMEDIATE : NS_VMREFRESH_NO_SYNC; if (aFlags & INVALIDATE_NOTIFY_ONLY)
return;
PRUint32 flags =
(aFlags & INVALIDATE_IMMEDIATE) ? NS_VMREFRESH_IMMEDIATE : NS_VMREFRESH_NO_SYNC;
nsIView* view = GetView(); nsIView* view = GetView();
NS_ASSERTION(view, "This can only be called on frames with views"); NS_ASSERTION(view, "This can only be called on frames with views");
view->GetViewManager()->UpdateView(view, aDamageRect + nsPoint(aX, aY), flags); view->GetViewManager()->UpdateView(view, aDamageRect, flags);
} }
static void static void
@@ -4443,7 +4445,7 @@ nsFrame::SetSelected(nsPresContext* aPresContext, nsIDOMRange *aRange, PRBool aS
RemoveStateBits(NS_FRAME_SELECTED_CONTENT); RemoveStateBits(NS_FRAME_SELECTED_CONTENT);
// Repaint this frame subtree's entire area // Repaint this frame subtree's entire area
Invalidate(GetOverflowRect(), PR_FALSE); InvalidateOverflowRect();
#ifdef IBMBIDI #ifdef IBMBIDI
PRInt32 start, end; PRInt32 start, end;

View File

@@ -567,7 +567,7 @@ nsSubDocumentFrame::Reflow(nsPresContext* aPresContext,
// Invalidate the frame contents // Invalidate the frame contents
// XXX is this really needed? // XXX is this really needed?
nsRect rect(nsPoint(0, 0), GetSize()); nsRect rect(nsPoint(0, 0), GetSize());
Invalidate(rect, PR_FALSE); Invalidate(rect);
if (!aPresContext->IsPaginated() && !mPostedReflowCallback) { if (!aPresContext->IsPaginated() && !mPostedReflowCallback) {
PresContext()->PresShell()->PostReflowCallback(this); PresContext()->PresShell()->PostReflowCallback(this);

View File

@@ -227,19 +227,30 @@ nsHTMLScrollFrame::GetType() const
void void
nsHTMLScrollFrame::InvalidateInternal(const nsRect& aDamageRect, nsHTMLScrollFrame::InvalidateInternal(const nsRect& aDamageRect,
nscoord aX, nscoord aY, nsIFrame* aForChild, nscoord aX, nscoord aY, nsIFrame* aForChild,
PRBool aImmediate) PRUint32 aFlags)
{ {
if (aForChild == mInner.mScrolledFrame) { if (aForChild == mInner.mScrolledFrame && !(aFlags & INVALIDATE_NOTIFY_ONLY)) {
// restrict aDamageRect to the scrollable view's bounds // restrict aDamageRect to the scrollable view's bounds
nsRect damage = aDamageRect + nsPoint(aX, aY);
nsRect r; nsRect r;
if (r.IntersectRect(aDamageRect + nsPoint(aX, aY), if (r.IntersectRect(damage, mInner.mScrollableView->View()->GetBounds())) {
mInner.mScrollableView->View()->GetBounds())) { nsHTMLContainerFrame::InvalidateInternal(r, 0, 0, aForChild, aFlags);
nsHTMLContainerFrame::InvalidateInternal(r, 0, 0, aForChild, aImmediate); }
if (mInner.mIsRoot && r != damage) {
// Make sure we notify our prescontext about invalidations outside
// viewport clipping.
// This is important for things that are snapshotting the viewport,
// possibly outside the scrolled bounds.
// We don't need to propagate this any further up, though. Anyone who
// cares about scrolled-out-of-view invalidates had better be listening
// to our window directly.
PresContext()->NotifyInvalidation(damage,
(aFlags & INVALIDATE_CROSS_DOC) != 0);
} }
return; return;
} }
nsHTMLContainerFrame::InvalidateInternal(aDamageRect, aX, aY, aForChild, aImmediate); nsHTMLContainerFrame::InvalidateInternal(aDamageRect, aX, aY, aForChild, aFlags);
} }
/** /**
@@ -1097,19 +1108,19 @@ nsXULScrollFrame::GetType() const
void void
nsXULScrollFrame::InvalidateInternal(const nsRect& aDamageRect, nsXULScrollFrame::InvalidateInternal(const nsRect& aDamageRect,
nscoord aX, nscoord aY, nsIFrame* aForChild, nscoord aX, nscoord aY, nsIFrame* aForChild,
PRBool aImmediate) PRUint32 aFlags)
{ {
if (aForChild == mInner.mScrolledFrame) { if (aForChild == mInner.mScrolledFrame) {
// restrict aDamageRect to the scrollable view's bounds // restrict aDamageRect to the scrollable view's bounds
nsRect r; nsRect r;
if (r.IntersectRect(aDamageRect + nsPoint(aX, aY), if (r.IntersectRect(aDamageRect + nsPoint(aX, aY),
mInner.mScrollableView->View()->GetBounds())) { mInner.mScrollableView->View()->GetBounds())) {
nsBoxFrame::InvalidateInternal(r, 0, 0, aForChild, aImmediate); nsBoxFrame::InvalidateInternal(r, 0, 0, aForChild, aFlags);
} }
return; return;
} }
nsBoxFrame::InvalidateInternal(aDamageRect, aX, aY, aForChild, aImmediate); nsBoxFrame::InvalidateInternal(aDamageRect, aX, aY, aForChild, aFlags);
} }
nscoord nscoord
@@ -1822,6 +1833,9 @@ nsGfxScrollFrameInner::ScrollPositionDidChange(nsIScrollableView* aScrollable, n
PostScrollEvent(); PostScrollEvent();
// Notify that the display has changed
mOuter->InvalidateWithFlags(nsRect(nsPoint(0, 0), mOuter->GetSize()),
nsIFrame::INVALIDATE_NOTIFY_ONLY);
return NS_OK; return NS_OK;
} }

View File

@@ -313,7 +313,7 @@ public:
virtual void InvalidateInternal(const nsRect& aDamageRect, virtual void InvalidateInternal(const nsRect& aDamageRect,
nscoord aX, nscoord aY, nsIFrame* aForChild, nscoord aX, nscoord aY, nsIFrame* aForChild,
PRBool aImmediate); PRUint32 aFlags);
virtual PRBool NeedsView() { return PR_TRUE; } virtual PRBool NeedsView() { return PR_TRUE; }
virtual PRBool DoesClipChildren() { return PR_TRUE; } virtual PRBool DoesClipChildren() { return PR_TRUE; }
@@ -478,7 +478,7 @@ public:
virtual void InvalidateInternal(const nsRect& aDamageRect, virtual void InvalidateInternal(const nsRect& aDamageRect,
nscoord aX, nscoord aY, nsIFrame* aForChild, nscoord aX, nscoord aY, nsIFrame* aForChild,
PRBool aImmediate); PRUint32 aFlags);
virtual PRBool NeedsView() { return PR_TRUE; } virtual PRBool NeedsView() { return PR_TRUE; }
virtual PRBool DoesClipChildren() { return PR_TRUE; } virtual PRBool DoesClipChildren() { return PR_TRUE; }

View File

@@ -160,7 +160,7 @@ nsHTMLCanvasFrame::Reflow(nsPresContext* aPresContext,
FinishAndStoreOverflow(&aMetrics); FinishAndStoreOverflow(&aMetrics);
if (mRect.width != aMetrics.width || mRect.height != aMetrics.height) { if (mRect.width != aMetrics.width || mRect.height != aMetrics.height) {
Invalidate(nsRect(0, 0, mRect.width, mRect.height), PR_FALSE); Invalidate(nsRect(0, 0, mRect.width, mRect.height));
} }
NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS, NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,

View File

@@ -370,7 +370,7 @@ CanvasFrame::RemoveFrame(nsIAtom* aListName,
// Damage the area occupied by the deleted frame // Damage the area occupied by the deleted frame
// The child of the canvas probably can't have an outline, but why bother // The child of the canvas probably can't have an outline, but why bother
// thinking about that? // thinking about that?
Invalidate(aOldFrame->GetOverflowRect() + aOldFrame->GetPosition(), PR_FALSE); Invalidate(aOldFrame->GetOverflowRect() + aOldFrame->GetPosition());
// Remove the frame and destroy it // Remove the frame and destroy it
mFrames.DestroyFrame(aOldFrame); mFrames.DestroyFrame(aOldFrame);

View File

@@ -105,10 +105,10 @@ struct nsMargin;
typedef class nsIFrame nsIBox; typedef class nsIFrame nsIBox;
// IID for the nsIFrame interface // IID for the nsIFrame interface
// bc99463c-5ff7-4ff3-b2c8-b4172646f793 // 626a1563-1bae-4a6e-8d2c-2dc2c13048dd
#define NS_IFRAME_IID \ #define NS_IFRAME_IID \
{ 0xbc99463c, 0x5ff7, 0x4ff3, \ { 0x626a1563, 0x1bae, 0x4a6e, \
{ 0xb2, 0xc8, 0xb4, 0x17, 0x26, 0x46, 0xf7, 0x93 } } { 0x8d, 0x2c, 0x2d, 0xc2, 0xc1, 0x30, 0x48, 0xdd } }
/** /**
* Indication of how the frame can be split. This is used when doing runaround * Indication of how the frame can be split. This is used when doing runaround
@@ -1652,6 +1652,11 @@ public:
*/ */
virtual nsIView* GetMouseCapturer() const { return nsnull; } virtual nsIView* GetMouseCapturer() const { return nsnull; }
/**
* @param aFlags see InvalidateInternal below
*/
void InvalidateWithFlags(const nsRect& aDamageRect, PRUint32 aFlags);
/** /**
* Invalidate part of the frame by asking the view manager to repaint. * 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 * aDamageRect is allowed to extend outside the frame's bounds. We'll do the right
@@ -1661,11 +1666,9 @@ public:
* need to be repainted. * need to be repainted.
* *
* @param aDamageRect is in the frame's local coordinate space * @param aDamageRect is in the frame's local coordinate space
* @param aImmediate repaint now if true, repaint later if false.
* In case it's true, pending notifications will be flushed which
* could cause frames to be deleted (including |this|).
*/ */
void Invalidate(const nsRect& aDamageRect, PRBool aImmediate = PR_FALSE); void Invalidate(const nsRect& aDamageRect)
{ return InvalidateWithFlags(aDamageRect, 0); }
/** /**
* Helper function that can be overridden by frame classes. The rectangle * Helper function that can be overridden by frame classes. The rectangle
@@ -1681,13 +1684,20 @@ public:
* *
* @param aForChild if the invalidation is coming from a child frame, this * @param aForChild if the invalidation is coming from a child frame, this
* is the frame; otherwise, this is null. * is the frame; otherwise, this is null.
* @param aImmediate repaint now if true, repaint later if false. * @param aFlags INVALIDATE_IMMEDIATE: repaint now if true, repaint later if false.
* In case it's true, pending notifications will be flushed which * In case it's true, pending notifications will be flushed which
* could cause frames to be deleted (including |this|). * could cause frames to be deleted (including |this|).
* @param aFlags INVALIDATE_CROSS_DOC: true if the invalidation
* originated in a subdocument
*/ */
enum {
INVALIDATE_IMMEDIATE = 0x1,
INVALIDATE_CROSS_DOC = 0x2,
INVALIDATE_NOTIFY_ONLY = 0x4
};
virtual void InvalidateInternal(const nsRect& aDamageRect, virtual void InvalidateInternal(const nsRect& aDamageRect,
nscoord aOffsetX, nscoord aOffsetY, nscoord aOffsetX, nscoord aOffsetY,
nsIFrame* aForChild, PRBool aImmediate); nsIFrame* aForChild, PRUint32 aFlags);
/** /**
* Helper function that funnels an InvalidateInternal request up to the * Helper function that funnels an InvalidateInternal request up to the
@@ -1701,7 +1711,7 @@ public:
* @return None, though this funnels the request up to the parent frame. * @return None, though this funnels the request up to the parent frame.
*/ */
void InvalidateInternalAfterResize(const nsRect& aDamageRect, nscoord aX, void InvalidateInternalAfterResize(const nsRect& aDamageRect, nscoord aX,
nscoord aY, PRBool aImmediate); nscoord aY, PRUint32 aFlags);
/** /**
* Take two rectangles in the coordinate system of this frame which * Take two rectangles in the coordinate system of this frame which
@@ -2221,9 +2231,7 @@ protected:
* For frames that have top-level windows (top-level viewports, * For frames that have top-level windows (top-level viewports,
* comboboxes, menupoups) this function will invalidate the window. * comboboxes, menupoups) this function will invalidate the window.
*/ */
void InvalidateRoot(const nsRect& aDamageRect, void InvalidateRoot(const nsRect& aDamageRect, PRUint32 aFlags);
nscoord aOffsetX, nscoord aOffsetY,
PRBool aImmediate);
/** /**
* Gets the overflow area for any properties that are common to all types of frames * Gets the overflow area for any properties that are common to all types of frames

View File

@@ -552,7 +552,7 @@ nsImageFrame::OnDataAvailable(imgIRequest *aRequest,
// handle iconLoads first... // handle iconLoads first...
if (HandleIconLoads(aRequest, PR_FALSE)) { if (HandleIconLoads(aRequest, PR_FALSE)) {
// Image changed, invalidate // Image changed, invalidate
Invalidate(r, PR_FALSE); Invalidate(r);
return NS_OK; return NS_OK;
} }
@@ -580,7 +580,7 @@ nsImageFrame::OnDataAvailable(imgIRequest *aRequest,
r.x, r.y, r.width, r.height); r.x, r.y, r.width, r.height);
#endif #endif
Invalidate(r, PR_FALSE); Invalidate(r);
return NS_OK; return NS_OK;
} }
@@ -633,7 +633,7 @@ nsImageFrame::OnStopDecode(imgIRequest *aRequest,
nsSize s = GetSize(); nsSize s = GetSize();
nsRect r(0, 0, s.width, s.height); nsRect r(0, 0, s.width, s.height);
// Update border+content to account for image change // Update border+content to account for image change
Invalidate(r, PR_FALSE); Invalidate(r);
} }
} }
} }
@@ -658,7 +658,7 @@ nsImageFrame::FrameChanged(imgIContainer *aContainer,
nsRect r = SourceRectToDest(*aDirtyRect); nsRect r = SourceRectToDest(*aDirtyRect);
// Update border+content to account for image change // Update border+content to account for image change
Invalidate(r, PR_FALSE); Invalidate(r);
return NS_OK; return NS_OK;
} }
@@ -849,7 +849,7 @@ nsImageFrame::Reflow(nsPresContext* aPresContext,
// we have no way to detect when mRect changes (since SetRect is non-virtual, // we have no way to detect when mRect changes (since SetRect is non-virtual,
// so this is the best we can do). // so this is the best we can do).
if (mRect.width != aMetrics.width || mRect.height != aMetrics.height) { if (mRect.width != aMetrics.width || mRect.height != aMetrics.height) {
Invalidate(nsRect(0, 0, mRect.width, mRect.height), PR_FALSE); Invalidate(nsRect(0, 0, mRect.width, mRect.height));
} }
NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS, NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,

View File

@@ -1024,7 +1024,7 @@ nsImageMap::ChangeFocus(nsIDOMEvent* aEvent, PRBool aFocus)
if (imgFrame) { if (imgFrame) {
nsRect dmgRect; nsRect dmgRect;
area->GetRect(imgFrame, dmgRect); area->GetRect(imgFrame, dmgRect);
imgFrame->Invalidate(dmgRect, PR_FALSE); imgFrame->Invalidate(dmgRect);
} }
} }
} }

View File

@@ -2756,7 +2756,7 @@ NS_IMETHODIMP nsBlinkTimer::Notify(nsITimer *timer)
// Determine damaged area and tell view manager to redraw it // Determine damaged area and tell view manager to redraw it
// blink doesn't blink outline ... I hope // blink doesn't blink outline ... I hope
nsRect bounds(nsPoint(0, 0), frameData->mFrame->GetSize()); nsRect bounds(nsPoint(0, 0), frameData->mFrame->GetSize());
frameData->mFrame->Invalidate(bounds, PR_FALSE); frameData->mFrame->Invalidate(bounds);
} }
return NS_OK; return NS_OK;
} }
@@ -4700,7 +4700,7 @@ nsTextFrame::SetSelected(nsPresContext* aPresContext,
NS_FRAME_IS_DIRTY); NS_FRAME_IS_DIRTY);
} }
// Selection might change anything. Invalidate the overflow area. // Selection might change anything. Invalidate the overflow area.
Invalidate(GetOverflowRect(), PR_FALSE); InvalidateOverflowRect();
} }
if (aSpread == eSpreadDown) if (aSpread == eSpreadDown)
{ {

View File

@@ -182,7 +182,7 @@ nsVideoFrame::Reflow(nsPresContext* aPresContext,
FinishAndStoreOverflow(&aMetrics); FinishAndStoreOverflow(&aMetrics);
if (mRect.width != aMetrics.width || mRect.height != aMetrics.height) { if (mRect.width != aMetrics.width || mRect.height != aMetrics.height) {
Invalidate(nsRect(0, 0, mRect.width, mRect.height), PR_FALSE); Invalidate(nsRect(0, 0, mRect.width, mRect.height));
} }
NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS, NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,

View File

@@ -321,7 +321,7 @@ ViewportFrame::Reflow(nsPresContext* aPresContext,
// If we were dirty then do a repaint // If we were dirty then do a repaint
if (GetStateBits() & NS_FRAME_IS_DIRTY) { if (GetStateBits() & NS_FRAME_IS_DIRTY) {
nsRect damageRect(0, 0, aDesiredSize.width, aDesiredSize.height); nsRect damageRect(0, 0, aDesiredSize.width, aDesiredSize.height);
Invalidate(damageRect, PR_FALSE); Invalidate(damageRect);
} }
// XXX Should we do something to clip our children to this? // XXX Should we do something to clip our children to this?
@@ -348,15 +348,19 @@ ViewportFrame::IsContainingBlock() const
void void
ViewportFrame::InvalidateInternal(const nsRect& aDamageRect, ViewportFrame::InvalidateInternal(const nsRect& aDamageRect,
nscoord aX, nscoord aY, nsIFrame* aForChild, nscoord aX, nscoord aY, nsIFrame* aForChild,
PRBool aImmediate) PRUint32 aFlags)
{ {
nsRect r = aDamageRect + nsPoint(aX, aY);
PresContext()->NotifyInvalidation(r, (aFlags & INVALIDATE_CROSS_DOC) != 0);
nsIFrame* parent = nsLayoutUtils::GetCrossDocParentFrame(this); nsIFrame* parent = nsLayoutUtils::GetCrossDocParentFrame(this);
if (parent) { if (parent) {
nsPoint pt = GetOffsetTo(parent); nsPoint pt = GetOffsetTo(parent);
parent->InvalidateInternal(aDamageRect, aX + pt.x, aY + pt.y, this, aImmediate); parent->InvalidateInternal(r, pt.x, pt.y, this,
aFlags | INVALIDATE_CROSS_DOC);
return; return;
} }
InvalidateRoot(aDamageRect, aX, aY, aImmediate); InvalidateRoot(r, aFlags);
} }
#ifdef DEBUG #ifdef DEBUG

View File

@@ -110,7 +110,7 @@ public:
virtual void InvalidateInternal(const nsRect& aDamageRect, virtual void InvalidateInternal(const nsRect& aDamageRect,
nscoord aX, nscoord aY, nsIFrame* aForChild, nscoord aX, nscoord aY, nsIFrame* aForChild,
PRBool aImmediate); PRUint32 aFlags);
#ifdef DEBUG #ifdef DEBUG
NS_IMETHOD GetFrameName(nsAString& aResult) const; NS_IMETHOD GetFrameName(nsAString& aResult) const;

View File

@@ -172,12 +172,14 @@ void
nsSVGForeignObjectFrame::InvalidateInternal(const nsRect& aDamageRect, nsSVGForeignObjectFrame::InvalidateInternal(const nsRect& aDamageRect,
nscoord aX, nscoord aY, nscoord aX, nscoord aY,
nsIFrame* aForChild, nsIFrame* aForChild,
PRBool aImmediate) PRUint32 aFlags)
{ {
if (mParent->GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD) if (mParent->GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD)
return; return;
mDirtyRegion.Or(mDirtyRegion, aDamageRect + nsPoint(aX, aY)); nsRegion* region = (aFlags & INVALIDATE_CROSS_DOC)
? &mCrossDocDirtyRegion : &mSameDocDirtyRegion;
region->Or(*region, aDamageRect + nsPoint(aX, aY));
FlushDirtyRegion(); FlushDirtyRegion();
} }
@@ -595,7 +597,8 @@ void nsSVGForeignObjectFrame::UpdateGraphic()
nsSVGUtils::UpdateGraphic(this); nsSVGUtils::UpdateGraphic(this);
// Clear any layout dirty region since we invalidated our whole area. // Clear any layout dirty region since we invalidated our whole area.
mDirtyRegion.SetEmpty(); mSameDocDirtyRegion.SetEmpty();
mCrossDocDirtyRegion.SetEmpty();
} }
void void
@@ -688,10 +691,33 @@ nsSVGForeignObjectFrame::DoReflow()
FlushDirtyRegion(); FlushDirtyRegion();
} }
void
nsSVGForeignObjectFrame::InvalidateDirtyRect(nsSVGOuterSVGFrame* aOuter,
const nsRect& aRect, PRUint32 aFlags)
{
if (aRect.IsEmpty())
return;
nsPresContext* presContext = PresContext();
nsCOMPtr<nsIDOMSVGMatrix> tm = GetTMIncludingOffset();
nsIntRect r = aRect;
r.ScaleRoundOut(1.0f / presContext->AppUnitsPerDevPixel());
float x = r.x, y = r.y, w = r.width, h = r.height;
nsRect rect = GetTransformedRegion(x, y, w, h, tm, presContext);
// XXX invalidate the entire covered region
// See bug 418063
rect.UnionRect(rect, mRect);
rect = nsSVGUtils::FindFilterInvalidation(this, rect);
aOuter->InvalidateWithFlags(rect, aFlags);
}
void void
nsSVGForeignObjectFrame::FlushDirtyRegion() nsSVGForeignObjectFrame::FlushDirtyRegion()
{ {
if (mDirtyRegion.IsEmpty() || mInReflow) if ((mSameDocDirtyRegion.IsEmpty() && mCrossDocDirtyRegion.IsEmpty()) ||
mInReflow)
return; return;
nsSVGOuterSVGFrame *outerSVGFrame = nsSVGUtils::GetOuterSVGFrame(this); nsSVGOuterSVGFrame *outerSVGFrame = nsSVGUtils::GetOuterSVGFrame(this);
@@ -703,18 +729,9 @@ nsSVGForeignObjectFrame::FlushDirtyRegion()
if (outerSVGFrame->IsRedrawSuspended()) if (outerSVGFrame->IsRedrawSuspended())
return; return;
nsCOMPtr<nsIDOMSVGMatrix> tm = GetTMIncludingOffset(); InvalidateDirtyRect(outerSVGFrame, mSameDocDirtyRegion.GetBounds(), 0);
nsIntRect r = mDirtyRegion.GetBounds(); InvalidateDirtyRect(outerSVGFrame, mCrossDocDirtyRegion.GetBounds(), INVALIDATE_CROSS_DOC);
r.ScaleRoundOut(1.0f / PresContext()->AppUnitsPerDevPixel());
float x = r.x, y = r.y, w = r.width, h = r.height;
nsRect rect = GetTransformedRegion(x, y, w, h, tm, PresContext());
// XXX invalidate the entire covered region mSameDocDirtyRegion.SetEmpty();
// See bug 418063 mCrossDocDirtyRegion.SetEmpty();
rect.UnionRect(rect, mRect);
rect = nsSVGUtils::FindFilterInvalidation(this, rect);
outerSVGFrame->Invalidate(rect);
mDirtyRegion.SetEmpty();
} }

View File

@@ -45,6 +45,8 @@
#include "nsRegion.h" #include "nsRegion.h"
#include "nsIPresShell.h" #include "nsIPresShell.h"
class nsSVGOuterSVGFrame;
typedef nsContainerFrame nsSVGForeignObjectFrameBase; typedef nsContainerFrame nsSVGForeignObjectFrameBase;
class nsSVGForeignObjectFrame : public nsSVGForeignObjectFrameBase, class nsSVGForeignObjectFrame : public nsSVGForeignObjectFrameBase,
@@ -108,7 +110,7 @@ public:
virtual void InvalidateInternal(const nsRect& aDamageRect, virtual void InvalidateInternal(const nsRect& aDamageRect,
nscoord aX, nscoord aY, nsIFrame* aForChild, nscoord aX, nscoord aY, nsIFrame* aForChild,
PRBool aImmediate); PRUint32 aFlags);
#ifdef DEBUG #ifdef DEBUG
NS_IMETHOD GetFrameName(nsAString& aResult) const NS_IMETHOD GetFrameName(nsAString& aResult) const
@@ -153,6 +155,8 @@ protected:
void UpdateGraphic(); void UpdateGraphic();
already_AddRefed<nsIDOMSVGMatrix> GetTMIncludingOffset(); already_AddRefed<nsIDOMSVGMatrix> GetTMIncludingOffset();
nsresult TransformPointFromOuterPx(const nsPoint &aIn, nsPoint* aOut); nsresult TransformPointFromOuterPx(const nsPoint &aIn, nsPoint* aOut);
void InvalidateDirtyRect(nsSVGOuterSVGFrame* aOuter,
const nsRect& aRect, PRUint32 aFlags);
void FlushDirtyRegion(); void FlushDirtyRegion();
// If width or height is less than or equal to zero we must disable rendering // If width or height is less than or equal to zero we must disable rendering
@@ -160,7 +164,10 @@ protected:
nsCOMPtr<nsIDOMSVGMatrix> mCanvasTM; nsCOMPtr<nsIDOMSVGMatrix> mCanvasTM;
nsCOMPtr<nsIDOMSVGMatrix> mOverrideCTM; nsCOMPtr<nsIDOMSVGMatrix> mOverrideCTM;
nsRegion mDirtyRegion; // Damage area due to in-this-doc invalidation
nsRegion mSameDocDirtyRegion;
// Damage area due to cross-doc invalidation
nsRegion mCrossDocDirtyRegion;
PRPackedBool mPropagateTransform; PRPackedBool mPropagateTransform;
PRPackedBool mInReflow; PRPackedBool mInReflow;

View File

@@ -592,13 +592,22 @@ nsSVGOuterSVGFrame::Paint(nsIRenderingContext& aRenderingContext,
// odd document is probably no worse than printing horribly for all // odd document is probably no worse than printing horribly for all
// documents. Better to fix things so we don't need fallback. // documents. Better to fix things so we don't need fallback.
nsIFrame* frame = this; nsIFrame* frame = this;
nsPresContext* presContext = PresContext();
PRUint32 flags = 0;
while (PR_TRUE) { while (PR_TRUE) {
nsIFrame* next = nsLayoutUtils::GetCrossDocParentFrame(frame); nsIFrame* next = nsLayoutUtils::GetCrossDocParentFrame(frame);
if (!next) if (!next)
break; break;
if (frame->GetParent() != next) {
// We're crossing a document boundary. Logically, the invalidation is
// being triggered by a subdocument of the root document. This will
// prevent an untrusted root document being told about invalidation
// that happened because a child was using SVG...
flags |= INVALIDATE_CROSS_DOC;
}
frame = next; frame = next;
} }
frame->Invalidate(nsRect(nsPoint(0, 0), frame->GetSize())); frame->InvalidateWithFlags(nsRect(nsPoint(0, 0), frame->GetSize()), flags);
} }
#endif #endif

View File

@@ -517,7 +517,7 @@ nsTableCellFrame::SetSelected(nsPresContext* aPresContext,
aPresContext->PresShell()->FrameSelection(); aPresContext->PresShell()->FrameSelection();
if (frameSelection->GetTableCellSelection()) { if (frameSelection->GetTableCellSelection()) {
// Selection can affect content, border and outline // Selection can affect content, border and outline
Invalidate(GetOverflowRect(), PR_FALSE); InvalidateOverflowRect();
} }
return NS_OK; return NS_OK;
} }
@@ -933,7 +933,7 @@ NS_METHOD nsTableCellFrame::Reflow(nsPresContext* aPresContext,
// XXXbz is this invalidate actually needed, really? // XXXbz is this invalidate actually needed, really?
if (GetStateBits() & NS_FRAME_IS_DIRTY) { if (GetStateBits() & NS_FRAME_IS_DIRTY) {
Invalidate(GetOverflowRect(), PR_FALSE); InvalidateOverflowRect();
} }
#ifdef NS_DEBUG #ifdef NS_DEBUG

View File

@@ -656,7 +656,7 @@ nsIFrame::Redraw(nsBoxLayoutState& aState,
else else
damageRect = GetOverflowRect(); damageRect = GetOverflowRect();
Invalidate(damageRect, aImmediate); InvalidateWithFlags(damageRect, aImmediate ? INVALIDATE_IMMEDIATE : 0);
return NS_OK; return NS_OK;
} }

View File

@@ -684,9 +684,9 @@ nsMenuPopupFrame::HidePopup(PRBool aDeselectMenu, nsPopupState aNewState)
void void
nsMenuPopupFrame::InvalidateInternal(const nsRect& aDamageRect, nsMenuPopupFrame::InvalidateInternal(const nsRect& aDamageRect,
nscoord aX, nscoord aY, nsIFrame* aForChild, nscoord aX, nscoord aY, nsIFrame* aForChild,
PRBool aImmediate) PRUint32 aFlags)
{ {
InvalidateRoot(aDamageRect, aX, aY, aImmediate); InvalidateRoot(aDamageRect + nsPoint(aX, aY), aFlags);
} }
void void

View File

@@ -174,7 +174,7 @@ public:
virtual void InvalidateInternal(const nsRect& aDamageRect, virtual void InvalidateInternal(const nsRect& aDamageRect,
nscoord aX, nscoord aY, nsIFrame* aForChild, nscoord aX, nscoord aY, nsIFrame* aForChild,
PRBool aImmediate); PRUint32 aFlags);
// returns true if the popup is a panel with the noautohide attribute set to // returns true if the popup is a panel with the noautohide attribute set to
// true. These panels do not roll up automatically. // true. These panels do not roll up automatically.

View File

@@ -684,7 +684,7 @@ nsSliderFrame::CurrentPositionChanged(nsPresContext* aPresContext,
thumbFrame->SetRect(newThumbRect); thumbFrame->SetRect(newThumbRect);
// Redraw the scrollbar // Redraw the scrollbar
Invalidate(clientRect, aImmediateRedraw); InvalidateWithFlags(clientRect, aImmediateRedraw ? INVALIDATE_IMMEDIATE : 0);
if (mScrollbarListener) if (mScrollbarListener)
mScrollbarListener->PositionChanged(aPresContext, mCurPos, curpospx); mScrollbarListener->PositionChanged(aPresContext, mCurPos, curpospx);

View File

@@ -692,7 +692,7 @@ nsTreeBodyFrame::Invalidate()
if (mUpdateBatchNest) if (mUpdateBatchNest)
return NS_OK; return NS_OK;
nsIFrame::Invalidate(GetOverflowRect(), PR_FALSE); InvalidateOverflowRect();
return NS_OK; return NS_OK;
} }
@@ -719,7 +719,7 @@ nsTreeBodyFrame::InvalidateColumn(nsITreeColumn* aCol)
// When false then column is out of view // When false then column is out of view
if (OffsetForHorzScroll(columnRect, PR_TRUE)) if (OffsetForHorzScroll(columnRect, PR_TRUE))
nsIFrame::Invalidate(columnRect, PR_FALSE); nsIFrame::Invalidate(columnRect);
return NS_OK; return NS_OK;
} }
@@ -741,7 +741,7 @@ nsTreeBodyFrame::InvalidateRow(PRInt32 aIndex)
return NS_OK; return NS_OK;
nsRect rowRect(mInnerBox.x, mInnerBox.y+mRowHeight*aIndex, mInnerBox.width, mRowHeight); nsRect rowRect(mInnerBox.x, mInnerBox.y+mRowHeight*aIndex, mInnerBox.width, mRowHeight);
nsLeafBoxFrame::Invalidate(rowRect, PR_FALSE); nsLeafBoxFrame::Invalidate(rowRect);
return NS_OK; return NS_OK;
} }
@@ -772,7 +772,7 @@ nsTreeBodyFrame::InvalidateCell(PRInt32 aIndex, nsITreeColumn* aCol)
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
if (OffsetForHorzScroll(cellRect, PR_TRUE)) if (OffsetForHorzScroll(cellRect, PR_TRUE))
nsIFrame::Invalidate(cellRect, PR_FALSE); nsIFrame::Invalidate(cellRect);
return NS_OK; return NS_OK;
} }
@@ -806,7 +806,7 @@ nsTreeBodyFrame::InvalidateRange(PRInt32 aStart, PRInt32 aEnd)
#endif #endif
nsRect rangeRect(mInnerBox.x, mInnerBox.y+mRowHeight*(aStart-mTopRowIndex), mInnerBox.width, mRowHeight*(aEnd-aStart+1)); nsRect rangeRect(mInnerBox.x, mInnerBox.y+mRowHeight*(aStart-mTopRowIndex), mInnerBox.width, mRowHeight*(aEnd-aStart+1));
nsIFrame::Invalidate(rangeRect, PR_FALSE); nsIFrame::Invalidate(rangeRect);
return NS_OK; return NS_OK;
} }
@@ -850,7 +850,7 @@ nsTreeBodyFrame::InvalidateColumnRange(PRInt32 aStart, PRInt32 aEnd, nsITreeColu
&rangeRect); &rangeRect);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
nsIFrame::Invalidate(rangeRect, PR_FALSE); nsIFrame::Invalidate(rangeRect);
return NS_OK; return NS_OK;
} }

View File

@@ -42,6 +42,7 @@
#include "nsPoint.h" #include "nsPoint.h"
#include "nsRect.h" #include "nsRect.h"
#include "nsRegion.h"
#include "nsEvent.h" #include "nsEvent.h"
#include "nsStringGlue.h" #include "nsStringGlue.h"
#include "nsCOMPtr.h" #include "nsCOMPtr.h"
@@ -101,6 +102,7 @@ class nsHashKey;
#define NS_MEDIA_EVENT 34 #define NS_MEDIA_EVENT 34
#endif // MOZ_MEDIA #endif // MOZ_MEDIA
#define NS_DRAG_EVENT 35 #define NS_DRAG_EVENT 35
#define NS_NOTIFYPAINT_EVENT 36
// These flags are sort of a mess. They're sort of shared between event // These flags are sort of a mess. They're sort of shared between event
// listener flags and event flags, but only some of them. You've been // listener flags and event flags, but only some of them. You've been
@@ -376,6 +378,10 @@ class nsHashKey;
#define NS_MEDIA_ERROR (NS_MEDIA_EVENT_START+21) #define NS_MEDIA_ERROR (NS_MEDIA_EVENT_START+21)
#endif // MOZ_MEDIA #endif // MOZ_MEDIA
// paint notification events
#define NS_NOTIFYPAINT_START 3400
#define NS_AFTERPAINT (NS_NOTIFYPAINT_START)
/** /**
* Return status for event processors, nsEventStatus, is defined in * Return status for event processors, nsEventStatus, is defined in
* nsEvent.h. * nsEvent.h.
@@ -1068,6 +1074,23 @@ public:
PRInt32 detail; PRInt32 detail;
}; };
/**
* NotifyPaint event
*/
class nsNotifyPaintEvent : public nsEvent
{
public:
nsNotifyPaintEvent(PRBool isTrusted, PRUint32 msg,
const nsRegion& aSameDocRegion, const nsRegion& aCrossDocRegion)
: nsEvent(isTrusted, msg, NS_NOTIFYPAINT_EVENT),
sameDocRegion(aSameDocRegion), crossDocRegion(aCrossDocRegion)
{
}
nsRegion sameDocRegion;
nsRegion crossDocRegion;
};
/** /**
* PageTransition event * PageTransition event
*/ */