Refactor definitions for the future
authorAryeh Gregor <AryehGregor+gitcommit@gmail.com>
Wed, 09 Nov 2011 11:55:15 -0700
changeset 671 d062944c5b59
parent 670 980710767f0e
child 672 55aba401ca70
Refactor definitions for the future

Regenerated tests, no changes. The changes will be relevant to a commit
in the near future that uses these definitions.
editing.html
implementation.js
source.html
--- a/editing.html	Wed Nov 09 11:24:27 2011 -0700
+++ b/editing.html	Wed Nov 09 11:55:15 2011 -0700
@@ -4570,10 +4570,6 @@
   <li>Return <var title="">node</var>.
 </ol>
 
-<p>Two <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node title=concept-node>nodes</a> are <dfn id=in-the-same-block>in the same block</dfn> if the <a href=#block-node-of>block node
-of</a> the first is non-null and the same as the <a href=#block-node-of>block node of</a>
-the second.
-
 
 <h3 id=assorted-block-formatting-command-algorithms>Assorted block formatting command algorithms</h3>
 
@@ -4878,19 +4874,24 @@
   unexpected results for nodes like <code title="">&lt;br&gt;</code>.
 
   <li>If <var title="">offset</var> is <var title="">node</var>'s <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node-length title=concept-node-length>length</a>, and
-  <var title="">node</var>'s <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-parent title=concept-tree-parent>parent</a> is not null, return (<var title="">node</var>'s
-  <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-parent title=concept-tree-parent>parent</a>, 1 + <var title="">node</var>'s <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-index title=concept-tree-index>index</a>).
+  <var title="">node</var>'s <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-parent title=concept-tree-parent>parent</a> is not null, and <var title="">node</var> is an
+  <a href=#inline-node>inline node</a>, return (<var title="">node</var>'s <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-parent title=concept-tree-parent>parent</a>, 1 +
+  <var title="">node</var>'s <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-index title=concept-tree-index>index</a>).
 
   <li class=note>For instance, <code title="">&lt;span&gt;foo[]&lt;/span&gt;</code> is equivalent to
-  <code title="">&lt;span&gt;foo{}&lt;/span&gt;</code>, which is equivalent to <code title="">&lt;span&gt;foo&lt;/span&gt;{}</code>.
+  <code title="">&lt;span&gt;foo{}&lt;/span&gt;</code>, which is equivalent to <code title="">&lt;span&gt;foo&lt;/span&gt;{}</code>.  However, <code title="">&lt;p&gt;foo{}&lt;/p&gt;</code> is <em>not</em> equivalent to
+  <code title="">&lt;p&gt;foo&lt;/p&gt;{}</code> &ndash; the cursor might look like it's in a visibly
+  different position.
 
   <li>If <var title="">node</var> has a <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>child</a> with <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-index title=concept-tree-index>index</a> <var title="">offset</var>,
-  and that <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>child</a>'s <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node-length title=concept-node-length>length</a> is not zero, return (that <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>child</a>, 0).
+  and that <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>child</a>'s <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node-length title=concept-node-length>length</a> is not zero, and that <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>child</a> is an
+  <a href=#inline-node>inline node</a>, return (that <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>child</a>, 0).
 
   <li class=note>For instance, <code title="">{}&lt;span&gt;foo&lt;/span&gt;</code> is equivalent to
   <code title="">&lt;span&gt;{}foo&lt;/span&gt;</code>, which is equivalent to
   <code title="">&lt;span&gt;[]foo&lt;/span&gt;</code>.  As noted before, though, we don't descend into
-  empty nodes.
+  empty nodes.  And again, <code title="">{}&lt;p&gt;foo&lt;/p&gt;</code> is different from
+  <code title="">&lt;p&gt;{}foo&lt;/p&gt;</code>.
 
   <li>Return null.
 </ol>
@@ -4903,15 +4904,39 @@
   <li>If <var title="">node</var>'s <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node-length title=concept-node-length>length</a> is zero, return null.
 
   <li>If <var title="">offset</var> is 0, and <var title="">node</var>'s <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-parent title=concept-tree-parent>parent</a> is not null,
