gecko/dom/smil/nsSMILTimeValueSpec.cpp
Robert O'Callahan cc8b720bee Bug 946065. Part 3: Move content/smil to dom/smil. r=Ms2ger
--HG--
rename : content/smil/SMILBoolType.cpp => dom/smil/SMILBoolType.cpp
rename : content/smil/SMILBoolType.h => dom/smil/SMILBoolType.h
rename : content/smil/SMILEnumType.cpp => dom/smil/SMILEnumType.cpp
rename : content/smil/SMILEnumType.h => dom/smil/SMILEnumType.h
rename : content/smil/SMILIntegerType.cpp => dom/smil/SMILIntegerType.cpp
rename : content/smil/SMILIntegerType.h => dom/smil/SMILIntegerType.h
rename : content/smil/SMILStringType.cpp => dom/smil/SMILStringType.cpp
rename : content/smil/SMILStringType.h => dom/smil/SMILStringType.h
rename : content/smil/crashtests/483584-1.svg => dom/smil/crashtests/483584-1.svg
rename : content/smil/crashtests/483584-2.svg => dom/smil/crashtests/483584-2.svg
rename : content/smil/crashtests/523188-1.svg => dom/smil/crashtests/523188-1.svg
rename : content/smil/crashtests/525099-1.svg => dom/smil/crashtests/525099-1.svg
rename : content/smil/crashtests/526536-1.svg => dom/smil/crashtests/526536-1.svg
rename : content/smil/crashtests/526875-1.svg => dom/smil/crashtests/526875-1.svg
rename : content/smil/crashtests/526875-2.svg => dom/smil/crashtests/526875-2.svg
rename : content/smil/crashtests/529387-1-helper.svg => dom/smil/crashtests/529387-1-helper.svg
rename : content/smil/crashtests/529387-1.xhtml => dom/smil/crashtests/529387-1.xhtml
rename : content/smil/crashtests/531550-1.svg => dom/smil/crashtests/531550-1.svg
rename : content/smil/crashtests/537157-1.svg => dom/smil/crashtests/537157-1.svg
rename : content/smil/crashtests/541297-1.svg => dom/smil/crashtests/541297-1.svg
rename : content/smil/crashtests/547333-1.svg => dom/smil/crashtests/547333-1.svg
rename : content/smil/crashtests/548899-1.svg => dom/smil/crashtests/548899-1.svg
rename : content/smil/crashtests/551620-1.svg => dom/smil/crashtests/551620-1.svg
rename : content/smil/crashtests/554141-1.svg => dom/smil/crashtests/554141-1.svg
rename : content/smil/crashtests/554202-1.svg => dom/smil/crashtests/554202-1.svg
rename : content/smil/crashtests/554202-2.svg => dom/smil/crashtests/554202-2.svg
rename : content/smil/crashtests/555026-1.svg => dom/smil/crashtests/555026-1.svg
rename : content/smil/crashtests/556841-1.svg => dom/smil/crashtests/556841-1.svg
rename : content/smil/crashtests/572938-1.svg => dom/smil/crashtests/572938-1.svg
rename : content/smil/crashtests/572938-2.svg => dom/smil/crashtests/572938-2.svg
rename : content/smil/crashtests/572938-3.svg => dom/smil/crashtests/572938-3.svg
rename : content/smil/crashtests/572938-4.svg => dom/smil/crashtests/572938-4.svg
rename : content/smil/crashtests/588287-1.svg => dom/smil/crashtests/588287-1.svg
rename : content/smil/crashtests/588287-2.svg => dom/smil/crashtests/588287-2.svg
rename : content/smil/crashtests/590425-1.html => dom/smil/crashtests/590425-1.html
rename : content/smil/crashtests/592477-1.xhtml => dom/smil/crashtests/592477-1.xhtml
rename : content/smil/crashtests/594653-1.svg => dom/smil/crashtests/594653-1.svg
rename : content/smil/crashtests/596796-1.svg => dom/smil/crashtests/596796-1.svg
rename : content/smil/crashtests/605345-1.svg => dom/smil/crashtests/605345-1.svg
rename : content/smil/crashtests/606101-1.svg => dom/smil/crashtests/606101-1.svg
rename : content/smil/crashtests/608295-1.html => dom/smil/crashtests/608295-1.html
rename : content/smil/crashtests/608549-1.svg => dom/smil/crashtests/608549-1.svg
rename : content/smil/crashtests/611927-1.svg => dom/smil/crashtests/611927-1.svg
rename : content/smil/crashtests/615002-1.svg => dom/smil/crashtests/615002-1.svg
rename : content/smil/crashtests/615872-1.svg => dom/smil/crashtests/615872-1.svg
rename : content/smil/crashtests/641388-1.html => dom/smil/crashtests/641388-1.html
rename : content/smil/crashtests/641388-2.html => dom/smil/crashtests/641388-2.html
rename : content/smil/crashtests/650732-1.svg => dom/smil/crashtests/650732-1.svg
rename : content/smil/crashtests/665334-1.svg => dom/smil/crashtests/665334-1.svg
rename : content/smil/crashtests/669225-1.svg => dom/smil/crashtests/669225-1.svg
rename : content/smil/crashtests/669225-2.svg => dom/smil/crashtests/669225-2.svg
rename : content/smil/crashtests/670313-1.svg => dom/smil/crashtests/670313-1.svg
rename : content/smil/crashtests/678822-1.svg => dom/smil/crashtests/678822-1.svg
rename : content/smil/crashtests/678847-1.svg => dom/smil/crashtests/678847-1.svg
rename : content/smil/crashtests/678938-1.svg => dom/smil/crashtests/678938-1.svg
rename : content/smil/crashtests/690994-1.svg => dom/smil/crashtests/690994-1.svg
rename : content/smil/crashtests/691337-1.svg => dom/smil/crashtests/691337-1.svg
rename : content/smil/crashtests/691337-2.svg => dom/smil/crashtests/691337-2.svg
rename : content/smil/crashtests/697640-1.svg => dom/smil/crashtests/697640-1.svg
rename : content/smil/crashtests/699325-1.svg => dom/smil/crashtests/699325-1.svg
rename : content/smil/crashtests/709907-1.svg => dom/smil/crashtests/709907-1.svg
rename : content/smil/crashtests/720103-1.svg => dom/smil/crashtests/720103-1.svg
rename : content/smil/crashtests/crashtests.list => dom/smil/crashtests/crashtests.list
rename : content/smil/moz.build => dom/smil/moz.build
rename : content/smil/nsDOMTimeEvent.cpp => dom/smil/nsDOMTimeEvent.cpp
rename : content/smil/nsDOMTimeEvent.h => dom/smil/nsDOMTimeEvent.h
rename : content/smil/nsISMILAttr.h => dom/smil/nsISMILAttr.h
rename : content/smil/nsISMILType.h => dom/smil/nsISMILType.h
rename : content/smil/nsSMILAnimationController.cpp => dom/smil/nsSMILAnimationController.cpp
rename : content/smil/nsSMILAnimationController.h => dom/smil/nsSMILAnimationController.h
rename : content/smil/nsSMILAnimationFunction.cpp => dom/smil/nsSMILAnimationFunction.cpp
rename : content/smil/nsSMILAnimationFunction.h => dom/smil/nsSMILAnimationFunction.h
rename : content/smil/nsSMILCSSProperty.cpp => dom/smil/nsSMILCSSProperty.cpp
rename : content/smil/nsSMILCSSProperty.h => dom/smil/nsSMILCSSProperty.h
rename : content/smil/nsSMILCSSValueType.cpp => dom/smil/nsSMILCSSValueType.cpp
rename : content/smil/nsSMILCSSValueType.h => dom/smil/nsSMILCSSValueType.h
rename : content/smil/nsSMILCompositor.cpp => dom/smil/nsSMILCompositor.cpp
rename : content/smil/nsSMILCompositor.h => dom/smil/nsSMILCompositor.h
rename : content/smil/nsSMILCompositorTable.h => dom/smil/nsSMILCompositorTable.h
rename : content/smil/nsSMILFloatType.cpp => dom/smil/nsSMILFloatType.cpp
rename : content/smil/nsSMILFloatType.h => dom/smil/nsSMILFloatType.h
rename : content/smil/nsSMILInstanceTime.cpp => dom/smil/nsSMILInstanceTime.cpp
rename : content/smil/nsSMILInstanceTime.h => dom/smil/nsSMILInstanceTime.h
rename : content/smil/nsSMILInterval.cpp => dom/smil/nsSMILInterval.cpp
rename : content/smil/nsSMILInterval.h => dom/smil/nsSMILInterval.h
rename : content/smil/nsSMILKeySpline.cpp => dom/smil/nsSMILKeySpline.cpp
rename : content/smil/nsSMILKeySpline.h => dom/smil/nsSMILKeySpline.h
rename : content/smil/nsSMILMappedAttribute.cpp => dom/smil/nsSMILMappedAttribute.cpp
rename : content/smil/nsSMILMappedAttribute.h => dom/smil/nsSMILMappedAttribute.h
rename : content/smil/nsSMILMilestone.h => dom/smil/nsSMILMilestone.h
rename : content/smil/nsSMILNullType.cpp => dom/smil/nsSMILNullType.cpp
rename : content/smil/nsSMILNullType.h => dom/smil/nsSMILNullType.h
rename : content/smil/nsSMILParserUtils.cpp => dom/smil/nsSMILParserUtils.cpp
rename : content/smil/nsSMILParserUtils.h => dom/smil/nsSMILParserUtils.h
rename : content/smil/nsSMILRepeatCount.cpp => dom/smil/nsSMILRepeatCount.cpp
rename : content/smil/nsSMILRepeatCount.h => dom/smil/nsSMILRepeatCount.h
rename : content/smil/nsSMILSetAnimationFunction.cpp => dom/smil/nsSMILSetAnimationFunction.cpp
rename : content/smil/nsSMILSetAnimationFunction.h => dom/smil/nsSMILSetAnimationFunction.h
rename : content/smil/nsSMILTargetIdentifier.h => dom/smil/nsSMILTargetIdentifier.h
rename : content/smil/nsSMILTimeContainer.cpp => dom/smil/nsSMILTimeContainer.cpp
rename : content/smil/nsSMILTimeContainer.h => dom/smil/nsSMILTimeContainer.h
rename : content/smil/nsSMILTimeValue.cpp => dom/smil/nsSMILTimeValue.cpp
rename : content/smil/nsSMILTimeValue.h => dom/smil/nsSMILTimeValue.h
rename : content/smil/nsSMILTimeValueSpec.cpp => dom/smil/nsSMILTimeValueSpec.cpp
rename : content/smil/nsSMILTimeValueSpec.h => dom/smil/nsSMILTimeValueSpec.h
rename : content/smil/nsSMILTimeValueSpecParams.h => dom/smil/nsSMILTimeValueSpecParams.h
rename : content/smil/nsSMILTimedElement.cpp => dom/smil/nsSMILTimedElement.cpp
rename : content/smil/nsSMILTimedElement.h => dom/smil/nsSMILTimedElement.h
rename : content/smil/nsSMILTypes.h => dom/smil/nsSMILTypes.h
rename : content/smil/nsSMILValue.cpp => dom/smil/nsSMILValue.cpp
rename : content/smil/nsSMILValue.h => dom/smil/nsSMILValue.h
rename : content/smil/test/db_smilAnimateMotion.js => dom/smil/test/db_smilAnimateMotion.js
rename : content/smil/test/db_smilCSSFromBy.js => dom/smil/test/db_smilCSSFromBy.js
rename : content/smil/test/db_smilCSSFromTo.js => dom/smil/test/db_smilCSSFromTo.js
rename : content/smil/test/db_smilCSSPaced.js => dom/smil/test/db_smilCSSPaced.js
rename : content/smil/test/db_smilCSSPropertyList.js => dom/smil/test/db_smilCSSPropertyList.js
rename : content/smil/test/db_smilMappedAttrList.js => dom/smil/test/db_smilMappedAttrList.js
rename : content/smil/test/mochitest.ini => dom/smil/test/mochitest.ini
rename : content/smil/test/moz.build => dom/smil/test/moz.build
rename : content/smil/test/smilAnimateMotionValueLists.js => dom/smil/test/smilAnimateMotionValueLists.js
rename : content/smil/test/smilExtDoc_helper.svg => dom/smil/test/smilExtDoc_helper.svg
rename : content/smil/test/smilTestUtils.js => dom/smil/test/smilTestUtils.js
rename : content/smil/test/smilXHR_helper.svg => dom/smil/test/smilXHR_helper.svg
rename : content/smil/test/test_smilAccessKey.xhtml => dom/smil/test/test_smilAccessKey.xhtml
rename : content/smil/test/test_smilAnimateMotion.xhtml => dom/smil/test/test_smilAnimateMotion.xhtml
rename : content/smil/test/test_smilAnimateMotionInvalidValues.xhtml => dom/smil/test/test_smilAnimateMotionInvalidValues.xhtml
rename : content/smil/test/test_smilAnimateMotionOverrideRules.xhtml => dom/smil/test/test_smilAnimateMotionOverrideRules.xhtml
rename : content/smil/test/test_smilBackwardsSeeking.xhtml => dom/smil/test/test_smilBackwardsSeeking.xhtml
rename : content/smil/test/test_smilCSSFontStretchRelative.xhtml => dom/smil/test/test_smilCSSFontStretchRelative.xhtml
rename : content/smil/test/test_smilCSSFromBy.xhtml => dom/smil/test/test_smilCSSFromBy.xhtml
rename : content/smil/test/test_smilCSSFromTo.xhtml => dom/smil/test/test_smilCSSFromTo.xhtml
rename : content/smil/test/test_smilCSSInherit.xhtml => dom/smil/test/test_smilCSSInherit.xhtml
rename : content/smil/test/test_smilCSSInvalidValues.xhtml => dom/smil/test/test_smilCSSInvalidValues.xhtml
rename : content/smil/test/test_smilCSSPaced.xhtml => dom/smil/test/test_smilCSSPaced.xhtml
rename : content/smil/test/test_smilChangeAfterFrozen.xhtml => dom/smil/test/test_smilChangeAfterFrozen.xhtml
rename : content/smil/test/test_smilContainerBinding.xhtml => dom/smil/test/test_smilContainerBinding.xhtml
rename : content/smil/test/test_smilCrossContainer.xhtml => dom/smil/test/test_smilCrossContainer.xhtml
rename : content/smil/test/test_smilDynamicDelayedBeginElement.xhtml => dom/smil/test/test_smilDynamicDelayedBeginElement.xhtml
rename : content/smil/test/test_smilExtDoc.xhtml => dom/smil/test/test_smilExtDoc.xhtml
rename : content/smil/test/test_smilFillMode.xhtml => dom/smil/test/test_smilFillMode.xhtml
rename : content/smil/test/test_smilGetSimpleDuration.xhtml => dom/smil/test/test_smilGetSimpleDuration.xhtml
rename : content/smil/test/test_smilGetStartTime.xhtml => dom/smil/test/test_smilGetStartTime.xhtml
rename : content/smil/test/test_smilHyperlinking.xhtml => dom/smil/test/test_smilHyperlinking.xhtml
rename : content/smil/test/test_smilInvalidValues.html => dom/smil/test/test_smilInvalidValues.html
rename : content/smil/test/test_smilKeySplines.xhtml => dom/smil/test/test_smilKeySplines.xhtml
rename : content/smil/test/test_smilKeyTimes.xhtml => dom/smil/test/test_smilKeyTimes.xhtml
rename : content/smil/test/test_smilKeyTimesPacedMode.xhtml => dom/smil/test/test_smilKeyTimesPacedMode.xhtml
rename : content/smil/test/test_smilMappedAttrFromBy.xhtml => dom/smil/test/test_smilMappedAttrFromBy.xhtml
rename : content/smil/test/test_smilMappedAttrFromTo.xhtml => dom/smil/test/test_smilMappedAttrFromTo.xhtml
rename : content/smil/test/test_smilMappedAttrPaced.xhtml => dom/smil/test/test_smilMappedAttrPaced.xhtml
rename : content/smil/test/test_smilMinTiming.html => dom/smil/test/test_smilMinTiming.html
rename : content/smil/test/test_smilRepeatDuration.html => dom/smil/test/test_smilRepeatDuration.html
rename : content/smil/test/test_smilRepeatTiming.xhtml => dom/smil/test/test_smilRepeatTiming.xhtml
rename : content/smil/test/test_smilReset.xhtml => dom/smil/test/test_smilReset.xhtml
rename : content/smil/test/test_smilRestart.xhtml => dom/smil/test/test_smilRestart.xhtml
rename : content/smil/test/test_smilSetCurrentTime.xhtml => dom/smil/test/test_smilSetCurrentTime.xhtml
rename : content/smil/test/test_smilSync.xhtml => dom/smil/test/test_smilSync.xhtml
rename : content/smil/test/test_smilSyncTransform.xhtml => dom/smil/test/test_smilSyncTransform.xhtml
rename : content/smil/test/test_smilSyncbaseTarget.xhtml => dom/smil/test/test_smilSyncbaseTarget.xhtml
rename : content/smil/test/test_smilTextZoom.xhtml => dom/smil/test/test_smilTextZoom.xhtml
rename : content/smil/test/test_smilTimeEvents.xhtml => dom/smil/test/test_smilTimeEvents.xhtml
rename : content/smil/test/test_smilTiming.xhtml => dom/smil/test/test_smilTiming.xhtml
rename : content/smil/test/test_smilTimingZeroIntervals.xhtml => dom/smil/test/test_smilTimingZeroIntervals.xhtml
rename : content/smil/test/test_smilUpdatedInterval.xhtml => dom/smil/test/test_smilUpdatedInterval.xhtml
rename : content/smil/test/test_smilValues.xhtml => dom/smil/test/test_smilValues.xhtml
rename : content/smil/test/test_smilXHR.xhtml => dom/smil/test/test_smilXHR.xhtml
extra : rebase_source : 4038f574b020b79d3725efd91eeef457d9d6a0b0
2014-01-03 14:49:22 +13:00

