Skip to content

Commit bc0d8fc

Browse files
committed
Merge pull request #195 from cscott/paint-validation
Validate fill, stroke, and opacity properties.
2 parents 899cddd + 30b3261 commit bc0d8fc

File tree

3 files changed

+179
-3
lines changed

3 files changed

+179
-3
lines changed

src/css/Properties.js

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,9 @@ var Properties = {
287287
"empty-cells" : "show | hide | inherit",
288288

289289
//F
290-
"fill" : "<color> | inherit",
290+
"fill" : "<paint> | inherit",
291+
"fill-opacity" : "<opacity-value> | inherit",
292+
"fill-rule" : "nonzero | evenodd | inherit",
291293
"filter" : "<filter-function-list> | none",
292294
"fit" : "fill | hidden | meet | slice",
293295
"fit-position" : 1,
@@ -423,7 +425,7 @@ var Properties = {
423425
//O
424426
"object-fit" : "fill | contain | cover | none | scale-down",
425427
"object-position" : "<position> | inherit",
426-
"opacity" : "<number> | inherit",
428+
"opacity" : "<opacity-value> | inherit",
427429
"order" : "<integer>",
428430
"-webkit-order" : "<integer>",
429431
"orphans" : "<integer> | inherit",
@@ -491,6 +493,14 @@ var Properties = {
491493
"src" : 1,
492494
"stress" : 1,
493495
"string-set" : 1,
496+
"stroke" : "<paint> | inherit",
497+
"stroke-dasharray" : "none | <dasharray> | inherit",
498+
"stroke-dashoffset" : "<percentage> | <length> | inherit",
499+
"stroke-linecap" : "butt | round | square | inherit",
500+
"stroke-linejoin" : "miter | round | bevel | inherit",
501+
"stroke-miterlimit" : "<miterlimit> | inherit",
502+
"stroke-opacity" : "<opacity-value> | inherit",
503+
"stroke-width" : "<percentage> | <length> | inherit",
494504

495505
"table-layout" : "auto | fixed | inherit",
496506
"tab-size" : "<integer> | <length>",

src/css/ValidationTypes.js

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -388,10 +388,39 @@ ValidationTypes = {
388388
return part.type === "color" || String(part) === "transparent" || String(part) === "currentColor";
389389
},
390390

391+
// The SVG <color> spec doesn't include "currentColor" or "transparent" as a color.
392+
"<color-svg>": function(part) {
393+
return part.type === "color";
394+
},
395+
396+
"<icccolor>": function(part){
397+
/* ex.:
398+
https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/local
399+
icc-color(acmecmyk, 0.11, 0.48, 0.83, 0.00)
400+
cielab(62.253188, 23.950124, 48.410653)
401+
cielch(62.253188, 54.011108, 63.677091)
402+
icc-color(FooColors, Sandy23C)
403+
http://www.w3.org/TR/2009/WD-SVGColor12-20091001/#iccnamedcolor
404+
~"icc-color(" name (comma-wsp number)+ ")"
405+
~"icc-named-color(" name comma-wsp namedColor ")"
406+
~"cielab(" lightness comma-wsp a-value comma-wsp b-value ")"
407+
~"cielchab(" lightness comma-wsp chroma comma-wsp hue ")"
408+
*/
409+
return ValidationTypes.isLiteral(part, "cielab() | cielch() | cielchab() | icc-color() | icc-named-color()");
410+
},
411+
391412
"<number>": function(part){
392413
return part.type === "number" || this["<integer>"](part);
393414
},
394415

416+
"<miterlimit>": function(part){
417+
return this["<number>"](part) && part.value >= 1;
418+
},
419+
420+
"<opacity-value>": function(part){
421+
return this["<number>"](part) && part.value >= 0 && part.value <= 1;
422+
},
423+
395424
"<integer>": function(part){
396425
return part.type === "integer";
397426
},
@@ -517,10 +546,31 @@ ValidationTypes = {
517546
// <basic-shape> || <geometry-box>
518547
Matcher.cast("<basic-shape>").oror("<geometry-box>"),
519548

549+
"<dasharray>":
550+
// "list of comma and/or white space separated <length>s and
551+
// <percentage>s". We use <padding-width> to enforce the
552+
// nonnegative constraint.
553+
Matcher.cast("<padding-width>")
554+
.braces(1, Infinity, "#", Matcher.cast(",").question()),
555+
520556
"<filter-function-list>":
521557
// [ <filter-function> | <uri> ]+
522558
Matcher.cast("<filter-function> | <uri>").plus(),
523559

560+
"<paint>":
561+
// none | currentColor | <color> [<icccolor>]? |
562+
// <funciri> [ none | currentColor | <color> [<icccolor>]? ]?
563+
564+
// Note that <color> here is "as defined in the SVG spec", which
565+
// is more restrictive that the <color> defined in the CSS spec.
566+
Matcher.alt("<paint-basic>",
567+
Matcher.seq("<uri>", Matcher.cast("<paint-basic>").question())),
568+
// Helper definition for <paint> above.
569+
"<paint-basic>":
570+
Matcher.alt("none", "currentColor",
571+
Matcher.seq("<color-svg>",
572+
Matcher.cast("<icccolor>").question())),
573+
524574
"<position>":
525575
// <position> = [
526576
// [ left | center | right | top | bottom | <percentage> | <length> ]

tests/css/Validation.js

Lines changed: 117 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -729,6 +729,46 @@
729729
}
730730
}));
731731