-  return (<var title="">node</var>'s <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-parent title=concept-tree-parent>parent</a>, <var title="">node</var>'s <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-index title=concept-tree-index>index</a>).
+  and <var title="">node</var> is an <a href=#inline-node>inline node</a>, return (<var title="">node</var>'s
+  <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-parent title=concept-tree-parent>parent</a>, <var title="">node</var>'s <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-index title=concept-tree-index>index</a>).
 
   <li>If <var title="">node</var> has a <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>child</a> with <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-index title=concept-tree-index>index</a> <var title="">offset</var>
-  &minus; 1, and that <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>child</a>'s <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node-length title=concept-node-length>length</a> is not zero, return (that
-  <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>child</a>, that <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>child</a>'s <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node-length title=concept-node-length>length</a>).
+  &minus; 1, and that <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>child</a>'s <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node-length title=concept-node-length>length</a> is not zero, and that <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>child</a> is
+  an <a href=#inline-node>inline node</a>, return (that <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>child</a>, that <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>child</a>'s
+  <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node-length title=concept-node-length>length</a>).
 
   <li>Return null.
 </ol>
 
+<p>The <dfn id=first-equivalent-point>first equivalent point</dfn> of a <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-range-bp title=concept-range-bp>boundary point</a>
+(<var title="">node</var>, <var title="">offset</var>) is returned by the following algorithm:
+
+<ol>
+  <li>While (<var title="">node</var>, <var title="">offset</var>)'s <a href=#previous-equivalent-point>previous equivalent
+  point</a> is not null, set (<var title="">node</var>, <var title="">offset</var>) to its
+  <a href=#previous-equivalent-point>previous equivalent point</a>.
+
+  <li>Return (<var title="">node</var>, <var title="">offset</var>).
+</ol>
+
+<p>The <dfn id=last-equivalent-point>last equivalent point</dfn> of a <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-range-bp title=concept-range-bp>boundary point</a>
+(<var title="">node</var>, <var title="">offset</var>) is returned by the following algorithm:
+
+<ol>
+  <li>While (<var title="">node</var>, <var title="">offset</var>)'s <a href=#next-equivalent-point>next equivalent
+  point</a> is not null, set (<var title="">node</var>, <var title="">offset</var>) to its
+  <a href=#next-equivalent-point>next equivalent point</a>.
+
+  <li>Return (<var title="">node</var>, <var title="">offset</var>).
+</ol>
+
 <!-- Turned out not to be necessary here, but I've left it in case it turns out
 to be handy elsewhere. -->
 <!--
@@ -5317,25 +5342,11 @@
   <li><a href=#canonicalize-whitespace>Canonicalize whitespace</a> at the <a href=#active-range>active range</a>'s
   <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-range-end title=concept-range-end>end</a>.
 
-  <li>Let <var title="">start node</var>, <var title="">start offset</var>, <var title="">end node</var>,
-  and <var title="">end offset</var> be the <a href=#active-range>active range</a>'s <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-range-start title=concept-range-start>start</a>
-  and <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-range-end title=concept-range-end>end</a> <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node title=concept-node>nodes</a> and <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-range-bp-offset title=concept-range-bp-offset>offsets</a>.
-
-  <li>While the <a href=#next-equivalent-point>next equivalent point</a> for (<var title="">start node</var>,
-  <var title="">start offset</var>) is not null, and that <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-range-bp title=concept-range-bp>boundary point</a>'s <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node title=concept-node>node</a>
-  is <a href=#in-the-same-editing-host>in the same editing host</a> and <a href=#in-the-same-block>in the same block</a>
-  as <var title="">start node</var>, set (<var title="">start node</var>, <var title="">start
-  offset</var>) to its <a href=#next-equivalent-point>next equivalent point</a>.
-
-  <p class=note>We don't want to leave the current block because otherwise,
-  for instance, a selection of <code title="">&lt;p&gt;foo[&lt;/p&gt;&lt;p&gt;]bar&lt;/p&gt;</code> would be treated
-  as empty and nothing would be deleted, when we want it to merge the blocks.
-
-  <li>While the <a href=#previous-equivalent-point>previous equivalent point</a> for (<var title="">end
-  node</var>, <var title="">end offset</var>) is not null, and that <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-range-bp title=concept-range-bp>boundary point</a>'s
-  <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node title=concept-node>node</a> is <a href=#in-the-same-editing-host>in the same editing host</a> and <a href=#in-the-same-block>in the same
-  block</a> as <var title="">end node</var>, set (<var title="">end node</var>, <var title="">end
-  offset</var>) to its <a href=#previous-equivalent-point>previous equivalent point</a>.
+  <li>Let (<var title="">start node</var>, <var title="">start offset</var>) be the <a href=#last-equivalent-point>last
+  equivalent point</a> for the <a href=#active-range>active range</a>'s <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-range-start title=concept-range-start>start</a>.
+
+  <li>Let (<var title="">end node</var>, <var title="">end offset</var>) be the <a href=#first-equivalent-point>first
+  equivalent point</a> for the <a href=#active-range>active range</a>'s <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-range-end title=concept-range-end>end</a>.
 
   <li>If (<var title="">end node</var>, <var title="">end offset</var>) is not <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-range-bp-after title=concept-range-bp-after>after</a>
   (<var title="">start node</var>, <var title="">start offset</var>):
