Start massive rewrite of inline formatting
authorAryeh Gregor <AryehGregor+gitcommit@gmail.com>
Fri, 08 Jul 2011 14:15:56 -0600
changeset 375 9e86f88d0da1
parent 374 34e650d18684
child 376 8cdcd95ad211
Start massive rewrite of inline formatting

Considerably shorter and simpler, but has the same effect. More changes
likely to come.
editcommands.html
implementation.js
preprocess
source.html
--- a/editcommands.html	Fri Jul 08 12:51:44 2011 -0600
+++ b/editcommands.html	Fri Jul 08 14:15:56 2011 -0600
@@ -84,25 +84,24 @@
   <ol>
    <li><a href=#inline-formatting-command-definitions><span class=secno>7.1 </span>Inline formatting command definitions</a></li>
    <li><a href=#assorted-inline-formatting-command-algorithms><span class=secno>7.2 </span>Assorted inline formatting command algorithms</a></li>
-   <li><a href=#decomposing-a-range-into-nodes><span class=secno>7.3 </span>Decomposing a range into nodes</a></li>
-   <li><a href="#clearing-an-element's-value"><span class=secno>7.4 </span>Clearing an element's value</a></li>
-   <li><a href=#pushing-down-values><span class=secno>7.5 </span>Pushing down values</a></li>
-   <li><a href=#forcing-the-value-of-a-node><span class=secno>7.6 </span>Forcing the value of a node</a></li>
-   <li><a href=#setting-the-value-of-a-node><span class=secno>7.7 </span>Setting the value of a node</a></li>
-   <li><a href=#the-backcolor-command><span class=secno>7.8 </span>The <code title="">backColor</code> command</a></li>
-   <li><a href=#the-bold-command><span class=secno>7.9 </span>The <code title="">bold</code> command</a></li>
-   <li><a href=#the-createlink-command><span class=secno>7.10 </span>The <code title="">createLink</code> command</a></li>
-   <li><a href=#the-fontname-command><span class=secno>7.11 </span>The <code title="">fontName</code> command</a></li>
-   <li><a href=#the-fontsize-command><span class=secno>7.12 </span>The <code title="">fontSize</code> command</a></li>
-   <li><a href=#the-forecolor-command><span class=secno>7.13 </span>The <code title="">foreColor</code> command</a></li>
-   <li><a href=#the-hilitecolor-command><span class=secno>7.14 </span>The <code title="">hiliteColor</code> command</a></li>
-   <li><a href=#the-italic-command><span class=secno>7.15 </span>The <code title="">italic</code> command</a></li>
-   <li><a href=#the-removeformat-command><span class=secno>7.16 </span>The <code title="">removeFormat</code> command</a></li>
-   <li><a href=#the-strikethrough-command><span class=secno>7.17 </span>The <code title="">strikethrough</code> command</a></li>
-   <li><a href=#the-subscript-command><span class=secno>7.18 </span>The <code title="">subscript</code> command</a></li>
-   <li><a href=#the-superscript-command><span class=secno>7.19 </span>The <code title="">superscript</code> command</a></li>
-   <li><a href=#the-underline-command><span class=secno>7.20 </span>The <code title="">underline</code> command</a></li>
-   <li><a href=#the-unlink-command><span class=secno>7.21 </span>The <code title="">unlink</code> command</a></ol></li>
+   <li><a href="#clearing-an-element's-value"><span class=secno>7.3 </span>Clearing an element's value</a></li>
+   <li><a href=#pushing-down-values><span class=secno>7.4 </span>Pushing down values</a></li>
+   <li><a href=#forcing-the-value-of-a-node><span class=secno>7.5 </span>Forcing the value of a node</a></li>
+   <li><a href="#setting-the-selection's-value"><span class=secno>7.6 </span>Setting the selection's value</a></li>
+   <li><a href=#the-backcolor-command><span class=secno>7.7 </span>The <code title="">backColor</code> command</a></li>
+   <li><a href=#the-bold-command><span class=secno>7.8 </span>The <code title="">bold</code> command</a></li>
+   <li><a href=#the-createlink-command><span class=secno>7.9 </span>The <code title="">createLink</code> command</a></li>
+   <li><a href=#the-fontname-command><span class=secno>7.10 </span>The <code title="">fontName</code> command</a></li>
+   <li><a href=#the-fontsize-command><span class=secno>7.11 </span>The <code title="">fontSize</code> command</a></li>
+   <li><a href=#the-forecolor-command><span class=secno>7.12 </span>The <code title="">foreColor</code> command</a></li>
+   <li><a href=#the-hilitecolor-command><span class=secno>7.13 </span>The <code title="">hiliteColor</code> command</a></li>
+   <li><a href=#the-italic-command><span class=secno>7.14 </span>The <code title="">italic</code> command</a></li>
+   <li><a href=#the-removeformat-command><span class=secno>7.15 </span>The <code title="">removeFormat</code> command</a></li>
+   <li><a href=#the-strikethrough-command><span class=secno>7.16 </span>The <code title="">strikethrough</code> command</a></li>
+   <li><a href=#the-subscript-command><span class=secno>7.17 </span>The <code title="">subscript</code> command</a></li>
+   <li><a href=#the-superscript-command><span class=secno>7.18 </span>The <code title="">superscript</code> command</a></li>
+   <li><a href=#the-underline-command><span class=secno>7.19 </span>The <code title="">underline</code> command</a></li>
+   <li><a href=#the-unlink-command><span class=secno>7.20 </span>The <code title="">unlink</code> command</a></ol></li>
  <li><a href=#block-formatting-commands><span class=secno>8 </span>Block formatting commands</a>
   <ol>
    <li><a href=#block-formatting-command-definitions><span class=secno>8.1 </span>Block formatting command definitions</a></li>
@@ -1069,32 +1068,35 @@
 that 1) in <b>[foo]</b>, the text node and the <b> are effectively contained
 but not contained; and 2) in <b>f[o]o</b>, the text node is effectively
 contained but not contained, and the <b> is neither effectively contained nor
-contained.  This is used mostly for the "decompose" algorithm, and also for
-most inline commands' states.
+contained.
 -->
 <ul>
   <li><var title="">node</var> is <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#contained>contained</a> in <var title="">range</var>.
 
   <li><var title="">node</var> is <var title="">range</var>'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>, it is 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-node-length title=concept-node-length>length</a> is different from <var title="">range</var>'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-offset title=concept-boundary-point-offset>offset</a>.
+  node, its <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-node-length title=concept-node-length>length</a> is different from <var title="">range</var>'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-offset title=concept-boundary-point-offset>offset</a>, and <var title="">range</var> is not <code class=external data-anolis-spec=domrange title=dom-Range-collapsed><a href=http://html5.org/specs/dom-range.html#dom-range-collapsed>collapsed</a></code>.
+  <!-- So like <b>f[oo]</b> or <b>f[o]o</b> or <b>f[oo</b>}, but not
+  <b>foo[</b>} or <b>f[]oo</b>. -->
 
   <li><var title="">node</var> is <var title="">range</var>'s <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range-end title=concept-range-end>end</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>, it is 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 <var title="">range</var>'s <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range-end title=concept-range-end>end</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 not 0.
+  <var title="">range</var>'s <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range-end title=concept-range-end>end</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 not 0, and <var title="">range</var> is not
+  <code class=external data-anolis-spec=domrange title=dom-Range-collapsed><a href=http://html5.org/specs/dom-range.html#dom-range-collapsed>collapsed</a></code>.
 
   <li><var title="">node</var> has at least one <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>child</a>; and all its <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>children</a> are
   <a href=#effectively-contained>effectively contained</a> in <var title="">range</var>; and either
   <var title="">range</var>'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 not a <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-descendant title=concept-tree-descendant>descendant</a> of <var title="">node</var>
-  or is not 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 or <var title="">range</var>'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-offset title=concept-boundary-point-offset>offset</a> is zero; and
-  either <var title="">range</var>'s <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range-end title=concept-range-end>end</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 not a <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-descendant title=concept-tree-descendant>descendant</a> of
-  <var title="">node</var> or is not 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 or <var title="">range</var>'s <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range-end title=concept-range-end>end</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 its <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range-end title=concept-range-end>end</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>.
+  or is not 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 or <var title="">range</var>'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-offset title=concept-boundary-point-offset>offset</a> is zero or
+  <var title="">range</var> is <code class=external data-anolis-spec=domrange title=dom-Range-collapsed><a href=http://html5.org/specs/dom-range.html#dom-range-collapsed>collapsed</a></code>; and either <var title="">range</var>'s <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range-end title=concept-range-end>end</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 not a <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-descendant title=concept-tree-descendant>descendant</a> of <var title="">node</var> or is not 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 or
+  <var title="">range</var>'s <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range-end title=concept-range-end>end</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 its <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range-end title=concept-range-end>end</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> or
+  <var title="">range</var> is <code class=external data-anolis-spec=domrange title=dom-Range-collapsed><a href=http://html5.org/specs/dom-range.html#dom-range-collapsed>collapsed</a></code>.
   <!--
   Basically, anything whose children are all effectively contained should be
   effectively contained itself, except that in a case like <b>f[o]o</b> we
   don't want <b> to be effectively contained even though the text node is.
-  That's because as soon as we decompose the range, the text node is split and
-  the <b> will no longer be effectively contained.
+  That's because we split the text node before we actually do anything, and the
+  <b> will no longer be effectively contained.
   -->
 </ul>
 
