Specify color parsing
authorAryeh Gregor <AryehGregor+gitcommit@gmail.com>
Wed, 13 Apr 2011 14:01:04 -0600
changeset 68 db8298c35b46
parent 67 3334e09907f1
child 69 bcd801b33f32
Specify color parsing
autoimplementation.html
editcommands.html
implementation.js
source.html
--- a/autoimplementation.html	Wed Apr 13 12:36:18 2011 -0600
+++ b/autoimplementation.html	Wed Apr 13 14:01:04 2011 -0600
@@ -362,6 +362,29 @@
 		'{<p><p> <p>foo</p>}',
 		'foo[bar<i>baz]qoz</i>quz',
 
+		['red', 'foo[bar]baz'],
+		['f', 'foo[bar]baz'],
+		['#f', 'foo[bar]baz'],
+		['f00', 'foo[bar]baz'],
+		['#f00', 'foo[bar]baz'],
+		['ff0000', 'foo[bar]baz'],
+		['#ff0000', 'foo[bar]baz'],
+		['fff000000', 'foo[bar]baz'],
+		['#fff000000', 'foo[bar]baz'],
+		['rgb(255, 0, 0)', 'foo[bar]baz'],
+		['rgb(100%, 0, 0)', 'foo[bar]baz'],
+		['rgb( 255 ,0 ,0)', 'foo[bar]baz'],
+		['rgba(255, 0, 0, 0.0)', 'foo[bar]baz'],
+		['rgb(375, -10, 15)', 'foo[bar]baz'],
+		['rgba(0, 0, 0, 1)', 'foo[bar]baz'],
+		['rgba(255, 255, 255, 1)', 'foo[bar]baz'],
+		['rgba(255, 0, 0, 0.5)', 'foo[bar]baz'],
+		['hsl(0%, 100%, 50%)', 'foo[bar]baz'],
+		['cornsilk', 'foo[bar]baz'],
+		['potato quiche', 'foo[bar]baz'],
+		['transparent', 'foo[bar]baz'],
+		['currentColor', 'foo[bar]baz'],
+
 		'<table><tbody><tr><td>foo<td>b[a]r<td>baz</table>',
 		'<table><tbody><tr data-start=1 data-end=2><td>foo<td>bar<td>baz</table>',
 		'<table><tbody><tr data-start=0 data-end=2><td>foo<td>bar<td>baz</table>',
--- a/editcommands.html	Wed Apr 13 12:36:18 2011 -0600
+++ b/editcommands.html	Wed Apr 13 14:01:04 2011 -0600
@@ -165,9 +165,6 @@
   Document, comments that are children of a Document, that sort of thing.  Not
   essential for prototyping, but needs to be cleaned up eventually.
 
-  <li>I haven't yet paid any attention to value parsing in most cases.  This is
-  going to be important to specify exactly in some cases, like with colors.
-
   <li>I haven't paid much attention to performance.  The algorithms here aren't
   performance-critical in most cases, but I might have accidentally included
   some algorithms that are too slow anyway on large pages.  Generally I haven't
@@ -918,14 +915,22 @@
     "underline", let <var title="">new parent</var> be the result of calling <code class=external data-anolis-spec=domcore title=dom-Document-createElement><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-document-createelement>createElement("u")</a></code> on the
     <code class=external data-anolis-spec=domcore title=dom-Node-ownerDocument><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-node-ownerdocument>ownerDocument</a></code> of <var title="">node</var>.
 