--- a/implementation.js	Wed Nov 09 11:24:27 2011 -0700
+++ b/implementation.js	Wed Nov 09 11:55:15 2011 -0700
@@ -3766,13 +3766,6 @@
 	return node;
 }
 
-// "Two nodes are in the same block if the block node of the first is non-null
-// and the same as the block node of the second."
-function inSameBlock(node1, node2) {
-	return getBlockNodeOf(node1)
-		&& getBlockNodeOf(node1) === getBlockNodeOf(node2);
-}
-
 //@}
 ///// Assorted block formatting command algorithms /////
 //@{
@@ -4021,17 +4014,20 @@
 		return null;
 	}
 
-	// "If offset is node's length, and node's parent is not null, return
-	// (node's parent, 1 + node's index)."
-	if (offset == getNodeLength(node) && node.parentNode) {
+	// "If offset is node's length, and node's parent is not null, and node is
+	// an inline node, return (node's parent, 1 + node's index)."
+	if (offset == getNodeLength(node)
+	&& node.parentNode
+	&& isInlineNode(node)) {
 		return [node.parentNode, 1 + getNodeIndex(node)];
 	}
 
 	// "If node has a child with index offset, and that child's length is not
-	// zero, return (that child, 0)."
+	// zero, and that child is an inline node, return (that child, 0)."
 	if (0 <= offset
 	&& offset < node.childNodes.length
-	&& getNodeLength(node.childNodes[offset]) != 0) {
+	&& getNodeLength(node.childNodes[offset]) != 0
+	&& isInlineNode(node.childNodes[offset])) {
 		return [node.childNodes[offset], 0];
 	}
 
@@ -4045,17 +4041,21 @@
 		return null;
 	}
 
-	// "If offset is 0, and node's parent is not null, return (node's parent,
-	// node's index)."
-	if (offset == 0 && node.parentNode) {
+	// "If offset is 0, and node's parent is not null, and node is an inline
+	// node, return (node's parent, node's index)."
+	if (offset == 0
+	&& node.parentNode
+	&& isInlineNode(node)) {
 		return [node.parentNode, getNodeIndex(node)];
 	}
 
 	// "If node has a child with index offset − 1, and that child's length is
-	// not zero, return (that child, that child's length)."
+	// not zero, and that child is an inline node, return (that child, that
+	// child's length)."
 	if (0 <= offset - 1
 	&& offset - 1 < node.childNodes.length
-	&& getNodeLength(node.childNodes[offset - 1]) != 0) {
+	&& getNodeLength(node.childNodes[offset - 1]) != 0
+	&& isInlineNode(node.childNodes[offset - 1])) {
 		return [node.childNodes[offset - 1], getNodeLength(node.childNodes[offset - 1])];
 	}
 
@@ -4063,6 +4063,32 @@
 	return null;
 }
 
+function getFirstEquivalentPoint(node, offset) {
+	// "While (node, offset)'s previous equivalent point is not null, set
+	// (node, offset) to its previous equivalent point."
+	var prev;
+	while (prev = getPreviousEquivalentPoint(node, offset)) {
+		node = prev[0];
+		offset = prev[1];
+	}
+
+	// "Return (node, offset)."
+	return [node, offset];
+}
+
+function getLastEquivalentPoint(node, offset) {
+	// "While (node, offset)'s next equivalent point is not null, set (node,
+	// offset) to its next equivalent point."
+	var next;
+	while (next = getNextEquivalentPoint(node, offset)) {
+		node = next[0];
+		offset = next[1];
+	}
+
+	// "Return (node, offset)."
+	return [node, offset];
+}
+
 //@}
 ///// Block-extending a range /////
 //@{
