Convert much of the SVG string parsing code to use Optional based return values rathe...
authorweinig@apple.com <weinig@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 21 Jun 2020 22:47:09 +0000 (22:47 +0000)
committerweinig@apple.com <weinig@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 21 Jun 2020 22:47:09 +0000 (22:47 +0000)
https://bugs.webkit.org/show_bug.cgi?id=213416

Reviewed by Darin Adler.

Update SVG parsers to use Optional style return programming rather than out parameters.
To make things even nicer, SVGPathSource based parsers now have a type per-parse function,
which makes working with them much easier. In the future, we should consider exanding these
new types to be used by SVGPathConsumer family of classes as well.

* WebCore.xcodeproj/project.pbxproj:
Add SVGPathSegValue.h, which was missing from the Xcode project.

* svg/SVGAngleValue.cpp:
(WebCore::parseAngleType):
(WebCore::SVGAngleValue::setValueAsString):
Adopt updated parseNumber() function, and do a drive by removal of an easy to remove
upconvertedCharacters.

* svg/SVGAnimateMotionElement.cpp:
(WebCore::SVGAnimateMotionElement::calculateToAtEndOfDurationValue):
(WebCore::SVGAnimateMotionElement::calculateFromAndToValues):
(WebCore::SVGAnimateMotionElement::calculateFromAndByValues):
(WebCore::SVGAnimateMotionElement::calculateDistance):
Now uses new parsePoint() function. Using Optional.valueOr() where
the old code would have had parsePoint() doing the clearing.

* svg/SVGAnimationElement.cpp:
(WebCore::parseKeySplines):
Now returns an Optional<Vector<UnitBezier>>.
(WebCore::SVGAnimationElement::parseAttribute):
Now uses new parseKeySplines, and does an explicit clear on parse failure (old code
did it implicitly in the parse function).

* svg/SVGFEConvolveMatrixElement.cpp:
(WebCore::SVGFEConvolveMatrixElement::parseAttribute):
* svg/SVGFEDiffuseLightingElement.cpp:
(WebCore::SVGFEDiffuseLightingElement::parseAttribute):
* svg/SVGFEDropShadowElement.cpp:
(WebCore::SVGFEDropShadowElement::parseAttribute):
* svg/SVGFEGaussianBlurElement.cpp:
(WebCore::SVGFEGaussianBlurElement::parseAttribute):
* svg/SVGFEMorphologyElement.cpp:
(WebCore::SVGFEMorphologyElement::parseAttribute):
* svg/SVGFESpecularLightingElement.cpp:
(WebCore::SVGFESpecularLightingElement::parseAttribute):
* svg/SVGFETurbulenceElement.cpp:
(WebCore::SVGFETurbulenceElement::parseAttribute):
Adopt Optional based parseNumberOptionalNumber.

* svg/SVGImageElement.cpp:
(WebCore::SVGImageElement::parseAttribute):
* svg/SVGFEImageElement.cpp:
(WebCore::SVGFEImageElement::parseAttribute):
Simplify by using the SVGPreserveAspectRatioValue constructor
which calls parse. No need for three lines.

* svg/SVGFitToViewBox.cpp:
(WebCore::SVGFitToViewBox::parseAttribute):
Adopt new Optional based parseViewBox.
Simplify by using the SVGPreserveAspectRatioValue constructor
which calls parse. No need for three lines.

(WebCore::SVGFitToViewBox::parseViewBox):
Convert to be Optional based, and adopt new parseNumber functions.

* svg/SVGFitToViewBox.h:
Updated signatures for new Optional based functions.

* svg/SVGGlyphRefElement.cpp:
(WebCore::parseFloat):
Adopt Optional based parseNumber.

* svg/SVGHKernElement.cpp:
(WebCore::SVGHKernElement::buildHorizontalKerningPair const):
* svg/SVGHKernElement.h:
* svg/SVGVKernElement.cpp:
(WebCore::SVGVKernElement::buildVerticalKerningPair const):
* svg/SVGVKernElement.h:
Convert to be Optional based. Update a few callers to use makeString.

* svg/SVGToOTFFontConversion.cpp:
(WebCore::SVGToOTFFontConverter::addKerningPair const):
(WebCore::SVGToOTFFontConverter::appendKERNSubtable):
Adopt new Optional based kerning pair builders. Add some moves
to avoid some copies.

* svg/SVGLengthValue.cpp:
(WebCore::SVGLengthValue::setValueAsString):
Adopt Optional based parseNumber.

* svg/SVGNumberList.h:
(WebCore::SVGNumberList::parse):
Adopt Optional based parseNumber.

* svg/SVGParserUtilities.cpp:
(WebCore::genericParseNumber):
(WebCore::parseNumber):
(WebCore::genericParseArcFlag):
(WebCore::parseArcFlag):
(WebCore::parseNumberOptionalNumber):
(WebCore::parsePoint):
(WebCore::parseRect):
(WebCore::parseGlyphName):
(WebCore::parseUnicodeRange):
(WebCore::parseKerningUnicodeString):
(WebCore::genericParseFloatPoint):
(WebCore::parseFloatPoint):
(WebCore::parseSVGNumber): Deleted.
(WebCore::parseNumberFromString): Deleted.
(WebCore::parseDelimitedString): Deleted.
(WebCore::parseFloatPoint2): Deleted.
(WebCore::parseFloatPoint3): Deleted.
* svg/SVGParserUtilities.h:
(WebCore::isSVGSpace):
(WebCore::skipOptionalSVGSpaces):
(WebCore::skipOptionalSVGSpacesOrDelimiter):
- Converts parse* functions to return Optional values rather than using outparameters.
- Removes unused parseSVGNumber and parseDelimitedString.
- Removes parseFloatPoint2 and parseFloatPoint3. They weren't useful enough to keep around.
- Renames parseNumberFromString to parseNumber. The argument is a String, it's clear enough.
- Replace boolean skip parameters with new enum SuffixSkippingPolicy.
- Make parseFloatPoint have two overloads rather than being templatized to be consistent.

* svg/SVGPathBlender.cpp:
(WebCore::pullFromSources):
(WebCore::SVGPathBlender::blendMoveToSegment):
(WebCore::SVGPathBlender::blendLineToSegment):
(WebCore::SVGPathBlender::blendLineToHorizontalSegment):
(WebCore::SVGPathBlender::blendLineToVerticalSegment):
(WebCore::SVGPathBlender::blendCurveToCubicSegment):
(WebCore::SVGPathBlender::blendCurveToCubicSmoothSegment):
(WebCore::SVGPathBlender::blendCurveToQuadraticSegment):
(WebCore::SVGPathBlender::blendCurveToQuadraticSmoothSegment):
(WebCore::SVGPathBlender::blendArcToSegment):
(WebCore::SVGPathBlender::canBlendPaths):
(WebCore::SVGPathBlender::blendAnimatedPath):
Update to adopt new SVGPathSource interface. Added pullFromSources helper
which substantially simplifies pulling from both the from and to source at
the same time and is now possible due to all the SVGPathSource functions
returning the segment types rather than taking them as out parameters.

* svg/SVGPathByteStreamSource.cpp:
(WebCore::SVGPathByteStreamSource::nextCommand):
(WebCore::SVGPathByteStreamSource::parseSVGSegmentType):
(WebCore::SVGPathByteStreamSource::parseMoveToSegment):
(WebCore::SVGPathByteStreamSource::parseLineToSegment):
(WebCore::SVGPathByteStreamSource::parseLineToHorizontalSegment):
(WebCore::SVGPathByteStreamSource::parseLineToVerticalSegment):
(WebCore::SVGPathByteStreamSource::parseCurveToCubicSegment):
(WebCore::SVGPathByteStreamSource::parseCurveToCubicSmoothSegment):
(WebCore::SVGPathByteStreamSource::parseCurveToQuadraticSegment):
(WebCore::SVGPathByteStreamSource::parseCurveToQuadraticSmoothSegment):
(WebCore::SVGPathByteStreamSource::parseArcToSegment):
* svg/SVGPathByteStreamSource.h:
Adopt new SVGPathSource interface.

* svg/SVGPathParser.cpp:
(WebCore::SVGPathParser::parseMoveToSegment):
(WebCore::SVGPathParser::parseLineToSegment):
(WebCore::SVGPathParser::parseLineToHorizontalSegment):
(WebCore::SVGPathParser::parseLineToVerticalSegment):
(WebCore::SVGPathParser::parseCurveToCubicSegment):
(WebCore::SVGPathParser::parseCurveToCubicSmoothSegment):
(WebCore::SVGPathParser::parseCurveToQuadraticSegment):
(WebCore::SVGPathParser::parseCurveToQuadraticSmoothSegment):
(WebCore::SVGPathParser::parseArcToSegment):
(WebCore::SVGPathParser::parsePathData):
Adapt to new SVGPathSource interface. Code reads a bit nicer now
that we don't have a ton of local variables in each method. Could
be made nicer in the future by adopting Segment types in the path
consumer code.

* svg/SVGPathSegListSource.cpp:
(WebCore::SVGPathSegListSource::nextCommand):
(WebCore::SVGPathSegListSource::parseSVGSegmentType):
(WebCore::SVGPathSegListSource::parseMoveToSegment):
(WebCore::SVGPathSegListSource::parseLineToSegment):
(WebCore::SVGPathSegListSource::parseLineToHorizontalSegment):
(WebCore::SVGPathSegListSource::parseLineToVerticalSegment):
(WebCore::SVGPathSegListSource::parseCurveToCubicSegment):
(WebCore::SVGPathSegListSource::parseCurveToCubicSmoothSegment):
(WebCore::SVGPathSegListSource::parseCurveToQuadraticSegment):
(WebCore::SVGPathSegListSource::parseCurveToQuadraticSmoothSegment):
(WebCore::SVGPathSegListSource::parseArcToSegment):
* svg/SVGPathSegListSource.h:
Adopt new SVGPathSource interface.

* svg/SVGPathSource.h:
Update interface to return Optionals, with a specific type for
segment kind that be parsed.

* svg/SVGPathStringSource.cpp:
(WebCore::nextCommandHelper):
(WebCore::SVGPathStringSource::nextCommand):
(WebCore::parseSVGSegmentTypeHelper):
(WebCore::SVGPathStringSource::parseSVGSegmentType):
(WebCore::SVGPathStringSource::parseMoveToSegment):
(WebCore::SVGPathStringSource::parseLineToSegment):
(WebCore::SVGPathStringSource::parseLineToHorizontalSegment):
(WebCore::SVGPathStringSource::parseLineToVerticalSegment):
(WebCore::SVGPathStringSource::parseCurveToCubicSegment):
(WebCore::SVGPathStringSource::parseCurveToCubicSmoothSegment):
(WebCore::SVGPathStringSource::parseCurveToQuadraticSegment):
(WebCore::SVGPathStringSource::parseCurveToQuadraticSmoothSegment):
(WebCore::SVGPathStringSource::parseArcToSegment):
(WebCore::parseArcToSegmentHelper): Deleted.
* svg/SVGPathStringSource.h:
Adopt new SVGPathSource interface. Replace out of line helpers (or use of things
like parseFloatPoint2) with generic lambda helpers, helping to keep the code more
localized.

* svg/SVGPointList.h:
(WebCore::SVGPointList::parse):
Adopt Optional based parseNumber.

* svg/SVGTransformList.h:
* svg/SVGTransformable.cpp:
(WebCore::parseTransformParamList):
(WebCore::SVGTransformable::parseTransformValue):
(WebCore::SVGTransformable::parseAndSkipType):
(WebCore::SVGTransformable::parseTransformType):
* svg/SVGTransformable.h:
Convert parseTransformValue/parseAndSkipType to be Optional based.

* svg/SVGViewSpec.cpp:
(WebCore::SVGViewSpec::parseViewSpec):
Adopt Optional based parseViewBox.

* svg/properties/SVGAnimationAdditiveValueFunctionImpl.h:
Adopt Optional based parseNumber.

* svg/properties/SVGPropertyTraits.h:
(WebCore::SVGPropertyTraits<float>::fromString):
(WebCore::SVGPropertyTraits<float>::parse):
(WebCore::SVGPropertyTraits<FloatPoint>::fromString):
(WebCore::SVGPropertyTraits<FloatPoint>::parse):
(WebCore::SVGPropertyTraits<FloatRect>::fromString):
(WebCore::SVGPropertyTraits<FloatRect>::parse):
Adopt Optional based parsers.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@263334 268f45cc-cd09-0410-ab3c-d52691b4dbfc

43 files changed:
Source/WebCore/ChangeLog
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/svg/SVGAngleValue.cpp
Source/WebCore/svg/SVGAnimateMotionElement.cpp
Source/WebCore/svg/SVGAnimateMotionElement.h
Source/WebCore/svg/SVGAnimationElement.cpp
Source/WebCore/svg/SVGFEConvolveMatrixElement.cpp
Source/WebCore/svg/SVGFEDiffuseLightingElement.cpp
Source/WebCore/svg/SVGFEDropShadowElement.cpp
Source/WebCore/svg/SVGFEGaussianBlurElement.cpp
Source/WebCore/svg/SVGFEImageElement.cpp
Source/WebCore/svg/SVGFEMorphologyElement.cpp
Source/WebCore/svg/SVGFESpecularLightingElement.cpp
Source/WebCore/svg/SVGFETurbulenceElement.cpp
Source/WebCore/svg/SVGFitToViewBox.cpp
Source/WebCore/svg/SVGFitToViewBox.h
Source/WebCore/svg/SVGGlyphRefElement.cpp
Source/WebCore/svg/SVGHKernElement.cpp
Source/WebCore/svg/SVGHKernElement.h
Source/WebCore/svg/SVGImageElement.cpp
Source/WebCore/svg/SVGLengthValue.cpp
Source/WebCore/svg/SVGNumberList.h
Source/WebCore/svg/SVGParserUtilities.cpp
Source/WebCore/svg/SVGParserUtilities.h
Source/WebCore/svg/SVGPathBlender.cpp
Source/WebCore/svg/SVGPathByteStreamSource.cpp
Source/WebCore/svg/SVGPathByteStreamSource.h
Source/WebCore/svg/SVGPathParser.cpp
Source/WebCore/svg/SVGPathSegListSource.cpp
Source/WebCore/svg/SVGPathSegListSource.h
Source/WebCore/svg/SVGPathSource.h
Source/WebCore/svg/SVGPathStringSource.cpp
Source/WebCore/svg/SVGPathStringSource.h
Source/WebCore/svg/SVGPointList.h
Source/WebCore/svg/SVGToOTFFontConversion.cpp
Source/WebCore/svg/SVGTransformList.h
Source/WebCore/svg/SVGTransformable.cpp
Source/WebCore/svg/SVGTransformable.h
Source/WebCore/svg/SVGVKernElement.cpp
Source/WebCore/svg/SVGVKernElement.h
Source/WebCore/svg/SVGViewSpec.cpp
Source/WebCore/svg/properties/SVGAnimationAdditiveValueFunctionImpl.h
Source/WebCore/svg/properties/SVGPropertyTraits.h

index 6247d87..dc8461c 100644 (file)
@@ -1,5 +1,249 @@
 2020-06-21  Sam Weinig  <weinig@apple.com>
 
