Commit masses of stuff
authorAryeh Gregor <AryehGregor+gitcommit@gmail.com>
Thu, 14 Jul 2011 12:24:49 -0600
changeset 424 3d003645df10
parent 423 bb55a5618600
child 425 84bc0c9e5e69
Commit masses of stuff

If I were expecting anyone to review this in detail, I'd probably break
it up into like ten commits. The major thing is a new concept of
state/value override is added, partially fixing an important todo and
making commands like bold work for collapsed selections. This will be
followed later by augmenting insertText to respect state/value for newly
inserted text. Stuff I happened to do in the course of that, in the
order it appears in the diff:

* Don't treat hiliteColor specially for IE now that we support
backColor.
* Record indeterm, state, and value in the execCommand() tests, and
sanity-check them with some useful invariants that now mostly hold
(after the overrides were added).
* Handle Firefox's insane treatment of backColor better.
* Make parseSimpleColor() vastly more robust.
* Link to the CSS3 extended color definitions.
* Add an XXX to foreColor, in a part that seems to be vague and/or not
match implementations.
* Update color-related tests to use blue and brown for test colors
instead of red and green, so it's easier to tell at a glance if the
new indeterm/state/value indicators are complaining.
* Fix my usage of percentage rgb() and of hsl(), which were both syntax
errors and therefore were not working. rgb() needs either all
arguments percentages or none of them, and hsl() needs the first
argument not a percentage.
* Remove long-outdated note claiming backColor isn't specced.
autoimplementation.html
editcommands.html
implementation.js
source.html
tests.css
tests.js
--- a/autoimplementation.html	Wed Jul 13 13:55:04 2011 -0600
+++ b/autoimplementation.html	Thu Jul 14 12:24:49 2011 -0600
@@ -156,11 +156,6 @@
 		test = test[1];
 	}
 
-	if (command == "hilitecolor" && navigator.userAgent.indexOf("MSIE") != -1) {
-		// IE behaves differently, and I want to see how it works.
-		command = "backcolor";
-	}
-
 	if (command == "hilitecolor") {
 		// Firefox refuses to do anything unless styleWithCSS is true.
 		styleWithCss = true;
@@ -187,8 +182,23 @@
 		try {
 			document.execCommand("styleWithCSS", false, styleWithCss);
 		} catch (e) {}
+
+		try { var beforeIndeterm = document.queryCommandIndeterm(command) }
+		catch(e) { beforeIndeterm = "Exception" }
+		try { var beforeState = document.queryCommandState(command) }
+		catch(e) { beforeState = "Exception" }
+		try { var beforeValue = document.queryCommandValue(command) }
+		catch(e) { beforeValue = "Exception" }
+
 		document.execCommand(command, false, value);
 
+		try { var afterIndeterm = document.queryCommandIndeterm(command) }
+		catch(e) { afterIndeterm = "Exception" }
+		try { var afterState = document.queryCommandState(command) }
+		catch(e) { afterState = "Exception" }
+		try { var afterValue = document.queryCommandValue(command) }
+		catch(e) { afterValue = "Exception" }
+
 		testDiv.contentEditable = "inherit";
 		testDiv.removeAttribute("spellcheck");
 		var compareDiv1 = testDiv.cloneNode(true);
@@ -230,7 +240,17 @@
 				browserCell.innerHTML.replace(/<div><\/div>$/, "");
 		}
 
+		if (document.body.hasAttribute("bgcolor")) {
+			var bgColor = document.body.getAttribute("bgcolor");
+			document.body.removeAttribute("bgcolor");
+			throw 'bgcolor="' + bgColor +'" added to body!';
+		}
+
 		browserCell.lastChild.textContent = browserCell.firstChild.innerHTML;
+		browserCell.lastChild.appendChild(queryOutputHelper(
+			beforeIndeterm, beforeState, beforeValue,
+			afterIndeterm, afterState, afterValue,
+			command, value));
 	} catch (e) {
 		browserCellException(e, testDiv, browserCell);
 	}
--- a/editcommands.html	Wed Jul 13 13:55:04 2011 -0600
+++ b/editcommands.html	Thu Jul 14 12:24:49 2011 -0600
@@ -60,7 +60,7 @@
 <body class=draft>
 <div class=head id=head>
 <h1>HTML Editing Commands</h1>
-<h2 class="no-num no-toc" id=work-in-progress-&mdash;-last-update-13-july-2011>Work in Progress &mdash; Last Update 13 July 2011</h2>
+<h2 class="no-num no-toc" id=work-in-progress-&mdash;-last-update-14-july-2011>Work in Progress &mdash; Last Update 14 July 2011</h2>
 <dl>
  <dt>Editor
  <dd>Aryeh Gregor &lt;<a href=mailto:ayg@aryeh.name>ayg@aryeh.name</a>&gt;
@@ -658,6 +658,9 @@
 
   <li>If <var title="">command</var> is not <a href=#enabled>enabled</a>, return false.
 
+  <li>If the <a href=#state-override>state override</a> for <var title="">command</var> is set, return
+  it.
+
   <li>Return true if <var title="">command</var>'s <a href=#state>state</a> is true, otherwise
   false.
 </ol>
@@ -694,12 +697,36 @@
   seems to return the string "false", and IE9 seems to return boolean false.
   -->
 
+  <li>If the <a href=#value-override>value override</a> for <var title="">command</var> is set, return
+  it.
+
   <li>Return <var title="">command</var>'s <a href=#value>value</a>.
 </ol>
 
 <p>All of these methods must treat their <var title="">command</var> argument <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#ascii-case-insensitive title="ASCII case-insensitive">ASCII
 case-insensitively</a>.
 
+<p>The methods in this section have been designed so that the following
+invariants hold after <code><a href=#execcommand()>execCommand()</a></code> is called, assuming it didn't
+throw an exception:
+
+<ul>
+  <li><code><a href=#querycommandindeterm()>queryCommandIndeterm()</a></code> will return false (or throw an
+  exception).
+
+  <li><code><a href=#querycommandstate()>queryCommandState()</a></code> will return the opposite of what it did
+  before <code><a href=#execcommand()>execCommand()</a></code> was called (or throw an exception).
+
+  <li><code><a href=#querycommandvalue()>queryCommandValue()</a></code> will return something equivalent to the
+  value passed to <code><a href=#execcommand()>execCommand()</a></code> (or throw an exception).
+  "Equivalent" here needs to be construed broadly in some cases, such as
+  <a href=#the-fontsize-command>the <code title="">fontSize</code> command</a>.
+</ul>
+
+<p>The first two points do not always hold for <a href=#the-strikethrough-command>the <code title="">strikethrough</code> command</a> or <a href=#the-underline-command>the <code title="">underline</code> command</a>, because it can be impossible to unset
+text-decoration in CSS, but all three points otherwise hold in all cases
+barring bugs.
+
 
 <h2 id=common-definitions><span class=secno>5 </span>Common definitions</h2>
 
@@ -824,6 +851,17 @@
 means of the <code><a href=#execcommand()>execCommand()</a></code> and <code><a href=#querycommandstate()>queryCommandState()</a></code>
 methods.)
 
+<p>For some <a href=#command title=command>commands</a>, each <code class=external data-anolis-spec=html><a href=http://www.whatwg.org/html/#htmldocument>HTMLDocument</a></code> must
+have a boolean <dfn id=state-override>state override</dfn> and/or a string <dfn id=value-override>value
+override</dfn>.  These do not change the <a href=#command>command</a>'s
+<a href=#state>state</a> or <a href=#value>value</a>, but change the way some algorithms
+behave, as specified in those algorithms' definitions.  Initially, both must be
+unset for every <a href=#command>command</a>.  Whenever the number of <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range title=concept-range>ranges</a> in the
+<code class=external data-anolis-spec=domrange><a href=http://html5.org/specs/dom-range.html#selection>Selection</a></code> changes to something different, and whenever a <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-boundary-point title=concept-boundary-point>boundary point</a>
+of the <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range title=concept-range>range</a> at a given index in the <code class=external data-anolis-spec=domrange><a href=http://html5.org/specs/dom-range.html#selection>Selection</a></code> changes to something
+different, the <a href=#state-override>state override</a> and <a href=#value-override>value override</a> must
+be unset for every <a href=#command>command</a>.
+
 <p>When the user agent is instructed to run a particular method, it must follow
 the steps defined for that method in the appropriate specification, not act as
 though the method had actually been called from JavaScript.  In particular,
@@ -1961,14 +1999,18 @@
 
     <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:
+    <!-- See comment for foreColor for discussion. -->
+
+    <p class=XXX>Check this more carefully for what happens if the components
+    are not integers or are out-of-range.
 
     <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>If <var title="">new value</var> is an <a href=http://www.w3.org/TR/css3-color/#svg-color>extended color
+      keyword</a>, 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
@@ -2197,6 +2239,39 @@
 <ol>
   <li>Let <var title="">command</var> be the current <a href=#command>command</a>.
 
+  <li>If there is no <a href=#editable>editable</a> <code class=external data-anolis-spec=domcore><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#text>Text</a></code> node <a href=#effectively-contained>effectively
+  contained</a> in the <a href=#active-range>active range</a>:
+
+  <ol>
+    <li>If <var title="">command</var> is in the following list, set the <a href=#state-override>state
+    override</a> appropriately:
+
+    <dl class=compact>
+      <dt>bold<dd>True if <var title="">new value</var> is not null and is greater than or equal
+      to 600, false otherwise.
+
+      <dt>italic<dd>True if <var title="">new value</var> is "italic" or "oblique", false
+      otherwise.
+
+      <dt>strikethrough<dd>True if <var title="">new value</var> is "line-through", false otherwise.
+
+      <dt>subscript<dd>True if <var title="">new value</var> is "sub", false otherwise.
+
+      <dt>superscript<dd>True if <var title="">new value</var> is "super", false otherwise.
+
+      <dt>underline<dd>True if <var title="">new value</var> is "underline", false otherwise.
+    </dl>
+
+    <li>If <var title="">command</var> has a <a href=#value>value</a> specified, unset the
+    <a href=#value-override>value override</a> if <var title="">new value</var> is null, and set the
+    <a href=#value-override>value override</a> to <var title="">new value</var> if it is not null.
+
+    <p class=XXX>This doesn't work as-is for fontSize, because that uses a
+    different format for the value.
+
+    <li>Abort these steps.
+  </ol>
+
   <li>If the <a href=#active-range>active range</a>'s <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range-start title=concept-range-start>start</a> <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-boundary-point-node title=concept-boundary-point-node>node</a> is an
   <a href=#editable>editable</a> <code class=external data-anolis-spec=domcore><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#text>Text</a></code> node, and its <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range-start title=concept-range-start>start</a> <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-boundary-point-offset title=concept-boundary-point-offset>offset</a> is neither zero
   nor its <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range-start title=concept-range-start>start</a> <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-boundary-point-node title=concept-boundary-point-node>node</a>'s <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-node-length title=concept-node-length>length</a>, call <code class=external data-anolis-spec=domcore title=dom-Text-splitText><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-text-splittext>splitText()</a></code> on the <a href=#active-range>active
@@ -2324,11 +2399,15 @@
 range</a>, there are two that have distinct <a href=#effective-command-value title="effective command
 value">effective command values</a>.  Otherwise false.
 
-<p><a href=#value>Value</a>: The <a href=#effective-command-value>effective command value</a> of the
-<a href=#active-range>active range</a>'s <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range-start title=concept-range-start>start</a> <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-boundary-point-node title=concept-boundary-point-node>node</a>.
-
-<p class=note>This cannot be null, since the boundary point node of a selection
-must always be either an element or a text node that's the child of an element.
+<p><a href=#value>Value</a>: The <a href=#effective-command-value>effective command value</a> of the first
+<a href=#editable>editable</a> <code class=external data-anolis-spec=domcore><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#text>Text</a></code> node that is <a href=#effectively-contained>effectively contained</a>
+in the <a href=#active-range>active range</a>, or if there is no such node, the
+<a href=#effective-command-value>effective command value</a> of the <a href=#active-range>active range</a>'s
+<a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range-start title=concept-range-start>start</a> <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-boundary-point-node title=concept-boundary-point-node>node</a>.
+
+<p class=note>The effective command value of the active range's start node
+cannot be null, since the boundary point node of a selection must always be
+either an element or a text node that's the child of an element.
 
 <p><a href=#relevant-css-property>Relevant CSS property</a>: "background-color"
 
@@ -2341,9 +2420,9 @@
 (fontName, italic, etc.).  Except not for strikethrough, where it just does
 nothing if the selection is empty.  Why strikethrough?  I don't know. -->
 
-<p><a href=#action>Action</a>: If the <a href=#state>state</a> is false, <a href="#set-the-selection's-value">set the
-selection's value</a> to "bold", otherwise <a href="#set-the-selection's-value">set the selection's
-value</a> to "normal".
+<p><a href=#action>Action</a>: If <code title=queryCommandState()><a href=#querycommandstate()>queryCommandState("bold")</a></code> returns true,
+<a href="#set-the-selection's-value">set the selection's value</a> to "normal".  Otherwise <a href="#set-the-selection's-value">set the
+selection's value</a> to "bold".
 
 <p><a href=#indeterminate>Indeterminate</a>: True if among <a href=#editable>editable</a> <code class=external data-anolis-spec=domcore><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#text>Text</a></code>
 nodes that are <a href=#effectively-contained>effectively contained</a> in the <a href=#active-range>active
@@ -2440,15 +2519,7 @@
   <li><a href="#set-the-selection's-value">Set the selection's value</a> to <var title="">value</var>.
 </ol>
 