@@ -4472,36 +4498,17 @@
 	// "Canonicalize whitespace at the active range's end."
 	canonicalizeWhitespace(getActiveRange().endContainer, getActiveRange().endOffset);
 
-	// "Let start node, start offset, end node, and end offset be the active
-	// range's start and end nodes and offsets."
-	var startNode = getActiveRange().startContainer;
-	var startOffset = getActiveRange().startOffset;
-	var endNode = getActiveRange().endContainer;
-	var endOffset = getActiveRange().endOffset;
-
-	// "While the next equivalent point for (start node, start offset) is not
-	// null, and that boundary point's node is in the same editing host and in
-	// the same block as start node, set (start node, start offset) to its next
-	// equivalent point."
-	while (getNextEquivalentPoint(startNode, startOffset)
-	&& inSameEditingHost(getNextEquivalentPoint(startNode, startOffset)[0], startNode)
-	&& inSameBlock(getNextEquivalentPoint(startNode, startOffset)[0], startNode)) {
-		var next = getNextEquivalentPoint(startNode, startOffset);
-		startNode = next[0];
-		startOffset = next[1];
-	}
-
-	// "While the previous equivalent point for (end node, end offset) is not
-	// null, and that boundary point's node is in the same editing host and in
-	// the same block as end node, set (end node, end offset) to its previous
-	// equivalent point."
-	while (getPreviousEquivalentPoint(endNode, endOffset)
-	&& inSameEditingHost(getPreviousEquivalentPoint(endNode, endOffset)[0], endNode)
-	&& inSameBlock(getPreviousEquivalentPoint(endNode, endOffset)[0], endNode)) {
-		var prev = getPreviousEquivalentPoint(endNode, endOffset);
-		endNode = prev[0];
-		endOffset = prev[1];
-	}
+	// "Let (start node, start offset) be the last equivalent point for the
+	// active range's start."
+	var start = getLastEquivalentPoint(getActiveRange().startContainer, getActiveRange().startOffset);
+	var startNode = start[0];
+	var startOffset = start[1];
+
+	// "Let (end node, end offset) be the first equivalent point for the active
+	// range's end."
+	var end = getFirstEquivalentPoint(getActiveRange().endContainer, getActiveRange().endOffset);
+	var endNode = end[0];
+	var endOffset = end[1];
 
 	// "If (end node, end offset) is not after (start node, start offset):"
 	if (getPosition(endNode, endOffset, startNode, startOffset) !== "after") {
--- a/source.html	Wed Nov 09 11:24:27 2011 -0700
+++ b/source.html	Wed Nov 09 11:55:15 2011 -0700
@@ -4611,10 +4611,6 @@
   <li>Return <var>node</var>.
 </ol>
 
-<p>Two [[nodes]] are <dfn>in the same block</dfn> if the <span>block node
-of</span> the first is non-null and the same as the <span>block node of</span>
-the second.
-
 <!-- @} -->
 <h3>Assorted block formatting command algorithms</h3>
 <!-- @{ -->
@@ -4921,20 +4917,25 @@
   unexpected results for nodes like {{code|<br>}}.
 
   <li>If <var>offset</var> is <var>node</var>'s [[length]], and
-  <var>node</var>'s [[parent]] is not null, return (<var>node</var>'s
-  [[parent]], 1 + <var>node</var>'s [[index]]).
+  <var>node</var>'s [[parent]] is not null, and <var>node</var> is an
+  <span>inline node</span>, return (<var>node</var>'s [[parent]], 1 +
+  <var>node</var>'s [[index]]).
 
   <li class=note>For instance, {{code|<span>foo[]</span>}} is equivalent to
   {{code|<span>foo{}</span>}}, which is equivalent to {{code|<span>foo</span>{}
-  }}.
+  }}.  However, {{code|<p>foo{}</p>}} is <em>not</em> equivalent to
+  {{code|<p>foo</p>{} }} &ndash; the cursor might look like it's in a visibly
+  different position.
 
   <li>If <var>node</var> has a [[child]] with [[index]] <var>offset</var>,
