Skip to content

Commit 91ae127

Browse files
authored
Add SVG paint attributes (#907)
Fixes #903
1 parent 3202273 commit 91ae127

File tree

5 files changed

+241
-2
lines changed

5 files changed

+241
-2
lines changed

include/tidyenum.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1346,6 +1346,22 @@ typedef enum
13461346
TidyAttr_SLOT, /**< SLOT= */
13471347
TidyAttr_LOADING, /**< LOADING= */
13481348

1349+
/* SVG paint attributes (SVG 1.1) */
1350+
TidyAttr_FILL, /**< FILL= */
1351+
TidyAttr_FILLRULE, /**< FILLRULE= */
1352+
TidyAttr_STROKE, /**< STROKE= */
1353+
TidyAttr_STROKEDASHARRAY, /**< STROKEDASHARRAY= */
1354+
TidyAttr_STROKEDASHOFFSET, /**< STROKEDASHOFFSET= */
1355+
TidyAttr_STROKELINECAP, /**< STROKELINECAP= */
1356+
TidyAttr_STROKELINEJOIN, /**< STROKELINEJOIN= */
1357+
TidyAttr_STROKEMITERLIMIT, /**< STROKEMITERLIMIT= */
1358+
TidyAttr_STROKEWIDTH, /**< STROKEWIDTH= */
1359+
TidyAttr_COLORINTERPOLATION, /**< COLORINTERPOLATION= */
1360+
TidyAttr_COLORRENDERING, /**< COLORRENDERING= */
1361+
TidyAttr_OPACITY, /**< OPACITY= */
1362+
TidyAttr_STROKEOPACITY, /**< STROKEOPACITY= */
1363+
TidyAttr_FILLOPACITY, /**< FILLOPACITY= */
1364+
13491365
N_TIDY_ATTRIBS /**< Must be last */
13501366
} TidyAttrId;
13511367

src/attrdict.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3116,6 +3116,21 @@ const AttrVersion TY_(W3CAttrsFor_SVG)[] =
31163116
{ TidyAttr_BASEPROFILE, xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|H41S|X10S|XH11|xxxx|HT50|XH50 },
31173117
{ TidyAttr_CONTENTSCRIPTTYPE, xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|H41S|X10S|XH11|xxxx|HT50|XH50 },
31183118
{ TidyAttr_CONTENTSTYLETYPE, xxxx|xxxx|H40T|H41T|X10T|H40F|H41F|X10F|xxxx|H41S|X10S|XH11|xxxx|HT50|XH50 },
3119+
{ TidyAttr_COLOR, xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 },
3120+
{ TidyAttr_FILL, xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 },
3121+
{ TidyAttr_FILLRULE, xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 },
3122+
{ TidyAttr_STROKE, xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 },
3123+
{ TidyAttr_STROKEDASHARRAY, xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 },
3124+
{ TidyAttr_STROKEDASHOFFSET, xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 },
3125+
{ TidyAttr_STROKELINECAP, xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 },
3126+
{ TidyAttr_STROKELINEJOIN, xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 },
3127+
{ TidyAttr_STROKEMITERLIMIT, xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 },
3128+
{ TidyAttr_STROKEWIDTH, xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 },
3129+
{ TidyAttr_COLORINTERPOLATION, xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 },
3130+
{ TidyAttr_COLORRENDERING, xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 },
3131+
{ TidyAttr_OPACITY, xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 },
3132+
{ TidyAttr_STROKEOPACITY, xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 },
3133+
{ TidyAttr_FILLOPACITY, xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|XH11|xxxx|HT50|XH50 },
31193134
INCLUDE_CORE_ATTRIBS
31203135
INCLUDE_CORE_EVENTS
31213136
INCLUDE_RDFA

src/attrs.c

Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ static AttrCheck CheckType;
5252
static AttrCheck CheckRDFaSafeCURIE;
5353
static AttrCheck CheckRDFaTerm;
5454
static AttrCheck CheckRDFaPrefix;
55+
static AttrCheck CheckDecimal;
56+
static AttrCheck CheckSvgAttr;
5557

