@@ -98,6 +98,14 @@ void psx_svg_timing_list_destroy(psx_svg_timing_list* tl)
9898 mem_free (tl->event_token );
9999 tl->event_token = NULL ;
100100 }
101+ if (tl->event_target_id ) {
102+ mem_free (tl->event_target_id );
103+ tl->event_target_id = NULL ;
104+ }
105+ if (tl->syncbase_id ) {
106+ mem_free (tl->syncbase_id );
107+ tl->syncbase_id = NULL ;
108+ }
101109 mem_free (tl);
102110}
103111
@@ -1727,6 +1735,68 @@ static INLINE void _parse_animation_value(psx_svg_node* node, psx_svg_attr* attr
17271735 attr->value .fval = 0 .0f ;
17281736 return ;
17291737 }
1738+ // font-weight: "bold"
1739+ if (vlen == 4 && strncmp (val_start, " bold" , 4 ) == 0 ) {
1740+ attr->value .fval = (float )FONT_WEIGHT_BOLD ;
1741+ return ;
1742+ }
1743+ // font-style: "italic"
1744+ if (vlen == 6 && strncmp (val_start, " italic" , 6 ) == 0 ) {
1745+ attr->value .fval = 1 .0f ;
1746+ return ;
1747+ }
1748+ // "normal": context-aware — font-weight maps to FONT_WEIGHT_REGULAR, font-style maps to 0
1749+ if (vlen == 6 && strncmp (val_start, " normal" , 6 ) == 0 ) {
1750+ int32_t target_attr = SVG_ATTR_INVALID ;
1751+ uint32_t na = node->attr_count ();
1752+ for (uint32_t i = 0 ; i < na; i++) {
1753+ const psx_svg_attr* ta = node->attr_at (i);
1754+ if (ta && (psx_svg_attr_type)ta->attr_id == SVG_ATTR_ATTRIBUTE_NAME ) {
1755+ target_attr = ta->value .ival ;
1756+ break ;
1757+ }
1758+ }
1759+ if (target_attr == SVG_ATTR_FONT_WEIGHT ) {
1760+ attr->value .fval = (float )FONT_WEIGHT_REGULAR ;
1761+ } else if (target_attr == SVG_ATTR_FONT_STYLE ) {
1762+ attr->value .fval = 0 .0f ;
1763+ } else {
1764+ attr->value .fval = 0 .0f ;
1765+ }
1766+ return ;
1767+ }
1768+ /* stroke-dasharray: parse as float array (comma/space separated). */
1769+ {
1770+ int32_t target_attr = SVG_ATTR_INVALID ;
1771+ uint32_t na = node->attr_count ();
1772+ for (uint32_t i = 0 ; i < na; i++) {
1773+ const psx_svg_attr* ta = node->attr_at (i);
1774+ if (ta && (psx_svg_attr_type)ta->attr_id == SVG_ATTR_ATTRIBUTE_NAME ) {
1775+ target_attr = ta->value .ival ;
1776+ break ;
1777+ }
1778+ }
1779+ if (target_attr == SVG_ATTR_STROKE_DASH_ARRAY ) {
1780+ attr->val_type = SVG_ATTR_VALUE_PTR ;
1781+ uint32_t list_cap = 4 ;
1782+ psx_svg_attr_values_list* list = (psx_svg_attr_values_list*)mem_malloc (sizeof (float ) * list_cap + sizeof (uint32_t ));
1783+ uint32_t count = 0 ;
1784+ const char * ptr = val_start;
1785+ while (ptr < val_end) {
1786+ if (count == list_cap) {
1787+ list_cap = list_cap << 1 ;
1788+ list = (psx_svg_attr_values_list*)mem_realloc (list, sizeof (float ) * list_cap + sizeof (uint32_t ));
1789+ }
1790+ float * val = (float *)(&list->data [0 ]) + count;
1791+ ptr = _parse_number (ptr, val_end, val);
1792+ if (!ptr) { break ; }
1793+ ++count;
1794+ }
1795+ list->length = count;
1796+ attr->value .val = list;
1797+ return ;
1798+ }
1799+ }
17301800 float val_number = 0 .0f ;
17311801 val_start = _parse_length (val_start, val_end, dpi, &val_number);
17321802 attr->value .fval = val_number;
@@ -1973,13 +2043,153 @@ static void _animation_begin_end_cb(psx_svg_node* node, psx_svg_attr* attr, cons
19732043 tl->offsets_ms [tl->offsets_len ++] = ms;
19742044 } else if (!tl->event_token ) {
19752045 uint32_t len = BUF_LEN (ts, te);
1976- char * s = (char *)mem_malloc (len + 1 );
1977- if (!s) {
1978- return ;
2046+ /* begin="indefinite" → store sentinel so trigger() can match it */
2047+ if (len == 10 && strncmp (ts, " indefinite" , 10 ) == 0 ) {
2048+ const char * sentinel = " __indefinite__" ;
2049+ uint32_t slen = 14 ; /* strlen("__indefinite__") */
2050+ char * s = (char *)mem_malloc (slen + 1 );
2051+ if (!s) {
2052+ return ;
2053+ }
2054+ mem_copy (s, sentinel, slen);
2055+ s[slen] = 0 ;
2056+ tl->event_token = s;
2057+ } else if (len >= 12 && strncmp (ts, " accessKey(" , 10 ) == 0 ) {
2058+ /* accessKey(x) → extract single char, store sentinel event token */
2059+ char key_char = ts[10 ];
2060+ if (key_char && ts[11 ] == ' )' ) {
2061+ tl->access_key = key_char;
2062+ const char * sentinel = " __accessKey__" ;
2063+ uint32_t slen = 13 ; /* strlen("__accessKey__") */
2064+ char * s = (char *)mem_malloc (slen + 1 );
2065+ if (!s) {
2066+ return ;
2067+ }
2068+ mem_copy (s, sentinel, slen);
2069+ s[slen] = 0 ;
2070+ tl->event_token = s;
2071+ }
2072+ } else {
2073+ /* Check for id.event syntax (e.g. "btn.click", "btn.click+2s").
2074+ * A dot is an id.event separator only if the first char of the
2075+ * token is a letter or underscore (avoids splitting numbers like
2076+ * "0.5s") and the char after the dot is also a letter. */
2077+ const char * dot = NULL ;
2078+ if ((*ts >= ' a' && *ts <= ' z' ) || (*ts >= ' A' && *ts <= ' Z' ) || *ts == ' _' ) {
2079+ for (const char * dc = ts + 1 ; dc < te; dc++) {
2080+ if (*dc == ' .' && (dc + 1 ) < te
2081+ && ((*(dc + 1 ) >= ' a' && *(dc + 1 ) <= ' z' )
2082+ || (*(dc + 1 ) >= ' A' && *(dc + 1 ) <= ' Z' ))) {
2083+ dot = dc;
2084+ break ;
2085+ }
2086+ }
2087+ }
2088+
2089+ const char * ev_start = ts;
2090+ if (dot) {
2091+ /* Store event_target_id = part before dot */
2092+ uint32_t id_len = (uint32_t )(dot - ts);
2093+ const char * after_dot = dot + 1 ;
2094+ uint32_t after_len = (uint32_t )(te - after_dot);
2095+
2096+ /* Check if this is a syncbase reference (id.begin or id.end) */
2097+ int is_syncbase = 0 ;
2098+ uint32_t sb_type = 0 ;
2099+ const char * sb_rest = NULL ;
2100+
2101+ if (after_len >= 5 && strncmp (after_dot, " begin" , 5 ) == 0 ) {
2102+ sb_rest = after_dot + 5 ;
2103+ /* "begin" must be followed by end-of-token, '+', or '-' */
2104+ if (sb_rest >= te || *sb_rest == ' +' || *sb_rest == ' -' ) {
2105+ is_syncbase = 1 ;
2106+ sb_type = 0 ;
2107+ }
2108+ } else if (after_len >= 3 && strncmp (after_dot, " end" , 3 ) == 0 ) {
2109+ sb_rest = after_dot + 3 ;
2110+ /* "end" must be followed by end-of-token, '+', or '-' */
2111+ if (sb_rest >= te || *sb_rest == ' +' || *sb_rest == ' -' ) {
2112+ is_syncbase = 1 ;
2113+ sb_type = 1 ;
2114+ }
2115+ }
2116+
2117+ if (is_syncbase) {
2118+ /* Store syncbase_id = part before dot */
2119+ char * sid = (char *)mem_malloc (id_len + 1 );
2120+ if (!sid) {
2121+ return ;
2122+ }
2123+ mem_copy (sid, ts, id_len);
2124+ sid[id_len] = 0 ;
2125+ tl->syncbase_id = sid;
2126+ tl->syncbase_type = sb_type;
2127+
2128+ /* Check for optional +/-offset (e.g. "a1.end+1s") */
2129+ if (sb_rest < te && (*sb_rest == ' +' || *sb_rest == ' -' )) {
2130+ float ms = 0 .0f ;
2131+ if (_parse_clock_time (sb_rest, te, &ms)) {
2132+ uint32_t new_len = tl->offsets_len + 1 ;
2133+ float * nbuf = (float *)mem_realloc (tl->offsets_ms , sizeof (float ) * new_len);
2134+ if (nbuf) {
2135+ tl->offsets_ms = nbuf;
2136+ tl->offsets_ms [tl->offsets_len ++] = ms;
2137+ }
2138+ }
2139+ }
2140+ return ; /* syncbase handled, don't fall through to event handling */
2141+ }
2142+
2143+ /* Not syncbase — original id.event handling */
2144+ char * tid = (char *)mem_malloc (id_len + 1 );
2145+ if (!tid) {
2146+ return ;
2147+ }
2148+ mem_copy (tid, ts, id_len);
2149+ tid[id_len] = 0 ;
2150+ tl->event_target_id = tid;
2151+ ev_start = dot + 1 ; /* remainder is the event token (+ optional offset) */
2152+ }
2153+
2154+ /* Check for event+offset syntax (e.g. "click+2s", "click-1s") */
2155+ const char * sign = NULL ;
2156+ for (const char * sc = ev_start + 1 ; sc < te; sc++) {
2157+ if (*sc == ' +' || *sc == ' -' ) {
2158+ sign = sc;
2159+ break ;
2160+ }
2161+ }
2162+ if (sign) {
2163+ /* event name is before the sign */
2164+ uint32_t elen = (uint32_t )(sign - ev_start);
2165+ char * s = (char *)mem_malloc (elen + 1 );
2166+ if (!s) {
2167+ return ;
2168+ }
2169+ mem_copy (s, ev_start, elen);
2170+ s[elen] = 0 ;
2171+ tl->event_token = s;
2172+ /* offset is from sign to end */
2173+ float ms = 0 .0f ;
2174+ if (_parse_clock_time (sign, te, &ms)) {
2175+ uint32_t new_len = tl->offsets_len + 1 ;
2176+ float * nbuf = (float *)mem_realloc (tl->offsets_ms , sizeof (float ) * new_len);
2177+ if (nbuf) {
2178+ tl->offsets_ms = nbuf;
2179+ tl->offsets_ms [tl->offsets_len ++] = ms;
2180+ }
2181+ }
2182+ } else {
2183+ uint32_t elen = (uint32_t )(te - ev_start);
2184+ char * s = (char *)mem_malloc (elen + 1 );
2185+ if (!s) {
2186+ return ;
2187+ }
2188+ mem_copy (s, ev_start, elen);
2189+ s[elen] = 0 ;
2190+ tl->event_token = s;
2191+ }
19792192 }
1980- mem_copy (s, ts, len);
1981- s[len] = 0 ;
1982- tl->event_token = s;
19832193 }
19842194}
19852195
0 commit comments