-  and that [[child]]'s [[length]] is not zero, return (that [[child]], 0).
+  and that [[child]]'s [[length]] is not zero, and that [[child]] is an
+  <span>inline node</span>, return (that [[child]], 0).
 
   <li class=note>For instance, {{code|{}<span>foo</span>}} is equivalent to
   {{code|<span>{}foo</span>}}, which is equivalent to
   {{code|<span>[]foo</span>}}.  As noted before, though, we don't descend into
-  empty nodes.
+  empty nodes.  And again, {{code|{}<p>foo</p>}} is different from
+  {{code|<p>{}foo</p>}}.
 
   <li>Return null.
 </ol>
@@ -4947,15 +4948,39 @@
   <li>If <var>node</var>'s [[length]] is zero, return null.
 
   <li>If <var>offset</var> is 0, and <var>node</var>'s [[parent]] is not null,
-  return (<var>node</var>'s [[parent]], <var>node</var>'s [[index]]).
+  and <var>node</var> is an <span>inline node</span>, return (<var>node</var>'s
+  [[parent]], <var>node</var>'s [[index]]).
 
   <li>If <var>node</var> has a [[child]] with [[index]] <var>offset</var>
-  &minus; 1, and that [[child]]'s [[length]] is not zero, return (that
-  [[child]], that [[child]]'s [[length]]).
+  &minus; 1, and that [[child]]'s [[length]] is not zero, and that [[child]] is
+  an <span>inline node</span>, return (that [[child]], that [[child]]'s
+  [[length]]).
 
   <li>Return null.
 </ol>
 
+<p>The <dfn>first equivalent point</dfn> of a [[boundarypoint]]
+(<var>node</var>, <var>offset</var>) is returned by the following algorithm:
+
+<ol>
+  <li>While (<var>node</var>, <var>offset</var>)'s <span>previous equivalent
+  point</span> is not null, set (<var>node</var>, <var>offset</var>) to its
+  <span>previous equivalent point</span>.
+
+  <li>Return (<var>node</var>, <var>offset</var>).
+</ol>
+
+<p>The <dfn>last equivalent point</dfn> of a [[boundarypoint]]
+(<var>node</var>, <var>offset</var>) is returned by the following algorithm:
+
+<ol>
+  <li>While (<var>node</var>, <var>offset</var>)'s <span>next equivalent
+  point</span> is not null, set (<var>node</var>, <var>offset</var>) to its
+  <span>next equivalent point</span>.
+
+  <li>Return (<var>node</var>, <var>offset</var>).
+</ol>
+
 <!-- Turned out not to be necessary here, but I've left it in case it turns out
 to be handy elsewhere. -->
 <!--
@@ -5369,25 +5394,11 @@
   <li><span>Canonicalize whitespace</span> at the <span>active range</span>'s
   [[rangeend]].
 
-  <li>Let <var>start node</var>, <var>start offset</var>, <var>end node</var>,
-  and <var>end offset</var> be the <span>active range</span>'s [[rangestart]]
-  and [[rangeend]] [[nodes]] and [[bpoffsets]].
-
-  <li>While the <span>next equivalent point</span> for (<var>start node</var>,
-  <var>start offset</var>) is not null, and that [[boundarypoint]]'s [[node]]
-  is <span>in the same editing host</span> and <span>in the same block</span>
-  as <var>start node</var>, set (<var>start node</var>, <var>start
-  offset</var>) to its <span>next equivalent point</span>.
-
-  <p class=note>We don't want to leave the current block because otherwise,
-  for instance, a selection of {{code|<p>foo[</p><p>]bar</p>}} would be treated
-  as empty and nothing would be deleted, when we want it to merge the blocks.
-
-  <li>While the <span>previous equivalent point</span> for (<var>end
-  node</var>, <var>end offset</var>) is not null, and that [[boundarypoint]]'s
-  [[node]] is <span>in the same editing host</span> and <span>in the same
-  block</span> as <var>end node</var>, set (<var>end node</var>, <var>end
-  offset</var>) to its <span>previous equivalent point</span>.
+  <li>Let (<var>start node</var>, <var>start offset</var>) be the <span>last
+  equivalent point</span> for the <span>active range</span>'s [[rangestart]].
+
+  <li>Let (<var>end node</var>, <var>end offset</var>) be the <span>first
+  equivalent point</span> for the <span>active range</span>'s [[rangeend]].
 
   <li>If (<var>end node</var>, <var>end offset</var>) is not [[bpafter]]
   (<var>start node</var>, <var>start offset</var>):