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::ondrop, { NS_DRAGDROP_DROP, EventNameType_HTMLXUL }},
{ &nsGkAtoms::onoverflow, { NS_SCROLLPORT_OVERFLOW, EventNameType_XUL }},
{ &nsGkAtoms::onunderflow, { NS_SCROLLPORT_UNDERFLOW, EventNameType_XUL }}
{ &nsGkAtoms::onunderflow, { NS_SCROLLPORT_UNDERFLOW, EventNameType_XUL }},
#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::onSVGAbort, { NS_SVG_ABORT, EventNameType_None }},
{ &nsGkAtoms::onSVGError, { NS_SVG_ERROR, EventNameType_None }},
{ &nsGkAtoms::onSVGResize, { NS_SVG_RESIZE, EventNameType_None }},
{ &nsGkAtoms::onSVGScroll, { NS_SVG_SCROLL, 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
#ifdef MOZ_MEDIA
,{ &nsGkAtoms::onloadstart, { NS_LOADSTART, EventNameType_HTML }},
{ &nsGkAtoms::onloadstart, { NS_LOADSTART, EventNameType_HTML }},
{ &nsGkAtoms::onprogress, { NS_PROGRESS, EventNameType_HTML }},
{ &nsGkAtoms::onloadedmetadata, { NS_LOADEDMETADATA, EventNameType_HTML }},
{ &nsGkAtoms::onloadedfirstframe, { NS_LOADEDFIRSTFRAME, EventNameType_HTML }},
@@ -477,6 +477,7 @@ nsContentUtils::InitializeEventTable() {
{ &nsGkAtoms::ondurationchange, { NS_DURATIONCHANGE, EventNameType_HTML }},
{ &nsGkAtoms::onvolumechange, { NS_VOLUMECHANGE, EventNameType_HTML }},
#endif //MOZ_MEDIA
{ &nsGkAtoms::onMozAfterPaint, { NS_AFTERPAINT, EventNameType_None }}
};
sEventTable = new nsDataHashtable<nsISupportsHashKey, EventNameMapping>;

View File

@@ -1289,28 +1289,6 @@ GetContainingBlockForClientRect(nsIFrame* 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
nsNSElementTearoff::GetBoundingClientRect(nsIDOMClientRect** aResult)
{
@@ -1330,7 +1308,7 @@ nsNSElementTearoff::GetBoundingClientRect(nsIDOMClientRect** aResult)
nsPresContext* presContext = frame->PresContext();
nsRect r = nsLayoutUtils::GetAllInFlowRectsUnion(frame,
GetContainingBlockForClientRect(frame));
SetClientRect(r, presContext, rect);
rect->SetLayoutRect(r, presContext);
return NS_OK;
}
@@ -1350,7 +1328,7 @@ struct RectListBuilder : public nsLayoutUtils::RectCallback {
return;
}
SetClientRect(aRect, mPresContext, rect);
rect->SetLayoutRect(aRect, mPresContext);
mRectList->Append(rect);
}
};

View File

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

View File

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

View File

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

View File

@@ -129,19 +129,17 @@ public:
eDOMEvents_online,
eDOMEvents_copy,
eDOMEvents_cut,
eDOMEvents_paste
eDOMEvents_paste,
#ifdef MOZ_SVG
,
eDOMEvents_SVGLoad,
eDOMEvents_SVGUnload,
eDOMEvents_SVGAbort,
eDOMEvents_SVGError,
eDOMEvents_SVGResize,
eDOMEvents_SVGScroll,
eDOMEvents_SVGZoom
eDOMEvents_SVGZoom,
#endif // MOZ_SVG
#ifdef MOZ_MEDIA
,
eDOMEvents_loadstart,
eDOMEvents_progress,
eDOMEvents_loadedmetadata,
@@ -161,8 +159,9 @@ public:
eDOMEvents_canplaythrough,
eDOMEvents_ratechange,
eDOMEvents_durationchange,
eDOMEvents_volumechange
eDOMEvents_volumechange,
#endif
eDOMEvents_afterpaint
};
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:
return NS_NewDOMCommandEvent(aDOMEvent, aPresContext,
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.
@@ -667,6 +671,8 @@ nsEventDispatcher::CreateEvent(nsPresContext* aPresContext,
return NS_NewDOMMessageEvent(aDOMEvent, aPresContext, nsnull);
if (aEventType.LowerCaseEqualsLiteral("progressevent"))
return NS_NewDOMProgressEvent(aDOMEvent, aPresContext, nsnull);
if (aEventType.LowerCaseEqualsLiteral("notifypaintevent"))
return NS_NewDOMNotifyPaintEvent(aDOMEvent, aPresContext, nsnull);
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
}

View File

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

View File

@@ -40,6 +40,8 @@
#include "nsContentUtils.h"
#include "nsDOMClassInfoID.h"
#include "nsPresContext.h"
NS_INTERFACE_TABLE_HEAD(nsClientRect)
NS_INTERFACE_TABLE1(nsClientRect, nsIDOMClientRect)
NS_INTERFACE_TABLE_TO_MAP_SEGUE
@@ -124,3 +126,23 @@ nsClientRectList::Item(PRUint32 aIndex, nsIDOMClientRect** aReturn)
NS_IF_ADDREF(*aReturn = mArray.ObjectAt(aIndex));
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 "nsIDOMClientRectList.h"
#include "nsCOMArray.h"
#include "nsRect.h"
class nsPresContext;
class nsClientRect : public nsIDOMClientRect
{
@@ -56,6 +59,8 @@ public:
NS_DECL_NSIDOMCLIENTRECT
void SetLayoutRect(const nsRect& aLayoutRect, nsPresContext* aPresContext);
protected:
float mX, mY, mWidth, mHeight;
};

View File

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

View File

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

View File

@@ -76,6 +76,7 @@ XPIDLSRCS = \
nsIDOMPageTransitionEvent.idl \
nsIDOMCommandEvent.idl \
nsIDOMMessageEvent.idl \
nsIDOMNotifyPaintEvent.idl \
$(NULL)
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_NotifyPaintEvent_id,
// This one better be the last one in this list
eDOMClassInfoIDCount
};

