// // $Id$ // From Philippe Le Hegaret (Philippe.Le_Hegaret@sophia.inria.fr) // // (c) COPYRIGHT MIT and INRIA, 1997. // Please first read the full copyright statement in file COPYRIGHT.html package org.w3c.css.values; import org.w3c.css.util.ApplContext; import org.w3c.css.util.CssVersion; import org.w3c.css.util.InvalidParamException; import java.util.Locale; import static org.w3c.css.values.CssOperator.COMMA; import static org.w3c.css.values.CssOperator.SPACE; /** * @version $Revision$ */ public class CssColor extends CssValue { public static final int type = CssTypes.CSS_COLOR; public final int getType() { return type; } Object color = null; // FIXME TODO, replace with one color type + one type for converted color for comparison RGB rgb = null; RGBA rgba = null; HSL hsl = null; HWB hwb = null; LAB lab = null; LCH lch = null; DeviceCMYK cmyk = null; boolean contains_variable = false; public boolean hasCssVariable() { return contains_variable; } public void markCssVariable() { contains_variable = true; } /** * Create a new CssColor. */ public CssColor() { } /** * Create a new CssColor with a color name. * * @param s The name color. * @throws InvalidParamException the color is incorrect */ public CssColor(ApplContext ac, String s) throws InvalidParamException { // setIdentColor(s.toLowerCase(), ac); setIdentColor(ac, s); } /** * Set the value from a defined color RBG. * * @param s the string representation of the color. * @throws InvalidParamException the color is incorrect. */ public void set(String s, ApplContext ac) throws InvalidParamException { if (s.charAt(0) == '#') { setShortRGBColor(ac, s.toLowerCase()); } else { setIdentColor(ac, s); } } /** * Return the internal value. */ public Object get() { if (color != null) { return color; } else { return rgb; } } /** * Returns a string representation of the object. */ public String toString() { if (color != null) { return color.toString(); } else if (rgb != null) { return rgb.toString(); } else if (rgba != null) { return rgba.toString(); } else if (hsl != null) { return hsl.toString(); } else if (hwb != null) { return hwb.toString(); } else if (lab != null) { return lab.toString(); } else if (lch != null) { return lch.toString(); } else if (cmyk != null) { return cmyk.toString(); } return "*invalid*"; } public void setRGBColor(ApplContext ac, CssExpression exp) throws InvalidParamException { boolean isCss3 = (ac.getCssVersion().compareTo(CssVersion.CSS3) >= 0); if (!isCss3) { setLegacyRGBColor(ac, exp); } else { setModernRGBColor(ac, exp); } } /** * Parse a RGB color. * format rgb(%?, %?, %?) */ public void setLegacyRGBColor(ApplContext ac, CssExpression exp) throws InvalidParamException { CssValue val = exp.getValue(); char op = exp.getOperator(); color = null; rgb = new RGB(); if (val == null || op != COMMA) { throw new InvalidParamException("invalid-color", ac); } switch (val.getType()) { case CssTypes.CSS_NUMBER: rgb.setPercent(false); rgb.setRed(ac, val); break; case CssTypes.CSS_PERCENTAGE: rgb.setPercent(true); rgb.setRed(ac, val); break; default: throw new InvalidParamException("rgb", val, ac); } exp.next(); val = exp.getValue(); op = exp.getOperator(); if (val == null || op != COMMA) { throw new InvalidParamException("invalid-color", ac); } switch (val.getType()) { case CssTypes.CSS_NUMBER: if (rgb.isPercent()) { throw new InvalidParamException("percent", val, ac); } rgb.setGreen(ac, val); break; case CssTypes.CSS_PERCENTAGE: if (!rgb.isPercent()) { throw new InvalidParamException("integer", val, ac); } rgb.setGreen(ac, val); break; default: throw new InvalidParamException("rgb", val, ac); } exp.next(); val = exp.getValue(); op = exp.getOperator(); if (val == null) { throw new InvalidParamException("invalid-color", ac); } switch (val.getType()) { case CssTypes.CSS_NUMBER: if (rgb.isPercent()) { throw new InvalidParamException("percent", val, ac); } rgb.setBlue(ac, val); break; case CssTypes.CSS_PERCENTAGE: if (!rgb.isPercent()) { throw new InvalidParamException("integer", val, ac); } rgb.setBlue(ac, val); break; default: throw new InvalidParamException("rgb", val, ac); } exp.next(); if (exp.getValue() != null) { throw new InvalidParamException("rgb", exp.getValue(), ac); } } /** * Parse a RGB color. * format rgb( {3} [ / ]? ) | * rgb( {3} [ / ]? ) */ public void setModernRGBColor(ApplContext ac, CssExpression exp) throws InvalidParamException { CssValue val; char op; color = null; rgba = new RGBA("rgb"); boolean separator_space = true; // check for variables if (exp.hasCssVariable()) { // don't check value then markCssVariable(); val = exp.getValue(); op = exp.getOperator(); separator_space = (op == SPACE); rgba.setModernStyle(separator_space); if (val == null || (!separator_space && (op != COMMA))) { // don't throw, perhaps a warning instead? FIXME // throw new InvalidParamException("invalid-color", ac); } rgba.vr = val; exp.next(); val = exp.getValue(); op = exp.getOperator(); if (val == null || (separator_space && (op != SPACE)) || (!separator_space && (op != COMMA))) { // don't throw, perhaps a warning instead? FIXME // throw new InvalidParamException("invalid-color", ac); } rgba.vg = val; exp.next(); val = exp.getValue(); op = exp.getOperator(); rgba.vb = val; exp.next(); if (!exp.end()) { // care for old syntax if (op == COMMA && !separator_space) { val = exp.getValue(); rgba.va = val; } else { // otherwise modern syntax if (op != SPACE) { // don't throw, perhaps a warning instead? FIXME // throw new InvalidParamException("invalid-color", ac); } // now we need an alpha. val = exp.getValue(); op = exp.getOperator(); if (val.getType() != CssTypes.CSS_SWITCH) { // don't throw, perhaps a warning instead? FIXME // throw new InvalidParamException("rgb", val, ac); } if (op != SPACE) { // don't throw, perhaps a warning instead? FIXME // throw new InvalidParamException("invalid-color", ac); } exp.next(); // now we get the alpha value if (exp.end()) { // don't throw, perhaps a warning instead? FIXME // throw new InvalidParamException("rgb", exp.getValue(), ac); } val = exp.getValue(); rgba.va = val; } exp.next(); } return; } val = exp.getValue(); op = exp.getOperator(); separator_space = (op == SPACE); rgba.setModernStyle(separator_space); if (val == null || (!separator_space && (op != COMMA))) { throw new InvalidParamException("invalid-color", ac); } switch (val.getType()) { case CssTypes.CSS_NUMBER: rgba.setPercent(false); rgba.setRed(ac, val); break; case CssTypes.CSS_PERCENTAGE: rgba.setPercent(true); rgba.setRed(ac, val); break; default: throw new InvalidParamException("rgb", val, ac); } exp.next(); val = exp.getValue(); op = exp.getOperator(); if (val == null || (separator_space && (op != SPACE)) || (!separator_space && (op != COMMA))) { throw new InvalidParamException("invalid-color", ac); } switch (val.getType()) { case CssTypes.CSS_NUMBER: if (rgba.isPercent()) { throw new InvalidParamException("percent", val, ac); } rgba.setGreen(ac, val); break; case CssTypes.CSS_PERCENTAGE: if (!rgba.isPercent()) { throw new InvalidParamException("integer", val, ac); } rgba.setGreen(ac, val); break; default: throw new InvalidParamException("rgb", val, ac); } exp.next(); val = exp.getValue(); op = exp.getOperator(); if (val == null) { throw new InvalidParamException("invalid-color", ac); } switch (val.getType()) { case CssTypes.CSS_NUMBER: if (rgba.isPercent()) { throw new InvalidParamException("percent", val, ac); } rgba.setBlue(ac, val); break; case CssTypes.CSS_PERCENTAGE: if (!rgba.isPercent()) { throw new InvalidParamException("integer", val, ac); } rgba.setBlue(ac, val); break; default: throw new InvalidParamException("rgb", val, ac); } exp.next(); // check for optional alpha channel if (!exp.end()) { // care for old syntax if (op == COMMA && !separator_space) { val = exp.getValue(); switch (val.getType()) { case CssTypes.CSS_NUMBER: case CssTypes.CSS_PERCENTAGE: rgba.setAlpha(ac, val); break; default: throw new InvalidParamException("rgb", val, ac); } } else { // otherwise modern syntax if (op != SPACE) { throw new InvalidParamException("invalid-color", ac); } // now we need an alpha. val = exp.getValue(); op = exp.getOperator(); if (val.getType() != CssTypes.CSS_SWITCH) { throw new InvalidParamException("rgb", val, ac); } if (op != SPACE) { throw new InvalidParamException("invalid-color", ac); } exp.next(); // now we get the alpha value if (exp.end()) { throw new InvalidParamException("rgb", exp.getValue(), ac); } val = exp.getValue(); switch (val.getType()) { case CssTypes.CSS_NUMBER: case CssTypes.CSS_PERCENTAGE: rgba.setAlpha(ac, val); break; default: throw new InvalidParamException("rgb", val, ac); } } exp.next(); if (!exp.end()) { throw new InvalidParamException("rgb", exp.getValue(), ac); } } } /** * Parse a HSL color. * format hsl( {3} [ / ]? ) | * hsl( {3} [ / ]? ) */ public void setHSLColor(ApplContext ac, CssExpression exp) throws InvalidParamException { // HSL defined in CSS3 and onward if (ac.getCssVersion().compareTo(CssVersion.CSS3) < 0) { StringBuilder sb = new StringBuilder(); sb.append("hsl(").append(exp.toStringFromStart()).append(')'); throw new InvalidParamException("notversion", sb.toString(), ac.getCssVersionString(), ac); } CssValue val = exp.getValue(); char op = exp.getOperator(); color = null; hsl = new HSL(); boolean separator_space = (op == SPACE); if (exp.hasCssVariable()) { markCssVariable(); } if (val == null || (!separator_space && (op != COMMA))) { if (!hasCssVariable()) { throw new InvalidParamException("invalid-color", ac); } } // H switch (val.getType()) { case CssTypes.CSS_ANGLE: case CssTypes.CSS_NUMBER: case CssTypes.CSS_VARIABLE: hsl.setHue(ac, val); break; default: if (!hasCssVariable()) { throw new InvalidParamException("colorfunc", val, "HSL", ac); } } exp.next(); val = exp.getValue(); op = exp.getOperator(); if (val == null || (separator_space && (op != SPACE)) || (!separator_space && (op != COMMA))) { if (!hasCssVariable()) { throw new InvalidParamException("invalid-color", ac); } } // S switch (val.getType()) { case CssTypes.CSS_PERCENTAGE: case CssTypes.CSS_VARIABLE: hsl.setSaturation(ac, val); break; default: exp.starts(); if (!hasCssVariable()) { throw new InvalidParamException("colorfunc", val, "HSL", ac); } } exp.next(); val = exp.getValue(); op = exp.getOperator(); if (val == null && !hasCssVariable()) { throw new InvalidParamException("invalid-color", ac); } // L switch (val.getType()) { case CssTypes.CSS_PERCENTAGE: case CssTypes.CSS_VARIABLE: hsl.setLightness(ac, val); break; default: exp.starts(); if (!hasCssVariable()) { throw new InvalidParamException("colorfunc", val, "HSL", ac); } } exp.next(); // check for optional alpha channel if (!exp.end()) { // care for old syntax if (op == COMMA && !separator_space) { val = exp.getValue(); switch (val.getType()) { case CssTypes.CSS_NUMBER: case CssTypes.CSS_PERCENTAGE: case CssTypes.CSS_VARIABLE: hsl.setAlpha(ac, val); break; default: exp.starts(); if (!hasCssVariable()) { throw new InvalidParamException("colorfunc", val, "HSL", ac); } } } else { // otherwise modern syntax if (op != SPACE && !hasCssVariable()) { throw new InvalidParamException("invalid-color", ac); } // now we need an alpha. val = exp.getValue(); op = exp.getOperator(); if (val.getType() != CssTypes.CSS_SWITCH && !hasCssVariable()) { throw new InvalidParamException("colorfunc", val, "HSL", ac); } if (op != SPACE && !hasCssVariable()) { throw new InvalidParamException("invalid-color", ac); } exp.next(); // now we get the alpha value if (exp.end() && !hasCssVariable()) { throw new InvalidParamException("colorfunc", exp.getValue(), "HSL", ac); } val = exp.getValue(); switch (val.getType()) { case CssTypes.CSS_NUMBER: case CssTypes.CSS_PERCENTAGE: case CssTypes.CSS_VARIABLE: hsl.setAlpha(ac, val); break; default: if (!hasCssVariable()) { throw new InvalidParamException("colorfunc", val, "HSL", ac); } } } exp.next(); if (!exp.end() && !hasCssVariable()) { throw new InvalidParamException("colorfunc", exp.getValue(), "HSL", ac); } } } /** * Parse a RGB color. * format #(3-6) */ public void setShortRGBColor(ApplContext ac, String s) throws InvalidParamException { int r; int g; int b; int a; int v; int idx; boolean islong; boolean hasAlpha = false; boolean isCss3; isCss3 = (ac.getCssVersion().compareTo(CssVersion.CSS3) >= 0); idx = 1; a = 0; switch (s.length()) { case 5: a = Character.digit(s.charAt(4), 16); if (!isCss3 || a < 0) { throw new InvalidParamException("rgb", s, ac); } hasAlpha = true; case 4: r = Character.digit(s.charAt(idx++), 16); g = Character.digit(s.charAt(idx++), 16); b = Character.digit(s.charAt(idx++), 16); if (r < 0 || g < 0 || b < 0) { throw new InvalidParamException("rgb", s, ac); } break; case 9: a = Character.digit(s.charAt(7), 16); v = Character.digit(s.charAt(8), 16); if (!isCss3 || a < 0 || v < 0) { throw new InvalidParamException("rgb", s, ac); } a = (a << 4) + v; hasAlpha = true; case 7: r = Character.digit(s.charAt(idx++), 16); v = Character.digit(s.charAt(idx++), 16); if (r < 0 || v < 0) { throw new InvalidParamException("rgb", s, ac); } r = (r << 4) + v; g = Character.digit(s.charAt(idx++), 16); v = Character.digit(s.charAt(idx++), 16); if (g < 0 || v < 0) { throw new InvalidParamException("rgb", s, ac); } g = (g << 4) + v; b = Character.digit(s.charAt(idx++), 16); v = Character.digit(s.charAt(idx++), 16); if (b < 0 || v < 0) { throw new InvalidParamException("rgb", s, ac); } b = (b << 4) + v; break; default: throw new InvalidParamException("rgb", s, ac); } color = null; if (hasAlpha) { rgba = new RGBA(isCss3, r, g, b, a); rgba.setRepresentationString(s); } else { rgb = new RGB(isCss3, r, g, b); // we force the specific display of it rgb.setRepresentationString(s); } } /** * Parse an ident color. */ protected void setIdentColor(ApplContext ac, String s) throws InvalidParamException { String lower_s = s.toLowerCase(Locale.ENGLISH); switch (ac.getCssVersion()) { case CSS1: rgb = CssColorCSS1.getRGB(lower_s); if (rgb == null) { throw new InvalidParamException("value", s, "color", ac); } color = lower_s; break; case CSS2: rgb = CssColorCSS2.getRGB(lower_s); if (rgb == null) { color = CssColorCSS2.getSystem(lower_s); if (color == null) { throw new InvalidParamException("value", s, "color", ac); } } else { color = lower_s; } break; case CSS21: rgb = CssColorCSS21.getRGB(lower_s); if (rgb == null) { color = CssColorCSS21.getSystem(lower_s); if (color == null) { throw new InvalidParamException("value", s, "color", ac); } } else { color = lower_s; } break; case CSS3: case CSS_2015: case CSS: // test RGB colors, RGBA colors (transparent), deprecated system colors rgb = CssColorCSS3.getRGB(lower_s); if (rgb != null) { color = lower_s; break; } rgba = CssColorCSS3.getRGBA(lower_s); if (rgba != null) { color = lower_s; break; } color = CssColorCSS3.getSystem(lower_s); if (color != null) { break; } color = CssColorCSS3.getDeprecatedSystem(lower_s); if (color != null) { ac.getFrame().addWarning("deprecated_replacement", s, color.toString()); color = s; break; } color = CssColorCSS3.getIdentColor(lower_s); if (color != null) { break; } // inherit or current color will be handled in the property def throw new InvalidParamException("value", s, "color", ac); default: throw new InvalidParamException("value", s, "color", ac); } } /** * Compares two values for equality. * * @param cssColor The other value. */ public boolean equals(Object cssColor) { if (!(cssColor instanceof CssColor)) { return false; } CssColor otherColor = (CssColor) cssColor; // FIXME we can have rgba(a,b,c,1) == rgb(a,b,c) if ((color != null) && (otherColor.color != null)) { return color.equals(otherColor.color); } else if ((rgb != null) && (otherColor.rgb != null)) { return rgb.equals(otherColor.rgb); } else if ((rgba != null) && (otherColor.rgba != null)) { return rgba.equals(otherColor.rgba); } else if ((hsl != null) && (otherColor.hsl != null)) { return hsl.equals(otherColor.hsl); } else if ((hwb != null) && (otherColor.hwb != null)) { return hwb.equals(otherColor.hwb); } else if ((lab != null) && (otherColor.lab != null)) { return lab.equals(otherColor.lab); } else if ((lch != null) && (otherColor.lch != null)) { return lch.equals(otherColor.lch); } else if ((cmyk != null) && (otherColor.cmyk != null)) { return cmyk.equals(otherColor.cmyk); } return false; } public void setATSCRGBAColor(ApplContext ac, CssExpression exp) throws InvalidParamException { rgba = new RGBA("atsc-rgba"); __setRGBAColor(ac, exp, rgba); } public void setRGBAColor(ApplContext ac, CssExpression exp) throws InvalidParamException { // RGBA defined in CSS3 and onward if (ac.getCssVersion().compareTo(CssVersion.CSS3) < 0) { StringBuilder sb = new StringBuilder(); sb.append("rgba(").append(exp.toStringFromStart()).append(')'); throw new InvalidParamException("notversion", sb.toString(), ac.getCssVersionString(), ac); } setModernRGBColor(ac, exp); } // use only for atsc profile, superseded by setModernRGBColor private void __setRGBAColor(ApplContext ac, CssExpression exp, RGBA rgba) throws InvalidParamException { CssValue val; char op; color = null; val = exp.getValue(); op = exp.getOperator(); if (val == null || op != COMMA) { throw new InvalidParamException("invalid-color", ac); } switch (val.getType()) { case CssTypes.CSS_NUMBER: rgba.setRed(ac, val); rgba.setPercent(false); break; case CssTypes.CSS_PERCENTAGE: rgba.setRed(ac, val); rgba.setPercent(true); break; default: throw new InvalidParamException("rgb", val, ac); // FIXME rgba } exp.next(); val = exp.getValue(); op = exp.getOperator(); if (val == null || op != COMMA) { throw new InvalidParamException("invalid-color", ac); } // green // and validate against the "percentageness" switch (val.getType()) { case CssTypes.CSS_NUMBER: if (rgba.isPercent()) { exp.starts(); throw new InvalidParamException("percent", val, ac); } rgba.setGreen(ac, val); break; case CssTypes.CSS_PERCENTAGE: if (!rgba.isPercent()) { exp.starts(); throw new InvalidParamException("integer", val, ac); } rgba.setGreen(ac, val); break; default: exp.starts(); throw new InvalidParamException("rgb", val, ac); // FIXME rgba } exp.next(); val = exp.getValue(); op = exp.getOperator(); if (val == null || op != COMMA) { exp.starts(); throw new InvalidParamException("invalid-color", ac); } // blue // and validate against the "percentageness" switch (val.getType()) { case CssTypes.CSS_NUMBER: if (rgba.isPercent()) { exp.starts(); throw new InvalidParamException("percent", val, ac); } rgba.setBlue(ac, val); break; case CssTypes.CSS_PERCENTAGE: if (!rgba.isPercent()) { exp.starts(); throw new InvalidParamException("integer", val, ac); } rgba.setBlue(ac, val); break; default: exp.starts(); throw new InvalidParamException("rgb", val, ac); // FIXME rgba } exp.next(); val = exp.getValue(); if (val == null) { exp.starts(); throw new InvalidParamException("invalid-color", ac); } switch (val.getType()) { case CssTypes.CSS_NUMBER: // starting with CSS Color 4 case CssTypes.CSS_PERCENTAGE: rgba.setAlpha(ac, val); break; default: exp.starts(); throw new InvalidParamException("rgb", val, ac); // FIXME rgba } exp.next(); if (exp.getValue() != null) { exp.starts(); throw new InvalidParamException("invalid-color", ac); } } public void setHWBColor(ApplContext ac, CssExpression exp) throws InvalidParamException { // HWB defined in CSSColor Level 4 and onward, currently used in the CSS level if (ac.getCssVersion().compareTo(CssVersion.CSS3) < 0) { StringBuilder sb = new StringBuilder(); sb.append("hwb(").append(exp.toStringFromStart()).append(')'); throw new InvalidParamException("notversion", sb.toString(), ac.getCssVersionString(), ac); } if (exp.hasCssVariable()) { markCssVariable(); } color = null; hwb = new HWB(); CssValue val = exp.getValue(); char op = exp.getOperator(); // H if ((val == null || op != SPACE) && !hasCssVariable()) { throw new InvalidParamException("invalid-color", ac); } switch (val.getType()) { case CssTypes.CSS_ANGLE: case CssTypes.CSS_NUMBER: case CssTypes.CSS_VARIABLE: hwb.setHue(ac, val); break; default: if (!hasCssVariable()) { throw new InvalidParamException("colorfunc", val, "HWB", ac); } } // W exp.next(); val = exp.getValue(); op = exp.getOperator(); if ((val == null || op != SPACE) && !hasCssVariable()) { exp.starts(); throw new InvalidParamException("invalid-color", ac); } switch (val.getType()) { case CssTypes.CSS_PERCENTAGE: case CssTypes.CSS_VARIABLE: hwb.setWhiteness(ac, val); break; default: if (!hasCssVariable()) { exp.starts(); throw new InvalidParamException("colorfunc", val, "HWB", ac); } } // B exp.next(); val = exp.getValue(); op = exp.getOperator(); if (val == null || (op != SPACE && exp.getRemainingCount() > 1)) { if (!hasCssVariable()) { exp.starts(); throw new InvalidParamException("invalid-color", ac); } } switch (val.getType()) { case CssTypes.CSS_PERCENTAGE: case CssTypes.CSS_VARIABLE: hwb.setBlackness(ac, val); break; default: if (!hasCssVariable()) { exp.starts(); throw new InvalidParamException("colorfunc", val, "HWB", ac); } } hwb.normalize(); // A exp.next(); if (!exp.end()) { if (op != SPACE && !hasCssVariable()) { throw new InvalidParamException("invalid-color", ac); } // now we need an alpha. val = exp.getValue(); op = exp.getOperator(); if ((val.getType() != CssTypes.CSS_SWITCH) && !hasCssVariable()) { throw new InvalidParamException("colorfunc", val, "HWB", ac); } if (op != SPACE && !hasCssVariable()) { throw new InvalidParamException("invalid-color", ac); } exp.next(); // now we get the alpha value val = exp.getValue(); if (val == null && !hasCssVariable()) { throw new InvalidParamException("invalid-color", exp.toStringFromStart(), ac); } switch (val.getType()) { case CssTypes.CSS_NUMBER: case CssTypes.CSS_PERCENTAGE: case CssTypes.CSS_VARIABLE: hwb.setAlpha(ac, val); break; default: if (!hasCssVariable()) { exp.starts(); throw new InvalidParamException("colorfunc", val, "HWB", ac); } } exp.next(); } // extra values? if (!exp.end()) { if (!hasCssVariable()) { exp.starts(); throw new InvalidParamException("colorfunc", exp.toStringFromStart(), "HWB", ac); } } } public void setLABColor(ApplContext ac, CssExpression exp) throws InvalidParamException { // HWB defined in CSSColor Level 4 and onward, currently used in the CSS level if (ac.getCssVersion().compareTo(CssVersion.CSS3) < 0) { StringBuilder sb = new StringBuilder(); sb.append("lab(").append(exp.toStringFromStart()).append(')'); throw new InvalidParamException("notversion", sb.toString(), ac.getCssVersionString(), ac); } if (exp.hasCssVariable()) { markCssVariable(); // we still parse variables as they will be ignored // we check the delimiter syntax, and other failures } color = null; lab = new LAB(); CssValue val = exp.getValue(); char op = exp.getOperator(); // L if ((val == null || op != SPACE) && !hasCssVariable()) { throw new InvalidParamException("colorfunc", exp, "Lab", ac); } switch (val.getType()) { case CssTypes.CSS_PERCENTAGE: case CssTypes.CSS_VARIABLE: lab.setL(ac, val); break; default: if (!hasCssVariable()) { throw new InvalidParamException("colorfunc", val, "Lab", ac); } } // A exp.next(); val = exp.getValue(); op = exp.getOperator(); if ((val == null || op != SPACE) && !hasCssVariable()) { exp.starts(); throw new InvalidParamException("invalid-color", ac); } switch (val.getType()) { case CssTypes.CSS_NUMBER: case CssTypes.CSS_VARIABLE: lab.setA(ac, val); break; default: if (!hasCssVariable()) { exp.starts(); throw new InvalidParamException("colorfunc", val, "Lab", ac); } } // B exp.next(); val = exp.getValue(); op = exp.getOperator(); if (val == null) { if (!hasCssVariable()) { exp.starts(); throw new InvalidParamException("colorfunc", exp, "Lab", ac); } } switch (val.getType()) { case CssTypes.CSS_NUMBER: case CssTypes.CSS_VARIABLE: lab.setB(ac, val); break; default: if (!hasCssVariable()) { exp.starts(); throw new InvalidParamException("colorfunc", val, "Lab", ac); } } exp.next(); if (!exp.end()) { if (op != SPACE && !hasCssVariable()) { throw new InvalidParamException("colorfunc", op, "Lab", ac); } // now we need an alpha. val = exp.getValue(); op = exp.getOperator(); if ((val.getType() != CssTypes.CSS_SWITCH) && !hasCssVariable()) { throw new InvalidParamException("colorfunc", val, "Lab", ac); } if (op != SPACE && !hasCssVariable()) { throw new InvalidParamException("colorfunc", val, "Lab", ac); } exp.next(); // now we get the alpha value val = exp.getValue(); if ((val == null) && !hasCssVariable()) { throw new InvalidParamException("colorfunc", exp.toStringFromStart(), "Lab", ac); } switch (val.getType()) { case CssTypes.CSS_NUMBER: case CssTypes.CSS_PERCENTAGE: case CssTypes.CSS_VARIABLE: lab.setAlpha(ac, val); break; default: if (!hasCssVariable()) { exp.starts(); throw new InvalidParamException("colorfunc", val, "Lab", ac); } } exp.next(); } // extra values? if (!exp.end()) { exp.starts(); if (!hasCssVariable()) { throw new InvalidParamException("colorfunc", exp.toStringFromStart(), "Lab", ac); } } } public void setLCHColor(ApplContext ac, CssExpression exp) throws InvalidParamException { // HWB defined in CSSColor Level 4 and onward, currently used in the CSS level if (ac.getCssVersion().compareTo(CssVersion.CSS3) < 0) { StringBuilder sb = new StringBuilder(); sb.append("lch(").append(exp.toStringFromStart()).append(')'); throw new InvalidParamException("notversion", sb.toString(), ac.getCssVersionString(), ac); } if (exp.hasCssVariable()) { markCssVariable(); } color = null; lch = new LCH(); CssValue val = exp.getValue(); char op = exp.getOperator(); // L if ((val == null || op != SPACE) && !hasCssVariable()) { throw new InvalidParamException("invalid-color", ac); } switch (val.getType()) { case CssTypes.CSS_PERCENTAGE: case CssTypes.CSS_VARIABLE: lch.setL(ac, val); break; default: if (!hasCssVariable()) { throw new InvalidParamException("colorfunc", val, "LCH", ac); } } // A exp.next(); val = exp.getValue(); op = exp.getOperator(); if ((val == null || op != SPACE) && !hasCssVariable()) { exp.starts(); throw new InvalidParamException("invalid-color", ac); } switch (val.getType()) { case CssTypes.CSS_NUMBER: case CssTypes.CSS_VARIABLE: lch.setC(ac, val); break; default: if (!hasCssVariable()) { exp.starts(); throw new InvalidParamException("colorfunc", val, "LCH", ac); } } // B exp.next(); val = exp.getValue(); op = exp.getOperator(); if ((val == null) && !hasCssVariable()) { throw new InvalidParamException("colorfunc", exp.toStringFromStart(), "LCH", ac); } switch (val.getType()) { case CssTypes.CSS_NUMBER: case CssTypes.CSS_ANGLE: case CssTypes.CSS_VARIABLE: lch.setH(ac, val); break; default: if (!hasCssVariable()) { exp.starts(); throw new InvalidParamException("colorfunc", val, "LCH", ac); } } exp.next(); if (!exp.end()) { if ((op != SPACE) && !hasCssVariable()) { throw new InvalidParamException("invalid-color", ac); } // now we need an alpha. val = exp.getValue(); op = exp.getOperator(); if ((val.getType() != CssTypes.CSS_SWITCH) && !hasCssVariable()) { throw new InvalidParamException("colorfunc", val, "LCH", ac); } if ((op != SPACE) && !hasCssVariable()) { throw new InvalidParamException("invalid-color", ac); } exp.next(); // now we get the alpha value val = exp.getValue(); if (val == null) { throw new InvalidParamException("colorfunc", exp.toStringFromStart(), "LCH", ac); } switch (val.getType()) { case CssTypes.CSS_NUMBER: case CssTypes.CSS_PERCENTAGE: case CssTypes.CSS_VARIABLE: lch.setAlpha(ac, val); break; default: if (!hasCssVariable()) { exp.starts(); throw new InvalidParamException("colorfunc", val, "LCH", ac); } } exp.next(); } // extra values? if (!exp.end()) { if (!hasCssVariable()) { exp.starts(); throw new InvalidParamException("colorfunc", exp.toStringFromStart(), "LCH", ac); } } } public void setDeviceCMYKColor(ApplContext ac, CssExpression exp) throws InvalidParamException { // HWB defined in CSSColor Level 4 and onward, currently used in the CSS level if (ac.getCssVersion().compareTo(CssVersion.CSS3) < 0) { StringBuilder sb = new StringBuilder(); sb.append("device-cmyk(").append(exp.toStringFromStart()).append(')'); throw new InvalidParamException("notversion", sb.toString(), ac.getCssVersionString(), ac); } color = null; cmyk = new DeviceCMYK(); CssValue val = exp.getValue(); char op = exp.getOperator(); boolean gotFallback = false; if (exp.hasCssVariable()) { markCssVariable(); } // C if ((val == null || op != SPACE) && !hasCssVariable()) { throw new InvalidParamException("invalid-color", ac); } switch (val.getType()) { case CssTypes.CSS_NUMBER: case CssTypes.CSS_PERCENTAGE: case CssTypes.CSS_VARIABLE: cmyk.setC(ac, val); break; default: if (!hasCssVariable()) { throw new InvalidParamException("colorfunc", val, "device-cmyk", ac); } } // M exp.next(); val = exp.getValue(); op = exp.getOperator(); if ((val == null || op != SPACE) && !hasCssVariable()) { exp.starts(); throw new InvalidParamException("invalid-color", ac); } switch (val.getType()) { case CssTypes.CSS_NUMBER: case CssTypes.CSS_PERCENTAGE: case CssTypes.CSS_VARIABLE: cmyk.setM(ac, val); break; default: if (!hasCssVariable()) { exp.starts(); throw new InvalidParamException("colorfunc", val, "device-cmyk", ac); } } // Y exp.next(); val = exp.getValue(); op = exp.getOperator(); if ((val == null) && !hasCssVariable()) { throw new InvalidParamException("colorfunc", exp.toStringFromStart(), "device-cmyk", ac); } switch (val.getType()) { case CssTypes.CSS_NUMBER: case CssTypes.CSS_PERCENTAGE: case CssTypes.CSS_VARIABLE: cmyk.setY(ac, val); break; default: if (!hasCssVariable()) { exp.starts(); throw new InvalidParamException("colorfunc", val, "device-cmyk", ac); } } // K exp.next(); val = exp.getValue(); op = exp.getOperator(); if ((val == null) && !hasCssVariable()) { throw new InvalidParamException("colorfunc", exp.toStringFromStart(), "device-cmyk", ac); } switch (val.getType()) { case CssTypes.CSS_NUMBER: case CssTypes.CSS_PERCENTAGE: case CssTypes.CSS_VARIABLE: cmyk.setK(ac, val); break; default: if (!hasCssVariable()) { exp.starts(); throw new InvalidParamException("colorfunc", val, "device-cmyk", ac); } } exp.next(); if (!exp.end()) { if ((op == SPACE) && !hasCssVariable()) { // now we need an alpha. val = exp.getValue(); op = exp.getOperator(); if ((val.getType() != CssTypes.CSS_SWITCH) && !hasCssVariable()) { throw new InvalidParamException("rgb", val, ac); } if ((op != SPACE) && !hasCssVariable()) { throw new InvalidParamException("invalid-color", ac); } exp.next(); // now we get the alpha value val = exp.getValue(); if ((val == null) && !hasCssVariable()) { throw new InvalidParamException("invalid-color", exp.toStringFromStart(), ac); } switch (val.getType()) { case CssTypes.CSS_NUMBER: case CssTypes.CSS_PERCENTAGE: case CssTypes.CSS_VARIABLE: cmyk.setAlpha(ac, val); break; default: if (!hasCssVariable()) { exp.starts(); throw new InvalidParamException("colorfunc", val, "device-cmyk", ac); } } // need to check if we get a comma after this. op = exp.getOperator(); exp.next(); } if (op == COMMA) { //the optional fallback if (exp.end() && !hasCssVariable()) { throw new InvalidParamException("colorfunc", exp.toStringFromStart(), "device-cmyk", ac); } val = exp.getValue(); cmyk.setFallbackColor(ac, val); exp.next(); } } // extra values? if (!exp.end() && !hasCssVariable()) { exp.starts(); throw new InvalidParamException("colorfunc", exp.toStringFromStart(), "device-cmyk", ac); } } }