| OLD | NEW |
| (Empty) |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "config.h" | |
| 6 #include "core/animation/PathSVGInterpolation.h" | |
| 7 | |
| 8 #include "core/svg/SVGPathByteStreamBuilder.h" | |
| 9 #include "core/svg/SVGPathByteStreamSource.h" | |
| 10 #include "core/svg/SVGPathElement.h" | |
| 11 #include "core/svg/SVGPathParser.h" | |
| 12 | |
| 13 namespace blink { | |
| 14 | |
| 15 namespace { | |
| 16 | |
| 17 struct SubPathCoordinates { | |
| 18 double initialX = 0; | |
| 19 double initialY = 0; | |
| 20 double currentX = 0; | |
| 21 double currentY = 0; | |
| 22 }; | |
| 23 | |
| 24 PassOwnPtr<InterpolableNumber> controlToInterpolableValue(double value, bool isA
bsolute, double currentValue) | |
| 25 { | |
| 26 if (isAbsolute) | |
| 27 return InterpolableNumber::create(value); | |
| 28 return InterpolableNumber::create(currentValue + value); | |
| 29 } | |
| 30 | |
| 31 double controlFromInterpolableValue(const InterpolableValue* number, bool isAbso
lute, double currentValue) | |
| 32 { | |
| 33 double value = toInterpolableNumber(number)->value(); | |
| 34 | |
| 35 if (isAbsolute) | |
| 36 return value; | |
| 37 return value - currentValue; | |
| 38 } | |
| 39 | |
| 40 PassOwnPtr<InterpolableNumber> specifiedToInterpolableValue(double value, bool i
sAbsolute, double& currentValue) | |
| 41 { | |
| 42 if (isAbsolute) | |
| 43 currentValue = value; | |
| 44 else | |
| 45 currentValue += value; | |
| 46 return InterpolableNumber::create(currentValue); | |
| 47 } | |
| 48 | |
| 49 double specifiedFromInterpolableValue(const InterpolableValue* number, bool isAb
solute, double& currentValue) | |
| 50 { | |
| 51 double previousValue = currentValue; | |
| 52 currentValue = toInterpolableNumber(number)->value(); | |
| 53 | |
| 54 if (isAbsolute) | |
| 55 return currentValue; | |
| 56 return currentValue - previousValue; | |
| 57 } | |
| 58 | |
| 59 PassOwnPtr<InterpolableValue> pathSegClosePathToInterpolableValue(const PathSegm
entData&, SubPathCoordinates& coordinates) | |
| 60 { | |
| 61 coordinates.currentX = coordinates.initialX; | |
| 62 coordinates.currentY = coordinates.initialY; | |
| 63 | |
| 64 // arbitrary | |
| 65 return InterpolableBool::create(false); | |
| 66 } | |
| 67 | |
| 68 PathSegmentData pathSegClosePathFromInterpolableValue(const InterpolableValue&,
SVGPathSegType segType, SubPathCoordinates& coordinates) | |
| 69 { | |
| 70 coordinates.currentX = coordinates.initialX; | |
| 71 coordinates.currentY = coordinates.initialY; | |
| 72 | |
| 73 PathSegmentData segment; | |
| 74 segment.command = segType; | |
| 75 return segment; | |
| 76 } | |
| 77 | |
| 78 PassOwnPtr<InterpolableValue> pathSegSingleCoordinateToInterpolableValue(const P
athSegmentData& segment, SubPathCoordinates& coordinates) | |
| 79 { | |
| 80 bool isAbsolute = isAbsolutePathSegType(segment.command); | |
| 81 OwnPtr<InterpolableList> result = InterpolableList::create(2); | |
| 82 result->set(0, specifiedToInterpolableValue(segment.x(), isAbsolute, coordin
ates.currentX)); | |
| 83 result->set(1, specifiedToInterpolableValue(segment.y(), isAbsolute, coordin
ates.currentY)); | |
| 84 | |
| 85 if (toAbsolutePathSegType(segment.command) == PathSegMoveToAbs) { | |
| 86 // Any upcoming 'closepath' commands bring us back to the location we ha
ve just moved to. | |
| 87 coordinates.initialX = coordinates.currentX; | |
| 88 coordinates.initialY = coordinates.currentY; | |
| 89 } | |
| 90 | |
| 91 return result.release(); | |
| 92 } | |
| 93 | |
| 94 PathSegmentData pathSegSingleCoordinateFromInterpolableValue(const InterpolableV
alue& value, SVGPathSegType segType, SubPathCoordinates& coordinates) | |
| 95 { | |
| 96 const InterpolableList& list = toInterpolableList(value); | |
| 97 bool isAbsolute = isAbsolutePathSegType(segType); | |
| 98 PathSegmentData segment; | |
| 99 segment.command = segType; | |
| 100 segment.targetPoint.setX(specifiedFromInterpolableValue(list.get(0), isAbsol
ute, coordinates.currentX)); | |
| 101 segment.targetPoint.setY(specifiedFromInterpolableValue(list.get(1), isAbsol
ute, coordinates.currentY)); | |
| 102 | |
| 103 if (toAbsolutePathSegType(segType) == PathSegMoveToAbs) { | |
| 104 // Any upcoming 'closepath' commands bring us back to the location we ha
ve just moved to. | |
| 105 coordinates.initialX = coordinates.currentX; | |
| 106 coordinates.initialY = coordinates.currentY; | |
| 107 } | |
| 108 | |
| 109 return segment; | |
| 110 } | |
| 111 | |
| 112 PassOwnPtr<InterpolableValue> pathSegCurvetoCubicToInterpolableValue(const PathS
egmentData& segment, SubPathCoordinates& coordinates) | |
| 113 { | |
| 114 bool isAbsolute = isAbsolutePathSegType(segment.command); | |
| 115 OwnPtr<InterpolableList> result = InterpolableList::create(6); | |
| 116 result->set(0, controlToInterpolableValue(segment.x1(), isAbsolute, coordina
tes.currentX)); | |
| 117 result->set(1, controlToInterpolableValue(segment.y1(), isAbsolute, coordina
tes.currentY)); | |
| 118 result->set(2, controlToInterpolableValue(segment.x2(), isAbsolute, coordina
tes.currentX)); | |
| 119 result->set(3, controlToInterpolableValue(segment.y2(), isAbsolute, coordina
tes.currentY)); | |
| 120 result->set(4, specifiedToInterpolableValue(segment.x(), isAbsolute, coordin
ates.currentX)); | |
| 121 result->set(5, specifiedToInterpolableValue(segment.y(), isAbsolute, coordin
ates.currentY)); | |
| 122 return result.release(); | |
| 123 } | |
| 124 | |
| 125 PathSegmentData pathSegCurvetoCubicFromInterpolableValue(const InterpolableValue
& value, SVGPathSegType segType, SubPathCoordinates& coordinates) | |
| 126 { | |
| 127 const InterpolableList& list = toInterpolableList(value); | |
| 128 bool isAbsolute = isAbsolutePathSegType(segType); | |
| 129 PathSegmentData segment; | |
| 130 segment.command = segType; | |
| 131 segment.point1.setX(controlFromInterpolableValue(list.get(0), isAbsolute, co
ordinates.currentX)); | |
| 132 segment.point1.setY(controlFromInterpolableValue(list.get(1), isAbsolute, co
ordinates.currentY)); | |
| 133 segment.point2.setX(controlFromInterpolableValue(list.get(2), isAbsolute, co
ordinates.currentX)); | |
| 134 segment.point2.setY(controlFromInterpolableValue(list.get(3), isAbsolute, co
ordinates.currentY)); | |
| 135 segment.targetPoint.setX(specifiedFromInterpolableValue(list.get(4), isAbsol
ute, coordinates.currentX)); | |
| 136 segment.targetPoint.setY(specifiedFromInterpolableValue(list.get(5), isAbsol
ute, coordinates.currentY)); | |
| 137 return segment; | |
| 138 } | |
| 139 | |
| 140 PassOwnPtr<InterpolableValue> pathSegCurvetoQuadraticToInterpolableValue(const P
athSegmentData& segment, SubPathCoordinates& coordinates) | |
| 141 { | |
| 142 bool isAbsolute = isAbsolutePathSegType(segment.command); | |
| 143 OwnPtr<InterpolableList> result = InterpolableList::create(4); | |
| 144 result->set(0, controlToInterpolableValue(segment.x1(), isAbsolute, coordina
tes.currentX)); | |
| 145 result->set(1, controlToInterpolableValue(segment.y1(), isAbsolute, coordina
tes.currentY)); | |
| 146 result->set(2, specifiedToInterpolableValue(segment.x(), isAbsolute, coordin
ates.currentX)); | |
| 147 result->set(3, specifiedToInterpolableValue(segment.y(), isAbsolute, coordin
ates.currentY)); | |
| 148 return result.release(); | |
| 149 } | |
| 150 | |
| 151 PathSegmentData pathSegCurvetoQuadraticFromInterpolableValue(const InterpolableV
alue& value, SVGPathSegType segType, SubPathCoordinates& coordinates) | |
| 152 { | |
| 153 const InterpolableList& list = toInterpolableList(value); | |
| 154 bool isAbsolute = isAbsolutePathSegType(segType); | |
| 155 PathSegmentData segment; | |
| 156 segment.command = segType; | |
| 157 segment.point1.setX(controlFromInterpolableValue(list.get(0), isAbsolute, co
ordinates.currentX)); | |
| 158 segment.point1.setY(controlFromInterpolableValue(list.get(1), isAbsolute, co
ordinates.currentY)); | |
| 159 segment.targetPoint.setX(specifiedFromInterpolableValue(list.get(2), isAbsol
ute, coordinates.currentX)); | |
| 160 segment.targetPoint.setY(specifiedFromInterpolableValue(list.get(3), isAbsol
ute, coordinates.currentY)); | |
| 161 return segment; | |
| 162 } | |
| 163 | |
| 164 PassOwnPtr<InterpolableValue> pathSegArcToInterpolableValue(const PathSegmentDat
a& segment, SubPathCoordinates& coordinates) | |
| 165 { | |
| 166 bool isAbsolute = isAbsolutePathSegType(segment.command); | |
| 167 OwnPtr<InterpolableList> result = InterpolableList::create(7); | |
| 168 result->set(0, specifiedToInterpolableValue(segment.x(), isAbsolute, coordin
ates.currentX)); | |
| 169 result->set(1, specifiedToInterpolableValue(segment.y(), isAbsolute, coordin
ates.currentY)); | |
| 170 result->set(2, InterpolableNumber::create(segment.r1())); | |
| 171 result->set(3, InterpolableNumber::create(segment.r2())); | |
| 172 result->set(4, InterpolableNumber::create(segment.arcAngle())); | |
| 173 result->set(5, InterpolableBool::create(segment.largeArcFlag())); | |
| 174 result->set(6, InterpolableBool::create(segment.sweepFlag())); | |
| 175 return result.release(); | |
| 176 } | |
| 177 | |
| 178 PathSegmentData pathSegArcFromInterpolableValue(const InterpolableValue& value,
SVGPathSegType segType, SubPathCoordinates& coordinates) | |
| 179 { | |
| 180 const InterpolableList& list = toInterpolableList(value); | |
| 181 bool isAbsolute = isAbsolutePathSegType(segType); | |
| 182 PathSegmentData segment; | |
| 183 segment.command = segType; | |
| 184 segment.targetPoint.setX(specifiedFromInterpolableValue(list.get(0), isAbsol
ute, coordinates.currentX)); | |
| 185 segment.targetPoint.setY(specifiedFromInterpolableValue(list.get(1), isAbsol
ute, coordinates.currentY)); | |
| 186 segment.arcRadii().setX(toInterpolableNumber(list.get(2))->value()); | |
| 187 segment.arcRadii().setY(toInterpolableNumber(list.get(3))->value()); | |
| 188 segment.setArcAngle(toInterpolableNumber(list.get(4))->value()); | |
| 189 segment.arcLarge = toInterpolableBool(list.get(5))->value(); | |
| 190 segment.arcSweep = toInterpolableBool(list.get(6))->value(); | |
| 191 return segment; | |
| 192 } | |
| 193 | |
| 194 PassOwnPtr<InterpolableValue> pathSegLinetoHorizontalToInterpolableValue(const P
athSegmentData& segment, SubPathCoordinates& coordinates) | |
| 195 { | |
| 196 bool isAbsolute = isAbsolutePathSegType(segment.command); | |
| 197 return specifiedToInterpolableValue(segment.x(), isAbsolute, coordinates.cur
rentX); | |
| 198 } | |
| 199 | |
| 200 PathSegmentData pathSegLinetoHorizontalFromInterpolableValue(const InterpolableV
alue& value, SVGPathSegType segType, SubPathCoordinates& coordinates) | |
| 201 { | |
| 202 bool isAbsolute = isAbsolutePathSegType(segType); | |
| 203 PathSegmentData segment; | |
| 204 segment.command = segType; | |
| 205 segment.targetPoint.setX(specifiedFromInterpolableValue(&value, isAbsolute,
coordinates.currentX)); | |
| 206 return segment; | |
| 207 } | |
| 208 | |
| 209 PassOwnPtr<InterpolableValue> pathSegLinetoVerticalToInterpolableValue(const Pat
hSegmentData& segment, SubPathCoordinates& coordinates) | |
| 210 { | |
| 211 bool isAbsolute = isAbsolutePathSegType(segment.command); | |
| 212 return specifiedToInterpolableValue(segment.y(), isAbsolute, coordinates.cur
rentY); | |
| 213 } | |
| 214 | |
| 215 PathSegmentData pathSegLinetoVerticalFromInterpolableValue(const InterpolableVal
ue& value, SVGPathSegType segType, SubPathCoordinates& coordinates) | |
| 216 { | |
| 217 bool isAbsolute = isAbsolutePathSegType(segType); | |
| 218 PathSegmentData segment; | |
| 219 segment.command = segType; | |
| 220 segment.targetPoint.setY(specifiedFromInterpolableValue(&value, isAbsolute,
coordinates.currentY)); | |
| 221 return segment; | |
| 222 } | |
| 223 | |
| 224 PassOwnPtr<InterpolableValue> pathSegCurvetoCubicSmoothToInterpolableValue(const
PathSegmentData& segment, SubPathCoordinates& coordinates) | |
| 225 { | |
| 226 bool isAbsolute = isAbsolutePathSegType(segment.command); | |
| 227 OwnPtr<InterpolableList> result = InterpolableList::create(4); | |
| 228 result->set(0, controlToInterpolableValue(segment.x2(), isAbsolute, coordina
tes.currentX)); | |
| 229 result->set(1, controlToInterpolableValue(segment.y2(), isAbsolute, coordina
tes.currentY)); | |
| 230 result->set(2, specifiedToInterpolableValue(segment.x(), isAbsolute, coordin
ates.currentX)); | |
| 231 result->set(3, specifiedToInterpolableValue(segment.y(), isAbsolute, coordin
ates.currentY)); | |
| 232 return result.release(); | |
| 233 } | |
| 234 | |
| 235 PathSegmentData pathSegCurvetoCubicSmoothFromInterpolableValue(const Interpolabl
eValue& value, SVGPathSegType segType, SubPathCoordinates& coordinates) | |
| 236 { | |
| 237 const InterpolableList& list = toInterpolableList(value); | |
| 238 bool isAbsolute = isAbsolutePathSegType(segType); | |
| 239 PathSegmentData segment; | |
| 240 segment.command = segType; | |
| 241 segment.point2.setX(controlFromInterpolableValue(list.get(0), isAbsolute, co
ordinates.currentX)); | |
| 242 segment.point2.setY(controlFromInterpolableValue(list.get(1), isAbsolute, co
ordinates.currentY)); | |
| 243 segment.targetPoint.setX(specifiedFromInterpolableValue(list.get(2), isAbsol
ute, coordinates.currentX)); | |
| 244 segment.targetPoint.setY(specifiedFromInterpolableValue(list.get(3), isAbsol
ute, coordinates.currentY)); | |
| 245 return segment; | |
| 246 } | |
| 247 | |
| 248 PassOwnPtr<InterpolableValue> pathSegToInterpolableValue(const PathSegmentData&
segment, SubPathCoordinates& coordinates, SVGPathSegType* ptrSegType) | |
| 249 { | |
| 250 if (ptrSegType) | |
| 251 *ptrSegType = segment.command; | |
| 252 | |
| 253 switch (segment.command) { | |
| 254 case PathSegClosePath: | |
| 255 return pathSegClosePathToInterpolableValue(segment, coordinates); | |
| 256 | |
| 257 case PathSegMoveToAbs: | |
| 258 case PathSegMoveToRel: | |
| 259 case PathSegLineToAbs: | |
| 260 case PathSegLineToRel: | |
| 261 case PathSegCurveToQuadraticSmoothAbs: | |
| 262 case PathSegCurveToQuadraticSmoothRel: | |
| 263 return pathSegSingleCoordinateToInterpolableValue(segment, coordinates); | |
| 264 | |
| 265 case PathSegCurveToCubicAbs: | |
| 266 case PathSegCurveToCubicRel: | |
| 267 return pathSegCurvetoCubicToInterpolableValue(segment, coordinates); | |
| 268 | |
| 269 case PathSegCurveToQuadraticAbs: | |
| 270 case PathSegCurveToQuadraticRel: | |
| 271 return pathSegCurvetoQuadraticToInterpolableValue(segment, coordinates); | |
| 272 | |
| 273 case PathSegArcAbs: | |
| 274 case PathSegArcRel: | |
| 275 return pathSegArcToInterpolableValue(segment, coordinates); | |
| 276 | |
| 277 case PathSegLineToHorizontalAbs: | |
| 278 case PathSegLineToHorizontalRel: | |
| 279 return pathSegLinetoHorizontalToInterpolableValue(segment, coordinates); | |
| 280 | |
| 281 case PathSegLineToVerticalAbs: | |
| 282 case PathSegLineToVerticalRel: | |
| 283 return pathSegLinetoVerticalToInterpolableValue(segment, coordinates); | |
| 284 | |
| 285 case PathSegCurveToCubicSmoothAbs: | |
| 286 case PathSegCurveToCubicSmoothRel: | |
| 287 return pathSegCurvetoCubicSmoothToInterpolableValue(segment, coordinates
); | |
| 288 | |
| 289 case PathSegUnknown: | |
| 290 ASSERT_NOT_REACHED(); | |
| 291 } | |
| 292 ASSERT_NOT_REACHED(); | |
| 293 return nullptr; | |
| 294 } | |
| 295 | |
| 296 PathSegmentData pathSegFromInterpolableValue(const InterpolableValue& value, SVG
PathSegType segType, SubPathCoordinates& coordinates) | |
| 297 { | |
| 298 switch (segType) { | |
| 299 case PathSegClosePath: | |
| 300 return pathSegClosePathFromInterpolableValue(value, segType, coordinates
); | |
| 301 | |
| 302 case PathSegMoveToAbs: | |
| 303 case PathSegMoveToRel: | |
| 304 case PathSegLineToAbs: | |
| 305 case PathSegLineToRel: | |
| 306 case PathSegCurveToQuadraticSmoothAbs: | |
| 307 case PathSegCurveToQuadraticSmoothRel: | |
| 308 return pathSegSingleCoordinateFromInterpolableValue(value, segType, coor
dinates); | |
| 309 | |
| 310 case PathSegCurveToCubicAbs: | |
| 311 case PathSegCurveToCubicRel: | |
| 312 return pathSegCurvetoCubicFromInterpolableValue(value, segType, coordina
tes); | |
| 313 | |
| 314 case PathSegCurveToQuadraticAbs: | |
| 315 case PathSegCurveToQuadraticRel: | |
| 316 return pathSegCurvetoQuadraticFromInterpolableValue(value, segType, coor
dinates); | |
| 317 | |
| 318 case PathSegArcAbs: | |
| 319 case PathSegArcRel: | |
| 320 return pathSegArcFromInterpolableValue(value, segType, coordinates); | |
| 321 | |
| 322 case PathSegLineToHorizontalAbs: | |
| 323 case PathSegLineToHorizontalRel: | |
| 324 return pathSegLinetoHorizontalFromInterpolableValue(value, segType, coor
dinates); | |
| 325 | |
| 326 case PathSegLineToVerticalAbs: | |
| 327 case PathSegLineToVerticalRel: | |
| 328 return pathSegLinetoVerticalFromInterpolableValue(value, segType, coordi
nates); | |
| 329 | |
| 330 case PathSegCurveToCubicSmoothAbs: | |
| 331 case PathSegCurveToCubicSmoothRel: | |
| 332 return pathSegCurvetoCubicSmoothFromInterpolableValue(value, segType, co
ordinates); | |
| 333 | |
| 334 case PathSegUnknown: | |
| 335 ASSERT_NOT_REACHED(); | |
| 336 } | |
| 337 ASSERT_NOT_REACHED(); | |
| 338 return PathSegmentData(); | |
| 339 } | |
| 340 | |
| 341 class InterpolatedPathSource : public SVGPathSource { | |
| 342 public: | |
| 343 InterpolatedPathSource(const InterpolableList& listValue, const Vector<SVGPa
thSegType>& pathSegTypes) | |
| 344 : m_currentIndex(0) | |
| 345 , m_list(listValue) | |
| 346 , m_segmentTypes(pathSegTypes) | |
| 347 { | |
| 348 ASSERT(m_list.length() == m_segmentTypes.size()); | |
| 349 } | |
| 350 | |
| 351 private: | |
| 352 bool hasMoreData() const override; | |
| 353 SVGPathSegType peekSegmentType() override; | |
| 354 PathSegmentData parseSegment() override; | |
| 355 | |
| 356 SubPathCoordinates m_normalizationState; | |
| 357 size_t m_currentIndex; | |
| 358 const InterpolableList& m_list; | |
| 359 const Vector<SVGPathSegType>& m_segmentTypes; | |
| 360 }; | |
| 361 | |
| 362 bool InterpolatedPathSource::hasMoreData() const | |
| 363 { | |
| 364 return m_currentIndex < m_list.length(); | |
| 365 } | |
| 366 | |
| 367 SVGPathSegType InterpolatedPathSource::peekSegmentType() | |
| 368 { | |
| 369 ASSERT(hasMoreData()); | |
| 370 return m_segmentTypes.at(m_currentIndex); | |
| 371 } | |
| 372 | |
| 373 PathSegmentData InterpolatedPathSource::parseSegment() | |
| 374 { | |
| 375 PathSegmentData segment = pathSegFromInterpolableValue(*m_list.get(m_current
Index), m_segmentTypes.at(m_currentIndex), m_normalizationState); | |
| 376 ++m_currentIndex; | |
| 377 return segment; | |
| 378 } | |
| 379 | |
| 380 size_t countPathCommands(const SVGPathByteStream& path) | |
| 381 { | |
| 382 size_t count = 0; | |
| 383 SVGPathByteStreamSource pathSource(path); | |
| 384 while (pathSource.hasMoreData()) { | |
| 385 pathSource.parseSegment(); | |
| 386 ++count; | |
| 387 } | |
| 388 return count; | |
| 389 } | |
| 390 | |
| 391 } // namespace | |
| 392 | |
| 393 PassRefPtr<PathSVGInterpolation> PathSVGInterpolation::maybeCreate(SVGPropertyBa
se* start, SVGPropertyBase* end, PassRefPtrWillBeRawPtr<SVGAnimatedPropertyBase>
attribute) | |
| 394 { | |
| 395 ASSERT(start->type() == SVGPath::classType()); | |
| 396 ASSERT(end->type() == SVGPath::classType()); | |
| 397 | |
| 398 const SVGPathByteStream& startPath = static_cast<SVGPath*>(start)->byteStrea
m(); | |
| 399 const SVGPathByteStream& endPath = static_cast<SVGPath*>(end)->byteStream(); | |
| 400 | |
| 401 if (startPath.size() != endPath.size()) | |
| 402 return nullptr; | |
| 403 | |
| 404 size_t length = countPathCommands(startPath); | |
| 405 | |
| 406 SVGPathByteStreamSource startPathSource(startPath); | |
| 407 SVGPathByteStreamSource endPathSource(endPath); | |
| 408 | |
| 409 Vector<SVGPathSegType> pathSegTypes(length); | |
| 410 OwnPtr<InterpolableList> startValue = InterpolableList::create(length); | |
| 411 OwnPtr<InterpolableList> endValue = InterpolableList::create(length); | |
| 412 SubPathCoordinates startCoordinates; | |
| 413 SubPathCoordinates endCoordinates; | |
| 414 size_t i = 0; | |
| 415 while (startPathSource.hasMoreData()) { | |
| 416 if (toAbsolutePathSegType(startPathSource.peekSegmentType()) != toAbsolu
tePathSegType(endPathSource.peekSegmentType())) | |
| 417 return nullptr; | |
| 418 | |
| 419 // Like Firefox SMIL, we use the final path seg type. | |
| 420 const PathSegmentData startSeg = startPathSource.parseSegment(); | |
| 421 startValue->set(i, pathSegToInterpolableValue(startSeg, startCoordinates
, nullptr)); | |
| 422 | |
| 423 const PathSegmentData endSeg = endPathSource.parseSegment(); | |
| 424 endValue->set(i, pathSegToInterpolableValue(endSeg, endCoordinates, &pat
hSegTypes.at(i))); | |
| 425 | |
| 426 ++i; | |
| 427 } | |
| 428 ASSERT(!endPathSource.hasMoreData()); | |
| 429 ASSERT(i == length); | |
| 430 | |
| 431 return adoptRef(new PathSVGInterpolation(startValue.release(), endValue.rele
ase(), attribute, pathSegTypes)); | |
| 432 } | |
| 433 | |
| 434 PassRefPtrWillBeRawPtr<SVGPropertyBase> PathSVGInterpolation::fromInterpolableVa
lue(const InterpolableValue& value, const Vector<SVGPathSegType>& pathSegTypes) | |
| 435 { | |
| 436 RefPtrWillBeRawPtr<SVGPath> result = SVGPath::create(); | |
| 437 InterpolatedPathSource source(toInterpolableList(value), pathSegTypes); | |
| 438 SVGPathByteStreamBuilder builder(result->mutableByteStream()); | |
| 439 SVGPathParser parser(&source, &builder); | |
| 440 parser.parsePathDataFromSource(UnalteredParsing, false); | |
| 441 return result.release(); | |
| 442 } | |
| 443 | |
| 444 PassRefPtrWillBeRawPtr<SVGPropertyBase> PathSVGInterpolation::interpolatedValue(
SVGElement&) const | |
| 445 { | |
| 446 return fromInterpolableValue(*m_cachedValue, m_pathSegTypes); | |
| 447 } | |
| 448 | |
| 449 } | |
| OLD | NEW |