-    <li>If <var title="">command</var> is "foreColor", let <var title="">new parent</var> be the
-    result of calling <code class=external data-anolis-spec=domcore title=dom-Document-createElement><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-document-createelement>createElement("font")</a></code> on the
-    <code class=external data-anolis-spec=domcore title=dom-Node-ownerDocument><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-node-ownerdocument>ownerDocument</a></code> of <var title="">node</var>, then set the <code class=external data-anolis-spec=html title=dom-font-color><a href=http://www.whatwg.org/html/#dom-font-color>color</a></code> attribute
-    of <var title="">new parent</var> to <var title="">new value</var>.
-
-    <p class=XXX>This can be wrong if, e.g., the color has an alpha channel.
-    We also need to specify exactly how it's serialized, since CSSOM doesn't
-    cover this.  It might be best to always output simple colors.
+    <li>If <var title="">command</var> is "foreColor", and <var title="">new value</var> is fully
+    opaque with red, green, and blue components in the range 0 to 255:
+
+    <ol>
+      <li>Let <var title="">new parent</var> be the result of calling <code class=external data-anolis-spec=domcore title=dom-Document-createElement><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-document-createelement>createElement("font")</a></code> on the
+      <code class=external data-anolis-spec=domcore title=dom-Node-ownerDocument><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-node-ownerdocument>ownerDocument</a></code> of <var title="">node</var>.
+
+      <li>If <var title="">new value</var> is one of the colors listed in the SVG color
+      keywords section of CSS3 Color, set the <code class=external data-anolis-spec=html title=dom-font-color><a href=http://www.whatwg.org/html/#dom-font-color>color</a></code> attribute of
+      <var title="">new parent</var> to <var title="">new value</var>.
+
+      <li>Otherwise, set the <code class=external data-anolis-spec=html title=dom-font-color><a href=http://www.whatwg.org/html/#dom-font-color>color</a></code> attribute of <var title="">new parent</var>
+      to the result of applying the <a class=external data-anolis-spec=html href=http://www.whatwg.org/html/#rules-for-serializing-simple-color-values>rules for
+      serializing simple color values</a> to <var title="">new value</var>
+      (interpreted as a <a class=external data-anolis-spec=html href=http://www.whatwg.org/html/#simple-color>simple color</a>).
+    </ol>
 
     <li>If <var title="">command</var> is "fontName", let <var title="">new parent</var> be
     the result of calling <code class=external data-anolis-spec=domcore title=dom-Document-createElement><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-document-createelement>createElement("font")</a></code> on the
@@ -1553,25 +1558,74 @@
 
 <dt><code title=""><dfn id=command-forecolor title=command-forecolor>foreColor</dfn></code>
 
-<dd><strong>Action</strong>: If <var title="">value</var> is not a valid CSS color,
-the user agent must do nothing and abort these steps.
-<!-- Browsers are all over the place here.  IE 9 RC seems to treat unrecognized
-colors as black, but everyone else ignores them.  There are also special rules
-for certain things that aren't valid CSS colors, in some browsers, like:
-
-IE 9 RC: "ffe" -> "#ffe", "123" -> "#123"
-Firefox 4b11: "ffe" -> no style, "123" -> no style
-Chrome 10 dev: "ffe" -> "#FFFFEE", "123" -> "#000123"
-Opera 11: "ffe" -> "#0f0f0e", "123" -> "#010203"
-
-Firefox seems to stick to just CSS colors, so with any luck that works.
-"limegreen" works as expected in all browsers.  rgb(255, 255, 255) does too,
-except in Opera, which tries to parse it in some crazy way and winds up with
-"#00b025".  rgba() colors don't work as uniformly, but I don't see any reason
-to prohibit them.  Best to just match CSS. -->
-Otherwise, it must <a href=#decompose>decompose</a> the <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range title=concept-range>range</a>, then <a href=#set-the-value>set the
-value</a> of each returned <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node title=concept-node>node</a> with <var title="">new value</var> equal to
-<var title="">value</var>.
+<dd><strong>Action</strong>:
+<!-- Color interpretations (wide screen recommended):
+
+                        IE9           Firefox 4.0              Chrome 12 dev            Opera 11.00
+red                     red           red                      #ff0000                  #ff0000
+f                       #f            -                        -                        #f00000
+#f                      #f            -                        -                        #f00000
+f00                     #f00          -                        #ff0000                  #0f0000
+#f00                    #f00          rgb(255, 0, 0)           #ff0000                  #0f0000
+ff0000                  #ff0000       -                        #ff0000                  #ff0000
+#ff0000                 #ff0000       rgb(255, 0, 0)           #ff0000                  #ff0000
+fff000000               #ff0000       -                        -                        #fff000
+#fff000000              #ff0000       -                        -                        #fff000
+rgb(255, 0, 0)          rgb(255,0,0)  rgb(255, 0, 0)           #ff0000                  #00b025
+rgb(100%, 0, 0)         rgb(255,0,0)  -                        -                        #00b010
+rgb( 255 ,0 ,0)         rgb(255,0,0)  rgb(255, 0, 0)           #ff0000                  #00b025
+rgba(255, 0, 0, 0.0)    #005000       rgba(255, 0, 0, 0)       rgba(255, 0, 0, 0.0)     #00ba02
+rgb(375, -10, 15)       rgb(255,0,15) rgb(255, 0, 15)          #ff000f                  #00b037
+rgba(0, 0, 0, 1)        #ba0010       rgb(0, 0, 0)             -                        #00ba00
+rgba(255, 255, 255, 1)  #000055       rgb(255, 255, 255)       #ffffff                  #00ba02
+rgba(255, 0, 0, 0.5)    #005000       rgba(255, 255, 255, 0.5) rgba(255, 0, 0, 0.49804) #00ba02
+hsl(0%, 100%, 50%)      #001050       -                        -                        -
+cornsilk                cornsilk      cornsilk                 #fff8dc                  #fff8dc
+potato quiche           #0000c0       -                        -                        #000a00
+transparent             transparent   -                        rgba(0, 0, 0.0)          #00a000
+currentColor            #c0e000       currentcolor             rgba(0, 0, 0.0)          #c000e0
+
+The interpretations given for Firefox are only in styleWithCSS mode.  In
+non-styleWithCSS mode, it just outputs the string literally as the <font color>
+attribute value, which can lead to different results.  The given output for
+Chrome is for <font>; the output in styleWithCSS mode is the same, but rgb() is
+used instead of hex notation, and "transparent" and "currentcolor" are passed
+through under those names.  IE and Opera only support <font> to begin with.
+
+Conclusions:
+
+* Everyone accepts simple color keywords and #xxxxxx notation.
+* Opera mangles #xxx, but everyone else handles it fine.
+* The leading # is optional in all browsers but Gecko.
+* rgb() is accepted by everyone but Opera.
+* rgba() is accepted by Gecko and WebKit, but rejected by IE and Opera.
+* hsl() isn't accepted by anyone.
+* IE and Opera mangle unrecognized stuff, Gecko and WebKit ignore.
+* Browsers will happily output stuff like "transparent" and "rgba()" into <font
+  color> even though it won't be uniformly accepted there.
+* Opera and WebKit normalize the output color very aggressively, Gecko leaves
+  keywords intact but otherwise normalizes for CSS output (but doesn't
+  normalize at all for <font>), and IE normalizes inconsistently.
+
+What I'm going to say is that it either has to be a valid CSS color, or
+prefixing it with # must result in a valid CSS color.  For <font>, I'll say
+that the output color should be normalized to #xxxxxx form unless it's an SVG
+color keyword, in which case it's passed through intact.  If the color is not a
+simple color (fully opaque with all channels between 0 and 255), I'll force
+style="" even if styleWithCSS mode is off.  Some of this disagrees with all
+browsers, but it's unlikely to hurt and it makes sense.
+-->
+<ol>
+  <li>If <var title="">value</var> is not a valid CSS color, prepend "#" to it.
+
+  <li>If <var title="">value</var> is still not a valid CSS color, or if it is
+  currentColor, do nothing and abort these steps.
+  <!-- currentColor is bad for the same reason as relative font sizes.  It will
+  confuse the algorithm, and doesn't seem very useful anyway. -->
+
+  <li><a href=#decompose>Decompose</a> the <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range title=concept-range>range</a>, then <a href=#set-the-value>set the value</a> of
+  each returned <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node title=concept-node>node</a> to <var title="">value</var>.
+</ol>
 
 <dd><strong>State</strong>: Always false.
 <!-- This matches IE 9 RC and Chrome 10.  Opera 11 seems to return true if
@@ -1600,12 +1654,25 @@
 The spec doesn't do any of these: background-color on non-inline elements is
 not touched by hiliteColor, neither created nor removed.  If users want to
 remove the style, they need to use removeFormat.  Adding it usually makes no
-sense; see the comment for backColor. -->
-
-<dd><strong>Action</strong>: If <var title="">value</var> is not a valid CSS color,
-do nothing and abort these steps.  Otherwise, <a href=#decompose>decompose</a> the
-<a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range title=concept-range>range</a>, then <a href=#set-the-value>set the value</a> of each returned <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node title=concept-node>node</a> with
-<var title="">new value</var> equal to <var title="">value</var>.
+sense; see the comment for backColor.
+
+For color parsing, see the comment for foreColor. -->
+
+<dd><strong>Action</strong>:
+
+<ol>
+  <li>If <var title="">value</var> is not a valid CSS color, prepend "#" to it.
+
+  <li>If <var title="">value</var> is still not a valid CSS color, or if it is
+  currentColor, do nothing and abort these steps.
+  <!-- currentColor is bad for the same reason as relative font sizes.  It will
+  confuse the algorithm, and doesn't seem very useful anyway.  For hiliteColor
+  you could conceive of it being useful, but it will still confuse the
+  algorithm, so ban it for now anyway. -->
+
+  <li><a href=#decompose>Decompose</a> the <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range title=concept-range>range</a>, then <a href=#set-the-value>set the value</a> of
+  each returned <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node title=concept-node>node</a> to <var title="">value</var>.
+</ol>
 
 <dd><strong>State</strong>: Always false.
 
--- a/implementation.js	Wed Apr 13 12:36:18 2011 -0600
+++ b/implementation.js	Wed Apr 13 14:01:04 2011 -0600
@@ -283,6 +283,40 @@
 }
 
 