@@ -1385,37 +1387,7 @@
 </ol>
 
 
-<h3 id=decomposing-a-range-into-nodes><span class=secno>7.3 </span>Decomposing a range into nodes</h3>
-
-<p>To <dfn id=decompose>decompose</dfn> a <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range title=concept-range>range</a> <var title="">range</var>:
-
-<p class=note>For this algorithm to be correct, it is essential that user
-agents follow the <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#range-mutation-rules>range mutation rules</a>, particularly those for <code title="">splitText()</code>.
-
-<ol>
-  <li>If <var title="">range</var>'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> and <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range-end title=concept-range-end>end</a> are the same,
-  return an empty list.
-
-  <li>If <var title="">range</var>'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 0 nor the <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-node-length title=concept-node-length>length</a> of 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>, run <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 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> with argument equal to 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>.
-
-  <li>If <var title="">range</var>'s <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range-end title=concept-range-end>end</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-end title=concept-range-end>end</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 0 nor the
-  <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-node-length title=concept-node-length>length</a> of its <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range-end title=concept-range-end>end</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>, run <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 its
-  <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range-end title=concept-range-end>end</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> with argument equal to its <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range-end title=concept-range-end>end</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>.
-
-  <!-- We want to make sure the returned list contains as many nodes as
-  possible, such as by treating <tag>[foo]</tag> as {<tag>foo</tag>}. -->
-  <li>Return a list consisting of every <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node title=concept-node>node</a> <a href=#effectively-contained>effectively
-  contained</a> in <var title="">range</var>, omitting any whose <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-parent title=concept-tree-parent>parent</a> is also
-  <a href=#effectively-contained>effectively contained</a> in <var title="">range</var>.
-</ol>
-
-
-<h3 id="clearing-an-element's-value"><span class=secno>7.4 </span>Clearing an element's value</h3>
+<h3 id="clearing-an-element's-value"><span class=secno>7.3 </span>Clearing an element's value</h3>
 
 <p>To <dfn id=clear-the-value>clear the value</dfn> of an <code class=external data-anolis-spec=domcore><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#element>Element</a></code> <var title="">element</var>:
 
@@ -1491,7 +1463,7 @@
 </ol>
 
 
-<h3 id=pushing-down-values><span class=secno>7.5 </span>Pushing down values</h3>
+<h3 id=pushing-down-values><span class=secno>7.4 </span>Pushing down values</h3>
 
 <p>To <dfn id=push-down-values>push down values</dfn> to a <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node title=concept-node>node</a> <var title="">node</var>, given a new
 value <var title="">new value</var>:
@@ -1635,7 +1607,7 @@
 </ol>
 
 
-<h3 id=forcing-the-value-of-a-node><span class=secno>7.6 </span>Forcing the value of a node</h3>
+<h3 id=forcing-the-value-of-a-node><span class=secno>7.5 </span>Forcing the value of a node</h3>
 
 <p>To <dfn id=force-the-value>force the value</dfn> of a <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node title=concept-node>node</a> <var title="">node</var> to <var title="">new
 value</var>:
@@ -1893,22 +1865,22 @@
 </ol>
 
 
-<h3 id=setting-the-value-of-a-node><span class=secno>7.7 </span>Setting the value of a node</h3>
-
-<p>To <dfn id=set-the-value>set the value</dfn> of a <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node title=concept-node>node</a> <var title="">node</var> to <var title="">new
-value</var>:
+<h3 id="setting-the-selection's-value"><span class=secno>7.6 </span>Setting the selection's value</h3>
+
+<p>To <dfn id="set-the-selection's-value">set the selection's value</dfn> to <var title="">new value</var>:
 
 <div class=note>
