Bug 1381710 - Selection.addRange will be failure with dynamic table insertion. r?tnikkel draft
authorMakoto Kato <m_kato@ga2.so-net.ne.jp>
Tue, 18 Jul 2017 16:54:31 +0900
changeset 642442 8d81c28b3d89de6b531db26273904ad155ac9987
parent 642204 65507616792c990b1230888612dd7ffc13ed32b4
child 724992 a66c7d3736d50447ab4bf8e6cc5e9fc1bad686a5
push id72748
push userbmo:m_kato@ga2.so-net.ne.jp
push dateTue, 08 Aug 2017 08:16:21 +0000
reviewerstnikkel
bugs1381710
milestone57.0a1
Bug 1381710 - Selection.addRange will be failure with dynamic table insertion. r?tnikkel When range is selected table element, Selection.addRange uses nsFrameSelection. If frame isn't constructed yet, addRange throws NS_ERROR_FAILURE even if table element isn't editable element. When getting nsITableCellLayout, we should flush frame to construct cell frame. MozReview-Commit-ID: 9qWwW46RYNL
dom/base/Selection.cpp
dom/base/test/mochitest.ini
dom/base/test/test_bug1381710.html
--- a/dom/base/Selection.cpp
+++ b/dom/base/Selection.cpp
@@ -600,24 +600,34 @@ Selection::GetTableCellLocationFromRange
 
   // Get the child content (the cell) pointed to by starting node of range
   // We do minimal checking since GetTableSelectionType assures
   //   us that this really is a table cell
   nsCOMPtr<nsIContent> content = do_QueryInterface(aRange->GetStartContainer());
   if (!content)
     return NS_ERROR_FAILURE;
 
-  nsIContent *child = content->GetChildAt(aRange->StartOffset());
+  nsCOMPtr<nsIContent> child = content->GetChildAt(aRange->StartOffset());
   if (!child)
     return NS_ERROR_FAILURE;
 
+  // GetCellLayout depends on current frame, we need flush frame to get
+  // nsITableCellLayout
+  nsCOMPtr<nsIPresShell> presShell = mFrameSelection->GetShell();
+  if (presShell) {
+    presShell->FlushPendingNotifications(FlushType::Frames);
+
+    // Since calling FlushPendingNotifications, so check whether disconnected.
+    if (!mFrameSelection || !mFrameSelection->GetShell()) {
+      return NS_ERROR_FAILURE;
+    }
+  }
+
   //Note: This is a non-ref-counted pointer to the frame
   nsITableCellLayout *cellLayout = mFrameSelection->GetCellLayout(child);
-  if (NS_FAILED(result))
-    return result;
   if (!cellLayout)
     return NS_ERROR_FAILURE;
 
   return cellLayout->GetCellIndexes(*aRow, *aCol);
 }
 
 nsresult
 Selection::AddTableCellRange(nsRange* aRange, bool* aDidAddRange,
@@ -2271,16 +2281,19 @@ Selection::AddRangeInternal(nsRange& aRa
   if (aDocument != rangeRoot && (!rangeRoot ||
                                  aDocument != rangeRoot->GetComposedDoc())) {
     // http://w3c.github.io/selection-api/#dom-selection-addrange
     // "...  if the root of the range's boundary points are the document
     // associated with context object. Otherwise, this method must do nothing."
     return;
   }
 
+  // AddTableCellRange might flush frame.
+  RefPtr<Selection> kungFuDeathGrip(this);
+
   // This inserts a table cell range in proper document order
   // and returns NS_OK if range doesn't contain just one table cell
   bool didAddRange;
   int32_t rangeIndex;
   nsresult result = AddTableCellRange(&aRange, &didAddRange, &rangeIndex);
   if (NS_FAILED(result)) {
     aRv.Throw(result);
     return;
--- a/dom/base/test/mochitest.ini
+++ b/dom/base/test/mochitest.ini
@@ -616,16 +616,17 @@ skip-if = toolkit == 'android'
 [test_bug1274806.html]
 [test_bug1281963.html]
 [test_bug1295852.html]
 [test_bug1307730.html]
 [test_bug1308069.html]
 [test_bug1314032.html]
 [test_bug1318303.html]
 [test_bug1375050.html]
+[test_bug1381710.html]
 [test_bug1384658.html]
 skip-if = toolkit == 'android'
 [test_caretPositionFromPoint.html]
 [test_change_policy.html]
 [test_clearTimeoutIntervalNoArg.html]
 [test_constructor-assignment.html]
 [test_constructor.html]
 [test_copyimage.html]
new file mode 100644
--- /dev/null
+++ b/dom/base/test/test_bug1381710.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1381710
+-->
+<head>
+  <title>Test for Mozilla Bug 1381710</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.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=1381710">Mozilla Bug 1381710</a>
+<div id="content">
+  <div id="nonedit"></div>
+  <div id="edit" contenteditable=true></div>
+</div>
+<pre id="test">
+<script type="application/javascript">
+function test(element)
+{
+  let selection = window.getSelection();
+  selection.removeAllRanges();
+  let range = document.createRange();
+
+  element.innerHTML = "<table><tr id=tr><td id=td>A</td><td>B</td><tr></table>";
+  let td = document.getElementById("td");
+  range.selectNode(td);
+  // Don't throw exception
+  selection.addRange(range);
+  is(selection.anchorNode, document.getElementById("tr"),
+     "anchor node should be <TR> element");
+  element.innerHTML = "";
+}
+
+test(document.getElementById("nonedit"));
+test(document.getElementById("edit"));
+</script>
+</pre>
+</body>
+</html>