44import java .util .ArrayList ;
55import java .util .Arrays ;
66import java .util .HashSet ;
7+ import java .util .regex .Pattern ;
78
89public class FilterUtils {
910 private static volatile boolean logDEBUG ;
@@ -289,6 +290,7 @@ else if(value.contains("rad"))
289290 SVGcolorKeywords .add ("whitesmoke" );
290291 SVGcolorKeywords .add ("yellow" );
291292 SVGcolorKeywords .add ("yellowgreen" );
293+ SVGcolorKeywords .add ("rebeccapurple" ); // CSS Colors Level 4: #663399
292294 }
293295 private final static HashSet <String > CSScolorKeywords =new HashSet <String >();
294296 static
@@ -315,34 +317,34 @@ else if(value.contains("rad"))
315317 }
316318 private final static HashSet <String > CSSsystemColorKeywords =new HashSet <String >();
317319 static {
318- CSScolorKeywords .add ("ActiveBorder " );
319- CSScolorKeywords .add ("ActiveCaption " );
320- CSScolorKeywords .add ("AppWorkspace " );
321- CSScolorKeywords .add ("Background " );
322- CSScolorKeywords .add ("ButtonFace " );
323- CSScolorKeywords .add ("ButtonHighlight " );
324- CSScolorKeywords .add ("ButtonShadow " );
325- CSScolorKeywords .add ("ButtonText " );
326- CSScolorKeywords .add ("CaptionText " );
327- CSScolorKeywords .add ("GrayText " );
328- CSScolorKeywords .add ("Highlight " );
329- CSScolorKeywords .add ("HighlightText " );
330- CSScolorKeywords .add ("InactiveBorder " );
331- CSScolorKeywords .add ("InactiveCaption " );
332- CSScolorKeywords .add ("InactiveCaptionText " );
333- CSScolorKeywords .add ("InfoBackground " );
334- CSScolorKeywords .add ("InfoText " );
335- CSScolorKeywords .add ("Menu " );
336- CSScolorKeywords .add ("MenuText " );
337- CSScolorKeywords .add ("Scrollbar " );
338- CSScolorKeywords .add ("ThreeDDarkShadow " );
339- CSScolorKeywords .add ("ThreeDFace " );
340- CSScolorKeywords .add ("ThreeDHighlight " );
341- CSScolorKeywords .add ("ThreeDLightShadow " );
342- CSScolorKeywords .add ("ThreeDShadow " );
343- CSScolorKeywords .add ("Window " );
344- CSScolorKeywords .add ("WindowFrame " );
345- CSScolorKeywords .add ("WindowText " );
320+ CSScolorKeywords .add ("activeborder " );
321+ CSScolorKeywords .add ("activecaption " );
322+ CSScolorKeywords .add ("appworkspace " );
323+ CSScolorKeywords .add ("background " );
324+ CSScolorKeywords .add ("buttonface " );
325+ CSScolorKeywords .add ("buttonhighlight " );
326+ CSScolorKeywords .add ("buttonshadow " );
327+ CSScolorKeywords .add ("buttontext " );
328+ CSScolorKeywords .add ("captiontext " );
329+ CSScolorKeywords .add ("graytext " );
330+ CSScolorKeywords .add ("highlight " );
331+ CSScolorKeywords .add ("highlighttext " );
332+ CSScolorKeywords .add ("inactiveborder " );
333+ CSScolorKeywords .add ("inactivecaption " );
334+ CSScolorKeywords .add ("inactivecaptiontext " );
335+ CSScolorKeywords .add ("infobackground " );
336+ CSScolorKeywords .add ("infotext " );
337+ CSScolorKeywords .add ("menu " );
338+ CSScolorKeywords .add ("menutext " );
339+ CSScolorKeywords .add ("scrollbar " );
340+ CSScolorKeywords .add ("threeddarkshadow " );
341+ CSScolorKeywords .add ("threedface " );
342+ CSScolorKeywords .add ("threedhighlight " );
343+ CSScolorKeywords .add ("threedlightshadow " );
344+ CSScolorKeywords .add ("threedshadow " );
345+ CSScolorKeywords .add ("window " );
346+ CSScolorKeywords .add ("windowframe " );
347+ CSScolorKeywords .add ("windowtext " );
346348 }
347349 public static boolean isValidCSSShape (String value )
348350 {
@@ -370,70 +372,57 @@ public static boolean isValidCSSShape(String value)
370372 public static boolean isMedia (String media ) {
371373 return cssMedia .contains (media );
372374 }
375+
376+ public static final Pattern hexColorPattern = Pattern .compile ("#(?>[0-9a-f]{8}|[0-9a-f]{6}|[0-9a-f]{3,4})" , Pattern .CASE_INSENSITIVE );
377+
373378 public static boolean isColor (String value )
374379 {
375- value =value .trim ();
380+ value =value .trim (). toLowerCase () ;
376381
377382 if (CSScolorKeywords .contains (value ) || CSSsystemColorKeywords .contains (value ) || SVGcolorKeywords .contains (value ))
378383 return true ;
379384
380385 if (value .indexOf ('#' )==0 )
381386 {
382-
383- if (value .length ()==4 )
387+ return hexColorPattern .matcher (value ).matches ();
388+ }
389+ if ((value .startsWith ("rgb(" ) || value .startsWith ("rgba(" )) && value .indexOf (')' )==value .length ()-1 )
390+ {
391+ // rgba is an alias to rgb
392+ if (value .contains ("," ))
384393 {
385- try {
386- Integer .valueOf (value .substring (1 ,2 ),16 ).intValue ();
387- Integer .valueOf (value .substring (2 ,3 ),16 ).intValue ();
388- Integer .valueOf (value .substring (3 ,4 ),16 ).intValue ();
389- return true ;
390- }
391- catch (Exception e )
394+ // Legacy format rgba(r,g,b,a)
395+ String [] colorParts =value .substring (value .indexOf ("(" )+1 ,value .length ()-1 ).split ("," );
396+ if (colorParts .length !=3 &&colorParts .length !=4 )
397+ return false ;
398+ for (int i =0 ; i <3 ; i ++)
392399 {
400+ if (!(isPercentage (colorParts [i ].trim ()) || isInteger (colorParts [i ].trim ())))
401+ return false ;
393402 }
394-
395- }
396- else if (value .length ()==7 )
397- {
398-
399- try {
400- Integer .valueOf (value .substring (1 ,3 ),16 ).intValue ();
401- Integer .valueOf (value .substring (3 ,5 ),16 ).intValue ();
402- Integer .valueOf (value .substring (5 ,7 ),16 ).intValue ();
403+ if (colorParts .length <=3 || isNumber (colorParts [3 ]))
403404 return true ;
405+ }else {
406+ if (value .contains ("/" )){
407+ // Modern format rgba(r g b / a)
408+ String alphaPart =value .substring (value .indexOf ("/" )+1 ,value .length ()-1 ).trim ();
409+ if (!alphaPart .isEmpty () && !isPercentage (alphaPart ) && !isNumber (alphaPart ) && !alphaPart .equalsIgnoreCase ("none" ))
410+ return false ;
411+ value =value .substring (0 ,value .indexOf ("/" ))+")" ; // Strip alpha value, proceed to the following tests
412+ }
413+ // Modern format rgba(r g b)
414+ String [] colorParts =value .substring (value .indexOf ("(" )+1 ,value .length ()-1 ).split (" " );
415+ if (colorParts .length !=3 ) {
416+ return false ;
404417 }
405- catch ( Exception e )
418+ for ( int i = 0 ; i < 3 ; i ++ )
406419 {
420+ String trimmed = colorParts [i ].trim ();
421+ if (!(trimmed .equalsIgnoreCase ("none" ) || isPercentage (trimmed ) || (isInteger (trimmed ) && isIntegerInRange (trimmed , 0 , 255 ))))
422+ return false ;
407423 }
408- }
409- }
410- if (value .indexOf ("rgb(" )==0 && value .indexOf (')' )==value .length ()-1 )
411- {
412- String [] colorParts =value .substring (4 ,value .length ()-1 ).split ("," );
413- if (colorParts .length !=3 )
414- return false ;
415- boolean isValidColorParts =true ;
416- for (int i =0 ; i <colorParts .length && isValidColorParts ;i ++)
417- {
418- if (!(isPercentage (colorParts [i ].trim ()) || isInteger (colorParts [i ].trim ())))
419- isValidColorParts = false ;
420- }
421- if (isValidColorParts )
422424 return true ;
423- }
424- if (value .indexOf ("rgba(" )==0 && value .indexOf (')' )==value .length ()-1 )
425- {
426- String [] colorParts =value .substring (5 ,value .length ()-1 ).split ("," );
427- if (colorParts .length !=4 )
428- return false ;
429- boolean isValidColorParts =true ;
430- for (int i =0 ; i <colorParts .length -1 && isValidColorParts ;i ++)
431- {
432- if (!(isPercentage (colorParts [i ].trim ()) || isInteger (colorParts [i ].trim ())))
433- isValidColorParts = false ;
434425 }
435- if (isValidColorParts && isNumber (colorParts [3 ]))
436- return true ;
437426 }
438427
439428 if (value .indexOf ("hsl(" )==0 && value .indexOf (')' )==value .length ()-1 )
0 commit comments