-<p>The effect of this algorithm is to ensure that the node and all its
-descendants have the style requested, no matter what, producing the simplest
-markup possible to achieve that effect.  It's inspired by the approach WebKit
-takes.  The only places where the algorithm should fail are when there's an
-!important CSS rule that conflicts with the requested style (which we don't try
-to override because we assume it's !important for a reason), or when it's
-literally impossible to succeed (such as when a text-decoration is propagated
-from an ancestor we can't reach).  Any other failures are bugs.
-
-<p>First, if the node is an element with an inline style rule for this
+<p>The effect of this algorithm is to ensure that all nodes effectively
+contained in the selection have the style requested, no matter what, producing
+the simplest markup possible to achieve that effect.  It's inspired by the
+approach WebKit takes.  The only places where the algorithm should fail are
+when there's an !important CSS rule that conflicts with the requested style
+(which we don't try to override because we assume it's !important for a
+reason), or when it's literally impossible to succeed (such as when a
+text-decoration is propagated from an ancestor we can't reach).  Any other
+failures are bugs.
+
+<p>First, if a node is an element with an inline style rule for this
 property, we unset it ("clearing styles").  This step also removes <a href=#simple-modifiable-element title="simple modifiable element">simple modifiable elements</a> entirely, and
 replaces elements like <code class=external data-anolis-spec=html title="the b element"><a href=http://www.whatwg.org/html/#the-b-element>b</a></code> or <code class=external data-anolis-spec=html title=font><a href=http://www.whatwg.org/html/#font>font</a></code> with <code class=external data-anolis-spec=html title="the span element"><a href=http://www.whatwg.org/html/#the-span-element>span</a></code>s if they aren't simple
 styling elements.  This will be sufficient if the desired style is inherited
@@ -1964,15 +1936,34 @@
 as desired.
 </div>
 
-<p class=XXX>Consider porting this algorithm to operate on runs of consecutive
-siblings instead of individual nodes.  We might be able to make some parts
-smarter, and also might be able to make it more efficient.
-
 <ol>
   <li>Let <var title="">command</var> be the current <a href=#command>command</a>.
 
-  <li>If <var title="">node</var> is not <a href=#editable>editable</a>:
+  <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
+  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>, with argument equal to 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-offset title=concept-boundary-point-offset>offset</a>.  Then set 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> to the result, 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> to zero.
+  <!-- This last sentence just prettifies the resulting range a bit. -->
+
+  <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-end title=concept-range-end>end</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-end title=concept-range-end>end</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-end title=concept-range-end>end</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
+  range</a>'s <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range-end title=concept-range-end>end</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>, with argument equal to 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-end title=concept-range-end>end</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>.
+
+  <li>Let <var title="">element list</var> be all <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#element>Element</a></code>s
+  <a href=#effectively-contained>effectively contained</a> in the <a href=#active-range>active range</a>.
+
+  <li>For each <var title="">element</var> in <var title="">element list</var>, <a href=#clear-the-value>clear the
+  value</a> of <var title="">element</var>.
+
+  <li>Let <var title="">node list</var> be all <a href=#editable>editable</a> <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node title=concept-node>nodes</a>
+  <a href=#effectively-contained>effectively contained</a> in the <a href=#active-range>active range</a>.
   <!--
+  We skip non-editable nodes.
+
   IE9: Allows everything to be modified by execCommand(), regardless of whether
     it's editable.
   Firefox 4.0: Ignores execCommand() if the start and end of the selection are
@@ -2006,41 +1997,17 @@
   are bolded, it will unbold instead of bolding.
   -->
 
-  <ol>
-    <li>Let <var title="">children</var> be the <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>children</a> of <var title="">node</var>.
-
-    <li><a href=#set-the-value>Set the value</a> of each member of <var title="">children</var>.
-
-    <li>Abort this algorithm.
-  </ol>
-
-  <li>If <var title="">node</var> is an <code class=external data-anolis-spec=domcore><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#element>Element</a></code>:
+  <li>For each <var title="">node</var> in <var title="">node list</var>:
 
   <ol>
-    <li><a href=#clear-the-value>Clear the value</a> of <var title="">node</var>, and let <var title="">new
-    nodes</var> be the result.
-
-    <li>For each <var title="">new node</var> in <var title="">new nodes</var>,
-    <a href=#set-the-value>set the value</a> of <var title="">new node</var>.
-
-    <li>If <var title="">node</var>'s <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-parent title=concept-tree-parent>parent</a> is null, abort this algorithm.
+    <li><a href=#push-down-values>Push down values</a> on <var title="">node</var>.
+
+    <li><a href=#force-the-value>Force the value</a> of <var title="">node</var>.
   </ol>
-
-  <li><a href=#push-down-values>Push down values</a> on <var title="">node</var>.
-
-  <li><a href=#force-the-value>Force the value</a> of <var title="">node</var>.
-
-  <li>Let <var title="">children</var> be the <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>children</a> of <var title="">node</var>.
-
-  <li><a href=#set-the-value>Set the value</a> of each member of <var title="">children</var>.
-
-  <p class=note>Styling a node involves clearing its styles, which can remove
-  it from the tree.  Implementers should be careful to compute the list of
-  children in full before they begin styling.
 </ol>
 
 
-<h3 id=the-backcolor-command><span class=secno>7.8 </span><dfn>The <code title="">backColor</code> command</dfn></h3>
+<h3 id=the-backcolor-command><span class=secno>7.7 </span><dfn>The <code title="">backColor</code> command</dfn></h3>
 
 <!--
 We have three behaviors to choose from for this one:
@@ -2084,8 +2051,7 @@
   <li>If <var title="">value</var> is still not a valid CSS color, or if it is
   currentColor, raise a <code class=external data-anolis-spec=domcore title=dom-DOMException-SYNTAX_ERR><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-domexception-syntax_err>SYNTAX_ERR</a></code> exception.
 
-  <li><a href=#decompose>Decompose</a> the <a href=#active-range>active range</a>, then <a href=#set-the-value>set the
-  value</a> of each returned <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node title=concept-node>node</a> to <var title="">value</var>.
+  <li><a href="#set-the-selection's-value">Set the selection's value</a> to <var title="">value</var>.
 </ol>
 
 <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>
@@ -2102,7 +2068,7 @@
 <p><a href=#relevant-css-property>Relevant CSS property</a>: "background-color"
 
 
-<h3 id=the-bold-command><span class=secno>7.9 </span><dfn>The <code title="">bold</code> command</dfn></h3>
+<h3 id=the-bold-command><span class=secno>7.8 </span><dfn>The <code title="">bold</code> command</dfn></h3>
 
 <!-- If the selection is collapsed (but not if it contains nothing but is not
 collapsed), IE9 wraps the whole line in a <strong>.  This seems bizarre and no
@@ -2110,9 +2076,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>: <a href=#decompose>Decompose</a> the <a href=#active-range>active range</a>.
-If the <a href=#state>state</a> is then false, <a href=#set-the-value>set the value</a> of each
-returned <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node title=concept-node>node</a> to "bold", otherwise <a href=#set-the-value>set the value</a> to "normal".
+<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=#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
@@ -2155,7 +2121,7 @@
 <p><a href=#relevant-css-property>Relevant CSS property</a>: "font-weight"
 
 
-<h3 id=the-createlink-command><span class=secno>7.10 </span><dfn>The <code title="">createLink</code> command</dfn></h3>
+<h3 id=the-createlink-command><span class=secno>7.9 </span><dfn>The <code title="">createLink</code> command</dfn></h3>
 
 <p><a href=#action>Action</a>:
 
@@ -2178,12 +2144,10 @@
   I think that's more useful.  See issues.
   -->
 
-  <li><a href=#decompose>Decompose</a> the <a href=#active-range>active range</a>, and let <var title="">node
-  list</var> be the result.
-
   <li>For each <a href=#editable>editable</a> <code class=external data-anolis-spec=html title="the a element"><a href=http://www.whatwg.org/html/#the-a-element>a</a></code> element that has an <code class=external data-anolis-spec=html title=attr-hyperlink-href><a href=http://www.whatwg.org/html/#attr-hyperlink-href>href</a></code>
-  attribute and is an <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-ancestor title=concept-tree-ancestor>ancestor</a> of some <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node title=concept-node>node</a> in <var title="">node list</var>,
-  set that element's <code class=external data-anolis-spec=html title=attr-hyperlink-href><a href=http://www.whatwg.org/html/#attr-hyperlink-href>href</a></code> attribute to <var title="">value</var>.
+  attribute and is an <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-ancestor title=concept-tree-ancestor>ancestor</a> of some <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node title=concept-node>node</a> <a href=#effectively-contained>effectively
+  contained</a> in the <a href=#active-range>active range</a>, set that <code class=external data-anolis-spec=html title="the a element"><a href=http://www.whatwg.org/html/#the-a-element>a</a></code> element's
+  <code class=external data-anolis-spec=html title=attr-hyperlink-href><a href=http://www.whatwg.org/html/#attr-hyperlink-href>href</a></code> attribute to <var title="">value</var>.
   <!-- There are three approaches here.  For instance, if you ask browsers to
   create a link to "http://example.org" on the "b" here:
 
@@ -2208,8 +2172,7 @@
   really intend to only change the link of part of it?
   -->
 
-  <li><a href=#set-the-value>Set the value</a> of each <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node title=concept-node>node</a> in <var title="">node list</var> to
-  <var title="">value</var>.
+  <li><a href="#set-the-selection's-value">Set the selection's value</a> to <var title="">value</var>.
 </ol>
 
 <!--
@@ -2223,10 +2186,10 @@
 false. -->
 
 
-<h3 id=the-fontname-command><span class=secno>7.11 </span><dfn>The <code title="">fontName</code> command</dfn></h3>
-
-<p><a href=#action>Action</a>: <a href=#decompose>Decompose</a> the <a href=#active-range>active range</a>,
-then <a href=#set-the-value>set the value</a> of each returned <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node title=concept-node>node</a> to <var title="">value</var>.
+<h3 id=the-fontname-command><span class=secno>7.10 </span><dfn>The <code title="">fontName</code> command</dfn></h3>
+
+<p><a href=#action>Action</a>: <a href="#set-the-selection's-value">Set the selection's value</a> to
+<var title="">value</var>.
 <!-- UAs differ a bit in the details here:
 
 IE 9 RC: Empty string sets <font face="">
@@ -2279,7 +2242,7 @@
 <p><a href=#relevant-css-property>Relevant CSS property</a>: "font-family"
 
 
-<h3 id=the-fontsize-command><span class=secno>7.12 </span><dfn>The <code title="">fontSize</code> command</dfn></h3>
+<h3 id=the-fontsize-command><span class=secno>7.11 </span><dfn>The <code title="">fontSize</code> command</dfn></h3>
 
 <p><a href=#action>Action</a>:
 
@@ -2379,8 +2342,7 @@
   allow numeric values.  There's no harm in allowing "x-small" and absolute
   sizes, I don't think.
 
-  <li><a href=#decompose>Decompose</a> the <a href=#active-range>active range</a>, then <a href=#set-the-value>set the
-  value</a> of each returned <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node title=concept-node>node</a> to <var title="">value</var>.
+  <li><a href="#set-the-selection's-value">Set the selection's value</a> to <var title="">value</var>.
 </ol>
 
 <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>
@@ -2448,7 +2410,7 @@
 <p><a href=#relevant-css-property>Relevant CSS property</a>: "font-size"
 
 
-<h3 id=the-forecolor-command><span class=secno>7.13 </span><dfn>The <code title="">foreColor</code> command</dfn></h3>
+<h3 id=the-forecolor-command><span class=secno>7.12 </span><dfn>The <code title="">foreColor</code> command</dfn></h3>
 
 <p><a href=#action>Action</a>:
 
@@ -2516,8 +2478,7 @@
   <!-- currentColor is bad for the same reason as relative font sizes.  It will
   confuse the algorithm, and doesn't seem very useful anyway. -->
 
-  <li><a href=#decompose>Decompose</a> the <a href=#active-range>active range</a>, then <a href=#set-the-value>set the
-  value</a> of each returned <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node title=concept-node>node</a> to <var title="">value</var>.
+  <li><a href="#set-the-selection's-value">Set the selection's value</a> to <var title="">value</var>.
 </ol>
 
 <!-- Opera 11 seems to return true for the state if there's some color style
@@ -2547,7 +2508,7 @@
 <p><a href=#relevant-css-property>Relevant CSS property</a>: "color"
 
 
-<h3 id=the-hilitecolor-command><span class=secno>7.14 </span><dfn>The <code title="">hiliteColor</code> command</dfn></h3>
+<h3 id=the-hilitecolor-command><span class=secno>7.13 </span><dfn>The <code title="">hiliteColor</code> command</dfn></h3>
 
 <!-- IE 9 RC doesn't support this.  It uses backColor instead, but Gecko and
 Opera treat that differently, while all non-IE browsers treat hiliteColor the
@@ -2578,8 +2539,7 @@
   you could conceive of it being useful, but it will still confuse the
   algorithm, so ban it for now anyway. -->
 
-  <li><a href=#decompose>Decompose</a> the <a href=#active-range>active range</a>, then <a href=#set-the-value>set the
-  value</a> of each returned <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node title=concept-node>node</a> to <var title="">value</var>.
+  <li><a href="#set-the-selection's-value">Set the selection's value</a> to <var title="">value</var>.
 </ol>
 
 <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>
@@ -2607,12 +2567,11 @@
 <p><a href=#relevant-css-property>Relevant CSS property</a>: "background-color"
 
 
-<h3 id=the-italic-command><span class=secno>7.15 </span><dfn>The <code title="">italic</code> command</dfn></h3>
-
-<p><a href=#action>Action</a>: <a href=#decompose>Decompose</a> the <a href=#active-range>active range</a>.
-If the <a href=#state>state</a> is then false, <a href=#set-the-value>set the value</a> of each
-returned <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node title=concept-node>node</a> to "italic", otherwise <a href=#set-the-value>set the value</a> to
-"normal".
+<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=#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
@@ -2628,7 +2587,7 @@
 <p><a href=#relevant-css-property>Relevant CSS property</a>: "font-style"
 
 
-<h3 id=the-removeformat-command><span class=secno>7.16 </span><dfn>The <code title="">removeFormat</code> command</dfn></h3>
+<h3 id=the-removeformat-command><span class=secno>7.15 </span><dfn>The <code title="">removeFormat</code> command</dfn></h3>
 
 <!--
 Tested in IE 9, Firefox 4.0, Chrome 12 dev, Opera 11.00.
@@ -2700,8 +2659,22 @@
     <li>Remove <var title="">element</var> from its <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-parent title=concept-tree-parent>parent</a>.
   </ol>
 
-  <li><a href=#decompose>Decompose</a> the <a href=#active-range>active range</a>, and let <var title="">node
-  list</var> be the result.
+  <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
+  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>, with argument equal to 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-offset title=concept-boundary-point-offset>offset</a>.  Then set 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> to the result, 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> to zero.
+  <!-- This last sentence just prettifies the resulting range a bit. -->
+
+  <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-end title=concept-range-end>end</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-end title=concept-range-end>end</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-end title=concept-range-end>end</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
+  range</a>'s <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range-end title=concept-range-end>end</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>, with argument equal to 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-end title=concept-range-end>end</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>.
+
+  <li>Let <var title="">node list</var> consist of all <a href=#editable>editable</a> <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node title=concept-node>nodes</a>
+  <a href=#effectively-contained>effectively contained</a> in the <a href=#active-range>active range</a>.
 
   <li>For each <var title="">node</var> in <var title="">node list</var>, while <var title="">node</var>'s
   <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-parent title=concept-tree-parent>parent</a> is an <a href=#editable>editable</a> <a href=#html-element>HTML element</a> <a href=#in-the-same-editing-host>in the
@@ -2711,10 +2684,9 @@
   <a href=#split-the-parent>split the parent</a> of the one-<a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node title=concept-node>node</a> list consisting of
   <var title="">node</var>.
 
-  <li>For each of the entries in the following list, in the given order:
-  <a href=#decompose>decompose</a> the <a href=#active-range>active range</a> again; then <a href=#set-the-value>set
-  the value</a> of the resulting <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node title=concept-node>nodes</a> to null, with <var title="">command</var>
-  as given.
+  <li>For each of the entries in the following list, in the given order,
+  <a href="#set-the-selection's-value">set the selection's value</a> to null, with <var title="">command</var> as
+  given.
   <!-- For cases like <p style=font-weight:bold>foo[bar]baz</p>. -->
 
   <ol>
@@ -2733,12 +2705,11 @@
 </ol>
 
 
-<h3 id=the-strikethrough-command><span class=secno>7.17 </span><dfn>The <code title="">strikethrough</code> command</dfn></h3>
-
-<p><a href=#action>Action</a>: <a href=#decompose>Decompose</a> the <a href=#active-range>active range</a>.
-If the <a href=#state>state</a> is then false, <a href=#set-the-value>set the value</a> of each
-returned <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node title=concept-node>node</a> to "line-through", otherwise <a href=#set-the-value>set the value</a> to
-null.
+<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 class=XXX>Has all the same problems as <a href=#the-underline-command>the <code title="">underline</code> command</a>.
 
@@ -2757,22 +2728,17 @@
 <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.  Otherwise false.
 
 
-<h3 id=the-subscript-command><span class=secno>7.18 </span><dfn>The <code title="">subscript</code> command</dfn></h3>
+<h3 id=the-subscript-command><span class=secno>7.17 </span><dfn>The <code title="">subscript</code> command</dfn></h3>
 
 <p><a href=#action>Action</a>:
 
 <ol>
-  <li><a href=#decompose>Decompose</a> the <a href=#active-range>active range</a>, and let <var title="">node
-  list</var> be the result.
-
   <li>Let <var title="">state</var> be the <a href=#state>state</a>.
 
-  <li><a href=#set-the-value>Set the value</a> of each <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node title=concept-node>node</a> in <var title="">node list</var> to
-  "baseline".
-
-  <li>If <var title="">state</var> is false, <a href=#decompose>decompose</a> the <a href=#active-range>active
-  range</a> again and <a href=#set-the-value>set the value</a> of each returned <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node title=concept-node>node</a>
-  to "sub".
+  <li><a href="#set-the-selection's-value">Set the selection's value</a> to "baseline".
+
+  <li>If <var title="">state</var> is false, <a href="#set-the-selection's-value">set the selection's value</a> to
+  "sub".
 </ol>
 
 <p><a href=#indeterminate>Indeterminate</a>: True if either among <a href=#editable>editable</a>
@@ -2802,22 +2768,17 @@
 <p><a href=#relevant-css-property>Relevant CSS property</a>: "vertical-align"
 
 
-<h3 id=the-superscript-command><span class=secno>7.19 </span><dfn>The <code title="">superscript</code> command</dfn></h3>
+<h3 id=the-superscript-command><span class=secno>7.18 </span><dfn>The <code title="">superscript</code> command</dfn></h3>
 
 <p><a href=#action>Action</a>:
 
 <ol>
-  <li><a href=#decompose>Decompose</a> the <a href=#active-range>active range</a>, and let <var title="">node
-  list</var> be the result.
-
   <li>Let <var title="">state</var> be the <a href=#state>state</a>.
 
-  <li><a href=#set-the-value>Set the value</a> of each <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node title=concept-node>node</a> in <var title="">node list</var> to
-  "baseline".
-
-  <li>If <var title="">state</var> is false, <a href=#decompose>decompose</a> the <a href=#active-range>active
-  range</a> again and <a href=#set-the-value>set the value</a> of each returned <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node title=concept-node>node</a>
-  to "super".
+  <li><a href="#set-the-selection's-value">Set the selection's value</a> to "baseline".
+
+  <li>If <var title="">state</var> is false, <a href="#set-the-selection's-value">set the selection's value</a> to
+  "super".
 </ol>
 
 <p><a href=#indeterminate>Indeterminate</a>: True if either among <a href=#editable>editable</a>
@@ -2836,11 +2797,11 @@
 <p><a href=#relevant-css-property>Relevant CSS property</a>: "vertical-align"
 
 
-<h3 id=the-underline-command><span class=secno>7.20 </span><dfn>The <code title="">underline</code> command</dfn></h3>
-
-<p><a href=#action>Action</a>: <a href=#decompose>Decompose</a> the <a href=#active-range>active range</a>.
-If the <a href=#state>state</a> is then false, <a href=#set-the-value>set the value</a> of each
-returned <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node title=concept-node>node</a> to "underline", otherwise <a href=#set-the-value>set the value</a> to null.
+<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.
 
 <div class=XXX>
 <p>There are a lot of problems with underline color and thickness, because
@@ -2906,7 +2867,7 @@
 <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.  Otherwise false.
 
 
-<h3 id=the-unlink-command><span class=secno>7.21 </span><dfn>The <code title="">unlink</code> command</dfn></h3>
+<h3 id=the-unlink-command><span class=secno>7.20 </span><dfn>The <code title="">unlink</code> command</dfn></h3>
 
 <p><a href=#action>Action</a>:
 
--- a/implementation.js	Fri Jul 08 12:51:44 2011 -0600
+++ b/implementation.js	Fri Jul 08 14:15:56 2011 -0600
@@ -1289,35 +1289,40 @@
 		return true;
 	}
 
-	// "node is range's start node, it is a Text node, and its length is
-	// different from range's start offset."
+	// "node is range's start node, it is a Text node, its length is different
+	// from range's start offset, and range is not collapsed."
 	if (node == range.startContainer
 	&& node.nodeType == Node.TEXT_NODE
-	&& getNodeLength(node) != range.startOffset) {
+	&& getNodeLength(node) != range.startOffset
+	&& !range.collapsed) {
 		return true;
 	}
 
-	// "node is range's end node, it is a Text node, and range's end offset is
-	// not 0."
+	// "node is range's end node, it is a Text node, range's end offset is not
+	// 0, and range is not collapsed."
 	if (node == range.endContainer
 	&& node.nodeType == Node.TEXT_NODE
-	&& range.endOffset != 0) {
+	&& range.endOffset != 0
+	&& !range.collapsed) {
 		return true;
 	}
 
 	// "node has at least one child; and all its children are effectively
 	// contained in range; and either range's start node is not a descendant of
-	// node or is not a Text node or range's start offset is zero; and either
-	// range's end node is not a descendant of node or is not a Text node or
-	// range's end offset is its end node's length."
+	// node or is not a Text node or range's start offset is zero or range is
+	// collapsed; and either range's end node is not a descendant of node or is
+	// not a Text node or range's end offset is its end node's length or range
+	// is collapsed."
 	if (node.hasChildNodes()
 	&& [].every.call(node.childNodes, function(child) { return isEffectivelyContained(child, range) })
 	&& (!isDescendant(range.startContainer, node)
 	|| range.startContainer.nodeType != Node.TEXT_NODE
-	|| range.startOffset == 0)
+	|| range.startOffset == 0
+	|| range.collapsed)
 	&& (!isDescendant(range.endContainer, node)
 	|| range.endContainer.nodeType != Node.TEXT_NODE
-	|| range.endOffset == getNodeLength(range.endContainer))) {
+	|| range.endOffset == getNodeLength(range.endContainer
+	|| range.collapsed))) {
 		return true;
 	}
 