535 lines
15 KiB
C++

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/dom/SVGAnimationElement.h"
#include "nsSMILTimeValueSpec.h"
#include "nsSMILInterval.h"
#include "nsSMILTimeContainer.h"
#include "nsSMILTimeValue.h"
#include "nsSMILTimedElement.h"
#include "nsSMILInstanceTime.h"
#include "nsSMILParserUtils.h"
#include "nsEventListenerManager.h"
#include "nsIDOMKeyEvent.h"
#include "nsIDOMTimeEvent.h"
#include "nsString.h"
#include <limits>
using namespace mozilla::dom;
//----------------------------------------------------------------------
// Nested class: EventListener
NS_IMPL_ISUPPORTS1(nsSMILTimeValueSpec::EventListener, nsIDOMEventListener)
NS_IMETHODIMP
nsSMILTimeValueSpec::EventListener::HandleEvent(nsIDOMEvent* aEvent)
{
if (mSpec) {
mSpec->HandleEvent(aEvent);
}
return NS_OK;
}
//----------------------------------------------------------------------
// Implementation
nsSMILTimeValueSpec::nsSMILTimeValueSpec(nsSMILTimedElement& aOwner,
bool aIsBegin)
: mOwner(&aOwner),
mIsBegin(aIsBegin),
mReferencedElement(MOZ_THIS_IN_INITIALIZER_LIST())
{
}
nsSMILTimeValueSpec::~nsSMILTimeValueSpec()
{
UnregisterFromReferencedElement(mReferencedElement.get());
if (mEventListener) {
mEventListener->Disconnect();
mEventListener = nullptr;
}
}
nsresult
nsSMILTimeValueSpec::SetSpec(const nsAString& aStringSpec,
Element* aContextNode)
{
nsSMILTimeValueSpecParams params;
if (!nsSMILParserUtils::ParseTimeValueSpecParams(aStringSpec, params))
return NS_ERROR_FAILURE;
mParams = params;
// According to SMIL 3.0:
// The special value "indefinite" does not yield an instance time in the
// begin list. It will, however yield a single instance with the value
// "indefinite" in an end list. This value is not removed by a reset.
if (mParams.mType == nsSMILTimeValueSpecParams::OFFSET ||
(!mIsBegin && mParams.mType == nsSMILTimeValueSpecParams::INDEFINITE)) {
mOwner->AddInstanceTime(new nsSMILInstanceTime(mParams.mOffset), mIsBegin);
}
// Fill in the event symbol to simplify handling later
if (mParams.mType == nsSMILTimeValueSpecParams::REPEAT) {
mParams.mEventSymbol = nsGkAtoms::repeatEvent;
} else if (mParams.mType == nsSMILTimeValueSpecParams::ACCESSKEY) {
mParams.mEventSymbol = nsGkAtoms::keypress;
}
ResolveReferences(aContextNode);
return NS_OK;
}
void
nsSMILTimeValueSpec::ResolveReferences(nsIContent* aContextNode)
{
if (mParams.mType != nsSMILTimeValueSpecParams::SYNCBASE && !IsEventBased())
return;
NS_ABORT_IF_FALSE(aContextNode,
"null context node for resolving timing references against");
// If we're not bound to the document yet, don't worry, we'll get called again
// when that happens
if (!aContextNode->IsInDoc())
return;
// Hold ref to the old element so that it isn't destroyed in between resetting
// the referenced element and using the pointer to update the referenced
// element.
nsRefPtr<Element> oldReferencedElement = mReferencedElement.get();
if (mParams.mDependentElemID) {
mReferencedElement.ResetWithID(aContextNode,
nsDependentAtomString(mParams.mDependentElemID));
} else if (mParams.mType == nsSMILTimeValueSpecParams::EVENT) {
Element* target = mOwner->GetTargetElement();
mReferencedElement.ResetWithElement(target);
} else if (mParams.mType == nsSMILTimeValueSpecParams::ACCESSKEY) {
nsIDocument* doc = aContextNode->GetCurrentDoc();
NS_ABORT_IF_FALSE(doc, "We are in the document but current doc is null");
mReferencedElement.ResetWithElement(doc->GetRootElement());
} else {
NS_ABORT_IF_FALSE(false, "Syncbase or repeat spec without ID");
}
UpdateReferencedElement(oldReferencedElement, mReferencedElement.get());
}
bool
nsSMILTimeValueSpec::IsEventBased() const
{
return mParams.mType == nsSMILTimeValueSpecParams::EVENT ||
mParams.mType == nsSMILTimeValueSpecParams::REPEAT ||
mParams.mType == nsSMILTimeValueSpecParams::ACCESSKEY;
}
void
nsSMILTimeValueSpec::HandleNewInterval(nsSMILInterval& aInterval,
const nsSMILTimeContainer* aSrcContainer)
{
const nsSMILInstanceTime& baseInstance = mParams.mSyncBegin
? *aInterval.Begin() : *aInterval.End();
nsSMILTimeValue newTime =
ConvertBetweenTimeContainers(baseInstance.Time(), aSrcContainer);
// Apply offset
if (!ApplyOffset(newTime)) {
NS_WARNING("New time overflows nsSMILTime, ignoring");
return;
}
// Create the instance time and register it with the interval
nsRefPtr<nsSMILInstanceTime> newInstance =
new nsSMILInstanceTime(newTime, nsSMILInstanceTime::SOURCE_SYNCBASE, this,
&aInterval);
mOwner->AddInstanceTime(newInstance, mIsBegin);
}
void
nsSMILTimeValueSpec::HandleTargetElementChange(Element* aNewTarget)
{
if (!IsEventBased() || mParams.mDependentElemID)
return;
mReferencedElement.ResetWithElement(aNewTarget);
}
void
nsSMILTimeValueSpec::HandleChangedInstanceTime(
const nsSMILInstanceTime& aBaseTime,
const nsSMILTimeContainer* aSrcContainer,
nsSMILInstanceTime& aInstanceTimeToUpdate,
bool aObjectChanged)
{
// If the instance time is fixed (e.g. because it's being used as the begin
// time of an active or postactive interval) we just ignore the change.
if (aInstanceTimeToUpdate.IsFixedTime())
return;
nsSMILTimeValue updatedTime =
ConvertBetweenTimeContainers(aBaseTime.Time(), aSrcContainer);
// Apply offset
if (!ApplyOffset(updatedTime)) {
NS_WARNING("Updated time overflows nsSMILTime, ignoring");
return;
}
// The timed element that owns the instance time does the updating so it can
// re-sort its array of instance times more efficiently
if (aInstanceTimeToUpdate.Time() != updatedTime || aObjectChanged) {
mOwner->UpdateInstanceTime(&aInstanceTimeToUpdate, updatedTime, mIsBegin);
}
}
void
nsSMILTimeValueSpec::HandleDeletedInstanceTime(
nsSMILInstanceTime &aInstanceTime)
{
mOwner->RemoveInstanceTime(&aInstanceTime, mIsBegin);
}
bool
nsSMILTimeValueSpec::DependsOnBegin() const
{
return mParams.mSyncBegin;
}
void
nsSMILTimeValueSpec::Traverse(nsCycleCollectionTraversalCallback* aCallback)
{
mReferencedElement.Traverse(aCallback);
}
void
nsSMILTimeValueSpec::Unlink()
{
UnregisterFromReferencedElement(mReferencedElement.get());
mReferencedElement.Unlink();
}
//----------------------------------------------------------------------
// Implementation helpers
void
nsSMILTimeValueSpec::UpdateReferencedElement(Element* aFrom, Element* aTo)
{
if (aFrom == aTo)
return;
UnregisterFromReferencedElement(aFrom);
switch (mParams.mType)
{
case nsSMILTimeValueSpecParams::SYNCBASE:
{
nsSMILTimedElement* to = GetTimedElement(aTo);
if (to) {
to->AddDependent(*this);
}
}
break;
case nsSMILTimeValueSpecParams::EVENT:
case nsSMILTimeValueSpecParams::REPEAT:
case nsSMILTimeValueSpecParams::ACCESSKEY:
RegisterEventListener(aTo);
break;
default:
// not a referencing-type
break;
}
}
void
nsSMILTimeValueSpec::UnregisterFromReferencedElement(Element* aElement)
{
if (!aElement)
return;
if (mParams.mType == nsSMILTimeValueSpecParams::SYNCBASE) {
nsSMILTimedElement* timedElement = GetTimedElement(aElement);
if (timedElement) {
timedElement->RemoveDependent(*this);
}
mOwner->RemoveInstanceTimesForCreator(this, mIsBegin);
} else if (IsEventBased()) {
UnregisterEventListener(aElement);
}
}
nsSMILTimedElement*
nsSMILTimeValueSpec::GetTimedElement(Element* aElement)
{
return aElement && aElement->IsNodeOfType(nsINode::eANIMATION) ?
&static_cast<SVGAnimationElement*>(aElement)->TimedElement() : nullptr;
}
// Indicates whether we're allowed to register an event-listener
// when scripting is disabled.
bool
nsSMILTimeValueSpec::IsWhitelistedEvent()
{
// The category of (SMIL-specific) "repeat(n)" events are allowed.
if (mParams.mType == nsSMILTimeValueSpecParams::REPEAT) {
return true;
}
// A specific list of other SMIL-related events are allowed, too.
if (mParams.mType == nsSMILTimeValueSpecParams::EVENT &&
(mParams.mEventSymbol == nsGkAtoms::repeat ||
mParams.mEventSymbol == nsGkAtoms::repeatEvent ||
mParams.mEventSymbol == nsGkAtoms::beginEvent ||
mParams.mEventSymbol == nsGkAtoms::endEvent)) {
return true;
}
return false;
}
void
nsSMILTimeValueSpec::RegisterEventListener(Element* aTarget)
{
NS_ABORT_IF_FALSE(IsEventBased(),
"Attempting to register event-listener for unexpected nsSMILTimeValueSpec"
" type");
NS_ABORT_IF_FALSE(mParams.mEventSymbol,
"Attempting to register event-listener but there is no event name");
if (!aTarget)
return;
// When script is disabled, only allow registration for whitelisted events.
if (!aTarget->GetOwnerDocument()->IsScriptEnabled() &&
!IsWhitelistedEvent()) {
return;
}
if (!mEventListener) {
mEventListener = new EventListener(this);
}
nsEventListenerManager* elm = GetEventListenerManager(aTarget);
if (!elm)
return;
elm->AddEventListenerByType(mEventListener,
nsDependentAtomString(mParams.mEventSymbol),
AllEventsAtSystemGroupBubble());
}
void
nsSMILTimeValueSpec::UnregisterEventListener(Element* aTarget)
{
if (!aTarget || !mEventListener)
return;
nsEventListenerManager* elm = GetEventListenerManager(aTarget);
if (!elm)
return;
elm->RemoveEventListenerByType(mEventListener,
nsDependentAtomString(mParams.mEventSymbol),
AllEventsAtSystemGroupBubble());
}
nsEventListenerManager*
nsSMILTimeValueSpec::GetEventListenerManager(Element* aTarget)
{
NS_ABORT_IF_FALSE(aTarget, "null target; can't get EventListenerManager");
nsCOMPtr<EventTarget> target;
if (mParams.mType == nsSMILTimeValueSpecParams::ACCESSKEY) {
nsIDocument* doc = aTarget->GetCurrentDoc();
if (!doc)
return nullptr;
nsPIDOMWindow* win = doc->GetWindow();
if (!win)
return nullptr;
target = do_QueryInterface(win);
} else {
target = aTarget;
}
if (!target)
return nullptr;
return target->GetOrCreateListenerManager();
}
void
nsSMILTimeValueSpec::HandleEvent(nsIDOMEvent* aEvent)
{
NS_ABORT_IF_FALSE(mEventListener, "Got event without an event listener");
NS_ABORT_IF_FALSE(IsEventBased(),
"Got event for non-event nsSMILTimeValueSpec");
NS_ABORT_IF_FALSE(aEvent, "No event supplied");
// XXX In the long run we should get the time from the event itself which will
// store the time in global document time which we'll need to convert to our
// time container
nsSMILTimeContainer* container = mOwner->GetTimeContainer();
if (!container)
return;
if (!CheckEventDetail(aEvent))
return;
nsSMILTime currentTime = container->GetCurrentTime();
nsSMILTimeValue newTime(currentTime);
if (!ApplyOffset(newTime)) {
NS_WARNING("New time generated from event overflows nsSMILTime, ignoring");
return;
}
nsRefPtr<nsSMILInstanceTime> newInstance =
new nsSMILInstanceTime(newTime, nsSMILInstanceTime::SOURCE_EVENT);
mOwner->AddInstanceTime(newInstance, mIsBegin);
}
bool
nsSMILTimeValueSpec::CheckEventDetail(nsIDOMEvent *aEvent)
{
switch (mParams.mType)
{
case nsSMILTimeValueSpecParams::REPEAT:
return CheckRepeatEventDetail(aEvent);
case nsSMILTimeValueSpecParams::ACCESSKEY:
return CheckAccessKeyEventDetail(aEvent);
default:
// nothing to check
return true;
}
}
bool
nsSMILTimeValueSpec::CheckRepeatEventDetail(nsIDOMEvent *aEvent)
{
nsCOMPtr<nsIDOMTimeEvent> timeEvent = do_QueryInterface(aEvent);
if (!timeEvent) {
NS_WARNING("Received a repeat event that was not a DOMTimeEvent");
return false;
}
int32_t detail;
timeEvent->GetDetail(&detail);
return detail > 0 && (uint32_t)detail == mParams.mRepeatIterationOrAccessKey;
}
bool
nsSMILTimeValueSpec::CheckAccessKeyEventDetail(nsIDOMEvent *aEvent)
{
nsCOMPtr<nsIDOMKeyEvent> keyEvent = do_QueryInterface(aEvent);
if (!keyEvent) {
NS_WARNING("Received an accesskey event that was not a DOMKeyEvent");
return false;
}
// Ignore the key event if any modifier keys are pressed UNLESS we're matching
// on the charCode in which case we ignore the state of the shift and alt keys
// since they might be needed to generate the character in question.
bool isCtrl;
bool isMeta;
keyEvent->GetCtrlKey(&isCtrl);
keyEvent->GetMetaKey(&isMeta);
if (isCtrl || isMeta)
return false;
uint32_t code;
keyEvent->GetCharCode(&code);
if (code)
return code == mParams.mRepeatIterationOrAccessKey;
// Only match on the keyCode if it corresponds to some ASCII character that
// does not produce a charCode.
// In this case we can safely bail out if either alt or shift is pressed since
// they won't already be incorporated into the keyCode unlike the charCode.
bool isAlt;
bool isShift;
keyEvent->GetAltKey(&isAlt);
keyEvent->GetShiftKey(&isShift);
if (isAlt || isShift)
return false;
keyEvent->GetKeyCode(&code);
switch (code)
{
case nsIDOMKeyEvent::DOM_VK_BACK_SPACE:
return mParams.mRepeatIterationOrAccessKey == 0x08;
case nsIDOMKeyEvent::DOM_VK_RETURN:
case nsIDOMKeyEvent::DOM_VK_ENTER:
return mParams.mRepeatIterationOrAccessKey == 0x0A ||
mParams.mRepeatIterationOrAccessKey == 0x0D;
case nsIDOMKeyEvent::DOM_VK_ESCAPE:
return mParams.mRepeatIterationOrAccessKey == 0x1B;
case nsIDOMKeyEvent::DOM_VK_DELETE:
return mParams.mRepeatIterationOrAccessKey == 0x7F;
default:
return false;
}
}
nsSMILTimeValue
nsSMILTimeValueSpec::ConvertBetweenTimeContainers(
const nsSMILTimeValue& aSrcTime,
const nsSMILTimeContainer* aSrcContainer)
{
// If the source time is either indefinite or unresolved the result is going
// to be the same
if (!aSrcTime.IsDefinite())
return aSrcTime;
// Convert from source time container to our parent time container
const nsSMILTimeContainer* dstContainer = mOwner->GetTimeContainer();
if (dstContainer == aSrcContainer)
return aSrcTime;
// If one of the elements is not attached to a time container then we can't do
// any meaningful conversion
if (!aSrcContainer || !dstContainer)
return nsSMILTimeValue(); // unresolved
nsSMILTimeValue docTime =
aSrcContainer->ContainerToParentTime(aSrcTime.GetMillis());
if (docTime.IsIndefinite())
// This will happen if the source container is paused and we have a future
// time. Just return the indefinite time.
return docTime;
NS_ABORT_IF_FALSE(docTime.IsDefinite(),
"ContainerToParentTime gave us an unresolved or indefinite time");
return dstContainer->ParentToContainerTime(docTime.GetMillis());
}
bool
nsSMILTimeValueSpec::ApplyOffset(nsSMILTimeValue& aTime) const
{
// indefinite + offset = indefinite. Likewise for unresolved times.
if (!aTime.IsDefinite()) {
return true;
}
double resultAsDouble =
(double)aTime.GetMillis() + mParams.mOffset.GetMillis();
if (resultAsDouble > std::numeric_limits<nsSMILTime>::max() ||
resultAsDouble < std::numeric_limits<nsSMILTime>::min()) {
return false;
}
aTime.SetMillis(aTime.GetMillis() + mParams.mOffset.GetMillis());
return true;
}