2002/css-validator/org/w3c/css/properties/css3 CssBackground.java,NONE,1.1 CssBackgroundAttachment.java,NONE,1.1 CssBackgroundClip.java,1.3,1.4 CssBackgroundColor.java,NONE,1.1 CssBackgroundImage.java,NONE,1.1 CssBackgroundOrigin.java,1.3,1.4 CssBackgroundPosition.java,NONE,1.1 CssBackgroundRepeat.java,NONE,1.1 CssBackgroundSize.java,1.3,1.4 CssColor.java,NONE,1.1 Css3Style.java,1.12,1.13

Update of /sources/public/2002/css-validator/org/w3c/css/properties/css3
In directory hutz:/tmp/cvs-serv17942/org/w3c/css/properties/css3

Modified Files:
	Css3Style.java 
Added Files:
	CssBackground.java CssBackgroundAttachment.java 
	CssBackgroundClip.java CssBackgroundColor.java 
	CssBackgroundImage.java CssBackgroundOrigin.java 
	CssBackgroundPosition.java CssBackgroundRepeat.java 
	CssBackgroundSize.java CssColor.java 
Log Message:
some reordering to have only one background-color to check in checkConflicts (like what was done for CssColors

Index: Css3Style.java
===================================================================
RCS file: /sources/public/2002/css-validator/org/w3c/css/properties/css3/Css3Style.java,v
retrieving revision 1.12
retrieving revision 1.13
diff -u -d -r1.12 -r1.13
--- Css3Style.java	27 Sep 2011 08:15:46 -0000	1.12
+++ Css3Style.java	4 Oct 2011 13:05:25 -0000	1.13
@@ -112,8 +112,6 @@
     public CssBackgroundClip cssBackgroundClip;
     public CssBackgroundSize cssBackgroundSize;
     public CssBackgroundOrigin cssBackgroundOrigin;
-    CssBackgroundQuantity cssBackgroundQuantity;
-    CssBackgroundSpacing cssBackgroundSpacing;
     CssTextDecorationCSS3 cssTextDecoration;
     CssWhiteSpaceCSS3 cssWhiteSpace;
     CssWordSpacingCSS3 cssWordSpacing;
@@ -1001,24 +999,6 @@
 	return cssBackgroundOrigin;
     }
 