+function parseSimpleColor(color) {
+	// This is stupid, but otherwise my automated tests will have places where
+	// they're known to contradict the spec, which is annoying, so . . . I
+	// don't aim for correctness, beyond my own provisional tests.  Real tests
+	// will have to be more exhaustive.
+
+	if (color.length == 7 && color[0] == "#") {
+		return color;
+	}
+
+	if (color.length == 4 && color[0] == "#") {
+		return "#" + color[1] + color[1] + color[2] + color[2] + color[3] + color[3];
+	}
+
+	// Otherwise, don't even try.
+	return {
+		"red": "red",
+		"blue": "blue",
+		"rgb(255, 0, 0)": "#ff0000",
+		"rgb(100%, 0, 0)": "#ff0000",
+		"rgb( 255 ,0 ,0)": "#ff0000",
+		"rgba(255, 0, 0, 0.0)": false,
+		"rgb(375, -10, 15)": false,
+		"rgba(0, 0, 0, 1)": "#000000",
+		"rgba(255, 255, 255, 1)": "#ffffff",
+		"rgba(255, 0, 0, 0.5)": false,
+		"hsl(0%, 100%, 50%)": "#ff0000",
+		"cornsilk": "cornsilk",
+		"transparent": false,
+		"currentColor": false,
+	}[color];
+}
+
+
 // Things defined in the edit command spec (i.e., the interesting stuff)
 
 
