Bug 677752 - [contentEditable] indent and justify* fail on editable nodes that have only one child; r=ehsan
authorFabien Cazenave <kaze@kompozer.net>
Tue, 23 Aug 2011 15:10:14 -0400
changeset 75760 d303dca1216d0957438b76ee273574c10f2c6c67
parent 75759 a624f57a9e6f693243af539fc9f4699421165e2a
child 75761 d898ca543bbb8beb57a9fbb3dc6a07dfefb45908
push id3
push userfelipc@gmail.com
push dateFri, 30 Sep 2011 20:09:13 +0000
reviewersehsan
bugs677752, 414526
milestone9.0a1
Bug 677752 - [contentEditable] indent and justify* fail on editable nodes that have only one child; r=ehsan Issue #1: indent/justify* can create non-valid fragments. When applying a block-level formatting to a text node, Gecko creates a div or blockquote block around the text node and sets the corresponding "align" or "style" attribute. This patch checks that the active editing host can contain such a block-level element. Issue #2: indent/justify* can modify the active editing host. On the first child of the editable element, the selection is extended outside of the active editing host -- which causes a few issues for our test cases. In this patch, this issue is "solved" by modifying `nsHTMLEditRules::GetPromotedPoint' for block-level operations. ** About the tests ** Sorry for the long explanation but I prefer to be as sharp as possible when I have to modify existing unit tests. This patch raises 34 unit test "failures" which are improvements. Two test files are concerned and have been modified accordingly: * test_htmleditor_keyevent_handling * test_richtext2.html One test has been clarified (no real modification): * test_bug414526.html Of course, a specific unit test has been added, see `test_bug677752.html'. ** editor/libeditor/html/tests/test_htmleditor_keyevent_handling.html ** Outdenting now works properly, which results in 4 `FAIL'. * 7372 ERROR TEST-UNEXPECTED-FAIL | non-tabbable HTML editor: Shift+Tab after Tab on UL - got "<ul><li id=\"target\">ul list item</li></ul>", expected "<ul><ul><li id=\"target\">ul list item</li></ul></ul>" * 7379 ERROR TEST-UNEXPECTED-FAIL | non-tabbable HTML editor: Shift+Tab on UL - got "ul list item", expected "<ul><li id=\"target\">ul list item</li></ul>" * 7415 ERROR TEST-UNEXPECTED-FAIL | non-tabbable HTML editor: Shift+Tab after Tab on OL - got "<ol><li id=\"target\">ol list item</li></ol>", expected "<ol><ol><li id=\"target\">ol list item</li></ol></ol>" * 7422 ERROR TEST-UNEXPECTED-FAIL | non-tabbable HTML editor: Shfit+Tab on OL - got "ol list item", expected "<ol><li id=\"target\">ol list item</li></ol>" ** editor/libeditor/html/tests/browserscope/test_richtext2.html ** The 15 tests that now pass result in 15 `FAIL' and 15 `UNEXPECTED_PASS'. Here's an overview of what we had before the patch: * Section A - Apply Formatting Tests: +10 points before patch: 21/31 (Selection: 9/31) after patch: 28/31 (Selection: 12/31) FB:BQ_TEXT-1_SI EXECUTION EXCEPTION FB:BQ_TEXT-1_SI EXECUTION EXCEPTION FB:BQ_BR.BR-1_SM EXECUTION EXCEPTION FB:BQ_BR.BR-1_SM EXECUTION EXCEPTION IND_TEXT-1_SI EXECUTION EXCEPTION IND_TEXT-1_SI EXECUTION EXCEPTION JC_TEXT-1_SC editing host is modified JF_TEXT-1_SC editing host is modified JL_TEXT-1_SC editing host is modified JR_TEXT-1_SC editing host is modified * Section AC - Apply Formatting Tests, using styleWithCSS: +5 points before patch: 7/18 (Selection: 5/18) after patch: 12/18 (Selection: 5/18) IND_TEXT-1_SI editing host is modified JC_TEXT-1_SC editing host is modified JF_TEXT-1_SC editing host is modified JL_TEXT-1_SC editing host is modified JR_TEXT-1_SC editing host is modified ** editor/libeditor/html/tests/test_bug414526.html ** This test has been clarified to get more explicit report messages -- the test themselves haven't been changed. A `todo_is' test has been added. This test is the one that shows that `IsNodeInActiveEditor' can't be modified, and that limiting the range promotion for block-level operations is preferrable.
editor/libeditor/html/nsHTMLEditRules.cpp
editor/libeditor/html/tests/Makefile.in
editor/libeditor/html/tests/browserscope/lib/richtext2/currentStatus.js
editor/libeditor/html/tests/test_bug414526.html
editor/libeditor/html/tests/test_bug677752.html
editor/libeditor/html/tests/test_htmleditor_keyevent_handling.html
--- a/editor/libeditor/html/nsHTMLEditRules.cpp
+++ b/editor/libeditor/html/nsHTMLEditRules.cpp
@@ -3725,17 +3725,21 @@ nsHTMLEditRules::WillCSSIndent(nsISelect
     {
       if (IsBlockNode(curNode)) {
         RelativeChangeIndentationOfElementNode(curNode, +1);
         curQuote = nsnull;
       }
       else {
         if (!curQuote)
         {
+          // First, check that our element can contain a div.
           NS_NAMED_LITERAL_STRING(divquoteType, "div");
+          if (!mEditor->CanContainTag(curParent, divquoteType))
+            return NS_OK; // cancelled
+
           res = SplitAsNeeded(&divquoteType, address_of(curParent), &offset);
           NS_ENSURE_SUCCESS(res, res);
           res = mHTMLEditor->CreateNode(divquoteType, curParent, offset, getter_AddRefs(curQuote));
           NS_ENSURE_SUCCESS(res, res);
           RelativeChangeIndentationOfElementNode(curQuote, +1);
           // remember our new block for postprocessing
           mNewBlock = curQuote;
           // curQuote is now the correct thing to put curNode in
@@ -3952,16 +3956,20 @@ nsHTMLEditRules::WillHTMLIndent(nsISelec
           res = InDifferentTableElements(curQuote, curNode, &bInDifTblElems);
           NS_ENSURE_SUCCESS(res, res);
           if (bInDifTblElems)
             curQuote = nsnull;
         }
         
         if (!curQuote) 
         {
+          // First, check that our element can contain a blockquote.
+          if (!mEditor->CanContainTag(curParent, quoteType))
+            return NS_OK; // cancelled
+
           res = SplitAsNeeded(&quoteType, address_of(curParent), &offset);
           NS_ENSURE_SUCCESS(res, res);
           res = mHTMLEditor->CreateNode(quoteType, curParent, offset, getter_AddRefs(curQuote));
           NS_ENSURE_SUCCESS(res, res);
           // remember our new block for postprocessing
           mNewBlock = curQuote;
           // curQuote is now the correct thing to put curNode in
         }
@@ -4084,20 +4092,20 @@ nsHTMLEditRules::WillOutdent(nsISelectio
           // fall out and handle curNode
         }
       }
       
       // are we inside a blockquote?
       nsCOMPtr<nsIDOMNode> n = curNode;
       nsCOMPtr<nsIDOMNode> tmp;
       curBlockQuoteIsIndentedWithCSS = PR_FALSE;
-      // keep looking up the hierarchy as long as we don't hit the body or a table element
-      // (other than an entire table)
-      while (!nsTextEditUtils::IsBody(n) &&   
-             (nsHTMLEditUtils::IsTable(n) || !nsHTMLEditUtils::IsTableElement(n)))
+      // keep looking up the hierarchy as long as we don't hit the body or the
+      // active editing host or a table element (other than an entire table)
+      while (!nsTextEditUtils::IsBody(n) && mHTMLEditor->IsNodeInActiveEditor(n)
+          && (nsHTMLEditUtils::IsTable(n) || !nsHTMLEditUtils::IsTableElement(n)))
       {
         n->GetParentNode(getter_AddRefs(tmp));
         if (!tmp) {
           break;
         }
         n = tmp;
         if (nsHTMLEditUtils::IsBlockquote(n))
         {
@@ -4780,29 +4788,33 @@ nsHTMLEditRules::WillAlign(nsISelection 
       }
       // clear out curDiv so that we don't put nodes after this one into it
     }      
 
     // need to make a div to put things in if we haven't already,
     // or if this node doesn't go in div we used earlier.
     if (!curDiv || transitionList[i])
     {
+      // First, check that our element can contain a div.
       NS_NAMED_LITERAL_STRING(divType, "div");
+      if (!mEditor->CanContainTag(curParent, divType))
+        return NS_OK; // cancelled
+
       res = SplitAsNeeded(&divType, address_of(curParent), &offset);
       NS_ENSURE_SUCCESS(res, res);
       res = mHTMLEditor->CreateNode(divType, curParent, offset, getter_AddRefs(curDiv));
       NS_ENSURE_SUCCESS(res, res);
       // remember our new block for postprocessing
       mNewBlock = curDiv;
       // set up the alignment on the div
       nsCOMPtr<nsIDOMElement> divElem = do_QueryInterface(curDiv);
       res = AlignBlock(divElem, alignType, PR_TRUE);
-//      nsAutoString attr(NS_LITERAL_STRING("align"));
-//      res = mHTMLEditor->SetAttribute(divElem, attr, *alignType);
-//      NS_ENSURE_SUCCESS(res, res);
+      //nsAutoString attr(NS_LITERAL_STRING("align"));
+      //res = mHTMLEditor->SetAttribute(divElem, attr, *alignType);
+      //NS_ENSURE_SUCCESS(res, res);
       // curDiv is now the correct thing to put curNode in
     }
 
     // tuck the node into the end of the active div
     res = mHTMLEditor->MoveNode(curNode, curDiv, -1);
     NS_ENSURE_SUCCESS(res, res);
   }
 
@@ -5593,19 +5605,23 @@ nsHTMLEditRules::GetPromotedPoint(RulesE
         break;
 
       res = nsEditor::GetNodeLocation(node, address_of(parent), &pOffset);
       NS_ENSURE_SUCCESS(res, res);
 
       // Don't walk past the editable section. Note that we need to check
       // before walking up to a parent because we need to return the parent
       // object, so the parent itself might not be in the editable area, but
-      // it's OK.
-      if (!mHTMLEditor->IsNodeInActiveEditor(node) &&
-          !mHTMLEditor->IsNodeInActiveEditor(parent)) {
+      // it's OK if we're not performing a block-level action.
+      PRBool blockLevelAction = (actionID == nsHTMLEditor::kOpIndent)
+                             || (actionID == nsHTMLEditor::kOpOutdent)
+                             || (actionID == nsHTMLEditor::kOpAlign)
+                             || (actionID == nsHTMLEditor::kOpMakeBasicBlock);
+      if (!mHTMLEditor->IsNodeInActiveEditor(parent) &&
+          (blockLevelAction || !mHTMLEditor->IsNodeInActiveEditor(node))) {
         break;
       }
 
       node = parent;
       offset = pOffset;
       res = mHTMLEditor->GetPriorHTMLNode(node, offset, address_of(nearNode), PR_TRUE);
       NS_ENSURE_SUCCESS(res, res);
     } 
@@ -8930,18 +8946,27 @@ nsHTMLEditRules::RelativeChangeIndentati
     if (0 < f) {
       nsAutoString newValue;
       newValue.AppendFloat(f);
       newValue.Append(unitString);
       mHTMLEditor->mHTMLCSSUtils->SetCSSProperty(element, marginProperty, newValue, PR_FALSE);
     }
     else {
       mHTMLEditor->mHTMLCSSUtils->RemoveCSSProperty(element, marginProperty, value, PR_FALSE);
-      if (nsHTMLEditUtils::IsDiv(aNode)) {
-        // we deal with a DIV ; let's see if it is useless and if we can remove it
+      // remove unnecessary DIV blocks:
+      // we could skip this section but that would cause a FAIL in
+      // editor/libeditor/html/tests/browserscope/richtext.html, which expects
+      // to unapply a CSS "indent" (<div style="margin-left: 40px;">) by
+      // removing the DIV container instead of just removing the CSS property.
+      nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
+      if (nsHTMLEditUtils::IsDiv(aNode)
+          && (node != mHTMLEditor->GetActiveEditingHost())
+          && mHTMLEditor->IsNodeInActiveEditor(aNode)) {
+        // we deal with an editable DIV;
+        // let's see if it is useless and if we can remove it
         nsCOMPtr<nsIDOMNamedNodeMap> attributeList;
         res = element->GetAttributes(getter_AddRefs(attributeList));
         NS_ENSURE_SUCCESS(res, res);
         PRUint32 count;
         attributeList->GetLength(&count);
         if (!count) {
           // the DIV has no attribute at all, let's remove it
           res = mHTMLEditor->RemoveContainer(element);
--- a/editor/libeditor/html/tests/Makefile.in
+++ b/editor/libeditor/html/tests/Makefile.in
@@ -81,16 +81,17 @@ include $(topsrcdir)/config/rules.mk
 		test_bug612447.html \
 		test_bug620906.html \
 		test_bug622371.html \
 		test_bug629845.html \
 		test_bug640321.html \
 		test_bug668599.html \
 		test_bug674861.html \
 		test_bug676401.html \
+		test_bug677752.html \
 		test_CF_HTML_clipboard.html \
 		test_contenteditable_focus.html \
 		test_htmleditor_keyevent_handling.html \
 		test_select_all_without_body.html \
 		file_select_all_without_body.html \
 		test_root_element_replacement.html \
 		$(NULL)
 
--- a/editor/libeditor/html/tests/browserscope/lib/richtext2/currentStatus.js
+++ b/editor/libeditor/html/tests/browserscope/lib/richtext2/currentStatus.js
@@ -4474,21 +4474,25 @@ const TEST_RESULTS = {
           "selresult": 5,
           "output": "<blockquote>`foo[bar]baz´</blockquote>",
           "innerHTML": "<blockquote>`foo[bar]baz´</blockquote>",
           "outerHTML": "<body xmlns=\"http://www.w3.org/1999/xhtml\" contenteditable=\"true\"><blockquote>`foo[bar]baz´</blockquote></body>",
           "bodyInnerHTML": "<blockquote>`foo[bar]baz´</blockquote>",
           "bodyOuterHTML": "<body xmlns=\"http://www.w3.org/1999/xhtml\" contenteditable=\"true\"><blockquote>`foo[bar]baz´</blockquote></body>"
         },
         "div": {
-          "valscore": 0,
-          "selscore": 0,
-          "valresult": 2,
-          "selresult": 3,
-          "output": "EXECUTION EXCEPTION: [Exception... \"Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsIDOMHTMLDocument.execCommand]\"  nsresult: \"0x80004005 (NS_ERROR_FAILURE)\"  location: \"JS frame :: http://mochi.test:8888/tests/editor/libeditor/html/tests/browserscope/lib/richtext2/richtext2/static/js/run.js :: runSingleTest :: line 143\"  data: no]"
+          "valscore": 1,
+          "selscore": 1,
+          "valresult": 8,
+          "selresult": 5,
+          "output": "<blockquote>`foo[bar]baz´</blockquote>",
+          "innerHTML": "<blockquote>`foo[bar]baz´</blockquote>",
+          "outerHTML": "<div xmlns=\"http://www.w3.org/1999/xhtml\" contenteditable=\"true\" id=\"editor-div\"><blockquote>`foo[bar]baz´</blockquote></div>",
+          "bodyInnerHTML": "CAN<br>ARY<div id=\"editor-div\" contenteditable=\"true\"><blockquote>`foo[bar]baz´</blockquote></div>CAN<br>ARY",
+          "bodyOuterHTML": "<body xmlns=\"http://www.w3.org/1999/xhtml\">CAN<br>ARY<div contenteditable=\"true\" id=\"editor-div\"><blockquote>`foo[bar]baz´</blockquote></div>CAN<br>ARY</body>"
         }
       },
       "FB:BQ_BR.BR-1_SM": {
         "dM": {
           "valscore": 1,
           "selscore": 1,
           "valresult": 8,
           "selresult": 5,
@@ -4505,21 +4509,25 @@ const TEST_RESULTS = {
           "selresult": 5,
           "output": "<blockquote>`fo[o´<br>`bar´<br>`b]az´</blockquote>",
           "innerHTML": "<blockquote>`fo[o´<br>`bar´<br>`b]az´</blockquote>",
           "outerHTML": "<body xmlns=\"http://www.w3.org/1999/xhtml\" contenteditable=\"true\"><blockquote>`fo[o´<br>`bar´<br>`b]az´</blockquote></body>",
           "bodyInnerHTML": "<blockquote>`fo[o´<br>`bar´<br>`b]az´</blockquote>",
           "bodyOuterHTML": "<body xmlns=\"http://www.w3.org/1999/xhtml\" contenteditable=\"true\"><blockquote>`fo[o´<br>`bar´<br>`b]az´</blockquote></body>"
         },
         "div": {
-          "valscore": 0,
-          "selscore": 0,
-          "valresult": 2,
-          "selresult": 3,
-          "output": "EXECUTION EXCEPTION: [Exception... \"Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsIDOMHTMLDocument.execCommand]\"  nsresult: \"0x80004005 (NS_ERROR_FAILURE)\"  location: \"JS frame :: http://mochi.test:8888/tests/editor/libeditor/html/tests/browserscope/lib/richtext2/richtext2/static/js/run.js :: runSingleTest :: line 143\"  data: no]"
+          "valscore": 1,
+          "selscore": 1,
+          "valresult": 8,
+          "selresult": 5,
+          "output": "<blockquote>`fo[o´<br>`bar´<br>`b]az´</blockquote>",
+          "innerHTML": "<blockquote>`fo[o´<br>`bar´<br>`b]az´</blockquote>",
+          "outerHTML": "<div xmlns=\"http://www.w3.org/1999/xhtml\" contenteditable=\"true\" id=\"editor-div\"><blockquote>`fo[o´<br>`bar´<br>`b]az´</blockquote></div>",
+          "bodyInnerHTML": "CAN<br>ARY<div id=\"editor-div\" contenteditable=\"true\"><blockquote>`fo[o´<br>`bar´<br>`b]az´</blockquote></div>CAN<br>ARY",
+          "bodyOuterHTML": "<body xmlns=\"http://www.w3.org/1999/xhtml\">CAN<br>ARY<div contenteditable=\"true\" id=\"editor-div\"><blockquote>`fo[o´<br>`bar´<br>`b]az´</blockquote></div>CAN<br>ARY</body>"
         }
       },
       "BC:blue_TEXT-1_SI": {
         "dM": {
           "valscore": 0,
           "selscore": 0,
           "valresult": 6,
           "selresult": 3,
@@ -4851,21 +4859,25 @@ const TEST_RESULTS = {
           "selresult": 5,
           "output": "<blockquote>`foo[bar]baz´</blockquote>",
           "innerHTML": "<blockquote>`foo[bar]baz´</blockquote>",
           "outerHTML": "<body xmlns=\"http://www.w3.org/1999/xhtml\" contenteditable=\"true\"><blockquote>`foo[bar]baz´</blockquote></body>",
           "bodyInnerHTML": "<blockquote>`foo[bar]baz´</blockquote>",
           "bodyOuterHTML": "<body xmlns=\"http://www.w3.org/1999/xhtml\" contenteditable=\"true\"><blockquote>`foo[bar]baz´</blockquote></body>"
         },
         "div": {
-          "valscore": 0,
-          "selscore": 0,
-          "valresult": 2,
-          "selresult": 3,
-          "output": "EXECUTION EXCEPTION: [Exception... \"Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsIDOMHTMLDocument.execCommand]\"  nsresult: \"0x80004005 (NS_ERROR_FAILURE)\"  location: \"JS frame :: http://mochi.test:8888/tests/editor/libeditor/html/tests/browserscope/lib/richtext2/richtext2/static/js/run.js :: runSingleTest :: line 143\"  data: no]"
+          "valscore": 1,
+          "selscore": 1,
+          "valresult": 8,
+          "selresult": 5,
+          "output": "<blockquote>`foo[bar]baz´</blockquote>",
+          "innerHTML": "<blockquote>`foo[bar]baz´</blockquote>",
+          "outerHTML": "<div xmlns=\"http://www.w3.org/1999/xhtml\" contenteditable=\"true\" id=\"editor-div\"><blockquote>`foo[bar]baz´</blockquote></div>",
+          "bodyInnerHTML": "CAN<br>ARY<div id=\"editor-div\" contenteditable=\"true\"><blockquote>`foo[bar]baz´</blockquote></div>CAN<br>ARY",
+          "bodyOuterHTML": "<body xmlns=\"http://www.w3.org/1999/xhtml\">CAN<br>ARY<div contenteditable=\"true\" id=\"editor-div\"><blockquote>`foo[bar]baz´</blockquote></div>CAN<br>ARY</body>"
         }
       },
       "JC_TEXT-1_SC": {
         "dM": {
           "valscore": 1,
           "selscore": 1,
           "valresult": 8,
           "selresult": 5,
@@ -4882,25 +4894,25 @@ const TEST_RESULTS = {
           "selresult": 5,
           "output": "<div align=\"center\">`foo^bar´</div>",
           "innerHTML": "<div align=\"center\">`foo^bar´</div>",
           "outerHTML": "<body xmlns=\"http://www.w3.org/1999/xhtml\" contenteditable=\"true\"><div align=\"center\">`foo^bar´</div></body>",
           "bodyInnerHTML": "<div align=\"center\">`foo^bar´</div>",
           "bodyOuterHTML": "<body xmlns=\"http://www.w3.org/1999/xhtml\" contenteditable=\"true\"><div align=\"center\">`foo^bar´</div></body>"
         },
         "div": {
-          "valscore": 0,
-          "selscore": 1,
-          "valresult": 7,
-          "selresult": 5,
-          "output": "<div xmlns=\"http://www.w3.org/1999/xhtml\" align=\"center\" contenteditable=\"true\" id=\"editor-div\">`foo^bar´</div>",
-          "innerHTML": "`foo^bar´",
-          "outerHTML": "<div xmlns=\"http://www.w3.org/1999/xhtml\" align=\"center\" contenteditable=\"true\" id=\"editor-div\">`foo^bar´</div>",
-          "bodyInnerHTML": "CAN<br>ARY<div id=\"editor-div\" contenteditable=\"true\" align=\"center\">`foo^bar´</div>CAN<br>ARY",
-          "bodyOuterHTML": "<body xmlns=\"http://www.w3.org/1999/xhtml\">CAN<br>ARY<div align=\"center\" contenteditable=\"true\" id=\"editor-div\">`foo^bar´</div>CAN<br>ARY</body>"
+          "valscore": 1,
+          "selscore": 1,
+          "valresult": 8,
+          "selresult": 5,
+          "output": "<div align=\"center\">`foo^bar´</div>",
+          "innerHTML": "<div align=\"center\">`foo^bar´</div>",
+          "outerHTML": "<div xmlns=\"http://www.w3.org/1999/xhtml\" contenteditable=\"true\" id=\"editor-div\"><div align=\"center\">`foo^bar´</div></div>",
+          "bodyInnerHTML": "CAN<br>ARY<div id=\"editor-div\" contenteditable=\"true\"><div align=\"center\">`foo^bar´</div></div>CAN<br>ARY",
+          "bodyOuterHTML": "<body xmlns=\"http://www.w3.org/1999/xhtml\">CAN<br>ARY<div contenteditable=\"true\" id=\"editor-div\"><div align=\"center\">`foo^bar´</div></div>CAN<br>ARY</body>"
         }
       },
       "JF_TEXT-1_SC": {
         "dM": {
           "valscore": 1,
           "selscore": 1,
           "valresult": 8,
           "selresult": 5,
@@ -4917,25 +4929,25 @@ const TEST_RESULTS = {
           "selresult": 5,
           "output": "<div align=\"justify\">`foo^bar´</div>",
           "innerHTML": "<div align=\"justify\">`foo^bar´</div>",
           "outerHTML": "<body xmlns=\"http://www.w3.org/1999/xhtml\" contenteditable=\"true\"><div align=\"justify\">`foo^bar´</div></body>",
           "bodyInnerHTML": "<div align=\"justify\">`foo^bar´</div>",
           "bodyOuterHTML": "<body xmlns=\"http://www.w3.org/1999/xhtml\" contenteditable=\"true\"><div align=\"justify\">`foo^bar´</div></body>"
         },
         "div": {
-          "valscore": 0,
-          "selscore": 1,
-          "valresult": 7,
-          "selresult": 5,
-          "output": "<div xmlns=\"http://www.w3.org/1999/xhtml\" align=\"justify\" contenteditable=\"true\" id=\"editor-div\">`foo^bar´</div>",
-          "innerHTML": "`foo^bar´",
-          "outerHTML": "<div xmlns=\"http://www.w3.org/1999/xhtml\" align=\"justify\" contenteditable=\"true\" id=\"editor-div\">`foo^bar´</div>",
-          "bodyInnerHTML": "CAN<br>ARY<div id=\"editor-div\" contenteditable=\"true\" align=\"justify\">`foo^bar´</div>CAN<br>ARY",
-          "bodyOuterHTML": "<body xmlns=\"http://www.w3.org/1999/xhtml\">CAN<br>ARY<div align=\"justify\" contenteditable=\"true\" id=\"editor-div\">`foo^bar´</div>CAN<br>ARY</body>"
+          "valscore": 1,
+          "selscore": 1,
+          "valresult": 8,
+          "selresult": 5,
+          "output": "<div align=\"justify\">`foo^bar´</div>",
+          "innerHTML": "<div align=\"justify\">`foo^bar´</div>",
+          "outerHTML": "<div xmlns=\"http://www.w3.org/1999/xhtml\" contenteditable=\"true\" id=\"editor-div\"><div align=\"justify\">`foo^bar´</div></div>",
+          "bodyInnerHTML": "CAN<br>ARY<div id=\"editor-div\" contenteditable=\"true\"><div align=\"justify\">`foo^bar´</div></div>CAN<br>ARY",
+          "bodyOuterHTML": "<body xmlns=\"http://www.w3.org/1999/xhtml\">CAN<br>ARY<div contenteditable=\"true\" id=\"editor-div\"><div align=\"justify\">`foo^bar´</div></div>CAN<br>ARY</body>"
         }
       },
       "JL_TEXT-1_SC": {
         "dM": {
           "valscore": 1,
           "selscore": 1,
           "valresult": 8,
           "selresult": 5,
@@ -4952,25 +4964,25 @@ const TEST_RESULTS = {
           "selresult": 5,
           "output": "<div align=\"left\">`foo^bar´</div>",
           "innerHTML": "<div align=\"left\">`foo^bar´</div>",
           "outerHTML": "<body xmlns=\"http://www.w3.org/1999/xhtml\" contenteditable=\"true\"><div align=\"left\">`foo^bar´</div></body>",
           "bodyInnerHTML": "<div align=\"left\">`foo^bar´</div>",
           "bodyOuterHTML": "<body xmlns=\"http://www.w3.org/1999/xhtml\" contenteditable=\"true\"><div align=\"left\">`foo^bar´</div></body>"
         },
         "div": {
-          "valscore": 0,
-          "selscore": 1,
-          "valresult": 7,
-          "selresult": 5,
-          "output": "<div xmlns=\"http://www.w3.org/1999/xhtml\" align=\"left\" contenteditable=\"true\" id=\"editor-div\">`foo^bar´</div>",
-          "innerHTML": "`foo^bar´",
-          "outerHTML": "<div xmlns=\"http://www.w3.org/1999/xhtml\" align=\"left\" contenteditable=\"true\" id=\"editor-div\">`foo^bar´</div>",
-          "bodyInnerHTML": "CAN<br>ARY<div id=\"editor-div\" contenteditable=\"true\" align=\"left\">`foo^bar´</div>CAN<br>ARY",
-          "bodyOuterHTML": "<body xmlns=\"http://www.w3.org/1999/xhtml\">CAN<br>ARY<div align=\"left\" contenteditable=\"true\" id=\"editor-div\">`foo^bar´</div>CAN<br>ARY</body>"
+          "valscore": 1,
+          "selscore": 1,
+          "valresult": 8,
+          "selresult": 5,
+          "output": "<div align=\"left\">`foo^bar´</div>",
+          "innerHTML": "<div align=\"left\">`foo^bar´</div>",
+          "outerHTML": "<div xmlns=\"http://www.w3.org/1999/xhtml\" contenteditable=\"true\" id=\"editor-div\"><div align=\"left\">`foo^bar´</div></div>",
+          "bodyInnerHTML": "CAN<br>ARY<div id=\"editor-div\" contenteditable=\"true\"><div align=\"left\">`foo^bar´</div></div>CAN<br>ARY",
+          "bodyOuterHTML": "<body xmlns=\"http://www.w3.org/1999/xhtml\">CAN<br>ARY<div contenteditable=\"true\" id=\"editor-div\"><div align=\"left\">`foo^bar´</div></div>CAN<br>ARY</body>"
         }
       },
       "JR_TEXT-1_SC": {
         "dM": {
           "valscore": 1,
           "selscore": 1,
           "valresult": 8,
           "selresult": 5,
@@ -4987,25 +4999,25 @@ const TEST_RESULTS = {
           "selresult": 5,
           "output": "<div align=\"right\">`foo^bar´</div>",
           "innerHTML": "<div align=\"right\">`foo^bar´</div>",
           "outerHTML": "<body xmlns=\"http://www.w3.org/1999/xhtml\" contenteditable=\"true\"><div align=\"right\">`foo^bar´</div></body>",
           "bodyInnerHTML": "<div align=\"right\">`foo^bar´</div>",
           "bodyOuterHTML": "<body xmlns=\"http://www.w3.org/1999/xhtml\" contenteditable=\"true\"><div align=\"right\">`foo^bar´</div></body>"
         },
         "div": {
-          "valscore": 0,
-          "selscore": 1,
-          "valresult": 7,
-          "selresult": 5,
-          "output": "<div xmlns=\"http://www.w3.org/1999/xhtml\" align=\"right\" contenteditable=\"true\" id=\"editor-div\">`foo^bar´</div>",
-          "innerHTML": "`foo^bar´",
-          "outerHTML": "<div xmlns=\"http://www.w3.org/1999/xhtml\" align=\"right\" contenteditable=\"true\" id=\"editor-div\">`foo^bar´</div>",
-          "bodyInnerHTML": "CAN<br>ARY<div id=\"editor-div\" contenteditable=\"true\" align=\"right\">`foo^bar´</div>CAN<br>ARY",
-          "bodyOuterHTML": "<body xmlns=\"http://www.w3.org/1999/xhtml\">CAN<br>ARY<div align=\"right\" contenteditable=\"true\" id=\"editor-div\">`foo^bar´</div>CAN<br>ARY</body>"
+          "valscore": 1,
+          "selscore": 1,
+          "valresult": 8,
+          "selresult": 5,
+          "output": "<div align=\"right\">`foo^bar´</div>",
+          "innerHTML": "<div align=\"right\">`foo^bar´</div>",
+          "outerHTML": "<div xmlns=\"http://www.w3.org/1999/xhtml\" contenteditable=\"true\" id=\"editor-div\"><div align=\"right\">`foo^bar´</div></div>",
+          "bodyInnerHTML": "CAN<br>ARY<div id=\"editor-div\" contenteditable=\"true\"><div align=\"right\">`foo^bar´</div></div>CAN<br>ARY",
+          "bodyOuterHTML": "<body xmlns=\"http://www.w3.org/1999/xhtml\">CAN<br>ARY<div contenteditable=\"true\" id=\"editor-div\"><div align=\"right\">`foo^bar´</div></div>CAN<br>ARY</body>"
         }
       },
       "H:H1_TEXT-1_SC": {
         "dM": {
           "valscore": 1,
           "selscore": 1,
           "valresult": 8,
           "selresult": 5,
@@ -5551,25 +5563,25 @@ const TEST_RESULTS = {
           "selresult": 5,
           "output": "<div style=\"margin-left: 40px;\">`foo[bar]baz´</div>",
           "innerHTML": "<div style=\"margin-left: 40px;\">`foo[bar]baz´</div>",
           "outerHTML": "<body xmlns=\"http://www.w3.org/1999/xhtml\" contenteditable=\"true\"><div style=\"margin-left: 40px;\">`foo[bar]baz´</div></body>",
           "bodyInnerHTML": "<div style=\"margin-left: 40px;\">`foo[bar]baz´</div>",
           "bodyOuterHTML": "<body xmlns=\"http://www.w3.org/1999/xhtml\" contenteditable=\"true\"><div style=\"margin-left: 40px;\">`foo[bar]baz´</div></body>"
         },
         "div": {
-          "valscore": 0,
-          "selscore": 1,
-          "valresult": 7,
-          "selresult": 5,
-          "output": "<div xmlns=\"http://www.w3.org/1999/xhtml\" contenteditable=\"true\" id=\"editor-div\" style=\"margin-left: 40px;\">`foo[bar]baz´</div>",
-          "innerHTML": "`foo[bar]baz´",
-          "outerHTML": "<div xmlns=\"http://www.w3.org/1999/xhtml\" contenteditable=\"true\" id=\"editor-div\" style=\"margin-left: 40px;\">`foo[bar]baz´</div>",
-          "bodyInnerHTML": "CAN<br>ARY<div style=\"margin-left: 40px;\" id=\"editor-div\" contenteditable=\"true\">`foo[bar]baz´</div>CAN<br>ARY",
-          "bodyOuterHTML": "<body xmlns=\"http://www.w3.org/1999/xhtml\">CAN<br>ARY<div contenteditable=\"true\" id=\"editor-div\" style=\"margin-left: 40px;\">`foo[bar]baz´</div>CAN<br>ARY</body>"
+          "valscore": 1,
+          "selscore": 1,
+          "valresult": 8,
+          "selresult": 5,
+          "output": "<div style=\"margin-left: 40px;\">`foo[bar]baz´</div>",
+          "innerHTML": "<div style=\"margin-left: 40px;\">`foo[bar]baz´</div>",
+          "outerHTML": "<div xmlns=\"http://www.w3.org/1999/xhtml\" contenteditable=\"true\" id=\"editor-div\"><div style=\"margin-left: 40px;\">`foo[bar]baz´</div></div>",
+          "bodyInnerHTML": "CAN<br>ARY<div id=\"editor-div\" contenteditable=\"true\"><div style=\"margin-left: 40px;\">`foo[bar]baz´</div></div>CAN<br>ARY",
+          "bodyOuterHTML": "<body xmlns=\"http://www.w3.org/1999/xhtml\">CAN<br>ARY<div contenteditable=\"true\" id=\"editor-div\"><div style=\"margin-left: 40px;\">`foo[bar]baz´</div></div>CAN<br>ARY</body>"
         }
       },
       "JC_TEXT-1_SC": {
         "dM": {
           "valscore": 1,
           "selscore": 1,
           "valresult": 8,
           "selresult": 5,
@@ -5586,25 +5598,25 @@ const TEST_RESULTS = {
           "selresult": 5,
           "output": "<div style=\"text-align: center;\">`foo^bar´</div>",
           "innerHTML": "<div style=\"text-align: center;\">`foo^bar´</div>",
           "outerHTML": "<body xmlns=\"http://www.w3.org/1999/xhtml\" contenteditable=\"true\"><div style=\"text-align: center;\">`foo^bar´</div></body>",
           "bodyInnerHTML": "<div style=\"text-align: center;\">`foo^bar´</div>",
           "bodyOuterHTML": "<body xmlns=\"http://www.w3.org/1999/xhtml\" contenteditable=\"true\"><div style=\"text-align: center;\">`foo^bar´</div></body>"
         },
         "div": {
-          "valscore": 0,
-          "selscore": 1,
-          "valresult": 7,
-          "selresult": 5,
-          "output": "<div xmlns=\"http://www.w3.org/1999/xhtml\" contenteditable=\"true\" id=\"editor-div\" style=\"text-align: center;\">`foo^bar´</div>",
-          "innerHTML": "`foo^bar´",
-          "outerHTML": "<div xmlns=\"http://www.w3.org/1999/xhtml\" contenteditable=\"true\" id=\"editor-div\" style=\"text-align: center;\">`foo^bar´</div>",
-          "bodyInnerHTML": "CAN<br>ARY<div style=\"text-align: center;\" id=\"editor-div\" contenteditable=\"true\">`foo^bar´</div>CAN<br>ARY",
-          "bodyOuterHTML": "<body xmlns=\"http://www.w3.org/1999/xhtml\">CAN<br>ARY<div contenteditable=\"true\" id=\"editor-div\" style=\"text-align: center;\">`foo^bar´</div>CAN<br>ARY</body>"
+          "valscore": 1,
+          "selscore": 1,
+          "valresult": 8,
+          "selresult": 5,
+          "output": "<div style=\"text-align: center;\">`foo^bar´</div>",
+          "innerHTML": "<div style=\"text-align: center;\">`foo^bar´</div>",
+          "outerHTML": "<div xmlns=\"http://www.w3.org/1999/xhtml\" contenteditable=\"true\" id=\"editor-div\"><div style=\"text-align: center;\">`foo^bar´</div></div>",
+          "bodyInnerHTML": "CAN<br>ARY<div id=\"editor-div\" contenteditable=\"true\"><div style=\"text-align: center;\">`foo^bar´</div></div>CAN<br>ARY",
+          "bodyOuterHTML": "<body xmlns=\"http://www.w3.org/1999/xhtml\">CAN<br>ARY<div contenteditable=\"true\" id=\"editor-div\"><div style=\"text-align: center;\">`foo^bar´</div></div>CAN<br>ARY</body>"
         }
       },
       "JF_TEXT-1_SC": {
         "dM": {
           "valscore": 1,
           "selscore": 1,
           "valresult": 8,
           "selresult": 5,
@@ -5621,25 +5633,25 @@ const TEST_RESULTS = {
           "selresult": 5,
           "output": "<div style=\"text-align: justify;\">`foo^bar´</div>",
           "innerHTML": "<div style=\"text-align: justify;\">`foo^bar´</div>",
           "outerHTML": "<body xmlns=\"http://www.w3.org/1999/xhtml\" contenteditable=\"true\"><div style=\"text-align: justify;\">`foo^bar´</div></body>",
           "bodyInnerHTML": "<div style=\"text-align: justify;\">`foo^bar´</div>",
           "bodyOuterHTML": "<body xmlns=\"http://www.w3.org/1999/xhtml\" contenteditable=\"true\"><div style=\"text-align: justify;\">`foo^bar´</div></body>"
         },
         "div": {
-          "valscore": 0,
-          "selscore": 1,
-          "valresult": 7,
-          "selresult": 5,
-          "output": "<div xmlns=\"http://www.w3.org/1999/xhtml\" contenteditable=\"true\" id=\"editor-div\" style=\"text-align: justify;\">`foo^bar´</div>",
-          "innerHTML": "`foo^bar´",
-          "outerHTML": "<div xmlns=\"http://www.w3.org/1999/xhtml\" contenteditable=\"true\" id=\"editor-div\" style=\"text-align: justify;\">`foo^bar´</div>",
-          "bodyInnerHTML": "CAN<br>ARY<div style=\"text-align: justify;\" id=\"editor-div\" contenteditable=\"true\">`foo^bar´</div>CAN<br>ARY",
-          "bodyOuterHTML": "<body xmlns=\"http://www.w3.org/1999/xhtml\">CAN<br>ARY<div contenteditable=\"true\" id=\"editor-div\" style=\"text-align: justify;\">`foo^bar´</div>CAN<br>ARY</body>"
+          "valscore": 1,
+          "selscore": 1,
+          "valresult": 8,
+          "selresult": 5,
+          "output": "<div style=\"text-align: justify;\">`foo^bar´</div>",
+          "innerHTML": "<div style=\"text-align: justify;\">`foo^bar´</div>",
+          "outerHTML": "<div xmlns=\"http://www.w3.org/1999/xhtml\" contenteditable=\"true\" id=\"editor-div\"><div style=\"text-align: justify;\">`foo^bar´</div></div>",
+          "bodyInnerHTML": "CAN<br>ARY<div id=\"editor-div\" contenteditable=\"true\"><div style=\"text-align: justify;\">`foo^bar´</div></div>CAN<br>ARY",
+          "bodyOuterHTML": "<body xmlns=\"http://www.w3.org/1999/xhtml\">CAN<br>ARY<div contenteditable=\"true\" id=\"editor-div\"><div style=\"text-align: justify;\">`foo^bar´</div></div>CAN<br>ARY</body>"
         }
       },
       "JL_TEXT-1_SC": {
         "dM": {
           "valscore": 1,
           "selscore": 1,
           "valresult": 8,
           "selresult": 5,
@@ -5656,25 +5668,25 @@ const TEST_RESULTS = {
           "selresult": 5,
           "output": "<div style=\"text-align: left;\">`foo^bar´</div>",
           "innerHTML": "<div style=\"text-align: left;\">`foo^bar´</div>",
           "outerHTML": "<body xmlns=\"http://www.w3.org/1999/xhtml\" contenteditable=\"true\"><div style=\"text-align: left;\">`foo^bar´</div></body>",
           "bodyInnerHTML": "<div style=\"text-align: left;\">`foo^bar´</div>",
           "bodyOuterHTML": "<body xmlns=\"http://www.w3.org/1999/xhtml\" contenteditable=\"true\"><div style=\"text-align: left;\">`foo^bar´</div></body>"
         },
         "div": {
-          "valscore": 0,
-          "selscore": 1,
-          "valresult": 7,
-          "selresult": 5,
-          "output": "<div xmlns=\"http://www.w3.org/1999/xhtml\" contenteditable=\"true\" id=\"editor-div\" style=\"text-align: left;\">`foo^bar´</div>",
-          "innerHTML": "`foo^bar´",
-          "outerHTML": "<div xmlns=\"http://www.w3.org/1999/xhtml\" contenteditable=\"true\" id=\"editor-div\" style=\"text-align: left;\">`foo^bar´</div>",
-          "bodyInnerHTML": "CAN<br>ARY<div style=\"text-align: left;\" id=\"editor-div\" contenteditable=\"true\">`foo^bar´</div>CAN<br>ARY",
-          "bodyOuterHTML": "<body xmlns=\"http://www.w3.org/1999/xhtml\">CAN<br>ARY<div contenteditable=\"true\" id=\"editor-div\" style=\"text-align: left;\">`foo^bar´</div>CAN<br>ARY</body>"
+          "valscore": 1,
+          "selscore": 1,
+          "valresult": 8,
+          "selresult": 5,
+          "output": "<div style=\"text-align: left;\">`foo^bar´</div>",
+          "innerHTML": "<div style=\"text-align: left;\">`foo^bar´</div>",
+          "outerHTML": "<div xmlns=\"http://www.w3.org/1999/xhtml\" contenteditable=\"true\" id=\"editor-div\"><div style=\"text-align: left;\">`foo^bar´</div></div>",
+          "bodyInnerHTML": "CAN<br>ARY<div id=\"editor-div\" contenteditable=\"true\"><div style=\"text-align: left;\">`foo^bar´</div></div>CAN<br>ARY",
+          "bodyOuterHTML": "<body xmlns=\"http://www.w3.org/1999/xhtml\">CAN<br>ARY<div contenteditable=\"true\" id=\"editor-div\"><div style=\"text-align: left;\">`foo^bar´</div></div>CAN<br>ARY</body>"
         }
       },
       "JR_TEXT-1_SC": {
         "dM": {
           "valscore": 1,
           "selscore": 1,
           "valresult": 8,
           "selresult": 5,
@@ -5691,25 +5703,25 @@ const TEST_RESULTS = {
           "selresult": 5,
           "output": "<div style=\"text-align: right;\">`foo^bar´</div>",
           "innerHTML": "<div style=\"text-align: right;\">`foo^bar´</div>",
           "outerHTML": "<body xmlns=\"http://www.w3.org/1999/xhtml\" contenteditable=\"true\"><div style=\"text-align: right;\">`foo^bar´</div></body>",
           "bodyInnerHTML": "<div style=\"text-align: right;\">`foo^bar´</div>",
           "bodyOuterHTML": "<body xmlns=\"http://www.w3.org/1999/xhtml\" contenteditable=\"true\"><div style=\"text-align: right;\">`foo^bar´</div></body>"
         },
         "div": {
-          "valscore": 0,
-          "selscore": 1,
-          "valresult": 7,
-          "selresult": 5,
-          "output": "<div xmlns=\"http://www.w3.org/1999/xhtml\" contenteditable=\"true\" id=\"editor-div\" style=\"text-align: right;\">`foo^bar´</div>",
-          "innerHTML": "`foo^bar´",
-          "outerHTML": "<div xmlns=\"http://www.w3.org/1999/xhtml\" contenteditable=\"true\" id=\"editor-div\" style=\"text-align: right;\">`foo^bar´</div>",
-          "bodyInnerHTML": "CAN<br>ARY<div style=\"text-align: right;\" id=\"editor-div\" contenteditable=\"true\">`foo^bar´</div>CAN<br>ARY",
-          "bodyOuterHTML": "<body xmlns=\"http://www.w3.org/1999/xhtml\">CAN<br>ARY<div contenteditable=\"true\" id=\"editor-div\" style=\"text-align: right;\">`foo^bar´</div>CAN<br>ARY</body>"
+          "valscore": 1,
+          "selscore": 1,
+          "valresult": 8,
+          "selresult": 5,
+          "output": "<div style=\"text-align: right;\">`foo^bar´</div>",
+          "innerHTML": "<div style=\"text-align: right;\">`foo^bar´</div>",
+          "outerHTML": "<div xmlns=\"http://www.w3.org/1999/xhtml\" contenteditable=\"true\" id=\"editor-div\"><div style=\"text-align: right;\">`foo^bar´</div></div>",
+          "bodyInnerHTML": "CAN<br>ARY<div id=\"editor-div\" contenteditable=\"true\"><div style=\"text-align: right;\">`foo^bar´</div></div>CAN<br>ARY",
+          "bodyOuterHTML": "<body xmlns=\"http://www.w3.org/1999/xhtml\">CAN<br>ARY<div contenteditable=\"true\" id=\"editor-div\"><div style=\"text-align: right;\">`foo^bar´</div></div>CAN<br>ARY</body>"
         }
       }
     }
   },
   "C": {
     "Proposed": {
       "I_I-1_SL": {
         "dM": {
--- a/editor/libeditor/html/tests/test_bug414526.html
+++ b/editor/libeditor/html/tests/test_bug414526.html
@@ -37,40 +37,53 @@ function runTests()
   }
 
   function moveCaretToEndOf(aEditor)
   {
     selection.selectAllChildren(aEditor);
     selection.collapseToEnd();
   }
 
+  /* TestCase #1
+   */
   const kTestCase1 =
     "<p id=\"editor1\" contenteditable=\"true\">editor1</p>" +
     "<p id=\"editor2\" contenteditable=\"true\">editor2</p>" +
     "<div id=\"editor3\" contenteditable=\"true\"><div>editor3</div></div>" +
     "<p id=\"editor4\" contenteditable=\"true\">editor4</p>" +
     "non-editable text" +
     "<p id=\"editor5\" contenteditable=\"true\">editor5</p>";
 
-  const kTestCase1_editor3_specialcase =
+  const kTestCase1_editor3_deleteAtStart =
     "<p id=\"editor1\" contenteditable=\"true\">editor1</p>" +
     "<p id=\"editor2\" contenteditable=\"true\">editor2</p>" +
     "<div id=\"editor3\" contenteditable=\"true\"><div>ditor3</div></div>" +
     "<p id=\"editor4\" contenteditable=\"true\">editor4</p>" +
     "non-editable text" +
     "<p id=\"editor5\" contenteditable=\"true\">editor5</p>";
 
+  const kTestCase1_editor3_backspaceAtEnd =
+    "<p id=\"editor1\" contenteditable=\"true\">editor1</p>" +
+    "<p id=\"editor2\" contenteditable=\"true\">editor2</p>" +
+    "<div id=\"editor3\" contenteditable=\"true\"><div>editor</div></div>" +
+    "<p id=\"editor4\" contenteditable=\"true\">editor4</p>" +
+    "non-editable text" +
+    "<p id=\"editor5\" contenteditable=\"true\">editor5</p>";
+
   container.innerHTML = kTestCase1;
 
   var editor1 = document.getElementById("editor1");
   var editor2 = document.getElementById("editor2");
   var editor3 = document.getElementById("editor3");
   var editor4 = document.getElementById("editor4");
   var editor5 = document.getElementById("editor5");
 
+  /* TestCase #1:
+   * pressing backspace key at start should not change the content.
+   */
   editor2.focus();
   moveCaretToStartOf(editor2);
   synthesizeKey("VK_BACK_SPACE", { });
   is(container.innerHTML, kTestCase1,
      "Pressing backspace key at start of editor2 changes the content");
   reset();
 
   editor3.focus();
@@ -89,16 +102,19 @@ function runTests()
 
   editor5.focus();
   moveCaretToStartOf(editor5);
   synthesizeKey("VK_BACK_SPACE", { });
   is(container.innerHTML, kTestCase1,
      "Pressing backspace key at start of editor5 changes the content");
   reset();
 
+  /* TestCase #1:
+   * pressing delete key at end should not change the content.
+   */
   editor1.focus();
   moveCaretToEndOf(editor1);
   synthesizeKey("VK_DELETE", { });
   is(container.innerHTML, kTestCase1,
      "Pressing delete key at end of editor1 changes the content");
   reset();
 
   editor2.focus();
@@ -122,31 +138,48 @@ function runTests()
 
   editor4.focus();
   moveCaretToEndOf(editor4);
   synthesizeKey("VK_DELETE", { });
   is(container.innerHTML, kTestCase1,
      "Pressing delete key at end of editor4 changes the content");
   reset();
 
-  // Cases when the caret is not on text node.
+  /* TestCase #1: cases when the caret is not on text node.
+   *   - pressing delete key at start should remove the first character
+   *   - pressing backspace key at end should remove the first character
+   * and the adjacent blocks should not be changed.
+   */
   editor3.focus();
   moveCaretToStartOf(editor3);
   synthesizeKey("VK_DELETE", { });
-  is(container.innerHTML, kTestCase1_editor3_specialcase,
-     "Pressing delete key at end of editor3 changes the content");
+  is(container.innerHTML, kTestCase1_editor3_deleteAtStart,
+     "Pressing delete key at start of editor3 changes adjacent elements"
+     + " and/or does not remove the first character.");
   reset();
 
+  // Backspace doesn't work here yet.
+  editor3.focus();
+  moveCaretToEndOf(editor3);
+  synthesizeKey("VK_BACK_SPACE", { });
+  todo_is(container.innerHTML, kTestCase1_editor3_backspaceAtEnd,
+          "Pressing backspace key at end of editor3 changes adjacent elements"
+          + " and/or does not remove the last character.");
+  reset();
+  //  We can still check that adjacent elements are not affected.
   editor3.focus();
   moveCaretToEndOf(editor3);
   synthesizeKey("VK_BACK_SPACE", { });
   is(container.innerHTML, kTestCase1,
      "Pressing backspace key at end of editor3 changes the content");
   reset();
 
+  /* TestCase #2:
+   * two adjacent editable <span> in a table cell.
+   */
   const kTestCase2 = "<table><tbody><tr><td><span id=\"editor1\" contenteditable=\"true\">test</span>" +
     "<span id=\"editor2\" contenteditable=\"true\">test</span></td></tr></tbody></table>";
 
   container.innerHTML = kTestCase2;
   editor1 = document.getElementById("editor1");
   editor2 = document.getElementById("editor2");
 
   editor2.focus();
@@ -158,16 +191,19 @@ function runTests()
 
   editor1.focus();
   moveCaretToEndOf(editor1);
   synthesizeKey("VK_DELETE", { });
   is(container.innerHTML, kTestCase2,
      "Pressing delete key at the end of editor1 changes the content for kTestCase2");
   reset();
 
+  /* TestCase #3:
+   * editable <span> in two adjacent table cells.
+   */
   const kTestCase3 = "<table><tbody><tr><td><span id=\"editor1\" contenteditable=\"true\">test</span></td>" +
     "<td><span id=\"editor2\" contenteditable=\"true\">test</span></td></tr></tbody></table>";
 
   container.innerHTML = kTestCase3;
   editor1 = document.getElementById("editor1");
   editor2 = document.getElementById("editor2");
 
   editor2.focus();
@@ -179,16 +215,19 @@ function runTests()
 
   editor1.focus();
   moveCaretToEndOf(editor1);
   synthesizeKey("VK_DELETE", { });
   is(container.innerHTML, kTestCase3,
      "Pressing delete key at the end of editor1 changes the content for kTestCase3");
   reset();
 
+  /* TestCase #4:
+   * editable <div> in two adjacent table cells.
+   */
   const kTestCase4 = "<table><tbody><tr><td><div id=\"editor1\" contenteditable=\"true\">test</div></td>" +
     "<td><div id=\"editor2\" contenteditable=\"true\">test</div></td></tr></tbody></table>";
 
   container.innerHTML = kTestCase4;
   editor1 = document.getElementById("editor1");
   editor2 = document.getElementById("editor2");
 
   editor2.focus();
new file mode 100644
--- /dev/null
+++ b/editor/libeditor/html/tests/test_bug677752.html
@@ -0,0 +1,107 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=677752
+-->
+<head>
+  <title>Test for Bug 677752</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=677752">Mozilla Bug 677752</a>
+<p id="display"></p>
+<div id="content">
+  <section contenteditable> foo bar </section>
+  <div contenteditable> foo bar </div>
+  <p contenteditable> foo bar </p>
+</div>
+
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 677752 **/
+SimpleTest.waitForExplicitFinish();
+SimpleTest.waitForFocus(runTests);
+
+function selectEditor(aEditor) {
+  aEditor.focus();
+  var selection = window.getSelection();
+  selection.selectAllChildren(aEditor);
+  selection.collapseToStart();
+}
+
+function runTests() {
+  var editor, node, initialHTML;
+  document.execCommand('styleWithCSS', false, true);
+
+  // editable <section>
+  editor = document.querySelector("section[contenteditable]");
+  initialHTML = editor.innerHTML;
+  selectEditor(editor);
+  // editable <section>: justify
+  document.execCommand("justifyright", false, null);
+  node = editor.querySelector("*");
+  is(node.nodeName.toLowerCase(), "div", "'justifyright' should create a <div> in the editable <section>.");
+  is(node.style.textAlign,      "right", "'justifyright' should create a 'text-align: right' CSS rule.");
+  document.execCommand("undo", false, null);
+  // editable <section>: indent
+  document.execCommand("indent", false, null);
+  node = editor.querySelector("*");
+  is(node.nodeName.toLowerCase(), "div", "'indent' should create a <div> in the editable <section>.");
+  is(node.style.marginLeft,      "40px", "'indent' should create a 'margin-left: 40px' CSS rule.");
+  // editable <section>: undo with outdent
+  // this should remove the whole <div> but only removing the CSS rule would be acceptable, too
+  document.execCommand("outdent", false, null);
+  is(editor.innerHTML, initialHTML, "'outdent' should undo the 'indent' action.");
+  // editable <section>: outdent again
+  document.execCommand("outdent", false, null);
+  is(editor.innerHTML, initialHTML, "another 'outdent' should not modify the <section> element.");
+
+  // editable <div>
+  editor = document.querySelector("div[contenteditable]");
+  initialHTML = editor.innerHTML;
+  selectEditor(editor);
+  // editable <div>: justify
+  document.execCommand("justifyright", false, null);
+  node = editor.querySelector("*");
+  is(node.nodeName.toLowerCase(), "div", "'justifyright' should create a <div> in the editable <div>.");
+  is(node.style.textAlign,      "right", "'justifyright' should create a 'text-align: right' CSS rule.");
+  document.execCommand("undo", false, null);
+  // editable <div>: indent
+  document.execCommand("indent", false, null);
+  node = editor.querySelector("*");
+  is(node.nodeName.toLowerCase(), "div", "'indent' should create a <div> in the editable <div>.");
+  is(node.style.marginLeft,      "40px", "'indent' should create a 'margin-left: 40px' CSS rule.");
+  // editable <div>: undo with outdent
+  // this should remove the whole <div> but only removing the CSS rule would be acceptable, too
+  document.execCommand("outdent", false, null);
+  is(editor.innerHTML, initialHTML, "'outdent' should undo the 'indent' action.");
+  // editable <div>: outdent again
+  document.execCommand("outdent", false, null);
+  is(editor.innerHTML, initialHTML, "another 'outdent' should not modify the <div> element.");
+
+  // editable <p>
+  // all block-level commands should be ignored (<p><div/></p> is not valid)
+  editor = document.querySelector("p[contenteditable]");
+  initialHTML = editor.innerHTML;
+  selectEditor(editor);
+  // editable <p>: justify
+  document.execCommand("justifyright", false, null);
+  is(editor.innerHTML, initialHTML, "'justifyright' should have no effect on <p>.");
+  // editable <p>: indent
+  document.execCommand("indent", false, null);
+  is(editor.innerHTML, initialHTML, "'indent' should have no effect on <p>.");
+  // editable <p>: outdent
+  document.execCommand("outdent", false, null);
+  is(editor.innerHTML, initialHTML, "'outdent' should have no effect on <p>.");
+
+  // done
+  SimpleTest.finish();
+}
+
+</script>
+</pre>
+</body>
+</html>
--- a/editor/libeditor/html/tests/test_htmleditor_keyevent_handling.html
+++ b/editor/libeditor/html/tests/test_htmleditor_keyevent_handling.html
@@ -320,35 +320,31 @@ function runTests()
          aIsPlaintext ? "<ul><li id=\"target\">ul list item\t</li></ul>" :
            "<ul><ul><li id=\"target\">ul list item</li></ul></ul>",
        aDescription + "Tab on UL");
     is(fm.focusedElement, aElement,
        aDescription + "focus moved unexpectedly (Tab on UL)");
     synthesizeKey("VK_TAB", { shiftKey: true });
     check(aDescription + "Shift+Tab after Tab on UL",
           true, true, !aIsTabbable && !aIsReadonly && !aIsPlaintext);
-    // XXX why do we fail to outdent on non-tabbable HTML editor?
     is(aElement.innerHTML,
-       aIsReadonly || aIsTabbable ?
+       aIsReadonly || aIsTabbable || (!aIsPlaintext) ?
          "<ul><li id=\"target\">ul list item</li></ul>" :
-         aIsPlaintext ? "<ul><li id=\"target\">ul list item\t</li></ul>" :
-           "<ul><ul><li id=\"target\">ul list item</li></ul></ul>",
+         "<ul><li id=\"target\">ul list item\t</li></ul>",
        aDescription + "Shift+Tab after Tab on UL");
     is(fm.focusedElement, aElement,
        aDescription + "focus moved unexpectedly (Shift+Tab after Tab on UL)");
 
     resetForIndent("<ul><li id=\"target\">ul list item</li></ul>");
     synthesizeKey("VK_TAB", { shiftKey: true });
     check(aDescription + "Shift+Tab on UL",
           true, true, !aIsTabbable && !aIsReadonly && !aIsPlaintext);
     is(aElement.innerHTML,
-       aIsReadonly || aIsTabbable ?
-         "<ul><li id=\"target\">ul list item</li></ul>" :
-         aIsPlaintext ? "<ul><li id=\"target\">ul list item</li></ul>" :
-           "<ul><li id=\"target\">ul list item</li></ul>",
+       aIsReadonly || aIsTabbable || aIsPlaintext ?
+         "<ul><li id=\"target\">ul list item</li></ul>" : "ul list item",
        aDescription + "Shift+Tab on UL");
     is(fm.focusedElement, aElement,
        aDescription + "focus moved unexpectedly (Shift+Tab on UL)");
 
     // Ctrl+Tab may be consumed by tabbrowser but editor shouldn't consume this.
     resetForIndent("<ul><li id=\"target\">ul list item</li></ul>");
     synthesizeKey("VK_TAB", { ctrlKey: true });
     check(aDescription + "Ctrl+Tab on UL", true, true, false);
@@ -384,35 +380,31 @@ function runTests()
          aIsPlaintext ? "<ol><li id=\"target\">ol list item\t</li></ol>" :
            "<ol><ol><li id=\"target\">ol list item</li></ol></ol>",
        aDescription + "Tab on OL");
     is(fm.focusedElement, aElement,
        aDescription + "focus moved unexpectedly (Tab on OL)");
     synthesizeKey("VK_TAB", { shiftKey: true });
     check(aDescription + "Shift+Tab after Tab on OL",
           true, true, !aIsTabbable && !aIsReadonly && !aIsPlaintext);
-    // XXX why do we fail to outdent on non-tabbable HTML editor?
     is(aElement.innerHTML,
-       aIsReadonly || aIsTabbable ?
+       aIsReadonly || aIsTabbable || (!aIsPlaintext) ?
          "<ol><li id=\"target\">ol list item</li></ol>" :
-         aIsPlaintext ? "<ol><li id=\"target\">ol list item\t</li></ol>" :
-           "<ol><ol><li id=\"target\">ol list item</li></ol></ol>",
+         "<ol><li id=\"target\">ol list item\t</li></ol>",
        aDescription + "Shift+Tab after Tab on OL");
     is(fm.focusedElement, aElement,
        aDescription + "focus moved unexpectedly (Shift+Tab after Tab on OL)");
 
     resetForIndent("<ol><li id=\"target\">ol list item</li></ol>");
     synthesizeKey("VK_TAB", { shiftKey: true });
     check(aDescription + "Shift+Tab on OL",
           true, true, !aIsTabbable && !aIsReadonly && !aIsPlaintext);
     is(aElement.innerHTML,
-       aIsReadonly || aIsTabbable ?
-         "<ol><li id=\"target\">ol list item</li></ol>" :
-         aIsPlaintext ? "<ol><li id=\"target\">ol list item</li></ol>" :
-           "<ol><li id=\"target\">ol list item</li></ol>",
+       aIsReadonly || aIsTabbable || aIsPlaintext ?
+         "<ol><li id=\"target\">ol list item</li></ol>" : "ol list item",
        aDescription + "Shfit+Tab on OL");
     is(fm.focusedElement, aElement,
        aDescription + "focus moved unexpectedly (Shift+Tab on OL)");
 
     // Ctrl+Tab may be consumed by tabbrowser but editor shouldn't consume this.
     resetForIndent("<ol><li id=\"target\">ol list item</li></ol>");
     synthesizeKey("VK_TAB", { ctrlKey: true });
     check(aDescription + "Ctrl+Tab on OL", true, true, false);