Tue, 06 Jan 2015 21:39:09 +0100
Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.
michael@0 | 1 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 4 | |
michael@0 | 5 | const C_i = Components.interfaces; |
michael@0 | 6 | |
michael@0 | 7 | const UNORDERED_TYPE = C_i.nsIDOMXPathResult.ANY_UNORDERED_NODE_TYPE; |
michael@0 | 8 | |
michael@0 | 9 | /** |
michael@0 | 10 | * Determine if the data node has only ignorable white-space. |
michael@0 | 11 | * |
michael@0 | 12 | * @return nsIDOMNodeFilter.FILTER_SKIP if it does. |
michael@0 | 13 | * @return nsIDOMNodeFilter.FILTER_ACCEPT otherwise. |
michael@0 | 14 | */ |
michael@0 | 15 | function isWhitespace(aNode) { |
michael@0 | 16 | return ((/\S/).test(aNode.nodeValue)) ? |
michael@0 | 17 | C_i.nsIDOMNodeFilter.FILTER_SKIP : |
michael@0 | 18 | C_i.nsIDOMNodeFilter.FILTER_ACCEPT; |
michael@0 | 19 | } |
michael@0 | 20 | |
michael@0 | 21 | /** |
michael@0 | 22 | * Create a DocumentFragment with cloned children equaling a node's children. |
michael@0 | 23 | * |
michael@0 | 24 | * @param aNode The node to copy from. |
michael@0 | 25 | * |
michael@0 | 26 | * @return DocumentFragment node. |
michael@0 | 27 | */ |
michael@0 | 28 | function getFragment(aNode) { |
michael@0 | 29 | var frag = aNode.ownerDocument.createDocumentFragment(); |
michael@0 | 30 | for (var i = 0; i < aNode.childNodes.length; i++) { |
michael@0 | 31 | frag.appendChild(aNode.childNodes.item(i).cloneNode(true)); |
michael@0 | 32 | } |
michael@0 | 33 | return frag; |
michael@0 | 34 | } |
michael@0 | 35 | |
michael@0 | 36 | // Goodies from head_content.js |
michael@0 | 37 | const serializer = new DOMSerializer(); |
michael@0 | 38 | const parser = new DOMParser(); |
michael@0 | 39 | |
michael@0 | 40 | /** |
michael@0 | 41 | * Dump the contents of a document fragment to the console. |
michael@0 | 42 | * |
michael@0 | 43 | * @param aFragment The fragment to serialize. |
michael@0 | 44 | */ |
michael@0 | 45 | function dumpFragment(aFragment) { |
michael@0 | 46 | dump(serializer.serializeToString(aFragment) + "\n\n"); |
michael@0 | 47 | } |
michael@0 | 48 | |
michael@0 | 49 | /** |
michael@0 | 50 | * Translate an XPath to a DOM node. This method uses a document |
michael@0 | 51 | * fragment as context node. |
michael@0 | 52 | * |
michael@0 | 53 | * @param aContextNode The context node to apply the XPath to. |
michael@0 | 54 | * @param aPath The XPath to use. |
michael@0 | 55 | * |
michael@0 | 56 | * @return nsIDOMNode The target node retrieved from the XPath. |
michael@0 | 57 | */ |
michael@0 | 58 | function evalXPathInDocumentFragment(aContextNode, aPath) { |
michael@0 | 59 | do_check_true(aContextNode instanceof C_i.nsIDOMDocumentFragment); |
michael@0 | 60 | do_check_true(aContextNode.childNodes.length > 0); |
michael@0 | 61 | if (aPath == ".") { |
michael@0 | 62 | return aContextNode; |
michael@0 | 63 | } |
michael@0 | 64 | |
michael@0 | 65 | // Separate the fragment's xpath lookup from the rest. |
michael@0 | 66 | var firstSlash = aPath.indexOf("/"); |
michael@0 | 67 | if (firstSlash == -1) { |
michael@0 | 68 | firstSlash = aPath.length; |
michael@0 | 69 | } |
michael@0 | 70 | var prefix = aPath.substr(0, firstSlash); |
michael@0 | 71 | var realPath = aPath.substr(firstSlash + 1); |
michael@0 | 72 | if (!realPath) { |
michael@0 | 73 | realPath = "."; |
michael@0 | 74 | } |
michael@0 | 75 | |
michael@0 | 76 | // Set up a special node filter to look among the fragment's child nodes. |
michael@0 | 77 | var childIndex = 1; |
michael@0 | 78 | var bracketIndex = prefix.indexOf("["); |
michael@0 | 79 | if (bracketIndex != -1) { |
michael@0 | 80 | childIndex = Number(prefix.substring(bracketIndex + 1, prefix.indexOf("]"))); |
michael@0 | 81 | do_check_true(childIndex > 0); |
michael@0 | 82 | prefix = prefix.substr(0, bracketIndex); |
michael@0 | 83 | } |
michael@0 | 84 | |
michael@0 | 85 | var targetType = C_i.nsIDOMNodeFilter.SHOW_ELEMENT; |
michael@0 | 86 | var targetNodeName = prefix; |
michael@0 | 87 | if (prefix.indexOf("processing-instruction(") == 0) { |
michael@0 | 88 | targetType = C_i.nsIDOMNodeFilter.SHOW_PROCESSING_INSTRUCTION; |
michael@0 | 89 | targetNodeName = prefix.substring(prefix.indexOf("(") + 2, prefix.indexOf(")") - 1); |
michael@0 | 90 | } |
michael@0 | 91 | switch (prefix) { |
michael@0 | 92 | case "text()": |
michael@0 | 93 | targetType = C_i.nsIDOMNodeFilter.SHOW_TEXT | |
michael@0 | 94 | C_i.nsIDOMNodeFilter.SHOW_CDATA_SECTION; |
michael@0 | 95 | targetNodeName = null; |
michael@0 | 96 | break; |
michael@0 | 97 | case "comment()": |
michael@0 | 98 | targetType = C_i.nsIDOMNodeFilter.SHOW_COMMENT; |
michael@0 | 99 | targetNodeName = null; |
michael@0 | 100 | break; |
michael@0 | 101 | case "node()": |
michael@0 | 102 | targetType = C_i.nsIDOMNodeFilter.SHOW_ALL; |
michael@0 | 103 | targetNodeName = null; |
michael@0 | 104 | } |
michael@0 | 105 | |
michael@0 | 106 | var filter = { |
michael@0 | 107 | count: 0, |
michael@0 | 108 | |
michael@0 | 109 | // nsIDOMNodeFilter |
michael@0 | 110 | acceptNode: function acceptNode(aNode) { |
michael@0 | 111 | if (aNode.parentNode != aContextNode) { |
michael@0 | 112 | // Don't bother looking at kids either. |
michael@0 | 113 | return C_i.nsIDOMNodeFilter.FILTER_REJECT; |
michael@0 | 114 | } |
michael@0 | 115 | |
michael@0 | 116 | if (targetNodeName && targetNodeName != aNode.nodeName) { |
michael@0 | 117 | return C_i.nsIDOMNodeFilter.FILTER_SKIP; |
michael@0 | 118 | } |
michael@0 | 119 | |
michael@0 | 120 | this.count++; |
michael@0 | 121 | if (this.count != childIndex) { |
michael@0 | 122 | return C_i.nsIDOMNodeFilter.FILTER_SKIP; |
michael@0 | 123 | } |
michael@0 | 124 | |
michael@0 | 125 | return C_i.nsIDOMNodeFilter.FILTER_ACCEPT; |
michael@0 | 126 | } |
michael@0 | 127 | }; |
michael@0 | 128 | |
michael@0 | 129 | // Look for the node matching the step from the document fragment. |
michael@0 | 130 | var walker = aContextNode.ownerDocument.createTreeWalker( |
michael@0 | 131 | aContextNode, |
michael@0 | 132 | targetType, |
michael@0 | 133 | filter); |
michael@0 | 134 | var targetNode = walker.nextNode(); |
michael@0 | 135 | do_check_neq(targetNode, null); |
michael@0 | 136 | |
michael@0 | 137 | // Apply our remaining xpath to the found node. |
michael@0 | 138 | var expr = aContextNode.ownerDocument.createExpression(realPath, null); |
michael@0 | 139 | var result = expr.evaluate(targetNode, UNORDERED_TYPE, null); |
michael@0 | 140 | do_check_true(result instanceof C_i.nsIDOMXPathResult); |
michael@0 | 141 | return result.singleNodeValue; |
michael@0 | 142 | } |
michael@0 | 143 | |
michael@0 | 144 | /** |
michael@0 | 145 | * Get a DOM range corresponding to the test's source node. |
michael@0 | 146 | * |
michael@0 | 147 | * @param aSourceNode <source/> element with range information. |
michael@0 | 148 | * @param aFragment DocumentFragment generated with getFragment(). |
michael@0 | 149 | * |
michael@0 | 150 | * @return Range object. |
michael@0 | 151 | */ |
michael@0 | 152 | function getRange(aSourceNode, aFragment) { |
michael@0 | 153 | do_check_true(aSourceNode instanceof C_i.nsIDOMElement); |
michael@0 | 154 | do_check_true(aFragment instanceof C_i.nsIDOMDocumentFragment); |
michael@0 | 155 | var doc = aSourceNode.ownerDocument; |
michael@0 | 156 | |
michael@0 | 157 | var containerPath = aSourceNode.getAttribute("startContainer"); |
michael@0 | 158 | var startContainer = evalXPathInDocumentFragment(aFragment, containerPath); |
michael@0 | 159 | var startOffset = Number(aSourceNode.getAttribute("startOffset")); |
michael@0 | 160 | |
michael@0 | 161 | containerPath = aSourceNode.getAttribute("endContainer"); |
michael@0 | 162 | var endContainer = evalXPathInDocumentFragment(aFragment, containerPath); |
michael@0 | 163 | var endOffset = Number(aSourceNode.getAttribute("endOffset")); |
michael@0 | 164 | |
michael@0 | 165 | var range = doc.createRange(); |
michael@0 | 166 | range.setStart(startContainer, startOffset); |
michael@0 | 167 | range.setEnd(endContainer, endOffset); |
michael@0 | 168 | return range; |
michael@0 | 169 | } |
michael@0 | 170 | |
michael@0 | 171 | /** |
michael@0 | 172 | * Get the document for a given path, and clean it up for our tests. |
michael@0 | 173 | * |
michael@0 | 174 | * @param aPath The path to the local document. |
michael@0 | 175 | */ |
michael@0 | 176 | function getParsedDocument(aPath) { |
michael@0 | 177 | var doc = do_parse_document(aPath, "application/xml"); |
michael@0 | 178 | do_check_true(doc.documentElement.localName != "parsererror"); |
michael@0 | 179 | do_check_true(doc instanceof C_i.nsIDOMXPathEvaluator); |
michael@0 | 180 | do_check_true(doc instanceof C_i.nsIDOMDocument); |
michael@0 | 181 | |
michael@0 | 182 | // Clean out whitespace. |
michael@0 | 183 | var walker = doc.createTreeWalker(doc, |
michael@0 | 184 | C_i.nsIDOMNodeFilter.SHOW_TEXT | |
michael@0 | 185 | C_i.nsIDOMNodeFilter.SHOW_CDATA_SECTION, |
michael@0 | 186 | isWhitespace); |
michael@0 | 187 | while (walker.nextNode()) { |
michael@0 | 188 | var parent = walker.currentNode.parentNode; |
michael@0 | 189 | parent.removeChild(walker.currentNode); |
michael@0 | 190 | walker.currentNode = parent; |
michael@0 | 191 | } |
michael@0 | 192 | |
michael@0 | 193 | // Clean out mandatory splits between nodes. |
michael@0 | 194 | var splits = doc.getElementsByTagName("split"); |
michael@0 | 195 | var i; |
michael@0 | 196 | for (i = splits.length - 1; i >= 0; i--) { |
michael@0 | 197 | var node = splits.item(i); |
michael@0 | 198 | node.parentNode.removeChild(node); |
michael@0 | 199 | } |
michael@0 | 200 | splits = null; |
michael@0 | 201 | |
michael@0 | 202 | // Replace empty CDATA sections. |
michael@0 | 203 | var emptyData = doc.getElementsByTagName("empty-cdata"); |
michael@0 | 204 | for (i = emptyData.length - 1; i >= 0; i--) { |
michael@0 | 205 | var node = emptyData.item(i); |
michael@0 | 206 | var cdata = doc.createCDATASection(""); |
michael@0 | 207 | node.parentNode.replaceChild(cdata, node); |
michael@0 | 208 | } |
michael@0 | 209 | |
michael@0 | 210 | return doc; |
michael@0 | 211 | } |
michael@0 | 212 | |
michael@0 | 213 | /** |
michael@0 | 214 | * Run the extraction tests. |
michael@0 | 215 | */ |
michael@0 | 216 | function run_extract_test() { |
michael@0 | 217 | var filePath = "test_delete_range.xml"; |
michael@0 | 218 | var doc = getParsedDocument(filePath); |
michael@0 | 219 | var tests = doc.getElementsByTagName("test"); |
michael@0 | 220 | |
michael@0 | 221 | // Run our deletion, extraction tests. |
michael@0 | 222 | for (var i = 0; i < tests.length; i++) { |
michael@0 | 223 | dump("Configuring for test " + i + "\n"); |
michael@0 | 224 | var currentTest = tests.item(i); |
michael@0 | 225 | |
michael@0 | 226 | // Validate the test is properly formatted for what this harness expects. |
michael@0 | 227 | var baseSource = currentTest.firstChild; |
michael@0 | 228 | do_check_eq(baseSource.nodeName, "source"); |
michael@0 | 229 | var baseResult = baseSource.nextSibling; |
michael@0 | 230 | do_check_eq(baseResult.nodeName, "result"); |
michael@0 | 231 | var baseExtract = baseResult.nextSibling; |
michael@0 | 232 | do_check_eq(baseExtract.nodeName, "extract"); |
michael@0 | 233 | do_check_eq(baseExtract.nextSibling, null); |
michael@0 | 234 | |
michael@0 | 235 | /* We do all our tests on DOM document fragments, derived from the test |
michael@0 | 236 | element's children. This lets us rip the various fragments to shreds, |
michael@0 | 237 | while preserving the original elements so we can make more copies of |
michael@0 | 238 | them. |
michael@0 | 239 | |
michael@0 | 240 | After the range's extraction or deletion is done, we use |
michael@0 | 241 | nsIDOMNode.isEqualNode() between the altered source fragment and the |
michael@0 | 242 | result fragment. We also run isEqualNode() between the extracted |
michael@0 | 243 | fragment and the fragment from the baseExtract node. If they are not |
michael@0 | 244 | equal, we have failed a test. |
michael@0 | 245 | |
michael@0 | 246 | We also have to ensure the original nodes on the end points of the |
michael@0 | 247 | range are still in the source fragment. This is bug 332148. The nodes |
michael@0 | 248 | may not be replaced with equal but separate nodes. The range extraction |
michael@0 | 249 | may alter these nodes - in the case of text containers, they will - but |
michael@0 | 250 | the nodes must stay there, to preserve references such as user data, |
michael@0 | 251 | event listeners, etc. |
michael@0 | 252 | |
michael@0 | 253 | First, an extraction test. |
michael@0 | 254 | */ |
michael@0 | 255 | |
michael@0 | 256 | var resultFrag = getFragment(baseResult); |
michael@0 | 257 | var extractFrag = getFragment(baseExtract); |
michael@0 | 258 | |
michael@0 | 259 | dump("Extract contents test " + i + "\n\n"); |
michael@0 | 260 | var baseFrag = getFragment(baseSource); |
michael@0 | 261 | var baseRange = getRange(baseSource, baseFrag); |
michael@0 | 262 | var startContainer = baseRange.startContainer; |
michael@0 | 263 | var endContainer = baseRange.endContainer; |
michael@0 | 264 | |
michael@0 | 265 | var cutFragment = baseRange.extractContents(); |
michael@0 | 266 | dump("cutFragment: " + cutFragment + "\n"); |
michael@0 | 267 | if (cutFragment) { |
michael@0 | 268 | do_check_true(extractFrag.isEqualNode(cutFragment)); |
michael@0 | 269 | } else { |
michael@0 | 270 | do_check_eq(extractFrag.firstChild, null); |
michael@0 | 271 | } |
michael@0 | 272 | do_check_true(baseFrag.isEqualNode(resultFrag)); |
michael@0 | 273 | |
michael@0 | 274 | dump("Ensure the original nodes weren't extracted - test " + i + "\n\n"); |
michael@0 | 275 | var walker = doc.createTreeWalker(baseFrag, |
michael@0 | 276 | C_i.nsIDOMNodeFilter.SHOW_ALL, |
michael@0 | 277 | null); |
michael@0 | 278 | var foundStart = false; |
michael@0 | 279 | var foundEnd = false; |
michael@0 | 280 | do { |
michael@0 | 281 | if (walker.currentNode == startContainer) { |
michael@0 | 282 | foundStart = true; |
michael@0 | 283 | } |
michael@0 | 284 | |
michael@0 | 285 | if (walker.currentNode == endContainer) { |
michael@0 | 286 | // An end container node should not come before the start container node. |
michael@0 | 287 | do_check_true(foundStart); |
michael@0 | 288 | foundEnd = true; |
michael@0 | 289 | break; |
michael@0 | 290 | } |
michael@0 | 291 | } while (walker.nextNode()) |
michael@0 | 292 | do_check_true(foundEnd); |
michael@0 | 293 | |
michael@0 | 294 | /* Now, we reset our test for the deleteContents case. This one differs |
michael@0 | 295 | from the extractContents case only in that there is no extracted document |
michael@0 | 296 | fragment to compare against. So we merely compare the starting fragment, |
michael@0 | 297 | minus the extracted content, against the result fragment. |
michael@0 | 298 | */ |
michael@0 | 299 | dump("Delete contents test " + i + "\n\n"); |
michael@0 | 300 | baseFrag = getFragment(baseSource); |
michael@0 | 301 | baseRange = getRange(baseSource, baseFrag); |
michael@0 | 302 | var startContainer = baseRange.startContainer; |
michael@0 | 303 | var endContainer = baseRange.endContainer; |
michael@0 | 304 | baseRange.deleteContents(); |
michael@0 | 305 | do_check_true(baseFrag.isEqualNode(resultFrag)); |
michael@0 | 306 | |
michael@0 | 307 | dump("Ensure the original nodes weren't deleted - test " + i + "\n\n"); |
michael@0 | 308 | walker = doc.createTreeWalker(baseFrag, |
michael@0 | 309 | C_i.nsIDOMNodeFilter.SHOW_ALL, |
michael@0 | 310 | null); |
michael@0 | 311 | foundStart = false; |
michael@0 | 312 | foundEnd = false; |
michael@0 | 313 | do { |
michael@0 | 314 | if (walker.currentNode == startContainer) { |
michael@0 | 315 | foundStart = true; |
michael@0 | 316 | } |
michael@0 | 317 | |
michael@0 | 318 | if (walker.currentNode == endContainer) { |
michael@0 | 319 | // An end container node should not come before the start container node. |
michael@0 | 320 | do_check_true(foundStart); |
michael@0 | 321 | foundEnd = true; |
michael@0 | 322 | break; |
michael@0 | 323 | } |
michael@0 | 324 | } while (walker.nextNode()) |
michael@0 | 325 | do_check_true(foundEnd); |
michael@0 | 326 | |
michael@0 | 327 | // Clean up after ourselves. |
michael@0 | 328 | walker = null; |
michael@0 | 329 | } |
michael@0 | 330 | } |
michael@0 | 331 | |
michael@0 | 332 | /** |
michael@0 | 333 | * Miscellaneous tests not covered above. |
michael@0 | 334 | */ |
michael@0 | 335 | function run_miscellaneous_tests() { |
michael@0 | 336 | var filePath = "test_delete_range.xml"; |
michael@0 | 337 | var doc = getParsedDocument(filePath); |
michael@0 | 338 | var tests = doc.getElementsByTagName("test"); |
michael@0 | 339 | |
michael@0 | 340 | // Let's try some invalid inputs to our DOM range and see what happens. |
michael@0 | 341 | var currentTest = tests.item(0); |
michael@0 | 342 | var baseSource = currentTest.firstChild; |
michael@0 | 343 | var baseResult = baseSource.nextSibling; |
michael@0 | 344 | var baseExtract = baseResult.nextSibling; |
michael@0 | 345 | |
michael@0 | 346 | var baseFrag = getFragment(baseSource); |
michael@0 | 347 | |
michael@0 | 348 | var baseRange = getRange(baseSource, baseFrag); |
michael@0 | 349 | var startContainer = baseRange.startContainer; |
michael@0 | 350 | var endContainer = baseRange.endContainer; |
michael@0 | 351 | var startOffset = baseRange.startOffset; |
michael@0 | 352 | var endOffset = baseRange.endOffset; |
michael@0 | 353 | |
michael@0 | 354 | // Text range manipulation. |
michael@0 | 355 | if ((endOffset > startOffset) && |
michael@0 | 356 | (startContainer == endContainer) && |
michael@0 | 357 | (startContainer instanceof C_i.nsIDOMText)) { |
michael@0 | 358 | // Invalid start node |
michael@0 | 359 | try { |
michael@0 | 360 | baseRange.setStart(null, 0); |
michael@0 | 361 | do_throw("Should have thrown NOT_OBJECT_ERR!"); |
michael@0 | 362 | } catch (e) { |
michael@0 | 363 | do_check_eq(e.constructor.name, "TypeError"); |
michael@0 | 364 | } |
michael@0 | 365 | |
michael@0 | 366 | // Invalid start node |
michael@0 | 367 | try { |
michael@0 | 368 | baseRange.setStart({}, 0); |
michael@0 | 369 | do_throw("Should have thrown SecurityError!"); |
michael@0 | 370 | } catch (e) { |
michael@0 | 371 | do_check_eq(e.constructor.name, "TypeError"); |
michael@0 | 372 | } |
michael@0 | 373 | |
michael@0 | 374 | // Invalid index |
michael@0 | 375 | try { |
michael@0 | 376 | baseRange.setStart(startContainer, -1); |
michael@0 | 377 | do_throw("Should have thrown IndexSizeError!"); |
michael@0 | 378 | } catch (e) { |
michael@0 | 379 | do_check_eq(e.name, "IndexSizeError"); |
michael@0 | 380 | } |
michael@0 | 381 | |
michael@0 | 382 | // Invalid index |
michael@0 | 383 | var newOffset = startContainer instanceof C_i.nsIDOMText ? |
michael@0 | 384 | startContainer.nodeValue.length + 1 : |
michael@0 | 385 | startContainer.childNodes.length + 1; |
michael@0 | 386 | try { |
michael@0 | 387 | baseRange.setStart(startContainer, newOffset); |
michael@0 | 388 | do_throw("Should have thrown IndexSizeError!"); |
michael@0 | 389 | } catch (e) { |
michael@0 | 390 | do_check_eq(e.name, "IndexSizeError"); |
michael@0 | 391 | } |
michael@0 | 392 | |
michael@0 | 393 | newOffset--; |
michael@0 | 394 | // Valid index |
michael@0 | 395 | baseRange.setStart(startContainer, newOffset); |
michael@0 | 396 | do_check_eq(baseRange.startContainer, baseRange.endContainer); |
michael@0 | 397 | do_check_eq(baseRange.startOffset, newOffset); |
michael@0 | 398 | do_check_true(baseRange.collapsed); |
michael@0 | 399 | |
michael@0 | 400 | // Valid index |
michael@0 | 401 | baseRange.setEnd(startContainer, 0); |
michael@0 | 402 | do_check_eq(baseRange.startContainer, baseRange.endContainer); |
michael@0 | 403 | do_check_eq(baseRange.startOffset, 0); |
michael@0 | 404 | do_check_true(baseRange.collapsed); |
michael@0 | 405 | } else { |
michael@0 | 406 | do_throw("The first test should be a text-only range test. Test is invalid.") |
michael@0 | 407 | } |
michael@0 | 408 | |
michael@0 | 409 | /* See what happens when a range has a startContainer in one fragment, and an |
michael@0 | 410 | endContainer in another. According to the DOM spec, section 2.4, the range |
michael@0 | 411 | should collapse to the new container and offset. */ |
michael@0 | 412 | baseRange = getRange(baseSource, baseFrag); |
michael@0 | 413 | startContainer = baseRange.startContainer; |
michael@0 | 414 | var startOffset = baseRange.startOffset; |
michael@0 | 415 | endContainer = baseRange.endContainer; |
michael@0 | 416 | var endOffset = baseRange.endOffset; |
michael@0 | 417 | |
michael@0 | 418 | dump("External fragment test\n\n"); |
michael@0 | 419 | |
michael@0 | 420 | var externalTest = tests.item(1); |
michael@0 | 421 | var externalSource = externalTest.firstChild; |
michael@0 | 422 | var externalFrag = getFragment(externalSource); |
michael@0 | 423 | var externalRange = getRange(externalSource, externalFrag); |
michael@0 | 424 | |
michael@0 | 425 | baseRange.setEnd(externalRange.endContainer, 0); |
michael@0 | 426 | do_check_eq(baseRange.startContainer, externalRange.endContainer); |
michael@0 | 427 | do_check_eq(baseRange.startOffset, 0); |
michael@0 | 428 | do_check_true(baseRange.collapsed); |
michael@0 | 429 | |
michael@0 | 430 | /* |
michael@0 | 431 | // XXX ajvincent if rv == WRONG_DOCUMENT_ERR, return false? |
michael@0 | 432 | do_check_false(baseRange.isPointInRange(startContainer, startOffset)); |
michael@0 | 433 | do_check_false(baseRange.isPointInRange(startContainer, startOffset + 1)); |
michael@0 | 434 | do_check_false(baseRange.isPointInRange(endContainer, endOffset)); |
michael@0 | 435 | */ |
michael@0 | 436 | |
michael@0 | 437 | // Requested by smaug: A range involving a comment as a document child. |
michael@0 | 438 | doc = parser.parseFromString("<!-- foo --><foo/>", "application/xml"); |
michael@0 | 439 | do_check_true(doc instanceof C_i.nsIDOMDocument); |
michael@0 | 440 | do_check_eq(doc.childNodes.length, 2); |
michael@0 | 441 | baseRange = doc.createRange(); |
michael@0 | 442 | baseRange.setStart(doc.firstChild, 1); |
michael@0 | 443 | baseRange.setEnd(doc.firstChild, 2); |
michael@0 | 444 | var frag = baseRange.extractContents(); |
michael@0 | 445 | do_check_eq(frag.childNodes.length, 1); |
michael@0 | 446 | do_check_true(frag.firstChild instanceof C_i.nsIDOMComment); |
michael@0 | 447 | do_check_eq(frag.firstChild.nodeValue, "f"); |
michael@0 | 448 | |
michael@0 | 449 | /* smaug also requested attribute tests. Sadly, those are not yet supported |
michael@0 | 450 | in ranges - see https://bugzilla.mozilla.org/show_bug.cgi?id=302775. |
michael@0 | 451 | */ |
michael@0 | 452 | } |
michael@0 | 453 | |
michael@0 | 454 | function run_test() { |
michael@0 | 455 | run_extract_test(); |
michael@0 | 456 | run_miscellaneous_tests(); |
michael@0 | 457 | } |