View File

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

View File

@@ -178,7 +178,7 @@ nsDOMWindowUtils::Redraw(PRUint32 aCount, PRUint32 *aDurationOut)
PRIntervalTime iStart = PR_IntervalNow();
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)
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");
nsRect rect;
rect.UnionRect(aRect, aHook);
aFrame->Invalidate(rect, PR_FALSE);
aFrame->Invalidate(rect);
}
//-----------------------------------------------------------------------------

View File

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

View File

@@ -82,6 +82,7 @@
#include "nsCSSRuleProcessor.h"
#include "nsStyleChangeList.h"
#include "nsRuleNode.h"
#include "nsEventDispatcher.h"
#ifdef IBMBIDI
#include "nsBidiPresUtils.h"
@@ -1569,3 +1570,54 @@ nsPresContext::HasAuthorSpecifiedRules(nsIFrame *aFrame, PRUint32 ruleTypeMask)
return nsRuleNode::
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"
// This also pulls in gfxTypes.h, which we cannot include directly.
#include "gfxRect.h"
#include "nsRegion.h"
class nsImageLoader;
#ifdef IBMBIDI
class nsBidiPresUtils;
@@ -778,6 +779,9 @@ public:
PRBool SupressingResizeReflow() const { return mSupressResizeReflow; }
void NotifyInvalidation(const nsRect& aRect, PRBool aIsCrossDoc);
void FireDOMPaintEvent();
protected:
friend class nsRunnableMethod<nsPresContext>;
NS_HIDDEN_(void) ThemeChangedInternal();
@@ -838,6 +842,9 @@ protected:
nsPropertyTable mPropertyTable;
nsRegion mSameDocDirtyRegion;
nsRegion mCrossDocDirtyRegion;
nsLanguageSpecificTransformType mLanguageSpecificTransformType;
PRInt32 mFontScaler;
nscoord mMinimumFontSize;

View File

