LCOV - code coverage report
Current view: top level - dom/svg - nsSVGAngle.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 3 201 1.5 %
Date: 2017-07-14 16:53:18 Functions: 0 24 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 "nsSVGAngle.h"
       8             : 
       9             : #include "mozilla/ArrayUtils.h"
      10             : #include "mozilla/dom/SVGMarkerElement.h"
      11             : #include "mozilla/Move.h"
      12             : #include "nsContentUtils.h" // NS_ENSURE_FINITE
      13             : #include "nsSMILValue.h"
      14             : #include "nsSVGAttrTearoffTable.h"
      15             : #include "nsTextFormatter.h"
      16             : #include "SVGAngle.h"
      17             : #include "SVGAnimatedAngle.h"
      18             : #include "SVGOrientSMILType.h"
      19             : 
      20             : using namespace mozilla;
      21             : using namespace mozilla::dom;
      22             : 
      23             : static nsIAtom** const unitMap[] =
      24             : {
      25             :   nullptr, /* SVG_ANGLETYPE_UNKNOWN */
      26             :   nullptr, /* SVG_ANGLETYPE_UNSPECIFIED */
      27             :   &nsGkAtoms::deg,
      28             :   &nsGkAtoms::rad,
      29             :   &nsGkAtoms::grad
      30             : };
      31             : 
      32             : static nsSVGAttrTearoffTable<nsSVGAngle, SVGAnimatedAngle>
      33           3 :   sSVGAnimatedAngleTearoffTable;
      34             : static nsSVGAttrTearoffTable<nsSVGAngle, SVGAngle>
      35           3 :   sBaseSVGAngleTearoffTable;
      36             : static nsSVGAttrTearoffTable<nsSVGAngle, SVGAngle>
      37           3 :   sAnimSVGAngleTearoffTable;
      38             : 
      39             : /* Helper functions */
      40             : 
      41             : static bool
      42           0 : IsValidUnitType(uint16_t unit)
      43             : {
      44           0 :   if (unit > SVG_ANGLETYPE_UNKNOWN &&
      45           0 :       unit <= SVG_ANGLETYPE_GRAD)
      46           0 :     return true;
      47             : 
      48           0 :   return false;
      49             : }
      50             : 
      51             : static void
      52           0 : GetUnitString(nsAString& unit, uint16_t unitType)
      53             : {
      54           0 :   if (IsValidUnitType(unitType)) {
      55           0 :     if (unitMap[unitType]) {
      56           0 :       (*unitMap[unitType])->ToString(unit);
      57             :     }
      58           0 :     return;
      59             :   }
      60             : 
      61           0 :   NS_NOTREACHED("Unknown unit type");
      62           0 :   return;
      63             : }
      64             : 
      65             : static uint16_t
      66           0 : GetUnitTypeForString(const nsAString& unitStr)
      67             : {
      68           0 :   if (unitStr.IsEmpty())
      69           0 :     return SVG_ANGLETYPE_UNSPECIFIED;
      70             : 
      71           0 :   nsIAtom *unitAtom = NS_GetStaticAtom(unitStr);
      72             : 
      73           0 :   if (unitAtom) {
      74           0 :     for (uint32_t i = 0 ; i < ArrayLength(unitMap) ; i++) {
      75           0 :       if (unitMap[i] && *unitMap[i] == unitAtom) {
      76           0 :         return i;
      77             :       }
      78             :     }
      79             :   }
      80             : 
      81           0 :   return SVG_ANGLETYPE_UNKNOWN;
      82             : }
      83             : 
      84             : static void
      85           0 : GetValueString(nsAString &aValueAsString, float aValue, uint16_t aUnitType)
      86             : {
      87             :   char16_t buf[24];
      88           0 :   nsTextFormatter::snprintf(buf, sizeof(buf)/sizeof(char16_t),
      89             :                             u"%g",
      90           0 :                             (double)aValue);
      91           0 :   aValueAsString.Assign(buf);
      92             : 
      93           0 :   nsAutoString unitString;
      94           0 :   GetUnitString(unitString, aUnitType);
      95           0 :   aValueAsString.Append(unitString);
      96           0 : }
      97             : 
      98             : static bool
      99           0 : GetValueFromString(const nsAString& aString,
     100             :                    float& aValue,
     101             :                    uint16_t* aUnitType)
     102             : {
     103             :   RangedPtr<const char16_t> iter =
     104           0 :     SVGContentUtils::GetStartRangedPtr(aString);
     105             :   const RangedPtr<const char16_t> end =
     106           0 :     SVGContentUtils::GetEndRangedPtr(aString);
     107             : 
     108           0 :   if (!SVGContentUtils::ParseNumber(iter, end, aValue)) {
     109           0 :     return false;
     110             :   }
     111             : 
     112           0 :   const nsAString& units = Substring(iter.get(), end.get());
     113           0 :   *aUnitType = GetUnitTypeForString(units);
     114           0 :   return IsValidUnitType(*aUnitType);
     115             : }
     116             : 
     117             : /* static */ float
     118           0 : nsSVGAngle::GetDegreesPerUnit(uint8_t aUnit)
     119             : {
     120           0 :   switch (aUnit) {
     121             :   case SVG_ANGLETYPE_UNSPECIFIED:
     122             :   case SVG_ANGLETYPE_DEG:
     123           0 :     return 1;
     124             :   case SVG_ANGLETYPE_RAD:
     125           0 :     return static_cast<float>(180.0 / M_PI);
     126             :   case SVG_ANGLETYPE_GRAD:
     127           0 :     return 90.0f / 100.0f;
     128             :   default:
     129           0 :     NS_NOTREACHED("Unknown unit type");
     130           0 :     return 0;
     131             :   }
     132             : }
     133             : 
     134             : void
     135           0 : nsSVGAngle::SetBaseValueInSpecifiedUnits(float aValue,
     136             :                                          nsSVGElement *aSVGElement)
     137             : {
     138           0 :   if (mBaseVal == aValue) {
     139           0 :     return;
     140             :   }
     141             : 
     142           0 :   nsAttrValue emptyOrOldValue = aSVGElement->WillChangeAngle(mAttrEnum);
     143           0 :   mBaseVal = aValue;
     144           0 :   if (!mIsAnimated) {
     145           0 :     mAnimVal = mBaseVal;
     146             :   }
     147             :   else {
     148           0 :     aSVGElement->AnimationNeedsResample();
     149             :   }
     150           0 :   aSVGElement->DidChangeAngle(mAttrEnum, emptyOrOldValue);
     151             : }
     152             : 
     153             : nsresult
     154           0 : nsSVGAngle::ConvertToSpecifiedUnits(uint16_t unitType,
     155             :                                     nsSVGElement *aSVGElement)
     156             : {
     157           0 :   if (!IsValidUnitType(unitType))
     158           0 :     return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
     159             : 
     160           0 :   if (mBaseValUnit == uint8_t(unitType))
     161           0 :     return NS_OK;
     162             : 
     163           0 :   nsAttrValue emptyOrOldValue;
     164           0 :   if (aSVGElement) {
     165           0 :     emptyOrOldValue = aSVGElement->WillChangeAngle(mAttrEnum);
     166             :   }
     167             : 
     168           0 :   float valueInUserUnits = mBaseVal * GetDegreesPerUnit(mBaseValUnit);
     169           0 :   mBaseValUnit = uint8_t(unitType);
     170             :   // Setting aDoSetAttr to false here will ensure we don't call
     171             :   // Will/DidChangeAngle a second time (and dispatch duplicate notifications).
     172           0 :   SetBaseValue(valueInUserUnits, aSVGElement, false);
     173             : 
     174           0 :   if (aSVGElement) {
     175           0 :     aSVGElement->DidChangeAngle(mAttrEnum, emptyOrOldValue);
     176             :   }
     177             : 
     178           0 :   return NS_OK;
     179             : }
     180             : 
     181             : nsresult
     182           0 : nsSVGAngle::NewValueSpecifiedUnits(uint16_t unitType,
     183             :                                    float valueInSpecifiedUnits,
     184             :                                    nsSVGElement *aSVGElement)
     185             : {
     186           0 :   NS_ENSURE_FINITE(valueInSpecifiedUnits, NS_ERROR_ILLEGAL_VALUE);
     187             : 
     188           0 :   if (!IsValidUnitType(unitType))
     189           0 :     return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
     190             : 
     191           0 :   if (mBaseVal == valueInSpecifiedUnits && mBaseValUnit == uint8_t(unitType))
     192           0 :     return NS_OK;
     193             : 
     194           0 :   nsAttrValue emptyOrOldValue;
     195           0 :   if (aSVGElement) {
     196           0 :     emptyOrOldValue = aSVGElement->WillChangeAngle(mAttrEnum);
     197             :   }
     198           0 :   mBaseVal = valueInSpecifiedUnits;
     199           0 :   mBaseValUnit = uint8_t(unitType);
     200           0 :   if (!mIsAnimated) {
     201           0 :     mAnimVal = mBaseVal;
     202           0 :     mAnimValUnit = mBaseValUnit;
     203             :   }
     204             :   else {
     205           0 :     aSVGElement->AnimationNeedsResample();
     206             :   }
     207           0 :   if (aSVGElement) {
     208           0 :     aSVGElement->DidChangeAngle(mAttrEnum, emptyOrOldValue);
     209             :   }
     210           0 :   return NS_OK;
     211             : }
     212             : 
     213             : already_AddRefed<SVGAngle>
     214           0 : nsSVGAngle::ToDOMBaseVal(nsSVGElement *aSVGElement)
     215             : {
     216             :   RefPtr<SVGAngle> domBaseVal =
     217           0 :     sBaseSVGAngleTearoffTable.GetTearoff(this);
     218           0 :   if (!domBaseVal) {
     219           0 :     domBaseVal = new SVGAngle(this, aSVGElement, SVGAngle::BaseValue);
     220           0 :     sBaseSVGAngleTearoffTable.AddTearoff(this, domBaseVal);
     221             :   }
     222             : 
     223           0 :   return domBaseVal.forget();
     224             : }
     225             : 
     226             : already_AddRefed<SVGAngle>
     227           0 : nsSVGAngle::ToDOMAnimVal(nsSVGElement *aSVGElement)
     228             : {
     229             :   RefPtr<SVGAngle> domAnimVal =
     230           0 :     sAnimSVGAngleTearoffTable.GetTearoff(this);
     231           0 :   if (!domAnimVal) {
     232           0 :     domAnimVal = new SVGAngle(this, aSVGElement, SVGAngle::AnimValue);
     233           0 :     sAnimSVGAngleTearoffTable.AddTearoff(this, domAnimVal);
     234             :   }
     235             : 
     236           0 :   return domAnimVal.forget();
     237             : }
     238             : 
     239           0 : SVGAngle::~SVGAngle()
     240             : {
     241           0 :   if (mType == BaseValue) {
     242           0 :     sBaseSVGAngleTearoffTable.RemoveTearoff(mVal);
     243           0 :   } else if (mType == AnimValue) {
     244           0 :     sAnimSVGAngleTearoffTable.RemoveTearoff(mVal);
     245             :   } else {
     246           0 :     delete mVal;
     247             :   }
     248           0 : }
     249             : 
     250             : /* Implementation */
     251             : 
     252             : nsresult
     253           0 : nsSVGAngle::SetBaseValueString(const nsAString &aValueAsString,
     254             :                                nsSVGElement *aSVGElement,
     255             :                                bool aDoSetAttr)
     256             : {
     257             :   float value;
     258             :   uint16_t unitType;
     259             : 
     260           0 :   if (!GetValueFromString(aValueAsString, value, &unitType)) {
     261           0 :      return NS_ERROR_DOM_SYNTAX_ERR;
     262             :   }
     263           0 :   if (mBaseVal == value && mBaseValUnit == uint8_t(unitType)) {
     264           0 :     return NS_OK;
     265             :   }
     266             : 
     267           0 :   nsAttrValue emptyOrOldValue;
     268           0 :   if (aDoSetAttr) {
     269           0 :     emptyOrOldValue = aSVGElement->WillChangeAngle(mAttrEnum);
     270             :   }
     271           0 :   mBaseVal = value;
     272           0 :   mBaseValUnit = uint8_t(unitType);
     273           0 :   if (!mIsAnimated) {
     274           0 :     mAnimVal = mBaseVal;
     275           0 :     mAnimValUnit = mBaseValUnit;
     276             :   }
     277             :   else {
     278           0 :     aSVGElement->AnimationNeedsResample();
     279             :   }
     280             : 
     281           0 :   if (aDoSetAttr) {
     282           0 :     aSVGElement->DidChangeAngle(mAttrEnum, emptyOrOldValue);
     283             :   }
     284           0 :   return NS_OK;
     285             : }
     286             : 
     287             : void
     288           0 : nsSVGAngle::GetBaseValueString(nsAString & aValueAsString) const
     289             : {
     290           0 :   GetValueString(aValueAsString, mBaseVal, mBaseValUnit);
     291           0 : }
     292             : 
     293             : void
     294           0 : nsSVGAngle::GetAnimValueString(nsAString & aValueAsString) const
     295             : {
     296           0 :   GetValueString(aValueAsString, mAnimVal, mAnimValUnit);
     297           0 : }
     298             : 
     299             : void
     300           0 : nsSVGAngle::SetBaseValue(float aValue, nsSVGElement *aSVGElement,
     301             :                          bool aDoSetAttr)
     302             : {
     303           0 :   if (mBaseVal == aValue * GetDegreesPerUnit(mBaseValUnit)) {
     304           0 :     return;
     305             :   }
     306           0 :   nsAttrValue emptyOrOldValue;
     307           0 :   if (aSVGElement && aDoSetAttr) {
     308           0 :     emptyOrOldValue = aSVGElement->WillChangeAngle(mAttrEnum);
     309             :   }
     310             : 
     311           0 :   mBaseVal = aValue / GetDegreesPerUnit(mBaseValUnit);
     312           0 :   if (!mIsAnimated) {
     313           0 :     mAnimVal = mBaseVal;
     314             :   }
     315             :   else {
     316           0 :     aSVGElement->AnimationNeedsResample();
     317             :   }
     318           0 :   if (aSVGElement && aDoSetAttr) {
     319           0 :     aSVGElement->DidChangeAngle(mAttrEnum, emptyOrOldValue);
     320             :   }
     321             : }
     322             : 
     323             : void
     324           0 : nsSVGAngle::SetAnimValue(float aValue, uint8_t aUnit, nsSVGElement *aSVGElement)
     325             : {
     326           0 :   if (mIsAnimated && mAnimVal == aValue && mAnimValUnit == aUnit) {
     327           0 :     return;
     328             :   }
     329           0 :   mAnimVal = aValue;
     330           0 :   mAnimValUnit = aUnit;
     331           0 :   mIsAnimated = true;
     332           0 :   aSVGElement->DidAnimateAngle(mAttrEnum);
     333             : }
     334             : 
     335             : already_AddRefed<SVGAnimatedAngle>
     336           0 : nsSVGAngle::ToDOMAnimatedAngle(nsSVGElement *aSVGElement)
     337             : {
     338             :   RefPtr<SVGAnimatedAngle> domAnimatedAngle =
     339           0 :     sSVGAnimatedAngleTearoffTable.GetTearoff(this);
     340           0 :   if (!domAnimatedAngle) {
     341           0 :     domAnimatedAngle = new SVGAnimatedAngle(this, aSVGElement);
     342           0 :     sSVGAnimatedAngleTearoffTable.AddTearoff(this, domAnimatedAngle);
     343             :   }
     344             : 
     345           0 :   return domAnimatedAngle.forget();
     346             : }
     347             : 
     348           0 : SVGAnimatedAngle::~SVGAnimatedAngle()
     349             : {
     350           0 :   sSVGAnimatedAngleTearoffTable.RemoveTearoff(mVal);
     351           0 : }
     352             : 
     353             : UniquePtr<nsISMILAttr>
     354           0 : nsSVGAngle::ToSMILAttr(nsSVGElement *aSVGElement)
     355             : {
     356           0 :   if (aSVGElement->NodeInfo()->Equals(nsGkAtoms::marker, kNameSpaceID_SVG)) {
     357           0 :     SVGMarkerElement *marker = static_cast<SVGMarkerElement*>(aSVGElement);
     358           0 :     return MakeUnique<SMILOrient>(marker->GetOrientType(), this, aSVGElement);
     359             :   }
     360             :   // SMILOrient would not be useful for general angle attributes (also,
     361             :   // "orient" is the only animatable <angle>-valued attribute in SVG 1.1).
     362           0 :   NS_NOTREACHED("Trying to animate unknown angle attribute.");
     363           0 :   return nullptr;
     364             : }
     365             : 
     366             : nsresult
     367           0 : nsSVGAngle::SMILOrient::ValueFromString(const nsAString& aStr,
     368             :                                         const SVGAnimationElement* /*aSrcElement*/,
     369             :                                         nsSMILValue& aValue,
     370             :                                         bool& aPreventCachingOfSandwich) const
     371             : {
     372           0 :   nsSMILValue val(&SVGOrientSMILType::sSingleton);
     373           0 :   if (aStr.EqualsLiteral("auto")) {
     374           0 :     val.mU.mOrient.mOrientType = SVG_MARKER_ORIENT_AUTO;
     375           0 :   } else if (aStr.EqualsLiteral("auto-start-reverse")) {
     376           0 :     val.mU.mOrient.mOrientType = SVG_MARKER_ORIENT_AUTO_START_REVERSE;
     377             :   } else {
     378             :     float value;
     379             :     uint16_t unitType;
     380           0 :     if (!GetValueFromString(aStr, value, &unitType)) {
     381           0 :       return NS_ERROR_DOM_SYNTAX_ERR;
     382             :     }
     383           0 :     val.mU.mOrient.mAngle = value;
     384           0 :     val.mU.mOrient.mUnit = unitType;
     385           0 :     val.mU.mOrient.mOrientType = SVG_MARKER_ORIENT_ANGLE;
     386             :   }
     387           0 :   aValue = Move(val);
     388           0 :   aPreventCachingOfSandwich = false;
     389             : 
     390           0 :   return NS_OK;
     391             : }
     392             : 
     393             : nsSMILValue
     394           0 : nsSVGAngle::SMILOrient::GetBaseValue() const
     395             : {
     396           0 :   nsSMILValue val(&SVGOrientSMILType::sSingleton);
     397           0 :   val.mU.mOrient.mAngle = mAngle->GetBaseValInSpecifiedUnits();
     398           0 :   val.mU.mOrient.mUnit = mAngle->GetBaseValueUnit();
     399           0 :   val.mU.mOrient.mOrientType = mOrientType->GetBaseValue();
     400           0 :   return val;
     401             : }
     402             : 
     403             : void
     404           0 : nsSVGAngle::SMILOrient::ClearAnimValue()
     405             : {
     406           0 :   if (mAngle->mIsAnimated) {
     407           0 :     mOrientType->SetAnimValue(mOrientType->GetBaseValue());
     408           0 :     mAngle->mIsAnimated = false;
     409           0 :     mAngle->mAnimVal = mAngle->mBaseVal;
     410           0 :     mAngle->mAnimValUnit = mAngle->mBaseValUnit;
     411           0 :     mSVGElement->DidAnimateAngle(mAngle->mAttrEnum);
     412             :   }
     413           0 : }
     414             : 
     415             : nsresult
     416           0 : nsSVGAngle::SMILOrient::SetAnimValue(const nsSMILValue& aValue)
     417             : {
     418           0 :   NS_ASSERTION(aValue.mType == &SVGOrientSMILType::sSingleton,
     419             :                "Unexpected type to assign animated value");
     420             : 
     421           0 :   if (aValue.mType == &SVGOrientSMILType::sSingleton) {
     422           0 :     mOrientType->SetAnimValue(aValue.mU.mOrient.mOrientType);
     423           0 :     if (aValue.mU.mOrient.mOrientType == SVG_MARKER_ORIENT_AUTO ||
     424           0 :         aValue.mU.mOrient.mOrientType == SVG_MARKER_ORIENT_AUTO_START_REVERSE) {
     425           0 :       mAngle->SetAnimValue(0.0f, SVG_ANGLETYPE_UNSPECIFIED, mSVGElement);
     426             :     } else {
     427           0 :       mAngle->SetAnimValue(aValue.mU.mOrient.mAngle, aValue.mU.mOrient.mUnit, mSVGElement);
     428             :     }
     429             :   }
     430           0 :   return NS_OK;
     431             : }

Generated by: LCOV version 1.13