-<!--
-The state is always false in Chrome 14 dev and Opera 11.11.  Firefox 6.0a2
-throws an exception, and IE9 seems to always either return false or throw an
-exception.  Therefore we make the state always false, although this doesn't
-seem very useful.
--->
-
-<!-- I'd have expected the value to be the URL, but guess not: it's always
-false. -->
+<p class=XXX>Define state and value, although browsers don't.
 
 
 <h3 id=the-fontname-command><span class=secno>7.10 </span><dfn>The <code title="">fontName</code> command</dfn></h3>
@@ -2482,12 +2553,17 @@
 value">effective command values</a>.  Otherwise false.
 <!-- This follows Firefox 6.0a2.  Chrome 14 dev always returns false. -->
 
-<p><a href=#value>Value</a>: The <a href=#effective-command-value>effective command value</a> of the
-<a href=#active-range>active range</a>'s <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range-start title=concept-range-start>start</a> <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-boundary-point-node title=concept-boundary-point-node>node</a>.
-
-<p class=note>This cannot be null, since the boundary point node of a selection
-must always be either an element or a text node that's the child of an element.
-<!-- Complicated.
+<p><a href=#value>Value</a>: The <a href=#effective-command-value>effective command value</a> of the first
+<a href=#editable>editable</a> <code class=external data-anolis-spec=domcore><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#text>Text</a></code> node that is <a href=#effectively-contained>effectively contained</a>
+in the <a href=#active-range>active range</a>, or if there is no such node, the
+<a href=#effective-command-value>effective command value</a> of the <a href=#active-range>active range</a>'s
+<a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range-start title=concept-range-start>start</a> <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-boundary-point-node title=concept-boundary-point-node>node</a>.
+
+<p class=note>The effective command value of the active range's start node
+cannot be null, since the boundary point node of a selection must always be
+either an element or a text node that's the child of an element.
+<!--
+Complicated.
 
 IE 9 RC: Always the empty string.  Not very useful.
 Firefox 4b11: Confusing.  Sometimes it returns generic family names, like
@@ -2502,7 +2578,10 @@
 
 I'm just going to punt on this and say it should be the resolved value of
 font-family.  I'll leave CSSOM to decide what that means if there are no
-applicable style rules. -->
+applicable style rules.
+
+For deciding which node should be checked, see comment for hiliteColor.
+-->
 
 <p><a href=#relevant-css-property>Relevant CSS property</a>: "font-family"
 
@@ -2644,11 +2723,16 @@
 -->
 <ol>
   <li>Let <var title="">pixel size</var> be the <a href=#effective-command-value>effective command value</a> of
-  the <a href=#active-range>active range</a>'s <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range-start title=concept-range-start>start</a> <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-boundary-point-node title=concept-boundary-point-node>node</a>, as a number of pixels.
-
-  <p class=note>The active range's start node cannot be null, since the
-  boundary point node of a selection must always be either an element or a text
-  node that's the child of an element.
+  the first <a href=#editable>editable</a> <code class=external data-anolis-spec=domcore><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#text>Text</a></code> node that is <a href=#effectively-contained>effectively
+  contained</a> in the <a href=#active-range>active range</a>, or if there is no such
+  node, the <a href=#effective-command-value>effective command value</a> of the <a href=#active-range>active
+  range</a>'s <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range-start title=concept-range-start>start</a> <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-boundary-point-node title=concept-boundary-point-node>node</a>, in either case interpreted as a number of
+  pixels.
+  <!-- See comment for hiliteColor on how I decided on this choice of node. -->
+
+  <p class=note>The effective command value of the active range's start node
+  cannot be null, since the boundary point node of a selection must always be
+  either an element or a text node that's the child of an element.
 
   <li>Let <var title="">returned size</var> be 1.
 
@@ -2684,29 +2768,29 @@
 
 <!-- Color interpretations (wide screen recommended):
 
-                        IE9           Firefox 4.0              Chrome 12 dev            Opera 11.00
-red                     red           red                      #ff0000                  #ff0000
+                        IE10PP2       Firefox 7.0a2            Chrome 14 dev            Opera 11.50
+blue                    blue          blue                     #0000ff                  #0000ff
 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
+00f                     #00f          -                        #0000ff                  #00000f
+#00f                    #00f          rgb(0, 0, 255)           #0000ff                  #00000f
+0000ff                  #0000ff       -                        #0000ff                  #0000ff
+#0000ff                 #0000ff       rgb(0, 0, 255)           #0000ff                  #0000ff
+000000fff               #0000ff       -                        -                        -
+#000000fff              #0000ff       -                        -                        -
+rgb(0, 0, 255)          rgb(0,0,255)  rgb(0, 0, 255)           #0000ff                  #00b000
+rgb(0%, 0%, 100%)       rgb(0,0,255)  rgb(0, 0, 255)           #0000ff                  #00b000
+rgb( 0 ,0 ,255)         rgb(0,0,255)  rgb(0, 0, 255)           #0000ff                  #00b000
+rgba(0, 0, 255, 0.0)    #ba0000       rgba(0, 0, 255, 0)       rgba(0, 0, 255, 0)       #00ba00
+rgb(15, -10, 375)       rgb(15,0,255) rgb(15, 0, 255)          #0f00ff                  #00b015
 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       -                        -                        -
+rgba(0, 0, 255, 0.5)    #ba0000       rgba(0, 0, 255, 0.5)     rgba(0, 0, 255, 0.5)     #00ba00
+hsl(240, 100%, 50%)     #000150       rgb(0, 0, 255)           #0000ff                  #000024
 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
+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>
@@ -2721,8 +2805,8 @@
 * 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.
+* rgba() and hsl() are accepted by Gecko and WebKit, but rejected by IE and
+  Opera.
 * 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.
@@ -2759,18 +2843,25 @@
 value">effective command values</a>.  Otherwise false.
 <!-- This follows Firefox 6.0a2.  Chrome 14 dev always returns false. -->
 
-<p><a href=#value>Value</a>: The <a href=#effective-command-value>effective command value</a> of the
-<a href=#active-range>active range</a>'s <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range-start title=concept-range-start>start</a> <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-boundary-point-node title=concept-boundary-point-node>node</a>.
-
-<p class=note>This cannot be null, since the boundary point node of a selection
-must always be either an element or a text node that's the child of an element.
+<p><a href=#value>Value</a>: The <a href=#effective-command-value>effective command value</a> of the first
+<a href=#editable>editable</a> <code class=external data-anolis-spec=domcore><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#text>Text</a></code> node that is <a href=#effectively-contained>effectively contained</a>
+in the <a href=#active-range>active range</a>, or if there is no such node, the
+<a href=#effective-command-value>effective command value</a> of the <a href=#active-range>active range</a>'s
+<a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range-start title=concept-range-start>start</a> <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-boundary-point-node title=concept-boundary-point-node>node</a>.
+
+<p class=note>The effective command value of the active range's start node
+cannot be null, since the boundary point node of a selection must always be
+either an element or a text node that's the child of an element.
 <!--
-The spec essentially matches Firefox 6.0a2 and Chrome 14 dev.  IE9 seems to
-always return the number 0 for some bizarre reason.  There are some cases where
-Firefox returns the empty string for some reason, and it seems to select the
-active node a little differently.  Opera uses #xxxxxx format for
-getComputedStyle() but rgb() here, and also drops the transparent part of the
-color if there is any.
+The spec essentially matches Firefox 6.0a2 and Chrome 14 dev, as far as how to
+decide what color the node has.  IE9 seems to always return the number 0 for
+some bizarre reason.  There are some cases where Firefox returns the empty
+string for some reason, and it seems to select the active node a little
+differently.  Opera uses #xxxxxx format for getComputedStyle() but rgb() here,
+and also drops the transparent part of the color if there is any.
+
+For why I chose this node to key the color off of, see the comment for
+hiliteColor.
 -->
 
 <p><a href=#relevant-css-property>Relevant CSS property</a>: "color"
@@ -2817,19 +2908,28 @@
 <!-- This follows no one.  Firefox 6.0a2 and Chrome 14 dev both always return
 false.  However, it makes sense. -->
 
-<p><a href=#value>Value</a>: The <a href=#effective-command-value>effective command value</a> of the
-<a href=#active-range>active range</a>'s <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range-start title=concept-range-start>start</a> <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-boundary-point-node title=concept-boundary-point-node>node</a>.
-
-<p class=note>This cannot be null, since the boundary point node of a selection
-must always be either an element or a text node that's the child of an element.
+<p><a href=#value>Value</a>: The <a href=#effective-command-value>effective command value</a> of the first
+<a href=#editable>editable</a> <code class=external data-anolis-spec=domcore><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#text>Text</a></code> node that is <a href=#effectively-contained>effectively contained</a>
+in the <a href=#active-range>active range</a>, or if there is no such node, the
+<a href=#effective-command-value>effective command value</a> of the <a href=#active-range>active range</a>'s
+<a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range-start title=concept-range-start>start</a> <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-boundary-point-node title=concept-boundary-point-node>node</a>.
+
+<p class=note>The effective command value of the active range's start node
+cannot be null, since the boundary point node of a selection must always be
+either an element or a text node that's the child of an element.
 <!--
-This seems to match Opera 11.11 exactly.  Chrome 14 dev returns boolean false
-consistently, bizarrely enough.  Firefox 6.0a2 seems to follow the same idea as
-the spec, but it likes to return "transparent", including sometimes when the
-answer really clearly should not be "transparent".  IE9 throws exceptions most
-of the time for backColor, so I can't say for sure, but in the few cases where
-it doesn't throw it returns a random-looking number, so I'll assume it's crazy
-like for foreColor.
+Opera 11.11 seems to always return the effective command value of the active
+range's start node.  Chrome 14 dev returns boolean false consistently,
+bizarrely enough.  Firefox 6.0a2 seems to follow the same idea as the spec, but
+it likes to return "transparent", including sometimes when the answer really
+clearly should not be "transparent".  IE9 throws exceptions most of the time
+for backColor, so I can't say for sure, but in the few cases where it doesn't
+throw it returns a random-looking number, so I'll assume it's crazy like for
+foreColor.
+
+I decided on something that would guarantee the following invariant: whenever
+you execute a command with a value provided (assuming value is relevant),
+queryCommandValue() will always return something equivalent to what you set.
 -->
 
 <p><a href=#relevant-css-property>Relevant CSS property</a>: "background-color"
@@ -2837,9 +2937,9 @@
 
 <h3 id=the-italic-command><span class=secno>7.14 </span><dfn>The <code title="">italic</code> command</dfn></h3>
 
-<p><a href=#action>Action</a>: If the <a href=#state>state</a> is false, <a href="#set-the-selection's-value">set the
-selection's value</a> to "italic", otherwise <a href="#set-the-selection's-value">set the selection's
-value</a> to "normal".
+<p><a href=#action>Action</a>: If <code title=queryCommandState()><a href=#querycommandstate()>queryCommandState("italic")</a></code> returns true,
+<a href="#set-the-selection's-value">set the selection's value</a> to "normal".  Otherwise <a href="#set-the-selection's-value">set the
+selection's value</a> to "italic".
 
 <p><a href=#indeterminate>Indeterminate</a>: True if among <a href=#editable>editable</a> <code class=external data-anolis-spec=domcore><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#text>Text</a></code>
 nodes that are <a href=#effectively-contained>effectively contained</a> in the <a href=#active-range>active
@@ -2983,9 +3083,9 @@
 
 <h3 id=the-strikethrough-command><span class=secno>7.16 </span><dfn>The <code title="">strikethrough</code> command</dfn></h3>
 
-<p><a href=#action>Action</a>: If the <a href=#state>state</a> is false, <a href="#set-the-selection's-value">set the
-selection's value</a> to "line-through", otherwise <a href="#set-the-selection's-value">set the selection's
-value</a> to null.
+<p><a href=#action>Action</a>: If <code title=queryCommandState()><a href=#querycommandstate()>queryCommandState("strikethrough")</a></code> returns
+true, <a href="#set-the-selection's-value">set the selection's value</a> to null.  Otherwise <a href="#set-the-selection's-value">set the
+selection's value</a> to "line-through".
 
 <!-- TODO: See underline TODO. -->
 
@@ -3006,7 +3106,8 @@
 <p><a href=#action>Action</a>:
 
 <ol>
-  <li>Let <var title="">state</var> be the <a href=#state>state</a>.
+  <li>Call <code title=queryCommandState()><a href=#querycommandstate()>queryCommandState("subscript")</a></code>, and let
+  <var title="">state</var> be the result.
 
   <li><a href="#set-the-selection's-value">Set the selection's value</a> to "baseline".
 
@@ -3046,7 +3147,8 @@
 <p><a href=#action>Action</a>:
 
 <ol>
-  <li>Let <var title="">state</var> be the <a href=#state>state</a>.
+  <li>Call <code title=queryCommandState()><a href=#querycommandstate()>queryCommandState("superscript")</a></code>, and let
+  <var title="">state</var> be the result.
 
   <li><a href="#set-the-selection's-value">Set the selection's value</a> to "baseline".
 
@@ -3072,9 +3174,9 @@
 
 <h3 id=the-underline-command><span class=secno>7.19 </span><dfn>The <code title="">underline</code> command</dfn></h3>
 
-<p><a href=#action>Action</a>: If the <a href=#state>state</a> is false, <a href="#set-the-selection's-value">set the
-selection's value</a> to "underline", otherwise <a href="#set-the-selection's-value">set the selection's
-value</a> to null.
+<p><a href=#action>Action</a>: If <code title=queryCommandState()><a href=#querycommandstate()>queryCommandState("underline")</a></code> returns true,
+<a href="#set-the-selection's-value">set the selection's value</a> to null.  Otherwise <a href="#set-the-selection's-value">set the
+selection's value</a> to "underline".
 
 <!--
 TODO: There are a lot of problems with underline color and thickness, because
@@ -6671,6 +6773,8 @@
 theory, but normalize the selection first, so they don't match it in practice.
 -->
 
+<p class=XXX>Needs to handle overridden state/value.
+
 <p><a href=#action>Action</a>:
 
 <!--