732+
// test <paint>
733+
suite.add(new ValidationTestCase({
734+
property: "fill",
735+
736+
valid: [
737+
"url('myGradient')",
738+
"url('myGradient') darkred",
739+
"url('myGradient') darkred icc-color(myCmykDarkRed)",
740+
"currentColor",
741+
"darkred icc-color(myCmykDarkRed)",
742+
"none",
743+
"inherit"
744+
],
745+
746+
invalid: {
747+
"url('myGradient') inherit" : "Expected end of value but found 'inherit'.",
748+
"url('myGradient') icc-color(myCmykDarkRed)" : "Expected end of value but found 'icc-color(myCmykDarkRed)'.",
749+
"currentColor icc-color(myCmykDarkRed)" : "Expected end of value but found 'icc-color(myCmykDarkRed)'.",
750+
"icc-color(myCmykDarkRed) darkred" : "Expected (<paint> | inherit) but found 'icc-color(myCmykDarkRed) darkred'.",
751+
"icc-color(myCmykDarkRed)" : "Expected (<paint> | inherit) but found 'icc-color(myCmykDarkRed)'.",
752+
"icc-color(myCmykDarkRed) inherit" : "Expected (<paint> | inherit) but found 'icc-color(myCmykDarkRed) inherit'.",
753+
"inherit icc-color(myCmykDarkRed)" : "Expected end of value but found 'icc-color(myCmykDarkRed)'.",
754+
"none inherit" : "Expected end of value but found 'inherit'."
755+
}
756+
}));
757+
758+
suite.add(new ValidationTestCase({
759+
property: "fill-rule",
760+
761+
valid: [
762+
"nonzero",
763+
"evenodd",
764+
"inherit"
765+
],
766+
767+
invalid: {
768+
"foo" : "Expected (nonzero | evenodd | inherit) but found 'foo'."
769+
}
770+
}));
771+
732772
suite.add(new ValidationTestCase({
733773
property: "filter",
734774

@@ -1040,11 +1080,15 @@
10401080
property: "opacity",
10411081

10421082
valid: [
1083+
"0",
1084+
"0.5",
10431085
"1"
10441086
],
10451087

10461088
invalid: {
1047-
"foo" : "Expected (<number> | inherit) but found 'foo'."
1089+
"-0.75" : "Expected (<opacity-value> | inherit) but found '-0.75'.",
1090+
"12" : "Expected (<opacity-value> | inherit) but found '12'.",
1091+
"foo" : "Expected (<opacity-value> | inherit) but found 'foo'."
10481092
}
10491093
}));
10501094

@@ -1070,6 +1114,78 @@
10701114
}
10711115
}));
10721116

1117+
suite.add(new ValidationTestCase({
1118+
property: "stroke-dasharray",
1119+
1120+
valid: [
1121+
"0",
1122+
"4",
1123+
"20px",
1124+
"20px 40px 30px",
1125+
"20px, 40px, 30px",
1126+
"calc(1px + 2px) calc(3px + 1em)",
1127+
"none",
1128+
"inherit"
1129+
],
1130+
1131+
invalid: {
1132+
"-20px" : "Expected (none | <dasharray> | inherit) but found '-20px'.",
1133+
"20px," : "Expected end of value but found ','.",
1134+
"20px, -20px": "Expected end of value but found ','.",
1135+
"auto" : "Expected (none | <dasharray> | inherit) but found 'auto'."
1136+
}
1137+
}));
1138+
1139+
suite.add(new ValidationTestCase({
1140+
property: "stroke-linecap",
1141+
1142+
valid: [
1143+
"butt",
1144+
"round",
1145+
"square",
1146+
"inherit"
1147+
],
1148+
1149+
invalid: {
1150+
"auto" : "Expected (butt | round | square | inherit) but found 'auto'.",
1151+
"none" : "Expected (butt | round | square | inherit) but found 'none'."
1152+
}
1153+
}));
1154+
1155+
suite.add(new ValidationTestCase({
1156+
property: "stroke-linejoin",
1157+
1158+
valid: [
1159+
"miter",
1160+
"round",
1161+
"bevel",
1162+
"inherit"
1163+
],
1164+
1165+
invalid: {
1166+
"auto" : "Expected (miter | round | bevel | inherit) but found 'auto'.",
1167+
"none" : "Expected (miter | round | bevel | inherit) but found 'none'."
1168+
}
1169+
}));
1170+
1171+
suite.add(new ValidationTestCase({
1172+
property: "stroke-miterlimit",
1173+
1174+
valid: [
1175+
"1",
1176+
"1.4",
1177+
"20",
1178+
"10",
1179+
"inherit"
1180+
],
1181+
1182+
invalid: {
1183+
"-10" : "Expected (<miterlimit> | inherit) but found '-10'.",
1184+
"0.5" : "Expected (<miterlimit> | inherit) but found '0.5'.",
1185+
"foo" : "Expected (<miterlimit> | inherit) but found 'foo'."
1186+
}
1187+
}));
1188+
10731189
suite.add(new ValidationTestCase({
10741190
property: "-ms-touch-action",
10751191

0 commit comments

Comments
 (0)