Merge mozilla-central to tracemonkey.

This commit is contained in:
Robert Sayre 2010-07-31 14:19:27 -07:00
commit d580edd975
39 changed files with 1149 additions and 234 deletions

View File

@ -157,6 +157,7 @@ enum EventNameType {
EventNameType_XUL = 0x0002,
EventNameType_SVGGraphic = 0x0004, // svg graphic elements
EventNameType_SVGSVG = 0x0008, // the svg element
EventNameType_SMIL = 0x0016, // smil elements
EventNameType_HTMLXUL = 0x0003,
EventNameType_All = 0xFFFF

View File

@ -575,6 +575,14 @@ nsContentUtils::InitializeEventTable() {
// This is a bit hackish, but SVG's event names are weird.
{ nsGkAtoms::onzoom, NS_SVG_ZOOM, EventNameType_SVGSVG, NS_EVENT_NULL },
#endif // MOZ_SVG
#ifdef MOZ_SMIL
{ nsGkAtoms::onbegin, NS_SMIL_BEGIN, EventNameType_SMIL, NS_EVENT_NULL },
{ nsGkAtoms::onbeginEvent, NS_SMIL_BEGIN, EventNameType_None, NS_SMIL_TIME_EVENT },
{ nsGkAtoms::onend, NS_SMIL_END, EventNameType_SMIL, NS_EVENT_NULL },
{ nsGkAtoms::onendEvent, NS_SMIL_END, EventNameType_None, NS_SMIL_TIME_EVENT },
{ nsGkAtoms::onrepeat, NS_SMIL_REPEAT, EventNameType_SMIL, NS_EVENT_NULL },
{ nsGkAtoms::onrepeatEvent, NS_SMIL_REPEAT, EventNameType_None, NS_SMIL_TIME_EVENT },
#endif // MOZ_SMIL
#ifdef MOZ_MEDIA
{ nsGkAtoms::onloadstart, NS_LOADSTART, EventNameType_HTML, NS_EVENT_NULL },
{ nsGkAtoms::onprogress, NS_PROGRESS, EventNameType_HTML, NS_EVENT_NULL },

View File

@ -1309,6 +1309,12 @@ GK_ATOM(keyPoints, "keyPoints")
GK_ATOM(keySplines, "keySplines")
GK_ATOM(keyTimes, "keyTimes")
GK_ATOM(mozAnimateMotionDummyAttr, "_mozAnimateMotionDummyAttr")
GK_ATOM(onbegin, "onbegin")
GK_ATOM(onbeginEvent, "onbeginEvent")
GK_ATOM(onend, "onend")
GK_ATOM(onendEvent, "onendEvent")
GK_ATOM(onrepeat, "onrepeat")
GK_ATOM(onrepeatEvent, "onrepeatEvent")
GK_ATOM(repeatCount, "repeatCount")
GK_ATOM(repeatDur, "repeatDur")
GK_ATOM(restart, "restart")

View File

@ -22,6 +22,7 @@
*
* Contributor(s):
* Christian Biesinger <cbiesinger@web.de>
* Bobby Holley <bobbyholley@gmail.com>
*
* 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
@ -103,14 +104,14 @@ nsImageLoadingContent::nsImageLoadingContent()
: mObserverList(nsnull),
mImageBlockingStatus(nsIContentPolicy::ACCEPT),
mLoadingEnabled(PR_TRUE),
mStartingLoad(PR_FALSE),
mIsImageStateForced(PR_FALSE),
mLoading(PR_FALSE),
// mBroken starts out true, since an image without a URI is broken....
mBroken(PR_TRUE),
mUserDisabled(PR_FALSE),
mSuppressed(PR_FALSE),
mBlockingOnload(PR_FALSE)
mBlockingOnload(PR_FALSE),
mStateChangerDepth(0)
{
if (!nsContentUtils::GetImgLoader()) {
mLoadingEnabled = PR_FALSE;
@ -120,18 +121,9 @@ nsImageLoadingContent::nsImageLoadingContent()
void
nsImageLoadingContent::DestroyImageLoadingContent()
{
// If we're blocking onload for any reason, now's a good time to stop
SetBlockingOnload(PR_FALSE);
// Cancel our requests so they won't hold stale refs to us
if (mCurrentRequest) {
mCurrentRequest->CancelAndForgetObserver(NS_ERROR_FAILURE);
mCurrentRequest = nsnull;
}
if (mPendingRequest) {
mPendingRequest->CancelAndForgetObserver(NS_ERROR_FAILURE);
mPendingRequest = nsnull;
}
ClearCurrentRequest(NS_BINDING_ABORTED);
ClearPendingRequest(NS_BINDING_ABORTED);
}
nsImageLoadingContent::~nsImageLoadingContent()
@ -261,6 +253,9 @@ nsImageLoadingContent::OnStopContainer(imgIRequest* aRequest,
return NS_OK;
}
// Warning - This isn't actually fired when decode is complete. Rather, it's
// fired when load is complete. See bug 505385, and in the mean time use
// OnStopContainer.
NS_IMETHODIMP
nsImageLoadingContent::OnStopDecode(imgIRequest* aRequest,
nsresult aStatus,
@ -273,21 +268,20 @@ nsImageLoadingContent::OnStopDecode(imgIRequest* aRequest,
"Unknown request");
LOOP_OVER_OBSERVERS(OnStopDecode(aRequest, aStatus, aStatusArg));
// XXXbholley - When we fix bug 505385, everything here should go in
// OnStopRequest.
// Our state may change. Watch it.
AutoStateChanger changer(this, PR_TRUE);
// If the pending request is loaded, switch to it.
if (aRequest == mPendingRequest) {
// If we were blocking for the soon-to-be-obsolete request, stop doing so
SetBlockingOnload(PR_FALSE);
// The new image is decoded - switch to it
// XXXbholley - This is technically not true pre bug 505385, but I don't
// think it's a big enough issue to worry about handling in the mean time
mCurrentRequest->Cancel(NS_ERROR_IMAGE_SRC_CHANGED);
mPendingRequest.swap(mCurrentRequest);
PrepareCurrentRequest() = mPendingRequest;
mPendingRequest = nsnull;
}
NS_ABORT_IF_FALSE(aRequest == mCurrentRequest,
"One way or another, we should be current by now");
// XXXbholley - When we fix bug 505385, this should go in OnStopRequest.
//
// We just loaded all the data we're going to get. If we haven't done an
// initial paint, we want to make sure the image starts decoding for 2
// reasons:
@ -324,26 +318,16 @@ nsImageLoadingContent::OnStopDecode(imgIRequest* aRequest,
// If we're requesting a decode, do it
if (doRequestDecode)
aRequest->RequestDecode();
mCurrentRequest->RequestDecode();
}
// XXXldb What's the difference between when OnStopDecode and OnStopRequest
// fire? Should we do this work there instead? Should they just be the
// same?
// Fire the appropriate DOM event.
if (NS_SUCCEEDED(aStatus)) {
FireEvent(NS_LITERAL_STRING("load"));
} else {
FireEvent(NS_LITERAL_STRING("error"));
}
// Have to check for state changes here (for example, the new load could
// have resulted in a broken image). Note that we don't want to do this
// async, unlike the event, because while this is waiting to happen our
// state could change yet again, and then we'll get confused about our
// state.
UpdateImageState(PR_TRUE);
return NS_OK;
}
@ -513,39 +497,36 @@ NS_IMETHODIMP
nsImageLoadingContent::LoadImageWithChannel(nsIChannel* aChannel,
nsIStreamListener** aListener)
{
NS_PRECONDITION(aListener, "null out param");
NS_ENSURE_ARG_POINTER(aChannel);
if (!nsContentUtils::GetImgLoader()) {
return NS_ERROR_NULL_POINTER;
}
// XXX what should we do with content policies here, if anything?
// Shouldn't that be done before the start of the load?
// XXX what about shouldProcess?
nsCOMPtr<nsIDocument> doc = GetOurDocument();
if (!doc) {
// Don't bother
return NS_OK;
}
// Null out our mCurrentURI, in case we have no image requests right now.
mCurrentURI = nsnull;
CancelImageRequests(NS_ERROR_IMAGE_SRC_CHANGED, PR_FALSE,
nsIContentPolicy::ACCEPT);
// XXX what should we do with content policies here, if anything?
// Shouldn't that be done before the start of the load?
// XXX what about shouldProcess?
nsCOMPtr<imgIRequest> & req = mCurrentRequest ? mPendingRequest : mCurrentRequest;
// Our state might change. Watch it.
AutoStateChanger changer(this, PR_TRUE);
// Do the load.
nsresult rv = nsContentUtils::GetImgLoader()->
LoadImageWithChannel(aChannel, this, doc, aListener, getter_AddRefs(req));
// Make sure our state is up to date
UpdateImageState(PR_TRUE);
return rv;
LoadImageWithChannel(aChannel, this, doc, aListener,
getter_AddRefs(PrepareNextRequest()));
if (NS_FAILED(rv)) {
// If we don't have a current URI, we might as well store this URI so people
// know what we tried (and failed) to load.
if (!mCurrentRequest)
aChannel->GetURI(getter_AddRefs(mCurrentURI));
FireEvent(NS_LITERAL_STRING("error"));
return rv;
}
return NS_OK;;
}
NS_IMETHODIMP nsImageLoadingContent::ForceReload()
@ -628,11 +609,10 @@ nsImageLoadingContent::LoadImage(nsIURI* aNewURI,
}
}
nsresult rv; // XXXbz Should failures in this method fire onerror?
// Skip the URI equality check if our current image was blocked. If
// that happened, we really do want to try loading again.
// URI equality check.
//
// We skip the equality check if our current image was blocked, since in that
// case we really do want to try loading again.
if (!aForce && NS_CP_ACCEPTED(mImageBlockingStatus)) {
nsCOMPtr<nsIURI> currentURI;
GetCurrentURI(getter_AddRefs(currentURI));
@ -645,71 +625,46 @@ nsImageLoadingContent::LoadImage(nsIURI* aNewURI,
}
}
// From this point on, our state could change before return, so make
// sure to notify if it does.
// From this point on, our image state could change. Watch it.
AutoStateChanger changer(this, aNotify);
// Use the principal of aDocument to avoid having to QI |this| an extra time.
// It should be the same as the principal of this node in any case.
// Sanity check.
//
// We use the principal of aDocument to avoid having to QI |this| an extra
// time. It should always be the same as the principal of this node.
#ifdef DEBUG
nsCOMPtr<nsIContent> thisContent = do_QueryInterface(this);
NS_ASSERTION(thisContent &&
thisContent->NodePrincipal() == aDocument->NodePrincipal(),
"Principal mismatch?");
NS_ABORT_IF_FALSE(thisContent &&
thisContent->NodePrincipal() == aDocument->NodePrincipal(),
"Principal mismatch?");
#endif
// If we'll be loading a new image, we want to cancel our existing
// requests; the question is what reason to pass in. If everything
// is going smoothly, that reason should be
// NS_ERROR_IMAGE_SRC_CHANGED so that our frame (if any) will know
// not to show the broken image icon. If the load is blocked by the
// content policy or security manager, we will want to cancel with
// the error code from those.
PRInt16 newImageStatus;
PRBool loadImage = nsContentUtils::CanLoadImage(aNewURI, this, aDocument,
aDocument->NodePrincipal(),
&newImageStatus);
NS_ASSERTION(loadImage || !NS_CP_ACCEPTED(newImageStatus),
"CanLoadImage lied");
nsresult cancelResult = loadImage ? NS_ERROR_IMAGE_SRC_CHANGED
: NS_ERROR_IMAGE_BLOCKED;
CancelImageRequests(cancelResult, PR_FALSE, newImageStatus);
// Remember the URL of this request, in case someone asks us for it later.
// But this only matters if we are affecting the current request. Need to do
// this after CancelImageRequests, since that affects the value of
// mCurrentRequest.
if (!mCurrentRequest) {
mCurrentURI = aNewURI;
}
if (!loadImage) {
// Don't actually load anything! This was blocked by CanLoadImage.
// Are we blocked?
PRInt16 cpDecision = nsIContentPolicy::REJECT_REQUEST;
nsContentUtils::CanLoadImage(aNewURI, this, aDocument,
aDocument->NodePrincipal(), &cpDecision);
if (!NS_CP_ACCEPTED(cpDecision)) {
FireEvent(NS_LITERAL_STRING("error"));
SetBlockedRequest(aNewURI, cpDecision);
return NS_OK;
}
nsCOMPtr<imgIRequest> & req = mCurrentRequest ? mPendingRequest : mCurrentRequest;
// Not blocked. Do the load.
nsresult rv;
rv = nsContentUtils::LoadImage(aNewURI, aDocument,
aDocument->NodePrincipal(),
aDocument->GetDocumentURI(),
this, aLoadFlags,
getter_AddRefs(req));
getter_AddRefs(PrepareNextRequest()));
if (NS_FAILED(rv)) {
// If we don't have a current URI, we might as well store this URI so people
// know what we tried (and failed) to load.
if (!mCurrentRequest)
mCurrentURI = aNewURI;
FireEvent(NS_LITERAL_STRING("error"));
return NS_OK;
}
// If we now have a current request, we don't need to store the URI, since
// we can get it off the request. Release it.
if (mCurrentRequest) {
mCurrentURI = nsnull;
}
return NS_OK;
}
@ -734,12 +689,13 @@ nsImageLoadingContent::ImageState() const
void
nsImageLoadingContent::UpdateImageState(PRBool aNotify)
{
if (mStartingLoad) {
// Ignore this call; we'll update our state when the state changer is
// destroyed. Need this to work around the fact that some libpr0n stuff is
// actually sync and hence we can get OnStopDecode called while we're still
// under LoadImage, and OnStopDecode doesn't know anything about
// aNotify
if (mStateChangerDepth > 0) {
// Ignore this call; we'll update our state when the outermost state
// changer is destroyed. Need this to work around the fact that some libpr0n
// stuff is actually sync and hence we can get OnStopDecode called while
// we're still under LoadImage, and OnStopDecode doesn't know anything about
// aNotify.
// XXX - This machinery should be removed after bug 521604.
return;
}
@ -788,78 +744,28 @@ nsImageLoadingContent::UpdateImageState(PRBool aNotify)
void
nsImageLoadingContent::CancelImageRequests(PRBool aNotify)
{
// Make sure to null out mCurrentURI here, so we no longer look like an image
AutoStateChanger changer(this, aNotify);
mCurrentURI = nsnull;
CancelImageRequests(NS_BINDING_ABORTED, PR_TRUE, nsIContentPolicy::ACCEPT);
}
void
nsImageLoadingContent::CancelImageRequests(nsresult aReason,
PRBool aEvenIfSizeAvailable,
PRInt16 aNewImageStatus)
{
// Cancel the pending request, if any
if (mPendingRequest) {
mPendingRequest->Cancel(aReason);
mPendingRequest = nsnull;
}
// Cancel the current request if it has not progressed enough to
// have a size yet
if (mCurrentRequest) {
PRUint32 loadStatus = imgIRequest::STATUS_ERROR;
mCurrentRequest->GetImageStatus(&loadStatus);
NS_ASSERTION(NS_CP_ACCEPTED(mImageBlockingStatus),
"Have current request but blocked image?");
if (aEvenIfSizeAvailable ||
!(loadStatus & imgIRequest::STATUS_SIZE_AVAILABLE)) {
// The new image is going to become the current request. Make sure to
// set mImageBlockingStatus _before_ we cancel the request... if we set
// it after, things that are watching the mCurrentRequest will get wrong
// data.
// If we were blocking onload for this image, stop doing so
SetBlockingOnload(PR_FALSE);
// Get rid of it
mImageBlockingStatus = aNewImageStatus;
mCurrentRequest->Cancel(aReason);
mCurrentRequest = nsnull;
}
} else {
// No current request so the new image status will become the
// status of the current request
mImageBlockingStatus = aNewImageStatus;
}
// Note that the only way we could have avoided setting the image blocking
// status above is if we have a current request and have kept it as the
// current request. In that case, we want to leave our old status, since the
// status corresponds to the current request. Even if we plan to do a
// pending request load, having an mCurrentRequest means that our current
// status is not a REJECT_* status, and doing the load shouldn't change that.
// XXXbz there is an issue here if different ACCEPT statuses are used, but...
ClearPendingRequest(NS_BINDING_ABORTED);
ClearCurrentRequest(NS_BINDING_ABORTED);
}
nsresult
nsImageLoadingContent::UseAsPrimaryRequest(imgIRequest* aRequest,
PRBool aNotify)
{
// Use an AutoStateChanger so that the clone call won't
// automatically notify from inside OnStopDecode.
// Also, make sure to use the CancelImageRequests which doesn't
// notify, so that the changer is handling the notifications.
NS_PRECONDITION(aRequest, "Must have a request here!");
// Our state will change. Watch it.
AutoStateChanger changer(this, aNotify);
mCurrentURI = nsnull;
CancelImageRequests(NS_BINDING_ABORTED, PR_TRUE, nsIContentPolicy::ACCEPT);
NS_ASSERTION(!mCurrentRequest, "We should not have a current request now");
// Get rid if our existing images
ClearPendingRequest(NS_BINDING_ABORTED);
ClearCurrentRequest(NS_BINDING_ABORTED);
return aRequest->Clone(this, getter_AddRefs(mCurrentRequest));
// Clone the request we were given.
nsCOMPtr<imgIRequest> newRequest;
nsresult rv = aRequest->Clone(this, getter_AddRefs(PrepareNextRequest()));
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
nsIDocument*
@ -911,6 +817,112 @@ nsImageLoadingContent::FireEvent(const nsAString& aEventType)
return NS_OK;
}
nsCOMPtr<imgIRequest>&
nsImageLoadingContent::PrepareNextRequest()
{
// If we don't have a usable current request, get rid of any half-baked
// request that might be sitting there and make this one current.
if (!HaveSize(mCurrentRequest))
return PrepareCurrentRequest();
// Otherwise, make it pending.
return PreparePendingRequest();
}
void
nsImageLoadingContent::SetBlockedRequest(nsIURI* aURI, PRInt16 aContentDecision)
{
// Sanity
NS_ABORT_IF_FALSE(!NS_CP_ACCEPTED(aContentDecision), "Blocked but not?");
// We do some slightly illogical stuff here to maintain consistency with
// old behavior that people probably depend on. Even in the case where the
// new image is blocked, the old one should really be canceled with the
// reason "image source changed". However, apparently there's some abuse
// over in nsImageFrame where the displaying of the "broken" icon for the
// next image depends on the cancel reason of the previous image. ugh.
ClearPendingRequest(NS_ERROR_IMAGE_BLOCKED);
// For the blocked case, we only want to cancel the existing current request
// if size is not available. bz says the web depends on this behavior.
if (!HaveSize(mCurrentRequest)) {
mImageBlockingStatus = aContentDecision;
ClearCurrentRequest(NS_ERROR_IMAGE_BLOCKED);
// We still want to remember what URI we were despite not having an actual
// request.
mCurrentURI = aURI;
}
}
nsCOMPtr<imgIRequest>&
nsImageLoadingContent::PrepareCurrentRequest()
{
// Blocked images go through SetBlockedRequest, which is a separate path. For
// everything else, we're unblocked.
mImageBlockingStatus = nsIContentPolicy::ACCEPT;
// Get rid of anything that was there previously.
ClearCurrentRequest(NS_ERROR_IMAGE_SRC_CHANGED);
// Return a reference.
return mCurrentRequest;
}
nsCOMPtr<imgIRequest>&
nsImageLoadingContent::PreparePendingRequest()
{
// Get rid of anything that was there previously.
ClearPendingRequest(NS_ERROR_IMAGE_SRC_CHANGED);
// Return a reference.
return mPendingRequest;
}
void
nsImageLoadingContent::ClearCurrentRequest(nsresult aReason)
{
if (!mCurrentRequest) {
// Even if we didn't have a current request, we might have been keeping
// a URI as a placeholder for a failed load. Clear that now.
mCurrentURI = nsnull;
return;
}
NS_ABORT_IF_FALSE(!mCurrentURI,
"Shouldn't have both mCurrentRequest and mCurrentURI!");
// Clean up the request.
mCurrentRequest->CancelAndForgetObserver(aReason);
mCurrentRequest = nsnull;
// We only block onload during the decoding of "current" images. This one is
// going away, so we should unblock unconditionally here.
SetBlockingOnload(PR_FALSE);
}
void
nsImageLoadingContent::ClearPendingRequest(nsresult aReason)
{
if (!mPendingRequest)
return;
mPendingRequest->CancelAndForgetObserver(aReason);
mPendingRequest = nsnull;
}
bool
nsImageLoadingContent::HaveSize(imgIRequest *aImage)
{
// Handle the null case
if (!aImage)
return false;
// Query the image
PRUint32 status;
nsresult rv = aImage->GetImageStatus(&status);
return (NS_SUCCEEDED(rv) && (status & imgIRequest::STATUS_SIZE_AVAILABLE));
}
void
nsImageLoadingContent::SetBlockingOnload(PRBool aBlocking)
{
@ -940,7 +952,7 @@ nsImageLoadingContent::CreateStaticImageClone(nsImageLoadingContent* aDest) cons
aDest->mForcedImageState = mForcedImageState;
aDest->mImageBlockingStatus = mImageBlockingStatus;
aDest->mLoadingEnabled = mLoadingEnabled;
aDest->mStartingLoad = mStartingLoad;
aDest->mStateChangerDepth = mStateChangerDepth;
aDest->mIsImageStateForced = mIsImageStateForced;
aDest->mLoading = mLoading;
aDest->mBroken = mBroken;

View File

@ -189,13 +189,11 @@ private:
mImageContent(aImageContent),
mNotify(aNotify)
{
NS_ASSERTION(!mImageContent->mStartingLoad,
"Nested AutoStateChangers somehow?");
mImageContent->mStartingLoad = PR_TRUE;
mImageContent->mStateChangerDepth++;
}
~AutoStateChanger()
{
mImageContent->mStartingLoad = PR_FALSE;
mImageContent->mStateChangerDepth--;
mImageContent->UpdateImageState(mNotify);
}
@ -248,9 +246,50 @@ private:
protected:
void CreateStaticImageClone(nsImageLoadingContent* aDest) const;
/**
* Prepare and returns a reference to the "next request". If there's already
* a _usable_ current request (one with SIZE_AVAILABLE), this request is
* "pending" until it becomes usable. Otherwise, this becomes the current
* request.
*/
nsCOMPtr<imgIRequest>& PrepareNextRequest();
/**
* Called when we would normally call PrepareNextRequest(), but the request was
* blocked.
*/
void SetBlockedRequest(nsIURI* aURI, PRInt16 aContentDecision);
/**
* Returns a COMPtr reference to the current/pending image requests, cleaning
* up and canceling anything that was there before. Note that if you just want
* to get rid of one of the requests, you should call
* Clear*Request(NS_BINDING_ABORTED) instead, since it passes a more appropriate
* aReason than Prepare*Request() does (NS_ERROR_IMAGE_SRC_CHANGED).
*/
nsCOMPtr<imgIRequest>& PrepareCurrentRequest();
nsCOMPtr<imgIRequest>& PreparePendingRequest();
/**
* Cancels and nulls-out the "current" and "pending" requests if they exist.
*/
void ClearCurrentRequest(nsresult aReason);
void ClearPendingRequest(nsresult aReason);
/**
* Static helper method to tell us if we have the size of a request. The
* image may be null.
*/
static bool HaveSize(imgIRequest *aImage);
/* MEMBERS */
nsCOMPtr<imgIRequest> mCurrentRequest;
nsCOMPtr<imgIRequest> mPendingRequest;
// If the image was blocked or if there was an error loading, it's nice to
// still keep track of what the URI was despite not having an imgIRequest.
// We only maintain this in those situations (in the common case, this is
// always null).
nsCOMPtr<nsIURI> mCurrentURI;
private:
@ -272,7 +311,6 @@ private:
PRInt16 mImageBlockingStatus;
PRPackedBool mLoadingEnabled : 1;
PRPackedBool mStartingLoad : 1;
/**
* When true, we return mForcedImageState from ImageState().
@ -292,6 +330,9 @@ private:
* Whether we're currently blocking document load.
*/
PRPackedBool mBlockingOnload : 1;
/* The number of nested AutoStateChangers currently tracking our state. */
PRUint8 mStateChangerDepth;
};
#endif // nsImageLoadingContent_h__

View File

@ -103,6 +103,10 @@ NS_NewDOMSVGEvent(nsIDOMEvent** aResult, nsPresContext* aPresContext, class nsEv
nsresult
NS_NewDOMSVGZoomEvent(nsIDOMEvent** aResult, nsPresContext* aPresContext, class nsGUIEvent* aEvent);
#endif // MOZ_SVG
#ifdef MOZ_SMIL
nsresult
NS_NewDOMTimeEvent(nsIDOMEvent** aResult, nsPresContext* aPresContext, class nsEvent* aEvent);
#endif // MOZ_SMIL
nsresult
NS_NewDOMXULCommandEvent(nsIDOMEvent** aResult, nsPresContext* aPresContext, class nsInputEvent* aEvent);
nsresult

View File

@ -81,6 +81,9 @@ static const char* const sEventNames[] = {
"SVGLoad", "SVGUnload", "SVGAbort", "SVGError", "SVGResize", "SVGScroll",
"SVGZoom",
#endif // MOZ_SVG
#ifdef MOZ_SMIL
"beginEvent", "endEvent", "repeatEvent",
#endif // MOZ_SMIL
#ifdef MOZ_MEDIA
"loadstart", "progress", "suspend", "emptied", "stalled", "play", "pause",
"loadedmetadata", "loadeddata", "waiting", "playing", "canplay",
@ -773,6 +776,15 @@ NS_METHOD nsDOMEvent::DuplicatePrivateData()
break;
}
#endif // MOZ_SVG
#ifdef MOZ_SMIL
case NS_SMIL_TIME_EVENT:
{
newEvent = new nsUIEvent(PR_FALSE, msg, 0);
NS_ENSURE_TRUE(newEvent, NS_ERROR_OUT_OF_MEMORY);
newEvent->eventStructType = NS_SMIL_TIME_EVENT;
break;
}
#endif // MOZ_SMIL
case NS_SIMPLE_GESTURE_EVENT:
{
nsSimpleGestureEvent* oldSimpleGestureEvent = static_cast<nsSimpleGestureEvent*>(mEvent);
@ -1225,6 +1237,14 @@ const char* nsDOMEvent::GetEventName(PRUint32 aEventType)
case NS_SVG_ZOOM:
return sEventNames[eDOMEvents_SVGZoom];
#endif // MOZ_SVG
#ifdef MOZ_SMIL
case NS_SMIL_BEGIN:
return sEventNames[eDOMEvents_beginEvent];
case NS_SMIL_END:
return sEventNames[eDOMEvents_endEvent];
case NS_SMIL_REPEAT:
return sEventNames[eDOMEvents_repeatEvent];
#endif // MOZ_SMIL
#ifdef MOZ_MEDIA
case NS_LOADSTART:
return sEventNames[eDOMEvents_loadstart];

View File

@ -142,6 +142,11 @@ public:
eDOMEvents_SVGScroll,
eDOMEvents_SVGZoom,
#endif // MOZ_SVG
#ifdef MOZ_SMIL
eDOMEvents_beginEvent,
eDOMEvents_endEvent,
eDOMEvents_repeatEvent,
#endif // MOZ_SMIL
#ifdef MOZ_MEDIA
eDOMEvents_loadstart,
eDOMEvents_progress,

View File

@ -742,6 +742,10 @@ nsEventDispatcher::CreateEvent(nsPresContext* aPresContext,
return NS_NewDOMSVGZoomEvent(aDOMEvent, aPresContext,
static_cast<nsGUIEvent*>(aEvent));
#endif // MOZ_SVG
#ifdef MOZ_SMIL
case NS_SMIL_TIME_EVENT:
return NS_NewDOMTimeEvent(aDOMEvent, aPresContext, aEvent);
#endif // MOZ_SMIL
case NS_COMMAND_EVENT:
return NS_NewDOMCommandEvent(aDOMEvent, aPresContext,
@ -797,6 +801,11 @@ nsEventDispatcher::CreateEvent(nsPresContext* aPresContext,
aEventType.LowerCaseEqualsLiteral("svgzoomevents"))
return NS_NewDOMSVGZoomEvent(aDOMEvent, aPresContext, nsnull);
#endif // MOZ_SVG
#ifdef MOZ_SMIL
if (aEventType.LowerCaseEqualsLiteral("timeevent") ||
aEventType.LowerCaseEqualsLiteral("timeevents"))
return NS_NewDOMTimeEvent(aDOMEvent, aPresContext, nsnull);
#endif // MOZ_SMIL
if (aEventType.LowerCaseEqualsLiteral("xulcommandevent") ||
aEventType.LowerCaseEqualsLiteral("xulcommandevents"))
return NS_NewDOMXULCommandEvent(aDOMEvent, aPresContext, nsnull);

View File

@ -983,6 +983,14 @@ nsEventListenerManager::CompileEventHandlerInternal(nsIScriptContext *aContext,
else if (aName == nsGkAtoms::onSVGZoom)
attrName = nsGkAtoms::onzoom;
#endif // MOZ_SVG
#ifdef MOZ_SMIL
else if (aName == nsGkAtoms::onbeginEvent)
attrName = nsGkAtoms::onbegin;
else if (aName == nsGkAtoms::onrepeatEvent)
attrName = nsGkAtoms::onrepeat;
else if (aName == nsGkAtoms::onendEvent)
attrName = nsGkAtoms::onend;
#endif // MOZ_SMIL
content->GetAttr(kNameSpaceID_None, attrName, handlerBody);

View File

@ -54,6 +54,7 @@ EXPORTS = nsSMILKeySpline.h
ifdef MOZ_SMIL
CPPSRCS += \
nsDOMTimeEvent.cpp \
nsSMILAnimationController.cpp \
nsSMILAnimationFunction.cpp \
nsSMILCompositor.cpp \
@ -105,6 +106,7 @@ EXPORTS += \
INCLUDES += \
-I$(srcdir)/../base/src \
-I$(srcdir)/../../layout/style \
-I$(srcdir)/../events/src \
$(NULL)
endif # MOZ_SMIL

View File

@ -0,0 +1,130 @@
/* -*- 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 the Mozilla SMIL Module.
*
* The Initial Developer of the Original Code is Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Brian Birtles <birtles@gmail.com>
*
* 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 "nsDOMTimeEvent.h"
#include "nsGUIEvent.h"
#include "nsPresContext.h"
#include "nsIInterfaceRequestorUtils.h"
#include "nsIDOMAbstractView.h"
nsDOMTimeEvent::nsDOMTimeEvent(nsPresContext* aPresContext, nsEvent* aEvent)
: nsDOMEvent(aPresContext, aEvent ? aEvent : new nsUIEvent(PR_FALSE, 0, 0)),
mDetail(0)
{
if (aEvent) {
mEventIsInternal = PR_FALSE;
} else {
mEventIsInternal = PR_TRUE;
mEvent->eventStructType = NS_SMIL_TIME_EVENT;
}
if (mEvent->eventStructType == NS_SMIL_TIME_EVENT) {
nsUIEvent* event = static_cast<nsUIEvent*>(mEvent);
mDetail = event->detail;
}
mEvent->flags |= NS_EVENT_FLAG_CANT_BUBBLE |
NS_EVENT_FLAG_CANT_CANCEL;
if (mPresContext) {
nsCOMPtr<nsISupports> container = mPresContext->GetContainer();
if (container) {
nsCOMPtr<nsIDOMWindowInternal> window = do_GetInterface(container);
if (window) {
mView = do_QueryInterface(window);
}
}
}
}
NS_IMPL_CYCLE_COLLECTION_CLASS(nsDOMTimeEvent)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsDOMTimeEvent, nsDOMEvent)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mView)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsDOMTimeEvent, nsDOMEvent)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mView)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_ADDREF_INHERITED(nsDOMTimeEvent, nsDOMEvent)
NS_IMPL_RELEASE_INHERITED(nsDOMTimeEvent, nsDOMEvent)
DOMCI_DATA(TimeEvent, nsDOMTimeEvent)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsDOMTimeEvent)
NS_INTERFACE_MAP_ENTRY(nsIDOMTimeEvent)
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(TimeEvent)
NS_INTERFACE_MAP_END_INHERITING(nsDOMEvent)
NS_IMETHODIMP
nsDOMTimeEvent::GetView(nsIDOMAbstractView** aView)
{
*aView = mView;
NS_IF_ADDREF(*aView);
return NS_OK;
}
NS_IMETHODIMP
nsDOMTimeEvent::GetDetail(PRInt32* aDetail)
{
*aDetail = mDetail;
return NS_OK;
}
NS_IMETHODIMP
nsDOMTimeEvent::InitTimeEvent(const nsAString& aTypeArg,
nsIDOMAbstractView* aViewArg,
PRInt32 aDetailArg)
{
nsresult rv = nsDOMEvent::InitEvent(aTypeArg, PR_FALSE /*doesn't bubble*/,
PR_FALSE /*can't cancel*/);
NS_ENSURE_SUCCESS(rv, rv);
mDetail = aDetailArg;
mView = aViewArg;
return NS_OK;
}
nsresult NS_NewDOMTimeEvent(nsIDOMEvent** aInstancePtrResult,
nsPresContext* aPresContext,
nsEvent* aEvent)
{
nsDOMTimeEvent* it = new nsDOMTimeEvent(aPresContext, aEvent);
return CallQueryInterface(it, aInstancePtrResult);
}

View File

@ -0,0 +1,65 @@
/* -*- 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 the Mozilla SMIL Module.
*
* The Initial Developer of the Original Code is Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Brian Birtles <birtles@gmail.com>
*
* 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 NS_DOMTIMEEVENT_H_
#define NS_DOMTIMEEVENT_H_
#include "nsIDOMTimeEvent.h"
#include "nsDOMEvent.h"
class nsDOMTimeEvent : public nsDOMEvent,
public nsIDOMTimeEvent
{
public:
nsDOMTimeEvent(nsPresContext* aPresContext, nsEvent* aEvent);
// nsISupports interface:
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsDOMTimeEvent, nsDOMEvent)
// nsIDOMTimeEvent interface:
NS_DECL_NSIDOMTIMEEVENT
// Forward to base class
NS_FORWARD_TO_NSDOMEVENT
private:
nsCOMPtr<nsIDOMAbstractView> mView;
PRInt32 mDetail;
};
#endif // NS_DOMTIMEEVENT_H_

View File

@ -43,15 +43,19 @@
#include "nsSMILParserUtils.h"
#include "nsSMILTimeContainer.h"
#include "nsGkAtoms.h"
#include "nsGUIEvent.h"
#include "nsEventDispatcher.h"
#include "nsReadableUtils.h"
#include "nsMathUtils.h"
#include "nsThreadUtils.h"
#include "nsIPresShell.h"
#include "prdtoa.h"
#include "plstr.h"
#include "prtime.h"
#include "nsString.h"
//----------------------------------------------------------------------
// Helper classes -- InstanceTimeComparator
// Helper class: InstanceTimeComparator
// Upon inserting an instance time into one of our instance time lists we assign
// it a serial number. This allows us to sort the instance times in such a way
@ -90,6 +94,43 @@ nsSMILTimedElement::InstanceTimeComparator::LessThan(
return cmp == 0 ? aElem1->Serial() < aElem2->Serial() : cmp < 0;
}
//----------------------------------------------------------------------
// Helper class: AsyncTimeEventRunner
namespace
{
class AsyncTimeEventRunner : public nsRunnable
{
protected:
nsRefPtr<nsIContent> mTarget;
PRUint32 mMsg;
PRInt32 mDetail;
public:
AsyncTimeEventRunner(nsIContent* aTarget, PRUint32 aMsg, PRInt32 aDetail)
: mTarget(aTarget), mMsg(aMsg), mDetail(aDetail)
{
}
NS_IMETHOD Run()
{
nsUIEvent event(PR_TRUE, mMsg, mDetail);
event.eventStructType = NS_SMIL_TIME_EVENT;
nsPresContext* context = nsnull;
nsIDocument* doc = mTarget->GetCurrentDoc();
if (doc) {
nsCOMPtr<nsIPresShell> shell = doc->GetShell();
if (shell) {
context = shell->GetPresContext();
}
}
return nsEventDispatcher::Dispatch(mTarget, context, &event);
}
};
}
//----------------------------------------------------------------------
// Templated helper functions
@ -150,6 +191,7 @@ nsSMILTimedElement::nsSMILTimedElement()
mInstanceSerialIndex(0),
mClient(nsnull),
mCurrentInterval(nsnull),
mCurrentRepeatIteration(0),
mPrevRegisteredMilestone(sMaxMilestone),
mElementState(STATE_STARTUP),
mSeekState(SEEK_NOT_SEEKING)
@ -506,20 +548,21 @@ nsSMILTimedElement::DoSampleAt(nsSMILTime aContainerTime, PRBool aEndOnly)
if (mCurrentInterval->Begin()->Time() <= sampleTime) {
mElementState = STATE_ACTIVE;
mCurrentInterval->FixBegin();
if (HasPlayed()) {
Reset(); // Apply restart behaviour
}
if (mClient) {
mClient->Activate(mCurrentInterval->Begin()->Time().GetMillis());
}
if (mSeekState == SEEK_NOT_SEEKING) {
FireTimeEventAsync(NS_SMIL_BEGIN, 0);
}
if (HasPlayed()) {
Reset(); // Apply restart behaviour
// The call to Reset() may mean that the end point of our current
// interval should be changed and so we should update the interval
// now. However, calling UpdateCurrentInterval could result in the
// interval getting deleted (perhaps through some web of syncbase
// dependencies) therefore we make updating the interval the last
// thing we do. There is no guarantee that mCurrentInterval.IsSet()
// is true after this.
// thing we do. There is no guarantee that mCurrentInterval is set
// after this.
UpdateCurrentInterval();
}
stateChanged = PR_TRUE;
@ -541,6 +584,10 @@ nsSMILTimedElement::DoSampleAt(nsSMILTime aContainerTime, PRBool aEndOnly)
mClient->Inactivate(mFillMode == FILL_FREEZE);
}
mCurrentInterval->FixEnd();
if (mSeekState == SEEK_NOT_SEEKING) {
FireTimeEventAsync(NS_SMIL_END, 0);
}
mCurrentRepeatIteration = 0;
mOldIntervals.AppendElement(mCurrentInterval.forget());
// We must update mOldIntervals before calling SampleFillValue
SampleFillValue();
@ -556,6 +603,19 @@ nsSMILTimedElement::DoSampleAt(nsSMILTime aContainerTime, PRBool aEndOnly)
"Sample time should not precede current interval");
nsSMILTime activeTime = aContainerTime - beginTime;
SampleSimpleTime(activeTime);
// We register our repeat times as milestones (except when we're
// seeking) so we should get a sample at exactly the time we repeat.
// (And even when we are seeking we want to update
// mCurrentRepeatIteration so we do that first before testing the seek
// state.)
PRUint32 prevRepeatIteration = mCurrentRepeatIteration;
if (ActiveTimeToSimpleTime(activeTime, mCurrentRepeatIteration)==0 &&
mCurrentRepeatIteration != prevRepeatIteration &&
mCurrentRepeatIteration &&
mSeekState == SEEK_NOT_SEEKING) {
FireTimeEventAsync(NS_SMIL_REPEAT,
static_cast<PRInt32>(mCurrentRepeatIteration));
}
}
}
break;
@ -607,6 +667,7 @@ nsSMILTimedElement::Rewind()
// Set the STARTUP state first so that if we get any callbacks we won't waste
// time recalculating the current interval
mElementState = STATE_STARTUP;
mCurrentRepeatIteration = 0;
// Clear the intervals and instance times except those instance times we can't
// regenerate (DOM calls etc.)
@ -1238,13 +1299,6 @@ nsSMILTimedElement::Reset()
void
nsSMILTimedElement::DoPostSeek()
{
// XXX When implementing TimeEvents we'll need to compare mElementState with
// mSeekState and dispatch events as follows:
// ACTIVE->INACTIVE: End event
// INACTIVE->ACTIVE: Begin event
// ACTIVE->ACTIVE: Nothing (even if they're different intervals)
// INACTIVE->INACTIVE: Nothing (even if we've skipped intervals)
// Finish backwards seek
if (mSeekState == SEEK_BACKWARD_FROM_INACTIVE ||
mSeekState == SEEK_BACKWARD_FROM_ACTIVE) {
@ -1266,6 +1320,34 @@ nsSMILTimedElement::DoPostSeek()
UpdateCurrentInterval();
}
// XXX
// Note that SMIL gives the very cryptic description:
// The associated time for the event is the document time before the seek.
// This action does not resolve any times in the instance times list for end
// times.
//
// The second sentence was added as a clarification in a SMIL 2.0 erratum.
// Presumably the intention is that we fire the event as implemented below but
// don't act on it. This makes sense at least for dependencies within the same
// time container. So we'll probably need to set a flag here to ensure we
// don't actually act on it when we implement event-based timing.
switch (mSeekState)
{
case SEEK_FORWARD_FROM_ACTIVE:
case SEEK_BACKWARD_FROM_ACTIVE:
if (mElementState != STATE_ACTIVE) {
FireTimeEventAsync(NS_SMIL_END, 0);
}
break;
case SEEK_FORWARD_FROM_INACTIVE:
case SEEK_BACKWARD_FROM_INACTIVE:
if (mElementState == STATE_ACTIVE) {
FireTimeEventAsync(NS_SMIL_BEGIN, 0);
}
break;
}
mSeekState = SEEK_NOT_SEEKING;
}
@ -1861,10 +1943,6 @@ nsSMILTimedElement::GetNextMilestone(nsSMILMilestone& aNextMilestone) const
{
// Return the next key moment in our lifetime.
//
// XXX Once we implement TimeEvents and event based timing we might need to
// include repeat times too, particularly if it's important to get them in
// order.
//
// XXX It may be possible in future to optimise this so that we only register
// for milestones if:
// a) We have time dependents, or
@ -1896,22 +1974,27 @@ nsSMILTimedElement::GetNextMilestone(nsSMILMilestone& aNextMilestone) const
case STATE_ACTIVE:
{
// XXX When we implement TimeEvents, we may need to consider what comes
// next: the interval end or an interval repeat.
// Work out what comes next: the interval end or the next repeat iteration
nsSMILTimeValue nextRepeat;
if (mSeekState == SEEK_NOT_SEEKING && mSimpleDur.IsResolved()) {
nextRepeat.SetMillis(mCurrentInterval->Begin()->Time().GetMillis() +
(mCurrentRepeatIteration + 1) * mSimpleDur.GetMillis());
}
nsSMILTimeValue nextMilestone =
NS_MIN(mCurrentInterval->End()->Time(), nextRepeat);
// Check for an early end
nsSMILInstanceTime* earlyEnd =
CheckForEarlyEnd(mCurrentInterval->End()->Time());
// Check for an early end before that time
nsSMILInstanceTime* earlyEnd = CheckForEarlyEnd(nextMilestone);
if (earlyEnd) {
aNextMilestone.mIsEnd = PR_TRUE;
aNextMilestone.mTime = earlyEnd->Time().GetMillis();
return PR_TRUE;
}
// Otherwise it's just the next interval end
if (mCurrentInterval->End()->Time().IsResolved()) {
aNextMilestone.mIsEnd = PR_TRUE;
aNextMilestone.mTime = mCurrentInterval->End()->Time().GetMillis();
// Apply the previously calculated milestone
if (nextMilestone.IsResolved()) {
aNextMilestone.mIsEnd = nextMilestone != nextRepeat;
aNextMilestone.mTime = nextMilestone.GetMillis();
return PR_TRUE;
}
@ -1958,6 +2041,17 @@ nsSMILTimedElement::NotifyChangedInterval()
mCurrentInterval->NotifyChanged(container);
}
void
nsSMILTimedElement::FireTimeEventAsync(PRUint32 aMsg, PRInt32 aDetail)
{
if (!mAnimationElement)
return;
nsCOMPtr<nsIRunnable> event =
new AsyncTimeEventRunner(&mAnimationElement->Content(), aMsg, aDetail);
NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
}
const nsSMILInstanceTime*
nsSMILTimedElement::GetEffectiveBeginInstance() const
{

View File

@ -482,6 +482,7 @@ protected:
void NotifyNewInterval();
void NotifyChangedInterval();
void FireTimeEventAsync(PRUint32 aMsg, PRInt32 aDetail);
const nsSMILInstanceTime* GetEffectiveBeginInstance() const;
const nsSMILInterval* GetPreviousInterval() const;
PRBool HasPlayed() const { return !mOldIntervals.IsEmpty(); }
@ -539,6 +540,7 @@ protected:
nsSMILAnimationFunction* mClient;
nsAutoPtr<nsSMILInterval> mCurrentInterval;
IntervalList mOldIntervals;
PRUint32 mCurrentRepeatIteration;
nsSMILMilestone mPrevRegisteredMilestone;
static const nsSMILMilestone sMaxMilestone;
static const PRUint8 sMaxNumIntervals;

View File

@ -82,6 +82,7 @@ _TEST_FILES = \
test_smilSyncbaseTarget.xhtml \
test_smilSyncTransform.xhtml \
test_smilTextZoom.xhtml \
test_smilTimeEvents.xhtml \
test_smilTiming.xhtml \
test_smilTimingZeroIntervals.xhtml \
test_smilUpdatedInterval.xhtml \

View File

@ -0,0 +1,292 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=572270
-->
<head>
<title>Test TimeEvents dispatching</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=572270">Mozilla Bug
572270</a>
<p id="display"></p>
<div id="content" style="display: none">
<svg id="svg" xmlns="http://www.w3.org/2000/svg" width="100px" height="100px">
<g font-size="10px">
<circle cx="0" cy="0" r="15" fill="blue" id="circle"
onbegin="parentHandler(evt)" onrepeat="parentHandler(evt)"
onend="parentHandler(evt)">
<animate attributeName="cy" from="0" to="100" dur="60s" begin="2s"
id="anim" repeatCount="2"
onbegin="handleOnBegin(evt)" onrepeat="handleOnRepeat(evt)"
onend="handleOnEnd(evt)"/>
</circle>
</g>
</svg>
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
<![CDATA[
/** Test SMIL TimeEvents dispatching **/
/* Global Variables */
const gTimeoutDur = 5000; // Time until we give up waiting for events in ms
var gSvg = document.getElementById("svg");
var gAnim = document.getElementById('anim');
var gCircle = document.getElementById('circle');
var gExpectedEvents = new Array();
var gTimeoutID;
var gTestStages =
[ testPlaybackBegin,
testPlaybackRepeat,
testPlaybackEnd,
testForwardsSeekToMid,
testForwardsSeekToNextInterval,
testForwardsSeekPastEnd,
testBackwardsSeekToMid,
testBackwardsSeekToStart,
testCreateEvent,
testRegistration
];
SimpleTest.waitForExplicitFinish();
function continueTest()
{
if (gTestStages.length == 0) {
SimpleTest.finish();
return;
}
gTestStages.shift()();
}
function testPlaybackBegin()
{
// Test events are dispatched through normal playback
gSvg.pauseAnimations();
gSvg.setCurrentTime(1.99);
gExpectedEvents.push("beginEvent", "beginEvent"); // Two registered handlers
gTimeoutID = setTimeout(timeoutFail, gTimeoutDur);
gSvg.unpauseAnimations();
}
function testPlaybackRepeat()
{
gSvg.pauseAnimations();
gSvg.setCurrentTime(61.99);
gExpectedEvents.push(["repeatEvent", 1], ["repeatEvent", 1]);
gTimeoutID = setTimeout(timeoutFail, gTimeoutDur);
gSvg.unpauseAnimations();
}
function testPlaybackEnd()
{
gSvg.pauseAnimations();
gSvg.setCurrentTime(121.99);
gExpectedEvents.push("endEvent", "endEvent");
gTimeoutID = setTimeout(timeoutFail, gTimeoutDur);
gSvg.unpauseAnimations();
}
function testForwardsSeekToMid()
{
gSvg.pauseAnimations();
// Set animation parameters to something that repeats a lot
gSvg.setCurrentTime(0);
gAnim.setAttribute('begin', '2s; 102s');
gAnim.setAttribute('dur', '15s');
gAnim.setAttribute('repeatCount', '6');
gSvg.setCurrentTime(46.99);
gExpectedEvents.push("beginEvent", "beginEvent",
["repeatEvent", 3], ["repeatEvent", 3]);
gTimeoutID = setTimeout(timeoutFail, gTimeoutDur);
gSvg.unpauseAnimations();
}
function testForwardsSeekToNextInterval()
{
// Skip to next interval -- we shouldn't get any additional begin or end
// events in between
gSvg.pauseAnimations();
gSvg.setCurrentTime(131.99);
gExpectedEvents.push(["repeatEvent", 2], ["repeatEvent", 2]);
gTimeoutID = setTimeout(timeoutFail, gTimeoutDur);
gSvg.unpauseAnimations();
}
function testForwardsSeekPastEnd()
{
gSvg.pauseAnimations();
gSvg.setCurrentTime(200);
gExpectedEvents.push("endEvent", "endEvent");
gTimeoutID = setTimeout(timeoutFail, gTimeoutDur);
gSvg.unpauseAnimations();
}
function testBackwardsSeekToMid()
{
gSvg.pauseAnimations();
gSvg.setCurrentTime(31.99);
gExpectedEvents.push("beginEvent", "beginEvent",
["repeatEvent", 2], ["repeatEvent", 2]);
gTimeoutID = setTimeout(timeoutFail, gTimeoutDur);
gSvg.unpauseAnimations();
}
function testBackwardsSeekToStart()
{
gSvg.pauseAnimations();
gExpectedEvents.push("endEvent", "endEvent");
gTimeoutID = setTimeout(timeoutFail, gTimeoutDur);
gSvg.setCurrentTime(0);
}
function testCreateEvent()
{
var evt;
try {
evt = document.createEvent("TimeEvents");
} catch (e) {
ok(false, "Failed to create TimeEvent via script: " + e);
return;
}
evt.initTimeEvent("repeatEvent", null, 3);
is(evt.type, "repeatEvent", "Unexpected type for user-generated event");
is(evt.detail, 3, "Unexpected detail for user-generated event");
is(evt.target, null, "Unexpected event target");
is(evt.currentTarget, null, "Unexpected event current target");
is(evt.eventPhase, evt.AT_TARGET);
is(evt.bubbles, false, "Event should not bubble");
is(evt.cancelable, false, "Event should not be cancelable");
is(evt.view, null, "Event view should be null");
// Prior to dispatch we should be able to change the event type
evt.initTimeEvent("beginEvent", document.defaultView, 0);
is(evt.type, "beginEvent", "Failed to update event type before dispatch");
is(evt.detail, 0, "Failed to update event detail before dispatch");
is(evt.view, document.defaultView, "Event view should be set");
// But not directly as it's readonly
try {
evt.type = "endEvent";
} catch(e) { }
is(evt.type, "beginEvent", "Event type should be readonly");
// Likewise the detail field should be readonly
try {
evt.detail = "8";
} catch(e) { }
is(evt.detail, 0, "Event detail should be readonly");
// Dispatch
gExpectedEvents.push("beginEvent", "beginEvent");
gTimeoutID = setTimeout(timeoutFail, gTimeoutDur);
gAnim.dispatchEvent(evt);
}
function testRegistration()
{
gSvg.pauseAnimations();
// Reset animation to something simple
gSvg.setCurrentTime(0);
gAnim.setAttribute('begin', '2s');
gAnim.setAttribute('dur', '50s');
// Remove attribute handler
gAnim.removeAttribute('onbegin');
// Add bogus handlers
gAnim.setAttribute('onbeginElement', 'handleOnBegin(evt)');
gAnim.addEventListener("begin", handleOnBegin, false);
gAnim.addEventListener("onbegin", handleOnBegin, false);
// We should now have just one legitimate listener: the one registered to
// handle 'beginElement'
gSvg.setCurrentTime(1.99);
gExpectedEvents.push("beginEvent");
gTimeoutID = setTimeout(timeoutFail, gTimeoutDur);
gSvg.unpauseAnimations();
}
function handleOnBegin(evt)
{
is(evt.type, "beginEvent", "Expected begin event but got " + evt.type);
checkExpectedEvent(evt);
}
function handleOnRepeat(evt)
{
is(evt.type, "repeatEvent", "Expected repeat event but got " + evt.type);
checkExpectedEvent(evt);
}
function handleOnEnd(evt)
{
is(evt.type, "endEvent", "Expected end event but got " + evt.type);
checkExpectedEvent(evt);
}
function sanityCheckEvent(evt)
{
is(evt.target, gAnim, "Unexpected event target");
is(evt.currentTarget, gAnim, "Unexpected event current target");
is(evt.eventPhase, evt.AT_TARGET);
is(evt.bubbles, false, "Event should not bubble");
is(evt.cancelable, false, "Event should not be cancelable");
// Currently we set event timestamps to 0 which DOM 2 allows. This isn't
// correct since SMIL uses this field to avoid synchronisation slew but first
// we need to fix bug 323039 and bug 77992 which involve storing timestamps as
// 64-bit integers and deciding whether those timestamps should be related to
// the epoch or system start.
is(evt.timeStamp, 0, "Event timeStamp should be 0");
ok(evt.view !== null, "Event view not set");
}
function checkExpectedEvent(evt)
{
sanityCheckEvent(evt);
ok(gExpectedEvents.length > 0, "Unexpected event: " + evt.type);
if (gExpectedEvents.length == 0) return;
var expected = gExpectedEvents.shift();
if (typeof expected == 'string') {
is(evt.type, expected, "Unexpected event type");
is(evt.detail, 0, "Unexpected event detail (repeat iteration)");
} else {
is(evt.type, expected[0], "Unexpected event type");
is(evt.detail, expected[1], "Unexpected event detail (repeat iteration)");
}
if (gExpectedEvents.length == 0) {
clearTimeout(gTimeoutID);
continueTest();
}
}
function timeoutFail()
{
ok(false, "Timed out waiting for events: " + gExpectedEvents.join(', '));
SimpleTest.finish(); // No point continuing
}
function parentHandler(evt)
{
ok(false, "Handler on parent got called but event shouldn't bubble.");
}
window.addEventListener("load", continueTest, false);
// Register event handlers *in addition* to the handlers already added via the
// "onbegin", "onend", "onrepeat" attributes on the <animate> and <circle>
// elements. This is to test that both types of registration work.
gAnim.addEventListener("beginEvent", handleOnBegin, false);
gAnim.addEventListener("repeatEvent", handleOnRepeat, false);
gAnim.addEventListener("endEvent", handleOnEnd, false);
gCircle.addEventListener("beginEvent", parentHandler, false);
]]>
</script>
</pre>
</body>
</html>

View File

@ -476,6 +476,12 @@ nsSVGAnimationElement::EndElementAt(float offset)
return NS_OK;
}
PRBool
nsSVGAnimationElement::IsEventName(nsIAtom* aName)
{
return nsContentUtils::IsEventAttributeName(aName, EventNameType_SMIL);
}
void
nsSVGAnimationElement::UpdateHrefTarget(nsIContent* aNodeForContext,
const nsAString& aHrefStr)

View File

@ -98,6 +98,9 @@ public:
virtual nsSMILTimeContainer* GetTimeContainer();
protected:
// nsSVGElement overrides
PRBool IsEventName(nsIAtom* aName);
void UpdateHrefTarget(nsIContent* aNodeForContext,
const nsAString& aHrefStr);

View File

@ -1364,6 +1364,14 @@ nsIAtom* nsSVGElement::GetEventNameForAttr(nsIAtom* aAttr)
return nsGkAtoms::onSVGScroll;
if (aAttr == nsGkAtoms::onzoom)
return nsGkAtoms::onSVGZoom;
#ifdef MOZ_SMIL
if (aAttr == nsGkAtoms::onbegin)
return nsGkAtoms::onbeginEvent;
if (aAttr == nsGkAtoms::onrepeat)
return nsGkAtoms::onrepeatEvent;
if (aAttr == nsGkAtoms::onend)
return nsGkAtoms::onendEvent;
#endif // MOZ_SMIL
return aAttr;
}

View File

@ -82,7 +82,8 @@ FORCE_STATIC_LIB = 1
include $(topsrcdir)/config/rules.mk
LOCAL_INCLUDES = -I$(srcdir)/../../../base/src \
-I$(srcdir)/../../content/src \
$(NULL)
-I$(srcdir)/../../content/src \
-I$(srcdir)/../../../../layout/xul/base/src/tree/src \
$(NULL)
DEFINES += -D_IMPL_NS_LAYOUT

View File

@ -65,6 +65,7 @@
#include "nsINameSpaceManager.h"
#include "nsIDOMClassInfo.h"
#include "nsWhitespaceTokenizer.h"
#include "nsTreeContentView.h"
// For security check
#include "nsIDocument.h"
@ -467,6 +468,9 @@ nsXULTreeBuilder::GetSelection(nsITreeSelection** aSelection)
NS_IMETHODIMP
nsXULTreeBuilder::SetSelection(nsITreeSelection* aSelection)
{
NS_ENSURE_TRUE(!aSelection ||
nsTreeContentView::CanTrustTreeSelection(aSelection),
NS_ERROR_DOM_SECURITY_ERR);
mSelection = aSelection;
return NS_OK;
}

View File

@ -377,6 +377,7 @@
#include "nsIDOMSVGSetElement.h"
#include "nsIDOMSVGAnimationElement.h"
#include "nsIDOMElementTimeControl.h"
#include "nsIDOMTimeEvent.h"
#endif // MOZ_SMIL
#include "nsIDOMSVGAnimTransformList.h"
#include "nsIDOMSVGCircleElement.h"
@ -1003,6 +1004,8 @@ static nsDOMClassInfoData sClassInfoData[] = {
ELEMENT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(SVGSetElement, nsElementSH,
ELEMENT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(TimeEvent, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
#endif // MOZ_SMIL
NS_DEFINE_CLASSINFO_DATA(SVGCircleElement, nsElementSH,
ELEMENT_SCRIPTABLE_FLAGS)
@ -3040,6 +3043,10 @@ nsDOMClassInfo::Init()
DOM_CLASSINFO_SVG_ELEMENT_MAP_ENTRIES
DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN(TimeEvent, nsIDOMTimeEvent)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMTimeEvent)
DOM_CLASSINFO_EVENT_MAP_ENTRIES
DOM_CLASSINFO_MAP_END
#endif // MOZ_SMIL
DOM_CLASSINFO_MAP_BEGIN(SVGCircleElement, nsIDOMSVGCircleElement)

View File

@ -240,6 +240,7 @@ DOMCI_CLASS(SVGAnimateTransformElement)
DOMCI_CLASS(SVGAnimateMotionElement)
DOMCI_CLASS(SVGMpathElement)
DOMCI_CLASS(SVGSetElement)
DOMCI_CLASS(TimeEvent)
#endif // MOZ_SMIL
DOMCI_CLASS(SVGCircleElement)
DOMCI_CLASS(SVGClipPathElement)

View File

@ -48,6 +48,7 @@ XPIDL_MODULE = dom_smil
XPIDLSRCS = \
nsIDOMElementTimeControl.idl \
nsIDOMTimeEvent.idl \
$(NULL)
include $(topsrcdir)/config/rules.mk

View File

@ -0,0 +1,57 @@
/* -*- 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 the Mozilla SMIL Module.
*
* The Initial Developer of the Original Code is Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Brian Birtles <birtles@gmail.com>
*
* 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 SMIL TimeEvent interface.
*
* For more information please refer to:
* http://www.w3.org/TR/SMIL/smil-timing.html#Events-TimeEvent
* http://www.w3.org/TR/SVG/animate.html#InterfaceTimeEvent
*/
[scriptable, uuid(0d309c26-ddbb-44cb-9af1-3008972349e3)]
interface nsIDOMTimeEvent : nsIDOMEvent
{
readonly attribute long detail;
readonly attribute nsIDOMAbstractView view;
void initTimeEvent(in DOMString typeArg,
in nsIDOMAbstractView viewArg,
in long detailArg);
};

View File

@ -9,6 +9,8 @@ Local patches:
angle-sunstudio.patch - Fix compilation with Sun Studio on Solaris
fix-compile.patch - Remove some trailing commas
To regenerate the flex/yacc generated files:
flex --noline --nounistd --outfile=generated/glslang.cpp src/compiler/glslang.l

View File

@ -0,0 +1,45 @@
# HG changeset patch
# User Robert Sayre <sayrer@gmail.com>
# Date 1280559674 25200
# Node ID bb4a143ee814097076640c37df84ef7f1303b63b
# Parent 9e08308ca8cb9d4584ff990f441f363f3d81bd57
Fix ShaderLang.h bustage. Commas at the end of enum lists.
diff --git a/gfx/angle/include/GLSLANG/ShaderLang.h b/gfx/angle/include/GLSLANG/ShaderLang.h
--- a/gfx/angle/include/GLSLANG/ShaderLang.h
+++ b/gfx/angle/include/GLSLANG/ShaderLang.h
@@ -47,7 +47,7 @@ ANGLE_API int ShFinalize();
typedef enum {
EShLangVertex,
EShLangFragment,
- EShLangCount,
+ EShLangCount
} EShLanguage;
//
@@ -56,7 +56,7 @@ typedef enum {
//
typedef enum {
EShSpecGLES2,
- EShSpecWebGL,
+ EShSpecWebGL
} EShSpec;
//
@@ -66,12 +66,12 @@ typedef enum {
EShOptNoGeneration,
EShOptNone,
EShOptSimple, // Optimizations that can be done quickly
- EShOptFull, // Optimizations that will take more time
+ EShOptFull // Optimizations that will take more time
} EShOptimizationLevel;
enum TDebugOptions {
EDebugOpNone = 0x000,
- EDebugOpIntermediate = 0x001, // Writes intermediate tree into info-log.
+ EDebugOpIntermediate = 0x001 // Writes intermediate tree into info-log.
};
//

View File

@ -693,13 +693,13 @@ static const yytype_uint16 yyrline[] =
1385, 1405, 1434, 1454, 1530, 1540, 1566, 1569, 1575, 1583,
1591, 1599, 1602, 1609, 1612, 1615, 1621, 1624, 1639, 1643,
1647, 1651, 1660, 1665, 1670, 1675, 1680, 1685, 1690, 1695,
1700, 1705, 1711, 1717, 1723, 1728, 1733, 1738, 1751, 1761,
1769, 1772, 1787, 1813, 1817, 1823, 1828, 1841, 1845, 1849,
1850, 1856, 1857, 1858, 1859, 1860, 1864, 1865, 1865, 1865,
1873, 1874, 1879, 1882, 1890, 1893, 1899, 1900, 1904, 1912,
1916, 1926, 1931, 1948, 1948, 1953, 1953, 1960, 1960, 1968,
1971, 1977, 1980, 1986, 1990, 1997, 2004, 2011, 2018, 2029,
2038, 2042, 2049, 2052, 2058, 2058
1700, 1705, 1711, 1717, 1723, 1728, 1733, 1738, 1751, 1764,
1772, 1775, 1790, 1816, 1820, 1826, 1834, 1850, 1854, 1858,
1859, 1865, 1866, 1867, 1868, 1869, 1873, 1874, 1874, 1874,
1882, 1883, 1888, 1891, 1899, 1902, 1908, 1909, 1913, 1921,
1925, 1935, 1940, 1957, 1957, 1962, 1962, 1969, 1969, 1977,
1980, 1986, 1989, 1995, 1999, 2006, 2013, 2020, 2027, 2038,
2047, 2051, 2058, 2061, 2067, 2067
};
#endif
@ -3943,6 +3943,9 @@ yyreduce:
case 138:
{
if (parseContext->reservedErrorCheck((yyvsp[(2) - (5)].lex).line, *(yyvsp[(2) - (5)].lex).string))
parseContext->recover();
TType* structure = new TType((yyvsp[(4) - (5)].interm.typeList), *(yyvsp[(2) - (5)].lex).string);
TVariable* userTypeDef = new TVariable((yyvsp[(2) - (5)].lex).string, *structure, true);
if (! parseContext->symbolTable.insert(*userTypeDef)) {
@ -4031,6 +4034,9 @@ yyreduce:
case 145:
{
if (parseContext->reservedErrorCheck((yyvsp[(1) - (1)].lex).line, *(yyvsp[(1) - (1)].lex).string))
parseContext->recover();
(yyval.interm.typeLine).type = new TType(EbtVoid, EbpUndefined);
(yyval.interm.typeLine).line = (yyvsp[(1) - (1)].lex).line;
(yyval.interm.typeLine).type->setFieldName(*(yyvsp[(1) - (1)].lex).string);
@ -4040,6 +4046,9 @@ yyreduce:
case 146:
{
if (parseContext->reservedErrorCheck((yyvsp[(1) - (4)].lex).line, *(yyvsp[(1) - (4)].lex).string))
parseContext->recover();
(yyval.interm.typeLine).type = new TType(EbtVoid, EbpUndefined);
(yyval.interm.typeLine).line = (yyvsp[(1) - (4)].lex).line;
(yyval.interm.typeLine).type->setFieldName(*(yyvsp[(1) - (4)].lex).string);

View File

@ -152,3 +152,14 @@ interface nsITreeSelection : nsISupports
*/
readonly attribute long shiftSelectPivot;
};
/**
* The following interface is not scriptable and MUST NEVER BE MADE scriptable.
* Native treeselections implement it, and we use this to check whether a
* treeselection is native (and therefore suitable for use by untrusted content).
*/
[uuid(1bd59678-5cb3-4316-b246-31a91b19aabe)]
interface nsINativeTreeSelection : nsITreeSelection
{
[noscript] void ensureNative();
};

View File

@ -428,6 +428,8 @@ protected:
InvalidateRow(aRow + aOrientation);
}
public:
static
already_AddRefed<nsTreeColumn> GetColumnImpl(nsITreeColumn* aUnknownCol) {
if (!aUnknownCol)
return nsnull;
@ -437,6 +439,8 @@ protected:
return col;
}
protected:
// Create a new timer. This method is used to delay various actions like
// opening/closing folders or tree scrolling.
// aID is type of the action, aFunc is the function to be called when

View File

@ -47,6 +47,14 @@
#include "nsIEventStateManager.h"
#include "nsINodeInfo.h"
#include "nsIXULSortService.h"
#include "nsContentUtils.h"
#include "nsTreeBodyFrame.h"
#define NS_ENSURE_NATIVE_COLUMN(_col) \
nsRefPtr<nsTreeColumn> col = nsTreeBodyFrame::GetColumnImpl(_col); \
if (!col) { \
return NS_ERROR_INVALID_ARG; \
}
// A content model view implementation for the tree.
@ -194,9 +202,22 @@ nsTreeContentView::GetSelection(nsITreeSelection** aSelection)
return NS_OK;
}
PRBool
nsTreeContentView::CanTrustTreeSelection(nsISupports* aValue)
{
// Untrusted content is only allowed to specify known-good views
if (nsContentUtils::IsCallerTrustedForWrite())
return PR_TRUE;
nsCOMPtr<nsINativeTreeSelection> nativeTreeSel = do_QueryInterface(aValue);
return nativeTreeSel && NS_SUCCEEDED(nativeTreeSel->EnsureNative());
}
NS_IMETHODIMP
nsTreeContentView::SetSelection(nsITreeSelection* aSelection)
{
NS_ENSURE_TRUE(!aSelection || CanTrustTreeSelection(aSelection),
NS_ERROR_DOM_SECURITY_ERR);
mSelection = aSelection;
if (!mSelection || !mUpdateSelection)
return NS_OK;
@ -247,7 +268,7 @@ nsTreeContentView::GetRowProperties(PRInt32 aIndex, nsISupportsArray* aPropertie
NS_IMETHODIMP
nsTreeContentView::GetCellProperties(PRInt32 aRow, nsITreeColumn* aCol, nsISupportsArray* aProperties)
{
NS_ENSURE_ARG_POINTER(aCol);
NS_ENSURE_NATIVE_COLUMN(aCol);
NS_ENSURE_ARG_POINTER(aProperties);
NS_PRECONDITION(aRow >= 0 && aRow < PRInt32(mRows.Length()), "bad row");
if (aRow < 0 || aRow >= PRInt32(mRows.Length()))
@ -272,7 +293,7 @@ nsTreeContentView::GetCellProperties(PRInt32 aRow, nsITreeColumn* aCol, nsISuppo
NS_IMETHODIMP
nsTreeContentView::GetColumnProperties(nsITreeColumn* aCol, nsISupportsArray* aProperties)
{
NS_ENSURE_ARG_POINTER(aCol);
NS_ENSURE_NATIVE_COLUMN(aCol);
NS_ENSURE_ARG_POINTER(aProperties);
nsCOMPtr<nsIDOMElement> element;
aCol->GetElement(getter_AddRefs(element));
@ -428,7 +449,7 @@ nsTreeContentView::GetLevel(PRInt32 aIndex, PRInt32* _retval)
nsTreeContentView::GetImageSrc(PRInt32 aRow, nsITreeColumn* aCol, nsAString& _retval)
{
_retval.Truncate();
NS_ENSURE_ARG_POINTER(aCol);
NS_ENSURE_NATIVE_COLUMN(aCol);
NS_PRECONDITION(aRow >= 0 && aRow < PRInt32(mRows.Length()), "bad row");
if (aRow < 0 || aRow >= PRInt32(mRows.Length()))
return NS_ERROR_INVALID_ARG;
@ -449,7 +470,7 @@ nsTreeContentView::GetImageSrc(PRInt32 aRow, nsITreeColumn* aCol, nsAString& _re
NS_IMETHODIMP
nsTreeContentView::GetProgressMode(PRInt32 aRow, nsITreeColumn* aCol, PRInt32* _retval)
{
NS_ENSURE_ARG_POINTER(aCol);
NS_ENSURE_NATIVE_COLUMN(aCol);
NS_PRECONDITION(aRow >= 0 && aRow < PRInt32(mRows.Length()), "bad row");
if (aRow < 0 || aRow >= PRInt32(mRows.Length()))
return NS_ERROR_INVALID_ARG;
@ -480,7 +501,7 @@ NS_IMETHODIMP
nsTreeContentView::GetCellValue(PRInt32 aRow, nsITreeColumn* aCol, nsAString& _retval)
{
_retval.Truncate();
NS_ENSURE_ARG_POINTER(aCol);
NS_ENSURE_NATIVE_COLUMN(aCol);
NS_PRECONDITION(aRow >= 0 && aRow < PRInt32(mRows.Length()), "bad row");
if (aRow < 0 || aRow >= PRInt32(mRows.Length()))
return NS_ERROR_INVALID_ARG;
@ -502,7 +523,7 @@ NS_IMETHODIMP
nsTreeContentView::GetCellText(PRInt32 aRow, nsITreeColumn* aCol, nsAString& _retval)
{
_retval.Truncate();
NS_ENSURE_ARG_POINTER(aCol);
NS_ENSURE_NATIVE_COLUMN(aCol);
NS_PRECONDITION(aRow >= 0 && aRow < PRInt32(mRows.Length()), "bad row");
NS_PRECONDITION(aCol, "bad column");
@ -610,7 +631,7 @@ nsTreeContentView::ToggleOpenState(PRInt32 aIndex)
NS_IMETHODIMP
nsTreeContentView::CycleHeader(nsITreeColumn* aCol)
{
NS_ENSURE_ARG_POINTER(aCol);
NS_ENSURE_NATIVE_COLUMN(aCol);
if (!mRoot)
return NS_OK;
@ -665,7 +686,7 @@ NS_IMETHODIMP
nsTreeContentView::IsEditable(PRInt32 aRow, nsITreeColumn* aCol, PRBool* _retval)
{
*_retval = PR_FALSE;
NS_ENSURE_ARG_POINTER(aCol);
NS_ENSURE_NATIVE_COLUMN(aCol);
NS_PRECONDITION(aRow >= 0 && aRow < PRInt32(mRows.Length()), "bad row");
if (aRow < 0 || aRow >= PRInt32(mRows.Length()))
return NS_ERROR_INVALID_ARG;
@ -690,6 +711,7 @@ nsTreeContentView::IsEditable(PRInt32 aRow, nsITreeColumn* aCol, PRBool* _retval
NS_IMETHODIMP
nsTreeContentView::IsSelectable(PRInt32 aRow, nsITreeColumn* aCol, PRBool* _retval)
{
NS_ENSURE_NATIVE_COLUMN(aCol);
NS_PRECONDITION(aRow >= 0 && aRow < PRInt32(mRows.Length()), "bad row");
if (aRow < 0 || aRow >= PRInt32(mRows.Length()))
return NS_ERROR_INVALID_ARG;
@ -714,7 +736,7 @@ nsTreeContentView::IsSelectable(PRInt32 aRow, nsITreeColumn* aCol, PRBool* _retv
NS_IMETHODIMP
nsTreeContentView::SetCellValue(PRInt32 aRow, nsITreeColumn* aCol, const nsAString& aValue)
{
NS_ENSURE_ARG_POINTER(aCol);
NS_ENSURE_NATIVE_COLUMN(aCol);
NS_PRECONDITION(aRow >= 0 && aRow < PRInt32(mRows.Length()), "bad row");
if (aRow < 0 || aRow >= PRInt32(mRows.Length()))
return NS_ERROR_INVALID_ARG;
@ -735,7 +757,7 @@ nsTreeContentView::SetCellValue(PRInt32 aRow, nsITreeColumn* aCol, const nsAStri
NS_IMETHODIMP
nsTreeContentView::SetCellText(PRInt32 aRow, nsITreeColumn* aCol, const nsAString& aValue)
{
NS_ENSURE_ARG_POINTER(aCol);
NS_ENSURE_NATIVE_COLUMN(aCol);
NS_PRECONDITION(aRow >= 0 && aRow < PRInt32(mRows.Length()), "bad row");
if (aRow < 0 || aRow >= PRInt32(mRows.Length()))
return NS_ERROR_INVALID_ARG;

View File

@ -82,6 +82,8 @@ class nsTreeContentView : public nsINativeTreeView,
NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
NS_DECL_NSIMUTATIONOBSERVER_NODEWILLBEDESTROYED
static PRBool CanTrustTreeSelection(nsISupports* aValue);
protected:
// Recursive methods which deal with serializing of nested content.
void Serialize(nsIContent* aContent, PRInt32 aParentIndex, PRInt32* aIndex,

View File

@ -280,6 +280,7 @@ DOMCI_DATA(TreeSelection, nsTreeSelection)
// QueryInterface implementation for nsBoxObject
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsTreeSelection)
NS_INTERFACE_MAP_ENTRY(nsITreeSelection)
NS_INTERFACE_MAP_ENTRY(nsINativeTreeSelection)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(TreeSelection)
NS_INTERFACE_MAP_END

View File

@ -50,7 +50,7 @@
class nsITreeBoxObject;
struct nsTreeRange;
class nsTreeSelection : public nsITreeSelection
class nsTreeSelection : public nsINativeTreeSelection
{
public:
nsTreeSelection(nsITreeBoxObject* aTree);
@ -60,6 +60,9 @@ public:
NS_DECL_CYCLE_COLLECTION_CLASS(nsTreeSelection)
NS_DECL_NSITREESELECTION
// nsINativeTreeSelection: Untrusted code can use us
NS_IMETHOD EnsureNative() { return NS_OK; }
friend struct nsTreeRange;
protected:

View File

@ -48,14 +48,12 @@ _TEST_FILES = imgutils.js \
test_bug399925.html \
bug399925.gif \
schrep.png \
test_bug435296.html \
bug468160.sjs \
test_bug468160.html \
red.png \
test_bug466586.html \
big.png \
blue.png \
test_bug478398.html \
bug478398_ONLY.png \
test_bug490949.html \
bug490949-iframe.html \
@ -75,5 +73,9 @@ _TEST_FILES = imgutils.js \
test_bug553982.html \
$(NULL)
# Tests disabled due to intermittent orange
# test_bug435296.html disabled - See bug 578591
# test_bug478398.html disabled - See bug 579139
libs:: $(_TEST_FILES)
$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)

View File

@ -101,6 +101,9 @@ class nsHashKey;
#define NS_SVG_EVENT 30
#define NS_SVGZOOM_EVENT 31
#endif // MOZ_SVG
#ifdef MOZ_SMIL
#define NS_SMIL_TIME_EVENT 32
#endif // MOZ_SMIL
#define NS_QUERY_CONTENT_EVENT 33
@ -460,6 +463,13 @@ class nsHashKey;
#define NS_TRANSITION_EVENT_START 4200
#define NS_TRANSITION_END (NS_TRANSITION_EVENT_START)
#ifdef MOZ_SMIL
#define NS_SMIL_TIME_EVENT_START 4300
#define NS_SMIL_BEGIN (NS_SMIL_TIME_EVENT_START)
#define NS_SMIL_END (NS_SMIL_TIME_EVENT_START + 1)
#define NS_SMIL_REPEAT (NS_SMIL_TIME_EVENT_START + 2)
#endif // MOZ_SMIL
/**
* Return status for event processors, nsEventStatus, is defined in
* nsEvent.h.

View File

@ -53,9 +53,13 @@ class nsMenuItemIconX;
class nsMenuItemX;
class nsIWidget;
// MenuDelegate is used to receive Cocoa notifications for
// setting up carbon events
// MenuDelegate is used to receive Cocoa notifications for setting
// up carbon events. Protocol is defined as of 10.6 SDK.
#if defined(MAC_OS_X_VERSION_10_6) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6)
@interface MenuDelegate : NSObject < NSMenuDelegate >
#else
@interface MenuDelegate : NSObject
#endif
{
nsMenuX* mGeckoMenu; // weak ref
}

View File

@ -69,9 +69,21 @@ GdkPixbuf*
nsImageToPixbuf::ImageToPixbuf(imgIContainer* aImage)
{
nsRefPtr<gfxImageSurface> frame;
aImage->CopyFrame(imgIContainer::FRAME_CURRENT,
imgIContainer::FLAG_SYNC_DECODE,
getter_AddRefs(frame));
nsresult rv = aImage->CopyFrame(imgIContainer::FRAME_CURRENT,
imgIContainer::FLAG_SYNC_DECODE,
getter_AddRefs(frame));
// If the last call failed, it was probably because our call stack originates
// in an imgIDecoderObserver event, meaning that we're not allowed request
// a sync decode. Presumably the originating event is something sensible like
// OnStopFrame(), so we can just retry the call without a sync decode.
if (NS_FAILED(rv))
aImage->CopyFrame(imgIContainer::FRAME_CURRENT,
imgIContainer::FLAG_NONE,
getter_AddRefs(frame));
if (!frame)
return nsnull;
return ImgSurfaceToPixbuf(frame, frame->Width(), frame->Height());
}