--- a/editcommands.html	Tue Jun 21 15:28:14 2011 -0600
+++ b/editcommands.html	Tue Jun 21 16:18:46 2011 -0600
@@ -446,6 +446,19 @@
 Or its ancestor has a fixed height?  Would it be better to use some DOM-based
 definition?
 
+<p>An <dfn id=extraneous-line-break>extraneous line break</dfn> is a <code class=external data-anolis-spec=html title="the br element"><a href=http://www.whatwg.org/html/#the-br-element>br</a></code> that has no visual effect,
+in that removing it from the DOM would not change layout, except that a <code class=external data-anolis-spec=html title="the br element"><a href=http://www.whatwg.org/html/#the-br-element>br</a></code>
+that is the sole child of an <code class=external data-anolis-spec=html title="the li element"><a href=http://www.whatwg.org/html/#the-li-element>li</a></code> is not extraneous.
+
+<p class=XXX>Also possibly a bad definition.  Again, I test by just removing it
+and seeing what happens.  (Actually, setting display: none, so that it doesn't
+mess up ranges.)
+
+<p class=XXX>The thing about li is a not very nice hack.  The issue is that an
+li won't collapse even if it has no children at all, but that's not true in all
+browsers (at least not in Opera 11.11), and also it breaks assumptions
+elsewhere.  E.g., if it gets turned into a p.
+
 <p>Each <code class=external data-anolis-spec=html><a href=http://www.whatwg.org/html/#htmldocument>HTMLDocument</a></code> has a boolean <dfn id=css-styling-flag>CSS styling flag</dfn> associated
 with it, which must initially be false.  (<a href=#the-stylewithcss-command>The <code title="">styleWithCSS</code> command</a> can be used to modify or query it, by
 means of the <code><a href=#execcommand()>execCommand()</a></code> and <code><a href=#querycommandstate()>queryCommandState()</a></code>
@@ -531,26 +544,38 @@
 <var title="">node</var>:
 
 <ol>
-  <li>If <var title="">node</var> is not 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>, or it is an <a href=#inline-node>inline
-  node</a>, do nothing and abort these steps.
-
-  <li>If the <code class=external data-anolis-spec=domcore title=dom-Node-previousSibling><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-node-previoussibling>previousSibling</a></code> of <var title="">node</var> is a <code class=external data-anolis-spec=html title="the br element"><a href=http://www.whatwg.org/html/#the-br-element>br</a></code>, and the
-  <code class=external data-anolis-spec=domcore title=dom-Node-previousSibling><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-node-previoussibling>previousSibling</a></code> of the <code class=external data-anolis-spec=domcore title=dom-Node-previousSibling><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-node-previoussibling>previousSibling</a></code> of <var title="">node</var> is an
-  <a href=#inline-node>inline node</a> that is not a <code class=external data-anolis-spec=html title="the br element"><a href=http://www.whatwg.org/html/#the-br-element>br</a></code>, remove the <code class=external data-anolis-spec=domcore title=dom-Node-previousSibling><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-node-previoussibling>previousSibling</a></code>
-  of <var title="">node</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>.
+  <li>Let <var title="">ref</var> be the <code class=external data-anolis-spec=domcore title=dom-Node-previousSibling><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-node-previoussibling>previousSibling</a></code> of <var title="">node</var>.
+
+  <li>If <var title="">ref</var> is null, abort these steps.
+
+  <li>While <var title="">ref</var> has <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>, set <var title="">ref</var> to its
+  <code class=external data-anolis-spec=domcore title=dom-Node-lastChild><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-node-lastchild>lastChild</a></code>.
+
+  <li>While <var title="">ref</var> is an <a href=#invisible-node>invisible node</a> but not an
+  <a href=#extraneous-line-break>extraneous line break</a>, and <var title="">ref</var> does not equal
+  <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>, set <var title="">ref</var> to the <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> before it in
+  <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#tree-order>tree order</a>.
+
+  <li>If <var title="">ref</var> is an <a href=#editable>editable</a> <a href=#extraneous-line-break>extraneous line
+  break</a>, remove it 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>
 
 <p>To <dfn id=remove-extraneous-line-breaks-at-the-end-of>remove extraneous line breaks at the end of</dfn> 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>:
 
 <ol>
-  <li>If <var title="">node</var> is not 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>, or it is an <a href=#inline-node>inline
-  node</a>, do nothing and abort these steps.
-
-  <li>If <var title="">node</var> has at least two <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>, and its last <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>
-  is a <code class=external data-anolis-spec=html title="the br element"><a href=http://www.whatwg.org/html/#the-br-element>br</a></code>, and its second-to-last <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> is an <a href=#inline-node>inline node</a>
-  that is not a <code class=external data-anolis-spec=html title="the br element"><a href=http://www.whatwg.org/html/#the-br-element>br</a></code>, remove the last <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> of <var title="">node</var> from
-  <var title="">node</var>.
+  <li>Let <var title="">ref</var> be <var title="">node</var>.
+
+  <li>While <var title="">ref</var> has <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>, set <var title="">ref</var> to its
+  <code class=external data-anolis-spec=domcore title=dom-Node-lastChild><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-node-lastchild>lastChild</a></code>.
+
+  <li>While <var title="">ref</var> is an <a href=#invisible-node>invisible node</a> but not an
+  <a href=#extraneous-line-break>extraneous line break</a>, and <var title="">ref</var> does not equal
+  <var title="">node</var>, set <var title="">ref</var> to the <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> before it in
+  <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#tree-order>tree order</a>.
+
+  <li>If <var title="">ref</var> is an <a href=#editable>editable</a> <a href=#extraneous-line-break>extraneous line
+  break</a>, remove it 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>
 
 <p>To <dfn id=remove-extraneous-line-breaks-from>remove extraneous line breaks from</dfn> 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>, first
@@ -675,8 +700,10 @@
   <var title="">original parent</var>.
 
   <li>If <var title="">node list</var>'s last member's <code class=external data-anolis-spec=domcore title=dom-Node-nextSibling><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-node-nextsibling>nextSibling</a></code> is null,
-  <a href=#remove-extraneous-line-breaks-at-the-end-of>remove extraneous line breaks at the end of</a> <var title="">node
-  list</var>'s last member'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>.
+  but 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> is not null, <a href=#remove-extraneous-line-breaks-at-the-end-of>remove extraneous line breaks at the
+  end of</a> <var title="">node list</var>'s last member'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>.
+  <!-- The parent might be null if it's a br that we removed in the last step,
+  in which case this step isn't necessary. -->
 </ol>
 
 <p>To remove 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> while <dfn id=preserving-its-descendants>preserving its
@@ -2562,9 +2589,9 @@
 <!-- Possibly to be made configurable later. -->
 
 <p>A <dfn id=visible-node>visible node</dfn> is 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> that either is a <a href=#prohibited-paragraph-child>prohibited
-paragraph child</a>, or 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 whose <code class=external data-anolis-spec=domcore title=dom-CharacterData-data><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-characterdata-data>data</a></code> is not empty, or a
-<code class=external data-anolis-spec=html title="the br element"><a href=http://www.whatwg.org/html/#the-br-element>br</a></code> or <code class=external data-anolis-spec=html title="the img element"><a href=http://www.whatwg.org/html/#the-img-element>img</a></code>, or any <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node title=concept-node>node</a> with 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> that is a
-<a href=#visible-node>visible node</a>.
+paragraph child</a>, or 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 whose <code class=external data-anolis-spec=domcore title=dom-CharacterData-data><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-characterdata-data>data</a></code> is not empty, or
+an <code class=external data-anolis-spec=html title="the img element"><a href=http://www.whatwg.org/html/#the-img-element>img</a></code>, or a <code class=external data-anolis-spec=html title="the br element"><a href=http://www.whatwg.org/html/#the-br-element>br</a></code> that is not an <a href=#extraneous-line-break>extraneous line break</a>, or
+any <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node title=concept-node>node</a> with 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> that is a <a href=#visible-node>visible node</a>.
 
 <p>An <dfn id=invisible-node>invisible node</dfn> is 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> that is not a <a href=#visible-node>visible
 node</a>.
@@ -4903,27 +4930,6 @@
     <var title="">offset</var> and that <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> is an <a href=#editable>editable</a>
     <a href=#invisible-node>invisible node</a>, remove that <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> from <var title="">node</var>.
 
-    <!-- We need these extra two steps in forwardDelete, relative to delete, to
-    skip over line breaks at the end of blocks. -->
-    <li>Otherwise, if <var title="">offset</var> is one less than <var title="">node</var>'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>, and <var title="">node</var> is a <a href=#prohibited-paragraph-child>prohibited paragraph
-    child</a> whose last <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> is a <code class=external data-anolis-spec=html title="the br element"><a href=http://www.whatwg.org/html/#the-br-element>br</a></code>, add one to
-    <var title="">offset</var>.
-
-    <li>Otherwise, if <var title="">node</var> has a <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> with <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-indexof title=concept-indexof>index</a>
-    <var title="">offset</var> + 1, and 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>child</a> of <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-indexof title=concept-indexof>index</a> <var title="">offset</var> is
-    a <code class=external data-anolis-spec=html title="the br element"><a href=http://www.whatwg.org/html/#the-br-element>br</a></code>, and 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>child</a> of <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-indexof title=concept-indexof>index</a> <var title="">offset</var> + 1 is a
-    <a href=#prohibited-paragraph-child>prohibited paragraph child</a>, add one to <var title="">offset</var>.
-
-    <div class=XXX>
-    <p>These two steps don't correctly handle things like
-
-    </p><xmp><p>foo<span><br></span></p></xmp>
-
-    <p>For that matter, nor do most cases where we deal with line breaks like
-    this.  Should add a bunch of tests for this and change stuff so we pass.
-    </div>
-
     <li>Otherwise, if <var title="">offset</var> is 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
     <var title="">node</var> and <var title="">node</var> is not a <a href=#prohibited-paragraph-child>prohibited paragraph
     child</a>, or if <var title="">node</var> is an <a href=#invisible-node>invisible node</a>, set
@@ -5527,6 +5533,10 @@
     <li><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="">container</var>.
 
+    <li>If <var title="">container</var> has no <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>, call
+    <code class=external data-anolis-spec=domcore title=dom-Document-createElement><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-document-createelement>createElement("br")</a></code> on the <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#context-object>context object</a> and append the result as
+    the last <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> of <var title="">container</var>.
+
     <li><a href=#fix-disallowed-ancestors>Fix disallowed ancestors</a> of <var title="">container</var>.
 
     <li>Abort these steps.
--- a/implementation.js	Tue Jun 21 15:28:14 2011 -0600
+++ b/implementation.js	Tue Jun 21 16:18:46 2011 -0600
@@ -683,6 +683,36 @@
 	return origHeight != finalHeight;
 }
 