@@ -1876,58 +1881,6 @@
 
 //@}
 
-///// Decomposing a range into nodes /////
-//@{
-
-function decomposeRange(range) {
-	// "If range's start and end are the same, return an empty list."
-	if (range.startContainer == range.endContainer
-	&& range.startOffset == range.endOffset) {
-		return [];
-	}
-
-	// "If range's start node is an editable Text node and its start offset is
-	// neither 0 nor the length of its start node, run splitText() on its start
-	// node with argument equal to its start offset."
-	if (isEditable(range.startContainer)
-	&& range.startContainer.nodeType == Node.TEXT_NODE
-	&& range.startOffset != 0
-	&& range.startOffset != getNodeLength(range.startContainer)) {
-		// Account for UAs not following range mutation rules
-		if (range.startContainer == range.endContainer) {
-			var newEndOffset = range.endOffset - range.startOffset;
-			var newText = range.startContainer.splitText(range.startOffset);
-			range.setStart(newText, 0);
-			range.setEnd(newText, newEndOffset);
-		} else {
-			var newText = range.startContainer.splitText(range.startOffset);
-			range.setStart(newText, 0);
-		}
-	}
-
-	// "If range's end node is an editable Text node and its end offset is
-	// neither 0 nor the length of its end node, run splitText() on its end
-	// node with argument equal to its end offset."
-	if (isEditable(range.endContainer)
-	&& range.endContainer.nodeType == Node.TEXT_NODE
-	&& range.endOffset != 0
-	&& range.endOffset != getNodeLength(range.endContainer)) {
-		// IE seems to mutate the range incorrectly here, so we need correction
-		// here as well.
-		var newStart = [range.startContainer, range.startOffset];
-		var newEnd = [range.endContainer, range.endOffset];
-		range.endContainer.splitText(range.endOffset);
-		range.setStart(newStart[0], newStart[1]);
-		range.setEnd(newEnd[0], newEnd[1]);
-	}
-
-	// "Return a list consisting of every node effectively contained in range,
-	// omitting any whose parent is also effectively contained in range."
-	return getEffectivelyContainedNodes(range);
-}
-
-//@}
-
 ///// Clearing an element's value /////
 //@{
 
