LCOV - code coverage report
Current view: top level - dom/svg - SVGAnimationElement.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 1 195 0.5 %
Date: 2017-07-14 16:53:18 Functions: 2 35 5.7 %
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/dom/SVGAnimationElement.h"
       8             : #include "mozilla/dom/SVGSVGElement.h"
       9             : #include "nsSMILTimeContainer.h"
      10             : #include "nsSMILAnimationController.h"
      11             : #include "nsSMILAnimationFunction.h"
      12             : #include "nsContentUtils.h"
      13             : #include "nsIContentInlines.h"
      14             : #include "nsIURI.h"
      15             : #include "prtime.h"
      16             : 
      17             : namespace mozilla {
      18             : namespace dom {
      19             : 
      20             : //----------------------------------------------------------------------
      21             : // nsISupports methods
      22             : 
      23           0 : NS_IMPL_ADDREF_INHERITED(SVGAnimationElement, SVGAnimationElementBase)
      24           0 : NS_IMPL_RELEASE_INHERITED(SVGAnimationElement, SVGAnimationElementBase)
      25             : 
      26           0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(SVGAnimationElement)
      27           0 :   NS_INTERFACE_MAP_ENTRY(mozilla::dom::SVGTests)
      28           0 : NS_INTERFACE_MAP_END_INHERITING(SVGAnimationElementBase)
      29             : 
      30           0 : NS_IMPL_CYCLE_COLLECTION_INHERITED(SVGAnimationElement,
      31             :                                    SVGAnimationElementBase,
      32             :                                    mHrefTarget, mTimedElement)
      33             : 
      34             : //----------------------------------------------------------------------
      35             : // Implementation
      36             : 
      37           0 : SVGAnimationElement::SVGAnimationElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
      38             :   : SVGAnimationElementBase(aNodeInfo),
      39           0 :     mHrefTarget(this)
      40             : {
      41           0 : }
      42             : 
      43           0 : SVGAnimationElement::~SVGAnimationElement()
      44             : {
      45           0 : }
      46             : 
      47             : nsresult
      48           0 : SVGAnimationElement::Init()
      49             : {
      50           0 :   nsresult rv = SVGAnimationElementBase::Init();
      51           0 :   NS_ENSURE_SUCCESS(rv, rv);
      52             : 
      53           0 :   mTimedElement.SetAnimationElement(this);
      54           0 :   AnimationFunction().SetAnimationElement(this);
      55           0 :   mTimedElement.SetTimeClient(&AnimationFunction());
      56             : 
      57           0 :   return NS_OK;
      58             : }
      59             : 
      60             : //----------------------------------------------------------------------
      61             : 
      62             : const nsAttrValue*
      63           0 : SVGAnimationElement::GetAnimAttr(nsIAtom* aName) const
      64             : {
      65           0 :   return mAttrsAndChildren.GetAttr(aName, kNameSpaceID_None);
      66             : }
      67             : 
      68             : bool
      69           0 : SVGAnimationElement::GetAnimAttr(nsIAtom* aAttName,
      70             :                                  nsAString& aResult) const
      71             : {
      72           0 :   return GetAttr(kNameSpaceID_None, aAttName, aResult);
      73             : }
      74             : 
      75             : bool
      76           0 : SVGAnimationElement::HasAnimAttr(nsIAtom* aAttName) const
      77             : {
      78           0 :   return HasAttr(kNameSpaceID_None, aAttName);
      79             : }
      80             : 
      81             : Element*
      82           0 : SVGAnimationElement::GetTargetElementContent()
      83             : {
      84           0 :   if (HasAttr(kNameSpaceID_XLink, nsGkAtoms::href) ||
      85           0 :       HasAttr(kNameSpaceID_None, nsGkAtoms::href)) {
      86           0 :     return mHrefTarget.get();
      87             :   }
      88           0 :   MOZ_ASSERT(!mHrefTarget.get(),
      89             :              "We shouldn't have a href target "
      90             :              "if we don't have an xlink:href or href attribute");
      91             : 
      92             :   // No "href" or "xlink:href" attribute --> I should target my parent.
      93           0 :   nsIContent* parent = GetFlattenedTreeParent();
      94           0 :   return parent && parent->IsElement() ? parent->AsElement() : nullptr;
      95             : }
      96             : 
      97             : bool
      98           0 : SVGAnimationElement::GetTargetAttributeName(int32_t *aNamespaceID,
      99             :                                             nsIAtom **aLocalName) const
     100             : {
     101             :   const nsAttrValue* nameAttr
     102           0 :     = mAttrsAndChildren.GetAttr(nsGkAtoms::attributeName);
     103             : 
     104           0 :   if (!nameAttr)
     105           0 :     return false;
     106             : 
     107           0 :   NS_ASSERTION(nameAttr->Type() == nsAttrValue::eAtom,
     108             :     "attributeName should have been parsed as an atom");
     109             : 
     110           0 :   return NS_SUCCEEDED(nsContentUtils::SplitQName(
     111             :                         this, nsDependentAtomString(nameAttr->GetAtomValue()),
     112             :                         aNamespaceID, aLocalName));
     113             : }
     114             : 
     115             : nsSMILTimedElement&
     116           0 : SVGAnimationElement::TimedElement()
     117             : {
     118           0 :   return mTimedElement;
     119             : }
     120             : 
     121             : nsSVGElement*
     122           0 : SVGAnimationElement::GetTargetElement()
     123             : {
     124           0 :   FlushAnimations();
     125             : 
     126             :   // We'll just call the other GetTargetElement method, and QI to the right type
     127           0 :   nsIContent* target = GetTargetElementContent();
     128             : 
     129           0 :   return (target && target->IsSVGElement())
     130           0 :            ? static_cast<nsSVGElement*>(target) : nullptr;
     131             : }
     132             : 
     133             : float
     134           0 : SVGAnimationElement::GetStartTime(ErrorResult& rv)
     135             : {
     136           0 :   FlushAnimations();
     137             : 
     138           0 :   nsSMILTimeValue startTime = mTimedElement.GetStartTime();
     139           0 :   if (!startTime.IsDefinite()) {
     140           0 :     rv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     141           0 :     return 0.f;
     142             :   }
     143             : 
     144           0 :   return float(double(startTime.GetMillis()) / PR_MSEC_PER_SEC);
     145             : }
     146             : 
     147             : float
     148           0 : SVGAnimationElement::GetCurrentTime()
     149             : {
     150             :   // Not necessary to call FlushAnimations() for this
     151             : 
     152           0 :   nsSMILTimeContainer* root = GetTimeContainer();
     153           0 :   if (root) {
     154           0 :     return float(double(root->GetCurrentTime()) / PR_MSEC_PER_SEC);
     155             :   }
     156             : 
     157           0 :   return 0.0f;
     158             : }
     159             : 
     160             : float
     161           0 : SVGAnimationElement::GetSimpleDuration(ErrorResult& rv)
     162             : {
     163             :   // Not necessary to call FlushAnimations() for this
     164             : 
     165           0 :   nsSMILTimeValue simpleDur = mTimedElement.GetSimpleDuration();
     166           0 :   if (!simpleDur.IsDefinite()) {
     167           0 :     rv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
     168           0 :     return 0.f;
     169             :   }
     170             : 
     171           0 :   return float(double(simpleDur.GetMillis()) / PR_MSEC_PER_SEC);
     172             : }
     173             : 
     174             : //----------------------------------------------------------------------
     175             : // nsIContent methods
     176             : 
     177             : nsresult
     178           0 : SVGAnimationElement::BindToTree(nsIDocument* aDocument,
     179             :                                 nsIContent* aParent,
     180             :                                 nsIContent* aBindingParent,
     181             :                                 bool aCompileEventHandlers)
     182             : {
     183           0 :   MOZ_ASSERT(!mHrefTarget.get(),
     184             :              "Shouldn't have href-target yet (or it should've been cleared)");
     185           0 :   nsresult rv = SVGAnimationElementBase::BindToTree(aDocument, aParent,
     186             :                                                     aBindingParent,
     187           0 :                                                     aCompileEventHandlers);
     188           0 :   NS_ENSURE_SUCCESS(rv,rv);
     189             : 
     190             :   // XXXdholbert is GetCtx (as a check for SVG parent) still needed here?
     191           0 :   if (!GetCtx()) {
     192             :     // No use proceeding. We don't have an SVG parent (yet) so we won't be able
     193             :     // to register ourselves etc. Maybe next time we'll have more luck.
     194             :     // (This sort of situation will arise a lot when trees are being constructed
     195             :     // piece by piece via script)
     196           0 :     return NS_OK;
     197             :   }
     198             : 
     199             :   // Add myself to the animation controller's master set of animation elements.
     200           0 :   if (aDocument) {
     201           0 :     nsSMILAnimationController *controller = aDocument->GetAnimationController();
     202           0 :     if (controller) {
     203           0 :       controller->RegisterAnimationElement(this);
     204             :     }
     205             :     const nsAttrValue* href =
     206           0 :       HasAttr(kNameSpaceID_None, nsGkAtoms::href)
     207           0 :       ? mAttrsAndChildren.GetAttr(nsGkAtoms::href, kNameSpaceID_None)
     208           0 :       : mAttrsAndChildren.GetAttr(nsGkAtoms::href, kNameSpaceID_XLink);
     209           0 :     if (href) {
     210           0 :       nsAutoString hrefStr;
     211           0 :       href->ToString(hrefStr);
     212             : 
     213             :       // Pass in |aParent| instead of |this| -- first argument is only used
     214             :       // for a call to GetComposedDoc(), and |this| might not have a current
     215             :       // document yet.
     216           0 :       UpdateHrefTarget(aParent, hrefStr);
     217             :     }
     218             : 
     219           0 :     mTimedElement.BindToTree(aParent);
     220             :   }
     221             : 
     222           0 :   AnimationNeedsResample();
     223             : 
     224           0 :   return NS_OK;
     225             : }
     226             : 
     227             : void
     228           0 : SVGAnimationElement::UnbindFromTree(bool aDeep, bool aNullParent)
     229             : {
     230           0 :   nsSMILAnimationController *controller = OwnerDoc()->GetAnimationController();
     231           0 :   if (controller) {
     232           0 :     controller->UnregisterAnimationElement(this);
     233             :   }
     234             : 
     235           0 :   mHrefTarget.Unlink();
     236           0 :   mTimedElement.DissolveReferences();
     237             : 
     238           0 :   AnimationNeedsResample();
     239             : 
     240           0 :   SVGAnimationElementBase::UnbindFromTree(aDeep, aNullParent);
     241           0 : }
     242             : 
     243             : bool
     244           0 : SVGAnimationElement::ParseAttribute(int32_t aNamespaceID,
     245             :                                     nsIAtom* aAttribute,
     246             :                                     const nsAString& aValue,
     247             :                                     nsAttrValue& aResult)
     248             : {
     249           0 :   if (aNamespaceID == kNameSpaceID_None) {
     250             :     // Deal with target-related attributes here
     251           0 :     if (aAttribute == nsGkAtoms::attributeName) {
     252           0 :       aResult.ParseAtom(aValue);
     253           0 :       AnimationNeedsResample();
     254           0 :       return true;
     255             :     }
     256             : 
     257           0 :     nsresult rv = NS_ERROR_FAILURE;
     258             : 
     259             :     // First let the animation function try to parse it...
     260             :     bool foundMatch =
     261           0 :       AnimationFunction().SetAttr(aAttribute, aValue, aResult, &rv);
     262             : 
     263             :     // ... and if that didn't recognize the attribute, let the timed element
     264             :     // try to parse it.
     265           0 :     if (!foundMatch) {
     266             :       foundMatch =
     267           0 :         mTimedElement.SetAttr(aAttribute, aValue, aResult, this, &rv);
     268             :     }
     269             : 
     270           0 :     if (foundMatch) {
     271           0 :       AnimationNeedsResample();
     272           0 :       if (NS_FAILED(rv)) {
     273           0 :         ReportAttributeParseFailure(OwnerDoc(), aAttribute, aValue);
     274           0 :         return false;
     275             :       }
     276           0 :       return true;
     277             :     }
     278             :   }
     279             : 
     280           0 :   return SVGAnimationElementBase::ParseAttribute(aNamespaceID, aAttribute,
     281           0 :                                                  aValue, aResult);
     282             : }
     283             : 
     284             : nsresult
     285           0 : SVGAnimationElement::AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
     286             :                                   const nsAttrValue* aValue,
     287             :                                   const nsAttrValue* aOldValue, bool aNotify)
     288             : {
     289             :   nsresult rv =
     290           0 :     SVGAnimationElementBase::AfterSetAttr(aNamespaceID, aName, aValue,
     291           0 :                                           aOldValue, aNotify);
     292             : 
     293           0 :   if (SVGTests::IsConditionalProcessingAttribute(aName)) {
     294           0 :     bool isDisabled = !SVGTests::PassesConditionalProcessingTests();
     295           0 :     if (mTimedElement.SetIsDisabled(isDisabled)) {
     296           0 :       AnimationNeedsResample();
     297             :     }
     298             :   }
     299             : 
     300           0 :   if (!((aNamespaceID == kNameSpaceID_None ||
     301             :          aNamespaceID == kNameSpaceID_XLink) &&
     302           0 :         aName == nsGkAtoms::href)) {
     303           0 :     return rv;
     304             :   }
     305             : 
     306           0 :   if (!aValue) {
     307           0 :     if (aNamespaceID == kNameSpaceID_None) {
     308           0 :       mHrefTarget.Unlink();
     309           0 :       AnimationTargetChanged();
     310             : 
     311             :       // After unsetting href, we may still have xlink:href, so we
     312             :       // should try to add it back.
     313             :       const nsAttrValue* xlinkHref =
     314           0 :         mAttrsAndChildren.GetAttr(nsGkAtoms::href, kNameSpaceID_XLink);
     315           0 :       if (xlinkHref) {
     316           0 :         UpdateHrefTarget(this, xlinkHref->GetStringValue());
     317             :       }
     318           0 :     } else if (!HasAttr(kNameSpaceID_None, nsGkAtoms::href)) {
     319           0 :       mHrefTarget.Unlink();
     320           0 :       AnimationTargetChanged();
     321             :     } // else: we unset xlink:href, but we still have href attribute, so keep
     322             :       // mHrefTarget linking to href.
     323           0 :   } else if (IsInUncomposedDoc() &&
     324           0 :              !(aNamespaceID == kNameSpaceID_XLink &&
     325           0 :                HasAttr(kNameSpaceID_None, nsGkAtoms::href))) {
     326             :     // Note: "href" takes priority over xlink:href. So if "xlink:href" is being
     327             :     // set here, we only let that update our target if "href" is *unset*.
     328           0 :     MOZ_ASSERT(aValue->Type() == nsAttrValue::eString,
     329             :                "Expected href attribute to be string type");
     330           0 :     UpdateHrefTarget(this, aValue->GetStringValue());
     331             :   } // else: we're not yet in a document -- we'll update the target on
     332             :     // next BindToTree call.
     333             : 
     334           0 :   return rv;
     335             : }
     336             : 
     337             : nsresult
     338           0 : SVGAnimationElement::UnsetAttr(int32_t aNamespaceID,
     339             :                                nsIAtom* aAttribute, bool aNotify)
     340             : {
     341           0 :   nsresult rv = SVGAnimationElementBase::UnsetAttr(aNamespaceID, aAttribute,
     342           0 :                                                    aNotify);
     343           0 :   NS_ENSURE_SUCCESS(rv,rv);
     344             : 
     345           0 :   if (aNamespaceID == kNameSpaceID_None) {
     346           0 :     if (AnimationFunction().UnsetAttr(aAttribute) ||
     347           0 :         mTimedElement.UnsetAttr(aAttribute)) {
     348           0 :       AnimationNeedsResample();
     349             :     }
     350             :   }
     351             : 
     352           0 :   return NS_OK;
     353             : }
     354             : 
     355             : bool
     356           0 : SVGAnimationElement::IsNodeOfType(uint32_t aFlags) const
     357             : {
     358           0 :   return !(aFlags & ~(eCONTENT | eANIMATION));
     359             : }
     360             : 
     361             : //----------------------------------------------------------------------
     362             : // SVGTests methods
     363             : 
     364             : bool
     365           0 : SVGAnimationElement::IsInChromeDoc() const
     366             : {
     367           0 :   return nsContentUtils::IsChromeDoc(OwnerDoc());
     368             : }
     369             : 
     370             : //----------------------------------------------------------------------
     371             : // SVG utility methods
     372             : 
     373             : void
     374           0 : SVGAnimationElement::ActivateByHyperlink()
     375             : {
     376           0 :   FlushAnimations();
     377             : 
     378             :   // The behavior for when the target is an animation element is defined in
     379             :   // SMIL Animation:
     380             :   //   http://www.w3.org/TR/smil-animation/#HyperlinkSemantics
     381           0 :   nsSMILTimeValue seekTime = mTimedElement.GetHyperlinkTime();
     382           0 :   if (seekTime.IsDefinite()) {
     383           0 :     nsSMILTimeContainer* timeContainer = GetTimeContainer();
     384           0 :     if (timeContainer) {
     385           0 :       timeContainer->SetCurrentTime(seekTime.GetMillis());
     386           0 :       AnimationNeedsResample();
     387             :       // As with SVGSVGElement::SetCurrentTime, we need to trigger
     388             :       // a synchronous sample now.
     389           0 :       FlushAnimations();
     390             :     }
     391             :     // else, silently fail. We mustn't be part of an SVG document fragment that
     392             :     // is attached to the document tree so there's nothing we can do here
     393             :   } else {
     394           0 :     IgnoredErrorResult rv;
     395           0 :     BeginElement(rv);
     396             :   }
     397           0 : }
     398             : 
     399             : //----------------------------------------------------------------------
     400             : // Implementation helpers
     401             : 
     402             : nsSMILTimeContainer*
     403           0 : SVGAnimationElement::GetTimeContainer()
     404             : {
     405           0 :   SVGSVGElement *element = SVGContentUtils::GetOuterSVGElement(this);
     406             : 
     407           0 :   if (element) {
     408           0 :     return element->GetTimedDocumentRoot();
     409             :   }
     410             : 
     411           0 :   return nullptr;
     412             : }
     413             : 
     414             : void
     415           0 : SVGAnimationElement::BeginElementAt(float offset, ErrorResult& rv)
     416             : {
     417             :   // Make sure the timegraph is up-to-date
     418           0 :   FlushAnimations();
     419             : 
     420             :   // This will fail if we're not attached to a time container (SVG document
     421             :   // fragment).
     422           0 :   rv = mTimedElement.BeginElementAt(offset);
     423           0 :   if (rv.Failed())
     424           0 :     return;
     425             : 
     426           0 :   AnimationNeedsResample();
     427             :   // Force synchronous sample so that events resulting from this call arrive in
     428             :   // the expected order and we get an up-to-date paint.
     429           0 :   FlushAnimations();
     430             : }
     431             : 
     432             : void
     433           0 : SVGAnimationElement::EndElementAt(float offset, ErrorResult& rv)
     434             : {
     435             :   // Make sure the timegraph is up-to-date
     436           0 :   FlushAnimations();
     437             : 
     438           0 :   rv = mTimedElement.EndElementAt(offset);
     439           0 :   if (rv.Failed())
     440           0 :     return;
     441             : 
     442           0 :   AnimationNeedsResample();
     443             :   // Force synchronous sample
     444           0 :   FlushAnimations();
     445             : }
     446             : 
     447             : bool
     448           0 : SVGAnimationElement::IsEventAttributeNameInternal(nsIAtom* aName)
     449             : {
     450           0 :   return nsContentUtils::IsEventAttributeName(aName, EventNameType_SMIL);
     451             : }
     452             : 
     453             : void
     454           0 : SVGAnimationElement::UpdateHrefTarget(nsIContent* aNodeForContext,
     455             :                                       const nsAString& aHrefStr)
     456             : {
     457           0 :   nsCOMPtr<nsIURI> targetURI;
     458           0 :   nsCOMPtr<nsIURI> baseURI = GetBaseURI();
     459           0 :   nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(targetURI),
     460           0 :                                             aHrefStr, OwnerDoc(), baseURI);
     461           0 :   mHrefTarget.Reset(aNodeForContext, targetURI);
     462           0 :   AnimationTargetChanged();
     463           0 : }
     464             : 
     465             : void
     466           0 : SVGAnimationElement::AnimationTargetChanged()
     467             : {
     468           0 :   mTimedElement.HandleTargetElementChange(GetTargetElementContent());
     469           0 :   AnimationNeedsResample();
     470           0 : }
     471             : 
     472             : } // namespace dom
     473           9 : } // namespace mozilla

Generated by: LCOV version 1.13