+// "An extraneous line break is a br that has no visual effect, in that
+// removing it from the DOM would not change layout, except that a br that is
+// the sole child of an li is not extraneous."
+function isExtraneousLineBreak(br) {
+	if (!isHtmlElement(br, "br")) {
+		return false;
+	}
+
+	if (isHtmlElement(br.parentNode, "li")
+	&& br.parentNode.childNodes.length == 1) {
+		return false;
+	}
+
+	var ref = br.parentNode;
+	while (getComputedStyle(ref).display == "inline") {
+		ref = ref.parentNode;
+	}
+	var style = br.hasAttribute("style") ? br.getAttribute("style") : null;
+	var origHeight = ref.offsetHeight;
+	br.setAttribute("style", "display:none");
+	var finalHeight = ref.offsetHeight;
+	if (style === null) {
+		br.removeAttribute("style");
+	} else {
+		br.setAttribute("style", style);
+	}
+
+	return origHeight == finalHeight;
+}
+
 //@}
 
 /////////////////////////////
@@ -806,41 +836,58 @@
 }
 
 function removeExtraneousLineBreaksBefore(node) {
-	// "If node is not an Element, or it is an inline node, do nothing and
-	// abort these steps."
-	if (!node
-	|| node.nodeType != Node.ELEMENT_NODE
-	|| isInlineNode(node)) {
+	// "Let ref be the previousSibling of node."
+	var ref = node.previousSibling;
+
+	// "If ref is null, abort these steps."
+	if (!ref) {
 		return;
 	}
 
-	// "If the previousSibling of node is a br, and the previousSibling of the
-	// previousSibling of node is an inline node that is not a br, remove the
-	// previousSibling of node from its parent."
-	if (isHtmlElement(node.previousSibling, "BR")
-	&& isInlineNode(node.previousSibling.previousSibling)
-	&& !isHtmlElement(node.previousSibling.previousSibling, "BR")) {
-		node.parentNode.removeChild(node.previousSibling);
+	// "While ref has children, set ref to its lastChild."
+	while (ref.hasChildNodes()) {
+		ref = ref.lastChild;
+	}
+
+	// "While ref is an invisible node but not an extraneous line break, and
+	// ref does not equal node's parent, set ref to the node before it in tree
+	// order."
+	while (isInvisibleNode(ref)
+	&& !isExtraneousLineBreak(ref)
+	&& ref != node.parentNode) {
+		ref = previousNode(ref);
+	}
+
+	// "If ref is an editable extraneous line break, remove it from its
+	// parent."
+	if (isEditable(ref)
+	&& isExtraneousLineBreak(ref)) {
+		ref.parentNode.removeChild(ref);
 	}
 }
 
 function removeExtraneousLineBreaksAtTheEndOf(node) {
-	// "If node is not an Element, or it is an inline node, do nothing and
-	// abort these steps."
-	if (!node
-	|| node.nodeType != Node.ELEMENT_NODE
-	|| isInlineNode(node)) {
-		return;
-	}
-
-	// "If node has at least two children, and its last child is a br, and its
-	// second-to-last child is an inline node that is not a br, remove the last
-	// child of node from node."
-	if (node.childNodes.length >= 2
-	&& isHtmlElement(node.lastChild, "BR")
-	&& isInlineNode(node.lastChild.previousSibling)
-	&& !isHtmlElement(node.lastChild.previousSibling, "BR")) {
-		node.removeChild(node.lastChild);
+	// "Let ref be node."
+	var ref = node;
+
+	// "While ref has children, set ref to its lastChild."
+	while (ref.hasChildNodes()) {
+		ref = ref.lastChild;
+	}
+
+	// "While ref is an invisible node but not an extraneous line break, and
+	// ref does not equal node, set ref to the node before it in tree order."
+	while (isInvisibleNode(ref)
+	&& !isExtraneousLineBreak(ref)
+	&& ref != node) {
+		ref = previousNode(ref);
+	}
+
+	// "If ref is an editable extraneous line break, remove it from its
+	// parent."
+	if (isEditable(ref)
+	&& isExtraneousLineBreak(ref)) {
+		ref.parentNode.removeChild(ref);
 	}
 }
 
@@ -956,9 +1003,11 @@
 		removeExtraneousLineBreaksBefore(originalParent);
 	}
 
-	// "If node list's last member's nextSibling is null, remove extraneous
-	// line breaks at the end of node list's last member's parent."
-	if (!nodeList[nodeList.length - 1].nextSibling) {
+	// "If node list's last member's nextSibling is null, but its parent is not
+	// null, remove extraneous line breaks at the end of node list's last
+	// member's parent."
+	if (!nodeList[nodeList.length - 1].nextSibling
+	&& nodeList[nodeList.length - 1].parentNode) {
 		removeExtraneousLineBreaksAtTheEndOf(nodeList[nodeList.length - 1].parentNode);
 	}
 }
@@ -3013,15 +3062,17 @@
 var defaultSingleLineContainerName = "p";
 
 // "A visible node is a node that either is a prohibited paragraph child, or a
-// Text node whose data is not empty, or a br or img, or any node with a
-// descendant that is a visible node."
+// Text node whose data is not empty, or an img, or a br that is not an
+// extraneous line break, or any node with a descendant that is a visible
+// node."
 function isVisibleNode(node) {
 	if (!node) {
 		return false;
 	}
 	if (isProhibitedParagraphChild(node)
 	|| (node.nodeType == Node.TEXT_NODE && node.length)
-	|| isHtmlElement(node, ["br", "img"])) {
+	|| isHtmlElement(node, "img")
+	|| (isHtmlElement(node, "br") && !isExtraneousLineBreak(node))) {
 		return true;
 	}
 	for (var i = 0; i < node.childNodes.length; i++) {
@@ -5134,22 +5185,6 @@
 			&& isInvisibleNode(node.childNodes[offset])) {
 				node.removeChild(node.childNodes[offset]);
 
-			// "Otherwise, if offset is one less than node's length, and node
-			// is a prohibited paragraph child whose last child is a br, add
-			// one to offset."
-			} else if (offset == getNodeLength(node) - 1
-			&& isProhibitedParagraphChild(node)
-			&& isHtmlElement(node.lastChild, "br")) {
-				offset++;
-
-			// "Otherwise, if node has a child with index offset + 1, and its
-			// child of index offset is a br, and its child of index offset + 1
-			// is a prohibited paragraph child, add one to offset."
-			} else if (offset + 1 < node.childNodes.length
-			&& isHtmlElement(node.childNodes[offset], "br")
-			&& isProhibitedParagraphChild(node.childNodes[offset + 1])) {
-				offset++;
-
 			// "Otherwise, if offset is the length of node and node is not a
 			// prohibited paragraph child, or if node is an invisible node, set
 			// offset to one plus the index of node, then set node to its
--- a/source.html	Tue Jun 21 15:28:14 2011 -0600
+++ b/source.html	Tue Jun 21 16:18:46 2011 -0600
@@ -388,6 +388,19 @@
 Or its ancestor has a fixed height?  Would it be better to use some DOM-based
 definition?
 
+<p>An <dfn>extraneous line break</dfn> is a [[br]] that has no visual effect,
+in that removing it from the DOM would not change layout, except that a [[br]]
+that is the sole child of an [[li]] is not extraneous.
+
+<p class=XXX>Also possibly a bad definition.  Again, I test by just removing it
+and seeing what happens.  (Actually, setting display: none, so that it doesn't
+mess up ranges.)
+
+<p class=XXX>The thing about li is a not very nice hack.  The issue is that an
+li won't collapse even if it has no children at all, but that's not true in all
+browsers (at least not in Opera 11.11), and also it breaks assumptions
+elsewhere.  E.g., if it gets turned into a p.
+
 <p>Each [[htmldocument]] has a boolean <dfn>CSS styling flag</dfn> associated
 with it, which must initially be false.  (<span>The <code
 title>styleWithCSS</code> command</span> can be used to modify or query it, by
@@ -476,26 +489,38 @@
 <var>node</var>:
 
 <ol>
-  <li>If <var>node</var> is not an [[element]], or it is an <span>inline
-  node</span>, do nothing and abort these steps.
-
-  <li>If the [[previoussibling]] of <var>node</var> is a [[br]], and the
-  [[previoussibling]] of the [[previoussibling]] of <var>node</var> is an
-  <span>inline node</span> that is not a [[br]], remove the [[previoussibling]]
-  of <var>node</var> from its [[parent]].
+  <li>Let <var>ref</var> be the [[previoussibling]] of <var>node</var>.
+
+  <li>If <var>ref</var> is null, abort these steps.
+
+  <li>While <var>ref</var> has [[children]], set <var>ref</var> to its
+  [[lastchild]].
+
+  <li>While <var>ref</var> is an <span>invisible node</span> but not an
+  <span>extraneous line break</span>, and <var>ref</var> does not equal
+  <var>node</var>'s [[parent]], set <var>ref</var> to the [[node]] before it in
+  [[treeorder]].
+
+  <li>If <var>ref</var> is an <span>editable</span> <span>extraneous line
+  break</span>, remove it from its [[parent]].
 </ol>
 
 <p>To <dfn>remove extraneous line breaks at the end of</dfn> a [[node]]
 <var>node</var>:
 
 <ol>
-  <li>If <var>node</var> is not an [[element]], or it is an <span>inline
-  node</span>, do nothing and abort these steps.
-
-  <li>If <var>node</var> has at least two [[children]], and its last [[child]]
-  is a [[br]], and its second-to-last [[child]] is an <span>inline node</span>
-  that is not a [[br]], remove the last [[child]] of <var>node</var> from
-  <var>node</var>.
+  <li>Let <var>ref</var> be <var>node</var>.
+
+  <li>While <var>ref</var> has [[children]], set <var>ref</var> to its
+  [[lastchild]].
+
+  <li>While <var>ref</var> is an <span>invisible node</span> but not an
+  <span>extraneous line break</span>, and <var>ref</var> does not equal
+  <var>node</var>, set <var>ref</var> to the [[node]] before it in
+  [[treeorder]].
+
+  <li>If <var>ref</var> is an <span>editable</span> <span>extraneous line
+  break</span>, remove it from its [[parent]].
 </ol>
 
 <p>To <dfn>remove extraneous line breaks from</dfn> a [[node]], first
@@ -623,8 +648,10 @@
   <var>original parent</var>.
 
   <li>If <var>node list</var>'s last member's [[nextsibling]] is null,
-  <span>remove extraneous line breaks at the end of</span> <var>node
-  list</var>'s last member's [[parent]].
+  but its [[parent]] is not null, <span>remove extraneous line breaks at the
+  end of</span> <var>node list</var>'s last member's [[parent]].
+  <!-- The parent might be null if it's a br that we removed in the last step,
+  in which case this step isn't necessary. -->
 </ol>
 
 <p>To remove a [[node]] <var>node</var> while <dfn>preserving its
@@ -2541,9 +2568,9 @@
 <!-- Possibly to be made configurable later. -->
 
 <p>A <dfn>visible node</dfn> is a [[node]] that either is a <span>prohibited
-paragraph child</span>, or a [[text]] node whose [[cddata]] is not empty, or a
-[[br]] or [[img]], or any [[node]] with a [[descendant]] that is a
-<span>visible node</span>.
+paragraph child</span>, or a [[text]] node whose [[cddata]] is not empty, or
+an [[img]], or a [[br]] that is not an <span>extraneous line break</span>, or
+any [[node]] with a [[descendant]] that is a <span>visible node</span>.
 
 <p>An <dfn>invisible node</dfn> is a [[node]] that is not a <span>visible
 node</span>.
@@ -4907,27 +4934,6 @@
     <var>offset</var> and that [[child]] is an <span>editable</span>
     <span>invisible node</span>, remove that [[child]] from <var>node</var>.
 
-    <!-- We need these extra two steps in forwardDelete, relative to delete, to
-    skip over line breaks at the end of blocks. -->
-    <li>Otherwise, if <var>offset</var> is one less than <var>node</var>'s
-    [[length]], and <var>node</var> is a <span>prohibited paragraph
-    child</span> whose last [[child]] is a [[br]], add one to
-    <var>offset</var>.
-
-    <li>Otherwise, if <var>node</var> has a [[child]] with [[index]]
-    <var>offset</var> + 1, and its [[child]] of [[index]] <var>offset</var> is
-    a [[br]], and its [[child]] of [[index]] <var>offset</var> + 1 is a
-    <span>prohibited paragraph child</span>, add one to <var>offset</var>.
-
-    <div class=XXX>
-    <p>These two steps don't correctly handle things like
-
-    <xmp><p>foo<span><br></span></p></xmp>
-
-    <p>For that matter, nor do most cases where we deal with line breaks like
-    this.  Should add a bunch of tests for this and change stuff so we pass.
-    </div>
-
     <li>Otherwise, if <var>offset</var> is the [[nodelength]] of
     <var>node</var> and <var>node</var> is not a <span>prohibited paragraph
     child</span>, or if <var>node</var> is an <span>invisible node</span>, set
@@ -5541,6 +5547,10 @@
     <li><span>Split the parent</span> of the one-[[node]] list consisting of
     <var>container</var>.
 
+    <li>If <var>container</var> has no [[children]], call
+    [[createelement|"br"]] on the [[contextobject]] and append the result as
+    the last [[child]] of <var>container</var>.
+
     <li><span>Fix disallowed ancestors</span> of <var>container</var>.
 
     <li>Abort these steps.