1414 *
1515 * Handles all SVG path commands (M, L, H, V, C, S, Q, T, A, Z) and converts
1616 * them to equivalent PDF drawing commands in the PDF coordinate system.
17- *
18- * @SuppressWarnings(PHPMD.ExcessiveClassComplexity)
1917 */
20- final class SvgPathCommandParser
18+ final readonly class SvgPathCommandParser
2119{
2220 public function __construct (
2321 private SvgArcConverter $ arcConverter = new SvgArcConverter (),
2422 private SvgTransformResolver $ transformResolver = new SvgTransformResolver (),
23+ private SvgPathNumberReader $ pathNumberReader = new SvgPathNumberReader (),
2524 ) {
2625 }
2726
@@ -165,7 +164,7 @@ private function handleMoveCommand(
165164 PathParsingState $ state ,
166165 PathCommandContext $ context ,
167166 ): void {
168- $ coordinates = $ this ->readPathNumbers ($ tokens , $ index , 2 , $ context ->source );
167+ $ coordinates = $ this ->pathNumberReader -> readPathNumbers ($ tokens , $ index , 2 , $ context ->source );
169168 $ state ->currentX = $ this ->resolveCoord ($ isRelative , $ state ->currentX , $ coordinates [0 ]);
170169 $ state ->currentY = $ this ->resolveCoord ($ isRelative , $ state ->currentY , $ coordinates [1 ]);
171170 [$ moveX , $ moveY ] = $ this ->transformResolver ->applyTransformToPoint (
@@ -178,7 +177,7 @@ private function handleMoveCommand(
178177 $ state ->lastCubicControlY = null ;
179178
180179 while ($ index < $ tokenCount && preg_match ('/^[A-Za-z]$/ ' , $ tokens [$ index ]) !== 1 ) {
181- $ coordinates = $ this ->readPathNumbers ($ tokens , $ index , 2 , $ context ->source );
180+ $ coordinates = $ this ->pathNumberReader -> readPathNumbers ($ tokens , $ index , 2 , $ context ->source );
182181 $ nextX = $ this ->resolveCoord ($ isRelative , $ state ->currentX , $ coordinates [0 ]);
183182 $ nextY = $ this ->resolveCoord ($ isRelative , $ state ->currentY , $ coordinates [1 ]);
184183 $ this ->appendLineToState ($ state , $ context , $ nextX , $ nextY );
@@ -199,9 +198,9 @@ private function handleLineCommand(
199198 PathCommandContext $ context ,
200199 ): void {
201200 while ($ index < $ tokenCount && preg_match ('/^[A-Za-z]$/ ' , $ tokens [$ index ]) !== 1 ) {
202- $ coordinates = $ this ->readPathNumbers ($ tokens , $ index , 2 , $ context ->source );
203- $ nextX = $ this ->resolveCoord ($ isRelative , $ state ->currentX , $ coordinates [0 ]);
204- $ nextY = $ this ->resolveCoord ($ isRelative , $ state ->currentY , $ coordinates [1 ]);
201+ $ coordinates = $ this ->pathNumberReader -> readPathNumbers ($ tokens , $ index , 2 , $ context ->source );
202+ $ nextX = $ this ->resolveCoord ($ isRelative , $ state ->currentX , $ coordinates [0 ]);
203+ $ nextY = $ this ->resolveCoord ($ isRelative , $ state ->currentY , $ coordinates [1 ]);
205204 $ this ->appendLineToState ($ state , $ context , $ nextX , $ nextY );
206205 }
207206 }
@@ -218,7 +217,7 @@ private function handleHorizontalCommand(
218217 PathCommandContext $ context ,
219218 ): void {
220219 while ($ index < $ tokenCount && preg_match ('/^[A-Za-z]$/ ' , $ tokens [$ index ]) !== 1 ) {
221- $ coordinates = $ this ->readPathNumbers ($ tokens , $ index , 1 , $ context ->source );
220+ $ coordinates = $ this ->pathNumberReader -> readPathNumbers ($ tokens , $ index , 1 , $ context ->source );
222221 $ state ->currentX = $ this ->resolveCoord ($ isRelative , $ state ->currentX , $ coordinates [0 ]);
223222 [$ lineX , $ lineY ] = $ this ->transformResolver ->applyTransformToPoint (
224223 $ context ->transformMatrix ,
@@ -243,7 +242,7 @@ private function handleVerticalCommand(
243242 PathCommandContext $ context ,
244243 ): void {
245244 while ($ index < $ tokenCount && preg_match ('/^[A-Za-z]$/ ' , $ tokens [$ index ]) !== 1 ) {
246- $ coordinates = $ this ->readPathNumbers ($ tokens , $ index , 1 , $ context ->source );
245+ $ coordinates = $ this ->pathNumberReader -> readPathNumbers ($ tokens , $ index , 1 , $ context ->source );
247246 $ state ->currentY = $ this ->resolveCoord ($ isRelative , $ state ->currentY , $ coordinates [0 ]);
248247 [$ lineX , $ lineY ] = $ this ->transformResolver ->applyTransformToPoint (
249248 $ context ->transformMatrix ,
@@ -268,13 +267,13 @@ private function handleCubicCommand(
268267 PathCommandContext $ context ,
269268 ): void {
270269 while ($ index < $ tokenCount && preg_match ('/^[A-Za-z]$/ ' , $ tokens [$ index ]) !== 1 ) {
271- $ coordinates = $ this ->readPathNumbers ($ tokens , $ index , 6 , $ context ->source );
272- $ startX1 = $ this ->resolveCoord ($ isRelative , $ state ->currentX , $ coordinates [0 ]);
273- $ startY1 = $ this ->resolveCoord ($ isRelative , $ state ->currentY , $ coordinates [1 ]);
274- $ endX2 = $ this ->resolveCoord ($ isRelative , $ state ->currentX , $ coordinates [2 ]);
275- $ endY2 = $ this ->resolveCoord ($ isRelative , $ state ->currentY , $ coordinates [3 ]);
276- $ x = $ this ->resolveCoord ($ isRelative , $ state ->currentX , $ coordinates [4 ]);
277- $ y = $ this ->resolveCoord ($ isRelative , $ state ->currentY , $ coordinates [5 ]);
270+ $ coordinates = $ this ->pathNumberReader -> readPathNumbers ($ tokens , $ index , 6 , $ context ->source );
271+ $ startX1 = $ this ->resolveCoord ($ isRelative , $ state ->currentX , $ coordinates [0 ]);
272+ $ startY1 = $ this ->resolveCoord ($ isRelative , $ state ->currentY , $ coordinates [1 ]);
273+ $ endX2 = $ this ->resolveCoord ($ isRelative , $ state ->currentX , $ coordinates [2 ]);
274+ $ endY2 = $ this ->resolveCoord ($ isRelative , $ state ->currentY , $ coordinates [3 ]);
275+ $ x = $ this ->resolveCoord ($ isRelative , $ state ->currentX , $ coordinates [4 ]);
276+ $ y = $ this ->resolveCoord ($ isRelative , $ state ->currentY , $ coordinates [5 ]);
278277
279278 $ state ->commands [] = $ this ->buildCubicCurveCommand (
280279 $ context ->transformMatrix ,
@@ -306,7 +305,7 @@ private function handleSmoothCubicCommand(
306305 PathCommandContext $ context ,
307306 ): void {
308307 while ($ index < $ tokenCount && preg_match ('/^[A-Za-z]$/ ' , $ tokens [$ index ]) !== 1 ) {
309- $ coordinates = $ this ->readPathNumbers ($ tokens , $ index , 4 , $ context ->source );
308+ $ coordinates = $ this ->pathNumberReader -> readPathNumbers ($ tokens , $ index , 4 , $ context ->source );
310309 $ startX1 = $ this ->reflectControlPoint ($ state ->lastCubicControlX , $ state ->currentX );
311310 $ startY1 = $ this ->reflectControlPoint ($ state ->lastCubicControlY , $ state ->currentY );
312311 $ endX2 = $ this ->resolveCoord ($ isRelative , $ state ->currentX , $ coordinates [0 ]);
@@ -344,7 +343,7 @@ private function handleQuadraticCommand(
344343 PathCommandContext $ context ,
345344 ): void {
346345 while ($ index < $ tokenCount && preg_match ('/^[A-Za-z]$/ ' , $ tokens [$ index ]) !== 1 ) {
347- $ coordinates = $ this ->readPathNumbers ($ tokens , $ index , 4 , $ context ->source );
346+ $ coordinates = $ this ->pathNumberReader -> readPathNumbers ($ tokens , $ index , 4 , $ context ->source );
348347 $ qcpX = $ this ->resolveCoord ($ isRelative , $ state ->currentX , $ coordinates [0 ]);
349348 $ qcpY = $ this ->resolveCoord ($ isRelative , $ state ->currentY , $ coordinates [1 ]);
350349 $ x = $ this ->resolveCoord ($ isRelative , $ state ->currentX , $ coordinates [2 ]);
@@ -377,7 +376,7 @@ private function handleSmoothQuadraticCommand(
377376 PathCommandContext $ context ,
378377 ): void {
379378 while ($ index < $ tokenCount && preg_match ('/^[A-Za-z]$/ ' , $ tokens [$ index ]) !== 1 ) {
380- $ coordinates = $ this ->readPathNumbers ($ tokens , $ index , 2 , $ context ->source );
379+ $ coordinates = $ this ->pathNumberReader -> readPathNumbers ($ tokens , $ index , 2 , $ context ->source );
381380 $ qcpX = $ this ->reflectControlPoint ($ state ->prevQuadCpX , $ state ->currentX );
382381 $ qcpY = $ this ->reflectControlPoint ($ state ->prevQuadCpY , $ state ->currentY );
383382 $ x = $ this ->resolveCoord ($ isRelative , $ state ->currentX , $ coordinates [0 ]);
@@ -409,7 +408,7 @@ private function handleArcCommand(
409408 PathCommandContext $ context ,
410409 ): void {
411410 while ($ index < $ tokenCount && preg_match ('/^[A-Za-z]$/ ' , $ tokens [$ index ]) !== 1 ) {
412- $ coordinates = $ this ->readPathNumbers ($ tokens , $ index , 7 , $ context ->source );
411+ $ coordinates = $ this ->pathNumberReader -> readPathNumbers ($ tokens , $ index , 7 , $ context ->source );
413412 $ radiusX = abs ($ coordinates [0 ]);
414413 $ radiusY = abs ($ coordinates [1 ]);
415414 $ rotation = $ coordinates [2 ];
@@ -548,29 +547,6 @@ private function quadraticToCubicControlPoints(
548547 return [$ controlX1 , $ controlY1 , $ controlX2 , $ controlY2 ];
549548 }
550549
551- /**
552- * @param list<string> $tokens
553- * @return list<float>
554- */
555- private function readPathNumbers (array $ tokens , int &$ index , int $ count , string $ source ): array
556- {
557- $ values = [];
558-
559- for ($ i = 0 ; $ i < $ count ; ++$ i ) {
560- if ($ index >= count ($ tokens ) || preg_match ('/^[A-Za-z]$/ ' , $ tokens [$ index ]) === 1 ) {
561- throw new InvalidArgumentException (sprintf (
562- 'Malformed SVG path data in "%s". ' ,
563- $ source ,
564- ));
565- }
566-
567- $ values [] = (float ) $ tokens [$ index ];
568- ++$ index ;
569- }
570-
571- return $ values ;
572- }
573-
574550 /**
575551 * @param array{0:float,1:float,2:float,3:float,4:float,5:float} $transformMatrix
576552 */
0 commit comments