5658
#define CH_PCDATA NULL
5759
#define CH_CHARSET NULL
@@ -97,6 +99,8 @@ static AttrCheck CheckRDFaPrefix;
9799
#define CH_RDFASCURIES CheckRDFaSafeCURIE
98100
#define CH_RDFATERM CheckRDFaTerm
99101
#define CH_RDFATERMS CheckRDFaTerm
102+
#define CH_DECIMAL CheckDecimal
103+
#define CH_SVG CheckSvgAttr
100104

101105
static const Attribute attribute_defs [] =
102106
{
@@ -444,6 +448,22 @@ static const Attribute attribute_defs [] =
444448
/* for xmlns:xlink in <svg> */
445449
{ TidyAttr_XMLNSXLINK, "xmlns:xlink", CH_URL },
446450

451+
/* SVG paint attributes (SVG 1.1) */
452+
{ TidyAttr_FILL, "fill", CH_SVG },
453+
{ TidyAttr_FILLRULE, "fill-rule", CH_SVG },
454+
{ TidyAttr_STROKE, "stroke", CH_SVG },
455+
{ TidyAttr_STROKEDASHARRAY, "stroke-dasharray", CH_SVG },
456+
{ TidyAttr_STROKEDASHOFFSET, "stroke-dashoffset", CH_SVG },
457+
{ TidyAttr_STROKELINECAP, "stroke-linecap", CH_SVG },
458+
{ TidyAttr_STROKELINEJOIN, "stroke-linejoin", CH_SVG },
459+
{ TidyAttr_STROKEMITERLIMIT, "stroke-miterlimit", CH_SVG },
460+
{ TidyAttr_STROKEWIDTH, "stroke-width", CH_SVG },
461+
{ TidyAttr_COLORINTERPOLATION, "color-interpolation", CH_SVG },
462+
{ TidyAttr_COLORRENDERING, "color-rendering", CH_SVG },
463+
{ TidyAttr_OPACITY, "opacity", CH_SVG },
464+
{ TidyAttr_STROKEOPACITY, "stroke-opacity", CH_SVG },
465+
{ TidyAttr_FILLOPACITY, "fill-opacity", CH_SVG },
466+
447467
/* this must be the final entry */
448468
{ N_TIDY_ATTRIBS, NULL, NULL }
449469
};
@@ -2099,6 +2119,180 @@ void CheckType( TidyDocImpl* doc, Node *node, AttVal *attval)
20992119
return;
21002120
}
21012121

