From: <rb...@us...> - 2017-09-28 05:39:40
|
Revision: 14848 http://sourceforge.net/p/htmlunit/code/14848 Author: rbri Date: 2017-09-28 05:39:37 +0000 (Thu, 28 Sep 2017) Log Message: ----------- fix for a strange side effect in Range.getClientRects() and Range.getBoundingClientRect(). Both calls have removed all nodes inside the range from the document. Modified Paths: -------------- trunk/htmlunit/src/changes/changes.xml trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/html/impl/SimpleRange.java trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/javascript/host/dom/Range.java trunk/htmlunit/src/test/java/com/gargoylesoftware/htmlunit/javascript/host/dom/RangeTest.java Modified: trunk/htmlunit/src/changes/changes.xml =================================================================== --- trunk/htmlunit/src/changes/changes.xml 2017-09-22 17:37:10 UTC (rev 14847) +++ trunk/htmlunit/src/changes/changes.xml 2017-09-28 05:39:37 UTC (rev 14848) @@ -9,6 +9,10 @@ <body> <release version="2.28" date="???" description="Bugfixes, Chrome 61"> <action type="fix" dev="rbri"> + JavaScript: fix for a strange side effect in Range.getClientRects() and Range.getBoundingClientRect(). + Both calls have removed all nodes inside the range from the document. + </action> + <action type="fix" dev="rbri"> JavaScript: fix handling of negative buffer sizes for the ArrayBuffer ctor. </action> <action type="add" dev="rbri"> Modified: trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/html/impl/SimpleRange.java =================================================================== --- trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/html/impl/SimpleRange.java 2017-09-22 17:37:10 UTC (rev 14847) +++ trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/html/impl/SimpleRange.java 2017-09-28 05:39:37 UTC (rev 14848) @@ -15,7 +15,9 @@ package com.gargoylesoftware.htmlunit.html.impl; import java.io.Serializable; +import java.util.ArrayList; import java.util.Iterator; +import java.util.List; import org.apache.commons.lang3.builder.EqualsBuilder; import org.apache.commons.lang3.builder.HashCodeBuilder; @@ -587,4 +589,66 @@ private static int getMaxOffset(final Node node) { return isOffsetChars(node) ? getText(node).length() : node.getChildNodes().getLength(); } + + /** + * @return a list with all nodes contained in this range + */ + public List<DomNode> containedNodes() { + final List<DomNode> nodes = new ArrayList<>(); + final DomNode ancestor = (DomNode) getCommonAncestorContainer(); + if (ancestor == null) { + return nodes; + } + + final DomNode start; + final DomNode end; + if (isOffsetChars(startContainer_)) { + start = (DomNode) startContainer_; + String text = getText(start); + if (startOffset_ > -1 && startOffset_ < text.length()) { + text = text.substring(0, startOffset_); + } + setText(start, text); + } + else if (startContainer_.getChildNodes().getLength() > startOffset_) { + start = (DomNode) startContainer_.getChildNodes().item(startOffset_); + } + else { + start = (DomNode) startContainer_.getNextSibling(); + } + if (isOffsetChars(endContainer_)) { + end = (DomNode) endContainer_; + String text = getText(end); + if (endOffset_ > -1 && endOffset_ < text.length()) { + text = text.substring(endOffset_); + } + setText(end, text); + } + else if (endContainer_.getChildNodes().getLength() > endOffset_) { + end = (DomNode) endContainer_.getChildNodes().item(endOffset_); + } + else { + end = (DomNode) endContainer_.getNextSibling(); + } + + boolean foundStart = false; + boolean started = false; + final Iterator<DomNode> i = ancestor.getDescendants().iterator(); + while (i.hasNext()) { + final DomNode n = i.next(); + if (n == end) { + break; + } + if (n == start) { + foundStart = true; + } + if (foundStart && (n != start || !isOffsetChars(startContainer_))) { + started = true; + } + if (started && !n.isAncestorOf(end)) { + nodes.add(n); + } + } + return nodes; + } } Modified: trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/javascript/host/dom/Range.java =================================================================== --- trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/javascript/host/dom/Range.java 2017-09-22 17:37:10 UTC (rev 14847) +++ trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/javascript/host/dom/Range.java 2017-09-28 05:39:37 UTC (rev 14848) @@ -497,8 +497,7 @@ rectList.setPrototype(getPrototype(rectList.getClass())); // simple impl for now - final DomDocumentFragment fragment = toW3C().extractContents(); - for (DomNode node : fragment.getDescendants()) { + for (DomNode node : toW3C().containedNodes()) { final ScriptableObject scriptable = node.getScriptableObject(); if (scriptable instanceof HTMLElement) { final ClientRect rect = new ClientRect(0, 0, 1, 1); @@ -523,8 +522,7 @@ rect.setPrototype(getPrototype(rect.getClass())); // simple impl for now - final DomDocumentFragment fragment = toW3C().extractContents(); - for (DomNode node : fragment.getDescendants()) { + for (DomNode node : toW3C().containedNodes()) { final ScriptableObject scriptable = node.getScriptableObject(); if (scriptable instanceof HTMLElement) { final ClientRect childRect = ((HTMLElement) scriptable).getBoundingClientRect(); Modified: trunk/htmlunit/src/test/java/com/gargoylesoftware/htmlunit/javascript/host/dom/RangeTest.java =================================================================== --- trunk/htmlunit/src/test/java/com/gargoylesoftware/htmlunit/javascript/host/dom/RangeTest.java 2017-09-22 17:37:10 UTC (rev 14847) +++ trunk/htmlunit/src/test/java/com/gargoylesoftware/htmlunit/javascript/host/dom/RangeTest.java 2017-09-28 05:39:37 UTC (rev 14848) @@ -375,4 +375,62 @@ + "</script></body></html>"; loadPageWithAlerts2(html); } + + /** + * Test for a regression, getBoundingClientRect has detached + * all elements of the range from the document. + * @throws Exception if the test fails + */ + @Test + @Alerts("[object HTMLBodyElement]") + public void getBoundingClientRectDoesNotChangeTheParent() throws Exception { + final String html + = "<html><head><title>foo</title><script>\n" + + "function doTest() {\n" + + " var range = document.createRange();\n" + + + " var elem = document.createElement('boundtest');\n" + + " document.body.appendChild(elem);\n" + + + " range.selectNode(elem);\n" + + " range.getBoundingClientRect();\n" + + + " alert(elem.parentNode);\n" + + "}\n" + + "</script>\n" + + "</head>\n" + + "<body onload='doTest()'>\n" + + "</body></html>"; + + loadPageWithAlerts2(html); + } + + /** + * Test for a regression, getClientRects has detached + * all elements of the range from the document. + * @throws Exception if the test fails + */ + @Test + @Alerts("[object HTMLBodyElement]") + public void getClientRectsDoesNotChangeTheParent() throws Exception { + final String html + = "<html><head><title>foo</title><script>\n" + + "function doTest() {\n" + + " var range = document.createRange();\n" + + + " var elem = document.createElement('boundtest');\n" + + " document.body.appendChild(elem);\n" + + + " range.selectNode(elem);\n" + + " range.getClientRects();\n" + + + " alert(elem.parentNode);\n" + + "}\n" + + "</script>\n" + + "</head>\n" + + "<body onload='doTest()'>\n" + + "</body></html>"; + + loadPageWithAlerts2(html); + } } |