--- a/implementation.js	Wed Jul 13 13:55:04 2011 -0600
+++ b/implementation.js	Thu Jul 14 12:24:49 2011 -0600
@@ -149,6 +149,16 @@
 			|| (val1.toLowerCase() == "normal" && val2 == "400")
 			|| (val2.toLowerCase() == "normal" && val1 == "400");
 	}
+
+	// This code path should probably only be hit by queryOutputHelper() in
+	// tests.js.  Anything else is most likely a bug.
+	if (command == "fontname" && /^[1-7]$/.test(val1)) {
+		val1 = [, "xx-small", "small", "medium", "large", "x-large", "xx-large", "xxx-large"][val1];
+	}
+	if (command == "fontname" && /^[1-7]$/.test(val2)) {
+		val2 = [, "xx-small", "small", "medium", "large", "x-large", "xx-large", "xxx-large"][val2];
+	}
+
 	var property = commands[command].relevantCssProperty;
 	var test1 = document.createElement("span");
 	test1.style[property] = val1;
@@ -479,38 +489,81 @@
 	return nodeList;
 }
 
-
+// Returns either null, or something of the form #xxxxxx, or the color itself
+// if it's a valid keyword.
 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] == "#") {
+	color = color.toLowerCase();
+	// Yay for Gecko allowing you to select a column of a table without
+	// selecting anything from other columns.
+	if (["aliceblue", "antiquewhite", "aqua", "aquamarine", "azure", "beige",
+	"bisque", "black", "blanchedalmond", "blue", "blueviolet", "brown",
+	"burlywood", "cadetblue", "chartreuse", "chocolate", "coral",
+	"cornflowerblue", "cornsilk", "crimson", "cyan", "darkblue", "darkcyan",
+	"darkgoldenrod", "darkgray", "darkgreen", "darkgrey", "darkkhaki",
+	"darkmagenta", "darkolivegreen", "darkorange", "darkorchid", "darkred",
+	"darksalmon", "darkseagreen", "darkslateblue", "darkslategray",
+	"darkslategrey", "darkturquoise", "darkviolet", "deeppink", "deepskyblue",
+	"dimgray", "dimgrey", "dodgerblue", "firebrick", "floralwhite",
+	"forestgreen", "fuchsia", "gainsboro", "ghostwhite", "gold", "goldenrod",
+	"gray", "green", "greenyellow", "grey", "honeydew", "hotpink", "indianred",
+	"indigo", "ivory", "khaki", "lavender", "lavenderblush", "lawngreen",
+	"lemonchiffon", "lightblue", "lightcoral", "lightcyan",
+	"lightgoldenrodyellow", "lightgray", "lightgreen", "lightgrey",
+	"lightpink", "lightsalmon", "lightseagreen", "lightskyblue",
+	"lightslategray", "lightslategrey", "lightsteelblue", "lightyellow",
+	"lime", "limegreen", "linen", "magenta", "maroon", "mediumaquamarine",
+	"mediumblue", "mediumorchid", "mediumpurple", "mediumseagreen",
+	"mediumslateblue", "mediumspringgreen", "mediumturquoise",
+	"mediumvioletred", "midnightblue", "mintcream", "mistyrose", "moccasin",
+	"navajowhite", "navy", "oldlace", "olive", "olivedrab", "orange",
+	"orangered", "orchid", "palegoldenrod", "palegreen", "paleturquoise",
+	"palevioletred", "papayawhip", "peachpuff", "peru", "pink", "plum",
+	"powderblue", "purple", "red", "rosybrown", "royalblue", "saddlebrown",
+	"salmon", "sandybrown", "seagreen", "seashell", "sienna", "silver",
+	"skyblue", "slateblue", "slategray", "slategrey", "snow", "springgreen",
+	"steelblue", "tan", "teal", "thistle", "tomato", "turquoise", "violet",
+	"wheat", "white", "whitesmoke", "yellow", "yellowgreen"].indexOf(color) != -1) {
 		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];
+	var outerSpan = document.createElement("span");
+	document.body.appendChild(outerSpan);
+	outerSpan.style.color = "black";
+
+	var innerSpan = document.createElement("span");
+	outerSpan.appendChild(innerSpan);
+	innerSpan.style.color = color;
+	color = getComputedStyle(innerSpan).color;
+
+	if (color == "rgb(0, 0, 0)") {
+		// Maybe it's really black, maybe it's invalid.
+		outerSpan.color = "white";
+		color = getComputedStyle(innerSpan).color;
+		if (color == "rgb(0, 0, 0)") {
+			return null;
+		}
+	}
+
+	document.body.removeChild(outerSpan);
+
+	if (/^rgba\([0-9]+, [0-9]+, [0-9]+, 1\)$/.test(color)) {
+		// IE10PP2 seems to do this sometimes.
+		color = color.replace("rgba", "rgb").replace(", 1)", ")");
+	}
+	// I rely on the fact that browsers generally provide consistent syntax for
+	// getComputedStyle(), although it's not standardized.  In particular, they
+	// seem to clamp the components to integers between 0 and 255, and use
+	// consistent spacing, and always return rgb() syntax.  (Firefox 7.0a2
+	// sometimes returns "transparent", but we need to return null then
+	// anyway.)
+	var matches = /^rgb\(([0-9]+), ([0-9]+), ([0-9]+)\)$/.exec(color);
+	if (matches) {
+		return "#"
+			+ parseInt(matches[1]).toString(16).replace(/^.$/, "0$&")
+			+ parseInt(matches[2]).toString(16).replace(/^.$/, "0$&")
+			+ parseInt(matches[3]).toString(16).replace(/^.$/, "0$&");
+	}
+	return null;
 }
 
 //@}
@@ -642,6 +695,11 @@
 		return false;
 	}
 
+	// "If the state override for command is set, return it."
+	if (typeof getStateOverride(command) != "undefined") {
+		return getStateOverride(command);
+	}
+
 	// "Return true if command's state is true, otherwise false."
 	return commands[command].state();
 }
@@ -672,6 +730,11 @@
 		return "";
 	}
 
+	// "If the value override for command is set, return it."
+	if (typeof getValueOverride(command) != "undefined") {
+		return getValueOverride(command);
+	}
+
 	// "Return command's value."
 	return commands[command].value();
 }
@@ -938,6 +1001,72 @@
 	}
 	return ret;
 }
+
+// "For some commands, each HTMLDocument must have a boolean state override
+// and/or a string value override. These do not change the command's state or
+// value, but change the way some algorithms behave, as specified in those
+// algorithms' definitions. Initially, both must be unset for every command.
+// Whenever the number of ranges in the Selection changes to something
+// different, and whenever a boundary point of the range at a given index in
+// the Selection changes to something different, the state override and value
+// override must be unset for every command."
+//
+// We implement this crudely by using setters and getters.  To verify that the
+// selection hasn't changed, we copy the active range and just check the
+// endpoints match.  This isn't really correct, but it's good enough for us.
+// Unset state/value overrides are undefined.  We put everything in a function
+// so no one can access anything except via the provided functions, since
+// otherwise callers might mistakenly use outdated overrides (if the selection
+// has changed).
+var getStateOverride, setStateOverride, unsetStateOverride,
+	getValueOverride, setValueOverride, unsetValueOverride;
+(function() {
+	var stateOverrides = {};
+	var valueOverrides = {};
+	var storedRange = null;
+
+	function resetOverrides() {
+		if (!storedRange
+		|| storedRange.startContainer != getActiveRange().startContainer
+		|| storedRange.endContainer != getActiveRange().endContainer
+		|| storedRange.startOffset != getActiveRange().startOffset
+		|| storedRange.endOffset != getActiveRange().endOffset) {
+			stateOverrides = {};
+			valueOverrides = {};
+			storedRange = getActiveRange().cloneRange();
+		}
+	}
+
+	getStateOverride = function(command) {
+		resetOverrides();
+		return stateOverrides[command];
+	};
+
+	setStateOverride = function(command, newState) {
+		resetOverrides();
+		stateOverrides[command] = newState;
+	};
+
+	unsetStateOverride = function(command) {
+		resetOverrides();
+		delete stateOverrides[command];
+	}
+
+	getValueOverride = function(command) {
+		resetOverrides();
+		return valueOverrides[command];
+	}
+
+	setValueOverride = function(command, newValue) {
+		resetOverrides();
+		valueOverrides[command] = newValue;
+	}
+
+	unsetValueOverride = function(command) {
+		resetOverrides();
+		delete valueOverrides[command];
+	}
+})();
 //@}
 
 /////////////////////////////
@@ -2482,16 +2611,13 @@
 
 		// "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");
 
