LCOV - code coverage report
Current view: top level - dom/svg - nsSVGLength2.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 43 231 18.6 %
Date: 2017-07-14 16:53:18 Functions: 8 39 20.5 %
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/ArrayUtils.h"
       8             : 
       9             : #include "nsSVGLength2.h"
      10             : #include "mozilla/dom/SVGAnimatedLength.h"
      11             : #include "mozilla/dom/SVGSVGElement.h"
      12             : #include "nsContentUtils.h" // NS_ENSURE_FINITE
      13             : #include "nsIFrame.h"
      14             : #include "nsSMILFloatType.h"
      15             : #include "nsSMILValue.h"
      16             : #include "nsSVGAttrTearoffTable.h"
      17             : #include "nsSVGIntegrationUtils.h"
      18             : #include "nsTextFormatter.h"
      19             : #include "DOMSVGLength.h"
      20             : #include "LayoutLogging.h"
      21             : 
      22             : using namespace mozilla;
      23             : using namespace mozilla::dom;
      24             : 
      25             : static nsIAtom** const unitMap[] =
      26             : {
      27             :   nullptr, /* SVG_LENGTHTYPE_UNKNOWN */
      28             :   nullptr, /* SVG_LENGTHTYPE_NUMBER */
      29             :   &nsGkAtoms::percentage,
      30             :   &nsGkAtoms::em,
      31             :   &nsGkAtoms::ex,
      32             :   &nsGkAtoms::px,
      33             :   &nsGkAtoms::cm,
      34             :   &nsGkAtoms::mm,
      35             :   &nsGkAtoms::in,
      36             :   &nsGkAtoms::pt,
      37             :   &nsGkAtoms::pc
      38             : };
      39             : 
      40             : static nsSVGAttrTearoffTable<nsSVGLength2, SVGAnimatedLength>
      41           3 :   sSVGAnimatedLengthTearoffTable;
      42             : 
      43             : /* Helper functions */
      44             : 
      45             : static bool
      46         106 : IsValidUnitType(uint16_t unit)
      47             : {
      48         212 :   if (unit > nsIDOMSVGLength::SVG_LENGTHTYPE_UNKNOWN &&
      49         106 :       unit <= nsIDOMSVGLength::SVG_LENGTHTYPE_PC)
      50         106 :     return true;
      51             : 
      52           0 :   return false;
      53             : }
      54             : 
      55             : static void
      56           0 : GetUnitString(nsAString& unit, uint16_t unitType)
      57             : {
      58           0 :   if (IsValidUnitType(unitType)) {
      59           0 :     if (unitMap[unitType]) {
      60           0 :       (*unitMap[unitType])->ToString(unit);
      61             :     }
      62           0 :     return;
      63             :   }
      64             : 
      65           0 :   NS_NOTREACHED("Unknown unit type");
      66           0 :   return;
      67             : }
      68             : 
      69             : static uint16_t
      70         106 : GetUnitTypeForString(const nsAString& unitStr)
      71             : {
      72         106 :   if (unitStr.IsEmpty())
      73         100 :     return nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER;
      74             : 
      75           6 :   nsIAtom *unitAtom = NS_GetStaticAtom(unitStr);
      76           6 :   if (unitAtom) {
      77          36 :     for (uint32_t i = 0 ; i < ArrayLength(unitMap) ; i++) {
      78          36 :       if (unitMap[i] && *unitMap[i] == unitAtom) {
      79           6 :         return i;
      80             :       }
      81             :     }
      82             :   }
      83             : 
      84           0 :   return nsIDOMSVGLength::SVG_LENGTHTYPE_UNKNOWN;
      85             : }
      86             : 
      87             : static void
      88           0 : GetValueString(nsAString &aValueAsString, float aValue, uint16_t aUnitType)
      89             : {
      90             :   char16_t buf[24];
      91           0 :   nsTextFormatter::snprintf(buf, sizeof(buf)/sizeof(char16_t),
      92             :                             u"%g",
      93           0 :                             (double)aValue);
      94           0 :   aValueAsString.Assign(buf);
      95             : 
      96           0 :   nsAutoString unitString;
      97           0 :   GetUnitString(unitString, aUnitType);
      98           0 :   aValueAsString.Append(unitString);
      99           0 : }
     100             : 
     101             : static bool
     102         106 : GetValueFromString(const nsAString& aString,
     103             :                    float& aValue,
     104             :                    uint16_t* aUnitType)
     105             : {
     106             :   RangedPtr<const char16_t> iter =
     107         106 :     SVGContentUtils::GetStartRangedPtr(aString);
     108             :   const RangedPtr<const char16_t> end =
     109         106 :     SVGContentUtils::GetEndRangedPtr(aString);
     110             : 
     111         106 :   if (!SVGContentUtils::ParseNumber(iter, end, aValue)) {
     112           0 :     return false;
     113             :   }
     114         212 :   const nsAString& units = Substring(iter.get(), end.get());
     115         106 :   *aUnitType = GetUnitTypeForString(units);
     116         106 :   return IsValidUnitType(*aUnitType);
     117             : }
     118             : 
     119           0 : static float GetMMPerPixel() { return MM_PER_INCH_FLOAT / 96; }
     120             : 
     121             : static float
     122           0 : FixAxisLength(float aLength)
     123             : {
     124           0 :   if (aLength == 0.0f) {
     125           0 :     LAYOUT_WARNING("zero axis length");
     126           0 :     return 1e-20f;
     127             :   }
     128           0 :   return aLength;
     129             : }
     130             : 
     131        1489 : SVGElementMetrics::SVGElementMetrics(nsSVGElement* aSVGElement,
     132        1489 :                                      SVGSVGElement* aCtx)
     133             :   : mSVGElement(aSVGElement)
     134        1489 :   , mCtx(aCtx)
     135             : {
     136        1489 : }
     137             : 
     138             : float
     139           0 : SVGElementMetrics::GetEmLength() const
     140             : {
     141           0 :   return SVGContentUtils::GetFontSize(mSVGElement);
     142             : }
     143             : 
     144             : float
     145           0 : SVGElementMetrics::GetExLength() const
     146             : {
     147           0 :   return SVGContentUtils::GetFontXHeight(mSVGElement);
     148             : }
     149             : 
     150             : float
     151           0 : SVGElementMetrics::GetAxisLength(uint8_t aCtxType) const
     152             : {
     153           0 :   if (!EnsureCtx()) {
     154           0 :     return 1;
     155             :   }
     156             : 
     157           0 :   return FixAxisLength(mCtx->GetLength(aCtxType));
     158             : }
     159             : 
     160             : bool
     161           0 : SVGElementMetrics::EnsureCtx() const
     162             : {
     163           0 :   if (!mCtx && mSVGElement) {
     164           0 :     mCtx = mSVGElement->GetCtx();
     165           0 :     if (!mCtx && mSVGElement->IsSVGElement(nsGkAtoms::svg)) {
     166             :       // mSVGElement must be the outer svg element
     167           0 :       mCtx = static_cast<SVGSVGElement*>(mSVGElement);
     168             :     }
     169             :   }
     170           0 :   return mCtx != nullptr;
     171             : }
     172             : 
     173           0 : NonSVGFrameUserSpaceMetrics::NonSVGFrameUserSpaceMetrics(nsIFrame* aFrame)
     174           0 :   : mFrame(aFrame)
     175             : {
     176           0 : }
     177             : 
     178             : float
     179           0 : NonSVGFrameUserSpaceMetrics::GetEmLength() const
     180             : {
     181           0 :   return SVGContentUtils::GetFontSize(mFrame);
     182             : }
     183             : 
     184             : float
     185           0 : NonSVGFrameUserSpaceMetrics::GetExLength() const
     186             : {
     187           0 :   return SVGContentUtils::GetFontXHeight(mFrame);
     188             : }
     189             : 
     190             : gfx::Size
     191           0 : NonSVGFrameUserSpaceMetrics::GetSize() const
     192             : {
     193           0 :   return nsSVGIntegrationUtils::GetSVGCoordContextForNonSVGFrame(mFrame);
     194             : }
     195             : 
     196             : float
     197           0 : UserSpaceMetricsWithSize::GetAxisLength(uint8_t aCtxType) const
     198             : {
     199           0 :   gfx::Size size = GetSize();
     200             :   float length;
     201           0 :   switch (aCtxType) {
     202             :   case SVGContentUtils::X:
     203           0 :     length = size.width;
     204           0 :     break;
     205             :   case SVGContentUtils::Y:
     206           0 :     length = size.height;
     207           0 :     break;
     208             :   case SVGContentUtils::XY:
     209           0 :     length = SVGContentUtils::ComputeNormalizedHypotenuse(size.width, size.height);
     210           0 :     break;
     211             :   default:
     212           0 :     NS_NOTREACHED("Unknown axis type");
     213           0 :     length = 1;
     214           0 :     break;
     215             :   }
     216           0 :   return FixAxisLength(length);
     217             : }
     218             : 
     219             : float
     220         236 : nsSVGLength2::GetUnitScaleFactor(nsSVGElement *aSVGElement,
     221             :                                  uint8_t aUnitType) const
     222             : {
     223         236 :   return GetUnitScaleFactor(SVGElementMetrics(aSVGElement), aUnitType);
     224             : }
     225             : 
     226             : float
     227        1253 : nsSVGLength2::GetUnitScaleFactor(SVGSVGElement *aCtx, uint8_t aUnitType) const
     228             : {
     229        1253 :   return GetUnitScaleFactor(SVGElementMetrics(aCtx, aCtx), aUnitType);
     230             : }
     231             : 
     232             : float
     233           0 : nsSVGLength2::GetUnitScaleFactor(nsIFrame *aFrame, uint8_t aUnitType) const
     234             : {
     235           0 :   nsIContent* content = aFrame->GetContent();
     236           0 :   if (content->IsSVGElement()) {
     237           0 :     return GetUnitScaleFactor(SVGElementMetrics(static_cast<nsSVGElement*>(content)), aUnitType);
     238             :   }
     239           0 :   return GetUnitScaleFactor(NonSVGFrameUserSpaceMetrics(aFrame), aUnitType);
     240             : }
     241             : 
     242             : float
     243        1489 : nsSVGLength2::GetUnitScaleFactor(const UserSpaceMetrics& aMetrics, uint8_t aUnitType) const
     244             : {
     245        1489 :   switch (aUnitType) {
     246             :   case nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER:
     247             :   case nsIDOMSVGLength::SVG_LENGTHTYPE_PX:
     248        1489 :     return 1;
     249             :   case nsIDOMSVGLength::SVG_LENGTHTYPE_MM:
     250           0 :     return GetMMPerPixel();
     251             :   case nsIDOMSVGLength::SVG_LENGTHTYPE_CM:
     252           0 :     return GetMMPerPixel() / 10.0f;
     253             :   case nsIDOMSVGLength::SVG_LENGTHTYPE_IN:
     254           0 :     return GetMMPerPixel() / MM_PER_INCH_FLOAT;
     255             :   case nsIDOMSVGLength::SVG_LENGTHTYPE_PT:
     256           0 :     return GetMMPerPixel() * POINTS_PER_INCH_FLOAT / MM_PER_INCH_FLOAT;
     257             :   case nsIDOMSVGLength::SVG_LENGTHTYPE_PC:
     258           0 :     return GetMMPerPixel() * POINTS_PER_INCH_FLOAT / MM_PER_INCH_FLOAT / 12.0f;
     259             :   case nsIDOMSVGLength::SVG_LENGTHTYPE_PERCENTAGE:
     260           0 :     return 100.0f / aMetrics.GetAxisLength(mCtxType);
     261             :   case nsIDOMSVGLength::SVG_LENGTHTYPE_EMS:
     262           0 :     return 1 / aMetrics.GetEmLength();
     263             :   case nsIDOMSVGLength::SVG_LENGTHTYPE_EXS:
     264           0 :     return 1 / aMetrics.GetExLength();
     265             :   default:
     266           0 :     NS_NOTREACHED("Unknown unit type");
     267           0 :     return 0;
     268             :   }
     269             : }
     270             : 
     271             : void
     272           0 : nsSVGLength2::SetBaseValueInSpecifiedUnits(float aValue,
     273             :                                            nsSVGElement *aSVGElement,
     274             :                                            bool aDoSetAttr)
     275             : {
     276           0 :   if (mIsBaseSet && mBaseVal == aValue) {
     277           0 :     return;
     278             :   }
     279             : 
     280           0 :   nsAttrValue emptyOrOldValue;
     281           0 :   if (aDoSetAttr) {
     282           0 :     emptyOrOldValue = aSVGElement->WillChangeLength(mAttrEnum);
     283             :   }
     284           0 :   mBaseVal = aValue;
     285           0 :   mIsBaseSet = true;
     286           0 :   if (!mIsAnimated) {
     287           0 :     mAnimVal = mBaseVal;
     288             :   }
     289             :   else {
     290           0 :     aSVGElement->AnimationNeedsResample();
     291             :   }
     292           0 :   if (aDoSetAttr) {
     293           0 :     aSVGElement->DidChangeLength(mAttrEnum, emptyOrOldValue);
     294             :   }
     295             : }
     296             : 
     297             : nsresult
     298           0 : nsSVGLength2::ConvertToSpecifiedUnits(uint16_t unitType,
     299             :                                       nsSVGElement *aSVGElement)
     300             : {
     301           0 :   if (!IsValidUnitType(unitType))
     302           0 :     return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
     303             : 
     304           0 :   if (mIsBaseSet && mSpecifiedUnitType == uint8_t(unitType))
     305           0 :     return NS_OK;
     306             : 
     307             :   // Even though we're not changing the visual effect this length will have
     308             :   // on the document, we still need to send out notifications in case we have
     309             :   // mutation listeners, since the actual string value of the attribute will
     310             :   // change.
     311           0 :   nsAttrValue emptyOrOldValue = aSVGElement->WillChangeLength(mAttrEnum);
     312             : 
     313             :   float valueInUserUnits =
     314           0 :     mBaseVal / GetUnitScaleFactor(aSVGElement, mSpecifiedUnitType);
     315           0 :   mSpecifiedUnitType = uint8_t(unitType);
     316             :   // Setting aDoSetAttr to false here will ensure we don't call
     317             :   // Will/DidChangeAngle a second time (and dispatch duplicate notifications).
     318           0 :   SetBaseValue(valueInUserUnits, aSVGElement, false);
     319             : 
     320           0 :   aSVGElement->DidChangeLength(mAttrEnum, emptyOrOldValue);
     321             : 
     322           0 :   return NS_OK;
     323             : }
     324             : 
     325             : nsresult
     326           0 : nsSVGLength2::NewValueSpecifiedUnits(uint16_t unitType,
     327             :                                      float valueInSpecifiedUnits,
     328             :                                      nsSVGElement *aSVGElement)
     329             : {
     330           0 :   NS_ENSURE_FINITE(valueInSpecifiedUnits, NS_ERROR_ILLEGAL_VALUE);
     331             : 
     332           0 :   if (!IsValidUnitType(unitType))
     333           0 :     return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
     334             : 
     335           0 :   if (mIsBaseSet && mBaseVal == valueInSpecifiedUnits &&
     336           0 :       mSpecifiedUnitType == uint8_t(unitType)) {
     337           0 :     return NS_OK;
     338             :   }
     339             : 
     340           0 :   nsAttrValue emptyOrOldValue = aSVGElement->WillChangeLength(mAttrEnum);
     341           0 :   mBaseVal = valueInSpecifiedUnits;
     342           0 :   mIsBaseSet = true;
     343           0 :   mSpecifiedUnitType = uint8_t(unitType);
     344           0 :   if (!mIsAnimated) {
     345           0 :     mAnimVal = mBaseVal;
     346             :   }
     347             :   else {
     348           0 :     aSVGElement->AnimationNeedsResample();
     349             :   }
     350           0 :   aSVGElement->DidChangeLength(mAttrEnum, emptyOrOldValue);
     351           0 :   return NS_OK;
     352             : }
     353             : 
     354             : nsresult
     355           0 : nsSVGLength2::ToDOMBaseVal(DOMSVGLength **aResult, nsSVGElement *aSVGElement)
     356             : {
     357             :   RefPtr<DOMSVGLength> domBaseVal =
     358           0 :     DOMSVGLength::GetTearOff(this, aSVGElement, false);
     359             : 
     360           0 :   domBaseVal.forget(aResult);
     361           0 :   return NS_OK;
     362             : }
     363             : 
     364             : nsresult
     365           0 : nsSVGLength2::ToDOMAnimVal(DOMSVGLength **aResult, nsSVGElement *aSVGElement)
     366             : {
     367             :   RefPtr<DOMSVGLength> domAnimVal =
     368           0 :     DOMSVGLength::GetTearOff(this, aSVGElement, true);
     369             : 
     370           0 :   domAnimVal.forget(aResult);
     371           0 :   return NS_OK;
     372             : }
     373             : 
     374             : /* Implementation */
     375             : 
     376             : nsresult
     377         106 : nsSVGLength2::SetBaseValueString(const nsAString &aValueAsString,
     378             :                                  nsSVGElement *aSVGElement,
     379             :                                  bool aDoSetAttr)
     380             : {
     381             :   float value;
     382             :   uint16_t unitType;
     383             : 
     384         106 :   if (!GetValueFromString(aValueAsString, value, &unitType)) {
     385           0 :     return NS_ERROR_DOM_SYNTAX_ERR;
     386             :   }
     387             : 
     388         106 :   if (mIsBaseSet && mBaseVal == float(value) &&
     389           0 :       mSpecifiedUnitType == uint8_t(unitType)) {
     390           0 :     return NS_OK;
     391             :   }
     392             : 
     393         212 :   nsAttrValue emptyOrOldValue;
     394         106 :   if (aDoSetAttr) {
     395           0 :     emptyOrOldValue = aSVGElement->WillChangeLength(mAttrEnum);
     396             :   }
     397         106 :   mBaseVal = value;
     398         106 :   mIsBaseSet = true;
     399         106 :   mSpecifiedUnitType = uint8_t(unitType);
     400         106 :   if (!mIsAnimated) {
     401         106 :     mAnimVal = mBaseVal;
     402             :   }
     403             :   else {
     404           0 :     aSVGElement->AnimationNeedsResample();
     405             :   }
     406             : 
     407         106 :   if (aDoSetAttr) {
     408           0 :     aSVGElement->DidChangeLength(mAttrEnum, emptyOrOldValue);
     409             :   }
     410         106 :   return NS_OK;
     411             : }
     412             : 
     413             : void
     414           0 : nsSVGLength2::GetBaseValueString(nsAString & aValueAsString) const
     415             : {
     416           0 :   GetValueString(aValueAsString, mBaseVal, mSpecifiedUnitType);
     417           0 : }
     418             : 
     419             : void
     420           0 : nsSVGLength2::GetAnimValueString(nsAString & aValueAsString) const
     421             : {
     422           0 :   GetValueString(aValueAsString, mAnimVal, mSpecifiedUnitType);
     423           0 : }
     424             : 
     425             : void
     426           0 : nsSVGLength2::SetBaseValue(float aValue, nsSVGElement *aSVGElement,
     427             :                            bool aDoSetAttr)
     428             : {
     429           0 :   SetBaseValueInSpecifiedUnits(aValue * GetUnitScaleFactor(aSVGElement,
     430           0 :                                                            mSpecifiedUnitType),
     431           0 :                                aSVGElement, aDoSetAttr);
     432           0 : }
     433             : 
     434             : void
     435           0 : nsSVGLength2::SetAnimValueInSpecifiedUnits(float aValue,
     436             :                                            nsSVGElement* aSVGElement)
     437             : {
     438           0 :   if (mAnimVal == aValue && mIsAnimated) {
     439           0 :     return;
     440             :   }
     441           0 :   mAnimVal = aValue;
     442           0 :   mIsAnimated = true;
     443           0 :   aSVGElement->DidAnimateLength(mAttrEnum);
     444             : }
     445             : 
     446             : void
     447           0 : nsSVGLength2::SetAnimValue(float aValue, nsSVGElement *aSVGElement)
     448             : {
     449           0 :   SetAnimValueInSpecifiedUnits(aValue * GetUnitScaleFactor(aSVGElement,
     450           0 :                                                            mSpecifiedUnitType),
     451           0 :                                aSVGElement);
     452           0 : }
     453             : 
     454             : already_AddRefed<SVGAnimatedLength>
     455           0 : nsSVGLength2::ToDOMAnimatedLength(nsSVGElement* aSVGElement)
     456             : {
     457             :   RefPtr<SVGAnimatedLength> svgAnimatedLength =
     458           0 :     sSVGAnimatedLengthTearoffTable.GetTearoff(this);
     459           0 :   if (!svgAnimatedLength) {
     460           0 :     svgAnimatedLength = new SVGAnimatedLength(this, aSVGElement);
     461           0 :     sSVGAnimatedLengthTearoffTable.AddTearoff(this, svgAnimatedLength);
     462             :   }
     463             : 
     464           0 :   return svgAnimatedLength.forget();
     465             : }
     466             : 
     467           0 : SVGAnimatedLength::~SVGAnimatedLength()
     468             : {
     469           0 :   sSVGAnimatedLengthTearoffTable.RemoveTearoff(mVal);
     470           0 : }
     471             : 
     472             : UniquePtr<nsISMILAttr>
     473           0 : nsSVGLength2::ToSMILAttr(nsSVGElement *aSVGElement)
     474             : {
     475           0 :   return MakeUnique<SMILLength>(this, aSVGElement);
     476             : }
     477             : 
     478             : nsresult
     479           0 : nsSVGLength2::SMILLength::ValueFromString(const nsAString& aStr,
     480             :                                  const SVGAnimationElement* /*aSrcElement*/,
     481             :                                  nsSMILValue& aValue,
     482             :                                  bool& aPreventCachingOfSandwich) const
     483             : {
     484             :   float value;
     485             :   uint16_t unitType;
     486             : 
     487           0 :   if (!GetValueFromString(aStr, value, &unitType)) {
     488           0 :     return NS_ERROR_DOM_SYNTAX_ERR;
     489             :   }
     490             : 
     491           0 :   nsSMILValue val(nsSMILFloatType::Singleton());
     492           0 :   val.mU.mDouble = value / mVal->GetUnitScaleFactor(mSVGElement, unitType);
     493           0 :   aValue = val;
     494           0 :   aPreventCachingOfSandwich =
     495           0 :               (unitType == nsIDOMSVGLength::SVG_LENGTHTYPE_PERCENTAGE ||
     496           0 :                unitType == nsIDOMSVGLength::SVG_LENGTHTYPE_EMS ||
     497           0 :                unitType == nsIDOMSVGLength::SVG_LENGTHTYPE_EXS);
     498             : 
     499           0 :   return NS_OK;
     500             : }
     501             : 
     502             : nsSMILValue
     503           0 : nsSVGLength2::SMILLength::GetBaseValue() const
     504             : {
     505           0 :   nsSMILValue val(nsSMILFloatType::Singleton());
     506           0 :   val.mU.mDouble = mVal->GetBaseValue(mSVGElement);
     507           0 :   return val;
     508             : }
     509             : 
     510             : void
     511           0 : nsSVGLength2::SMILLength::ClearAnimValue()
     512             : {
     513           0 :   if (mVal->mIsAnimated) {
     514           0 :     mVal->mIsAnimated = false;
     515           0 :     mVal->mAnimVal = mVal->mBaseVal;
     516           0 :     mSVGElement->DidAnimateLength(mVal->mAttrEnum);
     517             :   }
     518           0 : }
     519             : 
     520             : nsresult
     521           0 : nsSVGLength2::SMILLength::SetAnimValue(const nsSMILValue& aValue)
     522             : {
     523           0 :   NS_ASSERTION(aValue.mType == nsSMILFloatType::Singleton(),
     524             :     "Unexpected type to assign animated value");
     525           0 :   if (aValue.mType == nsSMILFloatType::Singleton()) {
     526           0 :     mVal->SetAnimValue(float(aValue.mU.mDouble), mSVGElement);
     527             :   }
     528           0 :   return NS_OK;
     529             : }

Generated by: LCOV version 1.13