@@ -4312,7 +4312,7 @@ PresShell::UnsuppressAndInvalidate()
if (rootFrame) {
// let's assume that outline on a root frame is not supported
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()

View File

@@ -92,6 +92,7 @@ _TEST_FILES = \
test_bug423523.html \
test_bug445810.html \
test_bug449781.html \
test_bug450930.xhtml \
$(NULL)
# test_bug396024.html is currently disabled because it interacts badly with
# 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
// rect to be drawn. This is much faster than ReResolvingStyle
// 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
// This is only needed for embedding, the focus may go to

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1467,7 +1467,7 @@ NS_IMETHODIMP nsBulletFrame::OnDataAvailable(imgIRequest *aRequest,
// The image has changed.
// 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
Invalidate(nsRect(0, 0, mRect.width, mRect.height), PR_FALSE);
Invalidate(nsRect(0, 0, mRect.width, mRect.height));
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
// always correct.
Invalidate(nsRect(0, 0, mRect.width, mRect.height), PR_FALSE);
Invalidate(nsRect(0, 0, mRect.width, mRect.height));
return NS_OK;
}

View File

@@ -3634,8 +3634,7 @@ nsIFrame::IsLeaf() const
}
void
nsIFrame::Invalidate(const nsRect& aDamageRect,
PRBool aImmediate)
nsIFrame::InvalidateWithFlags(const nsRect& aDamageRect, PRUint32 aFlags)
{
if (aDamageRect.IsEmpty()) {
return;
@@ -3651,7 +3650,7 @@ nsIFrame::Invalidate(const nsRect& aDamageRect,
return;
}
InvalidateInternal(aDamageRect, 0, 0, nsnull, aImmediate);
InvalidateInternal(aDamageRect, 0, 0, nsnull, aFlags);
}
/**
@@ -3667,7 +3666,7 @@ nsIFrame::Invalidate(const nsRect& aDamageRect,
*/
void
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
* 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);
GetParent()->
InvalidateInternal(newDamageRect, aX + mRect.x, aY + mRect.y, this,
aImmediate);
aFlags);
}
else
GetParent()->
InvalidateInternal(aDamageRect, aX + mRect.x, aY + mRect.y, this, aImmediate);
InvalidateInternal(aDamageRect, aX + mRect.x, aY + mRect.y, this, aFlags);
}
void
nsIFrame::InvalidateInternal(const nsRect& aDamageRect, nscoord aX, nscoord aY,
nsIFrame* aForChild, PRBool aImmediate)
nsIFrame* aForChild, PRUint32 aFlags)
{
#ifdef MOZ_SVG
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
* local coordinate space and do any remaining processing.
*/
InvalidateInternalAfterResize(r, 0, 0, aImmediate);
InvalidateInternalAfterResize(r, 0, 0, aFlags);
return;
}
#endif
InvalidateInternalAfterResize(aDamageRect, aX, aY, aImmediate);
InvalidateInternalAfterResize(aDamageRect, aX, aY, aFlags);
}
gfxMatrix
@@ -3800,13 +3799,16 @@ nsIFrame::InvalidateOverflowRect()
}
void
nsIFrame::InvalidateRoot(const nsRect& aDamageRect,
nscoord aX, nscoord aY, PRBool aImmediate)
nsIFrame::InvalidateRoot(const nsRect& aDamageRect, PRUint32 aFlags)
{
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();
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
@@ -4443,7 +4445,7 @@ nsFrame::SetSelected(nsPresContext* aPresContext, nsIDOMRange *aRange, PRBool aS
RemoveStateBits(NS_FRAME_SELECTED_CONTENT);
// Repaint this frame subtree's entire area
Invalidate(GetOverflowRect(), PR_FALSE);
InvalidateOverflowRect();
#ifdef IBMBIDI
PRInt32 start, end;

View File

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

View File

@@ -227,19 +227,30 @@ nsHTMLScrollFrame::GetType() const
void
nsHTMLScrollFrame::InvalidateInternal(const nsRect& aDamageRect,
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
nsRect damage = aDamageRect + nsPoint(aX, aY);
nsRect r;
if (r.IntersectRect(aDamageRect + nsPoint(aX, aY),
mInner.mScrollableView->View()->GetBounds())) {
nsHTMLContainerFrame::InvalidateInternal(r, 0, 0, aForChild, aImmediate);
if (r.IntersectRect(damage, mInner.mScrollableView->View()->GetBounds())) {
nsHTMLContainerFrame::InvalidateInternal(r, 0, 0, aForChild, aFlags);
}
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;
}
nsHTMLContainerFrame::InvalidateInternal(aDamageRect, aX, aY, aForChild, aImmediate);
nsHTMLContainerFrame::InvalidateInternal(aDamageRect, aX, aY, aForChild, aFlags);
}
/**
@@ -1097,19 +1108,19 @@ nsXULScrollFrame::GetType() const
void
nsXULScrollFrame::InvalidateInternal(const nsRect& aDamageRect,
nscoord aX, nscoord aY, nsIFrame* aForChild,
PRBool aImmediate)
PRUint32 aFlags)
{
if (aForChild == mInner.mScrolledFrame) {
// restrict aDamageRect to the scrollable view's bounds
nsRect r;
if (r.IntersectRect(aDamageRect + nsPoint(aX, aY),
mInner.mScrollableView->View()->GetBounds())) {
nsBoxFrame::InvalidateInternal(r, 0, 0, aForChild, aImmediate);
nsBoxFrame::InvalidateInternal(r, 0, 0, aForChild, aFlags);
}
return;
}
nsBoxFrame::InvalidateInternal(aDamageRect, aX, aY, aForChild, aImmediate);
nsBoxFrame::InvalidateInternal(aDamageRect, aX, aY, aForChild, aFlags);
}
nscoord
@@ -1822,6 +1833,9 @@ nsGfxScrollFrameInner::ScrollPositionDidChange(nsIScrollableView* aScrollable, n
PostScrollEvent();
// Notify that the display has changed
mOuter->InvalidateWithFlags(nsRect(nsPoint(0, 0), mOuter->GetSize()),
nsIFrame::INVALIDATE_NOTIFY_ONLY);
return NS_OK;
}

View File

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

View File

@@ -160,7 +160,7 @@ nsHTMLCanvasFrame::Reflow(nsPresContext* aPresContext,
FinishAndStoreOverflow(&aMetrics);
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,

View File

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

View File

@@ -105,10 +105,10 @@ struct nsMargin;
typedef class nsIFrame nsIBox;
// IID for the nsIFrame interface
// bc99463c-5ff7-4ff3-b2c8-b4172646f793
// 626a1563-1bae-4a6e-8d2c-2dc2c13048dd
#define NS_IFRAME_IID \
{ 0xbc99463c, 0x5ff7, 0x4ff3, \
{ 0xb2, 0xc8, 0xb4, 0x17, 0x26, 0x46, 0xf7, 0x93 } }
{ 0x626a1563, 0x1bae, 0x4a6e, \
{ 0x8d, 0x2c, 0x2d, 0xc2, 0xc1, 0x30, 0x48, 0xdd } }
/**
* 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; }
/**
* @param aFlags see InvalidateInternal below
*/
void InvalidateWithFlags(const nsRect& aDamageRect, PRUint32 aFlags);
/**
* 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
@@ -1661,11 +1666,9 @@ public:
* need to be repainted.
*
* @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
@@ -1681,13 +1684,20 @@ public:
*
* @param aForChild if the invalidation is coming from a child frame, this
* 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
* 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,
nscoord aOffsetX, nscoord aOffsetY,
nsIFrame* aForChild, PRBool aImmediate);
nsIFrame* aForChild, PRUint32 aFlags);
/**
* 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.
*/
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
@@ -2221,9 +2231,7 @@ protected:
* 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);
void InvalidateRoot(const nsRect& aDamageRect, PRUint32 aFlags);
/**
* 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...
if (HandleIconLoads(aRequest, PR_FALSE)) {
// Image changed, invalidate
Invalidate(r, PR_FALSE);
Invalidate(r);
return NS_OK;
}
@@ -580,7 +580,7 @@ nsImageFrame::OnDataAvailable(imgIRequest *aRequest,
r.x, r.y, r.width, r.height);
#endif
Invalidate(r, PR_FALSE);
Invalidate(r);
return NS_OK;
}
@@ -633,7 +633,7 @@ nsImageFrame::OnStopDecode(imgIRequest *aRequest,
nsSize s = GetSize();
nsRect r(0, 0, s.width, s.height);
// 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);
// Update border+content to account for image change
Invalidate(r, PR_FALSE);
Invalidate(r);
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,
// so this is the best we can do).
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,

View File

@@ -1024,7 +1024,7 @@ nsImageMap::ChangeFocus(nsIDOMEvent* aEvent, PRBool aFocus)
if (imgFrame) {
nsRect 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
// blink doesn't blink outline ... I hope
nsRect bounds(nsPoint(0, 0), frameData->mFrame->GetSize());
frameData->mFrame->Invalidate(bounds, PR_FALSE);
frameData->mFrame->Invalidate(bounds);
}
return NS_OK;
}
@@ -4700,7 +4700,7 @@ nsTextFrame::SetSelected(nsPresContext* aPresContext,
NS_FRAME_IS_DIRTY);
}
// Selection might change anything. Invalidate the overflow area.
Invalidate(GetOverflowRect(), PR_FALSE);
InvalidateOverflowRect();
}
if (aSpread == eSpreadDown)
{

View File

@@ -182,7 +182,7 @@ nsVideoFrame::Reflow(nsPresContext* aPresContext,
FinishAndStoreOverflow(&aMetrics);
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,

View File

@@ -321,7 +321,7 @@ ViewportFrame::Reflow(nsPresContext* aPresContext,
// If we were dirty then do a repaint
if (GetStateBits() & NS_FRAME_IS_DIRTY) {
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?
@@ -348,15 +348,19 @@ ViewportFrame::IsContainingBlock() const
void
ViewportFrame::InvalidateInternal(const nsRect& aDamageRect,
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);
if (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;
}
InvalidateRoot(aDamageRect, aX, aY, aImmediate);
InvalidateRoot(r, aFlags);
}
#ifdef DEBUG

View File

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

View File

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

View File

@@ -45,6 +45,8 @@
#include "nsRegion.h"
#include "nsIPresShell.h"
class nsSVGOuterSVGFrame;
typedef nsContainerFrame nsSVGForeignObjectFrameBase;
class nsSVGForeignObjectFrame : public nsSVGForeignObjectFrameBase,
@@ -108,7 +110,7 @@ public:
virtual void InvalidateInternal(const nsRect& aDamageRect,
nscoord aX, nscoord aY, nsIFrame* aForChild,
PRBool aImmediate);
PRUint32 aFlags);
#ifdef DEBUG
NS_IMETHOD GetFrameName(nsAString& aResult) const
@@ -153,6 +155,8 @@ protected:
void UpdateGraphic();
already_AddRefed<nsIDOMSVGMatrix> GetTMIncludingOffset();
nsresult TransformPointFromOuterPx(const nsPoint &aIn, nsPoint* aOut);
void InvalidateDirtyRect(nsSVGOuterSVGFrame* aOuter,
const nsRect& aRect, PRUint32 aFlags);
void FlushDirtyRegion();
// 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> 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 mInReflow;

View File

@@ -592,13 +592,22 @@ nsSVGOuterSVGFrame::Paint(nsIRenderingContext& aRenderingContext,
// odd document is probably no worse than printing horribly for all
// documents. Better to fix things so we don't need fallback.
nsIFrame* frame = this;
nsPresContext* presContext = PresContext();
PRUint32 flags = 0;
while (PR_TRUE) {
nsIFrame* next = nsLayoutUtils::GetCrossDocParentFrame(frame);
if (!next)
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->Invalidate(nsRect(nsPoint(0, 0), frame->GetSize()));
frame->InvalidateWithFlags(nsRect(nsPoint(0, 0), frame->GetSize()), flags);
}
#endif

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -42,6 +42,7 @@
#include "nsPoint.h"
#include "nsRect.h"
#include "nsRegion.h"
#include "nsEvent.h"
#include "nsStringGlue.h"
#include "nsCOMPtr.h"
@@ -101,6 +102,7 @@ class nsHashKey;
#define NS_MEDIA_EVENT 34
#endif // MOZ_MEDIA
#define NS_DRAG_EVENT 35
#define NS_NOTIFYPAINT_EVENT 36
// 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
@@ -376,6 +378,10 @@ class nsHashKey;
#define NS_MEDIA_ERROR (NS_MEDIA_EVENT_START+21)
#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
* nsEvent.h.
@@ -1068,6 +1074,23 @@ public:
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
*/