2122+
static void CheckDecimal( TidyDocImpl* doc, Node *node, AttVal *attval)
2123+
{
2124+
tmbstr p;
2125+
Bool hasPoint = no;
2126+
2127+
p = attval->value;
2128+
2129+
/* Allow leading sign */
2130+
if (*p == '+' || *p == '-')
2131+
++p;
2132+
2133+
while (*p)
2134+
{
2135+
/* Allow a single decimal point */
2136+
if (*p == '.')
2137+
{
2138+
if (!hasPoint)
2139+
hasPoint = yes;
2140+
else
2141+
TY_(ReportAttrError)( doc, node, attval, BAD_ATTRIBUTE_VALUE);
2142+
break;
2143+
}
2144+
2145+
if (!TY_(IsDigit)(*p))
2146+
{
2147+
TY_(ReportAttrError)( doc, node, attval, BAD_ATTRIBUTE_VALUE);
2148+
break;
2149+
}
2150+
++p;
2151+
}
2152+
}
2153+
2154+
static Bool IsSvgPaintAttr(AttVal *attval)
2155+
{
2156+
return attrIsCOLOR(attval)
2157+
|| attrIsSVG_FILL(attval)
2158+
|| attrIsSVG_FILLRULE(attval)
2159+
|| attrIsSVG_STROKE(attval)
2160+
|| attrIsSVG_STROKEDASHARRAY(attval)
2161+
|| attrIsSVG_STROKEDASHOFFSET(attval)
2162+
|| attrIsSVG_STROKELINECAP(attval)
2163+
|| attrIsSVG_STROKELINEJOIN(attval)
2164+
|| attrIsSVG_STROKEMITERLIMIT(attval)
2165+
|| attrIsSVG_STROKEWIDTH(attval)
2166+
|| attrIsSVG_COLORINTERPOLATION(attval)
2167+
|| attrIsSVG_COLORRENDERING(attval)
2168+
|| attrIsSVG_OPACITY(attval)
2169+
|| attrIsSVG_STROKEOPACITY(attval)
2170+
|| attrIsSVG_FILLOPACITY(attval);
2171+
}
2172+
2173+
/* Check SVG attributes */
2174+
static void CheckSvgAttr( TidyDocImpl* doc, Node *node, AttVal *attval)
2175+
{
2176+
if (!nodeIsSVG(node))
2177+
{
2178+
TY_(ReportAttrError)(doc, node, attval, ATTRIBUTE_IS_NOT_ALLOWED);
2179+
return;
2180+
}
2181+
2182+
/* Issue #903 - check SVG paint attributes */
2183+
if (IsSvgPaintAttr(attval))
2184+
{
2185+
/* all valid paint attributes have values */
2186+
if (!AttrHasValue(attval))
2187+
{
2188+
TY_(ReportAttrError)(doc, node, attval, MISSING_ATTR_VALUE);
2189+
return;
2190+
}
2191+
/* all paint attributes support an 'inherit' value,
2192+
per https://dev.w3.org/SVG/profiles/1.1F2/publish/painting.html#SpecifyingPaint */
2193+
if (AttrValueIs(attval, "inherit"))
2194+
{
2195+
return;
2196+
}
2197+
2198+
/* check paint datatypes
2199+
see https://dev.w3.org/SVG/profiles/1.1F2/publish/painting.html#SpecifyingPaint
2200+
*/
2201+
if (attrIsSVG_FILL(attval) || attrIsSVG_STROKE(attval))
2202+
{
2203+
/* TODO: support funciri */
2204+
static ctmbstr const values[] = {
2205+
"none", "currentColor", NULL};
2206+
2207+
if (AttrValueIsAmong(attval, values))
2208+
CheckLowerCaseAttrValue(doc, node, attval);
2209+
else
2210+
CheckColor(doc, node, attval);
2211+
}
2212+
else if (attrIsSVG_FILLRULE(attval))
2213+
{
2214+
static ctmbstr const values[] = {"nonzero", "evenodd", NULL};
2215+
2216+
if (AttrValueIsAmong(attval, values))
2217+
CheckLowerCaseAttrValue(doc, node, attval);
2218+
else
2219+
TY_(ReportAttrError)(doc, node, attval, BAD_ATTRIBUTE_VALUE);
2220+
}
2221+
else if (attrIsSVG_STROKEDASHARRAY(attval))
2222+
{
2223+
static ctmbstr const values[] = {"none", NULL};
2224+
2225+
if (AttrValueIsAmong(attval, values))
2226+
CheckLowerCaseAttrValue(doc, node, attval);
2227+
else
2228+
{
2229+
/* TODO: process dash arrays */
2230+
}
2231+
}
2232+
else if (attrIsSVG_STROKEDASHOFFSET(attval))
2233+
{
2234+
CheckLength(doc, node, attval);
2235+
}
2236+
else if (attrIsSVG_STROKELINECAP(attval))
2237+
{
2238+
static ctmbstr const values[] = {"butt", "round", "square", NULL};
2239+
2240+
if (AttrValueIsAmong(attval, values))
2241+
CheckLowerCaseAttrValue(doc, node, attval);
2242+
else
2243+
TY_(ReportAttrError)(doc, node, attval, BAD_ATTRIBUTE_VALUE);
2244+
}
2245+
else if (attrIsSVG_STROKELINEJOIN(attval))
2246+
{
2247+
static ctmbstr const values[] = {"miter", "round", "bevel", NULL};
2248+
2249+
if (AttrValueIsAmong(attval, values))
2250+
CheckLowerCaseAttrValue(doc, node, attval);
2251+
else
2252+
TY_(ReportAttrError)(doc, node, attval, BAD_ATTRIBUTE_VALUE);
2253+
}
2254+
else if (attrIsSVG_STROKEMITERLIMIT(attval))
2255+
{
2256+
CheckNumber(doc, node, attval);
2257+
}
2258+
else if (attrIsSVG_STROKEWIDTH(attval))
2259+
{
2260+
CheckLength(doc, node, attval);
2261+
}
2262+
else if (attrIsSVG_COLORINTERPOLATION(attval))
2263+
{
2264+
static ctmbstr const values[] = {"auto", "sRGB", "linearRGB", NULL};
2265+
2266+
if (AttrValueIsAmong(attval, values))
2267+
CheckLowerCaseAttrValue(doc, node, attval);
2268+
else
2269+
TY_(ReportAttrError)(doc, node, attval, BAD_ATTRIBUTE_VALUE);
2270+
}
2271+
else if (attrIsSVG_COLORRENDERING(attval))
2272+
{
2273+
static ctmbstr const values[] = {
2274+
"auto", "optimizeSpeed", "optimizeQuality", NULL};
2275+
2276+
if (AttrValueIsAmong(attval, values))
2277+
CheckLowerCaseAttrValue(doc, node, attval);
2278+
else
2279+
TY_(ReportAttrError)(doc, node, attval, BAD_ATTRIBUTE_VALUE);
2280+
}
2281+
else if(attrIsSVG_OPACITY(attval))
2282+
{
2283+
CheckDecimal(doc, node, attval);
2284+
}
2285+
else if(attrIsSVG_STROKEOPACITY(attval))
2286+
{
2287+
CheckDecimal(doc, node, attval);
2288+
}
2289+
else if(attrIsSVG_FILLOPACITY(attval))
2290+
{
2291+
CheckDecimal(doc, node, attval);
2292+
}
2293+
}
2294+
}
2295+
21022296
static
21032297
AttVal *SortAttVal( TidyDocImpl* doc, AttVal* list, TidyAttrSortStrategy strat );
21042298

