📄 svgparserutilities.cpp
字号:
/* Copyright (C) 2002, 2003 The Karbon Developers 2006 Alexander Kellett <lypanov@kde.org> 2006, 2007 Rob Buis <buis@kde.org> Copyrigth (C) 2007, 2009 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"#if ENABLE(SVG)#include "SVGParserUtilities.h"#include "ExceptionCode.h"#include "FloatConversion.h"#include "FloatPoint.h"#include "Path.h"#include "PlatformString.h"#include "SVGPathSegList.h"#include "SVGPathSegArc.h"#include "SVGPathSegClosePath.h"#include "SVGPathSegCurvetoCubic.h"#include "SVGPathSegCurvetoCubicSmooth.h"#include "SVGPathSegCurvetoQuadratic.h"#include "SVGPathSegCurvetoQuadraticSmooth.h"#include "SVGPathSegLineto.h"#include "SVGPathSegLinetoHorizontal.h"#include "SVGPathSegLinetoVertical.h"#include "SVGPathSegList.h"#include "SVGPathSegMoveto.h"#include "SVGPointList.h"#include "SVGPathElement.h"#include <math.h>#include <wtf/MathExtras.h>namespace WebCore {/* 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 FloatType> static bool _parseNumber(const UChar*& ptr, const UChar* end, FloatType& number, bool skip){ int integer, exponent; FloatType decimal, frac; int sign, expsign; const UChar* start = ptr; exponent = 0; integer = 0; frac = 1; decimal = 0; sign = 1; expsign = 1; // read the sign if (ptr < end && *ptr == '+') ptr++; else if (ptr < end && *ptr == '-') { ptr++; sign = -1; } if (ptr == end || ((*ptr < '0' || *ptr > '9') && *ptr != '.')) // The first character of a number must be one of [0-9+-.] return false; // read the integer part while (ptr < end && *ptr >= '0' && *ptr <= '9') integer = (integer * 10) + *(ptr++) - '0'; if (ptr < end && *ptr == '.') { // read the decimals ptr++; // There must be a least one digit following the . if (ptr >= end || *ptr < '0' || *ptr > '9') return false; while (ptr < end && *ptr >= '0' && *ptr <= '9') decimal += (*(ptr++) - '0') * (frac *= static_cast<FloatType>(0.1)); } // read the exponent part if (ptr != start && ptr + 1 < end && (*ptr == 'e' || *ptr == 'E') && (ptr[1] != 'x' && ptr[1] != 'm')) { ptr++; // read the sign of the exponent if (*ptr == '+') ptr++; else if (*ptr == '-') { ptr++; expsign = -1; } // There must be an exponent if (ptr >= end || *ptr < '0' || *ptr > '9') return false; while (ptr < end && *ptr >= '0' && *ptr <= '9') { exponent *= 10; exponent += *ptr - '0'; ptr++; } } number = integer + decimal; number *= sign * static_cast<FloatType>(pow(10.0, expsign * exponent)); if (start == ptr) return false; if (skip) skipOptionalSpacesOrDelimiter(ptr, end); return true;}bool parseNumber(const UChar*& ptr, const UChar* end, float& number, bool skip) { return _parseNumber(ptr, end, number, skip);}// Only used for parsing Pathsstatic bool parseNumber(const UChar*& ptr, const UChar* end, double& number, bool skip = true) { return _parseNumber(ptr, end, number, skip);}bool parseNumberOptionalNumber(const String& s, float& x, float& y){ if (s.isEmpty()) return false; const UChar* cur = s.characters(); const UChar* end = cur + s.length(); if (!parseNumber(cur, end, x)) return false; if (cur == end) y = x; else if (!parseNumber(cur, end, y, false)) return false; return cur == end;}bool pointsListFromSVGData(SVGPointList* pointsList, const String& points){ if (points.isEmpty()) return true; const UChar* cur = points.characters(); const UChar* end = cur + points.length(); skipOptionalSpaces(cur, end); bool delimParsed = false; while (cur < end) { delimParsed = false; float xPos = 0.0f; if (!parseNumber(cur, end, xPos)) return false; float yPos = 0.0f; if (!parseNumber(cur, end, yPos, false)) return false; skipOptionalSpaces(cur, end); if (cur < end && *cur == ',') { delimParsed = true; cur++; } skipOptionalSpaces(cur, end); ExceptionCode ec = 0; pointsList->appendItem(FloatPoint(xPos, yPos), ec); } return cur == end && !delimParsed;} /** * Parser for svg path data, contained in the d attribute. * * The parser delivers encountered commands and parameters by calling * methods that correspond to those commands. Clients have to derive * from this class and implement the abstract command methods. * * There are two operating modes. By default the parser just delivers unaltered * svg path data commands and parameters. In the second mode, it will convert all * relative coordinates to absolute ones, and convert all curves to cubic beziers. */ class SVGPathParser { public: virtual ~SVGPathParser() { } bool parseSVG(const String& d, bool process = false); protected: virtual void svgMoveTo(double x1, double y1, bool closed, bool abs = true) = 0; virtual void svgLineTo(double x1, double y1, bool abs = true) = 0; virtual void svgLineToHorizontal(double, bool /*abs*/ = true) { } virtual void svgLineToVertical(double /*y*/, bool /*abs*/ = true) { } virtual void svgCurveToCubic(double x1, double y1, double x2, double y2, double x, double y, bool abs = true) = 0; virtual void svgCurveToCubicSmooth(double /*x*/, double /*y*/, double /*x2*/, double /*y2*/, bool /*abs*/ = true) { } virtual void svgCurveToQuadratic(double /*x*/, double /*y*/, double /*x1*/, double /*y1*/, bool /*abs*/ = true) { } virtual void svgCurveToQuadraticSmooth(double /*x*/, double /*y*/, bool /*abs*/ = true) { } virtual void svgArcTo(double /*x*/, double /*y*/, double /*r1*/, double /*r2*/, double /*angle*/, bool /*largeArcFlag*/, bool /*sweepFlag*/, bool /*abs*/ = true) { } virtual void svgClosePath() = 0; private: void calculateArc(bool relative, double& curx, double& cury, double angle, double x, double y, double r1, double r2, bool largeArcFlag, bool sweepFlag); }; bool SVGPathParser::parseSVG(const String& s, bool process){ const UChar* ptr = s.characters(); const UChar* end = ptr + s.length(); double contrlx, contrly, curx, cury, subpathx, subpathy, tox, toy, x1, y1, x2, y2, xc, yc; double px1, py1, px2, py2, px3, py3; bool closed = true; if (!skipOptionalSpaces(ptr, end)) // skip any leading spaces return false; char command = *(ptr++), lastCommand = ' '; if (command != 'm' && command != 'M') // path must start with moveto return false; subpathx = subpathy = curx = cury = contrlx = contrly = 0.0; while (1) { skipOptionalSpaces(ptr, end); // skip spaces between command and first coord bool relative = false; switch(command) { case 'm': relative = true; case 'M': { if (!parseNumber(ptr, end, tox) || !parseNumber(ptr, end, toy)) return false; if (process) { subpathx = curx = relative ? curx + tox : tox; subpathy = cury = relative ? cury + toy : toy; svgMoveTo(narrowPrecisionToFloat(curx), narrowPrecisionToFloat(cury), closed); } else svgMoveTo(narrowPrecisionToFloat(tox), narrowPrecisionToFloat(toy), closed, !relative); closed = false; break; } case 'l': relative = true; case 'L': { if (!parseNumber(ptr, end, tox) || !parseNumber(ptr, end, toy)) return false; if (process) { curx = relative ? curx + tox : tox; cury = relative ? cury + toy : toy; svgLineTo(narrowPrecisionToFloat(curx), narrowPrecisionToFloat(cury)); } else svgLineTo(narrowPrecisionToFloat(tox), narrowPrecisionToFloat(toy), !relative); break; } case 'h': { if (!parseNumber(ptr, end, tox)) return false;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -