LCOV - code coverage report
Current view: top level - dom/smil - nsSMILTimeValueSpec.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 233 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 29 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "mozilla/EventListenerManager.h"
       8             : #include "mozilla/dom/SVGAnimationElement.h"
       9             : #include "nsSMILTimeValueSpec.h"
      10             : #include "nsSMILInterval.h"
      11             : #include "nsSMILTimeContainer.h"
      12             : #include "nsSMILTimeValue.h"
      13             : #include "nsSMILTimedElement.h"
      14             : #include "nsSMILInstanceTime.h"
      15             : #include "nsSMILParserUtils.h"
      16             : #include "nsIDOMKeyEvent.h"
      17             : #include "nsIDOMTimeEvent.h"
      18             : #include "nsString.h"
      19             : #include <limits>
      20             : 
      21             : using namespace mozilla;
      22             : using namespace mozilla::dom;
      23             : 
      24             : //----------------------------------------------------------------------
      25             : // Nested class: EventListener
      26             : 
      27           0 : NS_IMPL_ISUPPORTS(nsSMILTimeValueSpec::EventListener, nsIDOMEventListener)
      28             : 
      29             : NS_IMETHODIMP
      30           0 : nsSMILTimeValueSpec::EventListener::HandleEvent(nsIDOMEvent* aEvent)
      31             : {
      32           0 :   if (mSpec) {
      33           0 :     mSpec->HandleEvent(aEvent);
      34             :   }
      35           0 :   return NS_OK;
      36             : }
      37             : 
      38             : //----------------------------------------------------------------------
      39             : // Implementation
      40             : 
      41           0 : nsSMILTimeValueSpec::nsSMILTimeValueSpec(nsSMILTimedElement& aOwner,
      42           0 :                                          bool aIsBegin)
      43             :   : mOwner(&aOwner),
      44             :     mIsBegin(aIsBegin),
      45           0 :     mReferencedElement(this)
      46             : {
      47           0 : }
      48             : 
      49           0 : nsSMILTimeValueSpec::~nsSMILTimeValueSpec()
      50             : {
      51           0 :   UnregisterFromReferencedElement(mReferencedElement.get());
      52           0 :   if (mEventListener) {
      53           0 :     mEventListener->Disconnect();
      54           0 :     mEventListener = nullptr;
      55             :   }
      56           0 : }
      57             : 
      58             : nsresult
      59           0 : nsSMILTimeValueSpec::SetSpec(const nsAString& aStringSpec,
      60             :                              Element* aContextNode)
      61             : {
      62           0 :   nsSMILTimeValueSpecParams params;
      63             : 
      64           0 :   if (!nsSMILParserUtils::ParseTimeValueSpecParams(aStringSpec, params))
      65           0 :     return NS_ERROR_FAILURE;
      66             : 
      67           0 :   mParams = params;
      68             : 
      69             :   // According to SMIL 3.0:
      70             :   //   The special value "indefinite" does not yield an instance time in the
      71             :   //   begin list. It will, however yield a single instance with the value
      72             :   //   "indefinite" in an end list. This value is not removed by a reset.
      73           0 :   if (mParams.mType == nsSMILTimeValueSpecParams::OFFSET ||
      74           0 :       (!mIsBegin && mParams.mType == nsSMILTimeValueSpecParams::INDEFINITE)) {
      75           0 :     mOwner->AddInstanceTime(new nsSMILInstanceTime(mParams.mOffset), mIsBegin);
      76             :   }
      77             : 
      78             :   // Fill in the event symbol to simplify handling later
      79           0 :   if (mParams.mType == nsSMILTimeValueSpecParams::REPEAT) {
      80           0 :     mParams.mEventSymbol = nsGkAtoms::repeatEvent;
      81           0 :   } else if (mParams.mType == nsSMILTimeValueSpecParams::ACCESSKEY) {
      82           0 :     mParams.mEventSymbol = nsGkAtoms::keypress;
      83             :   }
      84             : 
      85           0 :   ResolveReferences(aContextNode);
      86             : 
      87           0 :   return NS_OK;
      88             : }
      89             : 
      90             : void
      91           0 : nsSMILTimeValueSpec::ResolveReferences(nsIContent* aContextNode)
      92             : {
      93           0 :   if (mParams.mType != nsSMILTimeValueSpecParams::SYNCBASE && !IsEventBased())
      94           0 :     return;
      95             : 
      96           0 :   MOZ_ASSERT(aContextNode,
      97             :              "null context node for resolving timing references against");
      98             : 
      99             :   // If we're not bound to the document yet, don't worry, we'll get called again
     100             :   // when that happens
     101           0 :   if (!aContextNode->IsInUncomposedDoc())
     102           0 :     return;
     103             : 
     104             :   // Hold ref to the old element so that it isn't destroyed in between resetting
     105             :   // the referenced element and using the pointer to update the referenced
     106             :   // element.
     107           0 :   RefPtr<Element> oldReferencedElement = mReferencedElement.get();
     108             : 
     109           0 :   if (mParams.mDependentElemID) {
     110           0 :     mReferencedElement.ResetWithID(aContextNode,
     111           0 :         nsDependentAtomString(mParams.mDependentElemID));
     112           0 :   } else if (mParams.mType == nsSMILTimeValueSpecParams::EVENT) {
     113           0 :     Element* target = mOwner->GetTargetElement();
     114           0 :     mReferencedElement.ResetWithElement(target);
     115           0 :   } else if (mParams.mType == nsSMILTimeValueSpecParams::ACCESSKEY) {
     116           0 :     nsIDocument* doc = aContextNode->GetUncomposedDoc();
     117           0 :     MOZ_ASSERT(doc, "We are in the document but current doc is null");
     118           0 :     mReferencedElement.ResetWithElement(doc->GetRootElement());
     119             :   } else {
     120           0 :     MOZ_ASSERT(false, "Syncbase or repeat spec without ID");
     121             :   }
     122           0 :   UpdateReferencedElement(oldReferencedElement, mReferencedElement.get());
     123             : }
     124             : 
     125             : bool
     126           0 : nsSMILTimeValueSpec::IsEventBased() const
     127             : {
     128           0 :   return mParams.mType == nsSMILTimeValueSpecParams::EVENT ||
     129           0 :          mParams.mType == nsSMILTimeValueSpecParams::REPEAT ||
     130           0 :          mParams.mType == nsSMILTimeValueSpecParams::ACCESSKEY;
     131             : }
     132             : 
     133             : void
     134           0 : nsSMILTimeValueSpec::HandleNewInterval(nsSMILInterval& aInterval,
     135             :                                        const nsSMILTimeContainer* aSrcContainer)
     136             : {
     137           0 :   const nsSMILInstanceTime& baseInstance = mParams.mSyncBegin
     138           0 :     ? *aInterval.Begin() : *aInterval.End();
     139             :   nsSMILTimeValue newTime =
     140           0 :     ConvertBetweenTimeContainers(baseInstance.Time(), aSrcContainer);
     141             : 
     142             :   // Apply offset
     143           0 :   if (!ApplyOffset(newTime)) {
     144           0 :     NS_WARNING("New time overflows nsSMILTime, ignoring");
     145           0 :     return;
     146             :   }
     147             : 
     148             :   // Create the instance time and register it with the interval
     149             :   RefPtr<nsSMILInstanceTime> newInstance =
     150             :     new nsSMILInstanceTime(newTime, nsSMILInstanceTime::SOURCE_SYNCBASE, this,
     151           0 :                            &aInterval);
     152           0 :   mOwner->AddInstanceTime(newInstance, mIsBegin);
     153             : }
     154             : 
     155             : void
     156           0 : nsSMILTimeValueSpec::HandleTargetElementChange(Element* aNewTarget)
     157             : {
     158           0 :   if (!IsEventBased() || mParams.mDependentElemID)
     159           0 :     return;
     160             : 
     161           0 :   mReferencedElement.ResetWithElement(aNewTarget);
     162             : }
     163             : 
     164             : void
     165           0 : nsSMILTimeValueSpec::HandleChangedInstanceTime(
     166             :     const nsSMILInstanceTime& aBaseTime,
     167             :     const nsSMILTimeContainer* aSrcContainer,
     168             :     nsSMILInstanceTime& aInstanceTimeToUpdate,
     169             :     bool aObjectChanged)
     170             : {
     171             :   // If the instance time is fixed (e.g. because it's being used as the begin
     172             :   // time of an active or postactive interval) we just ignore the change.
     173           0 :   if (aInstanceTimeToUpdate.IsFixedTime())
     174           0 :     return;
     175             : 
     176             :   nsSMILTimeValue updatedTime =
     177           0 :     ConvertBetweenTimeContainers(aBaseTime.Time(), aSrcContainer);
     178             : 
     179             :   // Apply offset
     180           0 :   if (!ApplyOffset(updatedTime)) {
     181           0 :     NS_WARNING("Updated time overflows nsSMILTime, ignoring");
     182           0 :     return;
     183             :   }
     184             : 
     185             :   // The timed element that owns the instance time does the updating so it can
     186             :   // re-sort its array of instance times more efficiently
     187           0 :   if (aInstanceTimeToUpdate.Time() != updatedTime || aObjectChanged) {
     188           0 :     mOwner->UpdateInstanceTime(&aInstanceTimeToUpdate, updatedTime, mIsBegin);
     189             :   }
     190             : }
     191             : 
     192             : void
     193           0 : nsSMILTimeValueSpec::HandleDeletedInstanceTime(
     194             :     nsSMILInstanceTime &aInstanceTime)
     195             : {
     196           0 :   mOwner->RemoveInstanceTime(&aInstanceTime, mIsBegin);
     197           0 : }
     198             : 
     199             : bool
     200           0 : nsSMILTimeValueSpec::DependsOnBegin() const
     201             : {
     202           0 :   return mParams.mSyncBegin;
     203             : }
     204             : 
     205             : void
     206           0 : nsSMILTimeValueSpec::Traverse(nsCycleCollectionTraversalCallback* aCallback)
     207             : {
     208           0 :   mReferencedElement.Traverse(aCallback);
     209           0 : }
     210             : 
     211             : void
     212           0 : nsSMILTimeValueSpec::Unlink()
     213             : {
     214           0 :   UnregisterFromReferencedElement(mReferencedElement.get());
     215           0 :   mReferencedElement.Unlink();
     216           0 : }
     217             : 
     218             : //----------------------------------------------------------------------
     219             : // Implementation helpers
     220             : 
     221             : void
     222           0 : nsSMILTimeValueSpec::UpdateReferencedElement(Element* aFrom, Element* aTo)
     223             : {
     224           0 :   if (aFrom == aTo)
     225           0 :     return;
     226             : 
     227           0 :   UnregisterFromReferencedElement(aFrom);
     228             : 
     229           0 :   switch (mParams.mType)
     230             :   {
     231             :   case nsSMILTimeValueSpecParams::SYNCBASE:
     232             :     {
     233           0 :       nsSMILTimedElement* to = GetTimedElement(aTo);
     234           0 :       if (to) {
     235           0 :         to->AddDependent(*this);
     236             :       }
     237             :     }
     238           0 :     break;
     239             : 
     240             :   case nsSMILTimeValueSpecParams::EVENT:
     241             :   case nsSMILTimeValueSpecParams::REPEAT:
     242             :   case nsSMILTimeValueSpecParams::ACCESSKEY:
     243           0 :     RegisterEventListener(aTo);
     244           0 :     break;
     245             : 
     246             :   default:
     247             :     // not a referencing-type
     248           0 :     break;
     249             :   }
     250             : }
     251             : 
     252             : void
     253           0 : nsSMILTimeValueSpec::UnregisterFromReferencedElement(Element* aElement)
     254             : {
     255           0 :   if (!aElement)
     256           0 :     return;
     257             : 
     258           0 :   if (mParams.mType == nsSMILTimeValueSpecParams::SYNCBASE) {
     259           0 :     nsSMILTimedElement* timedElement = GetTimedElement(aElement);
     260           0 :     if (timedElement) {
     261           0 :       timedElement->RemoveDependent(*this);
     262             :     }
     263           0 :     mOwner->RemoveInstanceTimesForCreator(this, mIsBegin);
     264           0 :   } else if (IsEventBased()) {
     265           0 :     UnregisterEventListener(aElement);
     266             :   }
     267             : }
     268             : 
     269             : nsSMILTimedElement*
     270           0 : nsSMILTimeValueSpec::GetTimedElement(Element* aElement)
     271             : {
     272           0 :   return aElement && aElement->IsNodeOfType(nsINode::eANIMATION) ?
     273           0 :     &static_cast<SVGAnimationElement*>(aElement)->TimedElement() : nullptr;
     274             : }
     275             : 
     276             : // Indicates whether we're allowed to register an event-listener
     277             : // when scripting is disabled.
     278             : bool
     279           0 : nsSMILTimeValueSpec::IsWhitelistedEvent()
     280             : {
     281             :   // The category of (SMIL-specific) "repeat(n)" events are allowed.
     282           0 :   if (mParams.mType == nsSMILTimeValueSpecParams::REPEAT) {
     283           0 :     return true;
     284             :   }
     285             : 
     286             :   // A specific list of other SMIL-related events are allowed, too.
     287           0 :   if (mParams.mType == nsSMILTimeValueSpecParams::EVENT &&
     288           0 :       (mParams.mEventSymbol == nsGkAtoms::repeat ||
     289           0 :        mParams.mEventSymbol == nsGkAtoms::repeatEvent ||
     290           0 :        mParams.mEventSymbol == nsGkAtoms::beginEvent ||
     291           0 :        mParams.mEventSymbol == nsGkAtoms::endEvent)) {
     292           0 :     return true;
     293             :   }
     294             : 
     295           0 :   return false;
     296             : }
     297             : 
     298             : void
     299           0 : nsSMILTimeValueSpec::RegisterEventListener(Element* aTarget)
     300             : {
     301           0 :   MOZ_ASSERT(IsEventBased(),
     302             :              "Attempting to register event-listener for unexpected "
     303             :              "nsSMILTimeValueSpec type");
     304           0 :   MOZ_ASSERT(mParams.mEventSymbol,
     305             :              "Attempting to register event-listener but there is no event "
     306             :              "name");
     307             : 
     308           0 :   if (!aTarget)
     309           0 :     return;
     310             : 
     311             :   // When script is disabled, only allow registration for whitelisted events.
     312           0 :   if (!aTarget->GetOwnerDocument()->IsScriptEnabled() &&
     313           0 :       !IsWhitelistedEvent()) {
     314           0 :     return;
     315             :   }
     316             : 
     317           0 :   if (!mEventListener) {
     318           0 :     mEventListener = new EventListener(this);
     319             :   }
     320             : 
     321           0 :   EventListenerManager* elm = GetEventListenerManager(aTarget);
     322           0 :   if (!elm)
     323           0 :     return;
     324             : 
     325             :   elm->AddEventListenerByType(mEventListener,
     326           0 :                               nsDependentAtomString(mParams.mEventSymbol),
     327           0 :                               AllEventsAtSystemGroupBubble());
     328             : }
     329             : 
     330             : void
     331           0 : nsSMILTimeValueSpec::UnregisterEventListener(Element* aTarget)
     332             : {
     333           0 :   if (!aTarget || !mEventListener)
     334           0 :     return;
     335             : 
     336           0 :   EventListenerManager* elm = GetEventListenerManager(aTarget);
     337           0 :   if (!elm)
     338           0 :     return;
     339             : 
     340             :   elm->RemoveEventListenerByType(mEventListener,
     341           0 :                                  nsDependentAtomString(mParams.mEventSymbol),
     342           0 :                                  AllEventsAtSystemGroupBubble());
     343             : }
     344             : 
     345             : EventListenerManager*
     346           0 : nsSMILTimeValueSpec::GetEventListenerManager(Element* aTarget)
     347             : {
     348           0 :   MOZ_ASSERT(aTarget, "null target; can't get EventListenerManager");
     349             : 
     350           0 :   nsCOMPtr<EventTarget> target;
     351             : 
     352           0 :   if (mParams.mType == nsSMILTimeValueSpecParams::ACCESSKEY) {
     353           0 :     nsIDocument* doc = aTarget->GetUncomposedDoc();
     354           0 :     if (!doc)
     355           0 :       return nullptr;
     356           0 :     nsPIDOMWindowOuter* win = doc->GetWindow();
     357           0 :     if (!win)
     358           0 :       return nullptr;
     359           0 :     target = do_QueryInterface(win);
     360             :   } else {
     361           0 :     target = aTarget;
     362             :   }
     363           0 :   if (!target)
     364           0 :     return nullptr;
     365             : 
     366           0 :   return target->GetOrCreateListenerManager();
     367             : }
     368             : 
     369             : void
     370           0 : nsSMILTimeValueSpec::HandleEvent(nsIDOMEvent* aEvent)
     371             : {
     372           0 :   MOZ_ASSERT(mEventListener, "Got event without an event listener");
     373           0 :   MOZ_ASSERT(IsEventBased(),
     374             :              "Got event for non-event nsSMILTimeValueSpec");
     375           0 :   MOZ_ASSERT(aEvent, "No event supplied");
     376             : 
     377             :   // XXX In the long run we should get the time from the event itself which will
     378             :   // store the time in global document time which we'll need to convert to our
     379             :   // time container
     380           0 :   nsSMILTimeContainer* container = mOwner->GetTimeContainer();
     381           0 :   if (!container)
     382           0 :     return;
     383             : 
     384           0 :   if (!CheckEventDetail(aEvent))
     385           0 :     return;
     386             : 
     387           0 :   nsSMILTime currentTime = container->GetCurrentTime();
     388           0 :   nsSMILTimeValue newTime(currentTime);
     389           0 :   if (!ApplyOffset(newTime)) {
     390           0 :     NS_WARNING("New time generated from event overflows nsSMILTime, ignoring");
     391           0 :     return;
     392             :   }
     393             : 
     394             :   RefPtr<nsSMILInstanceTime> newInstance =
     395           0 :     new nsSMILInstanceTime(newTime, nsSMILInstanceTime::SOURCE_EVENT);
     396           0 :   mOwner->AddInstanceTime(newInstance, mIsBegin);
     397             : }
     398             : 
     399             : bool
     400           0 : nsSMILTimeValueSpec::CheckEventDetail(nsIDOMEvent *aEvent)
     401             : {
     402           0 :   switch (mParams.mType)
     403             :   {
     404             :   case nsSMILTimeValueSpecParams::REPEAT:
     405           0 :     return CheckRepeatEventDetail(aEvent);
     406             : 
     407             :   case nsSMILTimeValueSpecParams::ACCESSKEY:
     408           0 :     return CheckAccessKeyEventDetail(aEvent);
     409             : 
     410             :   default:
     411             :     // nothing to check
     412           0 :     return true;
     413             :   }
     414             : }
     415             : 
     416             : bool
     417           0 : nsSMILTimeValueSpec::CheckRepeatEventDetail(nsIDOMEvent *aEvent)
     418             : {
     419           0 :   nsCOMPtr<nsIDOMTimeEvent> timeEvent = do_QueryInterface(aEvent);
     420           0 :   if (!timeEvent) {
     421           0 :     NS_WARNING("Received a repeat event that was not a DOMTimeEvent");
     422           0 :     return false;
     423             :   }
     424             : 
     425             :   int32_t detail;
     426           0 :   timeEvent->GetDetail(&detail);
     427           0 :   return detail > 0 && (uint32_t)detail == mParams.mRepeatIterationOrAccessKey;
     428             : }
     429             : 
     430             : bool
     431           0 : nsSMILTimeValueSpec::CheckAccessKeyEventDetail(nsIDOMEvent *aEvent)
     432             : {
     433           0 :   nsCOMPtr<nsIDOMKeyEvent> keyEvent = do_QueryInterface(aEvent);
     434           0 :   if (!keyEvent) {
     435           0 :     NS_WARNING("Received an accesskey event that was not a DOMKeyEvent");
     436           0 :     return false;
     437             :   }
     438             : 
     439             :   // Ignore the key event if any modifier keys are pressed UNLESS we're matching
     440             :   // on the charCode in which case we ignore the state of the shift and alt keys
     441             :   // since they might be needed to generate the character in question.
     442             :   bool isCtrl;
     443             :   bool isMeta;
     444           0 :   keyEvent->GetCtrlKey(&isCtrl);
     445           0 :   keyEvent->GetMetaKey(&isMeta);
     446           0 :   if (isCtrl || isMeta)
     447           0 :     return false;
     448             : 
     449             :   uint32_t code;
     450           0 :   keyEvent->GetCharCode(&code);
     451           0 :   if (code)
     452           0 :     return code == mParams.mRepeatIterationOrAccessKey;
     453             : 
     454             :   // Only match on the keyCode if it corresponds to some ASCII character that
     455             :   // does not produce a charCode.
     456             :   // In this case we can safely bail out if either alt or shift is pressed since
     457             :   // they won't already be incorporated into the keyCode unlike the charCode.
     458             :   bool isAlt;
     459             :   bool isShift;
     460           0 :   keyEvent->GetAltKey(&isAlt);
     461           0 :   keyEvent->GetShiftKey(&isShift);
     462           0 :   if (isAlt || isShift)
     463           0 :     return false;
     464             : 
     465           0 :   keyEvent->GetKeyCode(&code);
     466           0 :   switch (code)
     467             :   {
     468             :   case nsIDOMKeyEvent::DOM_VK_BACK_SPACE:
     469           0 :     return mParams.mRepeatIterationOrAccessKey == 0x08;
     470             : 
     471             :   case nsIDOMKeyEvent::DOM_VK_RETURN:
     472           0 :     return mParams.mRepeatIterationOrAccessKey == 0x0A ||
     473           0 :            mParams.mRepeatIterationOrAccessKey == 0x0D;
     474             : 
     475             :   case nsIDOMKeyEvent::DOM_VK_ESCAPE:
     476           0 :     return mParams.mRepeatIterationOrAccessKey == 0x1B;
     477             : 
     478             :   case nsIDOMKeyEvent::DOM_VK_DELETE:
     479           0 :     return mParams.mRepeatIterationOrAccessKey == 0x7F;
     480             : 
     481             :   default:
     482           0 :     return false;
     483             :   }
     484             : }
     485             : 
     486             : nsSMILTimeValue
     487           0 : nsSMILTimeValueSpec::ConvertBetweenTimeContainers(
     488             :     const nsSMILTimeValue& aSrcTime,
     489             :     const nsSMILTimeContainer* aSrcContainer)
     490             : {
     491             :   // If the source time is either indefinite or unresolved the result is going
     492             :   // to be the same
     493           0 :   if (!aSrcTime.IsDefinite())
     494           0 :     return aSrcTime;
     495             : 
     496             :   // Convert from source time container to our parent time container
     497           0 :   const nsSMILTimeContainer* dstContainer = mOwner->GetTimeContainer();
     498           0 :   if (dstContainer == aSrcContainer)
     499           0 :     return aSrcTime;
     500             : 
     501             :   // If one of the elements is not attached to a time container then we can't do
     502             :   // any meaningful conversion
     503           0 :   if (!aSrcContainer || !dstContainer)
     504           0 :     return nsSMILTimeValue(); // unresolved
     505             : 
     506             :   nsSMILTimeValue docTime =
     507           0 :     aSrcContainer->ContainerToParentTime(aSrcTime.GetMillis());
     508             : 
     509           0 :   if (docTime.IsIndefinite())
     510             :     // This will happen if the source container is paused and we have a future
     511             :     // time. Just return the indefinite time.
     512           0 :     return docTime;
     513             : 
     514           0 :   MOZ_ASSERT(docTime.IsDefinite(),
     515             :              "ContainerToParentTime gave us an unresolved or indefinite time");
     516             : 
     517           0 :   return dstContainer->ParentToContainerTime(docTime.GetMillis());
     518             : }
     519             : 
     520             : bool
     521           0 : nsSMILTimeValueSpec::ApplyOffset(nsSMILTimeValue& aTime) const
     522             : {
     523             :   // indefinite + offset = indefinite. Likewise for unresolved times.
     524           0 :   if (!aTime.IsDefinite()) {
     525           0 :     return true;
     526             :   }
     527             : 
     528             :   double resultAsDouble =
     529           0 :     (double)aTime.GetMillis() + mParams.mOffset.GetMillis();
     530           0 :   if (resultAsDouble > std::numeric_limits<nsSMILTime>::max() ||
     531           0 :       resultAsDouble < std::numeric_limits<nsSMILTime>::min()) {
     532           0 :     return false;
     533             :   }
     534           0 :   aTime.SetMillis(aTime.GetMillis() + mParams.mOffset.GetMillis());
     535           0 :   return true;
     536             : }

Generated by: LCOV version 1.13