src/attrs.h

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -375,8 +375,20 @@ Bool TY_(AttributeIsMismatched)(Node* node, AttVal* attval, TidyDocImpl* doc);
375375
#define attrIsARIA_VALUEMIN(av) AttrIsId( av, TidyAttr_ARIA_VALUEMIN )
376376
#define attrIsARIA_VALUENOW(av) AttrIsId( av, TidyAttr_ARIA_VALUENOW )
377377
#define attrIsARIA_VALUETEXT(av) AttrIsId( av, TidyAttr_ARIA_VALUETEXT )
378-
379-
378+
#define attrIsSVG_FILL(av) AttrIsId( av, TidyAttr_FILL )
379+
#define attrIsSVG_FILLRULE(av) AttrIsId( av, TidyAttr_FILLRULE )
380+
#define attrIsSVG_STROKE(av) AttrIsId( av, TidyAttr_STROKE )
381+
#define attrIsSVG_STROKEDASHARRAY(av) AttrIsId( av, TidyAttr_STROKEDASHARRAY )
382+
#define attrIsSVG_STROKEDASHOFFSET(av) AttrIsId( av, TidyAttr_STROKEDASHOFFSET )
383+
#define attrIsSVG_STROKELINECAP(av) AttrIsId( av, TidyAttr_STROKELINECAP )
384+
#define attrIsSVG_STROKELINEJOIN(av) AttrIsId( av, TidyAttr_STROKELINEJOIN )
385+
#define attrIsSVG_STROKEMITERLIMIT(av) AttrIsId( av, TidyAttr_STROKEMITERLIMIT )
386+
#define attrIsSVG_STROKEWIDTH(av) AttrIsId( av, TidyAttr_STROKEWIDTH )
387+
#define attrIsSVG_COLORINTERPOLATION(a) AttrIsId( a, TidyAttr_COLORINTERPOLATION )
388+
#define attrIsSVG_COLORRENDERING(av) AttrIsId( av, TidyAttr_COLORRENDERING )
389+
#define attrIsSVG_OPACITY(av) AttrIsId( av, TidyAttr_OPACITY )
390+
#define attrIsSVG_STROKEOPACITY(av) AttrIsId( av, TidyAttr_STROKEOPACITY )
391+
#define attrIsSVG_FILLOPACITY(av) AttrIsId( av, TidyAttr_FILLOPACITY )
380392

381393
/* Attribute Retrieval macros
382394
*/

src/tags.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -452,6 +452,8 @@ uint TY_(nodeHeaderLevel)( Node* node );
452452
#define nodeIsINS( node ) TagIsId( node, TidyTag_INS )
453453
#define nodeIsDEL( node ) TagIsId( node, TidyTag_DEL )
454454

455+
#define nodeIsSVG( node ) TagIsId( node, TidyTag_SVG )
456+
455457
/* HTML5 */
456458
#define nodeIsDATALIST( node ) TagIsId( node, TidyTag_DATALIST )
457459
#define nodeIsDATA( node ) TagIsId( node, TidyTag_DATA )

0 commit comments

Comments
 (0)