LCOV - code coverage report
Current view: top level - dom/svg - SVGFragmentIdentifier.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 29 88 33.0 %
Date: 2017-07-14 16:53:18 Functions: 6 10 60.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 "SVGFragmentIdentifier.h"
       8             : 
       9             : #include "mozilla/dom/SVGSVGElement.h"
      10             : #include "mozilla/dom/SVGViewElement.h"
      11             : #include "nsContentUtils.h" // for nsCharSeparatedTokenizerTemplate
      12             : #include "nsSVGAnimatedTransformList.h"
      13             : #include "nsCharSeparatedTokenizer.h"
      14             : 
      15             : namespace mozilla {
      16             : 
      17             : using namespace dom;
      18             : 
      19             : static bool
      20           2 : IsMatchingParameter(const nsAString& aString, const nsAString& aParameterName)
      21             : {
      22             :   // The first two tests ensure aString.Length() > aParameterName.Length()
      23             :   // so it's then safe to do the third test
      24           2 :   return StringBeginsWith(aString, aParameterName) &&
      25           2 :          aString.Last() == ')' &&
      26           2 :          aString.CharAt(aParameterName.Length()) == '(';
      27             : }
      28             : 
      29             : inline bool
      30           0 : IgnoreWhitespace(char16_t aChar)
      31             : {
      32           0 :   return false;
      33             : }
      34             : 
      35             : static SVGViewElement*
      36           2 : GetViewElement(nsIDocument* aDocument, const nsAString& aId)
      37             : {
      38           2 :   Element* element = aDocument->GetElementById(aId);
      39           2 :   return (element && element->IsSVGElement(nsGkAtoms::view)) ?
      40           2 :             static_cast<SVGViewElement*>(element) : nullptr;
      41             : }
      42             : 
      43             : // Handles setting/clearing the root's mSVGView pointer.
      44             : class MOZ_RAII AutoSVGViewHandler
      45             : {
      46             : public:
      47           2 :   explicit AutoSVGViewHandler(SVGSVGElement* aRoot
      48             :                               MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
      49           2 :     : mRoot(aRoot), mValid(false) {
      50           2 :     MOZ_GUARD_OBJECT_NOTIFIER_INIT;
      51           2 :     mWasOverridden = mRoot->UseCurrentView();
      52           2 :     mRoot->mSVGView = nullptr;
      53           2 :     mRoot->mCurrentViewID = nullptr;
      54           2 :   }
      55             : 
      56           4 :   ~AutoSVGViewHandler() {
      57           2 :     if (!mWasOverridden && !mValid) {
      58             :       // we weren't overridden before and we aren't
      59             :       // overridden now so nothing has changed.
      60           2 :       return;
      61             :     }
      62           0 :     if (mValid) {
      63           0 :       mRoot->mSVGView = mSVGView;
      64             :     }
      65           0 :     mRoot->InvalidateTransformNotifyFrame();
      66           2 :   }
      67             : 
      68           0 :   void CreateSVGView() {
      69           0 :     MOZ_ASSERT(!mSVGView, "CreateSVGView should not be called multiple times");
      70           0 :     mSVGView = new SVGView();
      71           0 :   }
      72             : 
      73           0 :   bool ProcessAttr(const nsAString& aToken, const nsAString &aParams) {
      74             : 
      75           0 :     MOZ_ASSERT(mSVGView, "CreateSVGView should have been called");
      76             : 
      77             :     // SVGViewAttributes may occur in any order, but each type may only occur
      78             :     // at most one time in a correctly formed SVGViewSpec.
      79             :     // If we encounter any attribute more than once or get any syntax errors
      80             :     // we're going to return false and cancel any changes.
      81             : 
      82           0 :     if (IsMatchingParameter(aToken, NS_LITERAL_STRING("viewBox"))) {
      83           0 :       if (mSVGView->mViewBox.IsExplicitlySet() ||
      84           0 :           NS_FAILED(mSVGView->mViewBox.SetBaseValueString(
      85             :                       aParams, mRoot, false))) {
      86           0 :         return false;
      87             :       }
      88           0 :     } else if (IsMatchingParameter(aToken, NS_LITERAL_STRING("preserveAspectRatio"))) {
      89           0 :       if (mSVGView->mPreserveAspectRatio.IsExplicitlySet() ||
      90           0 :           NS_FAILED(mSVGView->mPreserveAspectRatio.SetBaseValueString(
      91             :                       aParams, mRoot, false))) {
      92           0 :         return false;
      93             :       }
      94           0 :     } else if (IsMatchingParameter(aToken, NS_LITERAL_STRING("transform"))) {
      95           0 :       if (mSVGView->mTransforms) {
      96           0 :         return false;
      97             :       }
      98           0 :       mSVGView->mTransforms = new nsSVGAnimatedTransformList();
      99           0 :       if (NS_FAILED(mSVGView->mTransforms->SetBaseValueString(aParams))) {
     100           0 :         return false;
     101             :       }
     102           0 :     } else if (IsMatchingParameter(aToken, NS_LITERAL_STRING("zoomAndPan"))) {
     103           0 :       if (mSVGView->mZoomAndPan.IsExplicitlySet()) {
     104           0 :         return false;
     105             :       }
     106           0 :       nsIAtom* valAtom = NS_GetStaticAtom(aParams);
     107           0 :       if (!valAtom ||
     108           0 :           NS_FAILED(mSVGView->mZoomAndPan.SetBaseValueAtom(
     109             :                       valAtom, mRoot))) {
     110           0 :         return false;
     111             :       }
     112             :     } else {
     113             :       // We don't support viewTarget currently
     114           0 :       return false;
     115             :     }
     116           0 :     return true;
     117             :   }
     118             : 
     119           0 :   void SetValid() {
     120           0 :     mValid = true;
     121           0 :   }
     122             : 
     123             : private:
     124             :   SVGSVGElement*     mRoot;
     125             :   nsAutoPtr<SVGView> mSVGView;
     126             :   bool               mValid;
     127             :   bool               mWasOverridden;
     128             :   MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
     129             : };
     130             : 
     131             : bool
     132           2 : SVGFragmentIdentifier::ProcessSVGViewSpec(const nsAString& aViewSpec,
     133             :                                           SVGSVGElement* aRoot)
     134             : {
     135           4 :   AutoSVGViewHandler viewHandler(aRoot);
     136             : 
     137           2 :   if (!IsMatchingParameter(aViewSpec, NS_LITERAL_STRING("svgView"))) {
     138           2 :     return false;
     139             :   }
     140             : 
     141             :   // Each token is a SVGViewAttribute
     142           0 :   int32_t bracketPos = aViewSpec.FindChar('(');
     143           0 :   uint32_t lengthOfViewSpec = aViewSpec.Length() - bracketPos - 2;
     144             :   nsCharSeparatedTokenizerTemplate<IgnoreWhitespace> tokenizer(
     145           0 :     Substring(aViewSpec, bracketPos + 1, lengthOfViewSpec), ';');
     146             : 
     147           0 :   if (!tokenizer.hasMoreTokens()) {
     148           0 :     return false;
     149             :   }
     150           0 :   viewHandler.CreateSVGView();
     151             : 
     152           0 :   do {
     153             : 
     154           0 :     nsAutoString token(tokenizer.nextToken());
     155             : 
     156           0 :     bracketPos = token.FindChar('(');
     157           0 :     if (bracketPos < 1 || token.Last() != ')') {
     158             :       // invalid SVGViewAttribute syntax
     159           0 :       return false;
     160             :     }
     161             : 
     162             :     const nsAString &params =
     163           0 :       Substring(token, bracketPos + 1, token.Length() - bracketPos - 2);
     164             : 
     165           0 :     if (!viewHandler.ProcessAttr(token, params)) {
     166           0 :       return false;
     167             :     }
     168             : 
     169             :   } while (tokenizer.hasMoreTokens());
     170             : 
     171           0 :   viewHandler.SetValid();
     172           0 :   return true;
     173             : }
     174             : 
     175             : bool
     176           2 : SVGFragmentIdentifier::ProcessFragmentIdentifier(nsIDocument* aDocument,
     177             :                                                  const nsAString& aAnchorName)
     178             : {
     179           2 :   MOZ_ASSERT(aDocument->GetRootElement()->IsSVGElement(nsGkAtoms::svg),
     180             :              "expecting an SVG root element");
     181             : 
     182             :   SVGSVGElement* rootElement =
     183           2 :     static_cast<SVGSVGElement*>(aDocument->GetRootElement());
     184             : 
     185           2 :   const SVGViewElement* viewElement = GetViewElement(aDocument, aAnchorName);
     186             : 
     187           2 :   if (viewElement) {
     188           0 :     if (!rootElement->mCurrentViewID) {
     189           0 :       rootElement->mCurrentViewID = new nsString();
     190             :     }
     191           0 :     *rootElement->mCurrentViewID = aAnchorName;
     192           0 :     rootElement->mSVGView = nullptr;
     193           0 :     rootElement->InvalidateTransformNotifyFrame();
     194             :     // not an svgView()-style fragment identifier, return false so the caller
     195             :     // continues processing to match any :target pseudo elements
     196           0 :     return false;
     197             :   }
     198             : 
     199           2 :   return ProcessSVGViewSpec(aAnchorName, rootElement);
     200             : }
     201             : 
     202             : } // namespace mozilla

Generated by: LCOV version 1.13