LCOV - code coverage report
Current view: top level - pencil/source/draw - draw_svg_path_data.c (source / functions) Hit Total Coverage
Test: crystal-facet-uml_v1.61.0_covts Lines: 352 448 78.6 %
Date: 2024-10-26 21:44:38 Functions: 1 1 100.0 %

          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           4 :                         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-2024 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 1.16