@@ -2465,54 +2418,68 @@
 
 //@}
 
-///// Setting the value of a node /////
+///// Setting the selection's value /////
 //@{
 
-function setNodeValue(node, command, newValue) {
-	// "If node is not editable:"
-	if (!isEditable(node)) {
-		// "Let children be the children of node."
-		var children = Array.prototype.slice.call(node.childNodes);
-
-		// "Set the value of each member of children."
-		for (var i = 0; i < children.length; i++) {
-			setNodeValue(children[i], command, newValue);
-		}
-
-		// "Abort this algorithm."
-		return;
-	}
-
-	// "If node is an Element:"
-	if (node.nodeType == Node.ELEMENT_NODE) {
-		// "Clear the value of node, and let new nodes be the result."
-		var newNodes = clearValue(node, command);
-
-		// "For each new node in new nodes, set the value of new node, with the
-		// same inputs as this invocation of the algorithm."
-		for (var i = 0; i < newNodes.length; i++) {
-			setNodeValue(newNodes[i], command, newValue);
-		}
-
-		// "If node's parent is null, abort this algorithm."
-		if (!node.parentNode) {
-			return;
-		}
-	}
-
-	// "Push down values on node."
-	pushDownValues(node, command, newValue);
-
-	// "Force the value of node."
-	forceValue(node, command, newValue);
-
-	// "Let children be the children of node."
-	var children = Array.prototype.slice.call(node.childNodes);
-
-	// "Set the value of each member of children."
-	for (var i = 0; i < children.length; i++) {
-		setNodeValue(children[i], command, newValue);
-	}
+function setSelectionValue(command, newValue) {
+	// "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
+	// active range's start offset. Then set the active range's start node to
+	// the result, and its start offset to zero."
+	if (isEditable(getActiveRange().startContainer)
+	&& getActiveRange().startContainer.nodeType == Node.TEXT_NODE
+	&& getActiveRange().startOffset != 0
+	&& getActiveRange().startOffset != getNodeLength(getActiveRange().startContainer)) {
+		// Account for browsers not following range mutation rules
+		if (getActiveRange().startContainer == getActiveRange().endContainer) {
+			var newEnd = getActiveRange().endOffset - getActiveRange().startOffset;
+			var newNode = getActiveRange().startContainer.splitText(getActiveRange().startOffset);
+			getActiveRange().setStart(newNode, 0);
+			getActiveRange().setEnd(newNode, newEnd);
+		} else {
+			getActiveRange().setStart(getActiveRange().startContainer.splitText(getActiveRange().startOffset), 0);
+		}
+	}
+
+	// "If the active range's end node is an editable Text node, and its end
+	// offset is neither zero nor its end node's length, call splitText() on
+	// the active range's end node, with argument equal to the active range's
+	// end offset."
+	if (isEditable(getActiveRange().endContainer)
+	&& getActiveRange().endContainer.nodeType == Node.TEXT_NODE
+	&& getActiveRange().endOffset != 0
+	&& getActiveRange().endOffset != getNodeLength(getActiveRange().endContainer)) {
+		// IE seems to mutate the range incorrectly here, so we need correction
+		// here as well.
+		var newStart = [getActiveRange().startContainer, getActiveRange().startOffset];
+		var newEnd = [getActiveRange().endContainer, getActiveRange().endOffset];
+		getActiveRange().endContainer.splitText(getActiveRange().endOffset);
+		getActiveRange().setStart(newStart[0], newStart[1]);
+		getActiveRange().setEnd(newEnd[0], newEnd[1]);
+	}
+
+	// "Let element list be all editable Elements effectively contained in the
+	// active range.
+	//
+	// "For each element in element list, clear the value of element."
+	getAllEffectivelyContainedNodes(getActiveRange(), function(node) {
+		return isEditable(node) && node.nodeType == Node.ELEMENT_NODE;
+	}).forEach(function(element) {
+		clearValue(element, command);
+	});
+
+	// "Let node list be all editable nodes effectively contained in the active
+	// range.
+	//
+	// "For each node in node list:"
+	getAllEffectivelyContainedNodes(getActiveRange(), isEditable).forEach(function(node) {
+		// "Push down values on node."
+		pushDownValues(node, command, newValue);
+
+		// "Force the value of node."
+		forceValue(node, command, newValue);
+	});
 }
 
 //@}
@@ -2540,12 +2507,8 @@
 			throw "SYNTAX_ERR";
 		}
 
