You are viewing a plain text version of this content. The canonical link for it is here.
Posted to fop-commits@xmlgraphics.apache.org by je...@apache.org on 2011/02/10 16:58:58 UTC

svn commit: r1069439 [2/2] - in /xmlgraphics/fop/trunk: ./ src/java/org/apache/fop/afp/apps/ src/java/org/apache/fop/afp/goca/ src/java/org/apache/fop/afp/modca/ src/java/org/apache/fop/afp/parser/ src/java/org/apache/fop/afp/ptoca/ src/java/org/apache...

Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/util/AbstractPaintingState.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/util/AbstractPaintingState.java?rev=1069439&r1=1069438&r2=1069439&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/util/AbstractPaintingState.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/util/AbstractPaintingState.java Thu Feb 10 15:58:57 2011
@@ -75,7 +75,8 @@ public abstract class AbstractPaintingSt
      * @return true if the color has changed
      */
     public boolean setColor(Color col) {
-        if (!col.equals(getData().color)) {
+        Color other = getData().color;
+        if (!org.apache.xmlgraphics.java2d.color.ColorUtil.isSameColor(col, other)) {
             getData().color = col;
             return true;
         }
@@ -114,7 +115,8 @@ public abstract class AbstractPaintingSt
      * @return true if the color has changed
      */
     public boolean setBackColor(Color col) {
-        if (!col.equals(getData().backColor)) {
+        Color other = getData().backColor;
+        if (!org.apache.xmlgraphics.java2d.color.ColorUtil.isSameColor(col, other)) {
             getData().backColor = col;
             return true;
         }
@@ -364,6 +366,7 @@ public abstract class AbstractPaintingSt
     }
 
     /** {@inheritDoc} */
+    @Override
     public Object clone() {
         AbstractPaintingState state = instantiate();
         state.stateStack = new StateStack(this.stateStack);
@@ -372,6 +375,7 @@ public abstract class AbstractPaintingSt
     }
 
     /** {@inheritDoc} */
+    @Override
     public String toString() {
         return ", stateStack=" + stateStack
         + ", currentData=" + data;
@@ -506,6 +510,7 @@ public abstract class AbstractPaintingSt
         }
 
         /** {@inheritDoc} */
+        @Override
         public Object clone() {
             AbstractData data = instantiate();
             data.color = this.color;
@@ -522,6 +527,7 @@ public abstract class AbstractPaintingSt
         }
 
         /** {@inheritDoc} */
+        @Override
         public String toString() {
             return "color=" + color
                 + ", backColor=" + backColor

Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/util/ColorExt.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/util/ColorExt.java?rev=1069439&r1=1069438&r2=1069439&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/util/ColorExt.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/util/ColorExt.java Thu Feb 10 15:58:57 2011
@@ -1,3 +1,4 @@
+<<<<<<< .working
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -248,3 +249,261 @@ public final class ColorExt extends Colo
     }
 
 }
+=======
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.util;
+
+import java.awt.Color;
+import java.awt.color.ColorSpace;
+import java.util.Arrays;
+
+import org.apache.xmlgraphics.java2d.color.ColorWithAlternatives;
+
+/**
+ * Color helper class.
+ * <p>
+ * This class extends java.awt.Color class keeping track of the original color
+ * property values specified by the fo user in a rgb-icc call.
+ * @deprecated Replaced by {@link ColorWithAlternatives}
+ */
+@Deprecated
+public final class ColorExt extends Color {
+    //
+    private static final long serialVersionUID = 1L;
+
+    // Values of fop-rgb-icc arguments
+    private float rgbReplacementRed;
+    private float rgbReplacementGreen;
+    private float rgbReplacementBlue;
+
+    private String iccProfileName;
+    private String iccProfileSrc;
+    private ColorSpace colorSpace;
+
+    private float[] colorValues;
+
+    /*
+     * Helper for createFromFoRgbIcc
+     */
+    private ColorExt(ColorSpace colorSpace, float[] colorValues, float opacity) {
+        super(colorSpace, colorValues, opacity);
+    }
+
+    /*
+     * Helper for createFromSvgIccColor
+     */
+    private ColorExt(float red, float green, float blue, float opacity) {
+        super(red, green, blue, opacity);
+    }
+
+    /**
+     * Create ColorExt object backup up FO's rgb-icc color function
+     *
+     * @param redReplacement
+     *            Red part of RGB replacement color that will be used when ICC
+     *            profile can not be loaded
+     * @param greenReplacement
+     *            Green part of RGB replacement color that will be used when ICC
+     *            profile can not be loaded
+     * @param blueReplacement
+     *            Blue part of RGB replacement color that will be used when ICC
+     *            profile can not be loaded
+     * @param profileName
+     *            Name of ICC profile
+     * @param profileSrc
+     *            Source of ICC profile
+     * @param colorSpace
+     *            ICC ColorSpace for the ICC profile
+     * @param iccValues
+     *            color values
+     * @return the requested color object
+     */
+    public static ColorExt createFromFoRgbIcc(float redReplacement,
+            float greenReplacement, float blueReplacement, String profileName,
+            String profileSrc, ColorSpace colorSpace, float[] iccValues) {
+        ColorExt ce = new ColorExt(colorSpace, iccValues, 1.0f);
+        ce.rgbReplacementRed = redReplacement;
+        ce.rgbReplacementGreen = greenReplacement;
+        ce.rgbReplacementBlue = blueReplacement;
+        ce.iccProfileName = profileName;
+        ce.iccProfileSrc = profileSrc;
+        ce.colorSpace = colorSpace;
+        ce.colorValues = iccValues;
+        return ce;
+    }
+
+    /**
+     * Create ColorExt object backing up SVG's icc-color function.
+     *
+     * @param red
+     *            Red value resulting from the conversion from the user provided
+     *            (icc) color values to the batik (rgb) color space
+     * @param green
+     *            Green value resulting from the conversion from the user
+     *            provided (icc) color values to the batik (rgb) color space
+     * @param blue
+     *            Blue value resulting from the conversion from the user
+     *            provided (icc) color values to the batik (rgb) color space
+     * @param opacity
+     *            Opacity
+     * @param profileName
+     *            ICC profile name
+     * @param profileHref
+     *            the URI to the color profile
+     * @param profileCS
+     *            ICC ColorSpace profile
+     * @param colorValues
+     *            ICC color values
+     * @return the requested color object
+     */
+    public static ColorExt createFromSvgIccColor(                // CSOK: ParameterNumber
+            float red, float green,
+            float blue, float opacity, String profileName, String profileHref,
+            ColorSpace profileCS, float[] colorValues) {
+        //TODO this method is not referenced by FOP, can it be deleted?
+        ColorExt ce = new ColorExt(red, green, blue, opacity);
+        ce.rgbReplacementRed = -1;
+        ce.rgbReplacementGreen = -1;
+        ce.rgbReplacementBlue = -1;
+        ce.iccProfileName = profileName;
+        ce.iccProfileSrc = profileHref;
+        ce.colorSpace = profileCS;
+        ce.colorValues = colorValues;
+        return ce;
+
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int hashCode() {
+        //implementation from the superclass should be good enough for our purposes
+        return super.hashCode();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!super.equals(obj)) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        ColorExt other = (ColorExt)obj;
+        //TODO maybe use super.getColorComponents() instead
+        if (!Arrays.equals(colorValues, other.colorValues)) {
+            return false;
+        }
+        if (iccProfileName == null) {
+            if (other.iccProfileName != null) {
+                return false;
+            }
+        } else if (!iccProfileName.equals(other.iccProfileName)) {
+            return false;
+        }
+        if (iccProfileSrc == null) {
+            if (other.iccProfileSrc != null) {
+                return false;
+            }
+        } else if (!iccProfileSrc.equals(other.iccProfileSrc)) {
+            return false;
+        }
+        if (Float.floatToIntBits(rgbReplacementBlue)
+                != Float.floatToIntBits(other.rgbReplacementBlue)) {
+            return false;
+        }
+        if (Float.floatToIntBits(rgbReplacementGreen)
+                != Float.floatToIntBits(other.rgbReplacementGreen)) {
+            return false;
+        }
+        if (Float.floatToIntBits(rgbReplacementRed)
+                != Float.floatToIntBits(other.rgbReplacementRed)) {
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Get ICC profile name
+     *
+     * @return ICC profile name
+     */
+    public String getIccProfileName() {
+        return this.iccProfileName;
+    }
+
+    /**
+     * Get ICC profile source
+     *
+     * @return ICC profile source
+     */
+    public String getIccProfileSrc() {
+        return this.iccProfileSrc;
+    }
+
+    /**
+     * @return the original ColorSpace
+     */
+    public ColorSpace getOrigColorSpace() {
+        //TODO this method is probably unnecessary due to super.cs and getColorSpace()
+        return this.colorSpace;
+    }
+
+    /**
+     * Returns the original color values.
+     * @return the original color values
+     */
+    public float[] getOriginalColorComponents() {
+        //TODO this method is probably unnecessary due to super.fvalue and getColorComponents()
+        float[] copy = new float[this.colorValues.length];
+        System.arraycopy(this.colorValues, 0, copy, 0, copy.length);
+        return copy;
+    }
+
+    /**
+     * Create string representation of fop-rgb-icc function call to map this
+     * ColorExt settings
+     * @return the string representing the internal fop-rgb-icc() function call
+     */
+    public String toFunctionCall() {
+        StringBuffer sb = new StringBuffer(40);
+        sb.append("fop-rgb-icc(");
+        sb.append(this.rgbReplacementRed + ",");
+        sb.append(this.rgbReplacementGreen + ",");
+        sb.append(this.rgbReplacementBlue + ",");
+        sb.append(this.iccProfileName + ",");
+        if (this.iccProfileSrc != null) {
+            sb.append("\"" + this.iccProfileSrc + "\"");
+        }
+        float[] colorComponents = this.getColorComponents(null);
+        for (int ix = 0; ix < colorComponents.length; ix++) {
+            sb.append(",");
+            sb.append(colorComponents[ix]);
+        }
+        sb.append(")");
+        return sb.toString();
+    }
+
+}
+>>>>>>> .merge-right.r1069429

Propchange: xmlgraphics/fop/trunk/src/java/org/apache/fop/util/ColorExt.java
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Thu Feb 10 15:58:57 2011
@@ -1,4 +1,5 @@
 /xmlgraphics/fop/branches/Temp_AFPGOCAResources/src/java/org/apache/fop/util/ColorExt.java:630874-721418
 /xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/util/ColorExt.java:745924-830281
 /xmlgraphics/fop/branches/Temp_AreaTreeNewDesign/src/java/org/apache/fop/util/ColorExt.java:603620-746655
+/xmlgraphics/fop/branches/Temp_Color/src/java/org/apache/fop/util/ColorExt.java:956535-1069429
 /xmlgraphics/fop/branches/fop-0_95/src/java/org/apache/fop/util/ColorExt.java:684572,688085,688696

Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/util/ColorSpaceCache.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/util/ColorSpaceCache.java?rev=1069439&r1=1069438&r2=1069439&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/util/ColorSpaceCache.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/util/ColorSpaceCache.java Thu Feb 10 15:58:57 2011
@@ -20,7 +20,6 @@
 package org.apache.fop.util;
 
 import java.awt.color.ColorSpace;
-import java.awt.color.ICC_ColorSpace;
 import java.awt.color.ICC_Profile;
 import java.util.Collections;
 import java.util.Map;
@@ -33,6 +32,9 @@ import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.xmlgraphics.java2d.color.profile.ColorProfileUtil;
 
+import org.apache.xmlgraphics.java2d.color.ICCColorSpaceWithIntent;
+import org.apache.xmlgraphics.java2d.color.RenderingIntent;
+
 /**
  * Map with cached ICC based ColorSpace objects.
  */
@@ -61,13 +63,17 @@ public class ColorSpaceCache {
      * The FOP URI resolver is used to try and locate the ICC file.
      * If that fails null is returned.
      *
+     * @param profileName the profile name
      * @param base a base URI to resolve relative URIs
      * @param iccProfileSrc ICC Profile source to return a ColorSpace for
+     * @param renderingIntent overriding rendering intent
      * @return ICC ColorSpace object or null if ColorSpace could not be created
      */
-    public ColorSpace get(String base, String iccProfileSrc) {
+    public ColorSpace get(String profileName, String base, String iccProfileSrc,
+            RenderingIntent renderingIntent) {
+        String key = profileName + ":" + base + iccProfileSrc;
         ColorSpace colorSpace = null;
-        if (!colorSpaceMap.containsKey(base + iccProfileSrc)) {
+        if (!colorSpaceMap.containsKey(key)) {
             try {
                 ICC_Profile iccProfile = null;
                 // First attempt to use the FOP URI resolver to locate the ICC
@@ -88,7 +94,8 @@ public class ColorSpaceCache {
                     // iccProfile = ICC_Profile.getInstance(iccProfileSrc);
                 }
                 if (iccProfile != null) {
-                    colorSpace = new ICC_ColorSpace(iccProfile);
+                    colorSpace = new ICCColorSpaceWithIntent(iccProfile, renderingIntent,
+                            profileName, iccProfileSrc);
                 }
             } catch (Exception e) {
                 // Ignore exception - will be logged a bit further down
@@ -97,14 +104,14 @@ public class ColorSpaceCache {
 
             if (colorSpace != null) {
                 // Put in cache (not when VM resolved it as we can't control
-                colorSpaceMap.put(base + iccProfileSrc, colorSpace);
+                colorSpaceMap.put(key, colorSpace);
             } else {
                 // TODO To avoid an excessive amount of warnings perhaps
                 // register a null ColorMap in the colorSpaceMap
                 log.warn("Color profile '" + iccProfileSrc + "' not found.");
             }
         } else {
-            colorSpace = colorSpaceMap.get(base + iccProfileSrc);
+            colorSpace = colorSpaceMap.get(key);
         }
         return colorSpace;
     }

Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/util/ColorUtil.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/util/ColorUtil.java?rev=1069439&r1=1069438&r2=1069439&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/util/ColorUtil.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/util/ColorUtil.java Thu Feb 10 15:58:57 2011
@@ -21,14 +21,23 @@ package org.apache.fop.util;
 
 import java.awt.Color;
 import java.awt.color.ColorSpace;
+import java.awt.color.ICC_ColorSpace;
+import java.awt.color.ICC_Profile;
 import java.util.Collections;
 import java.util.Map;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 
+import org.apache.xmlgraphics.java2d.color.CIELabColorSpace;
+import org.apache.xmlgraphics.java2d.color.ColorSpaceOrigin;
 import org.apache.xmlgraphics.java2d.color.ColorSpaces;
+import org.apache.xmlgraphics.java2d.color.ColorWithAlternatives;
 import org.apache.xmlgraphics.java2d.color.DeviceCMYKColorSpace;
+import org.apache.xmlgraphics.java2d.color.NamedColorSpace;
+import org.apache.xmlgraphics.java2d.color.RenderingIntent;
+import org.apache.xmlgraphics.java2d.color.profile.NamedColorProfile;
+import org.apache.xmlgraphics.java2d.color.profile.NamedColorProfileParser;
 
 import org.apache.fop.apps.FOUserAgent;
 import org.apache.fop.fo.expr.PropertyException;
@@ -41,15 +50,22 @@ import org.apache.fop.fo.expr.PropertyEx
  */
 public final class ColorUtil {
 
+    //ColorWithFallback is used to preserve the sRGB fallback exclusively for the purpose
+    //of regenerating textual color functions as specified in XSL-FO.
+
     /** The name for the uncalibrated CMYK pseudo-profile */
     public static final String CMYK_PSEUDO_PROFILE = "#CMYK";
 
+    /** The name for the Separation pseudo-profile used for spot colors */
+    public static final String SEPARATION_PSEUDO_PROFILE = "#Separation";
+
     /**
-     *
-     * keeps all the predefined and parsed colors.
+     * Keeps all the predefined and parsed colors.
      * <p>
      * This map is used to predefine given colors, as well as speeding up
      * parsing of already parsed colors.
+     * <p>
+     * Important: The use of this color map assumes that all Color instances are immutable!
      */
     private static Map<String, Color> colorMap = null;
 
@@ -98,7 +114,7 @@ public final class ColorUtil {
             return null;
         }
 
-        Color parsedColor = (Color) colorMap.get(value.toLowerCase());
+        Color parsedColor = colorMap.get(value.toLowerCase());
 
         if (parsedColor == null) {
             if (value.startsWith("#")) {
@@ -114,6 +130,10 @@ public final class ColorUtil {
                 parsedColor = parseAsSystemColor(value);
             } else if (value.startsWith("fop-rgb-icc")) {
                 parsedColor = parseAsFopRgbIcc(foUserAgent, value);
+            } else if (value.startsWith("fop-rgb-named-color")) {
+                parsedColor = parseAsFopRgbNamedColor(foUserAgent, value);
+            } else if (value.startsWith("cie-lab-color")) {
+                parsedColor = parseAsCIELabColor(foUserAgent, value);
             } else if (value.startsWith("cmyk")) {
                 parsedColor = parseAsCMYK(value);
             }
@@ -125,9 +145,6 @@ public final class ColorUtil {
             colorMap.put(value, parsedColor);
         }
 
-        // TODO - Returned Color object can be one from the static colorMap cache.
-        //        That means it should be treated as read only for the rest of its lifetime.
-        //        Not sure that is the case though.
         return parsedColor;
     }
 
@@ -150,7 +167,7 @@ public final class ColorUtil {
             throw new PropertyException("Unknown color format: " + value
                     + ". Must be system-color(x)");
         }
-        return (Color) colorMap.get(value);
+        return colorMap.get(value);
     }
 
     /**
@@ -218,34 +235,14 @@ public final class ColorUtil {
                     throw new PropertyException(
                             "Invalid number of arguments: rgb(" + value + ")");
                 }
-                float red = 0.0f, green = 0.0f, blue = 0.0f;
-                String str = args[0].trim();
-                if (str.endsWith("%")) {
-                    red = Float.parseFloat(str.substring(0,
-                            str.length() - 1)) / 100f;
-                } else {
-                    red = Float.parseFloat(str) / 255f;
-                }
-                str = args[1].trim();
-                if (str.endsWith("%")) {
-                    green = Float.parseFloat(str.substring(0,
-                            str.length() - 1)) / 100f;
-                } else {
-                    green = Float.parseFloat(str) / 255f;
-                }
-                str = args[2].trim();
-                if (str.endsWith("%")) {
-                    blue = Float.parseFloat(str.substring(0,
-                            str.length() - 1)) / 100f;
-                } else {
-                    blue = Float.parseFloat(str) / 255f;
-                }
-                if ((red < 0.0 || red > 1.0)
-                        || (green < 0.0 || green > 1.0)
-                        || (blue < 0.0 || blue > 1.0)) {
-                    throw new PropertyException("Color values out of range");
-                }
-                parsedColor = new Color(red, green, blue);
+                float red = parseComponent255(args[0], value);
+                float green = parseComponent255(args[1], value);
+                float blue = parseComponent255(args[2], value);
+                //Convert to ints to synchronize the behaviour with toRGBFunctionCall()
+                int r = (int)(red * 255 + 0.5);
+                int g = (int)(green * 255 + 0.5);
+                int b = (int)(blue * 255 + 0.5);
+                parsedColor = new Color(r, g, b);
             } catch (PropertyException pe) {
                 //simply re-throw
                 throw pe;
@@ -260,8 +257,50 @@ public final class ColorUtil {
         return parsedColor;
     }
 
+    private static float parseComponent255(String str, String function)
+            throws PropertyException {
+        float component;
+        str = str.trim();
+        if (str.endsWith("%")) {
+            component = Float.parseFloat(str.substring(0,
+                    str.length() - 1)) / 100f;
+        } else {
+            component = Float.parseFloat(str) / 255f;
+        }
+        if ((component < 0.0 || component > 1.0)) {
+            throw new PropertyException("Color value out of range for " + function + ": "
+                    + str + ". Valid range: [0..255] or [0%..100%]");
+        }
+        return component;
+    }
+
+    private static float parseComponent1(String argument, String function)
+            throws PropertyException {
+        return parseComponent(argument, 0f, 1f, function);
+    }
+
+    private static float parseComponent(String argument, float min, float max, String function)
+            throws PropertyException {
+        float component = Float.parseFloat(argument.trim());
+        if ((component < min || component > max)) {
+            throw new PropertyException("Color value out of range for " + function + ": "
+                    + argument + ". Valid range: [" + min + ".." + max + "]");
+        }
+        return component;
+    }
+
+    private static Color parseFallback(String[] args, String value) throws PropertyException {
+        float red = parseComponent1(args[0], value);
+        float green = parseComponent1(args[1], value);
+        float blue = parseComponent1(args[2], value);
+        //Sun's classlib rounds differently with this constructor than when converting to sRGB
+        //via CIE XYZ.
+        Color sRGB = new Color(red, green, blue);
+        return sRGB;
+    }
+
     /**
-     * parse a color given in the #.... format.
+     * Parse a color given in the #.... format.
      *
      * @param value
      *            the complete line
@@ -320,6 +359,10 @@ public final class ColorUtil {
                 if (args.length < 5) {
                     throw new PropertyException("Too few arguments for rgb-icc() function");
                 }
+
+                //Set up fallback sRGB value
+                Color sRGB = parseFallback(args, value);
+
                 /* Get and verify ICC profile name */
                 String iccProfileName = args[3].trim();
                 if (iccProfileName == null || "".equals(iccProfileName)) {
@@ -330,6 +373,9 @@ public final class ColorUtil {
                 if (isPseudoProfile(iccProfileName)) {
                     if (CMYK_PSEUDO_PROFILE.equalsIgnoreCase(iccProfileName)) {
                         colorSpace = ColorSpaces.getDeviceCMYKColorSpace();
+                    } else if (SEPARATION_PSEUDO_PROFILE.equalsIgnoreCase(iccProfileName)) {
+                        colorSpace = new NamedColorSpace(args[5], sRGB,
+                                SEPARATION_PSEUDO_PROFILE, null);
                     } else {
                         assert false : "Incomplete implementation";
                     }
@@ -339,47 +385,51 @@ public final class ColorUtil {
                     if (iccProfileSrc == null || "".equals(iccProfileSrc)) {
                         throw new PropertyException("ICC profile source missing");
                     }
-                    if (iccProfileSrc.startsWith("\"") || iccProfileSrc.startsWith("'")) {
-                        iccProfileSrc = iccProfileSrc.substring(1);
-                    }
-                    if (iccProfileSrc.endsWith("\"") || iccProfileSrc.endsWith("'")) {
-                        iccProfileSrc = iccProfileSrc.substring(0, iccProfileSrc.length() - 1);
-                    }
+                    iccProfileSrc = unescapeString(iccProfileSrc);
                 }
                 /* ICC profile arguments */
-                float[] iccComponents = new float[args.length - 5];
-                for (int ix = 4; ++ix < args.length;) {
-                    iccComponents[ix - 5] = Float.parseFloat(args[ix].trim());
+                int componentStart = 4;
+                if (colorSpace instanceof NamedColorSpace) {
+                    componentStart++;
+                }
+                float[] iccComponents = new float[args.length - componentStart - 1];
+                for (int ix = componentStart; ++ix < args.length;) {
+                    iccComponents[ix - componentStart - 1] = Float.parseFloat(args[ix].trim());
                 }
-
-                float red = 0, green = 0, blue = 0;
-                red = Float.parseFloat(args[0].trim());
-                green = Float.parseFloat(args[1].trim());
-                blue = Float.parseFloat(args[2].trim());
-                /* Verify rgb replacement arguments */
-                if ((red < 0 || red > 1)
-                        || (green < 0 || green > 1)
-                        || (blue < 0 || blue > 1)) {
-                    throw new PropertyException("Color values out of range. "
-                            + "Fallback RGB arguments to fop-rgb-icc() must be [0..1]");
+                if (colorSpace instanceof NamedColorSpace && iccComponents.length == 0) {
+                    iccComponents = new float[] {1.0f}; //full tint if not specified
                 }
 
                 /* Ask FOP factory to get ColorSpace for the specified ICC profile source */
                 if (foUserAgent != null && iccProfileSrc != null) {
-                    colorSpace = foUserAgent.getFactory().getColorSpace(
-                            foUserAgent.getBaseURL(), iccProfileSrc);
+                    assert colorSpace == null;
+                    RenderingIntent renderingIntent = RenderingIntent.AUTO;
+                    //TODO connect to fo:color-profile/@rendering-intent
+                    colorSpace = foUserAgent.getFactory().getColorSpaceCache().get(
+                            iccProfileName,
+                            foUserAgent.getBaseURL(), iccProfileSrc,
+                            renderingIntent);
                 }
                 if (colorSpace != null) {
-                    // ColorSpace available - create ColorExt (keeps track of replacement rgb
-                    // values for possible later colorTOsRGBString call
-                    parsedColor = ColorExt.createFromFoRgbIcc(red, green, blue,
-                            iccProfileName, iccProfileSrc, colorSpace, iccComponents);
+                    // ColorSpace is available
+                    if (ColorSpaces.isDeviceColorSpace(colorSpace)) {
+                        //Device-specific colors are handled differently:
+                        //sRGB is the primary color with the CMYK as the alternative
+                        Color deviceColor = new Color(colorSpace, iccComponents, 1.0f);
+                        float[] rgbComps = sRGB.getRGBColorComponents(null);
+                        parsedColor = new ColorWithAlternatives(
+                                rgbComps[0], rgbComps[1], rgbComps[2],
+                                new Color[] {deviceColor});
+                    } else {
+                        Color specColor = new ColorWithFallback(
+                                colorSpace, iccComponents, 1.0f, null, sRGB);
+                        parsedColor = specColor;
+                    }
                 } else {
                     // ICC profile could not be loaded - use rgb replacement values */
                     log.warn("Color profile '" + iccProfileSrc
-                            + "' not found. Using rgb replacement values.");
-                    parsedColor = new Color(Math.round(red * 255),
-                            Math.round(green * 255), Math.round(blue * 255));
+                            + "' not found. Using sRGB replacement values.");
+                    parsedColor = sRGB;
                 }
             } catch (PropertyException pe) {
                 //simply re-throw
@@ -396,6 +446,161 @@ public final class ColorUtil {
     }
 
     /**
+     * Parse a color specified using the fop-rgb-named-color() function.
+     *
+     * @param value the function call
+     * @return a color if possible
+     * @throws PropertyException if the format is wrong.
+     */
+    private static Color parseAsFopRgbNamedColor(FOUserAgent foUserAgent, String value)
+            throws PropertyException {
+        Color parsedColor;
+        int poss = value.indexOf("(");
+        int pose = value.indexOf(")");
+        if (poss != -1 && pose != -1) {
+            String[] args = value.substring(poss + 1, pose).split(",");
+
+            try {
+                if (args.length != 6) {
+                    throw new PropertyException("rgb-named-color() function must have 6 arguments");
+                }
+
+                //Set up fallback sRGB value
+                Color sRGB = parseFallback(args, value);
+
+                /* Get and verify ICC profile name */
+                String iccProfileName = args[3].trim();
+                if (iccProfileName == null || "".equals(iccProfileName)) {
+                    throw new PropertyException("ICC profile name missing");
+                }
+                ICC_ColorSpace colorSpace = null;
+                String iccProfileSrc = null;
+                if (isPseudoProfile(iccProfileName)) {
+                    throw new IllegalArgumentException(
+                            "Pseudo-profiles are not allowed with fop-rgb-named-color()");
+                } else {
+                    /* Get and verify ICC profile source */
+                    iccProfileSrc = args[4].trim();
+                    if (iccProfileSrc == null || "".equals(iccProfileSrc)) {
+                        throw new PropertyException("ICC profile source missing");
+                    }
+                    iccProfileSrc = unescapeString(iccProfileSrc);
+                }
+
+                // color name
+                String colorName = unescapeString(args[5].trim());
+
+                /* Ask FOP factory to get ColorSpace for the specified ICC profile source */
+                if (foUserAgent != null && iccProfileSrc != null) {
+                    RenderingIntent renderingIntent = RenderingIntent.AUTO;
+                    //TODO connect to fo:color-profile/@rendering-intent
+                    colorSpace = (ICC_ColorSpace)foUserAgent.getFactory().getColorSpaceCache().get(
+                            iccProfileName,
+                            foUserAgent.getBaseURL(), iccProfileSrc,
+                            renderingIntent);
+                }
+                if (colorSpace != null) {
+                    ICC_Profile profile = colorSpace.getProfile();
+                    if (NamedColorProfileParser.isNamedColorProfile(profile)) {
+                        NamedColorProfileParser parser = new NamedColorProfileParser();
+                        NamedColorProfile ncp = parser.parseProfile(profile,
+                                    iccProfileName, iccProfileSrc);
+                        NamedColorSpace ncs = ncp.getNamedColor(colorName);
+                        if (ncs != null) {
+                            Color specColor = new ColorWithFallback(ncs,
+                                    new float[] {1.0f}, 1.0f, null, sRGB);
+                            parsedColor = specColor;
+                        } else {
+                            log.warn("Color '" + colorName
+                                    + "' does not exist in named color profile: " + iccProfileSrc);
+                            parsedColor = sRGB;
+                        }
+                    } else {
+                        log.warn("ICC profile is no named color profile: " + iccProfileSrc);
+                        parsedColor = sRGB;
+                    }
+                } else {
+                    // ICC profile could not be loaded - use rgb replacement values */
+                    log.warn("Color profile '" + iccProfileSrc
+                            + "' not found. Using sRGB replacement values.");
+                    parsedColor = sRGB;
+                }
+            } catch (PropertyException pe) {
+                //simply re-throw
+                throw pe;
+            } catch (Exception e) {
+                //wrap in a PropertyException
+                throw new PropertyException(e);
+            }
+        } else {
+            throw new PropertyException("Unknown color format: " + value
+                    + ". Must be fop-rgb-named-color(r,g,b,NCNAME,src,color-name)");
+        }
+        return parsedColor;
+    }
+
+    /**
+     * Parse a color specified using the cie-lab-color() function.
+     *
+     * @param value the function call
+     * @return a color if possible
+     * @throws PropertyException if the format is wrong.
+     */
+    private static Color parseAsCIELabColor(FOUserAgent foUserAgent, String value)
+            throws PropertyException {
+        Color parsedColor;
+        int poss = value.indexOf("(");
+        int pose = value.indexOf(")");
+        if (poss != -1 && pose != -1) {
+            String[] args = value.substring(poss + 1, pose).split(",");
+
+            try {
+                if (args.length != 6) {
+                    throw new PropertyException("cie-lab-color() function must have 6 arguments");
+                }
+
+                //Set up fallback sRGB value
+                float red = parseComponent255(args[0], value);
+                float green = parseComponent255(args[1], value);
+                float blue = parseComponent255(args[2], value);
+                Color sRGB = new Color(red, green, blue);
+
+                float l = parseComponent(args[3], 0f, 100f, value);
+                float a = parseComponent(args[4], -127f, 127f, value);
+                float b = parseComponent(args[5], -127f, 127f, value);
+
+                //Assuming the XSL-FO spec uses the D50 white point
+                CIELabColorSpace cs = ColorSpaces.getCIELabColorSpaceD50();
+                //use toColor() to have components normalized
+                Color labColor = cs.toColor(l, a, b, 1.0f);
+                //Convert to ColorWithFallback
+                parsedColor = new ColorWithFallback(labColor, sRGB);
+
+            } catch (PropertyException pe) {
+                //simply re-throw
+                throw pe;
+            } catch (Exception e) {
+                //wrap in a PropertyException
+                throw new PropertyException(e);
+            }
+        } else {
+            throw new PropertyException("Unknown color format: " + value
+                    + ". Must be cie-lab-color(r,g,b,Lightness,a-value,b-value)");
+        }
+        return parsedColor;
+    }
+
+    private static String unescapeString(String iccProfileSrc) {
+        if (iccProfileSrc.startsWith("\"") || iccProfileSrc.startsWith("'")) {
+            iccProfileSrc = iccProfileSrc.substring(1);
+        }
+        if (iccProfileSrc.endsWith("\"") || iccProfileSrc.endsWith("'")) {
+            iccProfileSrc = iccProfileSrc.substring(0, iccProfileSrc.length() - 1);
+        }
+        return iccProfileSrc;
+    }
+
+    /**
      * Parse a color given with the cmyk() function.
      *
      * @param value
@@ -416,48 +621,15 @@ public final class ColorUtil {
                     throw new PropertyException(
                             "Invalid number of arguments: cmyk(" + value + ")");
                 }
-                float cyan = 0.0f, magenta = 0.0f, yellow = 0.0f, black = 0.0f;
-                String str = args[0].trim();
-                if (str.endsWith("%")) {
-                  cyan  = Float.parseFloat(str.substring(0,
-                            str.length() - 1)) / 100.0f;
-                } else {
-                  cyan  = Float.parseFloat(str);
-                }
-                str = args[1].trim();
-                if (str.endsWith("%")) {
-                  magenta = Float.parseFloat(str.substring(0,
-                            str.length() - 1)) / 100.0f;
-                } else {
-                  magenta = Float.parseFloat(str);
-                }
-                str = args[2].trim();
-                if (str.endsWith("%")) {
-                  yellow = Float.parseFloat(str.substring(0,
-                            str.length() - 1)) / 100.0f;
-                } else {
-                  yellow = Float.parseFloat(str);
-                }
-                str = args[3].trim();
-                if (str.endsWith("%")) {
-                  black = Float.parseFloat(str.substring(0,
-                            str.length() - 1)) / 100.0f;
-                } else {
-                  black = Float.parseFloat(str);
-                }
-
-                if ((cyan < 0.0 || cyan > 1.0)
-                        || (magenta < 0.0 || magenta > 1.0)
-                        || (yellow < 0.0 || yellow > 1.0)
-                        || (black < 0.0 || black > 1.0)) {
-                    throw new PropertyException("Color values out of range"
-                            + "Arguments to cmyk() must be in the range [0%-100%] or [0.0-1.0]");
-                }
-                float[] cmyk = new float[] {cyan, magenta, yellow, black};
-                DeviceCMYKColorSpace cmykCs = ColorSpaces.getDeviceCMYKColorSpace();
-                float[] rgb = cmykCs.toRGB(cmyk);
-                parsedColor = ColorExt.createFromFoRgbIcc(rgb[0], rgb[1], rgb[2],
-                        CMYK_PSEUDO_PROFILE, null, cmykCs, cmyk);
+                float cyan = parseComponent1(args[0], value);
+                float magenta = parseComponent1(args[1], value);
+                float yellow = parseComponent1(args[2], value);
+                float black = parseComponent1(args[3], value);
+                float[] comps = new float[] {cyan, magenta, yellow, black};
+                Color cmykColor = DeviceCMYKColorSpace.createCMYKColor(comps);
+                float[] rgbComps = cmykColor.getRGBColorComponents(null);
+                parsedColor = new ColorWithAlternatives(rgbComps[0], rgbComps[1], rgbComps[2],
+                        new Color[] {cmykColor});
             } catch (PropertyException pe) {
                 throw pe;
             } catch (Exception e) {
@@ -482,40 +654,146 @@ public final class ColorUtil {
      */
     public static String colorToString(Color color) {
         ColorSpace cs = color.getColorSpace();
-        if (color instanceof ColorExt) {
-            return ((ColorExt)color).toFunctionCall();
+        if (color instanceof ColorWithAlternatives) {
+            return toFunctionCall((ColorWithAlternatives)color);
         } else if (cs != null && cs.getType() == ColorSpace.TYPE_CMYK) {
             StringBuffer sbuf = new StringBuffer(24);
             float[] cmyk = color.getColorComponents(null);
             sbuf.append("cmyk(" + cmyk[0] + "," + cmyk[1] + "," + cmyk[2] + "," +  cmyk[3] + ")");
             return sbuf.toString();
         } else {
-            StringBuffer sbuf = new StringBuffer();
-            sbuf.append('#');
-            String s = Integer.toHexString(color.getRed());
+            return toRGBFunctionCall(color);
+        }
+    }
+
+    private static String toRGBFunctionCall(Color color) {
+        StringBuffer sbuf = new StringBuffer();
+        sbuf.append('#');
+        String s = Integer.toHexString(color.getRed());
+        if (s.length() == 1) {
+            sbuf.append('0');
+        }
+        sbuf.append(s);
+        s = Integer.toHexString(color.getGreen());
+        if (s.length() == 1) {
+            sbuf.append('0');
+        }
+        sbuf.append(s);
+        s = Integer.toHexString(color.getBlue());
+        if (s.length() == 1) {
+            sbuf.append('0');
+        }
+        sbuf.append(s);
+        if (color.getAlpha() != 255) {
+            s = Integer.toHexString(color.getAlpha());
             if (s.length() == 1) {
                 sbuf.append('0');
             }
             sbuf.append(s);
-            s = Integer.toHexString(color.getGreen());
-            if (s.length() == 1) {
-                sbuf.append('0');
+        }
+        return sbuf.toString();
+    }
+
+    private static Color getsRGBFallback(ColorWithAlternatives color) {
+        Color fallbackColor;
+        if (color instanceof ColorWithFallback) {
+            fallbackColor = ((ColorWithFallback)color).getFallbackColor();
+            if (!fallbackColor.getColorSpace().isCS_sRGB()) {
+                fallbackColor = toSRGBColor(fallbackColor);
             }
-            sbuf.append(s);
-            s = Integer.toHexString(color.getBlue());
-            if (s.length() == 1) {
-                sbuf.append('0');
+        } else {
+            fallbackColor = toSRGBColor(color);
+        }
+        return fallbackColor;
+    }
+
+    private static Color toSRGBColor(Color color) {
+        float[] comps;
+        ColorSpace sRGB = ColorSpace.getInstance(ColorSpace.CS_sRGB);
+        comps = color.getRGBColorComponents(null);
+        float[] allComps = color.getComponents(null);
+        float alpha = allComps[allComps.length - 1]; //Alpha is on last component
+        return new Color(sRGB, comps, alpha);
+    }
+
+    /**
+     * Create string representation of a fop-rgb-icc (or fop-rgb-named-color) function call from
+     * the given color.
+     * @param color the color to turn into a function call
+     * @return the string representing the internal fop-rgb-icc() or fop-rgb-named-color()
+     *           function call
+     */
+    private static String toFunctionCall(ColorWithAlternatives color) {
+        ColorSpace cs = color.getColorSpace();
+        if (cs.isCS_sRGB() && !color.hasAlternativeColors()) {
+            return toRGBFunctionCall(color);
+        }
+        if (cs instanceof CIELabColorSpace) {
+            return toCIELabFunctionCall(color);
+        }
+
+        Color specColor = color;
+        if (color.hasAlternativeColors()) {
+            Color alt = color.getAlternativeColors()[0];
+            if (ColorSpaces.isDeviceColorSpace(alt.getColorSpace())) {
+                cs = alt.getColorSpace();
+                specColor = alt;
             }
-            sbuf.append(s);
-            if (color.getAlpha() != 255) {
-                s = Integer.toHexString(color.getAlpha());
-                if (s.length() == 1) {
-                    sbuf.append('0');
-                }
-                sbuf.append(s);
+        }
+        ColorSpaceOrigin origin = ColorSpaces.getColorSpaceOrigin(cs);
+        String functionName;
+
+        Color fallbackColor = getsRGBFallback(color);
+        float[] rgb = fallbackColor.getColorComponents(null);
+        assert rgb.length == 3;
+        StringBuffer sb = new StringBuffer(40);
+        sb.append("(");
+        sb.append(rgb[0]).append(",");
+        sb.append(rgb[1]).append(",");
+        sb.append(rgb[2]).append(",");
+        String profileName = origin.getProfileName();
+        sb.append(profileName).append(",");
+        if (origin.getProfileURI() != null) {
+            sb.append("\"").append(origin.getProfileURI()).append("\"");
+        }
+
+        if (cs instanceof NamedColorSpace) {
+            NamedColorSpace ncs = (NamedColorSpace)cs;
+            if (SEPARATION_PSEUDO_PROFILE.equalsIgnoreCase(profileName)) {
+                functionName = "fop-rgb-icc";
+            } else {
+                functionName = "fop-rgb-named-color";
+            }
+            sb.append(",").append(ncs.getColorName());
+        } else {
+            functionName = "fop-rgb-icc";
+            float[] colorComponents = specColor.getColorComponents(null);
+            for (int ix = 0; ix < colorComponents.length; ix++) {
+                sb.append(",");
+                sb.append(colorComponents[ix]);
             }
-            return sbuf.toString();
         }
+        sb.append(")");
+        return functionName + sb.toString();
+    }
+
+    private static String toCIELabFunctionCall(ColorWithAlternatives color) {
+        Color fallbackColor = getsRGBFallback(color);
+        StringBuffer sb = new StringBuffer("cie-lab-color(");
+        sb.append(fallbackColor.getRed()).append(',');
+        sb.append(fallbackColor.getGreen()).append(',');
+        sb.append(fallbackColor.getBlue());
+        CIELabColorSpace cs = (CIELabColorSpace)color.getColorSpace();
+        float[] lab = cs.toNativeComponents(color.getColorComponents(null));
+        for (int i = 0; i < 3; i++) {
+            sb.append(',').append(lab[i]);
+        }
+        sb.append(')');
+        return sb.toString();
+    }
+
+    private static Color createColor(int r, int g, int b) {
+        return new Color(r, g, b);
     }
 
     /**
@@ -524,155 +802,155 @@ public final class ColorUtil {
     private static void initializeColorMap() {                  // CSOK: MethodLength
         colorMap = Collections.synchronizedMap(new java.util.HashMap<String, Color>());
 
-        colorMap.put("aliceblue", new Color(240, 248, 255));
-        colorMap.put("antiquewhite", new Color(250, 235, 215));
-        colorMap.put("aqua", new Color(0, 255, 255));
-        colorMap.put("aquamarine", new Color(127, 255, 212));
-        colorMap.put("azure", new Color(240, 255, 255));
-        colorMap.put("beige", new Color(245, 245, 220));
-        colorMap.put("bisque", new Color(255, 228, 196));
-        colorMap.put("black", new Color(0, 0, 0));
-        colorMap.put("blanchedalmond", new Color(255, 235, 205));
-        colorMap.put("blue", new Color(0, 0, 255));
-        colorMap.put("blueviolet", new Color(138, 43, 226));
-        colorMap.put("brown", new Color(165, 42, 42));
-        colorMap.put("burlywood", new Color(222, 184, 135));
-        colorMap.put("cadetblue", new Color(95, 158, 160));
-        colorMap.put("chartreuse", new Color(127, 255, 0));
-        colorMap.put("chocolate", new Color(210, 105, 30));
-        colorMap.put("coral", new Color(255, 127, 80));
-        colorMap.put("cornflowerblue", new Color(100, 149, 237));
-        colorMap.put("cornsilk", new Color(255, 248, 220));
-        colorMap.put("crimson", new Color(220, 20, 60));
-        colorMap.put("cyan", new Color(0, 255, 255));
-        colorMap.put("darkblue", new Color(0, 0, 139));
-        colorMap.put("darkcyan", new Color(0, 139, 139));
-        colorMap.put("darkgoldenrod", new Color(184, 134, 11));
-        colorMap.put("darkgray", new Color(169, 169, 169));
-        colorMap.put("darkgreen", new Color(0, 100, 0));
-        colorMap.put("darkgrey", new Color(169, 169, 169));
-        colorMap.put("darkkhaki", new Color(189, 183, 107));
-        colorMap.put("darkmagenta", new Color(139, 0, 139));
-        colorMap.put("darkolivegreen", new Color(85, 107, 47));
-        colorMap.put("darkorange", new Color(255, 140, 0));
-        colorMap.put("darkorchid", new Color(153, 50, 204));
-        colorMap.put("darkred", new Color(139, 0, 0));
-        colorMap.put("darksalmon", new Color(233, 150, 122));
-        colorMap.put("darkseagreen", new Color(143, 188, 143));
-        colorMap.put("darkslateblue", new Color(72, 61, 139));
-        colorMap.put("darkslategray", new Color(47, 79, 79));
-        colorMap.put("darkslategrey", new Color(47, 79, 79));
-        colorMap.put("darkturquoise", new Color(0, 206, 209));
-        colorMap.put("darkviolet", new Color(148, 0, 211));
-        colorMap.put("deeppink", new Color(255, 20, 147));
-        colorMap.put("deepskyblue", new Color(0, 191, 255));
-        colorMap.put("dimgray", new Color(105, 105, 105));
-        colorMap.put("dimgrey", new Color(105, 105, 105));
-        colorMap.put("dodgerblue", new Color(30, 144, 255));
-        colorMap.put("firebrick", new Color(178, 34, 34));
-        colorMap.put("floralwhite", new Color(255, 250, 240));
-        colorMap.put("forestgreen", new Color(34, 139, 34));
-        colorMap.put("fuchsia", new Color(255, 0, 255));
-        colorMap.put("gainsboro", new Color(220, 220, 220));
-        colorMap.put("ghostwhite", new Color(248, 248, 255));
-        colorMap.put("gold", new Color(255, 215, 0));
-        colorMap.put("goldenrod", new Color(218, 165, 32));
-        colorMap.put("gray", new Color(128, 128, 128));
-        colorMap.put("green", new Color(0, 128, 0));
-        colorMap.put("greenyellow", new Color(173, 255, 47));
-        colorMap.put("grey", new Color(128, 128, 128));
-        colorMap.put("honeydew", new Color(240, 255, 240));
-        colorMap.put("hotpink", new Color(255, 105, 180));
-        colorMap.put("indianred", new Color(205, 92, 92));
-        colorMap.put("indigo", new Color(75, 0, 130));
-        colorMap.put("ivory", new Color(255, 255, 240));
-        colorMap.put("khaki", new Color(240, 230, 140));
-        colorMap.put("lavender", new Color(230, 230, 250));
-        colorMap.put("lavenderblush", new Color(255, 240, 245));
-        colorMap.put("lawngreen", new Color(124, 252, 0));
-        colorMap.put("lemonchiffon", new Color(255, 250, 205));
-        colorMap.put("lightblue", new Color(173, 216, 230));
-        colorMap.put("lightcoral", new Color(240, 128, 128));
-        colorMap.put("lightcyan", new Color(224, 255, 255));
-        colorMap.put("lightgoldenrodyellow", new Color(250, 250, 210));
-        colorMap.put("lightgray", new Color(211, 211, 211));
-        colorMap.put("lightgreen", new Color(144, 238, 144));
-        colorMap.put("lightgrey", new Color(211, 211, 211));
-        colorMap.put("lightpink", new Color(255, 182, 193));
-        colorMap.put("lightsalmon", new Color(255, 160, 122));
-        colorMap.put("lightseagreen", new Color(32, 178, 170));
-        colorMap.put("lightskyblue", new Color(135, 206, 250));
-        colorMap.put("lightslategray", new Color(119, 136, 153));
-        colorMap.put("lightslategrey", new Color(119, 136, 153));
-        colorMap.put("lightsteelblue", new Color(176, 196, 222));
-        colorMap.put("lightyellow", new Color(255, 255, 224));
-        colorMap.put("lime", new Color(0, 255, 0));
-        colorMap.put("limegreen", new Color(50, 205, 50));
-        colorMap.put("linen", new Color(250, 240, 230));
-        colorMap.put("magenta", new Color(255, 0, 255));
-        colorMap.put("maroon", new Color(128, 0, 0));
-        colorMap.put("mediumaquamarine", new Color(102, 205, 170));
-        colorMap.put("mediumblue", new Color(0, 0, 205));
-        colorMap.put("mediumorchid", new Color(186, 85, 211));
-        colorMap.put("mediumpurple", new Color(147, 112, 219));
-        colorMap.put("mediumseagreen", new Color(60, 179, 113));
-        colorMap.put("mediumslateblue", new Color(123, 104, 238));
-        colorMap.put("mediumspringgreen", new Color(0, 250, 154));
-        colorMap.put("mediumturquoise", new Color(72, 209, 204));
-        colorMap.put("mediumvioletred", new Color(199, 21, 133));
-        colorMap.put("midnightblue", new Color(25, 25, 112));
-        colorMap.put("mintcream", new Color(245, 255, 250));
-        colorMap.put("mistyrose", new Color(255, 228, 225));
-        colorMap.put("moccasin", new Color(255, 228, 181));
-        colorMap.put("navajowhite", new Color(255, 222, 173));
-        colorMap.put("navy", new Color(0, 0, 128));
-        colorMap.put("oldlace", new Color(253, 245, 230));
-        colorMap.put("olive", new Color(128, 128, 0));
-        colorMap.put("olivedrab", new Color(107, 142, 35));
-        colorMap.put("orange", new Color(255, 165, 0));
-        colorMap.put("orangered", new Color(255, 69, 0));
-        colorMap.put("orchid", new Color(218, 112, 214));
-        colorMap.put("palegoldenrod", new Color(238, 232, 170));
-        colorMap.put("palegreen", new Color(152, 251, 152));
-        colorMap.put("paleturquoise", new Color(175, 238, 238));
-        colorMap.put("palevioletred", new Color(219, 112, 147));
-        colorMap.put("papayawhip", new Color(255, 239, 213));
-        colorMap.put("peachpuff", new Color(255, 218, 185));
-        colorMap.put("peru", new Color(205, 133, 63));
-        colorMap.put("pink", new Color(255, 192, 203));
-        colorMap.put("plum ", new Color(221, 160, 221));
-        colorMap.put("plum", new Color(221, 160, 221));
-        colorMap.put("powderblue", new Color(176, 224, 230));
-        colorMap.put("purple", new Color(128, 0, 128));
-        colorMap.put("red", new Color(255, 0, 0));
-        colorMap.put("rosybrown", new Color(188, 143, 143));
-        colorMap.put("royalblue", new Color(65, 105, 225));
-        colorMap.put("saddlebrown", new Color(139, 69, 19));
-        colorMap.put("salmon", new Color(250, 128, 114));
-        colorMap.put("sandybrown", new Color(244, 164, 96));
-        colorMap.put("seagreen", new Color(46, 139, 87));
-        colorMap.put("seashell", new Color(255, 245, 238));
-        colorMap.put("sienna", new Color(160, 82, 45));
-        colorMap.put("silver", new Color(192, 192, 192));
-        colorMap.put("skyblue", new Color(135, 206, 235));
-        colorMap.put("slateblue", new Color(106, 90, 205));
-        colorMap.put("slategray", new Color(112, 128, 144));
-        colorMap.put("slategrey", new Color(112, 128, 144));
-        colorMap.put("snow", new Color(255, 250, 250));
-        colorMap.put("springgreen", new Color(0, 255, 127));
-        colorMap.put("steelblue", new Color(70, 130, 180));
-        colorMap.put("tan", new Color(210, 180, 140));
-        colorMap.put("teal", new Color(0, 128, 128));
-        colorMap.put("thistle", new Color(216, 191, 216));
-        colorMap.put("tomato", new Color(255, 99, 71));
-        colorMap.put("turquoise", new Color(64, 224, 208));
-        colorMap.put("violet", new Color(238, 130, 238));
-        colorMap.put("wheat", new Color(245, 222, 179));
-        colorMap.put("white", new Color(255, 255, 255));
-        colorMap.put("whitesmoke", new Color(245, 245, 245));
-        colorMap.put("yellow", new Color(255, 255, 0));
-        colorMap.put("yellowgreen", new Color(154, 205, 50));
-        colorMap.put("transparent", new Color(0, 0, 0, 0));
+        colorMap.put("aliceblue", createColor(240, 248, 255));
+        colorMap.put("antiquewhite", createColor(250, 235, 215));
+        colorMap.put("aqua", createColor(0, 255, 255));
+        colorMap.put("aquamarine", createColor(127, 255, 212));
+        colorMap.put("azure", createColor(240, 255, 255));
+        colorMap.put("beige", createColor(245, 245, 220));
+        colorMap.put("bisque", createColor(255, 228, 196));
+        colorMap.put("black", createColor(0, 0, 0));
+        colorMap.put("blanchedalmond", createColor(255, 235, 205));
+        colorMap.put("blue", createColor(0, 0, 255));
+        colorMap.put("blueviolet", createColor(138, 43, 226));
+        colorMap.put("brown", createColor(165, 42, 42));
+        colorMap.put("burlywood", createColor(222, 184, 135));
+        colorMap.put("cadetblue", createColor(95, 158, 160));
+        colorMap.put("chartreuse", createColor(127, 255, 0));
+        colorMap.put("chocolate", createColor(210, 105, 30));
+        colorMap.put("coral", createColor(255, 127, 80));
+        colorMap.put("cornflowerblue", createColor(100, 149, 237));
+        colorMap.put("cornsilk", createColor(255, 248, 220));
+        colorMap.put("crimson", createColor(220, 20, 60));
+        colorMap.put("cyan", createColor(0, 255, 255));
+        colorMap.put("darkblue", createColor(0, 0, 139));
+        colorMap.put("darkcyan", createColor(0, 139, 139));
+        colorMap.put("darkgoldenrod", createColor(184, 134, 11));
+        colorMap.put("darkgray", createColor(169, 169, 169));
+        colorMap.put("darkgreen", createColor(0, 100, 0));
+        colorMap.put("darkgrey", createColor(169, 169, 169));
+        colorMap.put("darkkhaki", createColor(189, 183, 107));
+        colorMap.put("darkmagenta", createColor(139, 0, 139));
+        colorMap.put("darkolivegreen", createColor(85, 107, 47));
+        colorMap.put("darkorange", createColor(255, 140, 0));
+        colorMap.put("darkorchid", createColor(153, 50, 204));
+        colorMap.put("darkred", createColor(139, 0, 0));
+        colorMap.put("darksalmon", createColor(233, 150, 122));
+        colorMap.put("darkseagreen", createColor(143, 188, 143));
+        colorMap.put("darkslateblue", createColor(72, 61, 139));
+        colorMap.put("darkslategray", createColor(47, 79, 79));
+        colorMap.put("darkslategrey", createColor(47, 79, 79));
+        colorMap.put("darkturquoise", createColor(0, 206, 209));
+        colorMap.put("darkviolet", createColor(148, 0, 211));
+        colorMap.put("deeppink", createColor(255, 20, 147));
+        colorMap.put("deepskyblue", createColor(0, 191, 255));
+        colorMap.put("dimgray", createColor(105, 105, 105));
+        colorMap.put("dimgrey", createColor(105, 105, 105));
+        colorMap.put("dodgerblue", createColor(30, 144, 255));
+        colorMap.put("firebrick", createColor(178, 34, 34));
+        colorMap.put("floralwhite", createColor(255, 250, 240));
+        colorMap.put("forestgreen", createColor(34, 139, 34));
+        colorMap.put("fuchsia", createColor(255, 0, 255));
+        colorMap.put("gainsboro", createColor(220, 220, 220));
+        colorMap.put("ghostwhite", createColor(248, 248, 255));
+        colorMap.put("gold", createColor(255, 215, 0));
+        colorMap.put("goldenrod", createColor(218, 165, 32));
+        colorMap.put("gray", createColor(128, 128, 128));
+        colorMap.put("green", createColor(0, 128, 0));
+        colorMap.put("greenyellow", createColor(173, 255, 47));
+        colorMap.put("grey", createColor(128, 128, 128));
+        colorMap.put("honeydew", createColor(240, 255, 240));
+        colorMap.put("hotpink", createColor(255, 105, 180));
+        colorMap.put("indianred", createColor(205, 92, 92));
+        colorMap.put("indigo", createColor(75, 0, 130));
+        colorMap.put("ivory", createColor(255, 255, 240));
+        colorMap.put("khaki", createColor(240, 230, 140));
+        colorMap.put("lavender", createColor(230, 230, 250));
+        colorMap.put("lavenderblush", createColor(255, 240, 245));
+        colorMap.put("lawngreen", createColor(124, 252, 0));
+        colorMap.put("lemonchiffon", createColor(255, 250, 205));
+        colorMap.put("lightblue", createColor(173, 216, 230));
+        colorMap.put("lightcoral", createColor(240, 128, 128));
+        colorMap.put("lightcyan", createColor(224, 255, 255));
+        colorMap.put("lightgoldenrodyellow", createColor(250, 250, 210));
+        colorMap.put("lightgray", createColor(211, 211, 211));
+        colorMap.put("lightgreen", createColor(144, 238, 144));
+        colorMap.put("lightgrey", createColor(211, 211, 211));
+        colorMap.put("lightpink", createColor(255, 182, 193));
+        colorMap.put("lightsalmon", createColor(255, 160, 122));
+        colorMap.put("lightseagreen", createColor(32, 178, 170));
+        colorMap.put("lightskyblue", createColor(135, 206, 250));
+        colorMap.put("lightslategray", createColor(119, 136, 153));
+        colorMap.put("lightslategrey", createColor(119, 136, 153));
+        colorMap.put("lightsteelblue", createColor(176, 196, 222));
+        colorMap.put("lightyellow", createColor(255, 255, 224));
+        colorMap.put("lime", createColor(0, 255, 0));
+        colorMap.put("limegreen", createColor(50, 205, 50));
+        colorMap.put("linen", createColor(250, 240, 230));
+        colorMap.put("magenta", createColor(255, 0, 255));
+        colorMap.put("maroon", createColor(128, 0, 0));
+        colorMap.put("mediumaquamarine", createColor(102, 205, 170));
+        colorMap.put("mediumblue", createColor(0, 0, 205));
+        colorMap.put("mediumorchid", createColor(186, 85, 211));
+        colorMap.put("mediumpurple", createColor(147, 112, 219));
+        colorMap.put("mediumseagreen", createColor(60, 179, 113));
+        colorMap.put("mediumslateblue", createColor(123, 104, 238));
+        colorMap.put("mediumspringgreen", createColor(0, 250, 154));
+        colorMap.put("mediumturquoise", createColor(72, 209, 204));
+        colorMap.put("mediumvioletred", createColor(199, 21, 133));
+        colorMap.put("midnightblue", createColor(25, 25, 112));
+        colorMap.put("mintcream", createColor(245, 255, 250));
+        colorMap.put("mistyrose", createColor(255, 228, 225));
+        colorMap.put("moccasin", createColor(255, 228, 181));
+        colorMap.put("navajowhite", createColor(255, 222, 173));
+        colorMap.put("navy", createColor(0, 0, 128));
+        colorMap.put("oldlace", createColor(253, 245, 230));
+        colorMap.put("olive", createColor(128, 128, 0));
+        colorMap.put("olivedrab", createColor(107, 142, 35));
+        colorMap.put("orange", createColor(255, 165, 0));
+        colorMap.put("orangered", createColor(255, 69, 0));
+        colorMap.put("orchid", createColor(218, 112, 214));
+        colorMap.put("palegoldenrod", createColor(238, 232, 170));
+        colorMap.put("palegreen", createColor(152, 251, 152));
+        colorMap.put("paleturquoise", createColor(175, 238, 238));
+        colorMap.put("palevioletred", createColor(219, 112, 147));
+        colorMap.put("papayawhip", createColor(255, 239, 213));
+        colorMap.put("peachpuff", createColor(255, 218, 185));
+        colorMap.put("peru", createColor(205, 133, 63));
+        colorMap.put("pink", createColor(255, 192, 203));
+        colorMap.put("plum ", createColor(221, 160, 221));
+        colorMap.put("plum", createColor(221, 160, 221));
+        colorMap.put("powderblue", createColor(176, 224, 230));
+        colorMap.put("purple", createColor(128, 0, 128));
+        colorMap.put("red", createColor(255, 0, 0));
+        colorMap.put("rosybrown", createColor(188, 143, 143));
+        colorMap.put("royalblue", createColor(65, 105, 225));
+        colorMap.put("saddlebrown", createColor(139, 69, 19));
+        colorMap.put("salmon", createColor(250, 128, 114));
+        colorMap.put("sandybrown", createColor(244, 164, 96));
+        colorMap.put("seagreen", createColor(46, 139, 87));
+        colorMap.put("seashell", createColor(255, 245, 238));
+        colorMap.put("sienna", createColor(160, 82, 45));
+        colorMap.put("silver", createColor(192, 192, 192));
+        colorMap.put("skyblue", createColor(135, 206, 235));
+        colorMap.put("slateblue", createColor(106, 90, 205));
+        colorMap.put("slategray", createColor(112, 128, 144));
+        colorMap.put("slategrey", createColor(112, 128, 144));
+        colorMap.put("snow", createColor(255, 250, 250));
+        colorMap.put("springgreen", createColor(0, 255, 127));
+        colorMap.put("steelblue", createColor(70, 130, 180));
+        colorMap.put("tan", createColor(210, 180, 140));
+        colorMap.put("teal", createColor(0, 128, 128));
+        colorMap.put("thistle", createColor(216, 191, 216));
+        colorMap.put("tomato", createColor(255, 99, 71));
+        colorMap.put("turquoise", createColor(64, 224, 208));
+        colorMap.put("violet", createColor(238, 130, 238));
+        colorMap.put("wheat", createColor(245, 222, 179));
+        colorMap.put("white", createColor(255, 255, 255));
+        colorMap.put("whitesmoke", createColor(245, 245, 245));
+        colorMap.put("yellow", createColor(255, 255, 0));
+        colorMap.put("yellowgreen", createColor(154, 205, 50));
+        colorMap.put("transparent", new ColorWithAlternatives(0, 0, 0, 0, null));
     }
 
     /**
@@ -692,7 +970,8 @@ public final class ColorUtil {
      * @return true if the color profile name is of a built-in pseudo-profile
      */
     public static boolean isPseudoProfile(String colorProfileName) {
-        return CMYK_PSEUDO_PROFILE.equalsIgnoreCase(colorProfileName);
+        return CMYK_PSEUDO_PROFILE.equalsIgnoreCase(colorProfileName)
+                || SEPARATION_PSEUDO_PROFILE.equalsIgnoreCase(colorProfileName);
     }
 
     /**
@@ -710,11 +989,6 @@ public final class ColorUtil {
      * @return the CMYK color
      */
     public static Color toCMYKGrayColor(float black) {
-        float[] cmyk = new float[] {0f, 0f, 0f, 1.0f - black};
-        DeviceCMYKColorSpace cmykCs = ColorSpaces.getDeviceCMYKColorSpace();
-        float[] rgb = cmykCs.toRGB(cmyk);
-        return ColorExt.createFromFoRgbIcc(rgb[0], rgb[1], rgb[2],
-                CMYK_PSEUDO_PROFILE, null, cmykCs, cmyk);
+        return org.apache.xmlgraphics.java2d.color.ColorUtil.toCMYKGrayColor(black);
     }
-
 }

Modified: xmlgraphics/fop/trunk/status.xml
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/status.xml?rev=1069439&r1=1069438&r2=1069439&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/status.xml (original)
+++ xmlgraphics/fop/trunk/status.xml Thu Feb 10 15:58:57 2011
@@ -59,6 +59,12 @@
       documents. Example: the fix of marks layering will be such a case when it's done.
     -->
     <release version="FOP Trunk" date="TBD">
+      <action context="Renderers" dev="JM" type="add">
+        Added support for CIE Lab colors (from XSL-FO 2.0 WD).
+      </action>
+      <action context="Renderers" dev="JM" type="add" fixes-bug="49403" due-to="Patrick Jaromin">
+        Initial work on spot colors (aka named colors) for PDF output.
+      </action>
       <action context="Renderers" dev="JM" type="fix" fixes-bug="50705" due-to="Mehdi Houshmand">
         Fix to preserve the order of AFP TLEs and NOPs as given in the XSL-FO document.
       </action>

Modified: xmlgraphics/fop/trunk/test/java/org/apache/fop/traits/BorderPropsTestCase.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/test/java/org/apache/fop/traits/BorderPropsTestCase.java?rev=1069439&r1=1069438&r2=1069439&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/test/java/org/apache/fop/traits/BorderPropsTestCase.java (original)
+++ xmlgraphics/fop/trunk/test/java/org/apache/fop/traits/BorderPropsTestCase.java Thu Feb 10 15:58:57 2011
@@ -23,11 +23,10 @@ import java.awt.Color;
 
 import junit.framework.TestCase;
 
-import org.apache.xmlgraphics.java2d.color.ColorSpaces;
+import org.apache.xmlgraphics.java2d.color.ColorWithAlternatives;
 import org.apache.xmlgraphics.java2d.color.DeviceCMYKColorSpace;
 
 import org.apache.fop.fo.Constants;
-import org.apache.fop.util.ColorExt;
 import org.apache.fop.util.ColorUtil;
 
 /**
@@ -51,10 +50,10 @@ public class BorderPropsTestCase extends
         assertEquals(b1, b2);
 
         float[] cmyk = new float[] {1.0f, 1.0f, 0.5f, 1.0f};
-        DeviceCMYKColorSpace cmykCs = ColorSpaces.getDeviceCMYKColorSpace();
-        float[] rgb = cmykCs.toRGB(cmyk);
-        col = ColorExt.createFromFoRgbIcc(rgb[0], rgb[1], rgb[2],
-                "#CMYK", null, cmykCs, cmyk);
+        col = DeviceCMYKColorSpace.createCMYKColor(cmyk);
+        //Convert to sRGB with CMYK alternative as constructed by the cmyk() function
+        float[] rgb = col.getRGBColorComponents(null);
+        col = new ColorWithAlternatives(rgb[0], rgb[1], rgb[2], new Color[] {col});
         b1 = new BorderProps(Constants.EN_INSET, 9999,
                 col, BorderProps.SEPARATE);
         ser = b1.toString();

Modified: xmlgraphics/fop/trunk/test/java/org/apache/fop/util/ColorUtilTestCase.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/test/java/org/apache/fop/util/ColorUtilTestCase.java?rev=1069439&r1=1069438&r2=1069439&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/test/java/org/apache/fop/util/ColorUtilTestCase.java (original)
+++ xmlgraphics/fop/trunk/test/java/org/apache/fop/util/ColorUtilTestCase.java Thu Feb 10 15:58:57 2011
@@ -21,10 +21,14 @@ package org.apache.fop.util;
 
 import java.awt.Color;
 import java.awt.color.ColorSpace;
+import java.net.URI;
 
 import junit.framework.TestCase;
 
 import org.apache.xmlgraphics.java2d.color.ColorSpaces;
+import org.apache.xmlgraphics.java2d.color.ColorWithAlternatives;
+import org.apache.xmlgraphics.java2d.color.NamedColorSpace;
+import org.apache.xmlgraphics.java2d.color.RenderingIntent;
 
 import org.apache.fop.apps.FOUserAgent;
 import org.apache.fop.apps.FopFactory;
@@ -79,11 +83,14 @@ public class ColorUtilTestCase extends T
         assertEquals(col1, col2);
 
         col1 = ColorUtil.parseColorString(null, "fop-rgb-icc(0.5,0.5,0.5,#CMYK,,0.0,0.0,0.0,0.5)");
+        /* The following doesn't work since java.awt.Color from Sun doesn't round consistently
         col2 = ColorUtil.parseColorString(null, "cmyk(0.0,0.0,0.0,0.5)");
         assertEquals(col1, col2);
+        */
 
         col2 = ColorUtil.parseColorString(null, "fop-rgb-icc(0.5,0.5,0.5,#CMYK,,0.5,0.5,0.5,0.0)");
-        assertFalse(col1.equals(col2));
+        assertTrue(col1.equals(col2));
+        assertFalse(org.apache.xmlgraphics.java2d.color.ColorUtil.isSameColor(col1, col2));
     }
 
     /**
@@ -109,31 +116,39 @@ public class ColorUtilTestCase extends T
      */
     public void testRGBICC() throws Exception {
         FopFactory fopFactory = FopFactory.newInstance();
-        ColorSpace cs = fopFactory.getColorSpace(null,
-                "src/java/org/apache/fop/pdf/sRGB Color Space Profile.icm");
-        assertNotNull(cs);
-
+        URI sRGBLoc = new URI(
+                "file:src/java/org/apache/fop/pdf/sRGB%20Color%20Space%20Profile.icm");
+        ColorSpace cs = fopFactory.getColorSpaceCache().get(
+                "sRGBAlt", null, sRGBLoc.toASCIIString(), RenderingIntent.AUTO);
+        assertNotNull("Color profile not found", cs);
 
         FOUserAgent ua = fopFactory.newFOUserAgent();
-        ColorExt colActual;
+        ColorWithFallback colActual;
 
         //fop-rgb-icc() is used instead of rgb-icc() inside FOP!
         String colSpec = "fop-rgb-icc(1.0,0.0,0.0,sRGBAlt,"
-            + "\"src/java/org/apache/fop/pdf/sRGB Color Space Profile.icm\",1.0,0.0,0.0)";
-        colActual = (ColorExt)ColorUtil.parseColorString(ua, colSpec);
-        //assertEquals(255, colActual.getRed()); //253 is returned
-        //assertEquals(24, colActual.getGreen()); //24 is returned
+            + "\"" + sRGBLoc.toASCIIString() + "\",1.0,0.0,0.0)";
+        colActual = (ColorWithFallback)ColorUtil.parseColorString(ua, colSpec);
+        assertEquals(cs, colActual.getColorSpace());
+        assertEquals(255, colActual.getRed(), 2f); //Java 5: 253, Java 6: 255
+        assertEquals(0, colActual.getGreen(), 25f); //Java 5: 25, Java 6: 0
+        assertEquals(0, colActual.getBlue());
         //I don't understand the difference. Maybe Java's sRGB and HP's sRGB are somehow not
         //equivalent. This is only going to be a problem if anyone actually makes use of the
         //RGB fallback in any renderer.
         //TODO Anyone know what's going on here?
-        assertEquals(0, colActual.getBlue());
-        assertEquals(cs, colActual.getColorSpace());
         float[] comps = colActual.getColorComponents(null);
         assertEquals(3, comps.length);
         assertEquals(1f, comps[0], 0);
         assertEquals(0f, comps[1], 0);
         assertEquals(0f, comps[2], 0);
+        assertEquals(0, colActual.getAlternativeColors().length);
+
+        Color fallback = colActual.getFallbackColor();
+        assertTrue(fallback.getColorSpace().isCS_sRGB());
+        assertEquals(255, fallback.getRed());
+        assertEquals(0, fallback.getGreen());
+        assertEquals(0, fallback.getBlue());
 
         assertEquals(colSpec, ColorUtil.colorToString(colActual));
 
@@ -148,16 +163,17 @@ public class ColorUtilTestCase extends T
      * @throws Exception if an error occurs
      */
     public void testCMYK() throws Exception {
-        ColorExt colActual;
+        ColorWithAlternatives colActual;
         String colSpec;
 
         colSpec = "cmyk(0.0, 0.0, 1.0, 0.0)";
-        colActual = (ColorExt)ColorUtil.parseColorString(null, colSpec);
+        colActual = (ColorWithAlternatives)ColorUtil.parseColorString(null, colSpec);
         assertEquals(255, colActual.getRed());
         assertEquals(255, colActual.getGreen());
         assertEquals(0, colActual.getBlue());
-        assertEquals(ColorSpaces.getDeviceCMYKColorSpace(), colActual.getColorSpace());
-        float[] comps = colActual.getColorComponents(null);
+        Color alt = colActual.getAlternativeColors()[0];
+        assertEquals(ColorSpaces.getDeviceCMYKColorSpace(), alt.getColorSpace());
+        float[] comps = alt.getColorComponents(null);
         assertEquals(4, comps.length);
         assertEquals(0f, comps[0], 0);
         assertEquals(0f, comps[1], 0);
@@ -167,12 +183,13 @@ public class ColorUtilTestCase extends T
                 ColorUtil.colorToString(colActual));
 
         colSpec = "cmyk(0.0274, 0.2196, 0.3216, 0.0)";
-        colActual = (ColorExt)ColorUtil.parseColorString(null, colSpec);
-        assertEquals(248, colActual.getRed());
-        assertEquals(199, colActual.getGreen());
-        assertEquals(172, colActual.getBlue());
-        assertEquals(ColorSpaces.getDeviceCMYKColorSpace(), colActual.getColorSpace());
-        comps = colActual.getColorComponents(null);
+        colActual = (ColorWithAlternatives)ColorUtil.parseColorString(null, colSpec);
+        assertEquals(248, colActual.getRed(), 1);
+        assertEquals(199, colActual.getGreen(), 1);
+        assertEquals(172, colActual.getBlue(), 1);
+        alt = colActual.getAlternativeColors()[0];
+        assertEquals(ColorSpaces.getDeviceCMYKColorSpace(), alt.getColorSpace());
+        comps = alt.getColorComponents(null);
         assertEquals(0.0274f, comps[0], 0.001);
         assertEquals(0.2196f, comps[1], 0.001);
         assertEquals(0.3216f, comps[2], 0.001);
@@ -181,12 +198,13 @@ public class ColorUtilTestCase extends T
                 ColorUtil.colorToString(colActual));
 
         colSpec = "fop-rgb-icc(1.0,1.0,0.0,#CMYK,,0.0,0.0,1.0,0.0)";
-        colActual = (ColorExt)ColorUtil.parseColorString(null, colSpec);
+        colActual = (ColorWithAlternatives)ColorUtil.parseColorString(null, colSpec);
         assertEquals(255, colActual.getRed());
         assertEquals(255, colActual.getGreen());
         assertEquals(0, colActual.getBlue());
-        assertEquals(ColorSpaces.getDeviceCMYKColorSpace(), colActual.getColorSpace());
-        comps = colActual.getColorComponents(null);
+        alt = colActual.getAlternativeColors()[0];
+        assertEquals(ColorSpaces.getDeviceCMYKColorSpace(), alt.getColorSpace());
+        comps = alt.getColorComponents(null);
         assertEquals(4, comps.length);
         assertEquals(0f, comps[0], 0);
         assertEquals(0f, comps[1], 0);
@@ -196,12 +214,13 @@ public class ColorUtilTestCase extends T
                 ColorUtil.colorToString(colActual));
 
         colSpec = "fop-rgb-icc(0.5,0.5,0.5,#CMYK,,0.0,0.0,0.0,0.5)";
-        colActual = (ColorExt)ColorUtil.parseColorString(null, colSpec);
-        assertEquals(127, colActual.getRed());
-        assertEquals(127, colActual.getGreen());
-        assertEquals(127, colActual.getBlue());
-        assertEquals(ColorSpaces.getDeviceCMYKColorSpace(), colActual.getColorSpace());
-        comps = colActual.getColorComponents(null);
+        colActual = (ColorWithAlternatives)ColorUtil.parseColorString(null, colSpec);
+        assertEquals(127, colActual.getRed(), 1);
+        assertEquals(127, colActual.getGreen(), 1);
+        assertEquals(127, colActual.getBlue(), 1);
+        alt = colActual.getAlternativeColors()[0];
+        assertEquals(ColorSpaces.getDeviceCMYKColorSpace(), alt.getColorSpace());
+        comps = alt.getColorComponents(null);
         assertEquals(4, comps.length);
         assertEquals(0f, comps[0], 0);
         assertEquals(0f, comps[1], 0);
@@ -209,6 +228,97 @@ public class ColorUtilTestCase extends T
         assertEquals(0.5f, comps[3], 0);
         assertEquals("fop-rgb-icc(0.5,0.5,0.5,#CMYK,,0.0,0.0,0.0,0.5)",
                 ColorUtil.colorToString(colActual));
+
+        //Verify that the cmyk() and fop-rgb-icc(#CMYK) functions have the same results
+        ColorWithAlternatives colCMYK = (ColorWithAlternatives)ColorUtil.parseColorString(
+                null, "cmyk(0,0,0,0.5)");
+        assertEquals(colCMYK.getAlternativeColors()[0], colActual.getAlternativeColors()[0]);
+        //The following doesn't work:
+        //assertEquals(colCMYK, colActual);
+        //java.awt.Color does not consistenly calculate the int RGB values:
+        //Color(ColorSpace cspace, float components[], float alpha): 0.5 --> 127
+        //Color(float r, float g, float b): 0.5 --> 128
+        if (!colCMYK.equals(colActual)) {
+            System.out.println("Info: java.awt.Color does not consistently calculate"
+                    + " int RGB values from float RGB values.");
+        }
     }
 
+    /**
+     * Tests color for the #Separation pseudo-colorspace.
+     * @throws Exception if an error occurs
+     */
+    public void testSeparationColor() throws Exception {
+        ColorWithFallback colActual;
+        String colSpec;
+
+        colSpec = "fop-rgb-icc(1.0,0.8,0.0,#Separation,,Postgelb)";
+        colActual = (ColorWithFallback)ColorUtil.parseColorString(null, colSpec);
+        assertEquals(255, colActual.getRed(), 5);
+        assertEquals(204, colActual.getGreen(), 3);
+        assertEquals(0, colActual.getBlue(), 12);
+        //sRGB results differ between JDKs
+
+        Color fallback = colActual.getFallbackColor();
+        assertEquals(255, fallback.getRed());
+        assertEquals(204, fallback.getGreen());
+        assertEquals(0, fallback.getBlue());
+
+        assertFalse(colActual.hasAlternativeColors());
+
+        assertTrue(colActual.getColorSpace() instanceof NamedColorSpace);
+        NamedColorSpace ncs;
+        ncs = (NamedColorSpace)colActual.getColorSpace();
+        assertEquals("Postgelb", ncs.getColorName());
+        float[] comps = colActual.getColorComponents(null);
+        assertEquals(1, comps.length);
+        assertEquals(1f, comps[0], 0);
+        assertEquals(colSpec, ColorUtil.colorToString(colActual));
+
+    }
+
+    /**
+     * Tests the fop-rgb-named-color() function.
+     * @throws Exception if an error occurs
+     */
+    public void testNamedColorProfile() throws Exception {
+        FopFactory fopFactory = FopFactory.newInstance();
+        URI ncpLoc = new URI("file:test/resources/color/ncp-example.icc");
+        ColorSpace cs = fopFactory.getColorSpaceCache().get(
+                "NCP", null, ncpLoc.toASCIIString(), RenderingIntent.AUTO);
+        assertNotNull("Color profile not found", cs);
+
+        FOUserAgent ua = fopFactory.newFOUserAgent();
+        ColorWithFallback colActual;
+
+        //fop-rgb-named-color() is used instead of rgb-named-color() inside FOP!
+        String colSpec = "fop-rgb-named-color(1.0,0.8,0.0,NCP,"
+            + "\"" + ncpLoc.toASCIIString() + "\",Postgelb)";
+        colActual = (ColorWithFallback)ColorUtil.parseColorString(ua, colSpec);
+        assertEquals(255, colActual.getRed(), 2);
+        assertEquals(193, colActual.getGreen(), 2);
+        assertEquals(0, colActual.getBlue());
+
+        Color fallback = colActual.getFallbackColor();
+        assertEquals(255, fallback.getRed());
+        assertEquals(204, fallback.getGreen());
+        assertEquals(0, fallback.getBlue());
+        assertEquals(ColorSpace.getInstance(ColorSpace.CS_sRGB), fallback.getColorSpace());
+
+        float[] comps = fallback.getColorComponents(null);
+        assertEquals(3, comps.length);
+        assertEquals(1f, comps[0], 0);
+        assertEquals(0.8f, comps[1], 0);
+        assertEquals(0f, comps[2], 0);
+
+        assertTrue(colActual.getColorSpace() instanceof NamedColorSpace);
+        NamedColorSpace ncs;
+        ncs = (NamedColorSpace)colActual.getColorSpace();
+        assertEquals("Postgelb", ncs.getColorName());
+        comps = colActual.getColorComponents(null);
+        assertEquals(1, comps.length);
+        assertEquals(1f, comps[0], 0);
+
+        assertEquals(colSpec, ColorUtil.colorToString(colActual));
+    }
 }



---------------------------------------------------------------------
To unsubscribe, e-mail: fop-commits-unsubscribe@xmlgraphics.apache.org
For additional commands, e-mail: fop-commits-help@xmlgraphics.apache.org