SVGMotionSMILPathUtils.cpp (4245B)
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 "SVGMotionSMILPathUtils.h" 8 9 #include "SVGContentUtils.h" 10 #include "SVGLength.h" 11 #include "nsCharSeparatedTokenizer.h" 12 #include "nsContentUtils.h" // for NS_ENSURE_FINITE2 13 14 using namespace mozilla::gfx; 15 16 namespace mozilla { 17 18 //---------------------------------------------------------------------- 19 // PathGenerator methods 20 21 // For the dummy 'from' value used in pure by-animation & to-animation 22 void SVGMotionSMILPathUtils::PathGenerator::MoveToOrigin() { 23 MOZ_ASSERT(!mHaveReceivedCommands, 24 "Not expecting requests for mid-path MoveTo commands"); 25 mHaveReceivedCommands = true; 26 mPathBuilder->MoveTo(Point(0, 0)); 27 } 28 29 // For 'from' and the first entry in 'values'. 30 bool SVGMotionSMILPathUtils::PathGenerator::MoveToAbsolute( 31 const nsAString& aCoordPairStr) { 32 MOZ_ASSERT(!mHaveReceivedCommands, 33 "Not expecting requests for mid-path MoveTo commands"); 34 mHaveReceivedCommands = true; 35 36 float xVal, yVal; 37 if (!ParseCoordinatePair(aCoordPairStr, xVal, yVal)) { 38 return false; 39 } 40 mPathBuilder->MoveTo(Point(xVal, yVal)); 41 return true; 42 } 43 44 // For 'to' and every entry in 'values' except the first. 45 bool SVGMotionSMILPathUtils::PathGenerator::LineToAbsolute( 46 const nsAString& aCoordPairStr, double& aSegmentDistance) { 47 mHaveReceivedCommands = true; 48 49 float xVal, yVal; 50 if (!ParseCoordinatePair(aCoordPairStr, xVal, yVal)) { 51 return false; 52 } 53 Point initialPoint = mPathBuilder->CurrentPoint(); 54 55 mPathBuilder->LineTo(Point(xVal, yVal)); 56 aSegmentDistance = NS_hypot(initialPoint.x - xVal, initialPoint.y - yVal); 57 return true; 58 } 59 60 // For 'by'. 61 bool SVGMotionSMILPathUtils::PathGenerator::LineToRelative( 62 const nsAString& aCoordPairStr, double& aSegmentDistance) { 63 mHaveReceivedCommands = true; 64 65 float xVal, yVal; 66 if (!ParseCoordinatePair(aCoordPairStr, xVal, yVal)) { 67 return false; 68 } 69 mPathBuilder->LineTo(mPathBuilder->CurrentPoint() + Point(xVal, yVal)); 70 aSegmentDistance = NS_hypot(xVal, yVal); 71 return true; 72 } 73 74 already_AddRefed<Path> 75 SVGMotionSMILPathUtils::PathGenerator::GetResultingPath() { 76 return mPathBuilder->Finish(); 77 } 78 79 //---------------------------------------------------------------------- 80 // Helper / protected methods 81 82 bool SVGMotionSMILPathUtils::PathGenerator::ParseCoordinatePair( 83 const nsAString& aCoordPairStr, float& aXVal, float& aYVal) { 84 nsCharSeparatedTokenizerTemplate<nsContentUtils::IsHTMLWhitespace, 85 nsTokenizerFlags::SeparatorOptional> 86 tokenizer(aCoordPairStr, ','); 87 88 SVGLength x, y; 89 90 if (!tokenizer.hasMoreTokens() || 91 !x.SetValueFromString(tokenizer.nextToken())) { 92 return false; 93 } 94 95 if (!tokenizer.hasMoreTokens() || 96 !y.SetValueFromString(tokenizer.nextToken())) { 97 return false; 98 } 99 100 if (tokenizer.separatorAfterCurrentToken() || // Trailing comma. 101 tokenizer.hasMoreTokens()) { // More text remains 102 return false; 103 } 104 105 float xRes = x.GetValueInPixels(mSVGElement, SVGContentUtils::X); 106 float yRes = y.GetValueInPixels(mSVGElement, SVGContentUtils::Y); 107 108 NS_ENSURE_FINITE2(xRes, yRes, false); 109 110 aXVal = xRes; 111 aYVal = yRes; 112 return true; 113 } 114 115 //---------------------------------------------------------------------- 116 // MotionValueParser methods 117 bool SVGMotionSMILPathUtils::MotionValueParser::Parse( 118 const nsAString& aValueStr) { 119 bool success; 120 if (!mPathGenerator->HaveReceivedCommands()) { 121 // Interpret first value in "values" attribute as the path's initial MoveTo 122 success = mPathGenerator->MoveToAbsolute(aValueStr); 123 if (success) { 124 success = !!mPointDistances->AppendElement(0.0, fallible); 125 } 126 } else { 127 double dist; 128 success = mPathGenerator->LineToAbsolute(aValueStr, dist); 129 if (success) { 130 mDistanceSoFar += dist; 131 success = !!mPointDistances->AppendElement(mDistanceSoFar, fallible); 132 } 133 } 134 return success; 135 } 136 137 } // namespace mozilla