-		// "Decompose the active range, then set the value of each returned
-		// node to value."
-		var nodeList = decomposeRange(getActiveRange());
-		for (var i = 0; i < nodeList.length; i++) {
-			setNodeValue(nodeList[i], "backcolor", value);
-		}
+		// "Set the selection's value to value."
+		setSelectionValue("backcolor", value);
 	}, indeterm: function() {
 		// "True if among editable Text nodes that are effectively contained in
 		// the active range, there are two that have distinct effective values.
@@ -2578,13 +2541,12 @@
 //@{
 commands.bold = {
 	action: function() {
-		// "Decompose the active range. If the state is then false, set the
-		// value of each returned node to "bold", otherwise set the value to
-		// "normal"."
-		var nodeList = decomposeRange(getActiveRange());
-		var newValue = commands.bold.state() ? "normal" : "bold";
-		for (var i = 0; i < nodeList.length; i++) {
-			setNodeValue(nodeList[i], "bold", newValue);
+		// "If the state is false, set the selection's value to "bold",
+		// otherwise set the selection's value to "normal"."
+		if (!commands.bold.state()) {
+			setSelectionValue("bold", "bold");
+		} else {
+			setSelectionValue("bold", "normal");
 		}
 	}, indeterm: function() { return indetermHelper(function(node) {
 		// "True if among editable Text nodes that are effectively contained in
@@ -2620,16 +2582,13 @@
 			throw "SYNTAX_ERR";
 		}
 
-		// "Decompose the active range, and let node list be the result."
-		var nodeList = decomposeRange(getActiveRange());
-
 		// "For each editable a element that has an href attribute and is an
-		// ancestor of some node in node list, set that element's href
-		// attribute to value."
+		// ancestor of some node effectively contained in the active range, set
+		// that a element's href attribute to value."
 		//
 		// TODO: We don't actually do this in tree order, not that it matters
 		// unless you're spying with mutation events.
-		nodeList.forEach(function(node) {
+		getAllEffectivelyContainedNodes(getActiveRange()).forEach(function(node) {
 			getAncestors(node).forEach(function(ancestor) {
 				if (isEditable(ancestor)
 				&& isHtmlElement(ancestor, "a")
@@ -2639,10 +2598,8 @@
 			});
 		});
 
-		// "Set the value of each node in node list to value."
-		for (var i = 0; i < nodeList.length; i++) {
-			setNodeValue(nodeList[i], "createlink", value);
-		}
+		// "Set the selection's value to value."
+		setSelectionValue("createlink", value);
 	}
 };
 //@}
@@ -2651,12 +2608,8 @@
 //@{
 commands.fontname = {
 	action: function(value) {
-		// "Decompose the active range, then set the value of each returned
-		// node to value."
-		var nodeList = decomposeRange(getActiveRange());
-		for (var i = 0; i < nodeList.length; i++) {
-			setNodeValue(nodeList[i], "fontname", value);
-		}
+		// "Set the selection's value to value."
+		setSelectionValue("fontname", value);
 	}, indeterm: function() {
 		// "True if among editable Text nodes that are effectively contained in
 		// the active range, there are two that have distinct effective values.
@@ -2760,12 +2713,8 @@
 			throw "SYNTAX_ERR";
 		}
 
-		// "Decompose the active range, then set the value of each returned
-		// node to value."
-		var nodeList = decomposeRange(getActiveRange());
-		for (var i = 0; i < nodeList.length; i++) {
-			setNodeValue(nodeList[i], "fontsize", value);
-		}
+		// "Set the selection's value to value."
+		setSelectionValue("fontsize", value);
 	}, indeterm: function() {
 		// "True if among editable Text nodes that are effectively contained in
 		// the active range, there are two that have distinct effective values.
@@ -2844,12 +2793,8 @@
 			throw "SYNTAX_ERR";
 		}
 
-		// "Decompose the active range, then set the value of each returned
-		// node to value."
-		var nodeList = decomposeRange(getActiveRange());
-		for (var i = 0; i < nodeList.length; i++) {
-			setNodeValue(nodeList[i], "forecolor", value);
-		}
+		// "Set the selection's value to value."
+		setSelectionValue("forecolor", value);
 	}, indeterm: function() {
 		// "True if among editable Text nodes that are effectively contained in
 		// the active range, there are two that have distinct effective values.
@@ -2902,12 +2847,8 @@
 			throw "SYNTAX_ERR";
 		}
 
-		// "Decompose the active range, then set the value of each returned
-		// node to value."
-		var nodeList = decomposeRange(getActiveRange());
-		for (var i = 0; i < nodeList.length; i++) {
-			setNodeValue(nodeList[i], "hilitecolor", value);
-		}
+		// "Set the selection's value to value."
+		setSelectionValue("hilitecolor", value);
 	}, indeterm: function() {
 		// "True if among editable Text nodes that are effectively contained in
 		// the active range, there are two that have distinct effective values.
@@ -2940,13 +2881,12 @@
 //@{
 commands.italic = {
 	action: function() {
-		// "Decompose the active range. If the state is then false, set the
-		// value of each returned node to "italic", otherwise set the value to
-		// "normal"."
-		var nodeList = decomposeRange(getActiveRange());
-		var newValue = commands.italic.state() ? "normal" : "italic";
-		for (var i = 0; i < nodeList.length; i++) {
-			setNodeValue(nodeList[i], "italic", newValue);
+		// "If the state is false, set the selection's value to "italic",
+		// otherwise set the selection's value to "normal"."
+		if (!commands.italic.state()) {
+			setSelectionValue("italic", "italic");
+		} else {
+			setSelectionValue("italic", "normal");
 		}
 	}, indeterm: function() { return indetermHelper(function(node) {
 		// "True if among editable Text nodes that are effectively contained in
@@ -2993,15 +2933,52 @@
 			element.parentNode.removeChild(element);
 		});
 
-		// "Decompose the active range, and let node list be the result."
-		var nodeList = decomposeRange(getActiveRange());
-
+		// "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 active range's start offset. Then set the active range's start
+		// node to the result, and its start offset to zero."
+		if (isEditable(getActiveRange().startContainer)
+		&& getActiveRange().startContainer.nodeType == Node.TEXT_NODE
+		&& getActiveRange().startOffset != 0
+		&& getActiveRange().startOffset != getNodeLength(getActiveRange().startContainer)) {
+			// Account for browsers not following range mutation rules
+			if (getActiveRange().startContainer == getActiveRange().endContainer) {
+				var newEnd = getActiveRange().endOffset - getActiveRange().startOffset;
+				var newNode = getActiveRange().startContainer.splitText(getActiveRange().startOffset);
+				getActiveRange().setStart(newNode, 0);
+				getActiveRange().setEnd(newNode, newEnd);
+			} else {
+				getActiveRange().setStart(getActiveRange().startContainer.splitText(getActiveRange().startOffset), 0);
+			}
+		}
+
+		// "If the active range's end node is an editable Text node, and its
+		// end offset is neither zero nor its end node's length, call
+		// splitText() on the active range's end node, with argument equal to
+		// the active range's end offset."
+		if (isEditable(getActiveRange().endContainer)
+		&& getActiveRange().endContainer.nodeType == Node.TEXT_NODE
+		&& getActiveRange().endOffset != 0
+		&& getActiveRange().endOffset != getNodeLength(getActiveRange().endContainer)) {
+			// IE seems to mutate the range incorrectly here, so we need
+			// correction here as well.
+			var newStart = [getActiveRange().startContainer, getActiveRange().startOffset];
+			var newEnd = [getActiveRange().endContainer, getActiveRange().endOffset];
+			getActiveRange().endContainer.splitText(getActiveRange().endOffset);
+			getActiveRange().setStart(newStart[0], newStart[1]);
+			getActiveRange().setEnd(newEnd[0], newEnd[1]);
+		}
+
+		// "Let node list consist of all editable nodes effectively contained
+		// in the active range."
+		//
 		// "For each node in node list, while node's parent is an editable HTML
 		// element in the same editing host as node, and node's parent is not a
 		// prohibited paragraph child and does not have local name "a" or
 		// "audio" or "br" or "img" or "video" or "wbr", split the parent of
 		// the one-node list consisting of node."
-		nodeList.forEach(function(node) {
+		getAllEffectivelyContainedNodes(getActiveRange(), isEditable).forEach(function(node) {
 			while (isEditable(node.parentNode)
 			&& isHtmlElement(node.parentNode)
 			&& !isProhibitedParagraphChild(node.parentNode)
@@ -3010,9 +2987,8 @@
 			}
 		});
 
-		// "For each of the entries in the following list, in the given order:
-		// decompose the active range again; then set the value of the
-		// resulting nodes to null, with command as given."
+		// "For each of the entries in the following list, in the given order,
+		// set the selection's value to null, with command as given."
 		[
 			"subscript",
 			"bold",
@@ -3024,9 +3000,7 @@
 			"strikethrough",
 			"underline",
 		].forEach(function(command) {
-			decomposeRange(getActiveRange()).forEach(function(node) {
-				setNodeValue(node, command, null);
-			});
+			setSelectionValue(command, null);
 		});
 	}
 };
@@ -3036,13 +3010,12 @@
 //@{
 commands.strikethrough = {
 	action: function() {
-		// "Decompose the active range. If the state is then false, set the
-		// value of each returned node to "line-through", otherwise set the
-		// value to null."
-		var nodeList = decomposeRange(getActiveRange());
-		var newValue = commands.strikethrough.state() ? null : "line-through";
-		for (var i = 0; i < nodeList.length; i++) {
-			setNodeValue(nodeList[i], "strikethrough", newValue);
+		// "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()) {
+			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
@@ -3063,24 +3036,15 @@
 //@{
 commands.subscript = {
 	action: function() {
-		// "Decompose the active range, and let node list be the result."
-		var nodeList = decomposeRange(getActiveRange());
-
 		// "Let state be the state."
 		var state = commands.subscript.state();
 
-		// "Set the value of each node in node list to "baseline"."
-		for (var i = 0; i < nodeList.length; i++) {
-			setNodeValue(nodeList[i], "subscript", "baseline");
-		}
-
-		// "If state is false, decompose the active range again and set the
-		// value of each returned node to "sub"."
+		// "Set the selection's value to "baseline"."
+		setSelectionValue("subscript", "baseline");
+
+		// "If state is false, set the selection's value to "sub"."
 		if (!state) {
-			nodeList = decomposeRange(getActiveRange());
-			for (var i = 0; i < nodeList.length; i++) {
-				setNodeValue(nodeList[i], "subscript", "sub");
-			}
+			setSelectionValue("subscript", "sub");
 		}
 	}, indeterm: function() {
 		// "True if either among editable Text nodes that are effectively
@@ -3107,24 +3071,15 @@
 //@{
 commands.superscript = {
 	action: function() {
-		// "Decompose the active range, and let node list be the result."
-		var nodeList = decomposeRange(getActiveRange());
-
 		// "Let state be the state."
 		var state = commands.superscript.state();
 
-		// "Set the value of each node in node list to "baseline"."
-		for (var i = 0; i < nodeList.length; i++) {
-			setNodeValue(nodeList[i], "superscript", "baseline");
-		}
-
-		// "If state is false, decompose the active range again and set the
-		// value of each returned node to "super"."
+		// "Set the selection's value to "baseline"."
+		setSelectionValue("superscript", "baseline");
+
+		// "If state is false, set the selection's value to "super"."
 		if (!state) {
-			nodeList = decomposeRange(getActiveRange());
-			for (var i = 0; i < nodeList.length; i++) {
-				setNodeValue(nodeList[i], "superscript", "super");
-			}
+			setSelectionValue("superscript", "super");
 		}
 	}, indeterm: function() {
 		// "True if either among editable Text nodes that are effectively
@@ -3151,13 +3106,12 @@
 //@{
 commands.underline = {
 	action: function() {
-		// "Decompose the active range. If the state is then false, set the
-		// value of each returned node to "underline", otherwise set the value
-		// to null."
-		var nodeList = decomposeRange(getActiveRange());
-		var newValue = commands.underline.state() ? null : "underline";
-		for (var i = 0; i < nodeList.length; i++) {
-			setNodeValue(nodeList[i], "underline", newValue);
+		// "If the state is false, set the selection's value to "underline",
+		// otherwise set the selection's value to null."
+		if (!commands.underline.state()) {
+			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/preprocess	Fri Jul 08 12:51:44 2011 -0600
+++ b/preprocess	Fri Jul 08 14:15:56 2011 -0600
@@ -25,6 +25,7 @@
     'cdlength': '<code data-anolis-spec=domcore title=dom-CharacterData-length>length</code>',
     'child': '<span data-anolis-spec=domcore title=concept-tree-child>child</span>',
     'children': '<span data-anolis-spec=domcore title=concept-tree-child>children</span>',
+    'collapsed': '<code data-anolis-spec=domrange title=dom-Range-collapsed>collapsed</code>',
     'collection': '<span data-anolis-spec=domcore title=concept-collection>collection</span>',
     'contained': '<span data-anolis-spec=domrange>contained</span>',
     'comment': '<code data-anolis-spec=domcore>Comment</code>',
@@ -136,6 +137,7 @@
     'selcollapse': '<code data-anolis-spec=domrange title=dom-Selection-collapse>collapse(\\1)</code>',
     'selectallchildren': '<code data-anolis-spec=domrange title=dom-Selection-selectAllChildren>selectAllChildren(\\1)</code>',
     'setattribute': '<code data-anolis-spec=domcore title=dom-Element-setAttribute>setAttribute(\\1)</code>',
+    'splittext': '<code data-anolis-spec=domcore title=dom-Text-splitText>splitText(\\1)</code>',
 }
 
 for key in fnreplace:
--- a/source.html	Fri Jul 08 12:51:44 2011 -0600
+++ b/source.html	Fri Jul 08 14:15:56 2011 -0600
@@ -1024,32 +1024,35 @@
 that 1) in <b>[foo]</b>, the text node and the <b> are effectively contained
 but not contained; and 2) in <b>f[o]o</b>, the text node is effectively
 contained but not contained, and the <b> is neither effectively contained nor
-contained.  This is used mostly for the "decompose" algorithm, and also for
-most inline commands' states.
+contained.
 -->
 <ul>
   <li><var>node</var> is [[contained]] in <var>range</var>.
 
   <li><var>node</var> is <var>range</var>'s [[startnode]], it is a [[text]]
-  node, and its [[nodelength]] is different from <var>range</var>'s
-  [[startoffset]].
+  node, its [[nodelength]] is different from <var>range</var>'s
+  [[startoffset]], and <var>range</var> is not [[collapsed]].
+  <!-- So like <b>f[oo]</b> or <b>f[o]o</b> or <b>f[oo</b>}, but not
+  <b>foo[</b>} or <b>f[]oo</b>. -->
 
   <li><var>node</var> is <var>range</var>'s [[endnode]], it is a [[text]] node,
-  and <var>range</var>'s [[endoffset]] is not 0.
+  <var>range</var>'s [[endoffset]] is not 0, and <var>range</var> is not
+  [[collapsed]].
 
   <li><var>node</var> has at least one [[child]]; and all its [[children]] are
   <span>effectively contained</span> in <var>range</var>; and either
   <var>range</var>'s [[startnode]] is not a [[descendant]] of <var>node</var>
-  or is not a [[text]] node or <var>range</var>'s [[startoffset]] is zero; and
-  either <var>range</var>'s [[endnode]] is not a [[descendant]] of
-  <var>node</var> or is not a [[text]] node or <var>range</var>'s [[endoffset]]
-  is its [[endnode]]'s [[length]].
+  or is not a [[text]] node or <var>range</var>'s [[startoffset]] is zero or
+  <var>range</var> is [[collapsed]]; and either <var>range</var>'s [[endnode]]
+  is not a [[descendant]] of <var>node</var> or is not a [[text]] node or
+  <var>range</var>'s [[endoffset]] is its [[endnode]]'s [[length]] or
+  <var>range</var> is [[collapsed]].
   <!--
   Basically, anything whose children are all effectively contained should be
   effectively contained itself, except that in a case like <b>f[o]o</b> we
   don't want <b> to be effectively contained even though the text node is.
-  That's because as soon as we decompose the range, the text node is split and
-  the <b> will no longer be effectively contained.
+  That's because we split the text node before we actually do anything, and the
+  <b> will no longer be effectively contained.
   -->
 </ul>
 
@@ -1340,39 +1343,6 @@
 </ol>
 <!-- @} -->
 
-<h3>Decomposing a range into nodes</h3>
-<!-- @{ -->
-<p>To <dfn>decompose</dfn> a [[range]] <var>range</var>:
-
-<p class=note>For this algorithm to be correct, it is essential that user
-agents follow the [[rangemutationrules]], particularly those for <code
-title>splitText()</code>.
-
-<ol>
-  <li>If <var>range</var>'s [[rangestart]] and [[rangeend]] are the same,
-  return an empty list.
-
-  <li>If <var>range</var>'s [[rangestart]] [[bpnode]] is an
-  <span>editable</span> [[text]] node and its [[rangestart]] [[bpoffset]] is
-  neither 0 nor the [[nodelength]] of its [[rangestart]] [[bpnode]], run <code
-  data-anolis-spec=domcore title=dom-Text-splitText>splitText()</code> on its
-  [[rangestart]] [[bpnode]] with argument equal to its [[rangestart]]
-  [[bpoffset]].
-
-  <li>If <var>range</var>'s [[rangeend]] [[bpnode]] is an <span>editable</span>
-  [[text]] node and its [[rangeend]] [[bpoffset]] is neither 0 nor the
-  [[nodelength]] of its [[rangeend]] [[bpnode]], run <code
-  data-anolis-spec=domcore title=dom-Text-splitText>splitText()</code> on its
-  [[rangeend]] [[bpnode]] with argument equal to its [[rangeend]] [[bpoffset]].
-
-  <!-- We want to make sure the returned list contains as many nodes as
-  possible, such as by treating <tag>[foo]</tag> as {<tag>foo</tag>}. -->
-  <li>Return a list consisting of every [[node]] <span>effectively
-  contained</span> in <var>range</var>, omitting any whose [[parent]] is also
-  <span>effectively contained</span> in <var>range</var>.
-</ol>
-<!-- @} -->
-
 <h3>Clearing an element's value</h3>
 <!-- @{ -->
 <p>To <dfn>clear the value</dfn> of an [[element]] <var>element</var>:
@@ -1869,22 +1839,22 @@
 </ol>
 <!-- @} -->
 
-<h3>Setting the value of a node</h3>
+<h3>Setting the selection's value</h3>
 <!-- @{ -->
-<p>To <dfn>set the value</dfn> of a [[node]] <var>node</var> to <var>new
-value</var>:
+<p>To <dfn>set the selection's value</dfn> to <var>new value</var>:
 
 <div class=note>
-<p>The effect of this algorithm is to ensure that the node and all its
-descendants have the style requested, no matter what, producing the simplest
-markup possible to achieve that effect.  It's inspired by the approach WebKit
-takes.  The only places where the algorithm should fail are when there's an
-!important CSS rule that conflicts with the requested style (which we don't try
-to override because we assume it's !important for a reason), or when it's
-literally impossible to succeed (such as when a text-decoration is propagated
-from an ancestor we can't reach).  Any other failures are bugs.
-
-<p>First, if the node is an element with an inline style rule for this
+<p>The effect of this algorithm is to ensure that all nodes effectively
+contained in the selection have the style requested, no matter what, producing
+the simplest markup possible to achieve that effect.  It's inspired by the
+approach WebKit takes.  The only places where the algorithm should fail are
+when there's an !important CSS rule that conflicts with the requested style
+(which we don't try to override because we assume it's !important for a
+reason), or when it's literally impossible to succeed (such as when a
+text-decoration is propagated from an ancestor we can't reach).  Any other
+failures are bugs.
+
+<p>First, if a node is an element with an inline style rule for this
 property, we unset it ("clearing styles").  This step also removes <span
 title="simple modifiable element">simple modifiable elements</span> entirely, and
 replaces elements like [[b]] or [[font]] with [[span]]s if they aren't simple
@@ -1941,15 +1911,34 @@
 as desired.
 </div>
 
-<p class=XXX>Consider porting this algorithm to operate on runs of consecutive
-siblings instead of individual nodes.  We might be able to make some parts
-smarter, and also might be able to make it more efficient.
-
 <ol>
   <li>Let <var>command</var> be the current <span>command</span>.
 
-  <li>If <var>node</var> is not <span>editable</span>:
+  <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
+  range</span>'s [[startnode]], with argument equal to the <span>active
+  range</span>'s [[startoffset]].  Then set the <span>active range</span>'s
+  [[startnode]] to the result, and its [[startoffset]] to zero.
+  <!-- This last sentence just prettifies the resulting range a bit. -->
+
+  <li>If the <span>active range</span>'s [[endnode]] is an
+  <span>editable</span> [[text]] node, and its [[endoffset]] is neither zero
+  nor its [[endnode]]'s [[length]], call [[splittext|]] on the <span>active
+  range</span>'s [[endnode]], with argument equal to the <span>active
+  range</span>'s [[endoffset]].
+
+  <li>Let <var>element list</var> be all <span>editable</span> [[element]]s
+  <span>effectively contained</span> in the <span>active range</span>.
+
+  <li>For each <var>element</var> in <var>element list</var>, <span>clear the
+  value</span> of <var>element</var>.
+
+  <li>Let <var>node list</var> be all <span>editable</span> [[nodes]]
+  <span>effectively contained</span> in the <span>active range</span>.
   <!--
+  We skip non-editable nodes.
+
   IE9: Allows everything to be modified by execCommand(), regardless of whether
     it's editable.
   Firefox 4.0: Ignores execCommand() if the start and end of the selection are
@@ -1983,37 +1972,13 @@
   are bolded, it will unbold instead of bolding.
   -->
 
-  <ol>
-    <li>Let <var>children</var> be the [[children]] of <var>node</var>.
-
-    <li><span>Set the value</span> of each member of <var>children</var>.
-
-    <li>Abort this algorithm.
-  </ol>
-
-  <li>If <var>node</var> is an [[element]]:
+  <li>For each <var>node</var> in <var>node list</var>:
 
   <ol>
-    <li><span>Clear the value</span> of <var>node</var>, and let <var>new
-    nodes</var> be the result.
-
-    <li>For each <var>new node</var> in <var>new nodes</var>,
-    <span>set the value</span> of <var>new node</var>.
-
-    <li>If <var>node</var>'s [[parent]] is null, abort this algorithm.
+    <li><span>Push down values</span> on <var>node</var>.
+
+    <li><span>Force the value</span> of <var>node</var>.
   </ol>
-
-  <li><span>Push down values</span> on <var>node</var>.
-
-  <li><span>Force the value</span> of <var>node</var>.
-
-  <li>Let <var>children</var> be the [[children]] of <var>node</var>.
-
-  <li><span>Set the value</span> of each member of <var>children</var>.
-
-  <p class=note>Styling a node involves clearing its styles, which can remove
-  it from the tree.  Implementers should be careful to compute the list of
-  children in full before they begin styling.
 </ol>
 <!-- @} -->
 
@@ -2061,8 +2026,7 @@
   <li>If <var>value</var> is still not a valid CSS color, or if it is
   currentColor, raise a [[SYNTAX_ERR]] exception.
 
-  <li><span>Decompose</span> the <span>active range</span>, then <span>set the
-  value</span> of each returned [[node]] to <var>value</var>.
+  <li><span>Set the selection's value</span> to <var>value</var>.
 </ol>
 
 <p><span>Indeterminate</span>: True if among <span>editable</span> [[text]]
@@ -2087,9 +2051,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><span>Action</span>: <span>Decompose</span> the <span>active range</span>.
-If the <span>state</span> is then false, <span>set the value</span> of each
-returned [[node]] to "bold", otherwise <span>set the value</span> to "normal".
+<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>Indeterminate</span>: True if among <span>editable</span> [[text]]
 nodes that are <span>effectively contained</span> in the <span>active
@@ -2155,12 +2119,10 @@
   I think that's more useful.  See issues.
   -->
 
-  <li><span>Decompose</span> the <span>active range</span>, and let <var>node
-  list</var> be the result.
-
   <li>For each <span>editable</span> [[a]] element that has an [[href]]
-  attribute and is an [[ancestor]] of some [[node]] in <var>node list</var>,
-  set that element's [[href]] attribute to <var>value</var>.
+  attribute and is an [[ancestor]] of some [[node]] <span>effectively
+  contained</span> in the <span>active range</span>, set that [[a]] element's
+  [[href]] attribute to <var>value</var>.
   <!-- There are three approaches here.  For instance, if you ask browsers to
   create a link to "http://example.org" on the "b" here:
 
@@ -2185,8 +2147,7 @@
   really intend to only change the link of part of it?
   -->
 
-  <li><span>Set the value</span> of each [[node]] in <var>node list</var> to
-  <var>value</var>.
+  <li><span>Set the selection's value</span> to <var>value</var>.
 </ol>
 
 <!--
@@ -2202,8 +2163,8 @@
 
 <h3><dfn>The <code title>fontName</code> command</dfn></h3>
 <!-- @{ -->
-<p><span>Action</span>: <span>Decompose</span> the <span>active range</span>,
-then <span>set the value</span> of each returned [[node]] to <var>value</var>.
+<p><span>Action</span>: <span>Set the selection's value</span> to
+<var>value</var>.
 <!-- UAs differ a bit in the details here:
 
 IE 9 RC: Empty string sets <font face="">
@@ -2356,8 +2317,7 @@
   allow numeric values.  There's no harm in allowing "x-small" and absolute
   sizes, I don't think.
 
-  <li><span>Decompose</span> the <span>active range</span>, then <span>set the
-  value</span> of each returned [[node]] to <var>value</var>.
+  <li><span>Set the selection's value</span> to <var>value</var>.
 </ol>
 
 <p><span>Indeterminate</span>: True if among <span>editable</span> [[text]]
@@ -2493,8 +2453,7 @@
   <!-- currentColor is bad for the same reason as relative font sizes.  It will
   confuse the algorithm, and doesn't seem very useful anyway. -->
 
-  <li><span>Decompose</span> the <span>active range</span>, then <span>set the
-  value</span> of each returned [[node]] to <var>value</var>.
+  <li><span>Set the selection's value</span> to <var>value</var>.
 </ol>
 
 <!-- Opera 11 seems to return true for the state if there's some color style
@@ -2555,8 +2514,7 @@
   you could conceive of it being useful, but it will still confuse the
   algorithm, so ban it for now anyway. -->
 
-  <li><span>Decompose</span> the <span>active range</span>, then <span>set the
-  value</span> of each returned [[node]] to <var>value</var>.
+  <li><span>Set the selection's value</span> to <var>value</var>.
 </ol>
 
 <p><span>Indeterminate</span>: True if among <span>editable</span> [[text]]
@@ -2586,10 +2544,9 @@
 
 <h3><dfn>The <code title>italic</code> command</dfn></h3>
 <!-- @{ -->
-<p><span>Action</span>: <span>Decompose</span> the <span>active range</span>.
-If the <span>state</span> is then false, <span>set the value</span> of each
-returned [[node]] to "italic", otherwise <span>set the value</span> to
-"normal".
+<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>Indeterminate</span>: True if among <span>editable</span> [[text]]
 nodes that are <span>effectively contained</span> in the <span>active
@@ -2677,8 +2634,22 @@
     <li>Remove <var>element</var> from its [[parent]].
   </ol>
 
-  <li><span>Decompose</span> the <span>active range</span>, and let <var>node
-  list</var> be the result.
+  <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
+  range</span>'s [[startnode]], with argument equal to the <span>active
+  range</span>'s [[startoffset]].  Then set the <span>active range</span>'s
+  [[startnode]] to the result, and its [[startoffset]] to zero.
+  <!-- This last sentence just prettifies the resulting range a bit. -->
+
+  <li>If the <span>active range</span>'s [[endnode]] is an
+  <span>editable</span> [[text]] node, and its [[endoffset]] is neither zero
+  nor its [[endnode]]'s [[length]], call [[splittext|]] on the <span>active
+  range</span>'s [[endnode]], with argument equal to the <span>active
+  range</span>'s [[endoffset]].
+
+  <li>Let <var>node list</var> consist of all <span>editable</span> [[nodes]]
+  <span>effectively contained</span> in the <span>active range</span>.
 
   <li>For each <var>node</var> in <var>node list</var>, while <var>node</var>'s
   [[parent]] is an <span>editable</span> <span>HTML element</span> <span>in the
@@ -2688,10 +2659,9 @@
   <span>split the parent</span> of the one-[[node]] list consisting of
   <var>node</var>.
 
-  <li>For each of the entries in the following list, in the given order:
-  <span>decompose</span> the <span>active range</span> again; then <span>set
-  the value</span> of the resulting [[nodes]] to null, with <var>command</var>
-  as given.
+  <li>For each of the entries in the following list, in the given order,
+  <span>set the selection's value</span> to null, with <var>command</var> as
+  given.
   <!-- For cases like <p style=font-weight:bold>foo[bar]baz</p>. -->
 
   <ol>
@@ -2712,10 +2682,9 @@
 
 <h3><dfn>The <code title>strikethrough</code> command</dfn></h3>
 <!-- @{ -->
-<p><span>Action</span>: <span>Decompose</span> the <span>active range</span>.
-If the <span>state</span> is then false, <span>set the value</span> of each
-returned [[node]] to "line-through", otherwise <span>set the value</span> to
-null.
+<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 class=XXX>Has all the same problems as <span>the <code
 title>underline</code> command</span>.
@@ -2740,17 +2709,12 @@
 <p><span>Action</span>:
 
 <ol>
-  <li><span>Decompose</span> the <span>active range</span>, and let <var>node
-  list</var> be the result.
-
   <li>Let <var>state</var> be the <span>state</span>.
 
-  <li><span>Set the value</span> of each [[node]] in <var>node list</var> to
-  "baseline".
-
-  <li>If <var>state</var> is false, <span>decompose</span> the <span>active
-  range</span> again and <span>set the value</span> of each returned [[node]]
-  to "sub".
+  <li><span>Set the selection's value</span> to "baseline".
+
+  <li>If <var>state</var> is false, <span>set the selection's value</span> to
+  "sub".
 </ol>
 
 <p><span>Indeterminate</span>: True if either among <span>editable</span>
@@ -2785,17 +2749,12 @@
 <p><span>Action</span>:
 
 <ol>
-  <li><span>Decompose</span> the <span>active range</span>, and let <var>node
-  list</var> be the result.
-
   <li>Let <var>state</var> be the <span>state</span>.
 
-  <li><span>Set the value</span> of each [[node]] in <var>node list</var> to
-  "baseline".
-
-  <li>If <var>state</var> is false, <span>decompose</span> the <span>active
-  range</span> again and <span>set the value</span> of each returned [[node]]
-  to "super".
+  <li><span>Set the selection's value</span> to "baseline".
+
+  <li>If <var>state</var> is false, <span>set the selection's value</span> to
+  "super".
 </ol>
 
 <p><span>Indeterminate</span>: True if either among <span>editable</span>
@@ -2816,9 +2775,9 @@
 
 <h3><dfn>The <code title>underline</code> command</dfn></h3>
 <!-- @{ -->
-<p><span>Action</span>: <span>Decompose</span> the <span>active range</span>.
-If the <span>state</span> is then false, <span>set the value</span> of each
-returned [[node]] to "underline", otherwise <span>set the value</span> to null.
+<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.
 
 <div class=XXX>
 <p>There are a lot of problems with underline color and thickness, because