LCOV - code coverage report
Current view: top level - pencil/source/draw - draw_svg_path_data.c (source / functions) Coverage Total Hit
Test: crystal-facet-uml_v1.63.2_covts Lines: 78.6 % 448 352
Test Date: 2025-05-01 10:10:14 Functions: 100.0 % 1 1

            Line data    Source code
       1              : /* File: draw_svg_path_data.c; Copyright and License: see below */
       2              : 
       3              : #include "draw_svg_path_data.h"
       4              : #include "layout/layout_visible_set.h"
       5              : #include "u8/u8_trace.h"
       6              : #include <stdio.h>
       7              : #include <stdlib.h>
       8              : #include <assert.h>
       9              : 
      10              : /*! \brief states of parsing drawing directives */
      11              : enum draw_svg_path_data_expect_enum {
      12              :     DRAW_SVG_PATH_DATA_EXPECT_COMMAND,  /*!< expecting initial drawing directive */
      13              :     DRAW_SVG_PATH_DATA_EXPECT_COMMAND_OR_COORD_SEQ,  /*!< expecting drawing directive or continuation of coordinate sequence */
      14              :     DRAW_SVG_PATH_DATA_EXPECT_COORD_CTRL1_X,  /*!< coordinate sequence, expecting cubic curve control_point1_X float */
      15              :     DRAW_SVG_PATH_DATA_EXPECT_COORD_CTRL1_Y,  /*!< coordinate sequence, expecting cubic curve control_point1_Y float */
      16              :     DRAW_SVG_PATH_DATA_EXPECT_COORD_CTRL2_X,  /*!< coordinate sequence, expecting cubic curve control_point2_X float */
      17              :     DRAW_SVG_PATH_DATA_EXPECT_COORD_CTRL2_Y,  /*!< coordinate sequence, expecting cubic curve control_point2_Y float */
      18              :     DRAW_SVG_PATH_DATA_EXPECT_COORD_QCTRL_X,  /*!< coordinate sequence, expecting quadratic curve control_point_X float */
      19              :     DRAW_SVG_PATH_DATA_EXPECT_COORD_QCTRL_Y,  /*!< coordinate sequence, expecting quadratic curve control_point_Y float */
      20              :     DRAW_SVG_PATH_DATA_EXPECT_ARC_RX,  /*!< arc parameter sequence, expecting arc rx float */
      21              :     DRAW_SVG_PATH_DATA_EXPECT_ARC_RY,  /*!< arc parameter sequence, expecting arc rx float */
      22              :     DRAW_SVG_PATH_DATA_EXPECT_ARC_PHI,  /*!< arc parameter sequence, expecting arc x axis rotation-angle float */
      23              :     DRAW_SVG_PATH_DATA_EXPECT_ARC_LARGE,  /*!< arc parameter sequence, expecting large arc flag */
      24              :     DRAW_SVG_PATH_DATA_EXPECT_ARC_SWEEP,  /*!< arc parameter sequence, expecting sweep arc flag */
      25              :     DRAW_SVG_PATH_DATA_EXPECT_COORD_END_X,  /*!< coordinate sequence, expecting end_x float */
      26              :     DRAW_SVG_PATH_DATA_EXPECT_COORD_END_Y,  /*!< coordinate sequence, expecting end_y float */
      27              :     DRAW_SVG_PATH_DATA_EXPECT_EXIT,  /*!< double quotes end the processing of path drawing commands */
      28              : };
      29              : 
      30           28 : u8_error_t draw_svg_path_data_private_parse ( const draw_svg_path_data_t *this_,
      31              :                                               bool draw,
      32              :                                               utf8stringviewtokenizer_t *tok_iterator,
      33              :                                               geometry_rectangle_t *io_view_rect,
      34              :                                               u8_error_info_t *out_err_info,
      35              :                                               const geometry_rectangle_t *target_bounds,
      36              :                                               cairo_t *cr )
      37              : {
      38           28 :     U8_TRACE_BEGIN();
      39           28 :     assert( NULL != tok_iterator );
      40           28 :     assert( UTF8STRINGVIEWTOKENMODE_FLOAT_ONLY == utf8stringviewtokenizer_get_mode( tok_iterator ) );
      41           28 :     assert( NULL != io_view_rect );
      42           28 :     assert( NULL != out_err_info );
      43           28 :     assert( NULL != target_bounds );
      44           28 :     assert( ( ! draw ) || ( NULL != cr ) );
      45           28 :     u8_error_t result = U8_ERROR_NONE;
      46              : 
      47              :     /* calculate scale and shift to convert view rect to target bounds */
      48           28 :     const double view_width = geometry_rectangle_get_width( io_view_rect ) < 0.0001 ? 1.0 : geometry_rectangle_get_width( io_view_rect );
      49           28 :     const double scale_x = geometry_rectangle_get_width( target_bounds ) / view_width;
      50           28 :     const double shift_x = geometry_rectangle_get_left( target_bounds ) - ( scale_x * geometry_rectangle_get_left( io_view_rect ) );
      51           28 :     const double view_height = geometry_rectangle_get_height( io_view_rect ) < 0.0001 ? 1.0 : geometry_rectangle_get_height( io_view_rect );
      52           28 :     const double scale_y = geometry_rectangle_get_height( target_bounds ) / view_height;
      53           28 :     const double shift_y = geometry_rectangle_get_top( target_bounds ) - ( scale_y * geometry_rectangle_get_top( io_view_rect ) );
      54              : 
      55              :     /* states while parsing: */
      56           28 :     enum draw_svg_path_data_expect_enum parser_state = DRAW_SVG_PATH_DATA_EXPECT_COMMAND;
      57           28 :     char last_command = ' ';
      58           28 :     double command_end_x = 0.0;  /* abscissa, absolute values */
      59           28 :     double command_end_y = 0.0;  /* ordinate, absolute values */
      60           28 :     double coord_ctrl1_x = 0.0;  /* abscissa, absolute values */
      61           28 :     double coord_ctrl1_y = 0.0;  /* ordinate, absolute values */
      62           28 :     double coord_ctrl2_x = 0.0;  /* abscissa, absolute values */
      63           28 :     double coord_ctrl2_y = 0.0;  /* ordinate, absolute values */
      64           28 :     double subpath_start_x = 0.0;  /* abscissa, absolute values */
      65           28 :     double subpath_start_y = 0.0;  /* ordinate, absolute values */
      66           28 :     double command_start_x = 0.0;  /* abscissa, absolute values */
      67           28 :     double command_start_y = 0.0;  /* ordinate, absolute values */
      68           28 :     double arc_r_x = 0.0;  /* major ellipsis radius */
      69           28 :     double arc_r_y = 0.0;  /* minor ellipsis radius */
      70           28 :     double arc_phi = 0.0;  /* angle between major ellipsis radius and x-axis (unit: rad) */
      71           28 :     bool arc_large_arc = false;  /* true if the arc is spanning more than 180 degree / 1*pi */
      72           28 :     bool arc_sweep_positive = false;  /* true if the arc is traversed in positive-angle direction */
      73           28 :     bool view_rect_drop_0_0 = true;  /* if io_view_rect only contains the initial point (0,0), true states that */
      74              :                                      /* this (0,0) point shall be ignored when updating the io_view_rect. */
      75              : 
      76              :     /* init draw */
      77           28 :     if ( draw )
      78              :     {
      79            0 :         assert( NULL != cr );
      80            0 :         cairo_move_to ( cr, command_end_x * scale_x + shift_x, command_end_y * scale_y + shift_y );
      81              :     }
      82              : 
      83          367 :     while( utf8stringviewtokenizer_has_next( tok_iterator )
      84          367 :            && ( parser_state != DRAW_SVG_PATH_DATA_EXPECT_EXIT )
      85          711 :            && ( result == U8_ERROR_NONE ) )
      86              :     {
      87          339 :         const utf8stringview_t tok = utf8stringviewtokenizer_next( tok_iterator );
      88          339 :         assert( utf8stringview_get_length( &tok ) > 0 );  /* otherwise this would not be a token */
      89          339 :         U8_TRACE_INFO_VIEW( "token:", tok );
      90              : 
      91          339 :         switch ( parser_state )
      92              :         {
      93           37 :             case DRAW_SVG_PATH_DATA_EXPECT_COMMAND:
      94              :             {
      95           37 :                 const char current = *utf8stringview_get_start( &tok );
      96           37 :                 if (( utf8stringview_equals_str( &tok, "\"" ) )||( utf8stringview_equals_str( &tok, "\'" ) ))
      97              :                 {
      98              :                     /* no subpath here to draw */
      99              :                     /* end of d attribute, back to caller */
     100            4 :                     parser_state = DRAW_SVG_PATH_DATA_EXPECT_EXIT;
     101              :                 }
     102           33 :                 else if (( current=='z' )||( current=='Z' ))
     103              :                 {
     104              :                     /* no line_to here because there is no subpath to end */
     105            4 :                     if ( draw )
     106              :                     {
     107            0 :                         assert( NULL != cr );
     108            0 :                         cairo_move_to ( cr, subpath_start_x, subpath_start_y );
     109              :                     }
     110              :                     /* end of subpath */
     111            4 :                     parser_state = DRAW_SVG_PATH_DATA_EXPECT_COMMAND;
     112            4 :                     last_command = current;
     113              :                 }
     114           29 :                 else if (( current=='m' )||( current=='M' )||( current=='l' )||( current=='L' ))
     115              :                 {
     116            8 :                     parser_state = DRAW_SVG_PATH_DATA_EXPECT_COORD_END_X;
     117            8 :                     last_command = current;
     118              :                 }
     119           21 :                 else if (( current=='h' )||( current=='H' ))
     120              :                 {
     121            2 :                     parser_state = DRAW_SVG_PATH_DATA_EXPECT_COORD_END_X;
     122            2 :                     last_command = current;
     123              :                 }
     124           19 :                 else if (( current=='v' )||( current=='V' ))
     125              :                 {
     126            2 :                     command_end_x = command_start_x;
     127            2 :                     parser_state = DRAW_SVG_PATH_DATA_EXPECT_COORD_END_Y;
     128            2 :                     last_command = current;
     129              :                 }
     130           17 :                 else if (( current=='c' )||( current=='C' ))
     131              :                 {
     132            2 :                     parser_state = DRAW_SVG_PATH_DATA_EXPECT_COORD_CTRL1_X;
     133            2 :                     last_command = current;
     134              :                 }
     135           15 :                 else if (( current=='s' )||( current=='S' ))
     136              :                 {
     137              :                     /* there was no preceding c/C/s/S command, initialize first control point to command start point: */
     138            2 :                     coord_ctrl1_x = command_start_x;
     139            2 :                     coord_ctrl1_y = command_start_y;
     140            2 :                     parser_state = DRAW_SVG_PATH_DATA_EXPECT_COORD_CTRL2_X;
     141            2 :                     last_command = current;
     142              :                 }
     143           13 :                 else if (( current=='q' )||( current=='Q' ))
     144              :                 {
     145            2 :                     parser_state = DRAW_SVG_PATH_DATA_EXPECT_COORD_QCTRL_X;
     146            2 :                     last_command = current;
     147              :                 }
     148           11 :                 else if (( current=='t' )||( current=='T' ))
     149              :                 {
     150              :                     /* there was no preceding q/Q/t/T command, initialize next control point to command start point: */
     151            2 :                     coord_ctrl1_x = command_start_x;
     152            2 :                     coord_ctrl1_y = command_start_y;
     153            2 :                     parser_state = DRAW_SVG_PATH_DATA_EXPECT_COORD_END_X;
     154            2 :                     last_command = current;
     155              :                 }
     156            9 :                 else if (( current=='a' )||( current=='A' ))
     157              :                 {
     158            7 :                     parser_state = DRAW_SVG_PATH_DATA_EXPECT_ARC_RX;
     159            7 :                     last_command = current;
     160              :                 }
     161              :                 else
     162              :                 {
     163              :                     /* unexpected token */
     164            2 :                     u8_error_info_init_line( out_err_info,
     165              :                                              U8_ERROR_PARSER_STRUCTURE,
     166            2 :                                              utf8stringviewtokenizer_get_line( tok_iterator )
     167              :                                            );
     168            2 :                     result |= U8_ERROR_PARSER_STRUCTURE;
     169              :                 }
     170              :             }
     171           37 :             break;
     172              : 
     173           59 :             case DRAW_SVG_PATH_DATA_EXPECT_COMMAND_OR_COORD_SEQ:
     174              :             {
     175           59 :                 const char current = *utf8stringview_get_start( &tok );
     176           59 :                 if (( utf8stringview_equals_str( &tok, "\"" ) )||( utf8stringview_equals_str( &tok, "\'" ) ))
     177              :                 {
     178              :                     /* end of d attribute, back to caller */
     179           19 :                     parser_state = DRAW_SVG_PATH_DATA_EXPECT_EXIT;
     180              :                 }
     181           40 :                 else if ( current=='z' || current=='Z' )
     182              :                 {
     183              :                     /* close subpath */
     184            5 :                     if ( draw )
     185              :                     {
     186            0 :                         assert( NULL != cr );
     187            0 :                         cairo_line_to ( cr, subpath_start_x * scale_x + shift_x, subpath_start_y * scale_y + shift_y );
     188              :                     }
     189            5 :                     command_start_x = subpath_start_x;
     190            5 :                     command_start_y = subpath_start_y;
     191              :                     /* end of subpath */
     192            5 :                     parser_state = DRAW_SVG_PATH_DATA_EXPECT_COMMAND;
     193            5 :                     last_command = current;
     194              :                 }
     195           35 :                 else if (( current=='m' )||( current=='M' )||( current=='l' )||( current=='L' ))
     196              :                 {
     197            4 :                     parser_state = DRAW_SVG_PATH_DATA_EXPECT_COORD_END_X;
     198            4 :                     last_command = current;
     199              :                 }
     200           31 :                 else if (( current=='h' )||( current=='H' ))
     201              :                 {
     202            4 :                     parser_state = DRAW_SVG_PATH_DATA_EXPECT_COORD_END_X;
     203            4 :                     last_command = current;
     204              :                 }
     205           27 :                 else if (( current=='v' )||( current=='V' ))
     206              :                 {
     207            4 :                     command_end_x = command_start_x;
     208            4 :                     parser_state = DRAW_SVG_PATH_DATA_EXPECT_COORD_END_Y;
     209            4 :                     last_command = current;
     210              :                 }
     211           23 :                 else if (( current=='c' )||( current=='C' ))
     212              :                 {
     213            2 :                     parser_state = DRAW_SVG_PATH_DATA_EXPECT_COORD_CTRL1_X;
     214            2 :                     last_command = current;
     215              :                 }
     216           21 :                 else if (( current=='s' )||( current=='S' ))
     217              :                 {
     218            2 :                     if (( last_command == 'c' )||( last_command == 'C' )||( last_command == 's' )||( last_command == 'S' ))
     219              :                     {
     220              :                         /* init the first control point as mirror of the last control point: */
     221            2 :                         coord_ctrl1_x = command_start_x + (command_start_x-coord_ctrl2_x);
     222            2 :                         coord_ctrl1_y = command_start_y + (command_start_y-coord_ctrl2_y);
     223              :                     }
     224              :                     else
     225              :                     {
     226            0 :                         coord_ctrl1_x = command_start_x;
     227            0 :                         coord_ctrl1_y = command_start_y;
     228              :                     }
     229            2 :                     parser_state = DRAW_SVG_PATH_DATA_EXPECT_COORD_CTRL2_X;
     230            2 :                     last_command = current;
     231              :                 }
     232           19 :                 else if (( current=='q' )||( current=='Q' ))
     233              :                 {
     234            2 :                     parser_state = DRAW_SVG_PATH_DATA_EXPECT_COORD_QCTRL_X;
     235            2 :                     last_command = current;
     236              :                 }
     237           17 :                 else if (( current=='t' )||( current=='T' ))
     238              :                 {
     239            3 :                     if (( last_command == 'q' )||( last_command == 'Q' )||( last_command == 't' )||( last_command == 'T' ))
     240              :                     {
     241              :                         /* init the next control point as mirror of the last control point: */
     242            2 :                         coord_ctrl1_x = command_start_x + (command_start_x-coord_ctrl1_x);
     243            2 :                         coord_ctrl1_y = command_start_y + (command_start_y-coord_ctrl1_y);
     244              :                     }
     245              :                     else
     246              :                     {
     247            1 :                         coord_ctrl1_x = command_start_x;
     248            1 :                         coord_ctrl1_y = command_start_y;
     249              :                     }
     250            3 :                     parser_state = DRAW_SVG_PATH_DATA_EXPECT_COORD_END_X;
     251            3 :                     last_command = current;
     252              :                 }
     253           14 :                 else if (( current=='a' )||( current=='A' ))
     254              :                 {
     255            0 :                     parser_state = DRAW_SVG_PATH_DATA_EXPECT_ARC_RX;
     256            0 :                     last_command = current;
     257              :                 }
     258           14 :                 else if ( current==',' )
     259              :                 {
     260              :                     /* skip */
     261              :                 }
     262              :                 else
     263              :                 {
     264              :                     /* read coordinate */
     265           14 :                     double value = 0.0;
     266              :                     unsigned int byte_length;
     267              :                     const u8_error_t float_err
     268           14 :                         = utf8string_parse_float( utf8stringview_get_start( &tok ), &byte_length, &value );
     269           14 :                     if ( float_err != U8_ERROR_NONE )
     270              :                     {
     271              :                         /* float_err could be a UTF8ERROR_NOT_FOUND or a UTF8ERROR_OUT_OF_RANGE */
     272            0 :                         u8_error_info_init_line( out_err_info,
     273              :                                                  U8_ERROR_PARSER_STRUCTURE,
     274            0 :                                                  utf8stringviewtokenizer_get_line( tok_iterator )
     275              :                                                );
     276            0 :                         result |= U8_ERROR_PARSER_STRUCTURE;
     277              :                     }
     278              :                     else
     279              :                     {
     280              :                         /* U8_TRACE_INFO_INT( "line", utf8stringviewtokenizer_get_line( tok_iterator ) ); */
     281           14 :                         assert( byte_length == utf8stringview_get_length( &tok ) );
     282              :                     }
     283           14 :                     const bool is_absolute = ( last_command <= 'Z' );
     284           14 :                     const double value_x_abs = is_absolute ? value : ( command_start_x + value );
     285              :                     /* do command */
     286           14 :                     if (( last_command=='v' )||( last_command=='V' ))
     287              :                     {
     288            1 :                         command_end_x = command_start_x;
     289            1 :                         command_end_y = is_absolute ? value : ( command_start_y + value );
     290              :                         /* draw */
     291            1 :                         if ( draw )
     292              :                         {
     293            0 :                             assert( NULL != cr );
     294            0 :                             cairo_line_to ( cr, command_end_x * scale_x + shift_x, command_end_y * scale_y + shift_y );
     295              :                         }
     296              :                         /* update state */
     297            1 :                         geometry_rectangle_embrace( io_view_rect, command_end_x, command_end_y );
     298            1 :                         command_start_y = command_end_y;
     299              :                         /* continue with next */
     300            1 :                         parser_state = DRAW_SVG_PATH_DATA_EXPECT_COMMAND_OR_COORD_SEQ;
     301              :                     }
     302           13 :                     else if (( last_command=='h' )||( last_command=='H' ))
     303              :                     {
     304            1 :                         command_end_x = value_x_abs;
     305            1 :                         command_end_y = command_start_y;
     306              :                         /* draw */
     307            1 :                         if ( draw )
     308              :                         {
     309            0 :                             assert( NULL != cr );
     310            0 :                             cairo_line_to ( cr, command_end_x * scale_x + shift_x, command_end_y * scale_y + shift_y );
     311              :                         }
     312              :                         /* update state */
     313            1 :                         geometry_rectangle_embrace( io_view_rect, command_end_x, command_end_y );
     314            1 :                         command_start_x = command_end_x;
     315              :                         /* continue with next */
     316            1 :                         parser_state = DRAW_SVG_PATH_DATA_EXPECT_COMMAND_OR_COORD_SEQ;
     317              :                     }
     318           12 :                     else if (( last_command=='c' )||( last_command=='C' ))
     319              :                     {
     320            1 :                         coord_ctrl1_x = value_x_abs;
     321              :                         /* reading last_command parameters */
     322            1 :                         parser_state = DRAW_SVG_PATH_DATA_EXPECT_COORD_CTRL1_Y;
     323              :                     }
     324           11 :                     else if (( last_command=='s' )||( last_command=='S' ))
     325              :                     {
     326              :                         /* init the first control point as mirror of the last control point: */
     327              :                         {
     328            1 :                             coord_ctrl1_x = command_start_x + (command_start_x-coord_ctrl2_x);
     329            1 :                             coord_ctrl1_y = command_start_y + (command_start_y-coord_ctrl2_y);
     330              :                         }
     331            1 :                         coord_ctrl2_x = value_x_abs;
     332            1 :                         parser_state = DRAW_SVG_PATH_DATA_EXPECT_COORD_CTRL2_Y;
     333              :                     }
     334           10 :                     else if (( last_command=='q' )||( last_command=='Q' ))
     335              :                     {
     336            1 :                         coord_ctrl1_x = value_x_abs;
     337            1 :                         parser_state = DRAW_SVG_PATH_DATA_EXPECT_COORD_QCTRL_Y;
     338              :                     }
     339            9 :                     else if (( last_command=='t' )||( last_command=='T' ))
     340              :                     {
     341              :                         /* init the next control point as mirror of the last control point: */
     342              :                         {
     343            1 :                             coord_ctrl1_x = command_start_x + (command_start_x-coord_ctrl1_x);
     344            1 :                             coord_ctrl1_y = command_start_y + (command_start_y-coord_ctrl1_y);
     345              :                         }
     346            1 :                         command_end_x = value_x_abs;
     347            1 :                         parser_state = DRAW_SVG_PATH_DATA_EXPECT_COORD_END_Y;
     348              :                     }
     349            8 :                     else if (( last_command=='a' )||( last_command=='A' ))
     350              :                     {
     351              :                         /* store major radius value to appropriate variable */
     352            1 :                         arc_r_x = value;
     353              :                         /* continue reading last_command parameters */
     354            1 :                         parser_state = DRAW_SVG_PATH_DATA_EXPECT_ARC_RY;
     355              :                     }
     356              :                     else
     357              :                     {
     358            7 :                         command_end_x = value_x_abs;
     359              :                         /* continue reading last_command parameters */
     360            7 :                         parser_state = DRAW_SVG_PATH_DATA_EXPECT_COORD_END_Y;
     361              :                     }
     362              :                 }
     363              :             }
     364           59 :             break;
     365              : 
     366           46 :             case DRAW_SVG_PATH_DATA_EXPECT_COORD_END_X:
     367              :             {
     368           46 :                 if ( utf8stringview_equals_str( &tok, "," ) )
     369              :                 {
     370              :                     /* skip */
     371              :                 }
     372              :                 else
     373              :                 {
     374              :                     /* read coordinate */
     375              :                     /* utf8string_parse_float is faster than utf8stringview_parse_float; only it may not stop at view end but at terminating 0 after svg-path */
     376           46 :                     double value = 0.0;
     377              :                     unsigned int byte_length;
     378              :                     const u8_error_t float_err
     379           46 :                         = utf8string_parse_float( utf8stringview_get_start( &tok ), &byte_length, &value );
     380           46 :                     if ( float_err != U8_ERROR_NONE )
     381              :                     {
     382              :                         /* float_err could be a UTF8ERROR_NOT_FOUND or a UTF8ERROR_OUT_OF_RANGE */
     383            2 :                         u8_error_info_init_line( out_err_info,
     384              :                                                  U8_ERROR_PARSER_STRUCTURE,
     385            2 :                                                  utf8stringviewtokenizer_get_line( tok_iterator )
     386              :                                                );
     387            2 :                         result |= U8_ERROR_PARSER_STRUCTURE;
     388              :                     }
     389              :                     else
     390              :                     {
     391           44 :                         assert( byte_length == utf8stringview_get_length( &tok ) );
     392              :                     }
     393           46 :                     const bool is_absolute = ( last_command <= 'Z' );
     394           46 :                     command_end_x = is_absolute ? value : ( command_start_x + value );
     395              :                     /* do command */
     396           46 :                     if (( last_command=='h' )||( last_command=='H' ))
     397              :                     {
     398            6 :                         command_end_y = command_start_y;
     399              :                         /* draw */
     400            6 :                         if ( draw )
     401              :                         {
     402            0 :                             assert( NULL != cr );
     403            0 :                             cairo_line_to ( cr, command_end_x * scale_x + shift_x, command_end_y * scale_y + shift_y );
     404              :                         }
     405              :                         /* update state */
     406            6 :                         geometry_rectangle_embrace( io_view_rect, command_end_x, command_end_y );
     407            6 :                         command_start_x = command_end_x;
     408              :                         /* continue with next */
     409            6 :                         parser_state = DRAW_SVG_PATH_DATA_EXPECT_COMMAND_OR_COORD_SEQ;
     410              :                     }
     411              :                     else
     412              :                     {
     413              :                         /* continue reading more parameters for last_command */
     414           40 :                         parser_state = DRAW_SVG_PATH_DATA_EXPECT_COORD_END_Y;
     415              :                     }
     416              :                 }
     417              :             }
     418           46 :             break;
     419              : 
     420           93 :             case DRAW_SVG_PATH_DATA_EXPECT_COORD_END_Y:
     421              :             {
     422           93 :                 if ( utf8stringview_equals_str( &tok, "," ) )
     423              :                 {
     424              :                     /* skip */
     425              :                 }
     426              :                 else
     427              :                 {
     428              :                     /* read coordinate */
     429              :                     /* utf8string_parse_float is faster than utf8stringview_parse_float; only it may not stop at view end but at terminating 0 after svg-path */
     430           52 :                     double value = 0.0;
     431              :                     unsigned int byte_length;
     432              :                     const u8_error_t float_err
     433           52 :                         = utf8string_parse_float( utf8stringview_get_start( &tok ), &byte_length, &value );
     434           52 :                     if ( float_err != U8_ERROR_NONE )
     435              :                     {
     436              :                         /* float_err could be a UTF8ERROR_NOT_FOUND or a UTF8ERROR_OUT_OF_RANGE */
     437            1 :                         u8_error_info_init_line( out_err_info,
     438              :                                                  U8_ERROR_PARSER_STRUCTURE,
     439            1 :                                                  utf8stringviewtokenizer_get_line( tok_iterator )
     440              :                                                );
     441            1 :                         result |= U8_ERROR_PARSER_STRUCTURE;
     442              :                     }
     443              :                     else
     444              :                     {
     445           51 :                         assert( byte_length == utf8stringview_get_length( &tok ) );
     446              :                     }
     447           52 :                     const bool is_absolute = ( last_command <= 'Z' );
     448           52 :                     command_end_y = is_absolute ? value : ( command_start_y + value );
     449              :                     /* do command */
     450           52 :                     if (( last_command=='m' )||( last_command=='M' ))
     451              :                     {
     452              :                         /* draw */
     453            4 :                         if ( draw )
     454              :                         {
     455            0 :                             assert( NULL != cr );
     456            0 :                             cairo_move_to ( cr, command_end_x * scale_x + shift_x, command_end_y * scale_y + shift_y );
     457              :                         }
     458              :                         /* update state */
     459            4 :                         subpath_start_x = command_end_x;
     460            4 :                         subpath_start_y = command_end_y;
     461            4 :                         command_start_x = command_end_x;
     462            4 :                         command_start_y = command_end_y;
     463            4 :                         last_command = is_absolute ? 'L' : 'l';  /* following coordinates are implicitely line-to commands */
     464              :                         /* init or update the io_view_rect parameter */
     465            8 :                         if ( geometry_rectangle_is_point( io_view_rect ) && view_rect_drop_0_0 )
     466              :                         {
     467              :                             /* when we have the first coordinate, the io_view_rect is not a point anymore... */
     468            3 :                             geometry_rectangle_init( io_view_rect, subpath_start_x, subpath_start_y, 0.0, 0.0 );
     469            3 :                             view_rect_drop_0_0 = false;
     470              :                         }
     471              :                         else
     472              :                         {
     473            1 :                             geometry_rectangle_embrace( io_view_rect, subpath_start_x, subpath_start_y );
     474              :                         }
     475              :                     }
     476           48 :                     else if (( last_command=='l' )||( last_command=='L' )||( last_command=='v' )||( last_command=='V' ))
     477              :                     {
     478              :                         /* draw */
     479           20 :                         if ( draw )
     480              :                         {
     481            0 :                             assert( NULL != cr );
     482            0 :                             cairo_line_to ( cr, command_end_x * scale_x + shift_x, command_end_y * scale_y + shift_y );
     483              :                         }
     484              :                         /* update state */
     485           20 :                         geometry_rectangle_embrace( io_view_rect, command_end_x, command_end_y );
     486           20 :                         command_start_x = command_end_x;
     487           20 :                         command_start_y = command_end_y;
     488              :                     }
     489           28 :                     else if (( last_command=='c' )||( last_command=='C' )||( last_command=='s' )||( last_command=='S' ))
     490              :                     {
     491              :                         /* draw */
     492           10 :                         if ( draw )
     493              :                         {
     494            0 :                             assert( NULL != cr );
     495            0 :                             cairo_curve_to( cr,
     496            0 :                                             coord_ctrl1_x * scale_x + shift_x,
     497            0 :                                             coord_ctrl1_y * scale_y + shift_y,
     498            0 :                                             coord_ctrl2_x * scale_x + shift_x,
     499            0 :                                             coord_ctrl2_y * scale_y + shift_y,
     500            0 :                                             command_end_x * scale_x + shift_x,
     501            0 :                                             command_end_y * scale_y + shift_y
     502              :                                           );
     503              :                         }
     504              :                         /* update state */
     505           10 :                         geometry_rectangle_embrace( io_view_rect, coord_ctrl1_x, coord_ctrl1_y );
     506           10 :                         geometry_rectangle_embrace( io_view_rect, coord_ctrl2_x, coord_ctrl2_y  );
     507           10 :                         geometry_rectangle_embrace( io_view_rect, command_end_x, command_end_y );
     508           10 :                         command_start_x = command_end_x;
     509           10 :                         command_start_y = command_end_y;
     510              :                     }
     511           18 :                     else if (( last_command=='q' )||( last_command=='Q' )||( last_command=='t' )||( last_command=='T' ))
     512              :                     {
     513              :                         /* draw */
     514           10 :                         if ( draw )
     515              :                         {
     516            0 :                             assert( NULL != cr );
     517            0 :                             cairo_curve_to( cr,
     518            0 :                                             coord_ctrl1_x * scale_x + shift_x,
     519            0 :                                             coord_ctrl1_y * scale_y + shift_y,
     520            0 :                                             coord_ctrl1_x * scale_x + shift_x, /* same control point */
     521            0 :                                             coord_ctrl1_y * scale_y + shift_y, /* same control point */
     522            0 :                                             command_end_x * scale_x + shift_x,
     523            0 :                                             command_end_y * scale_y + shift_y
     524              :                                           );
     525              :                         }
     526              :                         /* update state */
     527           10 :                         geometry_rectangle_embrace( io_view_rect, coord_ctrl1_x, coord_ctrl1_y );
     528           10 :                         geometry_rectangle_embrace( io_view_rect, command_end_x, command_end_y );
     529           10 :                         command_start_x = command_end_x;
     530           10 :                         command_start_y = command_end_y;
     531              :                     }
     532            8 :                     else if (( last_command=='a' )||( last_command=='A' ))
     533            8 :                     {
     534            8 :                         double center_x = 0.0;
     535            8 :                         double center_y = 0.0;
     536            8 :                         double start_angle = 0.0;
     537            8 :                         double delta_angle= 0.0;
     538              :                         const u8_error_t arc_err
     539            8 :                             = draw_svg_path_data_private_get_arc_center( this_,
     540              :                                                                          command_start_x,
     541              :                                                                          command_start_y,
     542              :                                                                          command_end_x,
     543              :                                                                          command_end_y,
     544              :                                                                          arc_large_arc,
     545              :                                                                          arc_sweep_positive,
     546              :                                                                          arc_r_x,
     547              :                                                                          arc_r_y,
     548              :                                                                          arc_phi,
     549              :                                                                          &center_x,
     550              :                                                                          &center_y,
     551              :                                                                          &start_angle,
     552              :                                                                          &delta_angle
     553              :                                                                        );
     554              : 
     555              :                         /* draw */
     556            8 :                         if ( draw )
     557              :                         {
     558            0 :                             assert( NULL != cr );
     559            0 :                             if ( arc_err == U8_ERROR_NONE )
     560              :                             {
     561            0 :                                 const double ellipsis_ratio = ( arc_r_x > 0.001 ) ? ( arc_r_y / arc_r_x ) : 1000.0;
     562              :                                 cairo_matrix_t orig_matrix;
     563            0 :                                 cairo_get_matrix( cr, &orig_matrix );
     564              :                                 /* scale and shift viewport to icon size */
     565            0 :                                 cairo_translate( cr, shift_x, shift_y );
     566            0 :                                 cairo_scale( cr, scale_x, scale_y );
     567              :                                 /* setup SVG transformations */
     568            0 :                                 cairo_translate( cr, center_x, center_y );
     569            0 :                                 cairo_rotate( cr, arc_phi );
     570            0 :                                 cairo_scale( cr, 1.0, ellipsis_ratio );
     571            0 :                                 if ( delta_angle < 0.0 )
     572              :                                 {
     573            0 :                                     cairo_arc_negative( cr,
     574              :                                                         0.0,
     575              :                                                         0.0,
     576              :                                                         arc_r_x,
     577              :                                                         start_angle,
     578              :                                                         start_angle + delta_angle
     579              :                                                       );
     580              :                                 }
     581              :                                 else
     582              :                                 {
     583            0 :                                     cairo_arc( cr,
     584              :                                                0.0,
     585              :                                                0.0,
     586              :                                                arc_r_x,
     587              :                                                start_angle,
     588              :                                                start_angle + delta_angle
     589              :                                              );
     590              :                                 }
     591            0 :                                 cairo_set_matrix( cr, &orig_matrix );
     592              :                             }
     593            0 :                             else if ( arc_err == U8_ERROR_EDGE_CASE_PARAM )
     594              :                             {
     595            0 :                                 cairo_line_to ( cr, command_end_x * scale_x + shift_x, command_end_y * scale_y + shift_y );
     596              :                             }
     597              :                             else
     598              :                             {
     599            0 :                                 cairo_move_to ( cr, command_end_x * scale_x + shift_x, command_end_y * scale_y + shift_y );
     600              :                             }
     601              :                         }
     602              :                         /* update state */
     603            8 :                         geometry_rectangle_embrace( io_view_rect, center_x, center_y - arc_r_y );
     604            8 :                         geometry_rectangle_embrace( io_view_rect, center_x - arc_r_x, center_y );
     605            8 :                         geometry_rectangle_embrace( io_view_rect, center_x, center_y + arc_r_y );
     606            8 :                         geometry_rectangle_embrace( io_view_rect, center_x + arc_r_x, center_y );
     607            8 :                         geometry_rectangle_embrace( io_view_rect, command_end_x, command_end_y );
     608            8 :                         command_start_x = command_end_x;
     609            8 :                         command_start_y = command_end_y;
     610              :                     }
     611              :                     else
     612              :                     {
     613            0 :                         U8_TRACE_INFO("inconsistent statemachine");
     614            0 :                         assert(false);
     615              :                     }
     616              :                     /* continue with next */
     617           52 :                     parser_state = DRAW_SVG_PATH_DATA_EXPECT_COMMAND_OR_COORD_SEQ;
     618              :                 }
     619              :             }
     620           93 :             break;
     621              : 
     622            4 :             case DRAW_SVG_PATH_DATA_EXPECT_COORD_CTRL1_X:
     623              :             {
     624            4 :                 if ( utf8stringview_equals_str( &tok, "," ) )
     625              :                 {
     626              :                     /* skip */
     627              :                 }
     628              :                 else
     629              :                 {
     630              :                     /* read coordinate */
     631              :                     /* utf8string_parse_float is faster than utf8stringview_parse_float; only it may not stop at view end but at terminating 0 after svg-path */
     632            4 :                     double value = 0.0;
     633              :                     unsigned int byte_length;
     634              :                     const u8_error_t float_err
     635            4 :                         = utf8string_parse_float( utf8stringview_get_start( &tok ), &byte_length, &value );
     636            4 :                     if ( float_err != U8_ERROR_NONE )
     637              :                     {
     638              :                         /* float_err could be a UTF8ERROR_NOT_FOUND or a UTF8ERROR_OUT_OF_RANGE */
     639            0 :                         u8_error_info_init_line( out_err_info,
     640              :                                                  U8_ERROR_PARSER_STRUCTURE,
     641            0 :                                                  utf8stringviewtokenizer_get_line( tok_iterator )
     642              :                                                );
     643            0 :                         result |= U8_ERROR_PARSER_STRUCTURE;
     644              :                     }
     645              :                     else
     646              :                     {
     647            4 :                         assert( byte_length == utf8stringview_get_length( &tok ) );
     648              :                     }
     649            4 :                     const bool is_absolute = ( last_command <= 'Z' );
     650            4 :                     coord_ctrl1_x = is_absolute ? value : ( command_start_x + value );
     651              :                     /* continue reading last_command parameters */
     652            4 :                     parser_state = DRAW_SVG_PATH_DATA_EXPECT_COORD_CTRL1_Y;
     653              :                 }
     654              :             }
     655            4 :             break;
     656              : 
     657           10 :             case DRAW_SVG_PATH_DATA_EXPECT_COORD_CTRL1_Y:
     658              :             {
     659           10 :                 if ( utf8stringview_equals_str( &tok, "," ) )
     660              :                 {
     661              :                     /* skip */
     662              :                 }
     663              :                 else
     664              :                 {
     665              :                     /* read coordinate */
     666              :                     /* utf8string_parse_float is faster than utf8stringview_parse_float; only it may not stop at view end but at terminating 0 after svg-path */
     667            5 :                     double value = 0.0;
     668              :                     unsigned int byte_length;
     669              :                     const u8_error_t float_err
     670            5 :                         = utf8string_parse_float( utf8stringview_get_start( &tok ), &byte_length, &value );
     671            5 :                     if ( float_err != U8_ERROR_NONE )
     672              :                     {
     673              :                         /* float_err could be a UTF8ERROR_NOT_FOUND or a UTF8ERROR_OUT_OF_RANGE */
     674            0 :                         u8_error_info_init_line( out_err_info,
     675              :                                                  U8_ERROR_PARSER_STRUCTURE,
     676            0 :                                                  utf8stringviewtokenizer_get_line( tok_iterator )
     677              :                                                );
     678            0 :                         result |= U8_ERROR_PARSER_STRUCTURE;
     679              :                     }
     680              :                     else
     681              :                     {
     682            5 :                         assert( byte_length == utf8stringview_get_length( &tok ) );
     683              :                     }
     684            5 :                     const bool is_absolute = ( last_command <= 'Z' );
     685            5 :                     coord_ctrl1_y = is_absolute ? value : ( command_start_y + value );
     686              :                     /* continue reading last_command parameters */
     687            5 :                     parser_state = DRAW_SVG_PATH_DATA_EXPECT_COORD_CTRL2_X;
     688              :                 }
     689              :             }
     690           10 :             break;
     691              : 
     692            9 :             case DRAW_SVG_PATH_DATA_EXPECT_COORD_CTRL2_X:
     693              :             {
     694            9 :                 if ( utf8stringview_equals_str( &tok, "," ) )
     695              :                 {
     696              :                     /* skip */
     697              :                 }
     698              :                 else
     699              :                 {
     700              :                     /* read coordinate */
     701              :                     /* utf8string_parse_float is faster than utf8stringview_parse_float; only it may not stop at view end but at terminating 0 after svg-path */
     702            9 :                     double value = 0.0;
     703              :                     unsigned int byte_length;
     704              :                     const u8_error_t float_err
     705            9 :                         = utf8string_parse_float( utf8stringview_get_start( &tok ), &byte_length, &value );
     706            9 :                     if ( float_err != U8_ERROR_NONE )
     707              :                     {
     708              :                         /* float_err could be a UTF8ERROR_NOT_FOUND or a UTF8ERROR_OUT_OF_RANGE */
     709            0 :                         u8_error_info_init_line( out_err_info,
     710              :                                                  U8_ERROR_PARSER_STRUCTURE,
     711            0 :                                                  utf8stringviewtokenizer_get_line( tok_iterator )
     712              :                                                );
     713            0 :                         result |= U8_ERROR_PARSER_STRUCTURE;
     714              :                     }
     715              :                     else
     716              :                     {
     717            9 :                         assert( byte_length == utf8stringview_get_length( &tok ) );
     718              :                     }
     719            9 :                     const bool is_absolute = ( last_command <= 'Z' );
     720            9 :                     coord_ctrl2_x = is_absolute ? value : ( command_start_x + value );
     721              :                     /* continue reading last_command parameters */
     722            9 :                     parser_state = DRAW_SVG_PATH_DATA_EXPECT_COORD_CTRL2_Y;
     723              :                 }
     724              :             }
     725            9 :             break;
     726              : 
     727           20 :             case DRAW_SVG_PATH_DATA_EXPECT_COORD_CTRL2_Y:
     728              :             {
     729           20 :                 if ( utf8stringview_equals_str( &tok, "," ) )
     730              :                 {
     731              :                     /* skip */
     732              :                 }
     733              :                 else
     734              :                 {
     735              :                     /* read coordinate */
     736              :                     /* utf8string_parse_float is faster than utf8stringview_parse_float; only it may not stop at view end but at terminating 0 after svg-path */
     737           10 :                     double value = 0.0;
     738              :                     unsigned int byte_length;
     739              :                     const u8_error_t float_err
     740           10 :                         = utf8string_parse_float( utf8stringview_get_start( &tok ), &byte_length, &value );
     741           10 :                     if ( float_err != U8_ERROR_NONE )
     742              :                     {
     743              :                         /* float_err could be a UTF8ERROR_NOT_FOUND or a UTF8ERROR_OUT_OF_RANGE */
     744            0 :                         u8_error_info_init_line( out_err_info,
     745              :                                                  U8_ERROR_PARSER_STRUCTURE,
     746            0 :                                                  utf8stringviewtokenizer_get_line( tok_iterator )
     747              :                                                );
     748            0 :                         result |= U8_ERROR_PARSER_STRUCTURE;
     749              :                     }
     750              :                     else
     751              :                     {
     752           10 :                         assert( byte_length == utf8stringview_get_length( &tok ) );
     753              :                     }
     754           10 :                     const bool is_absolute = ( last_command <= 'Z' );
     755           10 :                     coord_ctrl2_y = is_absolute ? value : ( command_start_y + value );
     756              :                     /* continue with next */
     757           10 :                     parser_state = DRAW_SVG_PATH_DATA_EXPECT_COORD_END_X;
     758              :                 }
     759              :             }
     760           20 :             break;
     761              : 
     762            4 :             case DRAW_SVG_PATH_DATA_EXPECT_COORD_QCTRL_X:
     763              :             {
     764            4 :                 if ( utf8stringview_equals_str( &tok, "," ) )
     765              :                 {
     766              :                     /* skip */
     767              :                 }
     768              :                 else
     769              :                 {
     770              :                     /* read coordinate */
     771              :                     /* utf8string_parse_float is faster than utf8stringview_parse_float; only it may not stop at view end but at terminating 0 after svg-path */
     772            4 :                     double value = 0.0;
     773              :                     unsigned int byte_length;
     774              :                     const u8_error_t float_err
     775            4 :                         = utf8string_parse_float( utf8stringview_get_start( &tok ), &byte_length, &value );
     776            4 :                     if ( float_err != U8_ERROR_NONE )
     777              :                     {
     778              :                         /* float_err could be a UTF8ERROR_NOT_FOUND or a UTF8ERROR_OUT_OF_RANGE */
     779            0 :                         u8_error_info_init_line( out_err_info,
     780              :                                                  U8_ERROR_PARSER_STRUCTURE,
     781            0 :                                                  utf8stringviewtokenizer_get_line( tok_iterator )
     782              :                                                );
     783            0 :                         result |= U8_ERROR_PARSER_STRUCTURE;
     784              :                     }
     785              :                     else
     786              :                     {
     787            4 :                         assert( byte_length == utf8stringview_get_length( &tok ) );
     788              :                     }
     789            4 :                     const bool is_absolute = ( last_command <= 'Z' );
     790            4 :                     coord_ctrl1_x = is_absolute ? value : ( command_start_x + value );
     791              :                     /* continue reading last_command parameters */
     792            4 :                     parser_state = DRAW_SVG_PATH_DATA_EXPECT_COORD_QCTRL_Y;
     793              :                 }
     794              :             }
     795            4 :             break;
     796              : 
     797           10 :             case DRAW_SVG_PATH_DATA_EXPECT_COORD_QCTRL_Y:
     798              :             {
     799           10 :                 if ( utf8stringview_equals_str( &tok, "," ) )
     800              :                 {
     801              :                     /* skip */
     802              :                 }
     803              :                 else
     804              :                 {
     805              :                     /* read coordinate */
     806              :                     /* utf8string_parse_float is faster than utf8stringview_parse_float; only it may not stop at view end but at terminating 0 after svg-path */
     807            5 :                     double value = 0.0;
     808              :                     unsigned int byte_length;
     809              :                     const u8_error_t float_err
     810            5 :                         = utf8string_parse_float( utf8stringview_get_start( &tok ), &byte_length, &value );
     811            5 :                     if ( float_err != U8_ERROR_NONE )
     812              :                     {
     813              :                         /* float_err could be a UTF8ERROR_NOT_FOUND or a UTF8ERROR_OUT_OF_RANGE */
     814            0 :                         u8_error_info_init_line( out_err_info,
     815              :                                                  U8_ERROR_PARSER_STRUCTURE,
     816            0 :                                                  utf8stringviewtokenizer_get_line( tok_iterator )
     817              :                                                );
     818            0 :                         result |= U8_ERROR_PARSER_STRUCTURE;
     819              :                     }
     820              :                     else
     821              :                     {
     822            5 :                         assert( byte_length == utf8stringview_get_length( &tok ) );
     823              :                     }
     824            5 :                     const bool is_absolute = ( last_command <= 'Z' );
     825            5 :                     coord_ctrl1_y = is_absolute ? value : ( command_start_y + value );
     826              :                     /* continue with next */
     827            5 :                     parser_state = DRAW_SVG_PATH_DATA_EXPECT_COORD_END_X;
     828              :                 }
     829              :             }
     830           10 :             break;
     831              : 
     832            7 :             case DRAW_SVG_PATH_DATA_EXPECT_ARC_RX:
     833              :             {
     834            7 :                 if ( utf8stringview_equals_str( &tok, "," ) )
     835              :                 {
     836              :                     /* skip */
     837              :                 }
     838              :                 else
     839              :                 {
     840              :                     /* read coordinate */
     841              :                     /* utf8string_parse_float is faster than utf8stringview_parse_float; only it may not stop at view end but at terminating 0 after svg-path */
     842            7 :                     double value = 0.0;
     843              :                     unsigned int byte_length;
     844              :                     const u8_error_t float_err
     845            7 :                         = utf8string_parse_float( utf8stringview_get_start( &tok ), &byte_length, &value );
     846            7 :                     if ( float_err != U8_ERROR_NONE )
     847              :                     {
     848              :                         /* float_err could be a UTF8ERROR_NOT_FOUND or a UTF8ERROR_OUT_OF_RANGE */
     849            0 :                         u8_error_info_init_line( out_err_info,
     850              :                                                  U8_ERROR_PARSER_STRUCTURE,
     851            0 :                                                  utf8stringviewtokenizer_get_line( tok_iterator )
     852              :                                                );
     853            0 :                         result |= U8_ERROR_PARSER_STRUCTURE;
     854              :                     }
     855              :                     else
     856              :                     {
     857            7 :                         assert( byte_length == utf8stringview_get_length( &tok ) );
     858              :                     }
     859              :                     /* store value to appropriate variable */
     860            7 :                     arc_r_x = value;
     861              :                     /* continue reading last_command parameters */
     862            7 :                     parser_state = DRAW_SVG_PATH_DATA_EXPECT_ARC_RY;
     863              :                 }
     864              :             }
     865            7 :             break;
     866              : 
     867           16 :             case DRAW_SVG_PATH_DATA_EXPECT_ARC_RY:
     868              :             {
     869           16 :                 if ( utf8stringview_equals_str( &tok, "," ) )
     870              :                 {
     871              :                     /* skip */
     872              :                 }
     873              :                 else
     874              :                 {
     875              :                     /* read coordinate */
     876              :                     /* utf8string_parse_float is faster than utf8stringview_parse_float; only it may not stop at view end but at terminating 0 after svg-path */
     877            8 :                     double value = 0.0;
     878              :                     unsigned int byte_length;
     879              :                     const u8_error_t float_err
     880            8 :                         = utf8string_parse_float( utf8stringview_get_start( &tok ), &byte_length, &value );
     881            8 :                     if ( float_err != U8_ERROR_NONE )
     882              :                     {
     883              :                         /* float_err could be a UTF8ERROR_NOT_FOUND or a UTF8ERROR_OUT_OF_RANGE */
     884            0 :                         u8_error_info_init_line( out_err_info,
     885              :                                                  U8_ERROR_PARSER_STRUCTURE,
     886            0 :                                                  utf8stringviewtokenizer_get_line( tok_iterator )
     887              :                                                );
     888            0 :                         result |= U8_ERROR_PARSER_STRUCTURE;
     889              :                     }
     890              :                     else
     891              :                     {
     892            8 :                         assert( byte_length == utf8stringview_get_length( &tok ) );
     893              :                     }
     894              :                     /* store value to appropriate variable */
     895            8 :                     arc_r_y = value;
     896              :                     /* continue reading last_command parameters */
     897            8 :                     parser_state = DRAW_SVG_PATH_DATA_EXPECT_ARC_PHI;
     898              :                 }
     899              :             }
     900           16 :             break;
     901              : 
     902            8 :             case DRAW_SVG_PATH_DATA_EXPECT_ARC_PHI:
     903              :             {
     904            8 :                 if ( utf8stringview_equals_str( &tok, "," ) )
     905              :                 {
     906              :                     /* skip */
     907              :                 }
     908              :                 else
     909              :                 {
     910              :                     /* read coordinate */
     911              :                     /* utf8string_parse_float is faster than utf8stringview_parse_float; only it may not stop at view end but at terminating 0 after svg-path */
     912            8 :                     double value = 0.0;
     913              :                     unsigned int byte_length;
     914              :                     const u8_error_t float_err
     915            8 :                         = utf8string_parse_float( utf8stringview_get_start( &tok ), &byte_length, &value );
     916            8 :                     if ( float_err != U8_ERROR_NONE )
     917              :                     {
     918              :                         /* float_err could be a UTF8ERROR_NOT_FOUND or a UTF8ERROR_OUT_OF_RANGE */
     919            0 :                         u8_error_info_init_line( out_err_info,
     920              :                                                  U8_ERROR_PARSER_STRUCTURE,
     921            0 :                                                  utf8stringviewtokenizer_get_line( tok_iterator )
     922              :                                                );
     923            0 :                         result |= U8_ERROR_PARSER_STRUCTURE;
     924              :                     }
     925              :                     else
     926              :                     {
     927            8 :                         assert( byte_length == utf8stringview_get_length( &tok ) );
     928              :                     }
     929              :                     /* store value to appropriate variable */
     930            8 :                     arc_phi = value * ( M_PI / 180.0 );
     931              :                     /* continue reading last_command parameters */
     932            8 :                     parser_state = DRAW_SVG_PATH_DATA_EXPECT_ARC_LARGE;
     933              :                 }
     934              :             }
     935            8 :             break;
     936              : 
     937            8 :             case DRAW_SVG_PATH_DATA_EXPECT_ARC_LARGE:
     938              :             {
     939            8 :                 if ( utf8stringview_equals_str( &tok, "," ) )
     940              :                 {
     941              :                     /* skip */
     942              :                 }
     943              :                 else
     944              :                 {
     945              :                     /* read coordinate */
     946              :                     /* utf8string_parse_float is faster than utf8stringview_parse_float; only it may not stop at view end but at terminating 0 after svg-path */
     947            8 :                     double value = 0.0;
     948              :                     unsigned int byte_length;
     949              :                     const u8_error_t float_err
     950            8 :                         = utf8string_parse_float( utf8stringview_get_start( &tok ), &byte_length, &value );
     951            8 :                     if ( float_err != U8_ERROR_NONE )
     952              :                     {
     953              :                         /* float_err could be a UTF8ERROR_NOT_FOUND or a UTF8ERROR_OUT_OF_RANGE */
     954            0 :                         u8_error_info_init_line( out_err_info,
     955              :                                                  U8_ERROR_PARSER_STRUCTURE,
     956            0 :                                                  utf8stringviewtokenizer_get_line( tok_iterator )
     957              :                                                );
     958            0 :                         result |= U8_ERROR_PARSER_STRUCTURE;
     959              :                     }
     960              :                     else
     961              :                     {
     962            8 :                         assert( byte_length == utf8stringview_get_length( &tok ) );
     963              :                     }
     964              :                     /* store value to appropriate variable */
     965            8 :                     arc_large_arc = ( value > 0.0001 );
     966              :                     /* continue reading last_command parameters */
     967            8 :                     parser_state = DRAW_SVG_PATH_DATA_EXPECT_ARC_SWEEP;
     968              :                 }
     969              :             }
     970            8 :             break;
     971              : 
     972            8 :             case DRAW_SVG_PATH_DATA_EXPECT_ARC_SWEEP:
     973              :             {
     974            8 :                 if ( utf8stringview_equals_str( &tok, "," ) )
     975              :                 {
     976              :                     /* skip */
     977              :                 }
     978              :                 else
     979              :                 {
     980              :                     /* read coordinate */
     981              :                     /* utf8string_parse_float is faster than utf8stringview_parse_float; only it may not stop at view end but at terminating 0 after svg-path */
     982            8 :                     double value = 0.0;
     983              :                     unsigned int byte_length;
     984              :                     const u8_error_t float_err
     985            8 :                         = utf8string_parse_float( utf8stringview_get_start( &tok ), &byte_length, &value );
     986            8 :                     if ( float_err != U8_ERROR_NONE )
     987              :                     {
     988              :                         /* float_err could be a UTF8ERROR_NOT_FOUND or a UTF8ERROR_OUT_OF_RANGE */
     989            0 :                         u8_error_info_init_line( out_err_info,
     990              :                                                  U8_ERROR_PARSER_STRUCTURE,
     991            0 :                                                  utf8stringviewtokenizer_get_line( tok_iterator )
     992              :                                                );
     993            0 :                         result |= U8_ERROR_PARSER_STRUCTURE;
     994              :                     }
     995              :                     else
     996              :                     {
     997            8 :                         assert( byte_length == utf8stringview_get_length( &tok ) );
     998              :                     }
     999              :                     /* store value to appropriate variable */
    1000            8 :                     arc_sweep_positive = ( value > 0.0001 );
    1001              :                     /* continue reading last_command parameters */
    1002            8 :                     parser_state = DRAW_SVG_PATH_DATA_EXPECT_COORD_END_X;
    1003              :                 }
    1004              :             }
    1005            8 :             break;
    1006              : 
    1007            0 :             case DRAW_SVG_PATH_DATA_EXPECT_EXIT:  /* or */
    1008              :             default:
    1009              :             {
    1010              :                 /* the outer while loop should already have been exited */
    1011            0 :                 assert( false );
    1012              :             }
    1013              :             break;
    1014              :         }
    1015              :     }
    1016              : 
    1017              :     /* report error on unfinished drawing */
    1018           28 :     if (( result == U8_ERROR_NONE )&&( parser_state != DRAW_SVG_PATH_DATA_EXPECT_EXIT ))
    1019              :     {
    1020            0 :         result |= U8_ERROR_PARSER_STRUCTURE;
    1021              :         /* if no other error encountered yet, report this one: */
    1022            0 :         if ( ! u8_error_info_is_error( out_err_info ) )
    1023              :         {
    1024            0 :             u8_error_info_init_line( out_err_info,
    1025              :                                      U8_ERROR_PARSER_STRUCTURE,
    1026            0 :                                      utf8stringviewtokenizer_get_line( tok_iterator )
    1027              :                                    );
    1028              :         }
    1029              :     }
    1030              : 
    1031              :     /* check if anything was drawn at all */
    1032           28 :     if ( geometry_rectangle_is_point( io_view_rect ) && view_rect_drop_0_0 )
    1033              :     {
    1034            3 :         result |= U8_ERROR_NOT_FOUND;
    1035              :     }
    1036              : 
    1037           28 :     U8_TRACE_END_ERR(result);
    1038           28 :     return result;
    1039              : }
    1040              : 
    1041              : 
    1042              : /*
    1043              : Copyright 2023-2025 Andreas Warnke
    1044              :     http://www.apache.org/licenses/LICENSE-2.0
    1045              : 
    1046              : Licensed under the Apache License, Version 2.0 (the "License");
    1047              : you may not use this file except in compliance with the License.
    1048              : You may obtain a copy of the License at
    1049              : 
    1050              : 
    1051              : Unless required by applicable law or agreed to in writing, software
    1052              : distributed under the License is distributed on an "AS IS" BASIS,
    1053              : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    1054              : See the License for the specific language governing permissions and
    1055              : limitations under the License.
    1056              : */
        

Generated by: LCOV version 2.0-1