2017-08-12 16:38:52 +00:00
|
|
|
/*
|
|
|
|
* Copyright (C) Research In Motion Limited 2010. All rights reserved.
|
|
|
|
* Copyright (C) 2013 Apple Inc. All rights reserved.
|
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Library General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Library General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Library General Public License
|
|
|
|
* along with this library; see the file COPYING.LIB. If not, write to
|
|
|
|
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
|
|
* Boston, MA 02110-1301, USA.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
#include "SVGPathStringSource.h"
|
|
|
|
|
|
|
|
#include "SVGParserUtilities.h"
|
|
|
|
|
|
|
|
namespace WebCore {
|
|
|
|
|
|
|
|
SVGPathStringSource::SVGPathStringSource(const String& string)
|
|
|
|
: m_string(string)
|
|
|
|
, m_is8BitSource(string.is8Bit())
|
|
|
|
{
|
|
|
|
ASSERT(!string.isEmpty());
|
|
|
|
|
2023-01-25 00:42:21 +00:00
|
|
|
if (m_is8BitSource)
|
|
|
|
m_buffer8 = { string.characters8(), string.length() };
|
|
|
|
else
|
|
|
|
m_buffer16 = { string.characters16(), string.length() };
|
2017-08-12 16:38:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool SVGPathStringSource::hasMoreData() const
|
|
|
|
{
|
|
|
|
if (m_is8BitSource)
|
2023-01-25 00:42:21 +00:00
|
|
|
return m_buffer8.hasCharactersRemaining();
|
|
|
|
return m_buffer16.hasCharactersRemaining();
|
2017-08-12 16:38:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool SVGPathStringSource::moveToNextToken()
|
|
|
|
{
|
|
|
|
if (m_is8BitSource)
|
2023-01-25 00:42:21 +00:00
|
|
|
return skipOptionalSVGSpaces(m_buffer8);
|
|
|
|
return skipOptionalSVGSpaces(m_buffer16);
|
2017-08-12 16:38:52 +00:00
|
|
|
}
|
|
|
|
|
2023-01-25 00:42:21 +00:00
|
|
|
template <typename CharacterType> static Optional<SVGPathSegType> nextCommandHelper(StringParsingBuffer<CharacterType>& buffer, SVGPathSegType previousCommand)
|
2017-08-12 16:38:52 +00:00
|
|
|
{
|
|
|
|
// Check for remaining coordinates in the current command.
|
2023-01-25 00:42:21 +00:00
|
|
|
if ((*buffer == '+' || *buffer == '-' || *buffer == '.' || isASCIIDigit(*buffer))
|
2017-08-12 16:38:52 +00:00
|
|
|
&& previousCommand != PathSegClosePath) {
|
2023-01-25 00:42:21 +00:00
|
|
|
if (previousCommand == PathSegMoveToAbs)
|
|
|
|
return PathSegLineToAbs;
|
|
|
|
if (previousCommand == PathSegMoveToRel)
|
|
|
|
return PathSegLineToRel;
|
|
|
|
return previousCommand;
|
2017-08-12 16:38:52 +00:00
|
|
|
}
|
|
|
|
|
2023-01-25 00:42:21 +00:00
|
|
|
return WTF::nullopt;
|
2017-08-12 16:38:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
SVGPathSegType SVGPathStringSource::nextCommand(SVGPathSegType previousCommand)
|
|
|
|
{
|
|
|
|
if (m_is8BitSource) {
|
2023-01-25 00:42:21 +00:00
|
|
|
if (auto nextCommand = nextCommandHelper(m_buffer8, previousCommand))
|
|
|
|
return *nextCommand;
|
2017-08-12 16:38:52 +00:00
|
|
|
} else {
|
2023-01-25 00:42:21 +00:00
|
|
|
if (auto nextCommand = nextCommandHelper(m_buffer16, previousCommand))
|
|
|
|
return *nextCommand;
|
2017-08-12 16:38:52 +00:00
|
|
|
}
|
|
|
|
|
2023-01-25 00:42:21 +00:00
|
|
|
return *parseSVGSegmentType();
|
2017-08-12 16:38:52 +00:00
|
|
|
}
|
|
|
|
|
2023-01-25 00:42:21 +00:00
|
|
|
template<typename F> decltype(auto) SVGPathStringSource::parse(F&& functor)
|
2017-08-12 16:38:52 +00:00
|
|
|
{
|
|
|
|
if (m_is8BitSource)
|
2023-01-25 00:42:21 +00:00
|
|
|
return functor(m_buffer8);
|
|
|
|
return functor(m_buffer16);
|
2017-08-12 16:38:52 +00:00
|
|
|
}
|
|
|
|
|
2023-01-25 00:42:21 +00:00
|
|
|
Optional<SVGPathSegType> SVGPathStringSource::parseSVGSegmentType()
|
2017-08-12 16:38:52 +00:00
|
|
|
{
|
2023-01-25 00:42:21 +00:00
|
|
|
return parse([](auto& buffer) -> SVGPathSegType {
|
|
|
|
auto character = *buffer;
|
|
|
|
buffer++;
|
|
|
|
switch (character) {
|
|
|
|
case 'Z':
|
|
|
|
case 'z':
|
|
|
|
return PathSegClosePath;
|
|
|
|
case 'M':
|
|
|
|
return PathSegMoveToAbs;
|
|
|
|
case 'm':
|
|
|
|
return PathSegMoveToRel;
|
|
|
|
case 'L':
|
|
|
|
return PathSegLineToAbs;
|
|
|
|
case 'l':
|
|
|
|
return PathSegLineToRel;
|
|
|
|
case 'C':
|
|
|
|
return PathSegCurveToCubicAbs;
|
|
|
|
case 'c':
|
|
|
|
return PathSegCurveToCubicRel;
|
|
|
|
case 'Q':
|
|
|
|
return PathSegCurveToQuadraticAbs;
|
|
|
|
case 'q':
|
|
|
|
return PathSegCurveToQuadraticRel;
|
|
|
|
case 'A':
|
|
|
|
return PathSegArcAbs;
|
|
|
|
case 'a':
|
|
|
|
return PathSegArcRel;
|
|
|
|
case 'H':
|
|
|
|
return PathSegLineToHorizontalAbs;
|
|
|
|
case 'h':
|
|
|
|
return PathSegLineToHorizontalRel;
|
|
|
|
case 'V':
|
|
|
|
return PathSegLineToVerticalAbs;
|
|
|
|
case 'v':
|
|
|
|
return PathSegLineToVerticalRel;
|
|
|
|
case 'S':
|
|
|
|
return PathSegCurveToCubicSmoothAbs;
|
|
|
|
case 's':
|
|
|
|
return PathSegCurveToCubicSmoothRel;
|
|
|
|
case 'T':
|
|
|
|
return PathSegCurveToQuadraticSmoothAbs;
|
|
|
|
case 't':
|
|
|
|
return PathSegCurveToQuadraticSmoothRel;
|
|
|
|
default:
|
|
|
|
return PathSegUnknown;
|
|
|
|
}
|
|
|
|
});
|
2017-08-12 16:38:52 +00:00
|
|
|
}
|
|
|
|
|
2023-01-25 00:42:21 +00:00
|
|
|
Optional<SVGPathSource::MoveToSegment> SVGPathStringSource::parseMoveToSegment()
|
2017-08-12 16:38:52 +00:00
|
|
|
{
|
2023-01-25 00:42:21 +00:00
|
|
|
return parse([](auto& buffer) -> Optional<MoveToSegment> {
|
|
|
|
auto targetPoint = parseFloatPoint(buffer);
|
|
|
|
if (!targetPoint)
|
|
|
|
return WTF::nullopt;
|
|
|
|
|
|
|
|
MoveToSegment segment;
|
|
|
|
segment.targetPoint = WTFMove(*targetPoint);
|
|
|
|
return segment;
|
|
|
|
});
|
2017-08-12 16:38:52 +00:00
|
|
|
}
|
|
|
|
|
2023-01-25 00:42:21 +00:00
|
|
|
Optional<SVGPathSource::LineToSegment> SVGPathStringSource::parseLineToSegment()
|
2017-08-12 16:38:52 +00:00
|
|
|
{
|
2023-01-25 00:42:21 +00:00
|
|
|
return parse([](auto& buffer) -> Optional<LineToSegment> {
|
|
|
|
auto targetPoint = parseFloatPoint(buffer);
|
|
|
|
if (!targetPoint)
|
|
|
|
return WTF::nullopt;
|
|
|
|
|
|
|
|
LineToSegment segment;
|
|
|
|
segment.targetPoint = WTFMove(*targetPoint);
|
|
|
|
return segment;
|
|
|
|
});
|
2017-08-12 16:38:52 +00:00
|
|
|
}
|
|
|
|
|
2023-01-25 00:42:21 +00:00
|
|
|
Optional<SVGPathSource::LineToHorizontalSegment> SVGPathStringSource::parseLineToHorizontalSegment()
|
2017-08-12 16:38:52 +00:00
|
|
|
{
|
2023-01-25 00:42:21 +00:00
|
|
|
return parse([](auto& buffer) -> Optional<LineToHorizontalSegment> {
|
|
|
|
auto x = parseNumber(buffer);
|
|
|
|
if (!x)
|
|
|
|
return WTF::nullopt;
|
|
|
|
|
|
|
|
LineToHorizontalSegment segment;
|
|
|
|
segment.x = *x;
|
|
|
|
return segment;
|
|
|
|
});
|
2017-08-12 16:38:52 +00:00
|
|
|
}
|
|
|
|
|
2023-01-25 00:42:21 +00:00
|
|
|
Optional<SVGPathSource::LineToVerticalSegment> SVGPathStringSource::parseLineToVerticalSegment()
|
2017-08-12 16:38:52 +00:00
|
|
|
{
|
2023-01-25 00:42:21 +00:00
|
|
|
return parse([](auto& buffer) -> Optional<LineToVerticalSegment> {
|
|
|
|
auto y = parseNumber(buffer);
|
|
|
|
if (!y)
|
|
|
|
return WTF::nullopt;
|
|
|
|
|
|
|
|
LineToVerticalSegment segment;
|
|
|
|
segment.y = *y;
|
|
|
|
return segment;
|
|
|
|
});
|
2017-08-12 16:38:52 +00:00
|
|
|
}
|
|
|
|
|
2023-01-25 00:42:21 +00:00
|
|
|
Optional<SVGPathSource::CurveToCubicSegment> SVGPathStringSource::parseCurveToCubicSegment()
|
2017-08-12 16:38:52 +00:00
|
|
|
{
|
2023-01-25 00:42:21 +00:00
|
|
|
return parse([](auto& buffer) -> Optional<CurveToCubicSegment> {
|
|
|
|
auto point1 = parseFloatPoint(buffer);
|
|
|
|
if (!point1)
|
|
|
|
return WTF::nullopt;
|
|
|
|
|
|
|
|
auto point2 = parseFloatPoint(buffer);
|
|
|
|
if (!point2)
|
|
|
|
return WTF::nullopt;
|
|
|
|
|
|
|
|
auto targetPoint = parseFloatPoint(buffer);
|
|
|
|
if (!targetPoint)
|
|
|
|
return WTF::nullopt;
|
|
|
|
|
|
|
|
CurveToCubicSegment segment;
|
|
|
|
segment.point1 = *point1;
|
|
|
|
segment.point2 = *point2;
|
|
|
|
segment.targetPoint = *targetPoint;
|
|
|
|
return segment;
|
|
|
|
});
|
2017-08-12 16:38:52 +00:00
|
|
|
}
|
|
|
|
|
2023-01-25 00:42:21 +00:00
|
|
|
Optional<SVGPathSource::CurveToCubicSmoothSegment> SVGPathStringSource::parseCurveToCubicSmoothSegment()
|
2017-08-12 16:38:52 +00:00
|
|
|
{
|
2023-01-25 00:42:21 +00:00
|
|
|
return parse([](auto& buffer) -> Optional<CurveToCubicSmoothSegment> {
|
|
|
|
auto point2 = parseFloatPoint(buffer);
|
|
|
|
if (!point2)
|
|
|
|
return WTF::nullopt;
|
|
|
|
|
|
|
|
auto targetPoint = parseFloatPoint(buffer);
|
|
|
|
if (!targetPoint)
|
|
|
|
return WTF::nullopt;
|
|
|
|
|
|
|
|
CurveToCubicSmoothSegment segment;
|
|
|
|
segment.point2 = *point2;
|
|
|
|
segment.targetPoint = *targetPoint;
|
|
|
|
return segment;
|
|
|
|
});
|
2017-08-12 16:38:52 +00:00
|
|
|
}
|
|
|
|
|
2023-01-25 00:42:21 +00:00
|
|
|
Optional<SVGPathSource::CurveToQuadraticSegment> SVGPathStringSource::parseCurveToQuadraticSegment()
|
2017-08-12 16:38:52 +00:00
|
|
|
{
|
2023-01-25 00:42:21 +00:00
|
|
|
return parse([](auto& buffer) -> Optional<CurveToQuadraticSegment> {
|
|
|
|
auto point1 = parseFloatPoint(buffer);
|
|
|
|
if (!point1)
|
|
|
|
return WTF::nullopt;
|
|
|
|
|
|
|
|
auto targetPoint = parseFloatPoint(buffer);
|
|
|
|
if (!targetPoint)
|
|
|
|
return WTF::nullopt;
|
|
|
|
|
|
|
|
CurveToQuadraticSegment segment;
|
|
|
|
segment.point1 = *point1;
|
|
|
|
segment.targetPoint = *targetPoint;
|
|
|
|
return segment;
|
|
|
|
});
|
2017-08-12 16:38:52 +00:00
|
|
|
}
|
|
|
|
|
2023-01-25 00:42:21 +00:00
|
|
|
Optional<SVGPathSource::CurveToQuadraticSmoothSegment> SVGPathStringSource::parseCurveToQuadraticSmoothSegment()
|
2017-08-12 16:38:52 +00:00
|
|
|
{
|
2023-01-25 00:42:21 +00:00
|
|
|
return parse([](auto& buffer) -> Optional<CurveToQuadraticSmoothSegment> {
|
|
|
|
auto targetPoint = parseFloatPoint(buffer);
|
|
|
|
if (!targetPoint)
|
|
|
|
return WTF::nullopt;
|
|
|
|
|
|
|
|
CurveToQuadraticSmoothSegment segment;
|
|
|
|
segment.targetPoint = *targetPoint;
|
|
|
|
return segment;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
Optional<SVGPathSource::ArcToSegment> SVGPathStringSource::parseArcToSegment()
|
|
|
|
{
|
|
|
|
return parse([](auto& buffer) -> Optional<ArcToSegment> {
|
|
|
|
auto rx = parseNumber(buffer);
|
|
|
|
if (!rx)
|
|
|
|
return WTF::nullopt;
|
|
|
|
auto ry = parseNumber(buffer);
|
|
|
|
if (!ry)
|
|
|
|
return WTF::nullopt;
|
|
|
|
auto angle = parseNumber(buffer);
|
|
|
|
if (!angle)
|
|
|
|
return WTF::nullopt;
|
|
|
|
auto largeArc = parseArcFlag(buffer);
|
|
|
|
if (!largeArc)
|
|
|
|
return WTF::nullopt;
|
|
|
|
auto sweep = parseArcFlag(buffer);
|
|
|
|
if (!sweep)
|
|
|
|
return WTF::nullopt;
|
|
|
|
auto targetPoint = parseFloatPoint(buffer);
|
|
|
|
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;
|
|
|
|
});
|
2017-08-12 16:38:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace WebKit
|