+        Convert much of the SVG string parsing code to use Optional based return values rather than out-parameters
+        https://bugs.webkit.org/show_bug.cgi?id=213416
+
+        Reviewed by Darin Adler.
+
+        Update SVG parsers to use Optional style return programming rather than out parameters.
+        To make things even nicer, SVGPathSource based parsers now have a type per-parse function,
+        which makes working with them much easier. In the future, we should consider exanding these
+        new types to be used by SVGPathConsumer family of classes as well.
+
+        * WebCore.xcodeproj/project.pbxproj:
+        Add SVGPathSegValue.h, which was missing from the Xcode project.
+
+        * svg/SVGAngleValue.cpp:
+        (WebCore::parseAngleType): 
+        (WebCore::SVGAngleValue::setValueAsString):
+        Adopt updated parseNumber() function, and do a drive by removal of an easy to remove
+        upconvertedCharacters.
+        * svg/SVGAnimateMotionElement.cpp:
+        (WebCore::SVGAnimateMotionElement::calculateToAtEndOfDurationValue):
+        (WebCore::SVGAnimateMotionElement::calculateFromAndToValues):
+        (WebCore::SVGAnimateMotionElement::calculateFromAndByValues):
+        (WebCore::SVGAnimateMotionElement::calculateDistance):
+        Now uses new parsePoint() function. Using Optional.valueOr() where
+        the old code would have had parsePoint() doing the clearing.
+    
+        * svg/SVGAnimationElement.cpp:
+        (WebCore::parseKeySplines):
+        Now returns an Optional<Vector<UnitBezier>>.
+        (WebCore::SVGAnimationElement::parseAttribute):
+        Now uses new parseKeySplines, and does an explicit clear on parse failure (old code 
+        did it implicitly in the parse function).
+
+        * svg/SVGFEConvolveMatrixElement.cpp:
+        (WebCore::SVGFEConvolveMatrixElement::parseAttribute):
+        * svg/SVGFEDiffuseLightingElement.cpp:
+        (WebCore::SVGFEDiffuseLightingElement::parseAttribute):
+        * svg/SVGFEDropShadowElement.cpp:
+        (WebCore::SVGFEDropShadowElement::parseAttribute):
+        * svg/SVGFEGaussianBlurElement.cpp:
+        (WebCore::SVGFEGaussianBlurElement::parseAttribute):
+        * svg/SVGFEMorphologyElement.cpp:
+        (WebCore::SVGFEMorphologyElement::parseAttribute):
+        * svg/SVGFESpecularLightingElement.cpp:
+        (WebCore::SVGFESpecularLightingElement::parseAttribute):
+        * svg/SVGFETurbulenceElement.cpp:
+        (WebCore::SVGFETurbulenceElement::parseAttribute):
+        Adopt Optional based parseNumberOptionalNumber.
+
+        * svg/SVGImageElement.cpp:
+        (WebCore::SVGImageElement::parseAttribute):
+        * svg/SVGFEImageElement.cpp:
+        (WebCore::SVGFEImageElement::parseAttribute):
+        Simplify by using the SVGPreserveAspectRatioValue constructor
+        which calls parse. No need for three lines.
+
+        * svg/SVGFitToViewBox.cpp:
+        (WebCore::SVGFitToViewBox::parseAttribute):
+        Adopt new Optional based parseViewBox.
+        Simplify by using the SVGPreserveAspectRatioValue constructor
+        which calls parse. No need for three lines.
+
+        (WebCore::SVGFitToViewBox::parseViewBox):
+        Convert to be Optional based, and adopt new parseNumber functions.
+
+        * svg/SVGFitToViewBox.h:
+        Updated signatures for new Optional based functions.
+
+        * svg/SVGGlyphRefElement.cpp:
+        (WebCore::parseFloat):
+        Adopt Optional based parseNumber.
+        
+        * svg/SVGHKernElement.cpp:
+        (WebCore::SVGHKernElement::buildHorizontalKerningPair const):
+        * svg/SVGHKernElement.h:
+        * svg/SVGVKernElement.cpp:
+        (WebCore::SVGVKernElement::buildVerticalKerningPair const):
+        * svg/SVGVKernElement.h:
+        Convert to be Optional based. Update a few callers to use makeString.
+
+        * svg/SVGToOTFFontConversion.cpp:
+        (WebCore::SVGToOTFFontConverter::addKerningPair const):
+        (WebCore::SVGToOTFFontConverter::appendKERNSubtable):
+        Adopt new Optional based kerning pair builders. Add some moves
+        to avoid some copies.
+
+        * svg/SVGLengthValue.cpp:
+        (WebCore::SVGLengthValue::setValueAsString):
+        Adopt Optional based parseNumber.
+
+        * svg/SVGNumberList.h:
+        (WebCore::SVGNumberList::parse):
+        Adopt Optional based parseNumber.
+
+        * svg/SVGParserUtilities.cpp:
+        (WebCore::genericParseNumber):
+        (WebCore::parseNumber):
+        (WebCore::genericParseArcFlag):
+        (WebCore::parseArcFlag):
+        (WebCore::parseNumberOptionalNumber):
+        (WebCore::parsePoint):
+        (WebCore::parseRect):
+        (WebCore::parseGlyphName):
+        (WebCore::parseUnicodeRange):
+        (WebCore::parseKerningUnicodeString):
+        (WebCore::genericParseFloatPoint):
+        (WebCore::parseFloatPoint):
+        (WebCore::parseSVGNumber): Deleted.
+        (WebCore::parseNumberFromString): Deleted.
+        (WebCore::parseDelimitedString): Deleted.
+        (WebCore::parseFloatPoint2): Deleted.
+        (WebCore::parseFloatPoint3): Deleted.
+        * svg/SVGParserUtilities.h:
+        (WebCore::isSVGSpace):
+        (WebCore::skipOptionalSVGSpaces):
+        (WebCore::skipOptionalSVGSpacesOrDelimiter):
+        - Converts parse* functions to return Optional values rather than using outparameters.
+        - Removes unused parseSVGNumber and parseDelimitedString.
+        - Removes parseFloatPoint2 and parseFloatPoint3. They weren't useful enough to keep around.
+        - Renames parseNumberFromString to parseNumber. The argument is a String, it's clear enough.
+        - Replace boolean skip parameters with new enum SuffixSkippingPolicy.
+        - Make parseFloatPoint have two overloads rather than being templatized to be consistent.
+
+
+        * svg/SVGPathBlender.cpp:
+        (WebCore::pullFromSources):
+        (WebCore::SVGPathBlender::blendMoveToSegment):
+        (WebCore::SVGPathBlender::blendLineToSegment):
+        (WebCore::SVGPathBlender::blendLineToHorizontalSegment):
+        (WebCore::SVGPathBlender::blendLineToVerticalSegment):
+        (WebCore::SVGPathBlender::blendCurveToCubicSegment):
+        (WebCore::SVGPathBlender::blendCurveToCubicSmoothSegment):
+        (WebCore::SVGPathBlender::blendCurveToQuadraticSegment):
+        (WebCore::SVGPathBlender::blendCurveToQuadraticSmoothSegment):
+        (WebCore::SVGPathBlender::blendArcToSegment):
+        (WebCore::SVGPathBlender::canBlendPaths):
+        (WebCore::SVGPathBlender::blendAnimatedPath):
+        Update to adopt new SVGPathSource interface. Added pullFromSources helper
+        which substantially simplifies pulling from both the from and to source at
+        the same time and is now possible due to all the SVGPathSource functions
+        returning the segment types rather than taking them as out parameters.
+
+        * svg/SVGPathByteStreamSource.cpp:
+        (WebCore::SVGPathByteStreamSource::nextCommand):
+        (WebCore::SVGPathByteStreamSource::parseSVGSegmentType):
+        (WebCore::SVGPathByteStreamSource::parseMoveToSegment):
+        (WebCore::SVGPathByteStreamSource::parseLineToSegment):
+        (WebCore::SVGPathByteStreamSource::parseLineToHorizontalSegment):
+        (WebCore::SVGPathByteStreamSource::parseLineToVerticalSegment):
+        (WebCore::SVGPathByteStreamSource::parseCurveToCubicSegment):
+        (WebCore::SVGPathByteStreamSource::parseCurveToCubicSmoothSegment):
+        (WebCore::SVGPathByteStreamSource::parseCurveToQuadraticSegment):
+        (WebCore::SVGPathByteStreamSource::parseCurveToQuadraticSmoothSegment):
+        (WebCore::SVGPathByteStreamSource::parseArcToSegment):
+        * svg/SVGPathByteStreamSource.h:
+        Adopt new SVGPathSource interface.
+
+        * svg/SVGPathParser.cpp:
+        (WebCore::SVGPathParser::parseMoveToSegment):
+        (WebCore::SVGPathParser::parseLineToSegment):
+        (WebCore::SVGPathParser::parseLineToHorizontalSegment):
+        (WebCore::SVGPathParser::parseLineToVerticalSegment):
+        (WebCore::SVGPathParser::parseCurveToCubicSegment):
+        (WebCore::SVGPathParser::parseCurveToCubicSmoothSegment):
+        (WebCore::SVGPathParser::parseCurveToQuadraticSegment):
+        (WebCore::SVGPathParser::parseCurveToQuadraticSmoothSegment):
+        (WebCore::SVGPathParser::parseArcToSegment):
+        (WebCore::SVGPathParser::parsePathData):
+        Adapt to new SVGPathSource interface. Code reads a bit nicer now
+        that we don't have a ton of local variables in each method. Could
+        be made nicer in the future by adopting Segment types in the path
+        consumer code.
+
+        * svg/SVGPathSegListSource.cpp:
+        (WebCore::SVGPathSegListSource::nextCommand):
+        (WebCore::SVGPathSegListSource::parseSVGSegmentType):
+        (WebCore::SVGPathSegListSource::parseMoveToSegment):
+        (WebCore::SVGPathSegListSource::parseLineToSegment):
+        (WebCore::SVGPathSegListSource::parseLineToHorizontalSegment):
+        (WebCore::SVGPathSegListSource::parseLineToVerticalSegment):
+        (WebCore::SVGPathSegListSource::parseCurveToCubicSegment):
+        (WebCore::SVGPathSegListSource::parseCurveToCubicSmoothSegment):
+        (WebCore::SVGPathSegListSource::parseCurveToQuadraticSegment):
+        (WebCore::SVGPathSegListSource::parseCurveToQuadraticSmoothSegment):
+        (WebCore::SVGPathSegListSource::parseArcToSegment):
+        * svg/SVGPathSegListSource.h:
+        Adopt new SVGPathSource interface.
+
+        * svg/SVGPathSource.h:
+        Update interface to return Optionals, with a specific type for
+        segment kind that be parsed.
+
+        * svg/SVGPathStringSource.cpp:
+        (WebCore::nextCommandHelper):
+        (WebCore::SVGPathStringSource::nextCommand):
+        (WebCore::parseSVGSegmentTypeHelper):
+        (WebCore::SVGPathStringSource::parseSVGSegmentType):
+        (WebCore::SVGPathStringSource::parseMoveToSegment):
+        (WebCore::SVGPathStringSource::parseLineToSegment):
+        (WebCore::SVGPathStringSource::parseLineToHorizontalSegment):
+        (WebCore::SVGPathStringSource::parseLineToVerticalSegment):
+        (WebCore::SVGPathStringSource::parseCurveToCubicSegment):
+        (WebCore::SVGPathStringSource::parseCurveToCubicSmoothSegment):
+        (WebCore::SVGPathStringSource::parseCurveToQuadraticSegment):
+        (WebCore::SVGPathStringSource::parseCurveToQuadraticSmoothSegment):
+        (WebCore::SVGPathStringSource::parseArcToSegment):
+        (WebCore::parseArcToSegmentHelper): Deleted.
+        * svg/SVGPathStringSource.h:
+        Adopt new SVGPathSource interface. Replace out of line helpers (or use of things
+        like parseFloatPoint2) with generic lambda helpers, helping to keep the code more
+        localized.
+    
+        * svg/SVGPointList.h:
+        (WebCore::SVGPointList::parse):
+        Adopt Optional based parseNumber.
+
+        * svg/SVGTransformList.h:
+        * svg/SVGTransformable.cpp:
+        (WebCore::parseTransformParamList):
+        (WebCore::SVGTransformable::parseTransformValue):
+        (WebCore::SVGTransformable::parseAndSkipType):
+        (WebCore::SVGTransformable::parseTransformType):
+        * svg/SVGTransformable.h:
+        Convert parseTransformValue/parseAndSkipType to be Optional based.
+
+        * svg/SVGViewSpec.cpp:
+        (WebCore::SVGViewSpec::parseViewSpec):
+        Adopt Optional based parseViewBox.
+
+        * svg/properties/SVGAnimationAdditiveValueFunctionImpl.h:
+        Adopt Optional based parseNumber.
+
+        * svg/properties/SVGPropertyTraits.h:
+        (WebCore::SVGPropertyTraits<float>::fromString):
+        (WebCore::SVGPropertyTraits<float>::parse):
+        (WebCore::SVGPropertyTraits<FloatPoint>::fromString):
+        (WebCore::SVGPropertyTraits<FloatPoint>::parse):
+        (WebCore::SVGPropertyTraits<FloatRect>::fromString):
+        (WebCore::SVGPropertyTraits<FloatRect>::parse):
+        Adopt Optional based parsers.
+
+2020-06-21  Sam Weinig  <weinig@apple.com>
+
         Convert DateComponents parsing code to use Optional based return values rather than out-parameters
         https://bugs.webkit.org/show_bug.cgi?id=213440
 
index e63eab6..62d0f95 100644 (file)
                7C83DE851D04CBD400FEBCF3 /* SpringSolver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SpringSolver.h; sourceTree = "<group>"; };
                7C85B20122FB04850030684F /* WHLSLUnnamedType.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = WHLSLUnnamedType.cpp; sourceTree = "<group>"; };
                7C85B20422FB06320030684F /* WHLSLUnnamedTypeHash.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WHLSLUnnamedTypeHash.h; sourceTree = "<group>"; };
+               7C8824C4249D7B0500ED8FC4 /* SVGPathSegValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SVGPathSegValue.h; sourceTree = "<group>"; };
                7C8E34921E4A338E0054CE23 /* JSDOMConvertAny.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSDOMConvertAny.h; sourceTree = "<group>"; };
                7C8E34931E4A338E0054CE23 /* JSDOMConvertBase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSDOMConvertBase.h; sourceTree = "<group>"; };
                7C8E34941E4A338E0054CE23 /* JSDOMConvertBoolean.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSDOMConvertBoolean.h; sourceTree = "<group>"; };
                                84B6B976120F13E500B8EFAF /* SVGPathSegListSource.h */,
                                B22278EF0D00BF210071B782 /* SVGPathSegMovetoAbs.idl */,
                                B22278F00D00BF210071B782 /* SVGPathSegMovetoRel.idl */,
+                               7C8824C4249D7B0500ED8FC4 /* SVGPathSegValue.h */,
                                84300BD7120C9AD40021954A /* SVGPathSource.h */,
                                8419D2B7120E0C7600141F8F /* SVGPathStringBuilder.cpp */,
                                8419D2B8120E0C7600141F8F /* SVGPathStringBuilder.h */,
index 85a7198..c4e2e00 100644 (file)
@@ -80,7 +80,7 @@ String SVGAngleValue::valueAsString() const
     return String();
 }
 
-static inline SVGAngleValue::Type parseAngleType(const UChar* ptr, const UChar* end)
+template<typename CharacterType> static inline SVGAngleValue::Type parseAngleType(const CharacterType* ptr, const CharacterType* end)
 {
     switch (end - ptr) {
     case 0:
@@ -106,21 +106,27 @@ ExceptionOr<void> SVGAngleValue::setValueAsString(const String& value)
         return { };
     }
 
-    auto upconvertedCharacters = StringView(value).upconvertedCharacters();
-    const UChar* ptr = upconvertedCharacters;
-    const UChar* end = ptr + value.length();
+    auto helper = [&](auto* ptr, auto* end) -> ExceptionOr<void> {
+        auto valueInSpecifiedUnits = parseNumber(ptr, end, SuffixSkippingPolicy::DontSkip);
+        if (!valueInSpecifiedUnits)
+            return Exception { SyntaxError };
 
-    float valueInSpecifiedUnits = 0;
-    if (!parseNumber(ptr, end, valueInSpecifiedUnits, false))
-        return Exception { SyntaxError };
+        auto unitType = parseAngleType(ptr, end);
+        if (unitType == SVGAngleValue::SVG_ANGLETYPE_UNKNOWN)
+            return Exception { SyntaxError };
 
-    auto unitType = parseAngleType(ptr, end);
-    if (unitType == SVG_ANGLETYPE_UNKNOWN)
-        return Exception { SyntaxError };
+        m_unitType = unitType;
+        m_valueInSpecifiedUnits = *valueInSpecifiedUnits;
+        return { };
+    };
 
-    m_unitType = unitType;
-    m_valueInSpecifiedUnits = valueInSpecifiedUnits;
-    return { };
+    if (value.is8Bit()) {
+        auto* ptr = value.characters8();
+        return helper(ptr, ptr + value.length());
+    }
+
+    auto* ptr = value.characters16();
+    return helper(ptr, ptr + value.length());
 }
 
 ExceptionOr<void> SVGAngleValue::newValueSpecifiedUnits(unsigned short unitType, float valueInSpecifiedUnits)
index 25458c4..b745238 100644 (file)
@@ -46,7 +46,6 @@ using namespace SVGNames;
 
 inline SVGAnimateMotionElement::SVGAnimateMotionElement(const QualifiedName& tagName, Document& document)
     : SVGAnimationElement(tagName, document)