-			// "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."
+			// "If new value is an extended color keyword, 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
@@ -2697,6 +2823,51 @@
 //@{
 
 function setSelectionValue(command, newValue) {
+	// "If there is no editable text node effectively contained in the active
+	// range:"
+	if (!getAllEffectivelyContainedNodes(getActiveRange())
+	.filter(function(node) { return node.nodeType == Node.TEXT_NODE})
+	.some(isEditable)) {
+		// "If command is in the following list, set the state override
+		// appropriately:"
+		switch (command) {
+			// "bold: True if new value is not null and is greater than or
+			// equal to 600, false otherwise."
+			case "bold": setStateOverride(command, newValue === "bold"); break;
+
+			// "italic: True if new value is "italic" or "oblique", false
+			// otherwise."
+			case "italic": setStateOverride(command, newValue === "italic"); break;
+
+			// "strikethrough: True if new value is "line-through", false
+			// otherwise."
+			case "strikethrough": setStateOverride(command, newValue === "line-through"); break;
+
+			// "subscript: True if new value is "sub", false otherwise."
+			case "subscript": setStateOverride(command, newValue === "sub"); break;
+
+			// "superscript: True if new value is "super", false otherwise."
+			case "superscript": setStateOverride(command, newValue === "super"); break;
+
+			// "underline: True if new value is "underline", false otherwise."
+			case "underline": setStateOverride(command, newValue === "underline");
+		}
+
+		// "If command has a value specified, unset the value override if new
+		// value is null, and set the value override to new value if it is not
+		// null."
+		if ("value" in commands[command]) {
+			if (newValue === null) {
+				unsetValueOverride(command);
+			} else {
+				setValueOverride(command, newValue);
+			}
+		}
+
+		// "Abort these steps."
+		return;
+	}
+
 	// "If the active range's start node is an editable Text node, and its
 	// start offset is neither zero nor its start node's length, call
 	// splitText() on the active range's start node, with argument equal to the
@@ -2764,6 +2935,8 @@
 commands.backcolor = {
 	// Copy-pasted, same as hiliteColor
 	action: function(value) {
+		// Action is further copy-pasted, same as foreColor
+
 		// "If value is not a valid CSS color, prepend "#" to it."
 		//
 		// "If value is still not a valid CSS color, or if it is currentColor,
@@ -2773,12 +2946,9 @@
 		if (/^([0-9a-fA-F]{3}){1,2}$/.test(value)) {
 			value = "#" + value;
 		}
-		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") {
+		if (!/^(rgba?|hsla?)\(.*\)$/.test(value)
+		&& !parseSimpleColor(value)
+		&& value.toLowerCase() != "transparent") {
 			throw "SYNTAX_ERR";
 		}
 
@@ -2796,12 +2966,20 @@
 			return arr.slice(0, i).indexOf(value) == -1;
 		}).length >= 2;
 	}, value: function() {
-		// "The effective command value of the active range's start node."
+		// "The effective command value of the first editable Text node that is
+		// effectively contained in the active range, or if there is no such
+		// node, the effective command value of the active range's start node."
 		//
 		// Opera uses a different format, so let's be nice and support that for
 		// the time being (since all this resolved value stuff is underdefined
 		// anyway).
-		var value = getEffectiveCommandValue(getActiveRange().startContainer, "backcolor");
+		var node = getAllEffectivelyContainedNodes(getActiveRange(), function(node) {
+			return isEditable(node) && node.nodeType == Node.TEXT_NODE;
+		})[0];
+		if (node === undefined) {
+			node = getActiveRange().startContainer;
+		}
+		var value = getEffectiveCommandValue(node, "backcolor");
 		if (/^#[0-9a-f]{6}$/.test(value)) {
 			value = "rgb(" + parseInt(value.slice(1, 3), 16)
 				+ "," + parseInt(value.slice(3, 5), 16)
@@ -2816,12 +2994,12 @@
 //@{
 commands.bold = {
 	action: function() {
-		// "If the state is false, set the selection's value to "bold",
-		// otherwise set the selection's value to "normal"."
-		if (!commands.bold.state()) {
+		// "If queryCommandState("bold") returns true, set the selection's
+		// value to "normal". Otherwise set the selection's value to "bold"."
+		if (myQueryCommandState("bold", getActiveRange())) {
+			setSelectionValue("bold", "normal");
+		} else {
 			setSelectionValue("bold", "bold");
-		} else {
-			setSelectionValue("bold", "normal");
 		}
 	}, indeterm: function() { return indetermHelper(function(node) {
 		// "True if among editable Text nodes that are effectively contained in
@@ -2897,8 +3075,16 @@
 			return arr.slice(0, i).indexOf(value) == -1;
 		}).length >= 2;
 	}, value: function() {
-		// "The effective command value of the active range's start node."
-		return getEffectiveCommandValue(getActiveRange().startContainer, "fontname");
+		// "The effective command value of the first editable Text node that is
+		// effectively contained in the active range, or if there is no such
+		// node, the effective command value of the active range's start node."
+		var node = getAllEffectivelyContainedNodes(getActiveRange(), function(node) {
+			return isEditable(node) && node.nodeType == Node.TEXT_NODE;
+		})[0];
+		if (node === undefined) {
+			node = getActiveRange().startContainer;
+		}
+		return getEffectiveCommandValue(node, "fontname");
 	}, relevantCssProperty: "fontFamily"
 };
 
@@ -3002,9 +3188,18 @@
 			return arr.slice(0, i).indexOf(value) == -1;
 		}).length >= 2;
 	}, value: function() {
-		// "Let pixel size be the effective command value of the active range's
-		// start node, as a number of pixels."
-		var pixelSize = parseInt(getEffectiveCommandValue(getActiveRange().startContainer, "fontsize"));
+		// "Let pixel size be the effective command value of the first editable
+		// Text node that is effectively contained in the active range, or if
+		// there is no such node, the effective command value of the active
+		// range's start node, in either case interpreted as a number of
+		// pixels."
+		var node = getAllEffectivelyContainedNodes(getActiveRange(), function(node) {
+			return isEditable(node) && node.nodeType == Node.TEXT_NODE;
+		})[0];
+		if (node === undefined) {
+			node = getActiveRange().startContainer;
+		}
+		var pixelSize = parseInt(getEffectiveCommandValue(node, "fontsize"));
 
 		// "Let returned size be 1."
 		var returnedSize = 1;
@@ -3048,7 +3243,7 @@
 //@{
 commands.forecolor = {
 	action: function(value) {
-		// Copy-pasted, same as hiliteColor
+		// Copy-pasted, same as backColor and hiliteColor
 
 		// "If value is not a valid CSS color, prepend "#" to it."
 		//
@@ -3059,12 +3254,9 @@
 		if (/^([0-9a-fA-F]{3}){1,2}$/.test(value)) {
 			value = "#" + value;
 		}
-		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") {
+		if (!/^(rgba?|hsla?)\(.*\)$/.test(value)
+		&& !parseSimpleColor(value)
+		&& value.toLowerCase() != "transparent") {
 			throw "SYNTAX_ERR";
 		}
 
@@ -3082,12 +3274,20 @@
 			return arr.slice(0, i).indexOf(value) == -1;
 		}).length >= 2;
 	}, value: function() {
-		// "The effective command value of the active range's start node."
+		// "The effective command value of the first editable Text node that is
+		// effectively contained in the active range, or if there is no such
+		// node, the effective command value of the active range's start node."
 		//
 		// Opera uses a different format, so let's be nice and support that for
 		// the time being (since all this resolved value stuff is underdefined
 		// anyway).
-		var value = getEffectiveCommandValue(getActiveRange().startContainer, "forecolor");
+		var node = getAllEffectivelyContainedNodes(getActiveRange(), function(node) {
+			return isEditable(node) && node.nodeType == Node.TEXT_NODE;
+		})[0];
+		if (node === undefined) {
+			node = getActiveRange().startContainer;
+		}
+		var value = getEffectiveCommandValue(node, "forecolor");
 		if (/^#[0-9a-f]{6}$/.test(value)) {
 			value = "rgb(" + parseInt(value.slice(1, 3), 16)
 				+ "," + parseInt(value.slice(3, 5), 16)
@@ -3101,8 +3301,9 @@
 ///// The hiliteColor command /////
 //@{
 commands.hilitecolor = {
+	// Copy-pasted, same as backColor
 	action: function(value) {
-		// Copy-pasted, same as foreColor
+		// Action is further copy-pasted, same as foreColor
 
 		// "If value is not a valid CSS color, prepend "#" to it."
 		//
@@ -3113,12 +3314,9 @@
 		if (/^([0-9a-fA-F]{3}){1,2}$/.test(value)) {
 			value = "#" + value;
 		}
-		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") {
+		if (!/^(rgba?|hsla?)\(.*\)$/.test(value)
+		&& !parseSimpleColor(value)
+		&& value.toLowerCase() != "transparent") {
 			throw "SYNTAX_ERR";
 		}
 
@@ -3136,12 +3334,20 @@
 			return arr.slice(0, i).indexOf(value) == -1;
 		}).length >= 2;
 	}, value: function() {
-		// "The effective command value of the active range's start node."
+		// "The effective command value of the first editable Text node that is
+		// effectively contained in the active range, or if there is no such
+		// node, the effective command value of the active range's start node."
 		//
 		// Opera uses a different format, so let's be nice and support that for
 		// the time being (since all this resolved value stuff is underdefined
 		// anyway).
-		var value = getEffectiveCommandValue(getActiveRange().startContainer, "hilitecolor");
+		var node = getAllEffectivelyContainedNodes(getActiveRange(), function(node) {
+			return isEditable(node) && node.nodeType == Node.TEXT_NODE;
+		})[0];
+		if (node === undefined) {
+			node = getActiveRange().startContainer;
+		}
+		var value = getEffectiveCommandValue(node, "hilitecolor");
 		if (/^#[0-9a-f]{6}$/.test(value)) {
 			value = "rgb(" + parseInt(value.slice(1, 3), 16)
 				+ "," + parseInt(value.slice(3, 5), 16)
@@ -3156,12 +3362,12 @@
 //@{
 commands.italic = {
 	action: function() {
-		// "If the state is false, set the selection's value to "italic",
-		// otherwise set the selection's value to "normal"."
-		if (!commands.italic.state()) {
+		// "If queryCommandState("italic") returns true, set the selection's
+		// value to "normal". Otherwise set the selection's value to "italic"."
+		if (myQueryCommandState("italic", getActiveRange())) {
+			setSelectionValue("italic", "normal");
+		} else {
 			setSelectionValue("italic", "italic");
-		} else {
-			setSelectionValue("italic", "normal");
 		}
 	}, indeterm: function() { return indetermHelper(function(node) {
 		// "True if among editable Text nodes that are effectively contained in
@@ -3286,12 +3492,13 @@
 //@{
 commands.strikethrough = {
 	action: function() {
-		// "If the state is false, set the selection's value to "line-through",
-		// otherwise set the selection's value to null."
-		if (!commands.strikethrough.state()) {
+		// "If queryCommandState("strikethrough") returns true, set the
+		// selection's value to null. Otherwise set the selection's value to
+		// "line-through"."
+		if (myQueryCommandState("strikethrough", getActiveRange())) {
+			setSelectionValue("strikethrough", null);
+		} else {
 			setSelectionValue("strikethrough", "line-through");
-		} else {
-			setSelectionValue("strikethrough", null);
 		}
 	}, indeterm: function() { return indetermHelper(function(node) {
 		// "True if among editable Text nodes that are effectively contained in
@@ -3312,8 +3519,8 @@
 //@{
 commands.subscript = {
 	action: function() {
-		// "Let state be the state."
-		var state = commands.subscript.state();
+		// "Call queryCommandState("subscript"), and let state be the result."
+		var state = myQueryCommandState("subscript", getActiveRange());
 
 		// "Set the selection's value to "baseline"."
 		setSelectionValue("subscript", "baseline");
@@ -3348,8 +3555,9 @@
 //@{
 commands.superscript = {
 	action: function() {
-		// "Let state be the state."
-		var state = commands.superscript.state();
+		// "Call queryCommandState("superscript"), and let state be the
+		// result."
+		var state = myQueryCommandState("superscript", getActiveRange());
 
 		// "Set the selection's value to "baseline"."
 		setSelectionValue("superscript", "baseline");
@@ -3385,12 +3593,12 @@
 //@{
 commands.underline = {
 	action: function() {
-		// "If the state is false, set the selection's value to "underline",
-		// otherwise set the selection's value to null."
-		if (!commands.underline.state()) {
+		// "If queryCommandState("underline") returns true, set the selection's
+		// value to null. Otherwise set the selection's value to "underline"."
+		if (myQueryCommandState("underline", getActiveRange())) {
+			setSelectionValue("underline", null);
+		} else {
 			setSelectionValue("underline", "underline");
-		} else {
-			setSelectionValue("underline", null);
 		}
 	}, indeterm: function() { return indetermHelper(function(node) {
 		// "True if among editable Text nodes that are effectively contained in
--- a/source.html	Wed Jul 13 13:55:04 2011 -0600
+++ b/source.html	Thu Jul 14 12:24:49 2011 -0600
@@ -604,6 +604,9 @@
 
   <li>If <var>command</var> is not <span>enabled</span>, return false.
 
+  <li>If the <span>state override</span> for <var>command</var> is set, return
+  it.
+
   <li>Return true if <var>command</var>'s <span>state</span> is true, otherwise
   false.
 </ol>
@@ -642,12 +645,38 @@
   seems to return the string "false", and IE9 seems to return boolean false.
   -->
 
+  <li>If the <span>value override</span> for <var>command</var> is set, return
+  it.
+
   <li>Return <var>command</var>'s <span>value</span>.
 </ol>
 
 <p>All of these methods must treat their <var>command</var> argument <span
 data-anolis-spec=domcore title="ASCII case-insensitive">ASCII
 case-insensitively</span>.
+
+<p>The methods in this section have been designed so that the following
+invariants hold after <code>execCommand()</code> is called, assuming it didn't
+throw an exception:
+
+<ul>
+  <li><code>queryCommandIndeterm()</code> will return false (or throw an
+  exception).
+
+  <li><code>queryCommandState()</code> will return the opposite of what it did
+  before <code>execCommand()</code> was called (or throw an exception).
+
+  <li><code>queryCommandValue()</code> will return something equivalent to the
+  value passed to <code>execCommand()</code> (or throw an exception).
+  "Equivalent" here needs to be construed broadly in some cases, such as
+  <span>the <code title>fontSize</code> command</span>.
+</ul>
+
+<p>The first two points do not always hold for <span>the <code
+title>strikethrough</code> command</span> or <span>the <code
+title>underline</code> command</span>, because it can be impossible to unset
+text-decoration in CSS, but all three points otherwise hold in all cases
+barring bugs.
 <!-- @} -->
 
 <h2>Common definitions</h2>
@@ -775,6 +804,17 @@
 means of the <code>execCommand()</code> and <code>queryCommandState()</code>
 methods.)
 
+<p>For some <span title=command>commands</span>, each [[htmldocument]] must
+have a boolean <dfn>state override</dfn> and/or a string <dfn>value
+override</dfn>.  These do not change the <span>command</span>'s
+<span>state</span> or <span>value</span>, but change the way some algorithms
+behave, as specified in those algorithms' definitions.  Initially, both must be
+unset for every <span>command</span>.  Whenever the number of [[ranges]] in the
+[[selection]] changes to something different, and whenever a [[boundarypoint]]
+of the [[range]] at a given index in the [[selection]] changes to something
+different, the <span>state override</span> and <span>value override</span> must
+be unset for every <span>command</span>.
+
 <p>When the user agent is instructed to run a particular method, it must follow
 the steps defined for that method in the appropriate specification, not act as
 though the method had actually been called from JavaScript.  In particular,
@@ -1928,6 +1968,10 @@
 
     <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:
+    <!-- See comment for foreColor for discussion. -->
+
+    <p class=XXX>Check this more carefully for what happens if the components
+    are not integers or are out-of-range.
 
     <ol>
       <li>Let <var>new parent</var> be the result of calling <code
@@ -1935,9 +1979,10 @@
       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>If <var>new value</var> is an <a
+      href=http://www.w3.org/TR/css3-color/#svg-color>extended color
+      keyword</a>, 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
@@ -2174,6 +2219,39 @@
 <ol>
   <li>Let <var>command</var> be the current <span>command</span>.
 
+  <li>If there is no <span>editable</span> [[text]] node <span>effectively
+  contained</span> in the <span>active range</span>:
+
+  <ol>
+    <li>If <var>command</var> is in the following list, set the <span>state
+    override</span> appropriately:
+
+    <dl class=compact>
+      <dt>bold<dd>True if <var>new value</var> is not null and is greater than or equal
+      to 600, false otherwise.
+
+      <dt>italic<dd>True if <var>new value</var> is "italic" or "oblique", false
+      otherwise.
+
+      <dt>strikethrough<dd>True if <var>new value</var> is "line-through", false otherwise.
+
+      <dt>subscript<dd>True if <var>new value</var> is "sub", false otherwise.
+
+      <dt>superscript<dd>True if <var>new value</var> is "super", false otherwise.
+
+      <dt>underline<dd>True if <var>new value</var> is "underline", false otherwise.
+    </dl>
+
+    <li>If <var>command</var> has a <span>value</span> specified, unset the
+    <span>value override</span> if <var>new value</var> is null, and set the
+    <span>value override</span> to <var>new value</var> if it is not null.
+
+    <p class=XXX>This doesn't work as-is for fontSize, because that uses a
+    different format for the value.
+
+    <li>Abort these steps.
+  </ol>
+
   <li>If the <span>active range</span>'s [[startnode]] is an
   <span>editable</span> [[text]] node, and its [[startoffset]] is neither zero
   nor its [[startnode]]'s [[length]], call [[splittext|]] on the <span>active
@@ -2301,11 +2379,15 @@
 range</span>, there are two that have distinct <span title="effective command
 value">effective command values</span>.  Otherwise false.
 
-<p><span>Value</span>: The <span>effective command value</span> of the
-<span>active range</span>'s [[startnode]].
-
-<p class=note>This cannot be null, since the boundary point node of a selection
-must always be either an element or a text node that's the child of an element.
+<p><span>Value</span>: The <span>effective command value</span> of the first
+<span>editable</span> [[text]] node that is <span>effectively contained</span>
+in the <span>active range</span>, or if there is no such node, the
+<span>effective command value</span> of the <span>active range</span>'s
+[[startnode]].
+
+<p class=note>The effective command value of the active range's start node
+cannot be null, since the boundary point node of a selection must always be
+either an element or a text node that's the child of an element.
 
 <p><span>Relevant CSS property</span>: "background-color"
 
@@ -2318,9 +2400,10 @@
 (fontName, italic, etc.).  Except not for strikethrough, where it just does
 nothing if the selection is empty.  Why strikethrough?  I don't know. -->
 
-<p><span>Action</span>: If the <span>state</span> is false, <span>set the
-selection's value</span> to "bold", otherwise <span>set the selection's
-value</span> to "normal".
+<p><span>Action</span>: If <code
+title=queryCommandState()>queryCommandState("bold")</code> returns true,
+<span>set the selection's value</span> to "normal".  Otherwise <span>set the
+selection's value</span> to "bold".
 
 <p><span>Indeterminate</span>: True if among <span>editable</span> [[text]]
 nodes that are <span>effectively contained</span> in the <span>active
@@ -2417,15 +2500,7 @@
   <li><span>Set the selection's value</span> to <var>value</var>.
 </ol>
 
-<!--
-The state is always false in Chrome 14 dev and Opera 11.11.  Firefox 6.0a2
-throws an exception, and IE9 seems to always either return false or throw an
-exception.  Therefore we make the state always false, although this doesn't
-seem very useful.
--->
-
-<!-- I'd have expected the value to be the URL, but guess not: it's always
-false. -->
+<p class=XXX>Define state and value, although browsers don't.
 
 <!-- @} -->
 <h3><dfn>The <code title>fontName</code> command</dfn></h3>
@@ -2459,12 +2534,17 @@
 value">effective command values</span>.  Otherwise false.
 <!-- This follows Firefox 6.0a2.  Chrome 14 dev always returns false. -->
 
-<p><span>Value</span>: The <span>effective command value</span> of the
-<span>active range</span>'s [[startnode]].
-
-<p class=note>This cannot be null, since the boundary point node of a selection
-must always be either an element or a text node that's the child of an element.
-<!-- Complicated.
+<p><span>Value</span>: The <span>effective command value</span> of the first
+<span>editable</span> [[text]] node that is <span>effectively contained</span>
+in the <span>active range</span>, or if there is no such node, the
+<span>effective command value</span> of the <span>active range</span>'s
+[[startnode]].
+
+<p class=note>The effective command value of the active range's start node
+cannot be null, since the boundary point node of a selection must always be
+either an element or a text node that's the child of an element.
+<!--
+Complicated.
 
 IE 9 RC: Always the empty string.  Not very useful.
 Firefox 4b11: Confusing.  Sometimes it returns generic family names, like
@@ -2479,7 +2559,10 @@
 
 I'm just going to punt on this and say it should be the resolved value of
 font-family.  I'll leave CSSOM to decide what that means if there are no
-applicable style rules. -->
+applicable style rules.
+
+For deciding which node should be checked, see comment for hiliteColor.
+-->
 
 <p><span>Relevant CSS property</span>: "font-family"
 
@@ -2621,11 +2704,16 @@
 -->
 <ol>
   <li>Let <var>pixel size</var> be the <span>effective command value</span> of
-  the <span>active range</span>'s [[startnode]], as a number of pixels.
-
-  <p class=note>The active range's start node cannot be null, since the
-  boundary point node of a selection must always be either an element or a text
-  node that's the child of an element.
+  the first <span>editable</span> [[text]] node that is <span>effectively
+  contained</span> in the <span>active range</span>, or if there is no such
+  node, the <span>effective command value</span> of the <span>active
+  range</span>'s [[startnode]], in either case interpreted as a number of
+  pixels.
+  <!-- See comment for hiliteColor on how I decided on this choice of node. -->
+
+  <p class=note>The effective command value of the active range's start node
+  cannot be null, since the boundary point node of a selection must always be
+  either an element or a text node that's the child of an element.
 
   <li>Let <var>returned size</var> be 1.
 
@@ -2661,29 +2749,29 @@
 
 <!-- Color interpretations (wide screen recommended):
 
-                        IE9           Firefox 4.0              Chrome 12 dev            Opera 11.00
-red                     red           red                      #ff0000                  #ff0000
+                        IE10PP2       Firefox 7.0a2            Chrome 14 dev            Opera 11.50
+blue                    blue          blue                     #0000ff                  #0000ff
 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
+00f                     #00f          -                        #0000ff                  #00000f
+#00f                    #00f          rgb(0, 0, 255)           #0000ff                  #00000f
+0000ff                  #0000ff       -                        #0000ff                  #0000ff
+#0000ff                 #0000ff       rgb(0, 0, 255)           #0000ff                  #0000ff
+000000fff               #0000ff       -                        -                        -
+#000000fff              #0000ff       -                        -                        -
+rgb(0, 0, 255)          rgb(0,0,255)  rgb(0, 0, 255)           #0000ff                  #00b000
+rgb(0%, 0%, 100%)       rgb(0,0,255)  rgb(0, 0, 255)           #0000ff                  #00b000
+rgb( 0 ,0 ,255)         rgb(0,0,255)  rgb(0, 0, 255)           #0000ff                  #00b000
+rgba(0, 0, 255, 0.0)    #ba0000       rgba(0, 0, 255, 0)       rgba(0, 0, 255, 0)       #00ba00
+rgb(15, -10, 375)       rgb(15,0,255) rgb(15, 0, 255)          #0f00ff                  #00b015
 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       -                        -                        -
+rgba(0, 0, 255, 0.5)    #ba0000       rgba(0, 0, 255, 0.5)     rgba(0, 0, 255, 0.5)     #00ba00
+hsl(240, 100%, 50%)     #000150       rgb(0, 0, 255)           #0000ff                  #000024
 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
+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>
@@ -2698,8 +2786,8 @@
 * 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.
+* rgba() and hsl() are accepted by Gecko and WebKit, but rejected by IE and
+  Opera.
 * 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.
@@ -2736,18 +2824,25 @@
 value">effective command values</span>.  Otherwise false.
 <!-- This follows Firefox 6.0a2.  Chrome 14 dev always returns false. -->
 
-<p><span>Value</span>: The <span>effective command value</span> of the
-<span>active range</span>'s [[startnode]].
-
-<p class=note>This cannot be null, since the boundary point node of a selection
-must always be either an element or a text node that's the child of an element.
+<p><span>Value</span>: The <span>effective command value</span> of the first
+<span>editable</span> [[text]] node that is <span>effectively contained</span>
+in the <span>active range</span>, or if there is no such node, the
+<span>effective command value</span> of the <span>active range</span>'s
+[[startnode]].
+
+<p class=note>The effective command value of the active range's start node
+cannot be null, since the boundary point node of a selection must always be
+either an element or a text node that's the child of an element.
 <!--
-The spec essentially matches Firefox 6.0a2 and Chrome 14 dev.  IE9 seems to
-always return the number 0 for some bizarre reason.  There are some cases where
-Firefox returns the empty string for some reason, and it seems to select the
-active node a little differently.  Opera uses #xxxxxx format for
-getComputedStyle() but rgb() here, and also drops the transparent part of the
-color if there is any.
+The spec essentially matches Firefox 6.0a2 and Chrome 14 dev, as far as how to
+decide what color the node has.  IE9 seems to always return the number 0 for
+some bizarre reason.  There are some cases where Firefox returns the empty
+string for some reason, and it seems to select the active node a little
+differently.  Opera uses #xxxxxx format for getComputedStyle() but rgb() here,
+and also drops the transparent part of the color if there is any.
+
+For why I chose this node to key the color off of, see the comment for
+hiliteColor.
 -->
 
 <p><span>Relevant CSS property</span>: "color"
@@ -2794,19 +2889,28 @@
 <!-- This follows no one.  Firefox 6.0a2 and Chrome 14 dev both always return
 false.  However, it makes sense. -->
 
-<p><span>Value</span>: The <span>effective command value</span> of the
-<span>active range</span>'s [[startnode]].
-
-<p class=note>This cannot be null, since the boundary point node of a selection
-must always be either an element or a text node that's the child of an element.
+<p><span>Value</span>: The <span>effective command value</span> of the first
+<span>editable</span> [[text]] node that is <span>effectively contained</span>
+in the <span>active range</span>, or if there is no such node, the
+<span>effective command value</span> of the <span>active range</span>'s
+[[startnode]].
+
+<p class=note>The effective command value of the active range's start node
+cannot be null, since the boundary point node of a selection must always be
+either an element or a text node that's the child of an element.
 <!--
-This seems to match Opera 11.11 exactly.  Chrome 14 dev returns boolean false
-consistently, bizarrely enough.  Firefox 6.0a2 seems to follow the same idea as
-the spec, but it likes to return "transparent", including sometimes when the
-answer really clearly should not be "transparent".  IE9 throws exceptions most
-of the time for backColor, so I can't say for sure, but in the few cases where
-it doesn't throw it returns a random-looking number, so I'll assume it's crazy
-like for foreColor.
+Opera 11.11 seems to always return the effective command value of the active
+range's start node.  Chrome 14 dev returns boolean false consistently,
+bizarrely enough.  Firefox 6.0a2 seems to follow the same idea as the spec, but
+it likes to return "transparent", including sometimes when the answer really
+clearly should not be "transparent".  IE9 throws exceptions most of the time
+for backColor, so I can't say for sure, but in the few cases where it doesn't
+throw it returns a random-looking number, so I'll assume it's crazy like for
+foreColor.
+
+I decided on something that would guarantee the following invariant: whenever
+you execute a command with a value provided (assuming value is relevant),
+queryCommandValue() will always return something equivalent to what you set.
 -->
 
 <p><span>Relevant CSS property</span>: "background-color"
@@ -2814,9 +2918,10 @@
 <!-- @} -->
 <h3><dfn>The <code title>italic</code> command</dfn></h3>
 <!-- @{ -->
-<p><span>Action</span>: If the <span>state</span> is false, <span>set the
-selection's value</span> to "italic", otherwise <span>set the selection's
-value</span> to "normal".
+<p><span>Action</span>: If <code
+title=queryCommandState()>queryCommandState("italic")</code> returns true,
+<span>set the selection's value</span> to "normal".  Otherwise <span>set the
+selection's value</span> to "italic".
 
 <p><span>Indeterminate</span>: True if among <span>editable</span> [[text]]
 nodes that are <span>effectively contained</span> in the <span>active
@@ -2960,9 +3065,10 @@
 <!-- @} -->
 <h3><dfn>The <code title>strikethrough</code> command</dfn></h3>
 <!-- @{ -->
-<p><span>Action</span>: If the <span>state</span> is false, <span>set the
-selection's value</span> to "line-through", otherwise <span>set the selection's
-value</span> to null.
+<p><span>Action</span>: If <code
+title=queryCommandState()>queryCommandState("strikethrough")</code> returns
+true, <span>set the selection's value</span> to null.  Otherwise <span>set the
+selection's value</span> to "line-through".
 
 <!-- TODO: See underline TODO. -->
 
@@ -2983,7 +3089,9 @@
 <p><span>Action</span>:
 
 <ol>
-  <li>Let <var>state</var> be the <span>state</span>.
+  <li>Call <code
+  title=queryCommandState()>queryCommandState("subscript")</code>, and let
+  <var>state</var> be the result.
 
   <li><span>Set the selection's value</span> to "baseline".
 
@@ -3023,7 +3131,9 @@
 <p><span>Action</span>:
 
 <ol>
-  <li>Let <var>state</var> be the <span>state</span>.
+  <li>Call <code
+  title=queryCommandState()>queryCommandState("superscript")</code>, and let
+  <var>state</var> be the result.
 
   <li><span>Set the selection's value</span> to "baseline".
 
@@ -3049,9 +3159,10 @@
 <!-- @} -->
 <h3><dfn>The <code title>underline</code> command</dfn></h3>
 <!-- @{ -->
-<p><span>Action</span>: If the <span>state</span> is false, <span>set the
-selection's value</span> to "underline", otherwise <span>set the selection's
-value</span> to null.
+<p><span>Action</span>: If <code
+title=queryCommandState()>queryCommandState("underline")</code> returns true,
+<span>set the selection's value</span> to null.  Otherwise <span>set the
+selection's value</span> to "underline".
 
 <!--
 TODO: There are a lot of problems with underline color and thickness, because
@@ -6666,6 +6777,8 @@
 theory, but normalize the selection first, so they don't match it in practice.
 -->
 
+<p class=XXX>Needs to handle overridden state/value.
+
 <p><span>Action</span>:
 
 <!--
--- a/tests.css	Wed Jul 13 13:55:04 2011 -0600
+++ b/tests.css	Thu Jul 14 12:24:49 2011 -0600
@@ -15,6 +15,9 @@
 	color: red;
 	font-weight: bold;
 }
+.extra-results { font-size: small }
+.good-result { color: green }
+.bad-result { color: red }
 /* http://www.w3.org/Bugs/Public/show_bug.cgi?id=12154
  * https://bugzilla.mozilla.org/show_bug.cgi?id=589124
  * https://bugs.webkit.org/show_bug.cgi?id=56400 */
--- a/tests.js	Wed Jul 13 13:55:04 2011 -0600
+++ b/tests.js	Thu Jul 14 12:24:49 2011 -0600
@@ -187,7 +187,7 @@
 		'<i><b>foo</b></i>[bar]<i><b>baz</b></i>',
 		'<i><b>foo</b></i>[bar]<b>baz</b>',
 		'<b>foo</b>[bar]<i><b>baz</b></i>',
-		'<font color=red face=monospace><b>foo</b></font>[bar]',
+		'<font color=blue face=monospace><b>foo</b></font>[bar]',
 
 		'foo<span style="font-weight: normal"><b>{bar}</b></span>baz',
 		'[foo<span class=notbold>bar</span>baz]',
@@ -393,11 +393,11 @@
 		'foo<blockquote>[]bar</blockquote>',
 		'foo<blockquote><blockquote>[]bar</blockquote></blockquote>',
 		'foo<blockquote><div>[]bar</div></blockquote>',
-		'foo<blockquote style="color: red">[]bar</blockquote>',
+		'foo<blockquote style="color: blue">[]bar</blockquote>',
 
 		'foo<blockquote><blockquote><p>[]bar<p>baz</blockquote></blockquote>',
 		'foo<blockquote><div><p>[]bar<p>baz</div></blockquote>',
-		'foo<blockquote style="color: red"><p>[]bar<p>baz</blockquote>',
+		'foo<blockquote style="color: blue"><p>[]bar<p>baz</blockquote>',
 
 		'foo<blockquote><p><b>[]bar</b><p>baz</blockquote>',
 		'foo<blockquote><p><strong>[]bar</strong><p>baz</blockquote>',
@@ -434,22 +434,22 @@
 		'<div><div><p>foo</p></div></div><div><div><div><!--abc-->[]bar</div></div></div>',
 
 		// Styled stuff with collapsed selection
-		'<p style=color:red>foo<p>[]bar',
-		'<p style=color:red>foo<p style=color:blue>[]bar',
-		'<p>foo<p style=color:blue>[]bar',
-		'<p><font color=red>foo</font><p>[]bar',
-		'<p><font color=red>foo</font><p><font color=blue>[]bar</font>',
-		'<p>foo<p><font color=blue>[]bar</font>',
-		'<p><span style=color:red>foo</font><p>[]bar',
-		'<p><span style=color:red>foo</font><p><span style=color:blue>[]bar</font>',
-		'<p>foo<p><span style=color:blue>[]bar</font>',
-
-		'<p style=background-color:salmon>foo<p>[]bar',
-		'<p style=background-color:salmon>foo<p style=background-color:aqua>[]bar',
-		'<p>foo<p style=background-color:aqua>[]bar',
-		'<p><span style=background-color:salmon>foo</font><p>[]bar',
-		'<p><span style=background-color:salmon>foo</font><p><span style=background-color:aqua>[]bar</font>',
-		'<p>foo<p><span style=background-color:aqua>[]bar</font>',
+		'<p style=color:blue>foo<p>[]bar',
+		'<p style=color:blue>foo<p style=color:brown>[]bar',
+		'<p>foo<p style=color:brown>[]bar',
+		'<p><font color=blue>foo</font><p>[]bar',
+		'<p><font color=blue>foo</font><p><font color=brown>[]bar</font>',
+		'<p>foo<p><font color=brown>[]bar</font>',
+		'<p><span style=color:blue>foo</font><p>[]bar',
+		'<p><span style=color:blue>foo</font><p><span style=color:brown>[]bar</font>',
+		'<p>foo<p><span style=color:brown>[]bar</font>',
+
+		'<p style=background-color:aqua>foo<p>[]bar',
+		'<p style=background-color:aqua>foo<p style=background-color:tan>[]bar',
+		'<p>foo<p style=background-color:tan>[]bar',
+		'<p><span style=background-color:aqua>foo</font><p>[]bar',
+		'<p><span style=background-color:aqua>foo</font><p><span style=background-color:tan>[]bar</font>',
+		'<p>foo<p><span style=background-color:tan>[]bar</font>',
 
 		'<p style=text-decoration:underline>foo<p>[]bar',
 		'<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar',
@@ -458,11 +458,11 @@
 		'<p><u>foo</u><p><s>[]bar</s>',
 		'<p>foo<p><s>[]bar</s>',
 
-		'<p style=color:red>foo</p>[]bar',
-		'foo<p style=color:blue>[]bar',
-		'<div style=color:red><p style=color:green>foo</div>[]bar',
-		'<div style=color:red><p style=color:green>foo</div><p style=color:blue>[]bar',
-		'<p style=color:red>foo<div style=color:blue><p style=color:green>[]bar',
+		'<p style=color:blue>foo</p>[]bar',
+		'foo<p style=color:brown>[]bar',
+		'<div style=color:blue><p style=color:green>foo</div>[]bar',
+		'<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar',
+		'<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar',
 
 		// Uncollapsed selection
 		'foo[bar]baz',
@@ -489,7 +489,7 @@
 		'<p><b>foo[bar</b><p>baz]quz',
 		'<div><p>foo[bar</div><p>baz]quz',
 		'<p>foo[bar<blockquote><p>baz]quz<p>qoz</blockquote',
-		'<p>foo[bar<p style=color:red>baz]quz',
+		'<p>foo[bar<p style=color:blue>baz]quz',
 		'<p>foo[bar<p><b>baz]quz</b>',
 
 		'<div><p>foo<p>[bar<p>baz]</div>',
@@ -751,24 +751,24 @@
 		'{<p><p> <p>foo</p>}',
 		'foo[bar<i>baz]qoz</i>quz',
 
-		['red', 'foo[bar]baz'],
+		['blue', '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'],
+		['00f', 'foo[bar]baz'],
+		['#00f', 'foo[bar]baz'],
+		['0000ff', 'foo[bar]baz'],
+		['#0000ff', 'foo[bar]baz'],
+		['000000fff', 'foo[bar]baz'],
+		['#000000fff', 'foo[bar]baz'],
+		['rgb(0, 0, 255)', 'foo[bar]baz'],
+		['rgb(0%, 0%, 100%)', 'foo[bar]baz'],
+		['rgb( 0 ,0 ,255)', 'foo[bar]baz'],
+		['rgba(0, 0, 255, 0.0)', 'foo[bar]baz'],
+		['rgb(15, -10, 375)', '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'],
+		['rgba(0, 0, 255, 0.5)', 'foo[bar]baz'],
+		['hsl(240, 100%, 50%)', 'foo[bar]baz'],
 		['cornsilk', 'foo[bar]baz'],
 		['potato quiche', 'foo[bar]baz'],
 		['transparent', 'foo[bar]baz'],
@@ -781,47 +781,47 @@
 		'<table data-start=0 data-end=1><tbody><tr><td>foo<td>bar<td>baz</table>',
 		'{<table><tr><td>foo<td>bar<td>baz</table>}',
 
-		'foo<font color=red>[bar]</font>baz',
-		'foo{<font color=red>bar</font>}baz',
-		'<span style="color: red">foo<span style="color: blue">[bar]</span>baz</span>',
-		'<span style="color: #f00">foo<span style="color: blue">[bar]</span>baz</span>',
-		'<span style="color: #ff0000">foo<span style="color: blue">[bar]</span>baz</span>',
-		'<span style="color: rgb(255, 0, 0)">foo<span style="color: blue">[bar]</span>baz</span>',
-		'<font color=red>foo<font color=blue>[bar]</font>baz</font>',
-		'<span style="color: rgb(255, 0, 0)">foo<span style="color: blue">b[ar]</span>baz</span>',
+		'foo<font color=blue>[bar]</font>baz',
+		'foo{<font color=blue>bar</font>}baz',
+		'<span style="color: blue">foo<span style="color: brown">[bar]</span>baz</span>',
+		'<span style="color: #00f">foo<span style="color: brown">[bar]</span>baz</span>',
+		'<span style="color: #0000ff">foo<span style="color: brown">[bar]</span>baz</span>',
+		'<span style="color: rgb(0, 0, 255)">foo<span style="color: brown">[bar]</span>baz</span>',
+		'<font color=blue>foo<font color=brown>[bar]</font>baz</font>',
+		'<span style="color: rgb(0, 0, 255)">foo<span style="color: brown">b[ar]</span>baz</span>',
 		'foo<span id=purple>ba[r</span>ba]z',
-		'<span style="color: rgb(255, 0, 0)">foo<span id=purple>b[a]r</span>baz</span>',
+		'<span style="color: rgb(0, 0, 255)">foo<span id=purple>b[a]r</span>baz</span>',
 
 		// Tests for queryCommandValue()
-		'<font color="red">[foo]</font>',
-		'<font color="ff0000">[foo]</font>',
-		'<font color="#ff0000">[foo]</font>',
-		'<span style="color: red">[foo]</span>',
-		'<span style="color: #ff0000">[foo]</span>',
-		'<span style="color: rgb(255, 0, 0)">[foo]</span>',
-		'<span style="color: rgb(100%, 0, 0)">[foo]</span>',
-		'<span style="color: rgb( 255 ,0 ,0)">[foo]</span>',
-		'<span style="color: rgba(255, 0, 0, 0.0)">[foo]</span>',
-		'<span style="color: rgb(375, -10, 15)">[foo]</span>',
+		'<font color="blue">[foo]</font>',
+		'<font color="0000ff">[foo]</font>',
+		'<font color="#0000ff">[foo]</font>',
+		'<span style="color: blue">[foo]</span>',
+		'<span style="color: #0000ff">[foo]</span>',
+		'<span style="color: rgb(0, 0, 255)">[foo]</span>',
+		'<span style="color: rgb(0%, 0%, 100%)">[foo]</span>',
+		'<span style="color: rgb( 0 ,0 ,255)">[foo]</span>',
+		'<span style="color: rgba(0, 0, 255, 0.0)">[foo]</span>',
+		'<span style="color: rgb(15, -10, 375)">[foo]</span>',
 		'<span style="color: rgba(0, 0, 0, 1)">[foo]</span>',
 		'<span style="color: rgba(255, 255, 255, 1)">[foo]</span>',
-		'<span style="color: rgba(255, 0, 0, 0.5)">[foo]</span>',
-		'<span style="color: hsl(0%, 100%, 50%)">[foo]</span>',
+		'<span style="color: rgba(0, 0, 255, 0.5)">[foo]</span>',
+		'<span style="color: hsl(240, 100%, 50%)">[foo]</span>',
 		'<span style="color: cornsilk">[foo]</span>',
 		'<span style="color: transparent">[foo]</span>',
 		'<span style="color: currentColor">[foo]</span>',
 
 		// Tests for queryCommandIndeterm() and queryCommandState()
-		'fo[o<font color=blue>b]ar</font>baz',
-		'foo<font color=blue>ba[r</font>b]az',
-		'fo[o<font color=blue>bar</font>b]az',
-		'foo[<font color=blue>b]ar</font>baz',
-		'foo<font color=blue>ba[r</font>]baz',
-		'foo[<font color=blue>bar</font>]baz',
-		'foo<font color=blue>[bar]</font>baz',
-		'foo{<font color=blue>bar</font>}baz',
-		'<font color=blue>fo[o</font><span style=color:blue>b]ar</span>',
-		'<span style=color:blue>fo[o</span><span style=color:#0000ff>b]ar</span>',
+		'fo[o<font color=brown>b]ar</font>baz',
+		'foo<font color=brown>ba[r</font>b]az',
+		'fo[o<font color=brown>bar</font>b]az',
+		'foo[<font color=brown>b]ar</font>baz',
+		'foo<font color=brown>ba[r</font>]baz',
+		'foo[<font color=brown>bar</font>]baz',
+		'foo<font color=brown>[bar]</font>baz',
+		'foo{<font color=brown>bar</font>}baz',
+		'<font color=brown>fo[o</font><span style=color:brown>b]ar</span>',
+		'<span style=color:brown>fo[o</span><span style=color:#0000ff>b]ar</span>',
 	],
 	//@}
 	formatblock: [
@@ -1075,7 +1075,7 @@
 		'<h1>[foo</h1><h2>bar]</h2>',
 		'<div>[foo</div>bar]',
 
-		['<p>', '<div style=color:red>[foo]</div>'],
+		['<p>', '<div style=color:blue>[foo]</div>'],
 	],
 	//@}
 	forwarddelete: [
@@ -1192,11 +1192,11 @@
 		'foo[]<blockquote>bar</blockquote>',
 		'foo[]<blockquote><blockquote>bar</blockquote></blockquote>',
 		'foo[]<blockquote><div>bar</div></blockquote>',
-		'foo[]<blockquote style="color: red">bar</blockquote>',
+		'foo[]<blockquote style="color: blue">bar</blockquote>',
 
 		'foo[]<blockquote><blockquote><p>bar<p>baz</blockquote></blockquote>',
 		'foo[]<blockquote><div><p>bar<p>baz</div></blockquote>',
-		'foo[]<blockquote style="color: red"><p>bar<p>baz</blockquote>',
+		'foo[]<blockquote style="color: blue"><p>bar<p>baz</blockquote>',
 
 		'foo[]<blockquote><p><b>bar</b><p>baz</blockquote>',
 		'foo[]<blockquote><p><strong>bar</strong><p>baz</blockquote>',
@@ -1233,22 +1233,22 @@
 		'<div><div><p>foo[]</p></div></div><div><div><div><!--abc-->bar</div></div></div>',
 
 		// Styled stuff with collapsed selection
-		'<p style=color:red>foo[]<p>bar',
-		'<p style=color:red>foo[]<p style=color:blue>bar',
-		'<p>foo[]<p style=color:blue>bar',
-		'<p><font color=red>foo[]</font><p>bar',
-		'<p><font color=red>foo[]</font><p><font color=blue>bar</font>',
-		'<p>foo[]<p><font color=blue>bar</font>',
-		'<p><span style=color:red>foo[]</font><p>bar',
-		'<p><span style=color:red>foo[]</font><p><span style=color:blue>bar</font>',
-		'<p>foo[]<p><span style=color:blue>bar</font>',
-
-		'<p style=background-color:salmon>foo[]<p>bar',
-		'<p style=background-color:salmon>foo[]<p style=background-color:aqua>bar',
-		'<p>foo[]<p style=background-color:aqua>bar',
-		'<p><span style=background-color:salmon>foo[]</font><p>bar',
-		'<p><span style=background-color:salmon>foo[]</font><p><span style=background-color:aqua>bar</font>',
-		'<p>foo[]<p><span style=background-color:aqua>bar</font>',
+		'<p style=color:blue>foo[]<p>bar',
+		'<p style=color:blue>foo[]<p style=color:brown>bar',
+		'<p>foo[]<p style=color:brown>bar',
+		'<p><font color=blue>foo[]</font><p>bar',
+		'<p><font color=blue>foo[]</font><p><font color=brown>bar</font>',
+		'<p>foo[]<p><font color=brown>bar</font>',
+		'<p><span style=color:blue>foo[]</font><p>bar',
+		'<p><span style=color:blue>foo[]</font><p><span style=color:brown>bar</font>',
+		'<p>foo[]<p><span style=color:brown>bar</font>',
+
+		'<p style=background-color:aqua>foo[]<p>bar',
+		'<p style=background-color:aqua>foo[]<p style=background-color:tan>bar',
+		'<p>foo[]<p style=background-color:tan>bar',
+		'<p><span style=background-color:aqua>foo[]</font><p>bar',
+		'<p><span style=background-color:aqua>foo[]</font><p><span style=background-color:tan>bar</font>',
+		'<p>foo[]<p><span style=background-color:tan>bar</font>',
 
 		'<p style=text-decoration:underline>foo[]<p>bar',
 		'<p style=text-decoration:underline>foo[]<p style=text-decoration:line-through>bar',
@@ -1257,11 +1257,11 @@
 		'<p><u>foo[]</u><p><s>bar</s>',
 		'<p>foo[]<p><s>bar</s>',
 
-		'<p style=color:red>foo[]</p>bar',
-		'foo[]<p style=color:blue>bar',
-		'<div style=color:red><p style=color:green>foo[]</div>bar',
-		'<div style=color:red><p style=color:green>foo[]</div><p style=color:blue>bar',
-		'<p style=color:red>foo[]<div style=color:blue><p style=color:green>bar',
+		'<p style=color:blue>foo[]</p>bar',
+		'foo[]<p style=color:brown>bar',
+		'<div style=color:blue><p style=color:green>foo[]</div>bar',
+		'<div style=color:blue><p style=color:green>foo[]</div><p style=color:brown>bar',
+		'<p style=color:blue>foo[]<div style=color:brown><p style=color:green>bar',
 
 		// Uncollapsed selection (should be same as delete command)
 		'foo[bar]baz',
@@ -1288,7 +1288,7 @@
 		'<p><b>foo[bar</b><p>baz]quz',
 		'<div><p>foo[bar</div><p>baz]quz',
 		'<p>foo[bar<blockquote><p>baz]quz<p>qoz</blockquote',
-		'<p>foo[bar<p style=color:red>baz]quz',
+		'<p>foo[bar<p style=color:blue>baz]quz',
 		'<p>foo[bar<p><b>baz]quz</b>',
 
 		'<div><p>foo<p>[bar<p>baz]</div>',
@@ -1369,30 +1369,31 @@
 		'<table data-start=0 data-end=1><tbody><tr><td>foo<td>bar<td>baz</table>',
 		'{<table><tr><td>foo<td>bar<td>baz</table>}',
 
-		'<p style="background-color: rgb(255, 136, 136)">foo[bar]baz</p>',
-		'<p style="background-color: #ff8888">foo[bar]baz</p>',
+		'<p style="background-color: rgb(0, 255, 255)">foo[bar]baz</p>',
+		'<p style="background-color: #00ffff">foo[bar]baz</p>',
 		'<p style="background-color: aqua">foo[bar]baz</p>',
 		'{<p style="background-color: aqua">foo</p><p>bar</p>}',
-		'<span style="background-color: #ff8888">foo<span style="background-color: aqua">[bar]</span>baz</span>',
-		'<span style="background-color: #f88">foo<span style="background-color: aqua">[bar]</span>baz</span>',
-		'<span style="background-color: rgb(255, 136, 136)">foo<span style="background-color: aqua">[bar]</span>baz</span>',
-		'<span style="background-color: #ff8888">foo<span style="background-color: aqua">b[ar]</span>baz</span>',
-		'<p style="background-color: #ff8888">foo<span style="background-color: aqua">b[ar]</span>baz</p>',
-		'<div style="background-color: #ff8888"><p style="background-color: aqua">b[ar]</p></div>',
-		'<span style="display: block; background-color: #ff8888"><span style="display: block; background-color: aqua">b[ar]</span></span>',
+		'<span style="background-color: aqua">foo<span style="background-color: tan">[bar]</span>baz</span>',
+		'<span style="background-color: #00ffff">foo<span style="background-color: tan">[bar]</span>baz</span>',
+		'<span style="background-color: #0ff">foo<span style="background-color: tan">[bar]</span>baz</span>',
+		'<span style="background-color: rgb(0, 255, 255)">foo<span style="background-color: tan">[bar]</span>baz</span>',
+		'<span style="background-color: aqua">foo<span style="background-color: tan">b[ar]</span>baz</span>',
+		'<p style="background-color: aqua">foo<span style="background-color: tan">b[ar]</span>baz</p>',
+		'<div style="background-color: aqua"><p style="background-color: tan">b[ar]</p></div>',
+		'<span style="display: block; background-color: aqua"><span style="display: block; background-color: tan">b[ar]</span></span>',
 
 		// Tests for queryCommandIndeterm() and queryCommandState()
-		'fo[o<span style=background-color:aqua>b]ar</span>baz',
-		'foo<span style=background-color:aqua>ba[r</span>b]az',
-		'fo[o<span style=background-color:aqua>bar</span>b]az',
-		'foo[<span style=background-color:aqua>b]ar</span>baz',
-		'foo<span style=background-color:aqua>ba[r</span>]baz',
-		'foo[<span style=background-color:aqua>bar</span>]baz',
-		'foo<span style=background-color:aqua>[bar]</span>baz',
-		'foo{<span style=background-color:aqua>bar</span>}baz',
-		'<span style=background-color:aqua>fo[o</span><span style=background-color:lime>b]ar</span>',
-		'<span style=background-color:aqua>fo[o</span><span style=background-color:aqua>b]ar</span>',
-		'<span style=background-color:aqua>fo[o<span style=background-color:transparent>b]ar</span></span>',
+		'fo[o<span style=background-color:tan>b]ar</span>baz',
+		'foo<span style=background-color:tan>ba[r</span>b]az',
+		'fo[o<span style=background-color:tan>bar</span>b]az',
+		'foo[<span style=background-color:tan>b]ar</span>baz',
+		'foo<span style=background-color:tan>ba[r</span>]baz',
+		'foo[<span style=background-color:tan>bar</span>]baz',
+		'foo<span style=background-color:tan>[bar]</span>baz',
+		'foo{<span style=background-color:tan>bar</span>}baz',
+		'<span style=background-color:tan>fo[o</span><span style=background-color:yellow>b]ar</span>',
+		'<span style=background-color:tan>fo[o</span><span style=background-color:tan>b]ar</span>',
+		'<span style=background-color:tan>fo[o<span style=background-color:transparent>b]ar</span></span>',
 	],
 	//@}
 	indent: [
@@ -1710,8 +1711,8 @@
 		['<nobr>abc</nobr>', '<nobr>f[o]o</nobr>'],
 		['<nobr>abc</nobr>', 'f[o]o'],
 
-		['<p>abc', '<font color=red>foo[]bar</font>'],
-		['<p>abc', '<span style=color:red>foo[]bar</span>'],
+		['<p>abc', '<font color=blue>foo[]bar</font>'],
+		['<p>abc', '<span style=color:blue>foo[]bar</span>'],
 		['<p>abc', '<span style=font-variant:small-caps>foo[]bar</span>'],
 		[' ', '<p>[foo]</p>'],
 		['<span style=display:none></span>', '<p>[foo]</p>'],
@@ -1746,7 +1747,7 @@
 		'<p><b>foo[bar</b><p>baz]quz',
 		'<div><p>foo[bar</div><p>baz]quz',
 		'<p>foo[bar<blockquote><p>baz]quz<p>qoz</blockquote',
-		'<p>foo[bar<p style=color:red>baz]quz',
+		'<p>foo[bar<p style=color:blue>baz]quz',
 		'<p>foo[bar<p><b>baz]quz</b>',
 
 		'<div><p>foo<p>[bar<p>baz]</div>',
@@ -1951,13 +1952,13 @@
 
 		// Attributes
 		'<ul id=abc><li>foo<li>[bar]<li>baz</ul>',
-		'<ul style=color:red><li>foo<li>[bar]<li>baz</ul>',
+		'<ul style=color:blue><li>foo<li>[bar]<li>baz</ul>',
 		'<ul style=text-indent:1em><li>foo<li>[bar]<li>baz</ul>',
 		'<ul id=abc><li>[foo]<li>bar<li>baz</ul>',
-		'<ul style=color:red><li>[foo]<li>bar<li>baz</ul>',
+		'<ul style=color:blue><li>[foo]<li>bar<li>baz</ul>',
 		'<ul style=text-indent:1em><li>[foo]<li>bar<li>baz</ul>',
 		'<ul id=abc><li>foo<li>bar<li>[baz]</ul>',
-		'<ul style=color:red><li>foo<li>bar<li>[baz]</ul>',
+		'<ul style=color:blue><li>foo<li>bar<li>[baz]</ul>',
 		'<ul style=text-indent:1em><li>foo<li>bar<li>[baz]</ul>',
 	],
 	//@}
@@ -2346,13 +2347,13 @@
 
 		// Attributes
 		'<ul id=abc><li>foo<li>[bar]<li>baz</ul>',
-		'<ul style=color:red><li>foo<li>[bar]<li>baz</ul>',
+		'<ul style=color:blue><li>foo<li>[bar]<li>baz</ul>',
 		'<ul style=text-indent:1em><li>foo<li>[bar]<li>baz</ul>',
 		'<ul id=abc><li>[foo]<li>bar<li>baz</ul>',
-		'<ul style=color:red><li>[foo]<li>bar<li>baz</ul>',
+		'<ul style=color:blue><li>[foo]<li>bar<li>baz</ul>',
 		'<ul style=text-indent:1em><li>[foo]<li>bar<li>baz</ul>',
 		'<ul id=abc><li>foo<li>bar<li>[baz]</ul>',
-		'<ul style=color:red><li>foo<li>bar<li>[baz]</ul>',
+		'<ul style=color:blue><li>foo<li>bar<li>[baz]</ul>',
 		'<ul style=text-indent:1em><li>foo<li>bar<li>[baz]</ul>',
 	],
 	//@}
@@ -2884,7 +2885,7 @@
 		'<blockquote><div>foo[bar]baz</div></blockquote>',
 		'<blockquote><div id=abc>foo[bar]baz</div></blockquote>',
 		'<blockquote id=abc>foo[bar]baz</blockquote>',
-		'<blockquote style="color: red">foo[bar]baz</blockquote>',
+		'<blockquote style="color: blue">foo[bar]baz</blockquote>',
 
 		'<blockquote><blockquote><p>foo[bar]<p>baz</blockquote></blockquote>',
 		'<blockquote><blockquote data-abc=def><p>foo[bar]<p>baz</blockquote></blockquote>',
@@ -2892,13 +2893,13 @@
 		'<blockquote><div><p>foo[bar]<p>baz</div></blockquote>',
 		'<blockquote><div id=abc><p>foo[bar]<p>baz</div></blockquote>',
 		'<blockquote id=abc><p>foo[bar]<p>baz</blockquote>',
-		'<blockquote style="color: red"><p>foo[bar]<p>baz</blockquote>',
+		'<blockquote style="color: blue"><p>foo[bar]<p>baz</blockquote>',
 
 		'<blockquote><p><b>foo[bar]</b><p>baz</blockquote>',
 		'<blockquote><p><strong>foo[bar]</strong><p>baz</blockquote>',
 		'<blockquote><p><span>foo[bar]</span><p>baz</blockquote>',
-		'<blockquote><blockquote style="color: red"><p>foo[bar]</blockquote><p>baz</blockquote>',
-		'<blockquote style="color: red"><blockquote><p>foo[bar]</blockquote><p>baz</blockquote>',
+		'<blockquote><blockquote style="color: blue"><p>foo[bar]</blockquote><p>baz</blockquote>',
+		'<blockquote style="color: blue"><blockquote><p>foo[bar]</blockquote><p>baz</blockquote>',
 
 		// Lists!
 		'<ol><li>foo<li>[bar]<li>baz</ol>',
@@ -2942,19 +2943,19 @@
 		// Attribute handling on lists
 		'foo<ol start=5><li>[bar]</ol>baz',
 		'foo<ol id=abc><li>[bar]</ol>baz',
-		'foo<ol style=color:red><li>[bar]</ol>baz',
+		'foo<ol style=color:blue><li>[bar]</ol>baz',
 		'foo<ol><li value=5>[bar]</ol>baz',
 		'foo<ol><li id=abc>[bar]</ol>baz',
-		'foo<ol><li style=color:red>[bar]</ol>baz',
+		'foo<ol><li style=color:blue>[bar]</ol>baz',
 		'<ol><li>foo</li><ol><li value=5>[bar]</ol></ol>',
 		'<ul><li>foo</li><ol><li value=5>[bar]</ol></ul>',
 		'<ol><li>foo</li><ol start=5><li>[bar]</ol><li>baz</ol>',
 		'<ol><li>foo</li><ol id=abc><li>[bar]</ol><li>baz</ol>',
-		'<ol><li>foo</li><ol style=color:red><li>[bar]</ol><li>baz</ol>',
+		'<ol><li>foo</li><ol style=color:blue><li>[bar]</ol><li>baz</ol>',
 		'<ol><li>foo</li><ol style=text-indent:1em><li>[bar]</ol><li>baz</ol>',
 		'<ol><li>foo</li><ol start=5><li>[bar<li>baz]</ol><li>quz</ol>',
 		'<ol><li>foo</li><ol id=abc><li>[bar<li>baz]</ol><li>quz</ol>',
-		'<ol><li>foo</li><ol style=color:red><li>[bar<li>baz]</ol><li>quz</ol>',
+		'<ol><li>foo</li><ol style=color:blue><li>[bar<li>baz]</ol><li>quz</ol>',
 		'<ol><li>foo</li><ol style=text-indent:1em><li>[bar<li>baz]</ol><li>quz</ol>',
 
 		// List inside indentation element
@@ -3014,8 +3015,8 @@
 		'foo<em>b[a]r</em>baz',
 		'[foo<font>bar</font>baz]',
 		'foo<font>b[a]r</font>baz',
-		'[foo<font color=red>bar</font>baz]',
-		'foo<font color=red>b[a]r</font>baz',
+		'[foo<font color=blue>bar</font>baz]',
+		'foo<font color=blue>b[a]r</font>baz',
 		'[foo<i>bar</i>baz]',
 		'foo<i>b[a]r</i>baz',
 		'[foo<ins>bar</ins>baz]',
@@ -3059,7 +3060,7 @@
 		'[foo<img src=abc>bar]',
 		'[foo<video></video>bar]',
 		'[foo<video src=abc></video>bar]',
-		'[foo<svg><circle fill=red r=20 cx=20 cy=20 /></svg>bar]',
+		'[foo<svg><circle fill=blue r=20 cx=20 cy=20 /></svg>bar]',
 
 		// Unrecognized elements
 		'[foo<nonexistentelement>bar</nonexistentelement>baz]',
@@ -3074,8 +3075,8 @@
 		'foo<span class=foo>b[a]r</span>baz',
 		'[foo<b style="font-weight: normal">bar</b>baz]',
 		'foo<b style="font-weight: normal">b[a]r</b>baz',
-		'<p style="background-color: red">foo[bar]baz</p>',
-		'<p><span style="background-color: red">foo[bar]baz</span></p>',
+		'<p style="background-color: blue">foo[bar]baz</p>',
+		'<p><span style="background-color: blue">foo[bar]baz</span></p>',
 		'<p style="font-weight: bold">foo[bar]baz</p>',
 		'<b><p style="font-weight: bold">foo[bar]baz</p></b>',
 		'<p style="font-variant: small-caps">foo[bar]baz</p>',
@@ -3104,8 +3105,8 @@
 		'foo<u>[bar]</u>baz',
 		'foo<span style="text-decoration: underline">[bar]</span>baz',
 		'<u>foo[bar]baz</u>',
-		'<u>foo[b<span style="color:red">ar]ba</span>z</u>',
-		'<u>foo[b<span style="color:red" id=foo>ar]ba</span>z</u>',
+		'<u>foo[b<span style="color:blue">ar]ba</span>z</u>',
+		'<u>foo[b<span style="color:blue" id=foo>ar]ba</span>z</u>',
 		'<u>foo[b<span style="font-size:3em">ar]ba</span>z</u>',
 		'<u>foo[b<i>ar]ba</i>z</u>',
 		'<p style="text-decoration: underline">foo[bar]baz</p>',
@@ -3113,30 +3114,30 @@
 		'foo<s>[bar]</s>baz',
 		'foo<span style="text-decoration: line-through">[bar]</span>baz',
 		'<s>foo[bar]baz</s>',
-		'<s>foo[b<span style="color:red">ar]ba</span>z</s>',
-		'<s>foo[b<span style="color:red" id=foo>ar]ba</span>z</s>',
+		'<s>foo[b<span style="color:blue">ar]ba</span>z</s>',
+		'<s>foo[b<span style="color:blue" id=foo>ar]ba</span>z</s>',
 		'<s>foo[b<span style="font-size:3em">ar]ba</span>z</s>',
 		'<s>foo[b<i>ar]ba</i>z</s>',
 		'<p style="text-decoration: line-through">foo[bar]baz</p>',
 
 		'foo<strike>[bar]</strike>baz',
 		'<strike>foo[bar]baz</strike>',
-		'<strike>foo[b<span style="color:red">ar]ba</span>z</strike>',
-		'<strike>foo[b<span style="color:red" id=foo>ar]ba</span>z</strike>',
+		'<strike>foo[b<span style="color:blue">ar]ba</span>z</strike>',
+		'<strike>foo[b<span style="color:blue" id=foo>ar]ba</span>z</strike>',
 		'<strike>foo[b<span style="font-size:3em">ar]ba</span>z</strike>',
 		'<strike>foo[b<i>ar]ba</i>z</strike>',
 
 		'foo<ins>[bar]</ins>baz',
 		'<ins>foo[bar]baz</ins>',
-		'<ins>foo[b<span style="color:red">ar]ba</span>z</ins>',
-		'<ins>foo[b<span style="color:red" id=foo>ar]ba</span>z</ins>',
+		'<ins>foo[b<span style="color:blue">ar]ba</span>z</ins>',
+		'<ins>foo[b<span style="color:blue" id=foo>ar]ba</span>z</ins>',
 		'<ins>foo[b<span style="font-size:3em">ar]ba</span>z</ins>',
 		'<ins>foo[b<i>ar]ba</i>z</ins>',
 
 		'foo<del>[bar]</del>baz',
 		'<del>foo[bar]baz</del>',
-		'<del>foo[b<span style="color:red">ar]ba</span>z</del>',
-		'<del>foo[b<span style="color:red" id=foo>ar]ba</span>z</del>',
+		'<del>foo[b<span style="color:blue">ar]ba</span>z</del>',
+		'<del>foo[b<span style="color:blue" id=foo>ar]ba</span>z</del>',
 		'<del>foo[b<span style="font-size:3em">ar]ba</span>z</del>',
 		'<del>foo[b<i>ar]ba</i>z</del>',
 
@@ -3297,8 +3298,8 @@
 		'foo<u>[bar]</u>baz',
 		'foo<span style="text-decoration: underline">[bar]</span>baz',
 		'<u>foo[bar]baz</u>',
-		'<u>foo[b<span style="color:red">ar]ba</span>z</u>',
-		'<u>foo[b<span style="color:red" id=foo>ar]ba</span>z</u>',
+		'<u>foo[b<span style="color:blue">ar]ba</span>z</u>',
+		'<u>foo[b<span style="color:blue" id=foo>ar]ba</span>z</u>',
 		'<u>foo[b<span style="font-size:3em">ar]ba</span>z</u>',
 		'<u>foo[b<i>ar]ba</i>z</u>',
 		'<p style="text-decoration: underline">foo[bar]baz</p>',
@@ -3306,30 +3307,30 @@
 		'foo<s>[bar]</s>baz',
 		'foo<span style="text-decoration: line-through">[bar]</span>baz',
 		'<s>foo[bar]baz</s>',
-		'<s>foo[b<span style="color:red">ar]ba</span>z</s>',
-		'<s>foo[b<span style="color:red" id=foo>ar]ba</span>z</s>',
+		'<s>foo[b<span style="color:blue">ar]ba</span>z</s>',
+		'<s>foo[b<span style="color:blue" id=foo>ar]ba</span>z</s>',
 		'<s>foo[b<span style="font-size:3em">ar]ba</span>z</s>',
 		'<s>foo[b<i>ar]ba</i>z</s>',
 		'<p style="text-decoration: line-through">foo[bar]baz</p>',
 
 		'foo<strike>[bar]</strike>baz',
 		'<strike>foo[bar]baz</strike>',
-		'<strike>foo[b<span style="color:red">ar]ba</span>z</strike>',
-		'<strike>foo[b<span style="color:red" id=foo>ar]ba</span>z</strike>',
+		'<strike>foo[b<span style="color:blue">ar]ba</span>z</strike>',
+		'<strike>foo[b<span style="color:blue" id=foo>ar]ba</span>z</strike>',
 		'<strike>foo[b<span style="font-size:3em">ar]ba</span>z</strike>',
 		'<strike>foo[b<i>ar]ba</i>z</strike>',
 
 		'foo<ins>[bar]</ins>baz',
 		'<ins>foo[bar]baz</ins>',
-		'<ins>foo[b<span style="color:red">ar]ba</span>z</ins>',
-		'<ins>foo[b<span style="color:red" id=foo>ar]ba</span>z</ins>',
+		'<ins>foo[b<span style="color:blue">ar]ba</span>z</ins>',
+		'<ins>foo[b<span style="color:blue" id=foo>ar]ba</span>z</ins>',
 		'<ins>foo[b<span style="font-size:3em">ar]ba</span>z</ins>',
 		'<ins>foo[b<i>ar]ba</i>z</ins>',
 
 		'foo<del>[bar]</del>baz',
 		'<del>foo[bar]baz</del>',
-		'<del>foo[b<span style="color:red">ar]ba</span>z</del>',
-		'<del>foo[b<span style="color:red" id=foo>ar]ba</span>z</del>',
+		'<del>foo[b<span style="color:blue">ar]ba</span>z</del>',
+		'<del>foo[b<span style="color:blue" id=foo>ar]ba</span>z</del>',
 		'<del>foo[b<span style="font-size:3em">ar]ba</span>z</del>',
 		'<del>foo[b<i>ar]ba</i>z</del>',
 
@@ -3414,13 +3415,13 @@
 
 var defaultValues = {
 //@{
-	backcolor: "#FF8888",
+	backcolor: "#00FFFF",
 	createlink: "http://www.google.com/",
 	fontname: "sans-serif",
 	fontsize: "4",
-	forecolor: "#FF0000",
+	forecolor: "#0000FF",
 	formatblock: "<div>",
-	hilitecolor: "#FF8888",
+	hilitecolor: "#00FFFF",
 	inserthorizontalrule: "",
 	inserthtml: "ab<b>c</b>d",
 	insertimage: "/img/lion.svg",
@@ -3430,9 +3431,7 @@
 
 var notes = {
 //@{
-	backcolor: '<strong>Note:</strong> No spec has yet been written, so the spec column does nothing.',
 	fontname: 'Note that the body\'s font-family is "serif".',
-	hilitecolor: 'In IE we run backColor instead of hiliteColor.',
 };
 //@}
 
@@ -3512,6 +3511,69 @@
 }
 //@}
 
+function queryOutputHelper(beforeIndeterm, beforeState, beforeValue, afterIndeterm, afterState, afterValue, command, value) {
+//@{
+	var frag = document.createDocumentFragment();
+	var beforeDiv = document.createElement("div");
+	var afterDiv = document.createElement("div");
+	frag.appendChild(beforeDiv);
+	frag.appendChild(afterDiv);
+	beforeDiv.className = afterDiv.className = "extra-results";
+	beforeDiv.textContent = "Before: ";
+	afterDiv.textContent = "After: ";
+
+	beforeDiv.appendChild(document.createElement("span"));
+	afterDiv.appendChild(document.createElement("span"));
+	if (afterIndeterm !== "Exception") {
+		afterDiv.lastChild.className =
+			!afterIndeterm
+				? "good-result"
+				: "bad-result";
+	}
+	beforeDiv.lastChild.textContent = "indeterm " + beforeIndeterm;
+	afterDiv.lastChild.textContent = "indeterm " + afterIndeterm;
+
+	beforeDiv.appendChild(document.createTextNode(", "));
+	afterDiv.appendChild(document.createTextNode(", "));
+
+	beforeDiv.appendChild(document.createElement("span"));
+	afterDiv.appendChild(document.createElement("span"));
+	if (beforeState !== "Exception" || afterState !== "Exception") {
+		beforeDiv.lastChild.className =
+		afterDiv.lastChild.className =
+			beforeState !== "Exception" && afterState !== "Exception" && beforeState === !afterState
+				? "good-result"
+				: "bad-result";
+	}
+	beforeDiv.lastChild.textContent = "state " + beforeState;
+	afterDiv.lastChild.textContent = "state " + afterState;
+
+	beforeDiv.appendChild(document.createTextNode(", "));
+	afterDiv.appendChild(document.createTextNode(", "));
+
+	// Hack to get highlighting working right for colors
+	if (command == "backcolor" || command == "forecolor" || command == "hilitecolor") {
+		if (/^([0-9a-fA-F]{3}){1,2}$/.test(value)) {
+			value = "#" + value;
+		}
+	}
+
+	beforeDiv.appendChild(document.createElement("span"));
+	afterDiv.appendChild(document.createElement("span"));
+	if (afterValue !== "Exception"
+	&& typeof value != "undefined") {
+		afterDiv.lastChild.className =
+			valuesEqual(command, afterValue, value)
+				? "good-result"
+				: "bad-result";
+	}
+	beforeDiv.lastChild.textContent = "value " + beforeValue;
+	afterDiv.lastChild.textContent = "value " + afterValue;
+
+	return frag;
+}
+//@}
+
 function doInputCell(tr, test) {
 //@{
 	var value = null;
@@ -3553,8 +3615,24 @@
 		}
 		specCell.firstChild.contentEditable = "true";
 		specCell.firstChild.spellcheck = false;
-		myExecCommand("styleWithCSS", false, styleWithCss);
+		myExecCommand("styleWithCSS", false, styleWithCss, range);
+
+		try { var beforeIndeterm = myQueryCommandIndeterm(command, range) }
+		catch(e) { beforeIndeterm = "Exception" }
+		try { var beforeState = myQueryCommandState(command, range) }
+		catch(e) { beforeState = "Exception" }
+		try { var beforeValue = myQueryCommandValue(command, range) }
+		catch(e) { beforeValue = "Exception" }
+
 		myExecCommand(command, false, value, range);
+
+		try { var afterIndeterm = myQueryCommandIndeterm(command, range) }
+		catch(e) { afterIndeterm = "Exception" }
+		try { var afterState = myQueryCommandState(command, range) }
+		catch(e) { afterState = "Exception" }
+		try { var afterValue = myQueryCommandValue(command, range) }
+		catch(e) { afterValue = "Exception" }
+
 		specCell.firstChild.contentEditable = "inherit";
 		specCell.firstChild.removeAttribute("spellcheck");
 		var compareDiv1 = specCell.firstChild.cloneNode(true);
@@ -3586,6 +3664,10 @@
 		}
 
 		specCell.lastChild.textContent = specCell.firstChild.innerHTML;
+		specCell.lastChild.appendChild(queryOutputHelper(
+			beforeIndeterm, beforeState, beforeValue,
+			afterIndeterm, afterState, afterValue,
+			command, value));
 	} catch (e) {
 		specCell.firstChild.contentEditable = "inherit";
 		specCell.firstChild.removeAttribute("spellcheck");