diff --git a/dom/base/nsRange.cpp b/dom/base/nsRange.cpp index c1f5ff472a41..c499ad76a859 100644 --- a/dom/base/nsRange.cpp +++ b/dom/base/nsRange.cpp @@ -3154,6 +3154,12 @@ nsRange::Constructor(const GlobalObject& aGlobal, return window->GetDoc()->CreateRange(aRv); } +static bool ExcludeIfNextToNonSelectable(nsIContent* aContent) +{ + return aContent->IsNodeOfType(nsINode::eTEXT) && + aContent->HasFlag(NS_CREATE_FRAME_IF_NON_WHITESPACE); +} + void nsRange::ExcludeNonSelectableNodes(nsTArray>* aOutRanges) { @@ -3172,6 +3178,10 @@ nsRange::ExcludeNonSelectableNodes(nsTArray>* aOutRanges) bool added = false; bool seenSelectable = false; + // |firstNonSelectableContent| is the first node in a consecutive sequence + // of non-IsSelectable nodes. When we find a selectable node after such + // a sequence we'll end the last nsRange, create a new one and restart + // the outer loop. nsIContent* firstNonSelectableContent = nullptr; while (true) { ErrorResult err; @@ -3181,12 +3191,19 @@ nsRange::ExcludeNonSelectableNodes(nsTArray>* aOutRanges) nsIContent* content = node && node->IsContent() ? node->AsContent() : nullptr; if (content) { - nsIFrame* frame = content->GetPrimaryFrame(); - for (nsIContent* p = content; !frame && (p = p->GetParent()); ) { - frame = p->GetPrimaryFrame(); + if (firstNonSelectableContent && ExcludeIfNextToNonSelectable(content)) { + // Ignorable whitespace next to a sequence of non-selectable nodes + // counts as non-selectable (bug 1216001). + selectable = false; } - if (frame) { - frame->IsSelectable(&selectable, nullptr); + if (selectable) { + nsIFrame* frame = content->GetPrimaryFrame(); + for (nsIContent* p = content; !frame && (p = p->GetParent()); ) { + frame = p->GetPrimaryFrame(); + } + if (frame) { + frame->IsSelectable(&selectable, nullptr); + } } } diff --git a/dom/base/test/test_user_select.html b/dom/base/test/test_user_select.html index 274e523a5cfd..6cac439d065b 100644 --- a/dom/base/test/test_user_select.html +++ b/dom/base/test/test_user_select.html @@ -12,7 +12,7 @@ src: url("Ahem.ttf"); } body { font-family: Ahem; font-size: 20px; } -s { -moz-user-select: none; } +s, .non-selectable { -moz-user-select: none; } n { display: none; } a { position:absolute; bottom: 0; right:0; } .text { -moz-user-select: text; } @@ -34,6 +34,16 @@ a { position:absolute; bottom: 0; right:0; }
aaaaaaabbbbbbbbccccccc
aaaaaaabbbbbbbbccccccc
aaaaaaabbbbddccccdddddddeeee
+
aaaa +
x
+
x
+
x
+bbbb
+
aaaa +
x
+
x
+
x
+bbbb
@@ -100,9 +110,11 @@ function test() is(NL(r.toString()), text, e.id + ": range["+index+"].toString()") } - function node(e, index) + function node(e, arg) { - return index == -1 ? e : e.childNodes[index]; + if (typeof arg == "number") + return arg == -1 ? e : e.childNodes[arg]; + return arg; } function checkRangeCount(n, e) @@ -258,6 +270,22 @@ function test() checkRanges([[0,1,-1,1]], e); doneTest(e); + clear(); + e = document.getElementById('testF'); + synthesizeMouse(e, 1, 1, {}); + synthesizeMouse(e, 400, 100, { shiftKey: true }); + checkText("aaaa bbbb", e); + checkRanges([[0,0,-1,1],[6,0,6,5]], e); + doneTest(e); + + clear(); + e = document.getElementById('testG'); + synthesizeMouse(e, 1, 1, {}); + synthesizeMouse(e, 400, 180, { shiftKey: true }); + checkText("aaaa bbbb", e); // XXX this doesn't seem right - bug 1247799 + checkRanges([[0,0,-1,1],[2,0,-1,3],[4,0,-1,5],[6,0,6,5]], e); + doneTest(e); + // ====================================================== // ==================== Script tests ==================== // ======================================================