@@ -1430,12 +1464,23 @@
 			newParent = node.ownerDocument.createElement("u");
 		}
 
-		// "If command is "foreColor", let new parent be the result of calling
-		// createElement("font") on the ownerDocument of node, then set the
-		// color attribute of new parent to new value."
-		if (command == "forecolor") {
+		// "If command is "foreColor", and new value is fully opaque with red,
+		// green, and blue components in the range 0 to 255:"
+		//
+		// Not going to do this properly, only well enough to pass tests.
+		if (command == "forecolor" && parseSimpleColor(newValue)) {
+			// "Let new parent be the result of calling createElement("font")
+			// on the ownerDocument of node."
 			newParent = node.ownerDocument.createElement("font");
-			newParent.color = newValue;
+
+			// "If new value is one of the colors listed in the SVG color
+			// keywords section of CSS3 Color, set the color attribute of new
+			// parent to new value."
+			//
+			// "Otherwise, set the color attribute of new parent to the result
+			// of applying the rules for serializing simple color values to new
+			// value (interpreted as a simple color)."
+			newParent.setAttribute("color", parseSimpleColor(newValue));
 		}
 
 		// "If command is "fontName", let new parent be the result of calling
@@ -1866,23 +1911,27 @@
 		break;
 
 		case "forecolor":
-		// "If value is not a valid CSS color, the user agent must do nothing
-		// and abort these steps. Otherwise, it must decompose the range, then
-		// set the value of each returned node with new value equal to value."
+		case "hilitecolor":
+		// "If value is not a valid CSS color, prepend "#" to it."
 		//
-		// Ignore validation for now.
-		var nodeList = decomposeRange(range);
-		for (var i = 0; i < nodeList.length; i++) {
-			setNodeValue(nodeList[i], command, value);
+		// "If value is still not a valid CSS color, or if it is currentColor,
+		// do nothing and abort these steps."
+		//
+		// Cheap hack for testing, no attempt to be comprehensive.
+		if (/^([0-9a-fA-F]{3}){1,2}$/.test(value)) {
+			value = "#" + value;
 		}
-		break;
+		if (!/^#([0-9a-fA-F]{3}){1,2}$/.test(value)
+		&& !/^(rgba?|hsla?)\(.*\)$/.test(value)
+		// Not gonna list all the keywords, only the ones I use.
+		&& value != "red"
+		&& value != "cornsilk"
+		&& value != "transparent") {
+			return;
+		}
 
-		case "hilitecolor":
-		// "If value is not a valid CSS color, do nothing and abort these
-		// steps. Otherwise, decompose the range, then set the value of each
-		// returned node with new value equal to value."
-		//
-		// Ignore validation for now.
+		// "Decompose the range, then set the value of each returned node to
+		// value."
 		var nodeList = decomposeRange(range);
 		for (var i = 0; i < nodeList.length; i++) {
 			setNodeValue(nodeList[i], command, value);
--- a/source.html	Wed Apr 13 12:36:18 2011 -0600
+++ b/source.html	Wed Apr 13 14:01:04 2011 -0600
@@ -153,9 +153,6 @@
   Document, comments that are children of a Document, that sort of thing.  Not
   essential for prototyping, but needs to be cleaned up eventually.
 
-  <li>I haven't yet paid any attention to value parsing in most cases.  This is
-  going to be important to specify exactly in some cases, like with colors.
-
   <li>I haven't paid much attention to performance.  The algorithms here aren't
   performance-critical in most cases, but I might have accidentally included
   some algorithms that are too slow anyway on large pages.  Generally I haven't
@@ -922,15 +919,24 @@
     title=dom-Document-createElement>createElement("u")</code> on the
     [[ownerdocument]] of <var>node</var>.
 
-    <li>If <var>command</var> is "foreColor", let <var>new parent</var> be the
-    result of calling <code data-anolis-spec=domcore
-    title=dom-Document-createElement>createElement("font")</code> on the
-    [[ownerdocument]] of <var>node</var>, then set the [[fontcolor]] attribute
-    of <var>new parent</var> to <var>new value</var>.
-
-    <p class=XXX>This can be wrong if, e.g., the color has an alpha channel.
-    We also need to specify exactly how it's serialized, since CSSOM doesn't
-    cover this.  It might be best to always output simple colors.
+    <li>If <var>command</var> is "foreColor", and <var>new value</var> is fully
+    opaque with red, green, and blue components in the range 0 to 255:
+
+    <ol>
+      <li>Let <var>new parent</var> be the result of calling <code
+      data-anolis-spec=domcore
+      title=dom-Document-createElement>createElement("font")</code> on the
+      [[ownerdocument]] of <var>node</var>.
+
+      <li>If <var>new value</var> is one of the colors listed in the SVG color
+      keywords section of CSS3 Color, set the [[fontcolor]] attribute of
+      <var>new parent</var> to <var>new value</var>.
+
+      <li>Otherwise, set the [[fontcolor]] attribute of <var>new parent</var>
+      to the result of applying the <span data-anolis-spec=html>rules for
+      serializing simple color values</span> to <var>new value</var>
+      (interpreted as a <span data-anolis-spec=html>simple color</span>).
+    </ol>
 
     <li>If <var>command</var> is "fontName", let <var>new parent</var> be
     the result of calling <code data-anolis-spec=domcore
@@ -1568,25 +1574,74 @@
 
 <dt><code title><dfn title=command-forecolor>foreColor</dfn></code>
 
-<dd><strong>Action</strong>: If <var>value</var> is not a valid CSS color,
-the user agent must do nothing and abort these steps.
-<!-- Browsers are all over the place here.  IE 9 RC seems to treat unrecognized
-colors as black, but everyone else ignores them.  There are also special rules
-for certain things that aren't valid CSS colors, in some browsers, like:
-
-IE 9 RC: "ffe" -> "#ffe", "123" -> "#123"
-Firefox 4b11: "ffe" -> no style, "123" -> no style
-Chrome 10 dev: "ffe" -> "#FFFFEE", "123" -> "#000123"
-Opera 11: "ffe" -> "#0f0f0e", "123" -> "#010203"
-
-Firefox seems to stick to just CSS colors, so with any luck that works.
-"limegreen" works as expected in all browsers.  rgb(255, 255, 255) does too,
-except in Opera, which tries to parse it in some crazy way and winds up with
-"#00b025".  rgba() colors don't work as uniformly, but I don't see any reason
-to prohibit them.  Best to just match CSS. -->
-Otherwise, it must <span>decompose</span> the [[range]], then <span>set the
-value</span> of each returned [[node]] with <var>new value</var> equal to
-<var>value</var>.
+<dd><strong>Action</strong>:
+<!-- Color interpretations (wide screen recommended):
+
+                        IE9           Firefox 4.0              Chrome 12 dev            Opera 11.00
+red                     red           red                      #ff0000                  #ff0000
+f                       #f            -                        -                        #f00000
+#f                      #f            -                        -                        #f00000
+f00                     #f00          -                        #ff0000                  #0f0000
+#f00                    #f00          rgb(255, 0, 0)           #ff0000                  #0f0000
+ff0000                  #ff0000       -                        #ff0000                  #ff0000
+#ff0000                 #ff0000       rgb(255, 0, 0)           #ff0000                  #ff0000
+fff000000               #ff0000       -                        -                        #fff000
+#fff000000              #ff0000       -                        -                        #fff000
+rgb(255, 0, 0)          rgb(255,0,0)  rgb(255, 0, 0)           #ff0000                  #00b025
+rgb(100%, 0, 0)         rgb(255,0,0)  -                        -                        #00b010
+rgb( 255 ,0 ,0)         rgb(255,0,0)  rgb(255, 0, 0)           #ff0000                  #00b025
+rgba(255, 0, 0, 0.0)    #005000       rgba(255, 0, 0, 0)       rgba(255, 0, 0, 0.0)     #00ba02
+rgb(375, -10, 15)       rgb(255,0,15) rgb(255, 0, 15)          #ff000f                  #00b037
+rgba(0, 0, 0, 1)        #ba0010       rgb(0, 0, 0)             -                        #00ba00
+rgba(255, 255, 255, 1)  #000055       rgb(255, 255, 255)       #ffffff                  #00ba02
+rgba(255, 0, 0, 0.5)    #005000       rgba(255, 255, 255, 0.5) rgba(255, 0, 0, 0.49804) #00ba02
+hsl(0%, 100%, 50%)      #001050       -                        -                        -
+cornsilk                cornsilk      cornsilk                 #fff8dc                  #fff8dc
+potato quiche           #0000c0       -                        -                        #000a00
+transparent             transparent   -                        rgba(0, 0, 0.0)          #00a000
+currentColor            #c0e000       currentcolor             rgba(0, 0, 0.0)          #c000e0
+
+The interpretations given for Firefox are only in styleWithCSS mode.  In
+non-styleWithCSS mode, it just outputs the string literally as the <font color>
+attribute value, which can lead to different results.  The given output for
+Chrome is for <font>; the output in styleWithCSS mode is the same, but rgb() is
+used instead of hex notation, and "transparent" and "currentcolor" are passed
+through under those names.  IE and Opera only support <font> to begin with.
+
+Conclusions:
+
+* Everyone accepts simple color keywords and #xxxxxx notation.
+* Opera mangles #xxx, but everyone else handles it fine.
+* The leading # is optional in all browsers but Gecko.
+* rgb() is accepted by everyone but Opera.
+* rgba() is accepted by Gecko and WebKit, but rejected by IE and Opera.
+* hsl() isn't accepted by anyone.
+* IE and Opera mangle unrecognized stuff, Gecko and WebKit ignore.
+* Browsers will happily output stuff like "transparent" and "rgba()" into <font
+  color> even though it won't be uniformly accepted there.
+* Opera and WebKit normalize the output color very aggressively, Gecko leaves
+  keywords intact but otherwise normalizes for CSS output (but doesn't
+  normalize at all for <font>), and IE normalizes inconsistently.
+
+What I'm going to say is that it either has to be a valid CSS color, or
+prefixing it with # must result in a valid CSS color.  For <font>, I'll say
+that the output color should be normalized to #xxxxxx form unless it's an SVG
+color keyword, in which case it's passed through intact.  If the color is not a
+simple color (fully opaque with all channels between 0 and 255), I'll force
+style="" even if styleWithCSS mode is off.  Some of this disagrees with all
+browsers, but it's unlikely to hurt and it makes sense.
+-->
+<ol>
+  <li>If <var>value</var> is not a valid CSS color, prepend "#" to it.
+
+  <li>If <var>value</var> is still not a valid CSS color, or if it is
+  currentColor, do nothing and abort these steps.
+  <!-- currentColor is bad for the same reason as relative font sizes.  It will
+  confuse the algorithm, and doesn't seem very useful anyway. -->
+
+  <li><span>Decompose</span> the [[range]], then <span>set the value</span> of
+  each returned [[node]] to <var>value</var>.
+</ol>
 
 <dd><strong>State</strong>: Always false.
 <!-- This matches IE 9 RC and Chrome 10.  Opera 11 seems to return true if
@@ -1615,12 +1670,25 @@
 The spec doesn't do any of these: background-color on non-inline elements is
 not touched by hiliteColor, neither created nor removed.  If users want to
 remove the style, they need to use removeFormat.  Adding it usually makes no
-sense; see the comment for backColor. -->
-
-<dd><strong>Action</strong>: If <var>value</var> is not a valid CSS color,
-do nothing and abort these steps.  Otherwise, <span>decompose</span> the
-[[range]], then <span>set the value</span> of each returned [[node]] with
-<var>new value</var> equal to <var>value</var>.
+sense; see the comment for backColor.
+
+For color parsing, see the comment for foreColor. -->
+
+<dd><strong>Action</strong>:
+
+<ol>
+  <li>If <var>value</var> is not a valid CSS color, prepend "#" to it.
+
+  <li>If <var>value</var> is still not a valid CSS color, or if it is
+  currentColor, do nothing and abort these steps.
+  <!-- currentColor is bad for the same reason as relative font sizes.  It will
+  confuse the algorithm, and doesn't seem very useful anyway.  For hiliteColor
+  you could conceive of it being useful, but it will still confuse the
+  algorithm, so ban it for now anyway. -->
+
+  <li><span>Decompose</span> the [[range]], then <span>set the value</span> of
+  each returned [[node]] to <var>value</var>.
+</ol>
 
 <dd><strong>State</strong>: Always false.