-    public CssBackgroundQuantity getCssBackgroundQuantity() {
-	if (cssBackgroundQuantity == null) {
-	    cssBackgroundQuantity =
-		(CssBackgroundQuantity) style.CascadingOrder(
-							     new CssBackgroundQuantity(), style, selector);
-	}
-	return cssBackgroundQuantity;
-    }
-
-    public CssBackgroundSpacing getCssBackgroundSpacing() {
-	if (cssBackgroundSpacing == null) {
-	    cssBackgroundSpacing =
-		(CssBackgroundSpacing) style.CascadingOrder(
-							    new CssBackgroundSpacing(), style, selector);
-	}
-	return cssBackgroundSpacing;
-    }
-
     public CssTextDecorationCSS3 getCssTextDecoration() {
 	if (cssTextDecoration == null) {
 	    cssTextDecoration =

--- NEW FILE: CssBackgroundRepeat.java ---
// $Id: CssBackgroundRepeat.java,v 1.1 2011/10/04 13:05:25 ylafon Exp $
// @author Yves Lafon <ylafon@w3.org>
//
// (c) COPYRIGHT MIT, ERCIM and Keio, 2010.
// Please first read the full copyright statement in file COPYRIGHT.html
package org.w3c.css.properties.css3;

import org.w3c.css.properties.css.CssProperty;
import org.w3c.css.util.ApplContext;
import org.w3c.css.util.InvalidParamException;
import org.w3c.css.values.CssExpression;
import org.w3c.css.values.CssIdent;
import org.w3c.css.values.CssTypes;
import org.w3c.css.values.CssValue;
import org.w3c.css.values.CssValueList;

import java.util.ArrayList;
import java.util.HashMap;

import static org.w3c.css.values.CssOperator.COMMA;
import static org.w3c.css.values.CssOperator.SPACE;

/**
 * http://www.w3.org/TR/2009/CR-css3-background-20091217/#the-background-repeat
 * <p/>
 * Name: 	background-repeat
 * Value: 	&lt;repeat-style&gt; [ , &lt;repeat-style&gt; ]*
 * Initial: 	repeat
 * Applies to: 	all elements
 * Inherited: 	no
 * Percentages: 	N/A
 * Media: 	visual
 * Computed value: 	as specified
 * <p/>
 * Specifies how background images are tiled after they have been sized and
 * positioned. Where
 * <p/>
 * &lt;repeat-style&gt; = repeat-x | repeat-y | [repeat | space |
 * round | no-repeat]{1,2}
 */
public class CssBackgroundRepeat extends org.w3c.css.properties.css.CssBackgroundRepeat {

    public final static CssIdent repeat;
    private static HashMap<String, CssIdent> allowed_simple_values;
    private static HashMap<String, CssIdent> allowed_double_values;

    static {
        allowed_simple_values = new HashMap<String, CssIdent>();
        allowed_double_values = new HashMap<String, CssIdent>();
        String[] REPEAT = {"repeat", "space", "round", "no-repeat"};

        allowed_simple_values.put("repeat-x", CssIdent.getIdent("repeat-x"));
        allowed_simple_values.put("repeat-y", CssIdent.getIdent("repeat-y"));

        for (String aREPEAT : REPEAT) {
            allowed_double_values.put(aREPEAT, CssIdent.getIdent(aREPEAT));
        }
        repeat = CssIdent.getIdent("repeat");
    }

    public static boolean isMatchingIdent(CssIdent ident) {
        String id = ident.toString();

        return (allowed_simple_values.containsKey(id) ||
                allowed_double_values.containsKey(id));
    }

    public Object value;

    /**
     * Create a new CssBackgroundRepeat
     */
    public CssBackgroundRepeat() {
        value = repeat;
    }

    /**
     * Set the value of the property
     *
     * @param ac         the context
     * @param expression The expression for this property
     * @param check      is length checking needed
     * @throws org.w3c.css.util.InvalidParamException The expression is incorrect
     */
    public CssBackgroundRepeat(ApplContext ac, CssExpression expression,
                               boolean check) throws InvalidParamException {

        ArrayList<CssValue> values = new ArrayList<CssValue>();
        boolean is_complete = true;
        CssValue val;
        CssValueList vl = null;
        char op;

        setByUser();

        while (!expression.end()) {
            val = expression.getValue();
            op = expression.getOperator();

            // not an ident? fail
            if (val.getType() != CssTypes.CSS_IDENT) {
                throw new InvalidParamException("value", expression.getValue(),
                        getPropertyName(), ac);
            }

            CssIdent id_val = (CssIdent) val;
            if (inherit.equals(id_val)) {
                // if we got inherit after other values, fail
                // if we got more than one value... fail
                if ((values.size() > 0) || (expression.getCount() > 1)) {
                    throw new InvalidParamException("value", val,
                            getPropertyName(), ac);
                }
                values.add(inherit);
            } else {
                String id_value = id_val.toString();
                CssIdent new_val;
                // check values that must be alone
                new_val = allowed_simple_values.get(id_value);
                if (new_val != null) {
                    // if we already have a double value... it's an error
                    if (!is_complete) {
                        throw new InvalidParamException("value",
                                val, getPropertyName(), ac);
                    }
                    values.add(new_val);
                    is_complete = true;
                } else {
                    // the the one that may come in pairs
                    new_val = allowed_double_values.get(id_value);
                    // not an allowed value !
                    if (new_val == null) {
                        throw new InvalidParamException("value",
                                val, getPropertyName(), ac);
                    }
                    if (is_complete) {
                        vl = new CssValueList();
                        vl.add(new_val);
                    } else {
                        vl.add(new_val);
                        values.add(vl);
                    }
                    is_complete = !is_complete;
                }
            }

            expression.next();
            if (!expression.end()) {
                // incomplete value followed by a comma... it's complete!
                if (!is_complete && (op == COMMA)) {
                    values.add(vl);
                    is_complete = true;
                }
                // complete values are separated by a comma, otherwise space
                if ((is_complete && (op != COMMA)) ||
                        (!is_complete && (op != SPACE))) {
                    throw new InvalidParamException("operator",
                            ((new Character(op)).toString()), ac);
                }
            }
        }
        // if we reach the end in a value that can come in pair
        if (!is_complete) {
            values.add(vl);
        }
        if (values.size() == 1) {
            value = values.get(0);
        } else {
            value = values;
        }
    }


    public CssBackgroundRepeat(ApplContext ac, CssExpression expression)
            throws InvalidParamException {
        this(ac, expression, false);
    }

    /**
     * Returns the value of this property
     */

    public Object get() {
        return value;
    }

    public void set(Object val) {
        value = val;
    }

    /**
     * Returns true if this property is "softly" inherited
     * e.g. his value equals inherit
     */
    public boolean isSoftlyInherited() {
        return (inherit == value);
    }

    /**
     * Returns a string representation of the object.
     */
    public String toString() {
        if (value instanceof ArrayList) {
            ArrayList values = (ArrayList) value;
            StringBuilder sb = new StringBuilder();
            for (Object aValue : values) {
                sb.append(aValue.toString()).append(", ");
            }
            sb.setLength(sb.length() - 2);
            return sb.toString();
        }
        return value.toString();
    }

    /**
     * Compares two properties for equality.
     *
     * @param property The other property.
     */
    public boolean equals(CssProperty property) {
        return (property instanceof CssBackgroundRepeat &&
                value == ((CssBackgroundRepeat) property).value);
    }

    /**
     * Is the value of this property is a default value.
     * It is used by all macro for the function <code>print</code>
     */
    public boolean isDefault() {
        return (repeat == value);
    }

}




--- NEW FILE: CssBackgroundColor.java ---
// $Id: CssBackgroundColor.java,v 1.1 2011/10/04 13:05:25 ylafon Exp $
// From Philippe Le Hegaret (Philippe.Le_Hegaret@sophia.inria.fr)
// Rewritten 2010 Yves Lafon <ylafon@w3.org>
//
// (c) COPYRIGHT MIT, ERCIM and Keio, 1997-2010.
// Please first read the full copyright statement in file COPYRIGHT.html

package org.w3c.css.properties.css3;

import org.w3c.css.properties.css.CssProperty;
import org.w3c.css.util.ApplContext;
import org.w3c.css.util.InvalidParamException;
import org.w3c.css.values.CssExpression;
import org.w3c.css.values.CssValue;

/**
 * http://www.w3.org/TR/2009/CR-css3-background-20091217/#the-background-color
 *
 * Name: 	background-color
 * Value: 	&lt;color&gt;
 * Initial: 	transparent
 * Applies to: 	all elements
 * Inherited: 	no
 * Percentages: 	N/A
 * Media: 	visual
 * Computed value: 	the computed color(s)
 *
 * This property sets the background color of an element. The color is drawn
 * behind any background images.
 */
public class CssBackgroundColor extends org.w3c.css.properties.css.CssBackgroundColor {

    CssValue color;

    /**
     * Create a new CssBackgroundColor
     */
    public CssBackgroundColor() {
    }

    /**
     * Create a new CssBackgroundColor
     *
     * @param expression The expression for this property
     * @throws org.w3c.css.util.InvalidParamException Values are incorrect
     */
    public CssBackgroundColor(ApplContext ac, CssExpression expression,
                              boolean check) throws InvalidParamException {

        setByUser();
        CssValue val = expression.getValue();

        if (check && expression.getCount() > 1) {
            throw new InvalidParamException("unrecognize", ac);
        }

        if (inherit.equals(val)) {
            color = inherit;
            expression.next();
        } else {
            try {
                // we use the latest version of CssColor, aka CSS3
                // instead of using CSS21 colors + transparent per spec.
                CssColor tcolor = new CssColor(ac, expression, check);
                color = tcolor.getColor();
            } catch (InvalidParamException e) {
                throw new InvalidParamException("value",
                        expression.getValue(),
                        getPropertyName(), ac);
            }
        }
    }

    public CssBackgroundColor(ApplContext ac, CssExpression expression)
            throws InvalidParamException {
        this(ac, expression, false);
    }

    /**
     * Returns the value of this property
     */
    public Object get() {
        return color;
    }


    public void set(CssValue col) {
        color = col;
    }
    /**
     * Returns the color
     */
    public CssValue getColor() {
        return color;
    }

    /**
     * Returns true if this property is "softly" inherited
     * e.g. his value equals inherit
     */
    public boolean isSoftlyInherited() {
        return color.equals(inherit);
    }

    /**
     * Returns a string representation of the object.
     */
    public String toString() {
        return color.toString();
    }


    /**
     * Compares two properties for equality.
     *
     * @param property The other property.
     */
    public boolean equals(CssProperty property) {
        return (property instanceof CssBackgroundColor &&
                color.equals(((CssBackgroundColor) property).color));
    }

    /**
     * Is the value of this property is a default value.
     * It is used by all macro for the function <code>print</code>
     */
    public boolean isDefault() {
        return (color == transparent);
    }

}

--- NEW FILE: CssBackgroundAttachment.java ---
// $Id: CssBackgroundAttachment.java,v 1.1 2011/10/04 13:05:25 ylafon Exp $
// @author Yves Lafon <ylafon@w3.org>

// (c) COPYRIGHT MIT, ERCIM and Keio, 2010.
// Please first read the full copyright statement in file COPYRIGHT.html

package org.w3c.css.properties.css3;

import org.w3c.css.properties.css.CssProperty;
import org.w3c.css.util.ApplContext;
import org.w3c.css.util.InvalidParamException;
import org.w3c.css.values.CssExpression;
import org.w3c.css.values.CssIdent;
import org.w3c.css.values.CssTypes;
import org.w3c.css.values.CssValue;

import java.util.ArrayList;
import java.util.HashMap;

import static org.w3c.css.values.CssOperator.COMMA;

/**
 * http://www.w3.org/TR/2009/CR-css3-background-20091217/#the-background-attachment
 * Name: 	background-attachment
 * Value: 	&lt;attachment&gt; [ , &lt;attachment&gt; ]*
 * Initial: 	scroll
 * Applies to: 	all elements
 * Inherited: 	no
 * Percentages: 	N/A
 * Media: 	visual
 * Computed value: 	as specified
 *
 * If background images are specified, this property specifies whether they
 * are fixed with regard to the viewport ('fixed') or scroll along with the
 * element ('scroll') or its contents ('local'). The property's value is given
 *  as a comma-separated list of &lt;attachment&gt; keywords where
 *
 * &lt;attachment&gt; = scroll | fixed | local
 */
public class CssBackgroundAttachment extends org.w3c.css.properties.css.CssBackgroundAttachment {

    private static HashMap<String, CssIdent> allowed_values;
    public static CssIdent scroll;

    static {
        allowed_values = new HashMap<String, CssIdent>();
        scroll = CssIdent.getIdent("scroll");
        allowed_values.put("scroll", scroll);
        allowed_values.put("fixed", CssIdent.getIdent("fixed"));
        allowed_values.put("local", CssIdent.getIdent("local"));
    }

    public static boolean isMatchingIdent(CssIdent ident) {
        return allowed_values.containsKey(ident.toString());
    }

    Object value;

    /**
     * Create a new CssBackgroundAttachment
     */
    public CssBackgroundAttachment() {
        value = scroll;
    }

    public void set(Object val) {
        value = val;
    }

    /**
     * Creates a new CssBackgroundAttachment
     *
     * @param ac the context
     * @param expression The expression for this property
     * @param check if some length checking is required
     * @throws org.w3c.css.util.InvalidParamException Values are incorrect
     */
    public CssBackgroundAttachment(ApplContext ac, CssExpression expression,
                                   boolean check) throws InvalidParamException {

        ArrayList<CssValue> values = new ArrayList<CssValue>();
        char op;
        CssValue val;

        setByUser();

        while (!expression.end()) {
            val = expression.getValue();
            op = expression.getOperator();
            if (val.getType() != CssTypes.CSS_IDENT) {
                throw new InvalidParamException("value", val,
                        getPropertyName(), ac);
            }
            if (inherit.equals(val)) {
                // if we got inherit after other values, fail
                // if we got more than one value... fail
                if ((values.size() > 0) || (expression.getCount() > 1)) {
                    throw new InvalidParamException("value", val,
                            getPropertyName(), ac);
                }
                values.add(inherit);
            } else {
                // check that it's in the allowed values
                CssValue new_val = allowed_values.get(val.toString());
                if (new_val == null) {
                    throw new InvalidParamException("value", val,
                            getPropertyName(), ac);
                }
                values.add(new_val);
            }
            expression.next();
            // and check that values are separated by commas
            if (!expression.end() && (op != COMMA)) {
                throw new InvalidParamException("operator",
                        ((new Character(op)).toString()), ac);
            }
        }

        if (values.size() == 1) {
            value = values.get(0);
        } else {
            value = values;
        }
    }

    public CssBackgroundAttachment(ApplContext ac, CssExpression expression)
            throws InvalidParamException {
        this(ac, expression, false);
    }

    /**
     * Returns the value of this property
     */
    public Object get() {
        return value;
    }

    /**
     * Returns true if this property is "softly" inherited
     * e.g. his value equals inherit
     */
    public boolean isSoftlyInherited() {
        return (inherit == value);
    }

    /**
     * Returns a string representation of the object.
     */
    public String toString() {
        if (value instanceof ArrayList) {
            ArrayList values = (ArrayList) value;
            StringBuilder sb = new StringBuilder();
            for (Object aValue : values) {
                sb.append(aValue.toString()).append(", ");
            }
            sb.setLength(sb.length() - 2);
            return sb.toString();
        }
        return value.toString();
    }

    /**
     * Compares two properties for equality.
     *
     * @param property The other property.
     */
    public boolean equals(CssProperty property) {
        return (property instanceof CssBackgroundAttachment &&
                value.equals(((CssBackgroundAttachment) property).value));
    }

    /**
     * Is the value of this property is a default value.
     * It is used by all macro for the function <code>print</code>
     */
    public boolean isDefault() {
        return (scroll == value);
    }
}

--- NEW FILE: CssBackground.java ---
// $Id: CssBackground.java,v 1.1 2011/10/04 13:05:25 ylafon Exp $
// From Philippe Le Hegaret (Philippe.Le_Hegaret@sophia.inria.fr)
// Rewritten 2010 Yves Lafon <ylafon@w3.org>

// (c) COPYRIGHT MIT, ERCIM and Keio, 1997-2010.
// Please first read the full copyright statement in file COPYRIGHT.html
package org.w3c.css.properties.css3;

import org.w3c.css.parser.CssSelectors;
import org.w3c.css.parser.CssStyle;
import org.w3c.css.properties.css.CssProperty;
import org.w3c.css.properties.css1.Css1Style;
import org.w3c.css.util.ApplContext;
import org.w3c.css.util.InvalidParamException;
import org.w3c.css.values.CssColor;
import org.w3c.css.values.CssExpression;
import org.w3c.css.values.CssIdent;
import org.w3c.css.values.CssTypes;
import org.w3c.css.values.CssValue;
import org.w3c.css.values.CssValueList;

import java.util.ArrayList;

import static org.w3c.css.values.CssOperator.COMMA;
import static org.w3c.css.values.CssOperator.SLASH;
import static org.w3c.css.values.CssOperator.SPACE;

/**
 * http://www.w3.org/TR/2009/CR-css3-background-20091217/#the-background
 * <p/>
 * Name: 	background
 * Value: 	[ &lt;bg-layer&gt; , ]* &lt;final-bg-layer&gt;
 * Initial: 	see individual properties
 * Applies to: 	all elements
 * Inherited: 	no
 * Percentages: 	see individual properties
 * Media: 	visual
 * Computed value: 	see individual properties
 * <p/>
 * Where
 * <p/>
 * &lt;bg-layer&gt; = &lt;bg-image&gt; || &lt;bg-position&gt; ||
 * / &lt;bg-size&gt; || &lt;repeat-style&gt; || &lt;attachment&gt; ||
 * &lt;bg-origin&gt;
 * <p/>
 * where ‘&lt;bg-position&gt;’ must occur before ‘/ &lt;bg-size&gt;’ if both
 * are present.
 * <p/>
 * &lt;final-bg-layer&gt; = &lt;bg-image&gt; || &lt;bg-position&gt; ||
 * / &lt;bg-size&gt; || &lt;repeat-style&gt; || &lt;attachment&gt; ||
 * &lt;bg-origin&gt; || &lt;'background-color'&gt;
 * <p/>
 * where ‘&lt;bg-position&gt;’ must not occur before ‘/ &lt;bg-size&gt;’ if
 * both are present.
 * <p/>
 * Note that a color is permitted in &lt;final-bg-layer&gt;, but
 * not in &lt;bg-layer&gt;.
 *
 * @see org.w3c.css.properties.css.CssBackgroundColor
 * @see org.w3c.css.properties.css.CssBackgroundImage
 * @see org.w3c.css.properties.css.CssBackgroundRepeat
 * @see org.w3c.css.properties.css.CssBackgroundAttachment
 * @see org.w3c.css.properties.css.CssBackgroundPosition
 * @see org.w3c.css.properties.css.CssBackgroundSize
 */
public class CssBackground extends org.w3c.css.properties.css.CssBackground {

    Object value;

    public CssColor _color;

    // TODO get rid of those or reformat them
    public CssBackgroundColor color;

    public CssBackgroundImage image;
    public CssBackgroundRepeat repeat;
    public CssBackgroundAttachment attachment;
    public CssBackgroundPosition position;
    public CssBackgroundSize size;

    public boolean same;

    /**
     * Create a new CssBackground
     */
    public CssBackground() {
    }

    /**
     * Set the value of the property<br/>
     * Does not check the number of values
     *
     * @param expression The expression for this property
     * @throws org.w3c.css.util.InvalidParamException The expression is incorrect
     */
    public CssBackground(ApplContext ac, CssExpression expression)
            throws InvalidParamException {
        this(ac, expression, false);
    }

    /**
     * Set the value of the property
     *
     * @param expression The expression for this property
     * @param check      set it to true to check the number of values
     * @throws org.w3c.css.util.InvalidParamException The expression is incorrect
     */
    public CssBackground(ApplContext ac, CssExpression expression,
                         boolean check) throws InvalidParamException {

        setByUser();
        CssValue val;
        ArrayList<CssBackgroundValue> values;
        CssExpression single_layer = null;
        CssBackgroundValue b_val = null;
        char op;

        values = new ArrayList<CssBackgroundValue>();
        // we just accumulate values and check at validation
        while (!expression.end()) {
            val = expression.getValue();
            op = expression.getOperator();

            if (inherit.equals(val)) {
                if (expression.getCount() > 1) {
                    throw new InvalidParamException("value", val,
                            getPropertyName(), ac);
                }
                value = inherit;
                expression.next();
                return;
            }
            if (single_layer == null) {
                single_layer = new CssExpression();
            }
            // we will check later
            single_layer.addValue(val);
            single_layer.setOperator(op);
            expression.next();

            if (!expression.end()) {
                // incomplete value followed by a comma... it's complete!
                if (op == COMMA) {
                    single_layer.setOperator(SPACE);
                    b_val = check(ac, single_layer, check, false);
                    values.add(b_val);
                    single_layer = null;
                } else if ((op != SPACE) && (op != SLASH)) {
                    throw new InvalidParamException("operator",
                            ((new Character(op)).toString()), ac);
                }
            }
        }
        // if we reach the end in a value that can come in pair
        if (single_layer != null) {
            b_val = check(ac, single_layer, check, true);
            values.add(b_val);
        }
        if (values.size() == 1) {
            value = values.get(0);
        } else {
            value = values;
        }
        transform_into_individual_values();
    }

    private Object getCssBackgroundRepeatValue(ApplContext ac,
                                               CssExpression expression,
                                               boolean check)
            throws InvalidParamException {
        char op = expression.getOperator();
        CssExpression exp = new CssExpression();

        exp.addValue(expression.getValue());
        CssBackgroundRepeat bg_size;
        repeat = new CssBackgroundRepeat(ac, exp, check);
        // now check if we can add a second value ;)
        if ((op == SPACE) && !expression.end()) {
            expression.next();
            if (!expression.end()) {
                CssValue val = expression.getValue();
                if ((val.getType() == CssTypes.CSS_IDENT) &&
                        (CssBackgroundRepeat.isMatchingIdent((CssIdent) val))) {
                    exp.addValue(expression.getValue());
                    exp.starts();
                    try {
                        repeat = new CssBackgroundRepeat(ac, exp, check);
                    } catch (InvalidParamException ipe) {
                        expression.precedent();
                    }
                } else {
                    expression.precedent();
                }
            }
        }
        return repeat.get();
    }

    private Object getCssBackgroundSizeValue(ApplContext ac,
                                             CssExpression expression,
                                             boolean check)
            throws InvalidParamException {
        char op = expression.getOperator();
        CssExpression exp = new CssExpression();

        exp.addValue(expression.getValue());
        CssBackgroundSize bg_size;
        bg_size = new CssBackgroundSize(ac, exp, check);
        // now check if we can add a second value ;)
        // TODO really dirty.. must check the use of 'check'
        // here, and possibly adjust the parsing model in
        // other classes :(
        if ((op == SPACE) && !expression.end()) {
            expression.next();
            if (!expression.end()) {
                exp.addValue(expression.getValue());
                exp.starts();
                try {
                    bg_size = new CssBackgroundSize(ac, exp, check);
                } catch (InvalidParamException ipe) {
                    // roll back
                    expression.precedent();
                }
            }
        }
        return bg_size.get();
    }


    private Object getCssBackgroundPositionValue(ApplContext ac,
                                                 CssExpression expression,
                                                 boolean check)
            throws InvalidParamException {
        CssExpression exp = new CssExpression();
        char op = expression.getOperator();
        exp.addValue(expression.getValue());
        int last_val = -1;

        CssBackgroundPosition bg_pos;
        bg_pos = new CssBackgroundPosition(ac, exp, check);
        // good we have a valid value, try something better..
        expression.mark();
        // we MUST try all the cases, as we can have something
        // invalid using 3 values (incompatible definitions)
        // but valid using 4 values...
        // example top 12% is invalid, top 12% center is valid...
        for (int i = 0; i < 3; i++) {
            if ((op == SPACE) && !expression.end()) {
                expression.next();
                if (expression.end()) {
                    break;
                }
                exp.addValue(expression.getValue());
                exp.starts();
                try {
                    bg_pos = new CssBackgroundPosition(ac, exp, check);
                    last_val = i;
                } catch (InvalidParamException ipe) {
                }

            }
        }
        expression.reset();
        while (last_val >= 0) {
            expression.next();
            last_val--;
        }
        return bg_pos.get();
    }


    public CssBackgroundValue check(ApplContext ac, CssExpression expression,
                                    boolean check, boolean is_final)
            throws InvalidParamException {
        // <bg-layer> = <bg-image> || <bg-position> || / <bg-size> || <repeat-style> ||
        //              <attachment> || <bg-origin>
        // bg_image is CSS_URL | IDENT
        // bg-position is IDENT | NUMBER | LENGTH | PERCENTAGE
        // bg-size is IDENT | NUMBER | LENGTH | PERCENTAGE
        // repeat-style is IDENT
        // attachment is IDENT
        // bg-origin is IDENT
        // + color as CSS_COLOR or IDENT on final-layer

        CssValue val;
        char op;
        CssExpression exp;
        CssBackgroundValue v = new CssBackgroundValue();
        boolean next_is_size, got_size;
        Object res;

        next_is_size = false;
        got_size = false;
        while (!expression.end()) {
            val = expression.getValue();
            op = expression.getOperator();

            switch (val.getType()) {
                case CssTypes.CSS_COLOR:
                    // we already got one, fail...
                    if (v.color != null || next_is_size || !is_final) {
                        throw new InvalidParamException("value", val,
                                getPropertyName(), ac);
                    }
                    exp = new CssExpression();
                    exp.addValue(val);

                    CssBackgroundColor bg_color;
                    bg_color = new CssBackgroundColor(ac, exp, check);
                    v.color = (CssValue) bg_color.get();
                    break;

                case CssTypes.CSS_URL:
                    // we already got one, fail...
                    if (v.bg_image != null || next_is_size) {
                        throw new InvalidParamException("value", val,
                                getPropertyName(), ac);
                    }
                    exp = new CssExpression();
                    exp.addValue(val);

                    CssBackgroundImage bg_image;
                    bg_image = new CssBackgroundImage(ac, exp, check);
                    res = bg_image.get();
                    // we only have one vale so it should always be the case
                    if (res instanceof CssValue) {
                        v.bg_image = (CssValue) res;
                    } else {
                        throw new InvalidParamException("value", val,
                                getPropertyName(), ac);
                    }
                    break;
                case CssTypes.CSS_NUMBER:
                case CssTypes.CSS_LENGTH:
                case CssTypes.CSS_PERCENTAGE:
                    // ok, so now we have a background position or size.
                    // and...
                    // in <bg_layer>: where '<bg-position>' must occur before
                    //  '/ <bg-size>' if both are present.
                    if (next_is_size) {
                        // size, we have up to two values
                        if (v.bg_size != null) {
                            throw new InvalidParamException("value", val,
                                    getPropertyName(), ac);
                        }
                        res = getCssBackgroundSizeValue(ac, expression, check);
                        op = expression.getOperator();
                        // we only have one vale so it should always be the case
                        if (res instanceof CssValue) {
                            v.bg_size = (CssValue) res;
                        } else {
                            throw new InvalidParamException("value", val,
                                    getPropertyName(), ac);
                        }
                        got_size = true;
                        next_is_size = false;
                    } else {
                        // position with it's up to 4 values...
                        if (got_size) {
                            throw new InvalidParamException("bg_order", val,
                                    getPropertyName(), ac);
                        }
                        if (v.bg_position != null) {
                            throw new InvalidParamException("value", val,
                                    getPropertyName(), ac);
                        }
                        res = getCssBackgroundPositionValue(ac, expression, check);
                        op = expression.getOperator();
                        // we only have one vale so it should always be the case
                        if (res instanceof CssValue) {
                            v.bg_position = (CssValue) res;
                        } else {
                            throw new InvalidParamException("value", val,
                                    getPropertyName(), ac);
                        }

                    }
                    break;
                case CssTypes.CSS_IDENT:
                    // inherit is already taken care of...
                    CssIdent ident_val = (CssIdent) val;
                    if (CssBackgroundAttachment.isMatchingIdent(ident_val)) {
                        if (v.attachment != null || next_is_size) {
                            throw new InvalidParamException("value", val,
                                    getPropertyName(), ac);
                        }
                        exp = new CssExpression();
                        exp.addValue(val);

                        CssBackgroundAttachment attachment;
                        attachment = new CssBackgroundAttachment(ac, exp, check);
                        res = attachment.get();
                        // we only have one vale so it should always be the case
                        if (res instanceof CssValue) {
                            v.attachment = (CssValue) res;
                        } else {
                            throw new InvalidParamException("value", val,
                                    getPropertyName(), ac);
                        }
                        break;
                    }
                    if (CssBackgroundImage.isMatchingIdent(ident_val)) {
                        if (v.bg_image != null || next_is_size) {
                            throw new InvalidParamException("value", val,
                                    getPropertyName(), ac);
                        }
                        // a bit of an overkill, as we know it can be only
                        // 'none'.. but it is more flexible if ever it changes
                        exp = new CssExpression();
                        exp.addValue(val);

                        bg_image = new CssBackgroundImage(ac, exp, check);
                        res = bg_image.get();
                        // we only have one vale so it should always be the case
                        if (res instanceof CssValue) {
                            v.bg_image = (CssValue) res;
                        } else {
                            throw new InvalidParamException("value", val,
                                    getPropertyName(), ac);
                        }
                        break;
                    }
                    if (CssBackgroundOrigin.isMatchingIdent(ident_val)) {
                        if (v.origin != null || next_is_size) {
                            throw new InvalidParamException("value", val,
                                    getPropertyName(), ac);
                        }
                        exp = new CssExpression();
                        exp.addValue(val);

                        CssBackgroundOrigin origin;
                        origin = new CssBackgroundOrigin(ac, exp, check);
                        res = origin.get();
                        // we only have one vale so it should always be the case
                        if (res instanceof CssValue) {
                            v.origin = (CssValue) res;
                        } else {
                            throw new InvalidParamException("value", val,
                                    getPropertyName(), ac);
                        }
                        break;
                    }
                    if (CssBackgroundRepeat.isMatchingIdent(ident_val)) {
                        if (v.repeat_style != null || next_is_size) {
                            throw new InvalidParamException("value", val,
                                    getPropertyName(), ac);
                        }
                        res = getCssBackgroundRepeatValue(ac, expression, check);
                        op = expression.getOperator();

                        // we only have one vale so it should always be the case
                        if (res instanceof CssValue) {
                            v.repeat_style = (CssValue) res;
                        } else {
                            throw new InvalidParamException("value", val,
                                    getPropertyName(), ac);
                        }
                        break;
                    }
                    if (next_is_size) {
                        if (CssBackgroundSize.isMatchingIdent(ident_val)) {
                            // size, we have up to two values
                            if (v.bg_size != null) {
                                throw new InvalidParamException("value", val,
                                        getPropertyName(), ac);
                            }
                            res = getCssBackgroundSizeValue(ac, expression, check);
                            op = expression.getOperator();
                            // we only have one vale so it should always be the case
                            if (res instanceof CssValue) {
                                v.bg_size = (CssValue) res;
                            } else {
                                throw new InvalidParamException("value", val,
                                        getPropertyName(), ac);
                            }
                            got_size = true;
                            next_is_size = false;
                            break;
                        }
                    } else {
                        if (CssBackgroundPosition.isMatchingIdent(ident_val)) {
                            // position with it's up to 4 values...
                            if (got_size) {
                                throw new InvalidParamException("bg_order",
                                        val, getPropertyName(), ac);
                            }
                            if (v.bg_position != null) {
                                throw new InvalidParamException("value", val,
                                        getPropertyName(), ac);
                            }
                            res = getCssBackgroundPositionValue(ac, expression, check);
                            op = expression.getOperator();
                            // we only have one vale so it should always be the case
                            if (res instanceof CssValue) {
                                v.bg_position = (CssValue) res;
                            } else {
                                throw new InvalidParamException("value", val,
                                        getPropertyName(), ac);
                            }
                            break;
                        }
                    }
                    // last one remaining... color!
                    // or else, it will fail :)
                    if (is_final) {
                        if (v.color != null || next_is_size) {
                            throw new InvalidParamException("value", val,
                                    getPropertyName(), ac);
                        }
                        exp = new CssExpression();
                        exp.addValue(val);
                        bg_color = new CssBackgroundColor(ac, exp, check);
                        v.color = (CssValue) bg_color.get();
                        break;
                    }
                    // unrecognized or unwanted ident
                    // let it fail now
                default:
                    throw new InvalidParamException("value", val,
                            getPropertyName(), ac);
            }

            if (op == SLASH) {
                next_is_size = true;
            } else if (op != SPACE) {
                throw new InvalidParamException("operator", val,
                        getPropertyName(), ac);
            }
            expression.next();
        }
        align_bg_values(v);
        return v;
    }

    private void align_bg_values(CssBackgroundValue v) {
        // <bg-layer> = <bg-image> || <bg-position> || / <bg-size> || <repeat-style> ||
        //              <attachment> || <bg-origin>
        Object value;
        if (v.bg_image == null) {
            value = (new CssBackgroundImage()).get();
            if (value instanceof CssValue) {
                v.bg_image_value = (CssValue) value;
            }
        } else {
            v.bg_image_value = v.bg_image;
        }

        if (v.bg_position == null) {
            value = (new CssBackgroundPosition()).get();
            if (value instanceof CssValue) {
                v.bg_position_value = (CssValue) value;
            }
        } else {
            v.bg_position_value = v.bg_position;
        }

        if (v.bg_size == null) {
            value = (new CssBackgroundSize()).get();
            if (value instanceof CssValue) {
                v.bg_size_value = (CssValue) value;
            }
        } else {
            v.bg_size_value = v.bg_size;
        }

        if (v.repeat_style == null) {
            value = (new CssBackgroundRepeat()).get();
            if (value instanceof CssValue) {
                v.repeat_style_value = (CssValue) value;
            }
        } else {
            v.repeat_style_value = v.repeat_style;
        }

        if (v.attachment == null) {
            value = (new CssBackgroundAttachment()).get();
            if (value instanceof CssValue) {
                v.attachment_value = (CssValue) value;
            }
        } else {
            v.attachment_value = v.attachment;
        }

        if (v.origin == null) {
            value = (new CssBackgroundOrigin()).get();
            if (value instanceof CssValue) {
                CssValue css_val = (CssValue) value;
                v.origin_value = (CssValue) value;
                // If 'background-origin' is present and its value matches a
                // possible value for 'background-clip' then it also sets
                //  'background-clip' to that value.
                if ((css_val.getType() == CssTypes.CSS_IDENT) &&
                        CssBackgroundClip.isMatchingIdent((CssIdent) css_val)) {
                    v.clip_value = v.origin_value;
                }
            }
        } else {
            v.origin_value = v.origin;
        }

        if (v.color == null) {
            v.color_value = (new CssBackgroundColor()).getColor();
        } else {
            v.color_value = v.color;
        }
    }

    /**
     * Transform the compound value into the equivalent individual
     * values (used for conflict check, like color and background-color
     * Note that the value verification already took place, so no need
     * for extra check
     */
    private void transform_into_individual_values() {
        if (value instanceof CssBackgroundValue) {
            CssBackgroundValue v = (CssBackgroundValue) value;
            if (v.color != null) {
                color = new CssBackgroundColor();
                color.set(v.color_value);
            }
            if (v.bg_image != null) {
                image = new CssBackgroundImage();
                image.set(v.bg_image_value);
            }
            if (v.repeat_style != null) {
                repeat = new CssBackgroundRepeat();
                repeat.set(v.repeat_style_value);
            }
            if (v.attachment != null) {
                attachment = new CssBackgroundAttachment();
                attachment.set(v.attachment_value);
            }
            if (v.bg_position != null) {
                position = new CssBackgroundPosition();
                position.set(v.bg_position_value);
            }
            if (v.bg_size != null) {
                size = new CssBackgroundSize();
                size.set(v.bg_size_value);
            }
        } else if (value instanceof ArrayList) {
            ArrayList vlist = (ArrayList) value;
            int len = vlist.size();
            ArrayList<CssValue> images = new ArrayList<CssValue>(len);
            ArrayList<CssValue> repeats = new ArrayList<CssValue>(len);
            ArrayList<CssValue> positions = new ArrayList<CssValue>(len);
            ArrayList<CssValue> attachments = new ArrayList<CssValue>(len);
            ArrayList<CssValue> sizes = new ArrayList<CssValue>(len);

            for (int i = 0; i < len; i++) {
                CssBackgroundValue v = (CssBackgroundValue) vlist.get(i);
                images.add(v.bg_image_value);
                repeats.add(v.repeat_style_value);
                positions.add(v.bg_position_value);
                attachments.add(v.attachment_value);
                sizes.add(v.bg_size_value);
                if (v.color != null) {
                    color = new CssBackgroundColor();
                    color.set(v.color_value);
                }
            }
            image = new CssBackgroundImage();
            image.set(images);

            repeat = new CssBackgroundRepeat();
            repeat.set(repeats);

            attachment = new CssBackgroundAttachment();
            attachment.set(attachments);

            position = new CssBackgroundPosition();
            position.set(sizes);

            size = new CssBackgroundSize();
            size.set(sizes);
        } else {
            // FIXME TODO use inherit?
            image = null;
            repeat = null;
            attachment = null;
            color = null;
            size = null;
            position = null;
        }
    }

    /**
     * @return Returns the image.
     */

    public CssBackgroundImage getImage() {
        return image;
    }

    /**
     * Returns the value of this property
     */
    public Object get() {
        return color;
    }

    /**
     * Returns the color
     */
    public CssValue getColor() {
        if (color == null) {
            return null;
        } else {
            return color.getColor();
        }
    }

    /**
     * Returns a string representation of the object.
     */
    public String toString() {
        if (value instanceof ArrayList) {
            ArrayList v_list;
            v_list = (ArrayList) value;
            StringBuilder sb = new StringBuilder();
            for (Object val : v_list) {
                sb.append(val.toString()).append(", ");
            }
            sb.setLength(sb.length() - 2);
            return sb.toString();
        }
        return value.toString();
    }

    /**
     * Set this property to be important.
     * Overrides this method for a macro
     */
    public void setImportant() {
        super.setImportant();
        if (color != null) {
            color.important = true;
        }
        if (image != null) {
            image.important = true;
        }
        if (repeat != null) {
            repeat.important = true;
        }
        if (attachment != null) {
            attachment.important = true;
        }
        if (position != null) {
            position.important = true;
        }
        if (size != null) {
            size.important = true;
        }
    }

    /**
     * Set the context.
     * Overrides this method for a macro
     *
     * @see org.w3c.css.css.CssCascadingOrder#order
     * @see org.w3c.css.css.StyleSheetParser#handleRule
     */
    public void setSelectors(CssSelectors selector) {
        super.setSelectors(selector);
        if (color != null) {
            color.setSelectors(selector);
        }
        if (image != null) {
            image.setSelectors(selector);
        }
        if (repeat != null) {
            repeat.setSelectors(selector);
        }
        if (attachment != null) {
            attachment.setSelectors(selector);
        }
        if (position != null) {
            position.setSelectors(selector);
        }
        if (size != null) {
            size.setSelectors(selector);
        }
    }

    /**
     * Add this property to the CssStyle
     *
     * @param style The CssStyle
     */
    public void addToStyle(ApplContext ac, CssStyle style) {
        ((Css1Style) style).cssBackground.same = same;
        ((Css1Style) style).cssBackground.byUser = byUser;

        if (color != null) {
            color.addToStyle(ac, style);
        }
        if (image != null) {
            image.addToStyle(ac, style);
        }
        if (repeat != null) {
            repeat.addToStyle(ac, style);
        }
        if (attachment != null) {
            attachment.addToStyle(ac, style);
        }
        if (position != null) {
            position.addToStyle(ac, style);
        }
        if (size != null) {
            size.addToStyle(ac, style);
        }
    }

    /**
     * Get this property in the style.
     *
     * @param style   The style where the property is
     * @param resolve if true, resolve the style to find this property
     */
    public CssProperty getPropertyInStyle(CssStyle style, boolean resolve) {
        if (resolve) {
            return ((Css1Style) style).getBackground();
        } else {
            return ((Css1Style) style).cssBackground;
        }
    }

    /**
     * Compares two properties for equality.
     *
     * @param property The other property.
     */
    public boolean equals(CssProperty property) {
        return false; // FIXME
    }

    /**
     * Update the source file and the line.
     * Overrides this method for a macro
     *
     * @param line   The line number where this property is defined
     * @param source The source file where this property is defined
     */
    public void setInfo(int line, String source) {
        super.setInfo(line, source);
        if (color != null) {
            color.setInfo(line, source);
        }
        if (image != null) {
            image.setInfo(line, source);
        }
        if (repeat != null) {
            repeat.setInfo(line, source);
        }
        if (attachment != null) {
            attachment.setInfo(line, source);
        }
        if (position != null) {
            position.setInfo(line, source);
        }
        if (size != null) {
            size.setInfo(line, source);
        }
    }

// placeholder for the different values

    public class CssBackgroundValue extends CssValueList {

        CssValue bg_image = null;
        CssValue bg_position = null;
        CssValue bg_size = null;
        CssValue repeat_style = null;
        CssValue attachment = null;
        CssValue origin = null;
        CssValue color = null;

        CssValue bg_image_value = null;
        CssValue bg_position_value = null;
        CssValue bg_size_value = null;
        CssValue repeat_style_value = null;
        CssValue attachment_value = null;
        CssValue origin_value = null;
        // If 'background-origin' is present and its value matches a possible
        // value for 'background-clip' then it also sets 'background-clip' to
        // that value.
        CssValue clip_value = null;
        CssValue color_value = null;

        public boolean equals(CssBackgroundValue v) {
            if (bg_image_value == null) {
                if (v.bg_image_value != null) {
                    return false;
                }
            } else if (!bg_image_value.equals(v.bg_image_value)) {
                return false;
            }
            if (bg_position_value == null) {
                if (v.bg_position_value != null) {
                    return false;
                }
            } else if (!bg_position_value.equals(v.bg_position_value)) {
                return false;
            }
            if (bg_size_value == null) {
                if (v.bg_size_value != null) {
                    return false;
                }
            } else if (!bg_size_value.equals(v.bg_size_value)) {
                return false;
            }
            if (repeat_style_value == null) {
                if (v.repeat_style_value != null) {
                    return false;
                }
            } else if (!repeat_style_value.equals(v.repeat_style_value)) {
                return false;
            }
            if (attachment_value == null) {
                if (v.attachment_value != null) {
                    return false;
                }
            } else if (!attachment_value.equals(v.attachment_value)) {
                return false;
            }
            if (origin_value == null) {
                if (v.origin_value != null) {
                    return false;
                }
            } else if (!origin_value.equals(v.origin_value)) {
                return false;
            }
            if (clip_value == null) {
                if (v.clip_value != null) {
                    return false;
                }
            } else if (!clip_value.equals(v.clip_value)) {
                return false;
            }
            if (color_value == null) {
                if (v.color_value != null) {
                    return false;
                }
            } else if (!color_value.equals(v.color_value)) {
                return false;
            }
            // at last!
            return true;
        }

        public String toString() {
            StringBuilder sb = new StringBuilder();
            if (bg_image != null) {
                sb.append(bg_image).append(' ');
            }
            if (bg_position != null) {
                sb.append(bg_position).append(' ');
            }
            if (bg_size != null) {
                sb.append('/').append(bg_size).append(' ');
            }
            if (repeat_style != null) {
                sb.append(repeat_style).append(' ');
            }
            if (attachment != null) {
                sb.append(attachment).append(' ');
            }
            if (origin != null) {
                sb.append(origin).append(' ');
            }
            if (color != null) {
                sb.append(color);
            } else {
                int sb_length = sb.length();
                if (sb_length > 0) {
                    sb.setLength(sb_length - 1);
                }
            }
            return sb.toString();
        }
    }
}

--- NEW FILE: CssBackgroundPosition.java ---
// $Id: CssBackgroundPosition.java,v 1.1 2011/10/04 13:05:25 ylafon Exp $
// From Philippe Le Hegaret (Philippe.Le_Hegaret@sophia.inria.fr)
// Rewritten by Yves Lafon <ylafon@w3.org>

// (c) COPYRIGHT MIT, Keio and ERCIM, 1997-2010.
// Please first read the full copyright statement in file COPYRIGHT.html

package org.w3c.css.properties.css3;

import org.w3c.css.parser.CssStyle;
import org.w3c.css.properties.css.CssBackground;
import org.w3c.css.properties.css.CssProperty;
import org.w3c.css.properties.css1.Css1Style;
import org.w3c.css.util.ApplContext;
import org.w3c.css.util.InvalidParamException;
import org.w3c.css.values.CssExpression;
import org.w3c.css.values.CssIdent;
import org.w3c.css.values.CssNumber;
import org.w3c.css.values.CssPercentage;
import org.w3c.css.values.CssTypes;
import org.w3c.css.values.CssValue;
import org.w3c.css.values.CssValueList;

import java.util.ArrayList;
import java.util.HashMap;

import static org.w3c.css.values.CssOperator.COMMA;
import static org.w3c.css.values.CssOperator.SPACE;

/**
 * http://www.w3.org/TR/2009/CR-css3-background-20091217/#background-position
 * <p/>
 * Name: 	background-position
 * Value: 	&lt;bg-position&gt; [ , &lt;bg-position&gt; ]*
 * Initial: 	0% 0%
 * Applies to: 	all elements
 * Inherited: 	no
 * Percentages: 	refer to size of background positioning area minus size of
 * background image; see text
 * Media: 	visual
 * Computed value: 	If one or two values are specified, for a &lt;length&gt;
 * the absolute value, otherwise a percentage. If three or
 * four values are specified, two pairs of a keyword plus a
 * length or percentage.
 * <p/>
 * <p/>
 * If background images have been specified, this property specifies their
 * initial position (after any resizing) within their corresponding
 * background positioning area.
 * <p/>
 * Where
 * <p/>
 * &lt;bg-position&gt; = [
 * [ [ &lt;percentage&gt; | &lt;length&gt; | left | center | right ] ]
 * [ [ &lt;percentage&gt; | &lt;length&gt; | top | center | bottom ] ]?
 * |
 * [ center | [ left | right ] [ &lt;percentage&gt; | &lt;length&gt; ]? ] ||
 * [ center | [ top | bottom ] [ &lt;percentage&gt; | &lt;length&gt; ]? ]
 * ]
 */
public class CssBackgroundPosition extends org.w3c.css.properties.css.CssBackgroundPosition {

    private static HashMap<String, CssIdent> allowed_values;
    private static final CssIdent center, top, bottom, left, right;
    private static final CssPercentage defaultPercent0, defaultPercent50;
    private static final CssPercentage defaultPercent100;

    static {
        top = CssIdent.getIdent("top");
        bottom = CssIdent.getIdent("bottom");
        left = CssIdent.getIdent("left");
        right = CssIdent.getIdent("right");
        center = CssIdent.getIdent("center");
        allowed_values = new HashMap<String, CssIdent>();
        allowed_values.put("top", top);
        allowed_values.put("bottom", bottom);
        allowed_values.put("left", left);
        allowed_values.put("right", right);
        allowed_values.put("center", center);

        defaultPercent0 = new CssPercentage(0);
        defaultPercent50 = new CssPercentage(50);
        defaultPercent100 = new CssPercentage(100);
    }

    public static boolean isMatchingIdent(CssIdent ident) {
        return allowed_values.containsKey(ident.toString());
    }

    Object value;

    /**
     * Create a new CssBackgroundPosition
     */
    public CssBackgroundPosition() {
        value = new CssBackgroundPositionValue();
    }

    /**
     * Creates a new CssBackgroundPosition
     *
     * @param expression The expression for this property
     * @throws org.w3c.css.util.InvalidParamException Values are incorrect
     */
    public CssBackgroundPosition(ApplContext ac, CssExpression expression,
                                 boolean check) throws InvalidParamException {
        setByUser();
        CssValue val;
        ArrayList<CssBackgroundPositionValue> values;
        CssBackgroundPositionValue b_val = null;
        char op;

        values = new ArrayList<CssBackgroundPositionValue>();
        // we just accumulate values and check at validation
        while (!expression.end()) {
            val = expression.getValue();
            op = expression.getOperator();

            if (inherit.equals(val)) {
                if (expression.getCount() > 1) {
                    throw new InvalidParamException("value", val,
                            getPropertyName(), ac);
                }
                value = inherit;
                expression.next();
                return;
            }
            if (b_val == null) {
                b_val = new CssBackgroundPositionValue();
            }
            // we will check later
            b_val.add(val);
            expression.next();

            if (!expression.end()) {
                // incomplete value followed by a comma... it's complete!
                if (op == COMMA) {
                    check(b_val, ac);
                    values.add(b_val);
                    b_val = null;
                } else if (op != SPACE) {
                    throw new InvalidParamException("operator",
                            ((new Character(op)).toString()), ac);
                }
            }
        }
        // if we reach the end in a value that can come in pair
        if (b_val != null) {
            check(b_val, ac);
            values.add(b_val);
        }
        if (values.size() == 1) {
            value = values.get(0);
        } else {
            value = values;
        }
    }

    public CssBackgroundPosition(ApplContext ac, CssExpression expression)
            throws InvalidParamException {
        this(ac, expression, false);
    }


    /**
     * Returns the value of this property
     */
    public Object get() {
        return value;
    }

    public void set(Object val) {
        value = val;
    }

    /**
     * Returns true if this property is "softly" inherited
     * e.g. his value equals inherit
     */
    public boolean isSoftlyInherited() {
        return (inherit == value);
    }

    /**
     * Returns a string representation of the object.
     */
    public String toString() {
        if (value instanceof ArrayList) {
            ArrayList v_list;
            v_list = (ArrayList) value;
            StringBuilder sb = new StringBuilder();
            for (Object val : v_list) {
                sb.append(val.toString()).append(", ");
            }
            sb.setLength(sb.length() - 2);
            return sb.toString();
        }
        return value.toString();
    }

    /**
     * Add this property to the CssStyle.
     *
     * @param style The CssStyle
     */
    public void addToStyle(ApplContext ac, CssStyle style) {
        CssBackground cssBackground = ((Css1Style) style).cssBackground;
        if (cssBackground.position != null)
            style.addRedefinitionWarning(ac, this);
        cssBackground.position = this;
    }

    /**
     * Get this property in the style.
     *
     * @param style   The style where the property is
     * @param resolve if true, resolve the style to find this property
     */
    public CssProperty getPropertyInStyle(CssStyle style, boolean resolve) {
        if (resolve) {
            return ((Css1Style) style).getBackgroundPosition();
        } else {
            return ((Css1Style) style).cssBackground.position;
        }
    }

    /**
     * Compares two properties for equality.
     *
     * @param property The other property.
     */
    public boolean equals(CssProperty property) {
        return ((property != null) &&
                (property instanceof CssBackgroundPosition) &&
                (value.equals(((CssBackgroundPosition) property).value)));
    }

    /**
     * Is the value of this property is a default value.
     * It is used by all macro for the function <code>print</code>
     */
    public boolean isDefault() {
        if (!(value instanceof CssBackgroundPositionValue)) {
            return false;
        }
        CssBackgroundPositionValue v = (CssBackgroundPositionValue) value;
        return ((v.val_vertical == defaultPercent0) &&
                (v.val_horizontal == defaultPercent0) &&
                (v.vertical_offset == null) &&
                (v.horizontal_offset == null));
    }

    public void check(CssBackgroundPositionValue v, ApplContext ac)
            throws InvalidParamException {
        int nb_keyword = 0;
        int nb_percentage = 0;
        int nb_length = 0;
        int nb_values = v.value.size();

        if (nb_values > 4) {
            throw new InvalidParamException("unrecognize", ac);
        }
        // basic check
        for (CssValue aValue : v.value) {
            switch (aValue.getType()) {
                case CssTypes.CSS_NUMBER:
                    aValue = ((CssNumber) aValue).getLength();
                case CssTypes.CSS_LENGTH:
                    nb_length++;
                    break;
                case CssTypes.CSS_PERCENTAGE:
                    nb_percentage++;
                    break;
                case CssTypes.CSS_IDENT:
                    nb_keyword++;
                    break;
                default:
                    throw new InvalidParamException("unrecognize", aValue,
                            ac);
            }
        }
        if ((nb_keyword > 2) || (nb_length > 2) || (nb_percentage > 2)) {
            throw new InvalidParamException("unrecognize", ac);
        }
        // this is unnecessary complex, blame it on the CSS3 spec.
        switch (nb_keyword) {
            case 0:
                // no keyword, so it's easy, it depends on the number
                // of values :)
                switch (nb_values) {
                    case 1:
                        // If only one value is specified, the second value
                        // is assumed to be 'center'.
                        v.horizontal = v.value.get(0);
                        if (v.horizontal.getType() == CssTypes.CSS_NUMBER) {
                            v.horizontal = defaultPercent0;
                        }
                        v.val_horizontal = v.horizontal;
                        v.val_vertical = defaultPercent50;
                        break;
                    case 2:
                        v.horizontal = v.value.get(0);
                        if (v.horizontal.getType() == CssTypes.CSS_NUMBER) {
                            v.horizontal = defaultPercent0;
                        }
                        v.val_horizontal = v.horizontal;
                        v.vertical = v.value.get(1);
                        if (v.vertical.getType() == CssTypes.CSS_NUMBER) {
                            v.vertical = defaultPercent0;
                        }
                        v.val_vertical = v.vertical;
                        break;
                    default:
                        // If three or four values are given, then each
                        // <percentage> or<length> represents an offset and
                        // must be preceded by a keyword
                        throw new InvalidParamException("unrecognize",
                                ac);

                }
                break;
            // we got one keyword... let's have fun...
            case 1:
                switch (nb_values) {
                    case 1:
                        CssIdent ident = (CssIdent) v.value.get(0);
                        // ugly as we need to set values for equality tests
                        v.val_vertical = defaultPercent50;
                        v.val_horizontal = defaultPercent50;
                        ident = allowed_values.get(ident.toString());
                        if (ident != null) {
                            if (isVertical(ident)) {
                                v.vertical = ident;
                                v.val_vertical = identToPercent(ident);
                            } else {
                                // horizontal || center
                                v.horizontal = ident;
                                v.val_horizontal = identToPercent(ident);
                            }
                            break;
                        }
                        throw new InvalidParamException("unrecognize",
                                ident, getPropertyName(), ac);
                    case 2:
                        // one ident, two values... first MUST be horizontal
                        // and second vertical
                        CssValue val0 = v.value.get(0);
                        if (val0.getType() == CssTypes.CSS_IDENT) {

                            ident = allowed_values.get(val0.toString());
                            if (ident == null) {
                                throw new InvalidParamException("unrecognize",
                                        ident, getPropertyName(), ac);
                            }
                            if (isVertical(ident)) {
                                throw new InvalidParamException("incompatible",
                                        ident, v.value.get(1), ac);
                            }
                            v.horizontal = ident;
                            v.val_horizontal = identToPercent(ident);
                            // and the vertical value...
                            v.vertical = v.value.get(1);
                            if (v.vertical.getType() == CssTypes.CSS_NUMBER) {
                                v.vertical = defaultPercent0;
                            }
                            v.val_vertical = v.vertical;
                        } else {
                            ident = allowed_values.get(v.value.get(1).toString());
                            if (ident == null) {
                                throw new InvalidParamException("unrecognize",
                                        ident, getPropertyName(), ac);
                            }
                            if (isHorizontal(ident)) {
                                throw new InvalidParamException("incompatible",
                                        val0, v.value.get(1), ac);
                            }
                            v.vertical = ident;
                            v.val_vertical = identToPercent(ident);
                            // and the first value
                            v.horizontal = val0;
                            if (v.horizontal.getType() == CssTypes.CSS_NUMBER) {
                                v.horizontal = defaultPercent0;
                            }
                            v.val_horizontal = v.horizontal;
                        }
                        break;
                    default:
                        // one ident, 3 or 4 values is not allowed
                        throw new InvalidParamException("unrecognize",
                                ac);
                }
                break;
            default:
                // ok so we have two keywords, with possible offsets
                // we must check that every possible offset is right
                // after a keyword and also that the two keywords are
                // not incompatible
                boolean got_ident = false;
                CssIdent id1 = null;
                CssIdent id2 = null;
                CssValue off1 = null;
                CssValue off2 = null;
                for (CssValue aValue : v.value) {
                    switch (aValue.getType()) {
                        case CssTypes.CSS_IDENT:
                            aValue = allowed_values.get(aValue.toString());
                            if (aValue == null) {
                                throw new InvalidParamException("unrecognize",
                                        aValue, getPropertyName(), ac);
                            }
                            got_ident = true;
                            if (id1 == null) {
                                id1 = (CssIdent) aValue;
                            } else {
                                id2 = (CssIdent) aValue;
                                // we got both, let's check.
                                if (((isVertical(id1) && isVertical(id2))) ||
                                        (isHorizontal(id1) && isHorizontal(id2))) {
                                    throw new InvalidParamException("incompatible",
                                            id1, id2, ac);
                                }
                            }
                            break;
                        case CssTypes.CSS_NUMBER:
                            aValue = ((CssNumber) aValue).getPercentage();
                        case CssTypes.CSS_PERCENTAGE:
                        case CssTypes.CSS_LENGTH:
                            if (!got_ident) {
                                throw new InvalidParamException("unrecognize",
                                        aValue, getPropertyName(), ac);
                            }
                            if (id2 == null) {
                                off1 = aValue;
                            } else {
                                off2 = aValue;
                            }
                            got_ident = false;
                            break;
                        default:
                            // should never happen
                    }
                }

                if (isVertical(id1) || isHorizontal(id2)) {
                    // if an offset is present and value is 'center'
                    if (((off1 != null) && !isVertical(id1)) ||
                            ((off2 != null) && !isHorizontal(id2))) {
                        throw new InvalidParamException("incompatible",
                                id1, id2, ac);
                    }
                    v.horizontal = id2;
                    v.val_horizontal = identToPercent(id2);
                    v.horizontal_offset = off2;
                    v.vertical = id1;
                    v.val_vertical = identToPercent(id1);
                    v.vertical_offset = off1;
                } else {
                    if (((off2 != null) && !isVertical(id2)) ||
                            ((off1 != null) && !isHorizontal(id1))) {
                        throw new InvalidParamException("incompatible",
                                id1, id2, ac);
                    }
                    v.horizontal = id1;
                    v.val_horizontal = identToPercent(id1);
                    v.horizontal_offset = off1;
                    v.vertical = id2;
                    v.val_vertical = identToPercent(id2);
                    v.vertical_offset = off2;
                }
        }
    }

    public static CssPercentage identToPercent(CssIdent ident) {
        if (center.equals(ident)) {
            return defaultPercent50;
        } else if (top.equals(ident) || left.equals(ident)) {
            return defaultPercent0;
        } else if (bottom.equals(ident) || right.equals(ident)) {
            return defaultPercent100;
        }
        return defaultPercent0; // FIXME throw an exception ?
    }

    public static boolean isHorizontal(CssIdent ident) {
        return (left.equals(ident) || right.equals(ident));
    }

    public static boolean isVertical(CssIdent ident) {
        return (top.equals(ident) || bottom.equals(ident));
    }

    // placeholder for the different values

    public class CssBackgroundPositionValue extends CssValueList {
        public CssValue vertical = null;
        public CssValue horizontal = null;
        public CssValue vertical_offset = null;
        public CssValue horizontal_offset = null;

        public CssValue val_vertical = defaultPercent0;
        public CssValue val_horizontal = defaultPercent0;

        public boolean equals(CssBackgroundPositionValue v) {
            // check vertical compatibility (with optional values)
            if (!val_vertical.equals(v.val_vertical)) {
                return false;
            }
            if (vertical_offset != null) {
                if (!vertical_offset.equals(v.vertical_offset)) {
                    return false;
                }
            } else if (v.vertical_offset != null) {
                return false;
            }

            if (!val_horizontal.equals(v.val_horizontal)) {
                return false;
            }
            if (horizontal_offset != null) {
                if (!horizontal_offset.equals(v.horizontal_offset)) {
                    return false;
                }
            } else if (v.horizontal_offset != null) {
                return false;
            }
            // yeah!    
            return true;
        }

        public String toString() {
            StringBuilder sb = new StringBuilder();
            if (horizontal != null) {
                sb.append(horizontal);
                if (horizontal_offset != null) {
                    sb.append(' ').append(horizontal_offset);
                }
                if (vertical != null) {
                    sb.append(' ');
                }
            }
            if (vertical != null) {
                sb.append(vertical);
                if (vertical_offset != null) {
                    sb.append(' ').append(vertical_offset);
                }
            }
            return sb.toString();
        }

    }

}

--- NEW FILE: CssColor.java ---
// $Id: CssColor.java,v 1.1 2011/10/04 13:05:25 ylafon Exp $
//
// (c) COPYRIGHT MIT, ERCIM and Keio University, 2011
// Please first read the full copyright statement in file COPYRIGHT.html

package org.w3c.css.properties.css3;

import org.w3c.css.properties.css.CssProperty;
import org.w3c.css.util.ApplContext;
import org.w3c.css.util.InvalidParamException;
import org.w3c.css.values.CssExpression;
import org.w3c.css.values.CssFunction;
import org.w3c.css.values.CssIdent;
import org.w3c.css.values.CssTypes;
import org.w3c.css.values.CssValue;

/**
 * @spec http://www.w3.org/TR/2011/REC-css3-color-20110607/#color0
 * @version $Revision: 1.1 $
 */
public class CssColor extends org.w3c.css.properties.css.CssColor {
    private static CssIdent same = CssIdent.getIdent("currentColor");

    CssValue color;
    org.w3c.css.values.CssColor tempcolor = new org.w3c.css.values.CssColor();
    String attrvalue = null;

    /**
     * Create a new CssColor
     */
    public CssColor() {
        color = inherit;
    }

    /**
     * Set the value of the property
     *
     * @param expression The expression for this property
     * @throws org.w3c.css.util.InvalidParamException
     *          Values are incorrect
     */
    public CssColor(ApplContext ac, CssExpression expression, boolean check)
            throws InvalidParamException {

        if (check && expression.getCount() > 1) {
            throw new InvalidParamException("unrecognize", ac);
        }

        CssValue val = expression.getValue();
        setByUser();

        switch (val.getType()) {
            case CssTypes.CSS_IDENT:
                if (inherit.equals(val)) {
                    color = inherit;
                } else if (same.equals(val)) {
                    color = same;
                } else {
                    color = new org.w3c.css.values.CssColor(ac, (String) val.get());
                }
                break;
            case CssTypes.CSS_COLOR:
                color = val;
                break;
            case CssTypes.CSS_FUNCTION:
                CssFunction attr = (CssFunction) val;
                CssExpression params = attr.getParameters();
                String fname = attr.getName();

                if (fname.equals("attr")) {
                    CssValue v1 = params.getValue();
                    params.next();
                    CssValue v2 = params.getValue();
                    if ((params.getCount() != 2)) {
                        throw new InvalidParamException("value",
                                params.getValue(),
                                getPropertyName(), ac);
                    } else if (v1.getType() != CssTypes.CSS_IDENT) {
                        throw new InvalidParamException("value",
                                params.getValue(),
                                getPropertyName(), ac);

                    } else if (!(v2.toString().equals("color"))) {
                        throw new InvalidParamException("value",
                                params.getValue(),
                                getPropertyName(), ac);
                    } else {
                        attrvalue = "attr(" + v1 + ", " + v2 + ')';
                    }
                } else if (fname.equals("rgba")) {
                    tempcolor.setRGBAColor(params, ac);
                    color = tempcolor;
                } else if (fname.equals("hsl")) {
                    tempcolor.setHSLColor(params, ac);
                    color = tempcolor;
                } else if (fname.equals("hsla")) {
                    tempcolor.setHSLAColor(params, ac);
                    color = tempcolor;
                } else {
                    throw new InvalidParamException("value",
                            params.getValue(),
                            getPropertyName(), ac);
                }
                break;
            default:
                throw new InvalidParamException("value", expression.getValue(),
                        getPropertyName(), ac);
        }
        expression.next();
    }

    public CssColor(ApplContext ac, CssExpression expression)
            throws InvalidParamException {
        this(ac, expression, false);
    }

    /**
     * Returns the value of this property
     */
    public Object get() {
        return color;
    }

    /**
     * Returns the color
     */
    public org.w3c.css.values.CssColor getColor() {
        if (inherit.equals(color) || same.equals(color)) {
            /*
             System.err.println("[ERROR] org.w3c.css.properties.CssColor");
             System.err.println("[ERROR] value is inherited");
           */
            return null;
        } else {
            return (org.w3c.css.values.CssColor) color;
        }
    }

    /**
     * Returns true if this property is "softly" inherited
     * e.g. his value equals inherit
     */
    public boolean isSoftlyInherited() {
        return inherit.equals(color) || same.equals(color);
    }

    /**
     * Returns a string representation of the object.
     */
    public String toString() {
        if (attrvalue != null) {
            return attrvalue;
        } else {
            return color.toString();
        }
    }

    /**
     * Compares two properties for equality.
     *
     * @param property The other property.
     */
    public boolean equals(CssProperty property) {
        return (property instanceof CssColor &&
                color.equals(((CssColor) property).color));
    }


}

--- NEW FILE: CssBackgroundImage.java ---
// $Id: CssBackgroundImage.java,v 1.1 2011/10/04 13:05:25 ylafon Exp $
// @author Yves Lafon <ylafon@w3.org>
//
// (c) COPYRIGHT MIT, ERCIM and Keio, 2010.
// Please first read the full copyright statement in file COPYRIGHT.html

package org.w3c.css.properties.css3;

import org.w3c.css.properties.css.CssProperty;
import org.w3c.css.util.ApplContext;
import org.w3c.css.util.InvalidParamException;
import org.w3c.css.values.CssExpression;
import org.w3c.css.values.CssIdent;
import org.w3c.css.values.CssTypes;
import org.w3c.css.values.CssValue;

import java.util.ArrayList;

import static org.w3c.css.values.CssOperator.COMMA;

/**
 * http://www.w3.org/TR/2009/CR-css3-background-20091217/#the-background-image
 * <p/>
 * Name: 	background-image
 * Value: 	&lt;bg-image&gt; [ , &lt;bg-image&gt; ]*
 * Initial: 	none
 * Applies to: 	all elements
 * Inherited: 	no
 * Percentages: 	N/A
 * Media: 	visual
 * Computed value: 	as specified, but with URIs made absolute
 * <p/>
 * This property sets the background image(s) of an element. Images are drawn
 * with the first specified one on top (closest to the user) and each
 * subsequent image behind the previous one. Where
 * <p/>
 * &lt;bg-image&gt; = &lt;image&gt; | none
 */
public class CssBackgroundImage extends org.w3c.css.properties.css.CssBackgroundImage {


    Object url = null;

    public static boolean isMatchingIdent(CssIdent ident) {
        return none.equals(ident);
    }

    /**
     * Create a new CssBackgroundImage
     */
    public CssBackgroundImage() {
    }

    /**
     * Creates a new CssBackgroundImage
     *
     * @param ac         the context
     * @param expression The expression for this property
     * @param check      boolean
     * @throws org.w3c.css.util.InvalidParamException Values are incorrect
     */
    public CssBackgroundImage(ApplContext ac, CssExpression expression,
                              boolean check) throws InvalidParamException {

        ArrayList<CssValue> values = new ArrayList<CssValue>();
        setByUser();

        CssValue val;
        char op;

        while (!expression.end()) {
            val = expression.getValue();
            op = expression.getOperator();
            switch (val.getType()) {
                case CssTypes.CSS_URL:
                    values.add(val);
                    break;
                case CssTypes.CSS_IDENT:
                    if (inherit.equals(val)) {
                        // if we got inherit after other values, fail
                        // if we got more than one value... fail
                        if ((values.size() > 0) || (expression.getCount() > 1)) {
                            throw new InvalidParamException("value", val,
                                    getPropertyName(), ac);
                        }
                        values.add(inherit);
                        break;
                    } else if (none.equals(val)) {
                        values.add(none);
                        break;
                    }
                default:
                    throw new InvalidParamException("value", val,
                            getPropertyName(), ac);
            }
            expression.next();
            if (!expression.end() && (op != COMMA)) {
                throw new InvalidParamException("operator",
                        ((new Character(op)).toString()), ac);
            }
        }
        if (values.size() == 1) {
            url = values.get(0);
        } else {
            url = values;
        }
    }

    public CssBackgroundImage(ApplContext ac, CssExpression expression)
            throws InvalidParamException {
        this(ac, expression, false);
    }

    /**
     * Returns the value of this property
     */

    public Object get() {
        return url;
    }

    public void set(Object val) {
        url = val;
    }

    /**
     * Returns true if this property is "softly" inherited
     * e.g. his value equals inherit
     */
    public boolean isSoftlyInherited() {
        return (inherit == url);
    }

    /**
     * Returns a string representation of the object.
     */
    public String toString() {
        if (url instanceof ArrayList) {
            ArrayList values = (ArrayList) url;
            StringBuilder sb = new StringBuilder();
            for (Object aValue : values) {
                sb.append(aValue.toString()).append(", ");
            }
            sb.setLength(sb.length() - 2);
            return sb.toString();
        }
        return url.toString();
    }

    /**
     * Compares two properties for equality.
     *
     * @param property The other property.
     */
    public boolean equals(CssProperty property) {
        return (property instanceof CssBackgroundImage && url != null &&
                url.equals(((CssBackgroundImage) property).url));
    }

    /**
     * Is the value of this property is a default value.
     * It is used by all macro for the function <code>print</code>
     */
    public boolean isDefault() {
        return (url == none);
    }

}

--- NEW FILE: CssBackgroundSize.java ---
// $Id: CssBackgroundSize.java,v 1.4 2011/10/04 13:05:25 ylafon Exp $
// @author Yves Lafon <ylafon@w3.org>
//
// (c) COPYRIGHT MIT, ERCIM and Keio University, 2010.
// Please first read the full copyright statement in file COPYRIGHT.html

package org.w3c.css.properties.css3;

import org.w3c.css.properties.css.CssProperty;
import org.w3c.css.util.ApplContext;
import org.w3c.css.util.InvalidParamException;
import org.w3c.css.values.CssExpression;
import org.w3c.css.values.CssIdent;
import org.w3c.css.values.CssNumber;
import org.w3c.css.values.CssTypes;
import org.w3c.css.values.CssValue;
import org.w3c.css.values.CssValueList;

import java.util.ArrayList;
import java.util.HashMap;

import static org.w3c.css.values.CssOperator.COMMA;
import static org.w3c.css.values.CssOperator.SPACE;

/**
 * http://www.w3.org/TR/2009/CR-css3-background-20091217/#the-background-size
 * <p/>
 * <p/>
 * Name: 	background-size
 * Value: 	&lt;bg-size&gt; [ , &lt;bg-size&gt; ]*
 * Initial: 	auto
 * Applies to: 	all elements
 * Inherited: 	no
 * Percentages: 	see text
 * Media: 	visual
 * Computed value: 	for &lt;length&gt; the absolute value, otherwise as
 * specified
 * <p/>
 * Specifies the size of the background images. Where
 * <p/>
 * &lt;bg-size&gt; = [ &lt;length&gt; | &lt;percentage&gt; | auto ]{1,2} |
 * cover | contain
 */
public class CssBackgroundSize extends org.w3c.css.properties.css.CssBackgroundSize {

    private static CssIdent auto;
    private static HashMap<String, CssIdent> allowed_values;

    static {
        auto = CssIdent.getIdent("auto");
        allowed_values = new HashMap<String, CssIdent>();
        allowed_values.put("auto", auto);
        allowed_values.put("cover", CssIdent.getIdent("cover"));
        allowed_values.put("contain", CssIdent.getIdent("contain"));
    }

    public static boolean isMatchingIdent(CssIdent ident) {
        return allowed_values.containsKey(ident.toString());
    }

    Object value;

    /**
     * Create a new CssBackgroundSize
     */
    public CssBackgroundSize() {
        value = auto;
    }

    /**
     * Create a new CssBackgroundSize
     *
     * @param ac         The context
     * @param expression The expression for this property
     * @param check      if arguments count must be checked.
     * @throws org.w3c.css.util.InvalidParamException Values are incorrect
     */
    public CssBackgroundSize(ApplContext ac, CssExpression expression,
                             boolean check) throws InvalidParamException {
        ArrayList<CssValue> values = new ArrayList<CssValue>();
        char op;
        CssValue val;
        CssValueList vl = null;
        boolean is_complete = true;

        setByUser();

        while (!expression.end()) {
            val = expression.getValue();
            op = expression.getOperator();
            switch (val.getType()) {
                case CssTypes.CSS_NUMBER:
                    val = ((CssNumber) val).getLength();
                case CssTypes.CSS_LENGTH:
                case CssTypes.CSS_PERCENTAGE:
                    // per spec only non-negative values are allowed
                    float f = ((Float) val.get()).floatValue();
                    if (f < 0) {
                        throw new InvalidParamException("negative-value",
                                val.toString(), ac);
                    }
                    if (is_complete) {
                        vl = new CssValueList();
                        vl.add(val);
                    } else {
                        vl.add(val);
                        values.add(vl);
                    }
                    is_complete = !is_complete;
                    break;
                case CssTypes.CSS_IDENT:
                    if (inherit.equals(val)) {
                        // if we got inherit after other values, fail
                        // if we got more than one value... fail
                        if ((values.size() > 0) || (expression.getCount() > 1)) {
                            throw new InvalidParamException("value", val,
                                    getPropertyName(), ac);
                        }
                        values.add(inherit);
                        break;
                    } else if (auto.equals(val)) {
                        if (is_complete) {
                            vl = new CssValueList();
                            vl.add(auto);
                        } else {
                            vl.add(auto);
                            values.add(vl);
                        }
                        is_complete = !is_complete;
                        break;
                    } else {
                        CssValue v = allowed_values.get(val.toString());
                        // if ok, and if we are not in a middle of a compound
                        // value...
                        if (v != null && is_complete) {
                            values.add(v);
                            break;
                        }
                    }
                default:
                    throw new InvalidParamException("value", val,
                            getPropertyName(), ac);

            }
            expression.next();
            if (!expression.end()) {
                // incomplete value followed by a comma... it's complete!
                if (!is_complete && (op == COMMA)) {
                    values.add(vl);
                    is_complete = true;
                }
                // complete values are separated by a comma, otherwise space
                if ((is_complete && (op != COMMA)) ||
                        (!is_complete && (op != SPACE))) {
                    throw new InvalidParamException("operator",
                            ((new Character(op)).toString()), ac);
                }
            }
        }
        // if we reach the end in a value that can come in pair
        if (!is_complete) {
            values.add(vl);
        }
        if (values.size() == 1) {
            value = values.get(0);
        } else {
            value = values;
        }
    }


    public CssBackgroundSize(ApplContext ac, CssExpression expression)
            throws InvalidParamException {
        this(ac, expression, false);
    }

    /**
     * Compares two properties for equality.
     *
     * @param property The other property.
     */
    public boolean equals(CssProperty property) {
        return (property instanceof CssBackgroundSize &&
                value.equals(((CssBackgroundSize) property).value));
    }

    /**
     * Returns the value of this property
     */
    public Object get() {
        return value;
    }

    public void set(Object val) {
        value = val;
    }
    /**
     * Returns true if this property is "softly" inherited
     */
    public boolean isSoftlyInherited() {
        return (inherit == value);
    }

    /**
     * Returns a string representation of the object
     */
    public String toString() {
        if (value instanceof ArrayList) {
            ArrayList values = (ArrayList) value;
            StringBuilder sb = new StringBuilder();
            for (Object aValue : values) {
                sb.append(aValue.toString()).append(", ");
            }
            sb.setLength(sb.length() - 2);
            return sb.toString();
        }
        return value.toString();
    }

    /**
     * Is the value of this property a default value
     * It is used by all macro for the function <code>print</code>
     */
    public boolean isDefault() {
        return (auto == value);
    }

}

--- NEW FILE: CssBackgroundOrigin.java ---
//
// $Id: CssBackgroundOrigin.java,v 1.4 2011/10/04 13:05:25 ylafon Exp $
// @author Yves Lafon <ylafon@w3.org>
//
// (c) COPYRIGHT 2010  World Wide Web Consortium (MIT, ERCIM, Keio University)
// Please first read the full copyright statement at
// http://www.w3.org/Consortium/Legal/copyright-software-19980720

package org.w3c.css.properties.css3;

import org.w3c.css.parser.CssStyle;
import org.w3c.css.properties.css.CssProperty;
import org.w3c.css.util.ApplContext;
import org.w3c.css.util.InvalidParamException;
import org.w3c.css.values.CssExpression;
import org.w3c.css.values.CssIdent;
import org.w3c.css.values.CssTypes;
import org.w3c.css.values.CssValue;

import java.util.ArrayList;

import static org.w3c.css.values.CssOperator.COMMA;

/**
 * http://www.w3.org/TR/2009/CR-css3-background-20091217/#the-background-origin
 * <p/>
 * Name: 	background-origin
 * Value: 	&lt;bg-origin&gt; [ , &lt;bg-origin&gt; ]*
 * Initial: 	padding-box
 * Applies to: 	all elements
 * Inherited: 	no
 * Percentages: 	N/A
 * Media: 	visual
 * Computed value: 	same as specified value
 * <p/>
 * For elements rendered as a single box, specifies the background positioning
 * area. For elements rendered as multiple boxes (e.g., inline boxes on several
 * lines, boxes on several pages) specifies which boxes 'box-decoration-break'
 * operates on to determine the background positioning area(s).
 * <p/>
 * &lt;bg-origin&gt; = border-box | padding-box | content-box
 */

public class CssBackgroundOrigin extends org.w3c.css.properties.css.CssBackgroundOrigin {

    private static CssIdent border_box;
    private static CssIdent padding_box;
    private static CssIdent content_box;

    Object value;

    static {
        border_box = CssIdent.getIdent("border-box");
        padding_box = CssIdent.getIdent("padding-box");
        content_box = CssIdent.getIdent("content-box");
    }

    public static boolean isMatchingIdent(CssIdent ident) {
        return (border_box.equals(ident) ||
                padding_box.equals(ident) ||
                content_box.equals(ident));
    }

    /**
     * Create a new CssBackgroundClip
     */
    public CssBackgroundOrigin() {
        value = padding_box;
    }

    /**
     * Create a new CssBackgroundClip
     *
     * @param expression The expression for this property
     * @throws org.w3c.css.util.InvalidParamException
     *          Incorrect value
     */
    public CssBackgroundOrigin(ApplContext ac, CssExpression expression,
                               boolean check) throws InvalidParamException {

        ArrayList<CssValue> values = new ArrayList<CssValue>();

        CssValue val = expression.getValue();
        char op;

        while (!expression.end()) {
            val = expression.getValue();
            op = expression.getOperator();
            switch (val.getType()) {
                case CssTypes.CSS_IDENT:
                    if (inherit.equals(val)) {
                        // if we got inherit after other values, fail
                        // if we got more than one value... fail
                        if ((values.size() > 0) || (expression.getCount() > 1)) {
                            throw new InvalidParamException("value", val,
                                    getPropertyName(), ac);
                        }
                        values.add(inherit);
                        break;
                    } else if (border_box.equals(val)) {
                        values.add(border_box);
                        break;
                    } else if (content_box.equals(val)) {
                        values.add(content_box);
                        break;
                    } else if (padding_box.equals(val)) {
                        values.add(padding_box);
                        break;
                    }
                default:
                    throw new InvalidParamException("value", val,
                            getPropertyName(), ac);
            }
            expression.next();
            if (!expression.end() && (op != COMMA)) {
                throw new InvalidParamException("operator",
                        ((new Character(op)).toString()), ac);
            }
        }
        if (values.size() == 1) {
            value = values.get(0);
        } else {
            value = values;
        }
    }

    public CssBackgroundOrigin(ApplContext ac, CssExpression expression)
            throws InvalidParamException {
        this(ac, expression, false);
    }

    /**
     * Add this property to the CssStyle
     *
     * @param style The CssStyle
     */
    public void addToStyle(ApplContext ac, CssStyle style) {
        // TODO FIXME -> in CssStyle
        if (((Css3Style) style).cssBackgroundOrigin != null)
            style.addRedefinitionWarning(ac, this);
        ((Css3Style) style).cssBackgroundOrigin = this;
    }

    /**
     * Get this property in the style.
     *
     * @param style   The style where the property is
     * @param resolve if true, resolve the style to find this property
     */
    public CssProperty getPropertyInStyle(CssStyle style, boolean resolve) {
        if (resolve) {
            return ((Css3Style) style).getCssBackgroundOrigin();
        } else {
            return ((Css3Style) style).cssBackgroundOrigin;
        }
    }

    /**
     * Compares two properties for equality.
     *
     * @param property The other property.
     */
    public boolean equals(CssProperty property) {
        return (property instanceof CssBackgroundOrigin &&
                value.equals(((CssBackgroundOrigin) property).value));
    }

    /**
     * Returns the value of this property
     */
    public Object get() {
        return value;
    }

    public void set(Object val) {
        value = val;
    }

    /**
     * Returns true if this property is "softly" inherited
     */
    public boolean isSoftlyInherited() {
        return inherit.equals(value);
    }

    /**
     * Returns a string representation of the object
     */
    public String toString() {
        if (value instanceof ArrayList) {
            ArrayList values = (ArrayList) value;
            StringBuilder sb = new StringBuilder();
            for (Object aValue : values) {
                sb.append(aValue.toString()).append(", ");
            }
            sb.setLength(sb.length() - 2);
            return sb.toString();
        }
        return value.toString();
    }

    /**
     * Is the value of this property a default value
     * It is used by all macro for the function <code>print</code>
     */
    public boolean isDefault() {
        return (padding_box == value);
    }

}
--- NEW FILE: CssBackgroundClip.java ---
// $Id: CssBackgroundClip.java,v 1.4 2011/10/04 13:05:25 ylafon Exp $
// @author Yves Lafon <ylafon@w3.org>
//
// (c) COPYRIGHT 2010  World Wide Web Consortium (MIT, ERCIM, Keio University)
// Please first read the full copyright statement at
// http://www.w3.org/Consortium/Legal/copyright-software-19980720

package org.w3c.css.properties.css3;

import org.w3c.css.parser.CssStyle;
import org.w3c.css.properties.css.CssProperty;
import org.w3c.css.util.ApplContext;
import org.w3c.css.util.InvalidParamException;
import org.w3c.css.values.CssExpression;
import org.w3c.css.values.CssIdent;
import org.w3c.css.values.CssTypes;
import org.w3c.css.values.CssValue;

import java.util.ArrayList;

import static org.w3c.css.values.CssOperator.COMMA;

/**
 * http://www.w3.org/TR/2009/CR-css3-background-20091217/#the-background-clip
 * Name: 	background-clip
 * Value: 	[border-box | padding-box ] [ , [border-box | padding-box ] ]*
 * Initial: 	border-box
 * Applies to: 	all elements
 * Inherited: 	no
 * Percentages: 	N/A
 * Media: 	visual
 * Computed value: 	same as specified value
 * <p/>
 * Determines the background painting area.
 */

public class CssBackgroundClip extends org.w3c.css.properties.css.CssBackgroundClip {

    public final static CssIdent border_box;
    public final static CssIdent padding_box;

    Object value;

    static {
        border_box = CssIdent.getIdent("border-box");
        padding_box = CssIdent.getIdent("padding-box");
    }

    public static boolean isMatchingIdent(CssIdent ident) {
        return (border_box.equals(ident) ||
                padding_box.equals(ident));
    }

    /**
     * Create a new CssBackgroundClip
     */
    public CssBackgroundClip() {
    }

    /**
     * Create a new CssBackgroundClip
     *
     * @param expression The expression for this property
     * @throws org.w3c.css.util.InvalidParamException Incorrect value
     */
    public CssBackgroundClip(ApplContext ac, CssExpression expression,
                             boolean check) throws InvalidParamException {

        ArrayList<CssValue> values = new ArrayList<CssValue>();

        CssValue val;
        char op;

        while (!expression.end()) {
            val = expression.getValue();
            op = expression.getOperator();
            switch (val.getType()) {
                case CssTypes.CSS_IDENT:
                    if (inherit.equals(val)) {
                        // if we got inherit after other values, fail
                        // if we got more than one value... fail
                        if ((values.size() > 0) || (expression.getCount() > 1)) {
                            throw new InvalidParamException("value", val,
                                    getPropertyName(), ac);
                        }
                        values.add(inherit);
                        break;
                    } else if (border_box.equals(val)) {
                        values.add(border_box);
                        break;
                    } else if (padding_box.equals(val)) {
                        values.add(padding_box);
                        break;
                    }
                default:
                    throw new InvalidParamException("value", val,
                            getPropertyName(), ac);
            }
            expression.next();
            if (!expression.end() && (op != COMMA)) {
                throw new InvalidParamException("operator",
                        ((new Character(op)).toString()), ac);
            }
        }
        if (values.size() == 1) {
            value = values.get(0);
        } else {
            value = values;
        }
    }

    public CssBackgroundClip(ApplContext ac, CssExpression expression)
            throws InvalidParamException {
        this(ac, expression, false);
    }

    public void set(Object val) {
        value = val;
    }
    
    /**
     * Add this property to the CssStyle
     *
     * @param style The CssStyle
     */
    public void addToStyle(ApplContext ac, CssStyle style) {
        // TODO FIXME -> in CssStyle
        if (((Css3Style) style).cssBackgroundClip != null)
            style.addRedefinitionWarning(ac, this);
        ((Css3Style) style).cssBackgroundClip = this;
    }

    /**
     * Get this property in the style.
     *
     * @param style   The style where the property is
     * @param resolve if true, resolve the style to find this property
     */
    public CssProperty getPropertyInStyle(CssStyle style, boolean resolve) {
        if (resolve) {
            return ((Css3Style) style).getCssBackgroundClip();
        } else {
            return ((Css3Style) style).cssBackgroundClip;
        }
    }

    /**
     * Compares two properties for equality.
     *
     * @param property The other property.
     */
    public boolean equals(CssProperty property) {
        return (property instanceof CssBackgroundClip &&
                value.equals(((CssBackgroundClip) property).value));
    }

    /**
     * Returns a string representation of the object
     */
    public String toString() {
        if (value instanceof ArrayList) {
            ArrayList values = (ArrayList) value;
            StringBuilder sb = new StringBuilder();
            for (Object aValue : values) {
                sb.append(aValue.toString()).append(", ");
            }
            sb.setLength(sb.length() - 2);
            return sb.toString();
        }
        return value.toString();
    }

    /**
     * Is the value of this property a default value
     * It is used by all macro for the function <code>print</code>
     */
    public boolean isDefault() {
        return (border_box == value);
    }

}

Received on Tuesday, 4 October 2011 13:05:39 UTC