-    , m_hasToPointAtEndOfDuration(false)
 {
     setCalcMode(CalcMode::Paced);
     ASSERT(hasTagName(animateMotionTag));
@@ -161,27 +160,25 @@ void SVGAnimateMotionElement::stopAnimation(SVGElement* targetElement)
 
 bool SVGAnimateMotionElement::calculateToAtEndOfDurationValue(const String& toAtEndOfDurationString)
 {
-    parsePoint(toAtEndOfDurationString, m_toPointAtEndOfDuration);
-    m_hasToPointAtEndOfDuration = true;
+    m_toPointAtEndOfDuration = parsePoint(toAtEndOfDurationString).valueOr(FloatPoint { });
     return true;
 }
 
 bool SVGAnimateMotionElement::calculateFromAndToValues(const String& fromString, const String& toString)
 {
-    m_hasToPointAtEndOfDuration = false;
-    parsePoint(fromString, m_fromPoint);
-    parsePoint(toString, m_toPoint);
+    m_toPointAtEndOfDuration = WTF::nullopt;
+    m_fromPoint = parsePoint(fromString).valueOr(FloatPoint { });
+    m_toPoint = parsePoint(toString).valueOr(FloatPoint { });
     return true;
 }
     
 bool SVGAnimateMotionElement::calculateFromAndByValues(const String& fromString, const String& byString)
 {
-    m_hasToPointAtEndOfDuration = false;
+    m_toPointAtEndOfDuration = WTF::nullopt;
     if (animationMode() == AnimationMode::By && !isAdditive())
         return false;
-    parsePoint(fromString, m_fromPoint);
-    FloatPoint byPoint;
-    parsePoint(byString, byPoint);
+    m_fromPoint = parsePoint(fromString).valueOr(FloatPoint { });
+    auto byPoint = parsePoint(byString).valueOr(FloatPoint { });
     m_toPoint = FloatPoint(m_fromPoint.x() + byPoint.x(), m_fromPoint.y() + byPoint.y());
     return true;
 }
@@ -222,8 +219,8 @@ void SVGAnimateMotionElement::calculateAnimatedValue(float percentage, unsigned
 
     if (animationMode() != AnimationMode::Path) {
         FloatPoint toPointAtEndOfDuration = m_toPoint;
-        if (isAccumulated() && repeatCount && m_hasToPointAtEndOfDuration)
-            toPointAtEndOfDuration = m_toPointAtEndOfDuration;
+        if (isAccumulated() && repeatCount && m_toPointAtEndOfDuration)
+            toPointAtEndOfDuration = *m_toPointAtEndOfDuration;
 
         float animatedX = 0;
         animateAdditiveNumber(percentage, repeatCount, m_fromPoint.x(), m_toPoint.x(), toPointAtEndOfDuration.x(), animatedX);
@@ -275,13 +272,13 @@ void SVGAnimateMotionElement::applyResultsToTarget()
 
 Optional<float> SVGAnimateMotionElement::calculateDistance(const String& fromString, const String& toString)
 {
-    FloatPoint from;
-    FloatPoint to;
-    if (!parsePoint(fromString, from))
+    auto from = parsePoint(fromString);
+    if (!from)
         return { };
-    if (!parsePoint(toString, to))
+    auto to = parsePoint(toString);
+    if (!to)
         return { };
-    FloatSize diff = to - from;
+    auto diff = *to - *from;
     return std::hypot(diff.width(), diff.height());
 }
 
index 0ae9dd5..7b024f2 100644 (file)
@@ -58,14 +58,12 @@ private:
     RotateMode rotateMode() const;
     void buildTransformForProgress(AffineTransform*, float percentage);
 
-    bool m_hasToPointAtEndOfDuration;
-
     void updateAnimationMode() override;
 
     // Note: we do not support percentage values for to/from coords as the spec implies we should (opera doesn't either)
     FloatPoint m_fromPoint;
     FloatPoint m_toPoint;
-    FloatPoint m_toPointAtEndOfDuration;
+    Optional<FloatPoint> m_toPointAtEndOfDuration;
 
     Path m_path;
     Path m_animationPath;
index 45e45d5..3a802e1 100644 (file)
@@ -77,44 +77,37 @@ fail:
     result.clear();
 }
 
-static void parseKeySplines(const String& parse, Vector<UnitBezier>& result)
+static Optional<Vector<UnitBezier>> parseKeySplines(const StringView& parse)
 {
-    result.clear();
     if (parse.isEmpty())
-        return;
+        return WTF::nullopt;
 
-    auto upconvertedCharacters = StringView(parse).upconvertedCharacters();
+    auto upconvertedCharacters = parse.upconvertedCharacters();
     const UChar* cur = upconvertedCharacters;
     const UChar* end = cur + parse.length();
 
     skipOptionalSVGSpaces(cur, end);
 
+    Vector<UnitBezier> result;
+
     bool delimParsed = false;
     while (cur < end) {
         delimParsed = false;
-        float posA = 0;
-        if (!parseNumber(cur, end, posA)) {
-            result.clear();
-            return;
-        }
+        auto posA = parseNumber(cur, end);
+        if (!posA)
+            return WTF::nullopt;
 
-        float posB = 0;
-        if (!parseNumber(cur, end, posB)) {
-            result.clear();
-            return;
-        }
+        auto posB = parseNumber(cur, end);
+        if (!posB)
+            return WTF::nullopt;
 
-        float posC = 0;
-        if (!parseNumber(cur, end, posC)) {
-            result.clear();
-            return;
-        }
+        auto posC = parseNumber(cur, end);
+        if (!posC)
+            return WTF::nullopt;
 
-        float posD = 0;
-        if (!parseNumber(cur, end, posD, false)) {
-            result.clear();
-            return;
-        }
+        auto posD = parseNumber(cur, end, SuffixSkippingPolicy::DontSkip);
+        if (!posD)
+            return WTF::nullopt;
 
         skipOptionalSVGSpaces(cur, end);
 
@@ -122,12 +115,16 @@ static void parseKeySplines(const String& parse, Vector<UnitBezier>& result)
             delimParsed = true;
             cur++;
         }
+
         skipOptionalSVGSpaces(cur, end);
 
-        result.append(UnitBezier(posA, posB, posC, posD));
+        result.append(UnitBezier { *posA, *posB, *posC, *posD });
     }
+
     if (!(cur == end && !delimParsed))
-        result.clear();
+        return WTF::nullopt;
+
+    return result;
 }
 
 bool SVGAnimationElement::isSupportedAttribute(const QualifiedName& attrName)
@@ -180,7 +177,10 @@ void SVGAnimationElement::parseAttribute(const QualifiedName& name, const AtomSt
     }
 
     if (name == SVGNames::keySplinesAttr) {
-        parseKeySplines(value, m_keySplines);
+        if (auto keySplines = parseKeySplines(value))
+            m_keySplines = WTFMove(*keySplines);
+        else
+            m_keySplines.clear();
         return;
     }
 
index 43d8d6d..d4020de 100644 (file)
@@ -67,10 +67,10 @@ void SVGFEConvolveMatrixElement::parseAttribute(const QualifiedName& name, const
     }
 
     if (name == SVGNames::orderAttr) {
-        float x, y;
-        if (parseNumberOptionalNumber(value, x, y) && x >= 1 && y >= 1) {
-            m_orderX->setBaseValInternal(x);
-            m_orderY->setBaseValInternal(y);
+        auto result = parseNumberOptionalNumber(value);
+        if (result && result->first >= 1 && result->second >= 1) {
+            m_orderX->setBaseValInternal(result->first);
+            m_orderY->setBaseValInternal(result->second);
         } else
             document().accessSVGExtensions().reportWarning("feConvolveMatrix: problem parsing order=\"" + value + "\". Filtered element will not be displayed.");
         return;
@@ -115,10 +115,10 @@ void SVGFEConvolveMatrixElement::parseAttribute(const QualifiedName& name, const
     }
 
     if (name == SVGNames::kernelUnitLengthAttr) {
-        float x, y;
-        if (parseNumberOptionalNumber(value, x, y) && x > 0 && y > 0) {
-            m_kernelUnitLengthX->setBaseValInternal(x);
-            m_kernelUnitLengthY->setBaseValInternal(y);
+        auto result = parseNumberOptionalNumber(value);
+        if (result && result->first > 0 && result->second > 0) {
+            m_kernelUnitLengthX->setBaseValInternal(result->first);
+            m_kernelUnitLengthY->setBaseValInternal(result->second);
         } else
             document().accessSVGExtensions().reportWarning("feConvolveMatrix: problem parsing kernelUnitLength=\"" + value + "\". Filtered element will not be displayed.");
         return;
index dd0aee6..88688e8 100644 (file)
@@ -71,10 +71,9 @@ void SVGFEDiffuseLightingElement::parseAttribute(const QualifiedName& name, cons
     }
 
     if (name == SVGNames::kernelUnitLengthAttr) {
-        float x, y;
-        if (parseNumberOptionalNumber(value, x, y)) {
-            m_kernelUnitLengthX->setBaseValInternal(x);
-            m_kernelUnitLengthY->setBaseValInternal(y);
+        if (auto result = parseNumberOptionalNumber(value)) {
+            m_kernelUnitLengthX->setBaseValInternal(result->first);
+            m_kernelUnitLengthY->setBaseValInternal(result->second);
         }
         return;
     }
index 662703e..1abf4b4 100644 (file)
@@ -61,10 +61,9 @@ void SVGFEDropShadowElement::setStdDeviation(float x, float y)
 void SVGFEDropShadowElement::parseAttribute(const QualifiedName& name, const AtomString& value)
 {
     if (name == SVGNames::stdDeviationAttr) {
-        float x, y;
-        if (parseNumberOptionalNumber(value, x, y)) {
-            m_stdDeviationX->setBaseValInternal(x);
-            m_stdDeviationY->setBaseValInternal(y);
+        if (auto result = parseNumberOptionalNumber(value)) {
+            m_stdDeviationX->setBaseValInternal(result->first);
+            m_stdDeviationY->setBaseValInternal(result->second);
         }
         return;
     }
index 5ef6c37..99fec9b 100644 (file)
@@ -60,10 +60,9 @@ void SVGFEGaussianBlurElement::setStdDeviation(float x, float y)
 void SVGFEGaussianBlurElement::parseAttribute(const QualifiedName& name, const AtomString& value)
 {
     if (name == SVGNames::stdDeviationAttr) {
-        float x, y;
-        if (parseNumberOptionalNumber(value, x, y)) {
-            m_stdDeviationX->setBaseValInternal(x);
-            m_stdDeviationY->setBaseValInternal(y);
+        if (auto result = parseNumberOptionalNumber(value)) {
+            m_stdDeviationX->setBaseValInternal(result->first);
+            m_stdDeviationY->setBaseValInternal(result->second);
         }
         return;
     }
index c5c48ef..566d5e1 100644 (file)
@@ -117,9 +117,7 @@ void SVGFEImageElement::buildPendingResource()
 void SVGFEImageElement::parseAttribute(const QualifiedName& name, const AtomString& value)
 {
     if (name == SVGNames::preserveAspectRatioAttr) {
-        SVGPreserveAspectRatioValue preserveAspectRatio;
-        preserveAspectRatio.parse(value);
-        m_preserveAspectRatio->setBaseValInternal(preserveAspectRatio);
+        m_preserveAspectRatio->setBaseValInternal(SVGPreserveAspectRatioValue { value });
         return;
     }
 
index 05d8a52..0f5c47f 100644 (file)
@@ -71,10 +71,9 @@ void SVGFEMorphologyElement::parseAttribute(const QualifiedName& name, const Ato
     }
 
     if (name == SVGNames::radiusAttr) {
-        float x, y;
-        if (parseNumberOptionalNumber(value, x, y)) {
-            m_radiusX->setBaseValInternal(x);
-            m_radiusY->setBaseValInternal(y);
+        if (auto result = parseNumberOptionalNumber(value)) {
+            m_radiusX->setBaseValInternal(result->first);
+            m_radiusY->setBaseValInternal(result->second);
         }
         return;
     }
index 1e93823..bcd7925 100644 (file)
@@ -78,10 +78,9 @@ void SVGFESpecularLightingElement::parseAttribute(const QualifiedName& name, con
     }
 
     if (name == SVGNames::kernelUnitLengthAttr) {
-        float x, y;
-        if (parseNumberOptionalNumber(value, x, y)) {
-            m_kernelUnitLengthX->setBaseValInternal(x);
-            m_kernelUnitLengthY->setBaseValInternal(y);
+        if (auto result = parseNumberOptionalNumber(value)) {
+            m_kernelUnitLengthX->setBaseValInternal(result->first);
+            m_kernelUnitLengthY->setBaseValInternal(result->second);
         }
         return;
     }
index f2628bb..cf4984b 100644 (file)
@@ -67,10 +67,9 @@ void SVGFETurbulenceElement::parseAttribute(const QualifiedName& name, const Ato
     }
 
     if (name == SVGNames::baseFrequencyAttr) {
-        float x, y;
-        if (parseNumberOptionalNumber(value, x, y)) {
-            m_baseFrequencyX->setBaseValInternal(x);
-            m_baseFrequencyY->setBaseValInternal(y);
+        if (auto result = parseNumberOptionalNumber(value)) {
+            m_baseFrequencyX->setBaseValInternal(result->first);
+            m_baseFrequencyY->setBaseValInternal(result->second);
         }
         return;
     }
index 1f47d36..934c505 100644 (file)
@@ -66,73 +66,71 @@ void SVGFitToViewBox::reset()
 bool SVGFitToViewBox::parseAttribute(const QualifiedName& name, const AtomString& value)
 {
     if (name == SVGNames::viewBoxAttr) {
-        FloatRect viewBox;
-        if (!value.isNull() && parseViewBox(value, viewBox))
-            setViewBox(viewBox);
-        else
-            resetViewBox();
+        if (!value.isNull()) {
+            if (auto result = parseViewBox(value)) {
+                setViewBox(WTFMove(*result));
+                return true;
+            }
+        }
+        resetViewBox();
         return true;
     }
 
     if (name == SVGNames::preserveAspectRatioAttr) {
-        SVGPreserveAspectRatioValue preserveAspectRatio;
-        preserveAspectRatio.parse(value);
-        setPreserveAspectRatio(preserveAspectRatio);
+        setPreserveAspectRatio(SVGPreserveAspectRatioValue { value });
         return true;
     }
 
     return false;
 }
 
-bool SVGFitToViewBox::parseViewBox(const AtomString& value, FloatRect& viewBox)
+Optional<FloatRect> SVGFitToViewBox::parseViewBox(const StringView& value)
 {
-    auto upconvertedCharacters = StringView(value).upconvertedCharacters();
+    auto upconvertedCharacters = value.upconvertedCharacters();
     const UChar* characters = upconvertedCharacters;
-    return parseViewBox(characters, characters + value.length(), viewBox);
+    return parseViewBox(characters, characters + value.length());
 }
 
-bool SVGFitToViewBox::parseViewBox(const UChar*& c, const UChar* end, FloatRect& viewBox, bool validate)
+Optional<FloatRect> SVGFitToViewBox::parseViewBox(const UChar*& c, const UChar* end, bool validate)
 {
-    String str(c, end - c);
+    StringView str(c, end - c);
 
     skipOptionalSVGSpaces(c, end);
 
-    float x = 0.0f;
-    float y = 0.0f;
-    float width = 0.0f;
-    float height = 0.0f;
-    bool valid = parseNumber(c, end, x) && parseNumber(c, end, y) && parseNumber(c, end, width) && parseNumber(c, end, height, false);
+    auto x = parseNumber(c, end);
+    auto y = parseNumber(c, end);
+    auto width = parseNumber(c, end);
+    auto height = parseNumber(c, end, SuffixSkippingPolicy::DontSkip);
 
     if (validate) {
         Document& document = m_viewBox->contextElement()->document();
 
-        if (!valid) {
-            document.accessSVGExtensions().reportWarning("Problem parsing viewBox=\"" + str + "\"");
-            return false;
+        if (!x || !y || !width || !height) {
+            document.accessSVGExtensions().reportWarning(makeString("Problem parsing viewBox=\"", str, "\""));
+            return WTF::nullopt;
         }
 
         // Check that width is positive.
-        if (width < 0.0) {
+        if (*width < 0.0) {
             document.accessSVGExtensions().reportError("A negative value for ViewBox width is not allowed");
-            return false;
+            return WTF::nullopt;
         }
 
         // Check that height is positive.
-        if (height < 0.0) {
+        if (*height < 0.0) {
             document.accessSVGExtensions().reportError("A negative value for ViewBox height is not allowed");
-            return false;
+            return WTF::nullopt;
         }
 
         // Nothing should come after the last, fourth number.
         skipOptionalSVGSpaces(c, end);
         if (c < end) {
-            document.accessSVGExtensions().reportWarning("Problem parsing viewBox=\"" + str + "\"");
-            return false;
+            document.accessSVGExtensions().reportWarning(makeString("Problem parsing viewBox=\"", str, "\""));
+            return WTF::nullopt;
         }
     }
 
-    viewBox = { x, y, width, height };
-    return true;
+    return FloatRect { x.valueOr(0), y.valueOr(0), width.valueOr(0), height.valueOr(0) };
 }
 
 AffineTransform SVGFitToViewBox::viewBoxToViewTransform(const FloatRect& viewBoxRect, const SVGPreserveAspectRatioValue& preserveAspectRatio, float viewWidth, float viewHeight)
index 907d655..1d61553 100644 (file)
@@ -65,8 +65,8 @@ protected:
 
     void reset();
     bool parseAttribute(const QualifiedName&, const AtomString&);
-    bool parseViewBox(const AtomString& value, FloatRect& viewBox);
-    bool parseViewBox(const UChar*& start, const UChar* end, FloatRect& viewBox, bool validate = true);
+    Optional<FloatRect> parseViewBox(const StringView& value);
+    Optional<FloatRect> parseViewBox(const UChar*& start, const UChar* end, bool validate = true);
 
 private:
     Ref<SVGAnimatedRect> m_viewBox;
index 1c4568a..87672de 100644 (file)
@@ -58,10 +58,7 @@ bool SVGGlyphRefElement::hasValidGlyphElement(String& glyphName) const
 
 static float parseFloat(const AtomString& value)
 {
-    float result;
-    if (!parseNumberFromString(value, result))
-        return 0;
-    return result;
+    return parseNumber(value).valueOr(0);
 }
 
 void SVGGlyphRefElement::parseAttribute(const QualifiedName& name, const AtomString& value)
index 3ed04ae..56b2883 100644 (file)
@@ -44,24 +44,47 @@ Ref<SVGHKernElement> SVGHKernElement::create(const QualifiedName& tagName, Docum
     return adoptRef(*new SVGHKernElement(tagName, document));
 }
 
-bool SVGHKernElement::buildHorizontalKerningPair(SVGKerningPair& kerningPair) const
+Optional<SVGKerningPair> SVGHKernElement::buildHorizontalKerningPair() const
 {
+    // FIXME: Can this be shared with SVGVKernElement::buildVerticalKerningPair?
+
     auto& u1 = attributeWithoutSynchronization(SVGNames::u1Attr);
     auto& g1 = attributeWithoutSynchronization(SVGNames::g1Attr);
+    if (u1.isEmpty() && g1.isEmpty())
+        return WTF::nullopt;
+
     auto& u2 = attributeWithoutSynchronization(SVGNames::u2Attr);
     auto& g2 = attributeWithoutSynchronization(SVGNames::g2Attr);
-    if ((u1.isEmpty() && g1.isEmpty()) || (u2.isEmpty() && g2.isEmpty()))
-        return false;
+    if (u2.isEmpty() && g2.isEmpty())
+        return WTF::nullopt;
+
+    auto glyphName1 = parseGlyphName(g1);
+    if (!glyphName1)
+        return WTF::nullopt;
+    auto glyphName2 = parseGlyphName(g2);
+    if (!glyphName2)
+        return WTF::nullopt;
+    auto unicodeString1 = parseKerningUnicodeString(u1);
+    if (!unicodeString1)
+        return WTF::nullopt;
+    auto unicodeString2 = parseKerningUnicodeString(u2);
+    if (!unicodeString2)
+        return WTF::nullopt;
+
+    bool ok = false;
+    auto kerning = attributeWithoutSynchronization(SVGNames::kAttr).string().toFloat(&ok);
+    if (!ok)
+        return WTF::nullopt;
 
-    if (parseGlyphName(g1, kerningPair.glyphName1)
-        && parseGlyphName(g2, kerningPair.glyphName2)
-        && parseKerningUnicodeString(u1, kerningPair.unicodeRange1, kerningPair.unicodeName1)
-        && parseKerningUnicodeString(u2, kerningPair.unicodeRange2, kerningPair.unicodeName2)) {
-        bool ok = false;
-        kerningPair.kerning = attributeWithoutSynchronization(SVGNames::kAttr).string().toFloat(&ok);
-        return ok;
-    }
-    return false;
+    return SVGKerningPair {
+        WTFMove(unicodeString1->first),
+        WTFMove(unicodeString1->second),
+        WTFMove(*glyphName1),
+        WTFMove(unicodeString2->first),
+        WTFMove(unicodeString2->second),
+        WTFMove(*glyphName2),
+        kerning
+    };
 }
 
 }
index 747b032..e233e1c 100644 (file)
@@ -32,7 +32,7 @@ class SVGHKernElement final : public SVGElement {
 public:
     static Ref<SVGHKernElement> create(const QualifiedName&, Document&);
 
-    bool buildHorizontalKerningPair(SVGKerningPair& kerningPair) const;
+    Optional<SVGKerningPair> buildHorizontalKerningPair() const;
 
 private:
     SVGHKernElement(const QualifiedName&, Document&);
index d6a42b7..4fbd945 100644 (file)
@@ -69,9 +69,7 @@ bool SVGImageElement::hasSingleSecurityOrigin() const
 void SVGImageElement::parseAttribute(const QualifiedName& name, const AtomString& value)
 {
     if (name == SVGNames::preserveAspectRatioAttr) {
-        SVGPreserveAspectRatioValue preserveAspectRatio;
-        preserveAspectRatio.parse(value);
-        m_preserveAspectRatio->setBaseValInternal(preserveAspectRatio);
+        m_preserveAspectRatio->setBaseValInternal(SVGPreserveAspectRatioValue { value });
         return;
     }
 
index c3126e3..364921d 100644 (file)
@@ -291,12 +291,12 @@ ExceptionOr<void> SVGLengthValue::setValueAsString(const String& string)
     if (string.isEmpty())
         return { };
 
-    float convertedNumber = 0;
     auto upconvertedCharacters = StringView(string).upconvertedCharacters();
     const UChar* ptr = upconvertedCharacters;
     const UChar* end = ptr + string.length();
 
-    if (!parseNumber(ptr, end, convertedNumber, false))
+    auto convertedNumber = parseNumber(ptr, end, SuffixSkippingPolicy::DontSkip);
+    if (!convertedNumber)
         return Exception { SyntaxError };
 
     auto lengthType = parseLengthType(ptr, end);
@@ -304,7 +304,7 @@ ExceptionOr<void> SVGLengthValue::setValueAsString(const String& string)
         return Exception { SyntaxError };
 
     m_lengthType = lengthType;
-    m_valueInSpecifiedUnits = convertedNumber;
+    m_valueInSpecifiedUnits = *convertedNumber;
     return { };
 }
 
index 3cede35..26f3222 100644 (file)
@@ -54,7 +54,6 @@ public:
     {
         clearItems();
 
-        float number = 0;
         auto upconvertedCharacters = StringView(value).upconvertedCharacters();
         const UChar* ptr = upconvertedCharacters;
         const UChar* end = ptr + value.length();
@@ -62,9 +61,10 @@ public:
         // The spec (section 4.1) strangely doesn't allow leading whitespace.
         // We might choose to violate that intentionally.
         while (ptr < end) {
-            if (!parseNumber(ptr, end, number))
+            auto number = parseNumber(ptr, end);
+            if (!number)
                 break;
-            append(SVGNumber::create(number));
+            append(SVGNumber::create(*number));
         }
 
         return ptr == end;
index 98243fd..9b758d6 100644 (file)
@@ -40,19 +40,18 @@ template <typename FloatType> static inline bool isValidRange(const FloatType& x
 // We use this generic parseNumber function to allow the Path parsing code to work 
 // at a higher precision internally, without any unnecessary runtime cost or code
 // complexity.
-template <typename CharacterType, typename FloatType> static bool genericParseNumber(const CharacterType*& ptr, const CharacterType* end, FloatType& number, bool skip)
+// FIXME: Can this be shared/replaced with number parsing in WTF?
+template <typename CharacterType, typename FloatType = float> static Optional<FloatType> genericParseNumber(const CharacterType*& ptr, const CharacterType* end, SuffixSkippingPolicy skip = SuffixSkippingPolicy::Skip)
 {
-    FloatType integer, decimal, frac, exponent;
-    int sign, expsign;
+    FloatType number = 0;
+    FloatType integer = 0;
+    FloatType decimal = 0;
+    FloatType frac = 1;
+    FloatType exponent = 0;
+    int sign = 1;
+    int expsign = 1;
     const CharacterType* start = ptr;
 
-    exponent = 0;
-    integer = 0;
-    frac = 1;
-    decimal = 0;
-    sign = 1;
-    expsign = 1;
-
     // read the sign
     if (ptr < end && *ptr == '+')
         ptr++;
@@ -62,7 +61,7 @@ template <typename CharacterType, typename FloatType> static bool genericParseNu
     } 
     
     if (ptr == end || (!isASCIIDigit(*ptr) && *ptr != '.'))
-        return false;
+        return WTF::nullopt;
 
     // read the integer part, build right-to-left
     const CharacterType* ptrStartIntPart = ptr;
@@ -78,7 +77,7 @@ template <typename CharacterType, typename FloatType> static bool genericParseNu
         }
         // Bail out early if this overflows.
         if (!isValidRange(integer))
-            return false;
+            return WTF::nullopt;
     }
 
     if (ptr < end && *ptr == '.') { // read the decimals
@@ -86,7 +85,7 @@ template <typename CharacterType, typename FloatType> static bool genericParseNu
         
         // There must be a least one digit following the .
         if (ptr >= end || !isASCIIDigit(*ptr))
-            return false;
+            return WTF::nullopt;
         
         while (ptr < end && isASCIIDigit(*ptr))
             decimal += (*(ptr++) - '0') * (frac *= static_cast<FloatType>(0.1));
@@ -107,7 +106,7 @@ template <typename CharacterType, typename FloatType> static bool genericParseNu
         
         // There must be an exponent
         if (ptr >= end || !isASCIIDigit(*ptr))
-            return false;
+            return WTF::nullopt;
 
         while (ptr < end && isASCIIDigit(*ptr)) {
             exponent *= static_cast<FloatType>(10);
@@ -116,7 +115,7 @@ template <typename CharacterType, typename FloatType> static bool genericParseNu
         }
         // Make sure exponent is valid.
         if (!isValidRange(exponent) || exponent > std::numeric_limits<FloatType>::max_exponent)
-            return false;
+            return WTF::nullopt;
     }
 
     number = integer + decimal;
@@ -127,148 +126,153 @@ template <typename CharacterType, typename FloatType> static bool genericParseNu
 
     // Don't return Infinity() or NaN().
     if (!isValidRange(number))
-        return false;
+        return WTF::nullopt;
 
     if (start == ptr)
-        return false;
+        return WTF::nullopt;
 
-    if (skip)
+    if (skip == SuffixSkippingPolicy::Skip)
         skipOptionalSVGSpacesOrDelimiter(ptr, end);
 
-    return true;
-}
-
-template <typename CharacterType>
-bool parseSVGNumber(CharacterType* begin, size_t length, double& number)
-{
-    const CharacterType* ptr = begin;
-    const CharacterType* end = ptr + length;
-    return genericParseNumber(ptr, end, number, false);
+    return number;
 }
 
-// Explicitly instantiate the two flavors of parseSVGNumber() to satisfy external callers
-template bool parseSVGNumber(LChar* begin, size_t length, double&);
-template bool parseSVGNumber(UChar* begin, size_t length, double&);
-
-bool parseNumber(const LChar*& ptr, const LChar* end, float& number, bool skip)
+Optional<float> parseNumber(const LChar*& ptr, const LChar* end, SuffixSkippingPolicy skip)
 {
-    return genericParseNumber(ptr, end, number, skip);
+    return genericParseNumber(ptr, end, skip);
 }
 
-bool parseNumber(const UChar*& ptr, const UChar* end, float& number, bool skip) 
+Optional<float> parseNumber(const UChar*& ptr, const UChar* end, SuffixSkippingPolicy skip)
 {
-    return genericParseNumber(ptr, end, number, skip);
+    return genericParseNumber(ptr, end, skip);
 }
 
-bool parseNumberFromString(const String& string, float& number, bool skip)
+Optional<float> parseNumber(const StringView& string, SuffixSkippingPolicy skip)
 {
-    auto upconvertedCharacters = StringView(string).upconvertedCharacters();
+    auto upconvertedCharacters = string.upconvertedCharacters();
     const UChar* ptr = upconvertedCharacters;
     const UChar* end = ptr + string.length();
-    return genericParseNumber(ptr, end, number, skip) && ptr == end;
+    auto result = genericParseNumber(ptr, end, skip);
+    if (ptr != end)
+        return WTF::nullopt;
+    return result;
 }
 
 // only used to parse largeArcFlag and sweepFlag which must be a "0" or "1"
 // and might not have any whitespace/comma after it
-template <typename CharacterType>
-bool genericParseArcFlag(const CharacterType*& ptr, const CharacterType* end, bool& flag)
+template <typename CharacterType> Optional<bool> genericParseArcFlag(const CharacterType*& ptr, const CharacterType* end)
 {
     if (ptr >= end)
-        return false;
+        return WTF::nullopt;
+
     const CharacterType flagChar = *ptr++;
+
+    bool flag;
     if (flagChar == '0')
         flag = false;
     else if (flagChar == '1')
         flag = true;
     else
-        return false;
-    
+        return WTF::nullopt;
+
     skipOptionalSVGSpacesOrDelimiter(ptr, end);
     
-    return true;
+    return flag;
 }
 
-bool parseArcFlag(const LChar*& ptr, const LChar* end, bool& flag)
+Optional<bool> parseArcFlag(const LChar*& ptr, const LChar* end)
 {
-    return genericParseArcFlag(ptr, end, flag);
+    return genericParseArcFlag(ptr, end);
 }
 
-bool parseArcFlag(const UChar*& ptr, const UChar* end, bool& flag)
+Optional<bool> parseArcFlag(const UChar*& ptr, const UChar* end)
 {
-    return genericParseArcFlag(ptr, end, flag);
+    return genericParseArcFlag(ptr, end);
 }
 
-bool parseNumberOptionalNumber(const String& s, float& x, float& y)
+Optional<std::pair<float, float>> parseNumberOptionalNumber(const StringView& string)
 {
-    if (s.isEmpty())
-        return false;
+    if (string.isEmpty())
+        return WTF::nullopt;
 
-    auto upconvertedCharacters = StringView(s).upconvertedCharacters();
+    auto upconvertedCharacters = string.upconvertedCharacters();
     const UChar* cur = upconvertedCharacters;
-    const UChar* end = cur + s.length();
+    const UChar* end = cur + string.length();
 
-    if (!parseNumber(cur, end, x))
-        return false;
+    auto x = parseNumber(cur, end);
+    if (!x)
+        return WTF::nullopt;
 
     if (cur == end)
-        y = x;
-    else if (!parseNumber(cur, end, y, false))
-        return false;
+        return std::make_pair(*x, *x);
 
-    return cur == end;
+    auto y = parseNumber(cur, end, SuffixSkippingPolicy::DontSkip);
+    if (!y)
+        return WTF::nullopt;
+
+    if (cur != end)
+        return WTF::nullopt;
+
+    return std::make_pair(*x, *y);
 }
 
-bool parsePoint(const String& s, FloatPoint& point)
+Optional<FloatPoint> parsePoint(const StringView& string)
 {
-    if (s.isEmpty())
-        return false;
-    auto upconvertedCharacters = StringView(s).upconvertedCharacters();
+    if (string.isEmpty())
+        return WTF::nullopt;
+
+    auto upconvertedCharacters = string.upconvertedCharacters();
     const UChar* cur = upconvertedCharacters;
-    const UChar* end = cur + s.length();
+    const UChar* end = cur + string.length();
 
     if (!skipOptionalSVGSpaces(cur, end))
-        return false;
+        return WTF::nullopt;
 
-    float x = 0;
-    if (!parseNumber(cur, end, x))
-        return false;
-
-    float y = 0;
-    if (!parseNumber(cur, end, y))
-        return false;
-
-    point = FloatPoint(x, y);
+    auto point = parseFloatPoint(cur, end);
+    if (!point)
+        return WTF::nullopt;
 
     // Disallow anything except spaces at the end.
-    return !skipOptionalSVGSpaces(cur, end);
+    skipOptionalSVGSpaces(cur, end);
+    
+    return point;
 }
 
-bool parseRect(const String& string, FloatRect& rect)
+Optional<FloatRect> parseRect(const StringView& string)
 {
-    auto upconvertedCharacters = StringView(string).upconvertedCharacters();
+    auto upconvertedCharacters = string.upconvertedCharacters();
     const UChar* ptr = upconvertedCharacters;
     const UChar* end = ptr + string.length();
+    
     skipOptionalSVGSpaces(ptr, end);
     
-    float x = 0;
-    float y = 0;
-    float width = 0;
-    float height = 0;
-    bool valid = parseNumber(ptr, end, x) && parseNumber(ptr, end, y) && parseNumber(ptr, end, width) && parseNumber(ptr, end, height, false);
-    rect = FloatRect(x, y, width, height);
-    return valid;
+    auto x = parseNumber(ptr, end);
+    if (!x)
+        return WTF::nullopt;
+    auto y = parseNumber(ptr, end);
+    if (!y)
+        return WTF::nullopt;
+    auto width = parseNumber(ptr, end);
+    if (!width)
+        return WTF::nullopt;
+    auto height = parseNumber(ptr, end, SuffixSkippingPolicy::DontSkip);
+    if (!height)
+        return WTF::nullopt;
+
+    return FloatRect { *x, *y, *width, *height };
 }
 
-bool parseGlyphName(const String& input, HashSet<String>& values)
+Optional<HashSet<String>> parseGlyphName(const StringView& string)
 {
     // FIXME: Parsing error detection is missing.
-    values.clear();
 
-    auto upconvertedCharacters = StringView(input).upconvertedCharacters();
+    auto upconvertedCharacters = string.upconvertedCharacters();
     const UChar* ptr = upconvertedCharacters;
-    const UChar* end = ptr + input.length();
+    const UChar* end = ptr + string.length();
     skipOptionalSVGSpaces(ptr, end);
 
+    HashSet<String> values;
+
     while (ptr < end) {
         // Leading and trailing white space, and white space before and after separators, will be ignored.
         const UChar* inputStart = ptr;
@@ -287,13 +291,13 @@ bool parseGlyphName(const String& input, HashSet<String>& values)
         skipOptionalSVGSpacesOrDelimiter(ptr, end, ',');
     }
 
-    return true;
+    return values;
 }
 
-static bool parseUnicodeRange(const UChar* characters, unsigned length, UnicodeRange& range)
+static Optional<UnicodeRange> parseUnicodeRange(const UChar* characters, unsigned length)
 {
     if (length < 2 || characters[0] != 'U' || characters[1] != '+')
-        return false;
+        return WTF::nullopt;
     
     // Parse the starting hex number (or its prefix).
     unsigned startRange = 0;
@@ -306,15 +310,15 @@ static bool parseUnicodeRange(const UChar* characters, unsigned length, UnicodeR
             break;
         ++startLength;
         if (startLength > 6)
-            return false;
+            return WTF::nullopt;
         startRange = (startRange << 4) | toASCIIHexValue(*ptr);
         ++ptr;
     }
-    
+
     // Handle the case of ranges separated by "-" sign.
     if (2 + startLength < length && *ptr == '-') {
         if (!startLength)
-            return false;
+            return WTF::nullopt;
         
         // Parse the ending hex number (or its prefix).
         unsigned endRange = 0;
@@ -325,17 +329,18 @@ static bool parseUnicodeRange(const UChar* characters, unsigned length, UnicodeR
                 break;
             ++endLength;
             if (endLength > 6)
-                return false;
+                return WTF::nullopt;
             endRange = (endRange << 4) | toASCIIHexValue(*ptr);
             ++ptr;
         }
         
         if (!endLength)
-            return false;
+            return WTF::nullopt;
         
+        UnicodeRange range;
         range.first = startRange;
         range.second = endRange;
-        return true;
+        return range;
     }
     
     // Handle the case of a number with some optional trailing question marks.
@@ -345,26 +350,31 @@ static bool parseUnicodeRange(const UChar* characters, unsigned length, UnicodeR
             break;
         ++startLength;
         if (startLength > 6)
-            return false;
+            return WTF::nullopt;
         startRange <<= 4;
         endRange = (endRange << 4) | 0xF;
         ++ptr;
     }
     
     if (!startLength)
-        return false;
+        return WTF::nullopt;
     
+    UnicodeRange range;
     range.first = startRange;
     range.second = endRange;
-    return true;
+    return range;
 }
 
-bool parseKerningUnicodeString(const String& input, UnicodeRanges& rangeList, HashSet<String>& stringList)
+Optional<std::pair<UnicodeRanges, HashSet<String>>> parseKerningUnicodeString(const StringView& string)
 {
     // FIXME: Parsing error detection is missing.
-    auto upconvertedCharacters = StringView(input).upconvertedCharacters();
+
+    auto upconvertedCharacters = string.upconvertedCharacters();
     const UChar* ptr = upconvertedCharacters;
-    const UChar* end = ptr + input.length();
+    const UChar* end = ptr + string.length();
+
+    UnicodeRanges rangeList;
+    HashSet<String> stringList;
 
     while (ptr < end) {
         const UChar* inputStart = ptr;
@@ -375,105 +385,37 @@ bool parseKerningUnicodeString(const String& input, UnicodeRanges& rangeList, Ha
             break;
 
         // Try to parse unicode range first
-        UnicodeRange range;
-        if (parseUnicodeRange(inputStart, ptr - inputStart, range))
-            rangeList.append(range);
+        if (auto range = parseUnicodeRange(inputStart, ptr - inputStart))
+            rangeList.append(WTFMove(*range));
         else
             stringList.add(String(inputStart, ptr - inputStart));
         ++ptr;
     }
 
-    return true;
+    return std::make_pair(rangeList, stringList);
 }
 
-Vector<String> parseDelimitedString(const String& input, const char seperator)
+template <typename CharacterType> static Optional<FloatPoint> genericParseFloatPoint(const CharacterType*& current, const CharacterType* end)
 {
-    Vector<String> values;
-
-    auto upconvertedCharacters = StringView(input).upconvertedCharacters();
-    const UChar* ptr = upconvertedCharacters;
-    const UChar* end = ptr + input.length();
-    skipOptionalSVGSpaces(ptr, end);
-
-    while (ptr < end) {
-        // Leading and trailing white space, and white space before and after semicolon separators, will be ignored.
-        const UChar* inputStart = ptr;
-        while (ptr < end && *ptr != seperator) // careful not to ignore whitespace inside inputs
-            ptr++;
-
-        if (ptr == inputStart)
-            break;
+    auto x = parseNumber(current, end);
+    if (!x)
+        return WTF::nullopt;
 
-        // walk backwards from the ; to ignore any whitespace
-        const UChar* inputEnd = ptr - 1;
-        while (inputStart < inputEnd && isSVGSpace(*inputEnd))
-            inputEnd--;
-
-        values.append(String(inputStart, inputEnd - inputStart + 1));
-        skipOptionalSVGSpacesOrDelimiter(ptr, end, seperator);
-    }
-
-    return values;
-}
+    auto y = parseNumber(current, end);
+    if (!y)
+        return WTF::nullopt;
 
-template <typename CharacterType>
-bool parseFloatPoint(const CharacterType*& current, const CharacterType* end, FloatPoint& point)
-{
-    float x;
-    float y;
-    if (!parseNumber(current, end, x)
-        || !parseNumber(current, end, y))
-        return false;
-    point = FloatPoint(x, y);
-    return true;
+    return FloatPoint { *x, *y };
 }
 
-template bool parseFloatPoint(const LChar*& current, const LChar* end, FloatPoint& point1);
-template bool parseFloatPoint(const UChar*& current, const UChar* end, FloatPoint& point1);
-
-template <typename CharacterType>
-inline bool parseFloatPoint2(const CharacterType*& current, const CharacterType* end, FloatPoint& point1, FloatPoint& point2)
+Optional<FloatPoint> parseFloatPoint(const LChar*& current, const LChar* end)
 {
-    float x1;
-    float y1;
-    float x2;
-    float y2;
-    if (!parseNumber(current, end, x1)
-        || !parseNumber(current, end, y1)
-        || !parseNumber(current, end, x2)
-        || !parseNumber(current, end, y2))
-        return false;
-    point1 = FloatPoint(x1, y1);
-    point2 = FloatPoint(x2, y2);
-    return true;
+    return genericParseFloatPoint(current, end);
 }
 
-template bool parseFloatPoint2(const LChar*& current, const LChar* end, FloatPoint& point1, FloatPoint& point2);
-template bool parseFloatPoint2(const UChar*& current, const UChar* end, FloatPoint& point1, FloatPoint& point2);
-
-template <typename CharacterType>
-bool parseFloatPoint3(const CharacterType*& current, const CharacterType* end, FloatPoint& point1, FloatPoint& point2, FloatPoint& point3)
+Optional<FloatPoint> parseFloatPoint(const UChar*& current, const UChar* end)
 {
-    float x1;
-    float y1;
-    float x2;
-    float y2;
-    float x3;
-    float y3;
-    if (!parseNumber(current, end, x1)
-        || !parseNumber(current, end, y1)
-        || !parseNumber(current, end, x2)
-        || !parseNumber(current, end, y2)
-        || !parseNumber(current, end, x3)
-        || !parseNumber(current, end, y3))
-        return false;
-    point1 = FloatPoint(x1, y1);
-    point2 = FloatPoint(x2, y2);
-    point3 = FloatPoint(x3, y3);
-    return true;
+    return genericParseFloatPoint(current, end);
 }
 
-template bool parseFloatPoint3(const LChar*& current, const LChar* end, FloatPoint& point1, FloatPoint& point2, FloatPoint& point3);
-template bool parseFloatPoint3(const UChar*& current, const UChar* end, FloatPoint& point1, FloatPoint& point2, FloatPoint& point3);
-
 }
index 3f1321d..e52bdde 100644 (file)
@@ -25,7 +25,7 @@
 #include <wtf/Vector.h>
 #include <wtf/text/WTFString.h>
 
-typedef std::pair<unsigned, unsigned> UnicodeRange;
+typedef std::pair<UChar32, UChar32> UnicodeRange;
 typedef Vector<UnicodeRange> UnicodeRanges;
 
 namespace WebCore {
@@ -33,42 +33,45 @@ namespace WebCore {
 class FloatPoint;
 class FloatRect;
 
-template <typename CharacterType>
-bool parseSVGNumber(CharacterType* ptr, size_t length, double& number);
-bool parseNumber(const LChar*& ptr, const LChar* end, float& number, bool skip = true);
-bool parseNumber(const UChar*& ptr, const UChar* end, float& number, bool skip = true);
-bool parseNumberFromString(const String&, float& number, bool skip = true);
-bool parseNumberOptionalNumber(const String& s, float& h, float& v);
-bool parseArcFlag(const LChar*& ptr, const LChar* end, bool& flag);
-bool parseArcFlag(const UChar*& ptr, const UChar* end, bool& flag);
-bool parsePoint(const String&, FloatPoint&);
-bool parseRect(const String&, FloatRect&);
-
-template <typename CharacterType>
-bool parseFloatPoint(const CharacterType*& current, const CharacterType* end, FloatPoint&);
-template <typename CharacterType>
-bool parseFloatPoint2(const CharacterType*& current, const CharacterType* end, FloatPoint&, FloatPoint&);
-template <typename CharacterType>
-bool parseFloatPoint3(const CharacterType*& current, const CharacterType* end, FloatPoint&, FloatPoint&, FloatPoint&);
+enum class SuffixSkippingPolicy {
+    DontSkip,
+    Skip
+};
+
+Optional<float> parseNumber(const LChar*& current, const LChar* end, SuffixSkippingPolicy = SuffixSkippingPolicy::Skip);
+Optional<float> parseNumber(const UChar*& current, const UChar* end, SuffixSkippingPolicy = SuffixSkippingPolicy::Skip);
+Optional<float> parseNumber(const StringView&, SuffixSkippingPolicy = SuffixSkippingPolicy::Skip);
+
+Optional<std::pair<float, float>> parseNumberOptionalNumber(const StringView&);
+
+Optional<bool> parseArcFlag(const LChar*& current, const LChar* end);
+Optional<bool> parseArcFlag(const UChar*& current, const UChar* end);
+
+Optional<FloatPoint> parsePoint(const StringView&);
+Optional<FloatRect> parseRect(const StringView&);
+
+Optional<FloatPoint> parseFloatPoint(const LChar*& current, const LChar* end);
+Optional<FloatPoint> parseFloatPoint(const UChar*& current, const UChar* end);
+
+Optional<std::pair<UnicodeRanges, HashSet<String>>> parseKerningUnicodeString(const StringView&);
+Optional<HashSet<String>> parseGlyphName(const StringView&);
+
 
 // SVG allows several different whitespace characters:
 // http://www.w3.org/TR/SVG/paths.html#PathDataBNF
-template <typename CharacterType>
-inline bool isSVGSpace(CharacterType c)
+template<typename CharacterType> constexpr bool isSVGSpace(CharacterType c)
 {
     return c == ' ' || c == '\t' || c == '\n' || c == '\r';
 }
 
-template <typename CharacterType>
-inline bool skipOptionalSVGSpaces(const CharacterType*& ptr, const CharacterType* end)
+template<typename CharacterType> constexpr bool skipOptionalSVGSpaces(const CharacterType*& ptr, const CharacterType* end)
 {
     while (ptr < end && isSVGSpace(*ptr))
         ptr++;
     return ptr < end;
 }
 
-template <typename CharacterType>
-inline bool skipOptionalSVGSpacesOrDelimiter(const CharacterType*& ptr, const CharacterType* end, char delimiter = ',')
+template<typename CharacterType> constexpr bool skipOptionalSVGSpacesOrDelimiter(const CharacterType*& ptr, const CharacterType* end, char delimiter = ',')
 {
     if (ptr < end && !isSVGSpace(*ptr) && *ptr != delimiter)
         return false;
@@ -81,11 +84,7 @@ inline bool skipOptionalSVGSpacesOrDelimiter(const CharacterType*& ptr, const Ch
     return ptr < end;
 }
 
-Vector<String> parseDelimitedString(const String& input, const char seperator);
-bool parseKerningUnicodeString(const String& input, UnicodeRanges&, HashSet<String>& stringList);
-bool parseGlyphName(const String& input, HashSet<String>& values);
-
-inline bool skipString(const UChar*& ptr, const UChar* end, const UChar* name, int length)
+constexpr bool skipString(const UChar*& ptr, const UChar* end, const UChar* name, int length)
 {
     if (end - ptr < length)
         return false;
@@ -95,9 +94,10 @@ inline bool skipString(const UChar*& ptr, const UChar* end, const UChar* name, i
     return true;
 }
 
-inline bool skipString(const UChar*& ptr, const UChar* end, const char* str)
+template<unsigned characterCount>
+inline bool skipString(const UChar*& ptr, const UChar* end, const char (&str)[characterCount])
 {
-    int length = strlen(str);
+    int length = characterCount - 1;
     if (end - ptr < length)
         return false;
     for (int i = 0; i < length; ++i) {
index 8d2f636..14781bb 100644 (file)
@@ -116,200 +116,201 @@ FloatPoint SVGPathBlender::blendAnimatedFloatPoint(const FloatPoint& fromPoint,
     return animatedPoint;
 }
 
+template<typename Function> using InvokeResult = typename std::invoke_result_t<Function, SVGPathSource>::value_type;
+template<typename Function> using ResultPair = std::pair<InvokeResult<Function>, InvokeResult<Function>>;
+template<typename Function> static Optional<ResultPair<Function>> pullFromSources(SVGPathSource& fromSource, SVGPathSource& toSource, Function&& function)
+{
+    InvokeResult<Function> fromResult;
+    if (fromSource.hasMoreData()) {
+        auto parsedFrom = std::invoke(function, fromSource);
+        if (!parsedFrom)
+            return WTF::nullopt;
+        fromResult = WTFMove(*parsedFrom);
+    }
+
+    auto parsedTo = std::invoke(std::forward<Function>(function), toSource);
+    if (!parsedTo)
+        return WTF::nullopt;
+
+    return ResultPair<Function> { WTFMove(fromResult), WTFMove(*parsedTo) };
+}
+
 bool SVGPathBlender::blendMoveToSegment(float progress)
 {
-    FloatPoint fromTargetPoint;
-    FloatPoint toTargetPoint;
-    if ((m_fromSource.hasMoreData() && !m_fromSource.parseMoveToSegment(fromTargetPoint))
-        || !m_toSource.parseMoveToSegment(toTargetPoint))
+    auto result = pullFromSources(m_fromSource, m_toSource, &SVGPathSource::parseMoveToSegment);
+    if (!result)
         return false;
 
     if (!m_consumer)
         return true;
 
-    m_consumer->moveTo(blendAnimatedFloatPoint(fromTargetPoint, toTargetPoint, progress), false, m_isInFirstHalfOfAnimation ? m_fromMode : m_toMode);
-    m_fromCurrentPoint = m_fromMode == AbsoluteCoordinates ? fromTargetPoint : m_fromCurrentPoint + fromTargetPoint;
-    m_toCurrentPoint = m_toMode == AbsoluteCoordinates ? toTargetPoint : m_toCurrentPoint + toTargetPoint;
+    auto [from, to] = *result;
+
+    m_consumer->moveTo(blendAnimatedFloatPoint(from.targetPoint, to.targetPoint, progress), false, m_isInFirstHalfOfAnimation ? m_fromMode : m_toMode);
+    m_fromCurrentPoint = m_fromMode == AbsoluteCoordinates ? from.targetPoint : m_fromCurrentPoint + from.targetPoint;
+    m_toCurrentPoint = m_toMode == AbsoluteCoordinates ? to.targetPoint : m_toCurrentPoint + to.targetPoint;
     return true;
 }
 
 bool SVGPathBlender::blendLineToSegment(float progress)
 {
-    FloatPoint fromTargetPoint;
-    FloatPoint toTargetPoint;
-    if ((m_fromSource.hasMoreData() && !m_fromSource.parseLineToSegment(fromTargetPoint))
-        || !m_toSource.parseLineToSegment(toTargetPoint))
+    auto result = pullFromSources(m_fromSource, m_toSource, &SVGPathSource::parseLineToSegment);
+    if (!result)
         return false;
 
     if (!m_consumer)
         return true;
 
-    m_consumer->lineTo(blendAnimatedFloatPoint(fromTargetPoint, toTargetPoint, progress), m_isInFirstHalfOfAnimation ? m_fromMode : m_toMode);
-    m_fromCurrentPoint = m_fromMode == AbsoluteCoordinates ? fromTargetPoint : m_fromCurrentPoint + fromTargetPoint;
-    m_toCurrentPoint = m_toMode == AbsoluteCoordinates ? toTargetPoint : m_toCurrentPoint + toTargetPoint;
+    auto [from, to] = *result;
+
+    m_consumer->lineTo(blendAnimatedFloatPoint(from.targetPoint, to.targetPoint, progress), m_isInFirstHalfOfAnimation ? m_fromMode : m_toMode);
+    m_fromCurrentPoint = m_fromMode == AbsoluteCoordinates ? from.targetPoint : m_fromCurrentPoint + from.targetPoint;
+    m_toCurrentPoint = m_toMode == AbsoluteCoordinates ? to.targetPoint : m_toCurrentPoint + to.targetPoint;
     return true;
 }
 
 bool SVGPathBlender::blendLineToHorizontalSegment(float progress)
 {
-    float fromX = 0;
-    float toX = 0;
-    if ((m_fromSource.hasMoreData() && !m_fromSource.parseLineToHorizontalSegment(fromX))
-        || !m_toSource.parseLineToHorizontalSegment(toX))
+    auto result = pullFromSources(m_fromSource, m_toSource, &SVGPathSource::parseLineToHorizontalSegment);
+    if (!result)
         return false;
 
     if (!m_consumer)
         return true;
 
-    m_consumer->lineToHorizontal(blendAnimatedDimensonalFloat(fromX, toX, BlendHorizontal, progress), m_isInFirstHalfOfAnimation ? m_fromMode : m_toMode);
-    m_fromCurrentPoint.setX(m_fromMode == AbsoluteCoordinates ? fromX : m_fromCurrentPoint.x() + fromX);
-    m_toCurrentPoint.setX(m_toMode == AbsoluteCoordinates ? toX : m_toCurrentPoint.x() + toX);
+    auto [from, to] = *result;
+
+    m_consumer->lineToHorizontal(blendAnimatedDimensonalFloat(from.x, to.x, BlendHorizontal, progress), m_isInFirstHalfOfAnimation ? m_fromMode : m_toMode);
+    m_fromCurrentPoint.setX(m_fromMode == AbsoluteCoordinates ? from.x : m_fromCurrentPoint.x() + from.x);
+    m_toCurrentPoint.setX(m_toMode == AbsoluteCoordinates ? to.x : m_toCurrentPoint.x() + to.x);
     return true;
 }
 
 bool SVGPathBlender::blendLineToVerticalSegment(float progress)
 {
-    float fromY = 0;
-    float toY = 0;
-    if ((m_fromSource.hasMoreData() && !m_fromSource.parseLineToVerticalSegment(fromY))
-        || !m_toSource.parseLineToVerticalSegment(toY))
+    auto result = pullFromSources(m_fromSource, m_toSource, &SVGPathSource::parseLineToVerticalSegment);
+    if (!result)
         return false;
 
     if (!m_consumer)
         return true;
 
-    m_consumer->lineToVertical(blendAnimatedDimensonalFloat(fromY, toY, BlendVertical, progress), m_isInFirstHalfOfAnimation ? m_fromMode : m_toMode);
-    m_fromCurrentPoint.setY(m_fromMode == AbsoluteCoordinates ? fromY : m_fromCurrentPoint.y() + fromY);
-    m_toCurrentPoint.setY(m_toMode == AbsoluteCoordinates ? toY : m_toCurrentPoint.y() + toY);
+    auto [from, to] = *result;
+
+    m_consumer->lineToVertical(blendAnimatedDimensonalFloat(from.y, to.y, BlendVertical, progress), m_isInFirstHalfOfAnimation ? m_fromMode : m_toMode);
+    m_fromCurrentPoint.setY(m_fromMode == AbsoluteCoordinates ? from.y : m_fromCurrentPoint.y() + from.y);
+    m_toCurrentPoint.setY(m_toMode == AbsoluteCoordinates ? to.y : m_toCurrentPoint.y() + to.y);
     return true;
 }
 
 bool SVGPathBlender::blendCurveToCubicSegment(float progress)
 {
-    FloatPoint fromTargetPoint;
-    FloatPoint fromPoint1;
-    FloatPoint fromPoint2;
-    FloatPoint toTargetPoint;
-    FloatPoint toPoint1;
-    FloatPoint toPoint2;
-    if ((m_fromSource.hasMoreData() && !m_fromSource.parseCurveToCubicSegment(fromPoint1, fromPoint2, fromTargetPoint))
-        || !m_toSource.parseCurveToCubicSegment(toPoint1, toPoint2, toTargetPoint))
+    auto result = pullFromSources(m_fromSource, m_toSource, &SVGPathSource::parseCurveToCubicSegment);
+    if (!result)
         return false;
 
     if (!m_consumer)
         return true;
 
-    m_consumer->curveToCubic(blendAnimatedFloatPoint(fromPoint1, toPoint1, progress),
-        blendAnimatedFloatPoint(fromPoint2, toPoint2, progress),
-        blendAnimatedFloatPoint(fromTargetPoint, toTargetPoint, progress),
+    auto [from, to] = *result;
+
+    m_consumer->curveToCubic(blendAnimatedFloatPoint(from.point1, to.point1, progress),
+        blendAnimatedFloatPoint(from.point2, to.point2, progress),
+        blendAnimatedFloatPoint(from.targetPoint, to.targetPoint, progress),
         m_isInFirstHalfOfAnimation ? m_fromMode : m_toMode);
-    m_fromCurrentPoint = m_fromMode == AbsoluteCoordinates ? fromTargetPoint : m_fromCurrentPoint + fromTargetPoint;
-    m_toCurrentPoint = m_toMode == AbsoluteCoordinates ? toTargetPoint : m_toCurrentPoint + toTargetPoint;
+    m_fromCurrentPoint = m_fromMode == AbsoluteCoordinates ? from.targetPoint : m_fromCurrentPoint + from.targetPoint;
+    m_toCurrentPoint = m_toMode == AbsoluteCoordinates ? to.targetPoint : m_toCurrentPoint + to.targetPoint;
     return true;
 }
 
 bool SVGPathBlender::blendCurveToCubicSmoothSegment(float progress)
 {
-    FloatPoint fromTargetPoint;
-    FloatPoint fromPoint2;
-    FloatPoint toTargetPoint;
-    FloatPoint toPoint2;
-    if ((m_fromSource.hasMoreData() && !m_fromSource.parseCurveToCubicSmoothSegment(fromPoint2, fromTargetPoint))
-        || !m_toSource.parseCurveToCubicSmoothSegment(toPoint2, toTargetPoint))
+    auto result = pullFromSources(m_fromSource, m_toSource, &SVGPathSource::parseCurveToCubicSmoothSegment);
+    if (!result)
         return false;
 
     if (!m_consumer)
         return true;
 
-    m_consumer->curveToCubicSmooth(blendAnimatedFloatPoint(fromPoint2, toPoint2, progress),
-        blendAnimatedFloatPoint(fromTargetPoint, toTargetPoint, progress),
+    auto [from, to] = *result;
+
+    m_consumer->curveToCubicSmooth(blendAnimatedFloatPoint(from.point2, to.point2, progress),
+        blendAnimatedFloatPoint(from.targetPoint, to.targetPoint, progress),
         m_isInFirstHalfOfAnimation ? m_fromMode : m_toMode);
-    m_fromCurrentPoint = m_fromMode == AbsoluteCoordinates ? fromTargetPoint : m_fromCurrentPoint + fromTargetPoint;
-    m_toCurrentPoint = m_toMode == AbsoluteCoordinates ? toTargetPoint : m_toCurrentPoint + toTargetPoint;
+    m_fromCurrentPoint = m_fromMode == AbsoluteCoordinates ? from.targetPoint : m_fromCurrentPoint + from.targetPoint;
+    m_toCurrentPoint = m_toMode == AbsoluteCoordinates ? to.targetPoint : m_toCurrentPoint + to.targetPoint;
     return true;
 }
 
 bool SVGPathBlender::blendCurveToQuadraticSegment(float progress)
 {
-    FloatPoint fromTargetPoint;
-    FloatPoint fromPoint1;
-    FloatPoint toTargetPoint;
-    FloatPoint toPoint1;
-    if ((m_fromSource.hasMoreData() && !m_fromSource.parseCurveToQuadraticSegment(fromPoint1, fromTargetPoint))
-        || !m_toSource.parseCurveToQuadraticSegment(toPoint1, toTargetPoint))
+    auto result = pullFromSources(m_fromSource, m_toSource, &SVGPathSource::parseCurveToQuadraticSegment);
+    if (!result)
         return false;
 
     if (!m_consumer)
         return true;
 
-    m_consumer->curveToQuadratic(blendAnimatedFloatPoint(fromPoint1, toPoint1, progress),
-        blendAnimatedFloatPoint(fromTargetPoint, toTargetPoint, progress),
+    auto [from, to] = *result;
+
+    m_consumer->curveToQuadratic(blendAnimatedFloatPoint(from.point1, to.point1, progress),
+        blendAnimatedFloatPoint(from.targetPoint, to.targetPoint, progress),
         m_isInFirstHalfOfAnimation ? m_fromMode : m_toMode);
-    m_fromCurrentPoint = m_fromMode == AbsoluteCoordinates ? fromTargetPoint : m_fromCurrentPoint + fromTargetPoint;
-    m_toCurrentPoint = m_toMode == AbsoluteCoordinates ? toTargetPoint : m_toCurrentPoint + toTargetPoint;
+    m_fromCurrentPoint = m_fromMode == AbsoluteCoordinates ? from.targetPoint : m_fromCurrentPoint + from.targetPoint;
+    m_toCurrentPoint = m_toMode == AbsoluteCoordinates ? to.targetPoint : m_toCurrentPoint + to.targetPoint;
     return true;
 }
 
 bool SVGPathBlender::blendCurveToQuadraticSmoothSegment(float progress)
 {
-    FloatPoint fromTargetPoint;
-    FloatPoint toTargetPoint;
-    if ((m_fromSource.hasMoreData() && !m_fromSource.parseCurveToQuadraticSmoothSegment(fromTargetPoint))
-        || !m_toSource.parseCurveToQuadraticSmoothSegment(toTargetPoint))
+    auto result = pullFromSources(m_fromSource, m_toSource, &SVGPathSource::parseCurveToQuadraticSmoothSegment);
+    if (!result)
         return false;
 
     if (!m_consumer)
         return true;
 
-    m_consumer->curveToQuadraticSmooth(blendAnimatedFloatPoint(fromTargetPoint, toTargetPoint, progress), m_isInFirstHalfOfAnimation ? m_fromMode : m_toMode);
-    m_fromCurrentPoint = m_fromMode == AbsoluteCoordinates ? fromTargetPoint : m_fromCurrentPoint + fromTargetPoint;
-    m_toCurrentPoint = m_toMode == AbsoluteCoordinates ? toTargetPoint : m_toCurrentPoint + toTargetPoint;
+    auto [from, to] = *result;
+
+    m_consumer->curveToQuadraticSmooth(blendAnimatedFloatPoint(from.targetPoint, to.targetPoint, progress), m_isInFirstHalfOfAnimation ? m_fromMode : m_toMode);
+    m_fromCurrentPoint = m_fromMode == AbsoluteCoordinates ? from.targetPoint : m_fromCurrentPoint + from.targetPoint;
+    m_toCurrentPoint = m_toMode == AbsoluteCoordinates ? to.targetPoint : m_toCurrentPoint + to.targetPoint;
     return true;
 }
 
 bool SVGPathBlender::blendArcToSegment(float progress)
 {
-    float fromRx = 0;
-    float fromRy = 0;
-    float fromAngle = 0;
-    bool fromLargeArc = false;
-    bool fromSweep = false;
-    FloatPoint fromTargetPoint;
-    float toRx = 0;
-    float toRy = 0;
-    float toAngle = 0;
-    bool toLargeArc = false;
-    bool toSweep = false;
-    FloatPoint toTargetPoint;
-    if ((m_fromSource.hasMoreData() && !m_fromSource.parseArcToSegment(fromRx, fromRy, fromAngle, fromLargeArc, fromSweep, fromTargetPoint))
-        || !m_toSource.parseArcToSegment(toRx, toRy, toAngle, toLargeArc, toSweep, toTargetPoint))
+    auto result = pullFromSources(m_fromSource, m_toSource, &SVGPathSource::parseArcToSegment);
+    if (!result)
         return false;
 
     if (!m_consumer)
         return true;
 
+    auto [from, to] = *result;
+
     if (m_addTypesCount) {
         ASSERT(m_fromMode == m_toMode);
-        FloatPoint scaledToTargetPoint = toTargetPoint;
+        auto scaledToTargetPoint = to.targetPoint;
         scaledToTargetPoint.scale(m_addTypesCount);
-        m_consumer->arcTo(fromRx + toRx * m_addTypesCount,
-            fromRy + toRy * m_addTypesCount,
-            fromAngle + toAngle * m_addTypesCount,
-            fromLargeArc || toLargeArc,
-            fromSweep || toSweep,
-            fromTargetPoint + scaledToTargetPoint,
+        m_consumer->arcTo(from.rx + to.rx * m_addTypesCount,
+            from.ry + to.ry * m_addTypesCount,
+            from.angle + to.angle * m_addTypesCount,
+            from.largeArc || to.largeArc,
+            from.sweep || to.sweep,
+            from.targetPoint + scaledToTargetPoint,
             m_fromMode);
     } else {
-        m_consumer->arcTo(blend(fromRx, toRx, progress),
-            blend(fromRy, toRy, progress),
-            blend(fromAngle, toAngle, progress),
-            m_isInFirstHalfOfAnimation ? fromLargeArc : toLargeArc,
-            m_isInFirstHalfOfAnimation ? fromSweep : toSweep,
-            blendAnimatedFloatPoint(fromTargetPoint, toTargetPoint, progress),
+        m_consumer->arcTo(blend(from.rx, to.rx, progress),
+            blend(from.ry, to.ry, progress),
+            blend(from.angle, to.angle, progress),
+            m_isInFirstHalfOfAnimation ? from.largeArc : to.largeArc,
+            m_isInFirstHalfOfAnimation ? from.sweep : to.sweep,
+            blendAnimatedFloatPoint(from.targetPoint, to.targetPoint, progress),
             m_isInFirstHalfOfAnimation ? m_fromMode : m_toMode);
     }
-    m_fromCurrentPoint = m_fromMode == AbsoluteCoordinates ? fromTargetPoint : m_fromCurrentPoint + fromTargetPoint;
-    m_toCurrentPoint = m_toMode == AbsoluteCoordinates ? toTargetPoint : m_toCurrentPoint + toTargetPoint;
+    m_fromCurrentPoint = m_fromMode == AbsoluteCoordinates ? from.targetPoint : m_fromCurrentPoint + from.targetPoint;
+    m_toCurrentPoint = m_toMode == AbsoluteCoordinates ? to.targetPoint : m_toCurrentPoint + to.targetPoint;
     return true;
 }
 
@@ -351,9 +352,16 @@ bool SVGPathBlender::canBlendPaths()
     bool fromSourceHadData = m_fromSource.hasMoreData();
     while (m_toSource.hasMoreData()) {
         SVGPathSegType fromCommand;
-        SVGPathSegType toCommand;
-        if ((fromSourceHadData && !m_fromSource.parseSVGSegmentType(fromCommand)) || !m_toSource.parseSVGSegmentType(toCommand))
+        if (fromSourceHadData) {
+            auto parsedFromCommand = m_fromSource.parseSVGSegmentType();
+            if (!parsedFromCommand)
+                return false;
+            fromCommand = *parsedFromCommand;
+        }
+        auto parsedtoCommand = m_toSource.parseSVGSegmentType();
+        if (!parsedtoCommand)
             return false;
+        SVGPathSegType toCommand = *parsedtoCommand;
 
         m_toMode = coordinateModeOfCommand(toCommand);
         m_fromMode = fromSourceHadData ? coordinateModeOfCommand(fromCommand) : m_toMode;
@@ -433,9 +441,16 @@ bool SVGPathBlender::blendAnimatedPath(float progress)
     bool fromSourceHadData = m_fromSource.hasMoreData();
     while (m_toSource.hasMoreData()) {
         SVGPathSegType fromCommand;
-        SVGPathSegType toCommand;
-        if ((fromSourceHadData && !m_fromSource.parseSVGSegmentType(fromCommand)) || !m_toSource.parseSVGSegmentType(toCommand))
+        if (fromSourceHadData) {
+            auto parsedFromCommand = m_fromSource.parseSVGSegmentType();
+            if (!parsedFromCommand)
+                return false;
+            fromCommand = *parsedFromCommand;
+        }
+        auto parsedToCommand = m_toSource.parseSVGSegmentType();
+        if (!parsedToCommand)
             return false;
+        SVGPathSegType toCommand = *parsedToCommand;
 
         m_toMode = coordinateModeOfCommand(toCommand);
         m_fromMode = fromSourceHadData ? coordinateModeOfCommand(fromCommand) : m_toMode;
index f71c454..df567a6 100644 (file)
@@ -34,78 +34,86 @@ bool SVGPathByteStreamSource::hasMoreData() const
     return m_streamCurrent < m_streamEnd;
 }
 
-bool SVGPathByteStreamSource::parseSVGSegmentType(SVGPathSegType& pathSegType)
+SVGPathSegType SVGPathByteStreamSource::nextCommand(SVGPathSegType)
 {
-    pathSegType = static_cast<SVGPathSegType>(readSVGSegmentType());
-    return true;
+    return static_cast<SVGPathSegType>(readSVGSegmentType());
 }
 
-SVGPathSegType SVGPathByteStreamSource::nextCommand(SVGPathSegType)
+Optional<SVGPathSegType> SVGPathByteStreamSource::parseSVGSegmentType()
 {
     return static_cast<SVGPathSegType>(readSVGSegmentType());
 }
 
-bool SVGPathByteStreamSource::parseMoveToSegment(FloatPoint& targetPoint)
+Optional<SVGPathSource::MoveToSegment> SVGPathByteStreamSource::parseMoveToSegment()
 {
-    targetPoint = readFloatPoint();
-    return true;
+    MoveToSegment segment;
+    segment.targetPoint = readFloatPoint();
+    return segment;
 }
 
-bool SVGPathByteStreamSource::parseLineToSegment(FloatPoint& targetPoint)
+Optional<SVGPathSource::LineToSegment> SVGPathByteStreamSource::parseLineToSegment()
 {
-    targetPoint = readFloatPoint();
-    return true;
+    LineToSegment segment;
+    segment.targetPoint = readFloatPoint();
+    return segment;
 }
 
-bool SVGPathByteStreamSource::parseLineToHorizontalSegment(float& x)
+Optional<SVGPathSource::LineToHorizontalSegment> SVGPathByteStreamSource::parseLineToHorizontalSegment()
 {
-    x = readFloat();
-    return true;
+    LineToHorizontalSegment segment;
+    segment.x = readFloat();
+    return segment;
 }
 
-bool SVGPathByteStreamSource::parseLineToVerticalSegment(float& y)
+Optional<SVGPathSource::LineToVerticalSegment> SVGPathByteStreamSource::parseLineToVerticalSegment()
 {
-    y = readFloat();
-    return true;
+    LineToVerticalSegment segment;
+    segment.y = readFloat();
+    return segment;
 }
 
-bool SVGPathByteStreamSource::parseCurveToCubicSegment(FloatPoint& point1, FloatPoint& point2, FloatPoint& targetPoint)
+Optional<SVGPathSource::CurveToCubicSegment> SVGPathByteStreamSource::parseCurveToCubicSegment()
 {
-    point1 = readFloatPoint();
-    point2 = readFloatPoint();
-    targetPoint = readFloatPoint();
-    return true;
+    CurveToCubicSegment segment;
+    segment.point1 = readFloatPoint();
+    segment.point2 = readFloatPoint();
+    segment.targetPoint = readFloatPoint();
+    return segment;
 }
 
-bool SVGPathByteStreamSource::parseCurveToCubicSmoothSegment(FloatPoint& point2, FloatPoint& targetPoint)
+Optional<SVGPathSource::CurveToCubicSmoothSegment> SVGPathByteStreamSource::parseCurveToCubicSmoothSegment()
 {
-    point2 = readFloatPoint();
-    targetPoint = readFloatPoint();
-    return true;
+    CurveToCubicSmoothSegment segment;
+    segment.point2 = readFloatPoint();
+    segment.targetPoint = readFloatPoint();
+    return segment;
 }
 
-bool SVGPathByteStreamSource::parseCurveToQuadraticSegment(FloatPoint& point1, FloatPoint& targetPoint)
+Optional<SVGPathSource::CurveToQuadraticSegment> SVGPathByteStreamSource::parseCurveToQuadraticSegment()
 {
-    point1 = readFloatPoint();
-    targetPoint = readFloatPoint();
-    return true;
+    CurveToQuadraticSegment segment;
+    segment.point1 = readFloatPoint();
+    segment.targetPoint = readFloatPoint();
+    return segment;
 }
 
-bool SVGPathByteStreamSource::parseCurveToQuadraticSmoothSegment(FloatPoint& targetPoint)
+Optional<SVGPathSource::CurveToQuadraticSmoothSegment> SVGPathByteStreamSource::parseCurveToQuadraticSmoothSegment()
 {
-    targetPoint = readFloatPoint();
-    return true;
+    CurveToQuadraticSmoothSegment segment;
+    segment.targetPoint = readFloatPoint();
+    return segment;
 }
 
-bool SVGPathByteStreamSource::parseArcToSegment(float& rx, float& ry, float& angle, bool& largeArc, bool& sweep, FloatPoint& targetPoint)
+Optional<SVGPathSource::ArcToSegment> SVGPathByteStreamSource::parseArcToSegment()
 {
-    rx = readFloat();
-    ry = readFloat();
-    angle = readFloat();
-    largeArc = readFlag();
-    sweep = readFlag();
-    targetPoint = readFloatPoint();
-    return true;
+    ArcToSegment segment;
+    segment.rx = readFloat();
+    segment.ry = readFloat();
+    segment.angle = readFloat();
+    segment.largeArc = readFlag();
+    segment.sweep = readFlag();
+    segment.targetPoint = readFloatPoint();
+    return segment;
 }
 
 }
index 2e03c8c..264dff2 100644 (file)
@@ -32,18 +32,18 @@ public:
 private:
     bool hasMoreData() const final;
     bool moveToNextToken() final { return true; }
-    bool parseSVGSegmentType(SVGPathSegType&) final;
     SVGPathSegType nextCommand(SVGPathSegType) final;
 
-    bool parseMoveToSegment(FloatPoint&) final;
-    bool parseLineToSegment(FloatPoint&) final;
-    bool parseLineToHorizontalSegment(float&) final;
-    bool parseLineToVerticalSegment(float&) final;
-    bool parseCurveToCubicSegment(FloatPoint&, FloatPoint&, FloatPoint&) final;
-    bool parseCurveToCubicSmoothSegment(FloatPoint&, FloatPoint&) final;
-    bool parseCurveToQuadraticSegment(FloatPoint&, FloatPoint&) final;
-    bool parseCurveToQuadraticSmoothSegment(FloatPoint&) final;
-    bool parseArcToSegment(float&, float&, float&, bool&, bool&, FloatPoint&) final;
+    Optional<SVGPathSegType> parseSVGSegmentType() final;
+    Optional<MoveToSegment> parseMoveToSegment() final;
+    Optional<LineToSegment> parseLineToSegment() final;
+    Optional<LineToHorizontalSegment> parseLineToHorizontalSegment() final;
+    Optional<LineToVerticalSegment> parseLineToVerticalSegment() final;
+    Optional<CurveToCubicSegment> parseCurveToCubicSegment() final;
+    Optional<CurveToCubicSmoothSegment> parseCurveToCubicSmoothSegment() final;
+    Optional<CurveToQuadraticSegment> parseCurveToQuadraticSegment() final;
+    Optional<CurveToQuadraticSmoothSegment> parseCurveToQuadraticSmoothSegment() final;
+    Optional<ArcToSegment> parseArcToSegment() final;
 
 #if COMPILER(MSVC)
 #pragma warning(disable: 4701)
index 9997ee9..654e15e 100644 (file)
@@ -73,102 +73,99 @@ void SVGPathParser::parseClosePathSegment()
 
 bool SVGPathParser::parseMoveToSegment()
 {
-    FloatPoint targetPoint;
-    if (!m_source.parseMoveToSegment(targetPoint))
+    auto result = m_source.parseMoveToSegment();
+    if (!result)
         return false;
 
     if (m_pathParsingMode == NormalizedParsing) {
         if (m_mode == RelativeCoordinates)
-            m_currentPoint += targetPoint;
+            m_currentPoint += result->targetPoint;
         else
-            m_currentPoint = targetPoint;
+            m_currentPoint = result->targetPoint;
         m_subPathPoint = m_currentPoint;
         m_consumer.moveTo(m_currentPoint, m_closePath, AbsoluteCoordinates);
     } else
-        m_consumer.moveTo(targetPoint, m_closePath, m_mode);
+        m_consumer.moveTo(result->targetPoint, m_closePath, m_mode);
     m_closePath = false;
     return true;
 }
 
 bool SVGPathParser::parseLineToSegment()
 {
-    FloatPoint targetPoint;
-    if (!m_source.parseLineToSegment(targetPoint))
+    auto result = m_source.parseLineToSegment();
+    if (!result)
         return false;
 
     if (m_pathParsingMode == NormalizedParsing) {
         if (m_mode == RelativeCoordinates)
-            m_currentPoint += targetPoint;
+            m_currentPoint += result->targetPoint;
         else
-            m_currentPoint = targetPoint;
+            m_currentPoint = result->targetPoint;
         m_consumer.lineTo(m_currentPoint, AbsoluteCoordinates);
     } else
-        m_consumer.lineTo(targetPoint, m_mode);
+        m_consumer.lineTo(result->targetPoint, m_mode);
     return true;
 }
 
 bool SVGPathParser::parseLineToHorizontalSegment()
 {
-    float toX;
-    if (!m_source.parseLineToHorizontalSegment(toX))
+    auto result = m_source.parseLineToHorizontalSegment();
+    if (!result)
         return false;
 
     if (m_pathParsingMode == NormalizedParsing) {
         if (m_mode == RelativeCoordinates)
-            m_currentPoint.move(toX, 0);
+            m_currentPoint.move(result->x, 0);
         else
-            m_currentPoint.setX(toX);
+            m_currentPoint.setX(result->x);
         m_consumer.lineTo(m_currentPoint, AbsoluteCoordinates);
     } else
-        m_consumer.lineToHorizontal(toX, m_mode);
+        m_consumer.lineToHorizontal(result->x, m_mode);
     return true;
 }
 
 bool SVGPathParser::parseLineToVerticalSegment()
 {
-    float toY;
-    if (!m_source.parseLineToVerticalSegment(toY))
+    auto result = m_source.parseLineToVerticalSegment();
+    if (!result)
         return false;
 
     if (m_pathParsingMode == NormalizedParsing) {
         if (m_mode == RelativeCoordinates)
-            m_currentPoint.move(0, toY);
+            m_currentPoint.move(0, result->y);
         else
-            m_currentPoint.setY(toY);
+            m_currentPoint.setY(result->y);
         m_consumer.lineTo(m_currentPoint, AbsoluteCoordinates);
     } else
-        m_consumer.lineToVertical(toY, m_mode);
+        m_consumer.lineToVertical(result->y, m_mode);
     return true;
 }
 
 bool SVGPathParser::parseCurveToCubicSegment()
 {
-    FloatPoint point1;
-    FloatPoint point2;
-    FloatPoint targetPoint;
-    if (!m_source.parseCurveToCubicSegment(point1, point2, targetPoint))
+    auto result = m_source.parseCurveToCubicSegment();
+    if (!result)
         return false;
 
     if (m_pathParsingMode == NormalizedParsing) {
         if (m_mode == RelativeCoordinates) {
-            point1 += m_currentPoint;
-            point2 += m_currentPoint;
-            targetPoint += m_currentPoint;
+            result->point1 += m_currentPoint;
+            result->point2 += m_currentPoint;
+            result->targetPoint += m_currentPoint;
         }
-        m_consumer.curveToCubic(point1, point2, targetPoint, AbsoluteCoordinates);
+        m_consumer.curveToCubic(result->point1, result->point2, result->targetPoint, AbsoluteCoordinates);
 
-        m_controlPoint = point2;
-        m_currentPoint = targetPoint;
+        m_controlPoint = result->point2;
+        m_currentPoint = result->targetPoint;
     } else
-        m_consumer.curveToCubic(point1, point2, targetPoint, m_mode);
+        m_consumer.curveToCubic(result->point1, result->point2, result->targetPoint, m_mode);
     return true;
 }
 
 bool SVGPathParser::parseCurveToCubicSmoothSegment()
 {
-    FloatPoint point2;
-    FloatPoint targetPoint;
-    if (!m_source.parseCurveToCubicSmoothSegment(point2, targetPoint))
+    auto result = m_source.parseCurveToCubicSmoothSegment();
+    if (!result)
         return false;
 
     if (m_lastCommand != PathSegCurveToCubicAbs
@@ -182,53 +179,53 @@ bool SVGPathParser::parseCurveToCubicSmoothSegment()
         point1.scale(2);
         point1.move(-m_controlPoint.x(), -m_controlPoint.y());
         if (m_mode == RelativeCoordinates) {
-            point2 += m_currentPoint;
-            targetPoint += m_currentPoint;
+            result->point2 += m_currentPoint;
+            result->targetPoint += m_currentPoint;
         }
 
-        m_consumer.curveToCubic(point1, point2, targetPoint, AbsoluteCoordinates);
+        m_consumer.curveToCubic(point1, result->point2, result->targetPoint, AbsoluteCoordinates);
 
-        m_controlPoint = point2;
-        m_currentPoint = targetPoint;
+        m_controlPoint = result->point2;
+        m_currentPoint = result->targetPoint;
     } else
-        m_consumer.curveToCubicSmooth(point2, targetPoint, m_mode);
+        m_consumer.curveToCubicSmooth(result->point2, result->targetPoint, m_mode);
     return true;
 }
 
 bool SVGPathParser::parseCurveToQuadraticSegment()
 {
-    FloatPoint point1;
-    FloatPoint targetPoint;
-    if (!m_source.parseCurveToQuadraticSegment(point1, targetPoint))
+    auto result = m_source.parseCurveToQuadraticSegment();
+    if (!result)
         return false;
 
     if (m_pathParsingMode == NormalizedParsing) {
-        m_controlPoint = point1;
+        m_controlPoint = result->point1;
+
         FloatPoint point1 = m_currentPoint;
         point1.move(2 * m_controlPoint.x(), 2 * m_controlPoint.y());
-        FloatPoint point2(targetPoint.x() + 2 * m_controlPoint.x(), targetPoint.y() + 2 * m_controlPoint.y());
+        FloatPoint point2(result->targetPoint.x() + 2 * m_controlPoint.x(), result->targetPoint.y() + 2 * m_controlPoint.y());
         if (m_mode == RelativeCoordinates) {
             point1.move(2 * m_currentPoint.x(), 2 * m_currentPoint.y());
             point2.move(3 * m_currentPoint.x(), 3 * m_currentPoint.y());
-            targetPoint += m_currentPoint;
+            result->targetPoint += m_currentPoint;
         }
         point1.scale(gOneOverThree);
         point2.scale(gOneOverThree);
 
-        m_consumer.curveToCubic(point1, point2, targetPoint, AbsoluteCoordinates);
+        m_consumer.curveToCubic(point1, point2, result->targetPoint, AbsoluteCoordinates);
 
         if (m_mode == RelativeCoordinates)
             m_controlPoint += m_currentPoint;
-        m_currentPoint = targetPoint;
+        m_currentPoint = result->targetPoint;
     } else
-        m_consumer.curveToQuadratic(point1, targetPoint, m_mode);
+        m_consumer.curveToQuadratic(result->point1, result->targetPoint, m_mode);
     return true;
 }
 
 bool SVGPathParser::parseCurveToQuadraticSmoothSegment()
 {
-    FloatPoint targetPoint;
-    if (!m_source.parseCurveToQuadraticSmoothSegment(targetPoint))
+    auto result = m_source.parseCurveToQuadraticSmoothSegment();
+    if (!result)
         return false;
 
     if (m_lastCommand != PathSegCurveToQuadraticAbs
@@ -242,67 +239,62 @@ bool SVGPathParser::parseCurveToQuadraticSmoothSegment()
         cubicPoint.scale(2);
         cubicPoint.move(-m_controlPoint.x(), -m_controlPoint.y());
         FloatPoint point1(m_currentPoint.x() + 2 * cubicPoint.x(), m_currentPoint.y() + 2 * cubicPoint.y());
-        FloatPoint point2(targetPoint.x() + 2 * cubicPoint.x(), targetPoint.y() + 2 * cubicPoint.y());
+        FloatPoint point2(result->targetPoint.x() + 2 * cubicPoint.x(), result->targetPoint.y() + 2 * cubicPoint.y());
         if (m_mode == RelativeCoordinates) {
             point2 += m_currentPoint;
-            targetPoint += m_currentPoint;
+            result->targetPoint += m_currentPoint;
         }
         point1.scale(gOneOverThree);
         point2.scale(gOneOverThree);
 
-        m_consumer.curveToCubic(point1, point2, targetPoint, AbsoluteCoordinates);
+        m_consumer.curveToCubic(point1, point2, result->targetPoint, AbsoluteCoordinates);
 
         m_controlPoint = cubicPoint;
-        m_currentPoint = targetPoint;
+        m_currentPoint = result->targetPoint;
     } else
-        m_consumer.curveToQuadraticSmooth(targetPoint, m_mode);
+        m_consumer.curveToQuadraticSmooth(result->targetPoint, m_mode);
     return true;
 }
 
 bool SVGPathParser::parseArcToSegment()
 {
-    float rx;
-    float ry;
-    float angle;
-    bool largeArc;
-    bool sweep;
-    FloatPoint targetPoint;
-    if (!m_source.parseArcToSegment(rx, ry, angle, largeArc, sweep, targetPoint))
+    auto result = m_source.parseArcToSegment();
+    if (!result)
         return false;
 
     // If rx = 0 or ry = 0 then this arc is treated as a straight line segment (a "lineto") joining the endpoints.
     // http://www.w3.org/TR/SVG/implnote.html#ArcOutOfRangeParameters
     // If the current point and target point for the arc are identical, it should be treated as a zero length
     // path. This ensures continuity in animations.
-    rx = fabsf(rx);
-    ry = fabsf(ry);
+    result->rx = std::abs(result->rx);
+    result->ry = std::abs(result->ry);
     bool arcIsZeroLength = false;
     if (m_pathParsingMode == NormalizedParsing) {
         if (m_mode == RelativeCoordinates)
-            arcIsZeroLength = targetPoint == FloatPoint::zero();
+            arcIsZeroLength = result->targetPoint == FloatPoint::zero();
         else
-            arcIsZeroLength = targetPoint == m_currentPoint;
+            arcIsZeroLength = result->targetPoint == m_currentPoint;
     }
-    if (!rx || !ry || arcIsZeroLength) {
+    if (!result->rx || !result->ry || arcIsZeroLength) {
         if (m_pathParsingMode == NormalizedParsing) {
             if (m_mode == RelativeCoordinates)
-                m_currentPoint += targetPoint;
+                m_currentPoint += result->targetPoint;
             else
-                m_currentPoint = targetPoint;
+                m_currentPoint = result->targetPoint;
             m_consumer.lineTo(m_currentPoint, AbsoluteCoordinates);
         } else
-            m_consumer.lineTo(targetPoint, m_mode);
+            m_consumer.lineTo(result->targetPoint, m_mode);
         return true;
     }
 
     if (m_pathParsingMode == NormalizedParsing) {
         FloatPoint point1 = m_currentPoint;
         if (m_mode == RelativeCoordinates)
-            targetPoint += m_currentPoint;
-        m_currentPoint = targetPoint;
-        return decomposeArcToCubic(angle, rx, ry, point1, targetPoint, largeArc, sweep);
+            result->targetPoint += m_currentPoint;
+        m_currentPoint = result->targetPoint;
+        return decomposeArcToCubic(result->angle, result->rx, result->ry, point1, result->targetPoint, result->largeArc, result->sweep);
     }
-    m_consumer.arcTo(rx, ry, angle, largeArc, sweep, targetPoint, m_mode);
+    m_consumer.arcTo(result->rx, result->ry, result->angle, result->largeArc, result->sweep, result->targetPoint, m_mode);
     return true;
 }
 
@@ -312,8 +304,11 @@ bool SVGPathParser::parsePathData(bool checkForInitialMoveTo)
     if (!m_source.moveToNextToken())
         return true;
 
-    SVGPathSegType command;
-    m_source.parseSVGSegmentType(command);
+    auto parsedCommand = m_source.parseSVGSegmentType();
+    if (!parsedCommand)
+        return false;
+
+    auto command = *parsedCommand;
 
     // Path must start with moveto.
     if (checkForInitialMoveTo && command != PathSegMoveToAbs && command != PathSegMoveToRel)
index b58854f..6645c67 100644 (file)
@@ -40,15 +40,15 @@ bool SVGPathSegListSource::hasMoreData() const
     return m_itemCurrent < m_itemEnd;
 }
 
-bool SVGPathSegListSource::parseSVGSegmentType(SVGPathSegType& pathSegType)
+SVGPathSegType SVGPathSegListSource::nextCommand(SVGPathSegType)
 {
     m_segment = m_pathSegList.at(m_itemCurrent);
-    pathSegType = static_cast<SVGPathSegType>(m_segment->pathSegType());
+    SVGPathSegType pathSegType = static_cast<SVGPathSegType>(m_segment->pathSegType());
     ++m_itemCurrent;
-    return true;
+    return pathSegType;
 }
 
-SVGPathSegType SVGPathSegListSource::nextCommand(SVGPathSegType)
+Optional<SVGPathSegType> SVGPathSegListSource::parseSVGSegmentType()
 {
     m_segment = m_pathSegList.at(m_itemCurrent);
     SVGPathSegType pathSegType = static_cast<SVGPathSegType>(m_segment->pathSegType());
@@ -56,94 +56,112 @@ SVGPathSegType SVGPathSegListSource::nextCommand(SVGPathSegType)
     return pathSegType;
 }
 
-bool SVGPathSegListSource::parseMoveToSegment(FloatPoint& targetPoint)
+Optional<SVGPathSource::MoveToSegment> SVGPathSegListSource::parseMoveToSegment()
 {
     ASSERT(m_segment);
     ASSERT(m_segment->pathSegType() == PathSegMoveToAbs || m_segment->pathSegType() == PathSegMoveToRel);
     SVGPathSegSingleCoordinate* moveTo = static_cast<SVGPathSegSingleCoordinate*>(m_segment.get());
-    targetPoint = FloatPoint(moveTo->x(), moveTo->y());
-    return true;
+    
+    MoveToSegment segment;
+    segment.targetPoint = FloatPoint(moveTo->x(), moveTo->y());
+    return segment;
 }
 
-bool SVGPathSegListSource::parseLineToSegment(FloatPoint& targetPoint)
+Optional<SVGPathSource::LineToSegment> SVGPathSegListSource::parseLineToSegment()
 {
     ASSERT(m_segment);
     ASSERT(m_segment->pathSegType() == PathSegLineToAbs || m_segment->pathSegType() == PathSegLineToRel);
     SVGPathSegSingleCoordinate* lineTo = static_cast<SVGPathSegSingleCoordinate*>(m_segment.get());
-    targetPoint = FloatPoint(lineTo->x(), lineTo->y());
-    return true;
+    
+    LineToSegment segment;
+    segment.targetPoint = FloatPoint(lineTo->x(), lineTo->y());
+    return segment;
 }
 
-bool SVGPathSegListSource::parseLineToHorizontalSegment(float& x)
+Optional<SVGPathSource::LineToHorizontalSegment> SVGPathSegListSource::parseLineToHorizontalSegment()
 {
     ASSERT(m_segment);
     ASSERT(m_segment->pathSegType() == PathSegLineToHorizontalAbs || m_segment->pathSegType() == PathSegLineToHorizontalRel);
     SVGPathSegLinetoHorizontal* horizontal = static_cast<SVGPathSegLinetoHorizontal*>(m_segment.get());
-    x = horizontal->x();
-    return true;
+    
+    LineToHorizontalSegment segment;
+    segment.x = horizontal->x();
+    return segment;
 }
 
-bool SVGPathSegListSource::parseLineToVerticalSegment(float& y)
+Optional<SVGPathSource::LineToVerticalSegment> SVGPathSegListSource::parseLineToVerticalSegment()
 {
     ASSERT(m_segment);
     ASSERT(m_segment->pathSegType() == PathSegLineToVerticalAbs || m_segment->pathSegType() == PathSegLineToVerticalRel);
     SVGPathSegLinetoVertical* vertical = static_cast<SVGPathSegLinetoVertical*>(m_segment.get());
-    y = vertical->y();
-    return true;
+    
+    LineToVerticalSegment segment;
+    segment.y = vertical->y();
+    return segment;
 }
 
-bool SVGPathSegListSource::parseCurveToCubicSegment(FloatPoint& point1, FloatPoint& point2, FloatPoint& targetPoint)
+Optional<SVGPathSource::CurveToCubicSegment> SVGPathSegListSource::parseCurveToCubicSegment()
 {
     ASSERT(m_segment);
     ASSERT(m_segment->pathSegType() == PathSegCurveToCubicAbs || m_segment->pathSegType() == PathSegCurveToCubicRel);
     SVGPathSegCurvetoCubic* cubic = static_cast<SVGPathSegCurvetoCubic*>(m_segment.get());
-    point1 = FloatPoint(cubic->x1(), cubic->y1());
-    point2 = FloatPoint(cubic->x2(), cubic->y2());
-    targetPoint = FloatPoint(cubic->x(), cubic->y());
-    return true;
+    
+    CurveToCubicSegment segment;
+    segment.point1 = FloatPoint(cubic->x1(), cubic->y1());
+    segment.point2 = FloatPoint(cubic->x2(), cubic->y2());
+    segment.targetPoint = FloatPoint(cubic->x(), cubic->y());
+    return segment;
 }
 
-bool SVGPathSegListSource::parseCurveToCubicSmoothSegment(FloatPoint& point2, FloatPoint& targetPoint)
+Optional<SVGPathSource::CurveToCubicSmoothSegment> SVGPathSegListSource::parseCurveToCubicSmoothSegment()
 {
     ASSERT(m_segment);
     ASSERT(m_segment->pathSegType() == PathSegCurveToCubicSmoothAbs || m_segment->pathSegType() == PathSegCurveToCubicSmoothRel);
     SVGPathSegCurvetoCubicSmooth* cubicSmooth = static_cast<SVGPathSegCurvetoCubicSmooth*>(m_segment.get());
-    point2 = FloatPoint(cubicSmooth->x2(), cubicSmooth->y2());
-    targetPoint = FloatPoint(cubicSmooth->x(), cubicSmooth->y());
-    return true;
+    
+    CurveToCubicSmoothSegment segment;
+    segment.point2 = FloatPoint(cubicSmooth->x2(), cubicSmooth->y2());
+    segment.targetPoint = FloatPoint(cubicSmooth->x(), cubicSmooth->y());
+    return segment;
 }
 
-bool SVGPathSegListSource::parseCurveToQuadraticSegment(FloatPoint& point1, FloatPoint& targetPoint)
+Optional<SVGPathSource::CurveToQuadraticSegment> SVGPathSegListSource::parseCurveToQuadraticSegment()
 {
     ASSERT(m_segment);
     ASSERT(m_segment->pathSegType() == PathSegCurveToQuadraticAbs || m_segment->pathSegType() == PathSegCurveToQuadraticRel);
     SVGPathSegCurvetoQuadratic* quadratic = static_cast<SVGPathSegCurvetoQuadratic*>(m_segment.get());
-    point1 = FloatPoint(quadratic->x1(), quadratic->y1());
-    targetPoint = FloatPoint(quadratic->x(), quadratic->y());
-    return true;
+    
+    CurveToQuadraticSegment segment;
+    segment.point1 = FloatPoint(quadratic->x1(), quadratic->y1());
+    segment.targetPoint = FloatPoint(quadratic->x(), quadratic->y());
+    return segment;
 }
 
-bool SVGPathSegListSource::parseCurveToQuadraticSmoothSegment(FloatPoint& targetPoint)
+Optional<SVGPathSource::CurveToQuadraticSmoothSegment> SVGPathSegListSource::parseCurveToQuadraticSmoothSegment()
 {
     ASSERT(m_segment);
     ASSERT(m_segment->pathSegType() == PathSegCurveToQuadraticSmoothAbs || m_segment->pathSegType() == PathSegCurveToQuadraticSmoothRel);
     SVGPathSegSingleCoordinate* quadraticSmooth = static_cast<SVGPathSegSingleCoordinate*>(m_segment.get());
-    targetPoint = FloatPoint(quadraticSmooth->x(), quadraticSmooth->y());
-    return true;
+    
+    CurveToQuadraticSmoothSegment segment;
+    segment.targetPoint = FloatPoint(quadraticSmooth->x(), quadraticSmooth->y());
+    return segment;
 }
 
-bool SVGPathSegListSource::parseArcToSegment(float& rx, float& ry, float& angle, bool& largeArc, bool& sweep, FloatPoint& targetPoint)
+Optional<SVGPathSource::ArcToSegment> SVGPathSegListSource::parseArcToSegment()
 {
     ASSERT(m_segment);
     ASSERT(m_segment->pathSegType() == PathSegArcAbs || m_segment->pathSegType() == PathSegArcRel);
     SVGPathSegArc* arcTo = static_cast<SVGPathSegArc*>(m_segment.get());
-    rx = arcTo->r1();
-    ry = arcTo->r2();
-    angle = arcTo->angle();
-    largeArc = arcTo->largeArcFlag();
-    sweep = arcTo->sweepFlag();
-    targetPoint = FloatPoint(arcTo->x(), arcTo->y());
-    return true;
+    
+    ArcToSegment segment;
+    segment.rx = arcTo->r1();
+    segment.ry = arcTo->r2();
+    segment.angle = arcTo->angle();
+    segment.largeArc = arcTo->largeArcFlag();
+    segment.sweep = arcTo->sweepFlag();
+    segment.targetPoint = FloatPoint(arcTo->x(), arcTo->y());
+    return segment;
 }
 
 }
index 50ebb8c..9067520 100644 (file)
@@ -36,18 +36,18 @@ public:
 private:
     bool hasMoreData() const final;
     bool moveToNextToken() final { return true; }
-    bool parseSVGSegmentType(SVGPathSegType&) final;
     SVGPathSegType nextCommand(SVGPathSegType) final;
 
-    bool parseMoveToSegment(FloatPoint&) final;
-    bool parseLineToSegment(FloatPoint&) final;
-    bool parseLineToHorizontalSegment(float&) final;
-    bool parseLineToVerticalSegment(float&) final;
-    bool parseCurveToCubicSegment(FloatPoint&, FloatPoint&, FloatPoint&) final;
-    bool parseCurveToCubicSmoothSegment(FloatPoint&, FloatPoint&) final;
-    bool parseCurveToQuadraticSegment(FloatPoint&, FloatPoint&) final;
-    bool parseCurveToQuadraticSmoothSegment(FloatPoint&) final;
-    bool parseArcToSegment(float&, float&, float&, bool&, bool&, FloatPoint&) final;
+    Optional<SVGPathSegType> parseSVGSegmentType() final;
+    Optional<MoveToSegment> parseMoveToSegment() final;
+    Optional<LineToSegment> parseLineToSegment() final;
+    Optional<LineToHorizontalSegment> parseLineToHorizontalSegment() final;
+    Optional<LineToVerticalSegment> parseLineToVerticalSegment() final;
+    Optional<CurveToCubicSegment> parseCurveToCubicSegment() final;
+    Optional<CurveToCubicSmoothSegment> parseCurveToCubicSmoothSegment() final;
+    Optional<CurveToQuadraticSegment> parseCurveToQuadraticSegment() final;
+    Optional<CurveToQuadraticSmoothSegment> parseCurveToQuadraticSmoothSegment() final;
+    Optional<ArcToSegment> parseArcToSegment() final;
 
     const SVGPathSegList& m_pathSegList;
     RefPtr<SVGPathSeg> m_segment;
index 0afa5c7..c0e7301 100644 (file)
@@ -33,18 +33,63 @@ public:
 
     virtual bool hasMoreData() const = 0;
     virtual bool moveToNextToken() = 0;
-    virtual bool parseSVGSegmentType(SVGPathSegType&) = 0;
     virtual SVGPathSegType nextCommand(SVGPathSegType previousCommand) = 0;
 
-    virtual bool parseMoveToSegment(FloatPoint&) = 0;
-    virtual bool parseLineToSegment(FloatPoint&) = 0;
-    virtual bool parseLineToHorizontalSegment(float&) = 0;
-    virtual bool parseLineToVerticalSegment(float&) = 0;
-    virtual bool parseCurveToCubicSegment(FloatPoint&, FloatPoint&, FloatPoint&) = 0;
-    virtual bool parseCurveToCubicSmoothSegment(FloatPoint&, FloatPoint&) = 0;
-    virtual bool parseCurveToQuadraticSegment(FloatPoint&, FloatPoint&) = 0;
-    virtual bool parseCurveToQuadraticSmoothSegment(FloatPoint&) = 0;
-    virtual bool parseArcToSegment(float&, float&, float&, bool&, bool&, FloatPoint&) = 0;
+    virtual Optional<SVGPathSegType> parseSVGSegmentType() = 0;
+
+    struct MoveToSegment {
+        FloatPoint targetPoint;
+    };
+    virtual Optional<MoveToSegment> parseMoveToSegment() = 0;
+
+    struct LineToSegment {
+        FloatPoint targetPoint;
+    };
+    virtual Optional<LineToSegment> parseLineToSegment() = 0;
+
+    struct LineToHorizontalSegment {
+        float x = 0;
+    };
+    virtual Optional<LineToHorizontalSegment> parseLineToHorizontalSegment() = 0;
+
+    struct LineToVerticalSegment {
+        float y = 0;
+    };
+    virtual Optional<LineToVerticalSegment> parseLineToVerticalSegment() = 0;
+
+    struct CurveToCubicSegment {
+        FloatPoint point1;
+        FloatPoint point2;
+        FloatPoint targetPoint;
+    };
+    virtual Optional<CurveToCubicSegment> parseCurveToCubicSegment() = 0;
+
+    struct CurveToCubicSmoothSegment {
+        FloatPoint point2;
+        FloatPoint targetPoint;
+    };
+    virtual Optional<CurveToCubicSmoothSegment> parseCurveToCubicSmoothSegment() = 0;
+
+    struct CurveToQuadraticSegment {
+        FloatPoint point1;
+        FloatPoint targetPoint;
+    };
+    virtual Optional<CurveToQuadraticSegment> parseCurveToQuadraticSegment() = 0;
+
+    struct CurveToQuadraticSmoothSegment {
+        FloatPoint targetPoint;
+    };
+    virtual Optional<CurveToQuadraticSmoothSegment> parseCurveToQuadraticSmoothSegment() = 0;
+
+    struct ArcToSegment {
+        float rx = 0;
+        float ry = 0;
+        float angle = 0;
+        bool largeArc = false;
+        bool sweep = false;
+        FloatPoint targetPoint;
+    };
+    virtual Optional<ArcToSegment> parseArcToSegment() = 0;
 };
 
 } // namespace WebCore
index 21776b5..334e22b 100644 (file)
@@ -55,195 +55,279 @@ bool SVGPathStringSource::moveToNextToken()
     return skipOptionalSVGSpaces(m_current.m_character16, m_end.m_character16);
 }
 
-template <typename CharacterType>
-static bool parseSVGSegmentTypeHelper(const CharacterType*& current, SVGPathSegType& pathSegType)
+template <typename CharacterType> static Optional<SVGPathSegType> nextCommandHelper(const CharacterType*& current, SVGPathSegType previousCommand)
+{
+    // Check for remaining coordinates in the current command.
+    if ((*current == '+' || *current == '-' || *current == '.' || isASCIIDigit(*current))
+        && previousCommand != PathSegClosePath) {
+        if (previousCommand == PathSegMoveToAbs)
+            return PathSegLineToAbs;
+        if (previousCommand == PathSegMoveToRel)
+            return PathSegLineToRel;
+        return previousCommand;
+    }
+
+    return WTF::nullopt;
+}
+
+SVGPathSegType SVGPathStringSource::nextCommand(SVGPathSegType previousCommand)
+{
+    if (m_is8BitSource) {
+        if (auto nextCommand = nextCommandHelper(m_current.m_character8, previousCommand))
+            return *nextCommand;
+    } else {
+        if (auto nextCommand = nextCommandHelper(m_current.m_character16, previousCommand))
+            return *nextCommand;
+    }
+
+    return *parseSVGSegmentType();
+}
+
+template <typename CharacterType> static SVGPathSegType parseSVGSegmentTypeHelper(const CharacterType*& current)
 {
     switch (*(current++)) {
     case 'Z':
     case 'z':
-        pathSegType = PathSegClosePath;
-        break;
+        return PathSegClosePath;
     case 'M':
-        pathSegType = PathSegMoveToAbs;
-        break;
+        return PathSegMoveToAbs;
     case 'm':
-        pathSegType = PathSegMoveToRel;
-        break;
+        return PathSegMoveToRel;
     case 'L':
-        pathSegType = PathSegLineToAbs;
-        break;
+        return PathSegLineToAbs;
     case 'l':
-        pathSegType = PathSegLineToRel;
-        break;
+        return PathSegLineToRel;
     case 'C':
-        pathSegType = PathSegCurveToCubicAbs;
-        break;
+        return PathSegCurveToCubicAbs;
     case 'c':
-        pathSegType = PathSegCurveToCubicRel;
-        break;
+        return PathSegCurveToCubicRel;
     case 'Q':
-        pathSegType = PathSegCurveToQuadraticAbs;
-        break;
+        return PathSegCurveToQuadraticAbs;
     case 'q':
-        pathSegType = PathSegCurveToQuadraticRel;
-        break;
+        return PathSegCurveToQuadraticRel;
     case 'A':
-        pathSegType = PathSegArcAbs;
-        break;
+        return PathSegArcAbs;
     case 'a':
-        pathSegType = PathSegArcRel;
-        break;
+        return PathSegArcRel;
     case 'H':
-        pathSegType = PathSegLineToHorizontalAbs;
-        break;
+        return PathSegLineToHorizontalAbs;
     case 'h':
-        pathSegType = PathSegLineToHorizontalRel;
-        break;
+        return PathSegLineToHorizontalRel;
     case 'V':
-        pathSegType = PathSegLineToVerticalAbs;
-        break;
+        return PathSegLineToVerticalAbs;
     case 'v':
-        pathSegType = PathSegLineToVerticalRel;
-        break;
+        return PathSegLineToVerticalRel;
     case 'S':
-        pathSegType = PathSegCurveToCubicSmoothAbs;
-        break;
+        return PathSegCurveToCubicSmoothAbs;
     case 's':
-        pathSegType = PathSegCurveToCubicSmoothRel;
-        break;
+        return PathSegCurveToCubicSmoothRel;
     case 'T':
-        pathSegType = PathSegCurveToQuadraticSmoothAbs;
-        break;
+        return PathSegCurveToQuadraticSmoothAbs;
     case 't':
-        pathSegType = PathSegCurveToQuadraticSmoothRel;
-        break;
+        return PathSegCurveToQuadraticSmoothRel;
     default:
-        pathSegType = PathSegUnknown;
+        return PathSegUnknown;
     }
-    return true;
 }
 
-bool SVGPathStringSource::parseSVGSegmentType(SVGPathSegType& pathSegType)
+Optional<SVGPathSegType> SVGPathStringSource::parseSVGSegmentType()
 {
     if (m_is8BitSource)
-        return parseSVGSegmentTypeHelper(m_current.m_character8, pathSegType);
-    return parseSVGSegmentTypeHelper(m_current.m_character16, pathSegType);
+        return parseSVGSegmentTypeHelper(m_current.m_character8);
+    return parseSVGSegmentTypeHelper(m_current.m_character16);
 }
 
-template <typename CharacterType>
-static bool nextCommandHelper(const CharacterType*& current, SVGPathSegType previousCommand, SVGPathSegType& nextCommand)
+Optional<SVGPathSource::MoveToSegment> SVGPathStringSource::parseMoveToSegment()
 {
-    // Check for remaining coordinates in the current command.
-    if ((*current == '+' || *current == '-' || *current == '.' || isASCIIDigit(*current))
-        && previousCommand != PathSegClosePath) {
-        if (previousCommand == PathSegMoveToAbs) {
-            nextCommand = PathSegLineToAbs;
-            return true;
-        }
-        if (previousCommand == PathSegMoveToRel) {
-            nextCommand = PathSegLineToRel;
-            return true;
-        }
-        nextCommand = previousCommand;
-        return true;
-    }
+    auto helper = [](const auto*& current, const auto* end) -> Optional<MoveToSegment> {
+        auto targetPoint = parseFloatPoint(current, end);
+        if (!targetPoint)
+            return WTF::nullopt;
+        
+        MoveToSegment segment;
+        segment.targetPoint = WTFMove(*targetPoint);
+        return segment;
+    };
 
-    return false;
+    if (m_is8BitSource)
+        return helper(m_current.m_character8, m_end.m_character8);
+    return helper(m_current.m_character16, m_end.m_character16);
 }
 
-SVGPathSegType SVGPathStringSource::nextCommand(SVGPathSegType previousCommand)
+Optional<SVGPathSource::LineToSegment> SVGPathStringSource::parseLineToSegment()
 {
-    SVGPathSegType nextCommand;
-    if (m_is8BitSource) {
-        if (nextCommandHelper(m_current.m_character8, previousCommand, nextCommand))
-            return nextCommand;
-    } else {
-        if (nextCommandHelper(m_current.m_character16, previousCommand, nextCommand))
-            return nextCommand;
-    }
-
-    parseSVGSegmentType(nextCommand);
-    return nextCommand;
-}
+    auto helper = [](const auto*& current, const auto* end) -> Optional<LineToSegment> {
+        auto targetPoint = parseFloatPoint(current, end);
+        if (!targetPoint)
+            return WTF::nullopt;
+        
+        LineToSegment segment;
+        segment.targetPoint = WTFMove(*targetPoint);
+        return segment;
+    };
 
-bool SVGPathStringSource::parseMoveToSegment(FloatPoint& targetPoint)
-{
     if (m_is8BitSource)
-        return parseFloatPoint(m_current.m_character8, m_end.m_character8, targetPoint);
-    return parseFloatPoint(m_current.m_character16, m_end.m_character16, targetPoint);
+        return helper(m_current.m_character8, m_end.m_character8);
+    return helper(m_current.m_character16, m_end.m_character16);
 }
 
-bool SVGPathStringSource::parseLineToSegment(FloatPoint& targetPoint)
+Optional<SVGPathSource::LineToHorizontalSegment> SVGPathStringSource::parseLineToHorizontalSegment()
 {
-    if (m_is8BitSource)
-        return parseFloatPoint(m_current.m_character8, m_end.m_character8, targetPoint);
-    return parseFloatPoint(m_current.m_character16, m_end.m_character16, targetPoint);
-}
+    auto helper = [](const auto*& current, const auto* end) -> Optional<LineToHorizontalSegment> {
+        auto x = parseNumber(current, end);
+        if (!x)
+            return WTF::nullopt;
+        
+        LineToHorizontalSegment segment;
+        segment.x = *x;
+        return segment;
+    };
 
-bool SVGPathStringSource::parseLineToHorizontalSegment(float& x)
-{
     if (m_is8BitSource)
-        return parseNumber(m_current.m_character8, m_end.m_character8, x);
-    return parseNumber(m_current.m_character16, m_end.m_character16, x);
+        return helper(m_current.m_character8, m_end.m_character8);
+    return helper(m_current.m_character16, m_end.m_character16);
 }
 
-bool SVGPathStringSource::parseLineToVerticalSegment(float& y)
+Optional<SVGPathSource::LineToVerticalSegment> SVGPathStringSource::parseLineToVerticalSegment()
 {
+    auto helper = [](const auto*& current, const auto* end) -> Optional<LineToVerticalSegment> {
+        auto y = parseNumber(current, end);
+        if (!y)
+            return WTF::nullopt;
+        
+        LineToVerticalSegment segment;
+        segment.y = *y;
+        return segment;
+    };
+
     if (m_is8BitSource)
-        return parseNumber(m_current.m_character8, m_end.m_character8, y);
-    return parseNumber(m_current.m_character16, m_end.m_character16, y);
+        return helper(m_current.m_character8, m_end.m_character8);
+    return helper(m_current.m_character16, m_end.m_character16);
 }
 
-bool SVGPathStringSource::parseCurveToCubicSegment(FloatPoint& point1, FloatPoint& point2, FloatPoint& targetPoint)
+Optional<SVGPathSource::CurveToCubicSegment> SVGPathStringSource::parseCurveToCubicSegment()
 {
+    auto helper = [](const auto*& current, const auto* end) -> Optional<CurveToCubicSegment> {
+        auto point1 = parseFloatPoint(current, end);
+        if (!point1)
+            return WTF::nullopt;
+
+        auto point2 = parseFloatPoint(current, end);
+        if (!point2)
+            return WTF::nullopt;
+
+        auto targetPoint = parseFloatPoint(current, end);
+        if (!targetPoint)
+            return WTF::nullopt;
+
+        CurveToCubicSegment segment;
+        segment.point1 = *point1;
+        segment.point2 = *point2;
+        segment.targetPoint = *targetPoint;
+        return segment;
+    };
+
     if (m_is8BitSource)
-        return parseFloatPoint3(m_current.m_character8, m_end.m_character8, point1, point2, targetPoint);
-    return parseFloatPoint3(m_current.m_character16, m_end.m_character16, point1, point2, targetPoint);
+        return helper(m_current.m_character8, m_end.m_character8);
+    return helper(m_current.m_character16, m_end.m_character16);
 }
 
-bool SVGPathStringSource::parseCurveToCubicSmoothSegment(FloatPoint& point1, FloatPoint& targetPoint)
+Optional<SVGPathSource::CurveToCubicSmoothSegment> SVGPathStringSource::parseCurveToCubicSmoothSegment()
 {
+    auto helper = [](const auto*& current, const auto* end) -> Optional<CurveToCubicSmoothSegment> {
+        auto point2 = parseFloatPoint(current, end);
+        if (!point2)
+            return WTF::nullopt;
+
+        auto targetPoint = parseFloatPoint(current, end);
+        if (!targetPoint)
+            return WTF::nullopt;
+
+        CurveToCubicSmoothSegment segment;
+        segment.point2 = *point2;
+        segment.targetPoint = *targetPoint;
+        return segment;
+    };
+
     if (m_is8BitSource)
-        return parseFloatPoint2(m_current.m_character8, m_end.m_character8, point1, targetPoint);
-    return parseFloatPoint2(m_current.m_character16, m_end.m_character16, point1, targetPoint);
+        return helper(m_current.m_character8, m_end.m_character8);
+    return helper(m_current.m_character16, m_end.m_character16);
 }
 
-bool SVGPathStringSource::parseCurveToQuadraticSegment(FloatPoint& point2, FloatPoint& targetPoint)
+Optional<SVGPathSource::CurveToQuadraticSegment> SVGPathStringSource::parseCurveToQuadraticSegment()
 {
+    auto helper = [](const auto*& current, const auto* end) -> Optional<CurveToQuadraticSegment> {
+        auto point1 = parseFloatPoint(current, end);
+        if (!point1)
+            return WTF::nullopt;
+
+        auto targetPoint = parseFloatPoint(current, end);
+        if (!targetPoint)
+            return WTF::nullopt;
+
+        CurveToQuadraticSegment segment;
+        segment.point1 = *point1;
+        segment.targetPoint = *targetPoint;
+        return segment;
+    };
+
     if (m_is8BitSource)
-        return parseFloatPoint2(m_current.m_character8, m_end.m_character8, point2, targetPoint);
-    return parseFloatPoint2(m_current.m_character16, m_end.m_character16, point2, targetPoint);
+        return helper(m_current.m_character8, m_end.m_character8);
+    return helper(m_current.m_character16, m_end.m_character16);
 }
 
-bool SVGPathStringSource::parseCurveToQuadraticSmoothSegment(FloatPoint& targetPoint)
+Optional<SVGPathSource::CurveToQuadraticSmoothSegment> SVGPathStringSource::parseCurveToQuadraticSmoothSegment()
 {
+    auto helper = [](const auto*& current, const auto* end) -> Optional<CurveToQuadraticSmoothSegment> {
+        auto targetPoint = parseFloatPoint(current, end);
+        if (!targetPoint)
+            return WTF::nullopt;
+
+        CurveToQuadraticSmoothSegment segment;
+        segment.targetPoint = *targetPoint;
+        return segment;
+    };
+
     if (m_is8BitSource)
-        return parseFloatPoint(m_current.m_character8, m_end.m_character8, targetPoint);
-    return parseFloatPoint(m_current.m_character16, m_end.m_character16, targetPoint);
+        return helper(m_current.m_character8, m_end.m_character8);
+    return helper(m_current.m_character16, m_end.m_character16);
 }
 
-template <typename CharacterType>
-static bool parseArcToSegmentHelper(const CharacterType*& current, const CharacterType* end, float& rx, float& ry, float& angle, bool& largeArc, bool& sweep, FloatPoint& targetPoint)
+Optional<SVGPathSource::ArcToSegment> SVGPathStringSource::parseArcToSegment()
 {
-    float toX;
-    float toY;
-    if (!parseNumber(current, end, rx)
-        || !parseNumber(current, end, ry)
-        || !parseNumber(current, end, angle)
-        || !parseArcFlag(current, end, largeArc)
-        || !parseArcFlag(current, end, sweep)
-        || !parseNumber(current, end, toX)
-        || !parseNumber(current, end, toY))
-        return false;
-    targetPoint = FloatPoint(toX, toY);
-    return true;
-}
+    auto helper = [](const auto*& current, const auto* end) -> Optional<ArcToSegment> {
+        auto rx = parseNumber(current, end);
+        if (!rx)
+            return WTF::nullopt;
+        auto ry = parseNumber(current, end);
+        if (!ry)
+            return WTF::nullopt;
+        auto angle = parseNumber(current, end);
+        if (!angle)
+            return WTF::nullopt;
+        auto largeArc = parseArcFlag(current, end);
+        if (!largeArc)
+            return WTF::nullopt;
+        auto sweep = parseArcFlag(current, end);
+        if (!sweep)
+            return WTF::nullopt;
+        auto targetPoint = parseFloatPoint(current, end);
+        if (!targetPoint)
+            return WTF::nullopt;
+
+        ArcToSegment segment;
+        segment.rx = *rx;
+        segment.ry = *ry;
+        segment.angle = *angle;
+        segment.largeArc = *largeArc;
+        segment.sweep = *sweep;
+        segment.targetPoint = *targetPoint;
+        return segment;
+    };
 
-bool SVGPathStringSource::parseArcToSegment(float& rx, float& ry, float& angle, bool& largeArc, bool& sweep, FloatPoint& targetPoint)
-{
     if (m_is8BitSource)
-        return parseArcToSegmentHelper(m_current.m_character8, m_end.m_character8, rx, ry, angle, largeArc, sweep, targetPoint);
-    return parseArcToSegmentHelper(m_current.m_character16, m_end.m_character16, rx, ry, angle, largeArc, sweep, targetPoint);
+        return helper(m_current.m_character8, m_end.m_character8);
+    return helper(m_current.m_character16, m_end.m_character16);
 }
 
 } // namespace WebKit
index e14b159..896da05 100644 (file)
@@ -32,18 +32,18 @@ public:
 private:
     bool hasMoreData() const final;
     bool moveToNextToken() final;
-    bool parseSVGSegmentType(SVGPathSegType&) final;
     SVGPathSegType nextCommand(SVGPathSegType previousCommand) final;
 
-    bool parseMoveToSegment(FloatPoint&) final;
-    bool parseLineToSegment(FloatPoint&) final;
-    bool parseLineToHorizontalSegment(float&) final;
-    bool parseLineToVerticalSegment(float&) final;
-    bool parseCurveToCubicSegment(FloatPoint&, FloatPoint&, FloatPoint&) final;
-    bool parseCurveToCubicSmoothSegment(FloatPoint&, FloatPoint&) final;
-    bool parseCurveToQuadraticSegment(FloatPoint&, FloatPoint&) final;
-    bool parseCurveToQuadraticSmoothSegment(FloatPoint&) final;
-    bool parseArcToSegment(float&, float&, float&, bool&, bool&, FloatPoint&) final;
+    Optional<SVGPathSegType> parseSVGSegmentType() final;
+    Optional<MoveToSegment> parseMoveToSegment() final;
+    Optional<LineToSegment> parseLineToSegment() final;
+    Optional<LineToHorizontalSegment> parseLineToHorizontalSegment() final;
+    Optional<LineToVerticalSegment> parseLineToVerticalSegment() final;
+    Optional<CurveToCubicSegment> parseCurveToCubicSegment() final;
+    Optional<CurveToCubicSmoothSegment> parseCurveToCubicSmoothSegment() final;
+    Optional<CurveToQuadraticSegment> parseCurveToQuadraticSegment() final;
+    Optional<CurveToQuadraticSmoothSegment> parseCurveToQuadraticSmoothSegment() final;
+    Optional<ArcToSegment> parseArcToSegment() final;
 
     String m_string;
     bool m_is8BitSource;
index 25d033a..4119a07 100644 (file)
@@ -63,12 +63,13 @@ public:
         bool delimParsed = false;
         while (cur < end) {
             delimParsed = false;
-            float xPos = 0.0f;
-            if (!parseNumber(cur, end, xPos))
+
+            auto xPos = parseNumber(cur, end);
+            if (!xPos)
                 return false;
 
-            float yPos = 0.0f;
-            if (!parseNumber(cur, end, yPos, false))
+            auto yPos = parseNumber(cur, end, SuffixSkippingPolicy::DontSkip);
+            if (!yPos)
                 return false;
 
             skipOptionalSVGSpaces(cur, end);
@@ -79,7 +80,7 @@ public:
             }
             skipOptionalSVGSpaces(cur, end);
 
-            append(SVGPoint::create({ xPos, yPos }));
+            append(SVGPoint::create({ *xPos, *yPos }));
         }
 
         return !delimParsed;
index 8067517..f3d75ef 100644 (file)
@@ -229,8 +229,8 @@ private:
     void addCodepointRanges(const UnicodeRanges&, HashSet<Glyph>& glyphSet) const;
     void addCodepoints(const HashSet<String>& codepoints, HashSet<Glyph>& glyphSet) const;
     void addGlyphNames(const HashSet<String>& glyphNames, HashSet<Glyph>& glyphSet) const;
-    void addKerningPair(Vector<KerningData>&, const SVGKerningPair&) const;
-    template<typename T> size_t appendKERNSubtable(bool (T::*buildKerningPair)(SVGKerningPair&) const, uint16_t coverage);
+    void addKerningPair(Vector<KerningData>&, SVGKerningPair&&) const;
+    template<typename T> size_t appendKERNSubtable(Optional<SVGKerningPair> (T::*buildKerningPair)() const, uint16_t coverage);
     size_t finishAppendingKERNSubtable(Vector<KerningData>, uint16_t coverage);
 
     void appendLigatureSubtable(size_t subtableRecordLocation);
@@ -1040,7 +1040,7 @@ void SVGToOTFFontConverter::addGlyphNames(const HashSet<String>& glyphNames, Has
     }
 }
 
-void SVGToOTFFontConverter::addKerningPair(Vector<KerningData>& data, const SVGKerningPair& kerningPair) const
+void SVGToOTFFontConverter::addKerningPair(Vector<KerningData>& data, SVGKerningPair&& kerningPair) const
 {
     HashSet<Glyph> glyphSet1;
     HashSet<Glyph> glyphSet2;
@@ -1059,13 +1059,12 @@ void SVGToOTFFontConverter::addKerningPair(Vector<KerningData>& data, const SVGK
     }
 }
 
-template<typename T> inline size_t SVGToOTFFontConverter::appendKERNSubtable(bool (T::*buildKerningPair)(SVGKerningPair&) const, uint16_t coverage)
+template<typename T> inline size_t SVGToOTFFontConverter::appendKERNSubtable(Optional<SVGKerningPair> (T::*buildKerningPair)() const, uint16_t coverage)
 {
     Vector<KerningData> kerningData;
     for (auto& element : childrenOfType<T>(m_fontElement)) {
-        SVGKerningPair kerningPair;
-        if ((element.*buildKerningPair)(kerningPair))
-            addKerningPair(kerningData, kerningPair);
+        if (auto kerningPair = (element.*buildKerningPair)())
+            addKerningPair(kerningData, WTFMove(*kerningPair));
     }
     return finishAppendingKERNSubtable(WTFMove(kerningData), coverage);
 }
index 4e96b6a..52c507a 100644 (file)
@@ -114,17 +114,18 @@ private:
         bool delimParsed = false;
         while (start < end) {
             delimParsed = false;
-            SVGTransformValue::SVGTransformType type = SVGTransformValue::SVG_TRANSFORM_UNKNOWN;
             skipOptionalSVGSpaces(start, end);
-
-            if (!SVGTransformable::parseAndSkipType(start, end, type))
+            
+            auto type = SVGTransformable::parseAndSkipType(start, end);
+            if (!type)
                 return false;
 
-            Ref<SVGTransform> transform = SVGTransform::create(type);
-            if (!SVGTransformable::parseTransformValue(type, start, end, transform->value()))
+            auto parsedTransformValue = SVGTransformable::parseTransformValue(*type, start, end);
+            if (!parsedTransformValue)
                 return false;
 
-            append(WTFMove(transform));
+            append(SVGTransform::create(*parsedTransformValue));
+
             skipOptionalSVGSpaces(start, end);
             if (start < end && *start == ',') {
                 delimParsed = true;
index 06d7a62..dfc521e 100644 (file)
@@ -43,8 +43,12 @@ static int parseTransformParamList(const UChar*& ptr, const UChar* end, float* v
     skipOptionalSVGSpaces(ptr, end);
 
     while (requiredParams < required) {
-        if (ptr >= end || !parseNumber(ptr, end, values[requiredParams], false))
+        if (ptr >= end)
             return -1;
+        auto parsedNumber = parseNumber(ptr, end, SuffixSkippingPolicy::DontSkip);
+        if (!parsedNumber)
+            return -1;
+        values[requiredParams] = *parsedNumber;
         requiredParams++;
         if (requiredParams < required)
             skipOptionalSVGSpacesOrDelimiter(ptr, end);
@@ -63,8 +67,12 @@ static int parseTransformParamList(const UChar*& ptr, const UChar* end, float* v
             return -1;
     } else {
         while (optionalParams < optional) {
-            if (ptr >= end || !parseNumber(ptr, end, values[requiredParams + optionalParams], false))
+            if (ptr >= end)
+                return -1;
+            auto parsedNumber = parseNumber(ptr, end, SuffixSkippingPolicy::DontSkip);
+            if (!parsedNumber)
                 return -1;
+            values[requiredParams + optionalParams] = *parsedNumber;
             optionalParams++;
             if (optionalParams < optional)
                 skipOptionalSVGSpacesOrDelimiter(ptr, end);
@@ -90,16 +98,17 @@ static const int optionalValuesForType[] =  {0, 0, 1, 1, 2, 0, 0};
 // This destructor is needed in order to link correctly with Intel ICC.
 SVGTransformable::~SVGTransformable() = default;
 
-bool SVGTransformable::parseTransformValue(SVGTransformValue::SVGTransformType type, const UChar*& ptr, const UChar* end, SVGTransformValue& transform)
+Optional<SVGTransformValue> SVGTransformable::parseTransformValue(SVGTransformValue::SVGTransformType type, const UChar*& ptr, const UChar* end)
 {
     if (type == SVGTransformValue::SVG_TRANSFORM_UNKNOWN)
-        return false;
+        return WTF::nullopt;
 
     int valueCount = 0;
     float values[] = {0, 0, 0, 0, 0, 0};
     if ((valueCount = parseTransformParamList(ptr, end, values, requiredValuesForType[type], optionalValuesForType[type])) < 0)
-        return false;
+        return WTF::nullopt;
 
+    SVGTransformValue transform;
     switch (type) {
     case SVGTransformValue::SVG_TRANSFORM_UNKNOWN:
         ASSERT_NOT_REACHED();
@@ -133,7 +142,7 @@ bool SVGTransformable::parseTransformValue(SVGTransformValue::SVGTransformType t
         break;
     }
 
-    return true;
+    return transform;
 }
 
 static const UChar skewXDesc[] =  {'s', 'k', 'e', 'w', 'X'};
@@ -143,39 +152,35 @@ static const UChar translateDesc[] =  {'t', 'r', 'a', 'n', 's', 'l', 'a', 't', '
 static const UChar rotateDesc[] =  {'r', 'o', 't', 'a', 't', 'e'};
 static const UChar matrixDesc[] =  {'m', 'a', 't', 'r', 'i', 'x'};
 
-bool SVGTransformable::parseAndSkipType(const UChar*& currTransform, const UChar* end, SVGTransformValue::SVGTransformType& type)
+Optional<SVGTransformValue::SVGTransformType> SVGTransformable::parseAndSkipType(const UChar*& currTransform, const UChar* end)
 {
     if (currTransform >= end)
-        return false;
+        return WTF::nullopt;
 
     if (*currTransform == 's') {
         if (skipString(currTransform, end, skewXDesc, WTF_ARRAY_LENGTH(skewXDesc)))
-            type = SVGTransformValue::SVG_TRANSFORM_SKEWX;
+            return SVGTransformValue::SVG_TRANSFORM_SKEWX;
         else if (skipString(currTransform, end, skewYDesc, WTF_ARRAY_LENGTH(skewYDesc)))
-            type = SVGTransformValue::SVG_TRANSFORM_SKEWY;
+            return SVGTransformValue::SVG_TRANSFORM_SKEWY;
         else if (skipString(currTransform, end, scaleDesc, WTF_ARRAY_LENGTH(scaleDesc)))
-            type = SVGTransformValue::SVG_TRANSFORM_SCALE;
+            return SVGTransformValue::SVG_TRANSFORM_SCALE;
         else
-            return false;
+            return WTF::nullopt;
     } else if (skipString(currTransform, end, translateDesc, WTF_ARRAY_LENGTH(translateDesc)))
-        type = SVGTransformValue::SVG_TRANSFORM_TRANSLATE;
+        return SVGTransformValue::SVG_TRANSFORM_TRANSLATE;
     else if (skipString(currTransform, end, rotateDesc, WTF_ARRAY_LENGTH(rotateDesc)))
-        type = SVGTransformValue::SVG_TRANSFORM_ROTATE;
+        return SVGTransformValue::SVG_TRANSFORM_ROTATE;
     else if (skipString(currTransform, end, matrixDesc, WTF_ARRAY_LENGTH(matrixDesc)))
-        type = SVGTransformValue::SVG_TRANSFORM_MATRIX;
-    else
-        return false;
+        return SVGTransformValue::SVG_TRANSFORM_MATRIX;
 
-    return true;
+    return WTF::nullopt;
 }
 
 SVGTransformValue::SVGTransformType SVGTransformable::parseTransformType(const String& typeString)
 {
-    SVGTransformValue::SVGTransformType type = SVGTransformValue::SVG_TRANSFORM_UNKNOWN;
     auto upconvertedCharacters = StringView(typeString).upconvertedCharacters();
     const UChar* characters = upconvertedCharacters;
-    parseAndSkipType(characters, characters + typeString.length(), type);
-    return type;
+    return parseAndSkipType(characters, characters + typeString.length()).valueOr(SVGTransformValue::SVG_TRANSFORM_UNKNOWN);
 }
 
 }
index b70cf8c..36d2795 100644 (file)
@@ -32,9 +32,9 @@ class SVGTransformable : public SVGLocatable {
 public:
     virtual ~SVGTransformable();
 
-    static bool parseTransformValue(SVGTransformValue::SVGTransformType, const UChar*& ptr, const UChar* end, SVGTransformValue&);
+    static Optional<SVGTransformValue> parseTransformValue(SVGTransformValue::SVGTransformType, const UChar*& ptr, const UChar* end);
     static SVGTransformValue::SVGTransformType parseTransformType(const String&);
-    static bool parseAndSkipType(const UChar*& currTransform, const UChar* end, SVGTransformValue::SVGTransformType&);
+    static Optional<SVGTransformValue::SVGTransformType> parseAndSkipType(const UChar*& currTransform, const UChar* end);
 
     AffineTransform localCoordinateSpaceTransform(SVGLocatable::CTMScope) const override { return animatedLocalTransform(); }
     virtual AffineTransform animatedLocalTransform() const = 0;
index 8e89c5f..a0b1e79 100644 (file)
@@ -43,24 +43,47 @@ Ref<SVGVKernElement> SVGVKernElement::create(const QualifiedName& tagName, Docum
     return adoptRef(*new SVGVKernElement(tagName, document));
 }
 
-bool SVGVKernElement::buildVerticalKerningPair(SVGKerningPair& kerningPair) const
+Optional<SVGKerningPair> SVGVKernElement::buildVerticalKerningPair() const
 {
+    // FIXME: Can this be shared with SVGHKernElement::buildVerticalKerningPair?
+
     auto& u1 = attributeWithoutSynchronization(SVGNames::u1Attr);
     auto& g1 = attributeWithoutSynchronization(SVGNames::g1Attr);
+    if (u1.isEmpty() && g1.isEmpty())
+        return WTF::nullopt;
+
     auto& u2 = attributeWithoutSynchronization(SVGNames::u2Attr);
     auto& g2 = attributeWithoutSynchronization(SVGNames::g2Attr);
-    if ((u1.isEmpty() && g1.isEmpty()) || (u2.isEmpty() && g2.isEmpty()))
-        return false;
+    if (u2.isEmpty() && g2.isEmpty())
+        return WTF::nullopt;
+
+    auto glyphName1 = parseGlyphName(g1);
+    if (!glyphName1)
+        return WTF::nullopt;
+    auto glyphName2 = parseGlyphName(g2);
+    if (!glyphName2)
+        return WTF::nullopt;
+    auto unicodeString1 = parseKerningUnicodeString(u1);
+    if (!unicodeString1)
+        return WTF::nullopt;
+    auto unicodeString2 = parseKerningUnicodeString(u2);
+    if (!unicodeString2)
+        return WTF::nullopt;
+
+    bool ok = false;
+    auto kerning = attributeWithoutSynchronization(SVGNames::kAttr).string().toFloat(&ok);
+    if (!ok)
+        return WTF::nullopt;
 
-    if (parseGlyphName(g1, kerningPair.glyphName1)
-        && parseGlyphName(g2, kerningPair.glyphName2)
-        && parseKerningUnicodeString(u1, kerningPair.unicodeRange1, kerningPair.unicodeName1)
-        && parseKerningUnicodeString(u2, kerningPair.unicodeRange2, kerningPair.unicodeName2)) {
-        bool ok = false;
-        kerningPair.kerning = attributeWithoutSynchronization(SVGNames::kAttr).string().toFloat(&ok);
-        return ok;
-    }
-    return false;
+    return SVGKerningPair {
+        WTFMove(unicodeString1->first),
+        WTFMove(unicodeString1->second),
+        WTFMove(*glyphName1),
+        WTFMove(unicodeString2->first),
+        WTFMove(unicodeString2->second),
+        WTFMove(*glyphName2),
+        kerning
+    };
 }
 
 }
index 78c8d55..05896f2 100644 (file)
@@ -31,7 +31,7 @@ class SVGVKernElement final : public SVGElement {
 public:
     static Ref<SVGVKernElement> create(const QualifiedName&, Document&);
 
-    bool buildVerticalKerningPair(SVGKerningPair& kerningPair) const;
+    Optional<SVGKerningPair> buildVerticalKerningPair() const;
 
 private:
     SVGVKernElement(const QualifiedName&, Document&);
index 8f42351..7507293 100644 (file)
@@ -89,10 +89,10 @@ bool SVGViewSpec::parseViewSpec(const String& viewSpec)
                 if (currViewSpec >= end || *currViewSpec != '(')
                     return false;
                 currViewSpec++;
-                FloatRect viewBox;
-                if (!SVGFitToViewBox::parseViewBox(currViewSpec, end, viewBox, false))
+                auto viewBox = SVGFitToViewBox::parseViewBox(currViewSpec, end, false);
+                if (!viewBox)
                     return false;
-                setViewBox(viewBox);
+                setViewBox(WTFMove(*viewBox));
                 if (currViewSpec >= end || *currViewSpec != ')')
                     return false;
                 currViewSpec++;
index e572d02..0b2deee 100644 (file)
@@ -254,11 +254,7 @@ public:
 
     Optional<float> calculateDistance(SVGElement*, const String& from, const String& to) const override
     {
-        float fromNumber = 0;
-        float toNumber = 0;
-        parseNumberFromString(from, fromNumber);
-        parseNumberFromString(to, toNumber);
-        return fabsf(toNumber - fromNumber);
+        return std::abs(parseNumber(to).valueOr(0) - parseNumber(from).valueOr(0));
     }
 
 private:
index bfcd211..b77ce58 100644 (file)
@@ -75,10 +75,10 @@ struct SVGPropertyTraits<std::pair<int, int>> {
     static std::pair<int, int> initialValue() { return { }; }
     static std::pair<int, int> fromString(const String& string)
     {
-        float firstNumber = 0, secondNumber = 0;
-        if (!parseNumberOptionalNumber(string, firstNumber, secondNumber))
+        auto result = parseNumberOptionalNumber(string);
+        if (!result)
             return { };
-        return std::make_pair(static_cast<int>(roundf(firstNumber)), static_cast<int>(roundf(secondNumber)));
+        return std::make_pair(static_cast<int>(std::round(result->first)), static_cast<int>(std::round(result->second)));
     }
     static Optional<std::pair<int, int>> parse(const QualifiedName&, const String&) { ASSERT_NOT_REACHED(); return initialValue(); }
     static String toString(std::pair<int, int>) { ASSERT_NOT_REACHED(); return emptyString(); }
@@ -89,17 +89,11 @@ struct SVGPropertyTraits<float> {
     static float initialValue() { return 0; }
     static float fromString(const String& string)
     {
-        float number = 0;
-        if (!parseNumberFromString(string, number))
-            return 0;
-        return number;
+        return parseNumber(string).valueOr(0);
     }
     static Optional<float> parse(const QualifiedName&, const String& string)
     {
-        float number;
-        if (!parseNumberFromString(string, number))
-            return WTF::nullopt;
-        return number;
+        return parseNumber(string);
     }
     static String toString(float type) { return String::number(type); }
 };
@@ -109,10 +103,7 @@ struct SVGPropertyTraits<std::pair<float, float>> {
     static std::pair<float, float> initialValue() { return { }; }
     static std::pair<float, float> fromString(const String& string)
     {
-        float firstNumber = 0, secondNumber = 0;
-        if (!parseNumberOptionalNumber(string, firstNumber, secondNumber))
-            return { };
-        return std::make_pair(firstNumber, secondNumber);
+        return parseNumberOptionalNumber(string).valueOr(std::pair<float, float> { });
     }
     static Optional<std::pair<float, float>> parse(const QualifiedName&, const String&) { ASSERT_NOT_REACHED(); return initialValue(); }
     static String toString(std::pair<float, float>) { ASSERT_NOT_REACHED(); return emptyString(); }
@@ -123,17 +114,11 @@ struct SVGPropertyTraits<FloatPoint> {
     static FloatPoint initialValue() { return FloatPoint(); }
     static FloatPoint fromString(const String& string)
     {
-        FloatPoint point;
-        if (!parsePoint(string, point))
-            return { };
-        return point;
+        return parsePoint(string).valueOr(FloatPoint { });
     }
     static Optional<FloatPoint> parse(const QualifiedName&, const String& string)
     {
-        FloatPoint point;
-        if (!parsePoint(string, point))
-            return WTF::nullopt;
-        return point;
+        return parsePoint(string);
     }
     static String toString(const FloatPoint& type)
     {
@@ -146,17 +131,11 @@ struct SVGPropertyTraits<FloatRect> {
     static FloatRect initialValue() { return FloatRect(); }
     static FloatRect fromString(const String& string)
     {
-        FloatRect rect;
-        if (!parseRect(string, rect))
-            return { };
-        return rect;
+        return parseRect(string).valueOr(FloatRect { });
     }
     static Optional<FloatRect> parse(const QualifiedName&, const String& string)
     {
-        FloatRect rect;
-        if (!parseRect(string, rect))
-            return WTF::nullopt;
-        return rect;
+        return parseRect(string);
     }
     static String toString(const FloatRect& type)
     {