Changeset 239190 in webkit
- Timestamp:
- Dec 13, 2018 5:45:24 PM (5 years ago)
- Location:
- trunk
- Files:
-
- 21 added
- 7 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r239189 r239190 1 2018-12-13 Ryosuke Niwa <rniwa@webkit.org> 2 3 Make HTMLConverter work across shadow boundaries 4 https://bugs.webkit.org/show_bug.cgi?id=192640 5 6 Reviewed by Wenson Hsieh. 7 8 Added tests for generating attributed string out across shadow boundaries based on the tests 9 of respective names in editing/pasteboard. 10 11 * editing/mac/attributed-string/attributed-string-across-shadow-boundaries-1-expected.txt: Added. 12 * editing/mac/attributed-string/attributed-string-across-shadow-boundaries-1.html: Added. 13 * editing/mac/attributed-string/attributed-string-across-shadow-boundaries-2-expected.txt: Added. 14 * editing/mac/attributed-string/attributed-string-across-shadow-boundaries-2.html: Added. 15 * editing/mac/attributed-string/attributed-string-across-shadow-boundaries-3-expected.txt: Added. 16 * editing/mac/attributed-string/attributed-string-across-shadow-boundaries-3.html: Added. 17 * editing/mac/attributed-string/attributed-string-across-shadow-boundaries-4-expected.txt: Added. 18 * editing/mac/attributed-string/attributed-string-across-shadow-boundaries-4.html: Added. 19 * editing/mac/attributed-string/attributed-string-across-shadow-boundaries-5-expected.txt: Added. 20 * editing/mac/attributed-string/attributed-string-across-shadow-boundaries-5.html: Added. 21 * editing/mac/attributed-string/attributed-string-across-shadow-boundaries-with-style-1-expected.txt: Added. 22 * editing/mac/attributed-string/attributed-string-across-shadow-boundaries-with-style-1.html: Added. 23 * editing/mac/attributed-string/attributed-string-across-shadow-boundaries-with-style-2-expected.txt: Added. 24 * editing/mac/attributed-string/attributed-string-across-shadow-boundaries-with-style-2.html: Added. 25 * editing/mac/attributed-string/resources/dump-attributed-string.js: 26 (window.dumpAttributedString): Now takes start and end containers and offsets. 27 (serializeSubtreeWithShadow): Added. This function serializes the content of shadow roots along with 28 start and end markers. 29 (serializeSubtreeWithShadow.serializeCharacterData): Added. 30 (serializeSubtreeWithShadow.serializeNode): Added. 31 (serializeSubtreeWithShadow.serializeChildNodes): Added. 32 (serializeSubtreeWithShadow.serializeShadowRootAndChildNodes): Added. 33 (dumpAttributedString): Deleted. 34 * platform/mac-sierra/editing/mac/attributed-string/attributed-string-across-shadow-boundaries-1-expected.txt: Added. 35 * platform/mac-sierra/editing/mac/attributed-string/attributed-string-across-shadow-boundaries-2-expected.txt: Added. 36 * platform/mac-sierra/editing/mac/attributed-string/attributed-string-across-shadow-boundaries-3-expected.txt: Added. 37 * platform/mac-sierra/editing/mac/attributed-string/attributed-string-across-shadow-boundaries-4-expected.txt: Added. 38 * platform/mac-sierra/editing/mac/attributed-string/attributed-string-across-shadow-boundaries-5-expected.txt: Added. 39 * platform/mac-sierra/editing/mac/attributed-string/attributed-string-across-shadow-boundaries-with-style-1-expected.txt: Added. 40 * platform/mac-sierra/editing/mac/attributed-string/attributed-string-across-shadow-boundaries-with-style-2-expected.txt: Added. 41 1 42 2018-12-13 Youenn Fablet <youenn@apple.com> 2 43 -
trunk/LayoutTests/editing/mac/attributed-string/resources/dump-attributed-string.js
r239149 r239190 5 5 testRunner.dumpAsText(); 6 6 7 function dumpAttributedString(container) {7 window.dumpAttributedString = function dumpAttributedString(root = document.body, startContainer, startOffset, endContainer, endOffset) { 8 8 shouldAutoDump = false; 9 9 10 var body = document.body; 11 if (!container) 12 container = body; 10 const markup = serializeSubtreeWithShadow(root, startContainer, startOffset, endContainer, endOffset).trim(); 13 11 14 var range = document.createRange(); 15 range.selectNodeContents(container); 12 if (!startContainer) 13 startContainer = root; 14 if (startOffset == undefined) 15 startOffset = 0; 16 if (!endContainer) 17 endContainer = root; 18 if (endOffset == undefined) 19 endOffset = endContainer.childNodes.length; 16 20 17 varpre = document.createElement('pre');18 var result = serializeAttributedString(textInputController.legacyAttributedString(container, 0, container, container.childNodes.length));19 pre.textContent = 'Input:\n' + container.innerHTML.trim()+ '\n\nOutput:\n' + result;21 const pre = document.createElement('pre'); 22 const result = serializeAttributedString(textInputController.legacyAttributedString(startContainer, startOffset, endContainer, endOffset)); 23 pre.textContent = 'Input:\n' + markup + '\n\nOutput:\n' + result; 20 24 21 body.innerHTML = ''; 22 body.appendChild(pre); 25 document.body.innerHTML = ''; 26 document.body.appendChild(pre); 27 } 28 29 function serializeSubtreeWithShadow(parent, startContainer, startOffset, endContainer, endOffset) { 30 function serializeCharacterData(node) { 31 let data = node.data; 32 let result = data; 33 if (node == startContainer && node == endContainer) { 34 result = data.substring(0, startOffset); 35 result += '<#start>'; 36 result = data.substring(startOffset, endOffset); 37 result += '<#end>'; 38 result += data.substring(endOffset); 39 } else if (node == startContainer) { 40 result = data.substring(0, startOffset); 41 result += '<#start>'; 42 result += data.substring(startOffset); 43 } else if (node == endContainer) { 44 result = data.substring(0, endOffset); 45 result += '<#end>'; 46 result += data.substring(endOffset); 47 } 48 return result; 49 } 50 51 function serializeNode(node) { 52 if (node.nodeType == Node.TEXT_NODE) 53 return serializeCharacterData(node); 54 if (node.nodeType == Node.COMMENT_NODE) 55 return '<!--' + node.nodeValue + '-->'; 56 if (node.nodeType == Node.CDATA_SECTION_NODE) 57 return '<!--[CDATA[' + node.nodeValue + '-->'; 58 59 const elementTags = node.cloneNode(false).outerHTML; 60 const endTagIndex = elementTags.lastIndexOf('</'); 61 const startTag = endTagIndex >= 0 ? elementTags.substring(0, endTagIndex) : elementTags; 62 const endTag = endTagIndex >= 0 ? elementTags.substring(endTagIndex) : ''; 63 return startTag + serializeShadowRootAndChildNodes(node) + endTag; 64 } 65 66 function serializeChildNodes(node) { 67 let result = ''; 68 for (let i = 0; i < node.childNodes.length; i++) { 69 if (node == startContainer && i == startOffset) 70 result += '<#start>'; 71 result += serializeNode(node.childNodes[i]); 72 if (node == endContainer && i + 1 == endOffset) 73 result += '<#end>'; 74 } 75 return result; 76 } 77 78 function serializeShadowRootAndChildNodes(node) { 79 const shadowRoot = node.nodeType == Node.ELEMENT_NODE ? internals.shadowRoot(node) : null; 80 if (!shadowRoot) 81 return serializeChildNodes(node); 82 return `<#shadow-start>${serializeChildNodes(shadowRoot)}<#shadow-end>${serializeChildNodes(node)}`; 83 } 84 85 return serializeShadowRootAndChildNodes(parent); 23 86 } 24 87 -
trunk/Source/WebCore/ChangeLog
r239189 r239190 1 2018-12-13 Ryosuke Niwa <rniwa@webkit.org> 2 3 Make HTMLConverter work across shadow boundaries 4 https://bugs.webkit.org/show_bug.cgi?id=192640 5 6 Reviewed by Wenson Hsieh. 7 8 Made HTMLConverter work with shadow boundaries by replacing the various tree traversal functions. 9 10 Tests: editing/mac/attributed-string/attributed-string-across-shadow-boundaries-1.html 11 editing/mac/attributed-string/attributed-string-across-shadow-boundaries-2.html 12 editing/mac/attributed-string/attributed-string-across-shadow-boundaries-3.html 13 editing/mac/attributed-string/attributed-string-across-shadow-boundaries-4.html 14 editing/mac/attributed-string/attributed-string-across-shadow-boundaries-5.html 15 editing/mac/attributed-string/attributed-string-across-shadow-boundaries-with-style-1.html 16 editing/mac/attributed-string/attributed-string-across-shadow-boundaries-with-style-2.html 17 editing/mac/attributed-string/attributed-string-across-shadow-boundaries-with-style-3.html 18 19 * dom/Position.cpp: 20 (WebCore::commonShadowIncludingAncestor): Moved from markup.cpp to be shared between HTMLConverter 21 and serializePreservingVisualAppearanceInternal. 22 * dom/Position.h: 23 * editing/cocoa/HTMLConverter.mm: 24 (HTMLConverter::convert): 25 (HTMLConverterCaches::propertyValueForNode): 26 (HTMLConverterCaches::floatPropertyValueForNode): 27 (HTMLConverter::_blockLevelElementForNode): 28 (HTMLConverterCaches::colorPropertyValueForNode): 29 (HTMLConverter::aggregatedAttributesForAncestors): 30 (HTMLConverter::aggregatedAttributesForElementAndItsAncestors): 31 (HTMLConverter::_processElement): 32 (HTMLConverter::_traverseNode): 33 (HTMLConverter::_traverseFooterNode): 34 (HTMLConverterCaches::cacheAncestorsOfStartToBeConverted): 35 (WebCore::attributedStringFromSelection): 36 * editing/markup.cpp: 37 (WebCore::commonShadowIncludingAncestor): Moved to Position.cpp. 38 1 39 2018-12-13 Youenn Fablet <youenn@apple.com> 2 40 -
trunk/Source/WebCore/dom/Position.cpp
r236649 r239190 1602 1602 } 1603 1603 1604 RefPtr<Node> commonShadowIncludingAncestor(const Position& a, const Position& b) 1605 { 1606 auto* commonScope = commonTreeScope(a.containerNode(), b.containerNode()); 1607 if (!commonScope) 1608 return nullptr; 1609 auto* nodeA = commonScope->ancestorNodeInThisScope(a.containerNode()); 1610 ASSERT(nodeA); 1611 auto* nodeB = commonScope->ancestorNodeInThisScope(b.containerNode()); 1612 ASSERT(nodeB); 1613 return Range::commonAncestorContainer(nodeA, nodeB); 1614 } 1615 1604 1616 } // namespace WebCore 1605 1617 -
trunk/Source/WebCore/dom/Position.h
r236785 r239190 334 334 } 335 335 336 RefPtr<Node> commonShadowIncludingAncestor(const Position&, const Position&); 337 336 338 WTF::TextStream& operator<<(WTF::TextStream&, const Position&); 337 339 -
trunk/Source/WebCore/editing/cocoa/HTMLConverter.mm
r239149 r239190 35 35 #import "ColorCocoa.h" 36 36 #import "ColorMac.h" 37 #import "ComposedTreeIterator.h" 37 38 #import "Document.h" 38 39 #import "DocumentLoader.h" … … 495 496 if (!m_dataSource) 496 497 return nil; 497 498 498 499 _domRangeStartIndex = 0; 499 500 _traverseNode(*commonAncestorContainer, 0, false /* embedded */); 500 501 if (_domRangeStartIndex > 0 && _domRangeStartIndex <= [_attrStr length]) 501 502 [_attrStr deleteCharactersInRange:NSMakeRange(0, _domRangeStartIndex)]; 502 503 503 504 return [[_attrStr retain] autorelease]; 504 505 } … … 666 667 { 667 668 if (!is<Element>(node)) { 668 if (Node* parent = node.parent Node())669 if (Node* parent = node.parentInComposedTree()) 669 670 return propertyValueForNode(*parent, propertyId); 670 671 return String(); … … 774 775 775 776 if (inherit) { 776 if (Node* parent = node.parent Node())777 if (Node* parent = node.parentInComposedTree()) 777 778 return propertyValueForNode(*parent, propertyId); 778 779 } … … 811 812 { 812 813 if (!is<Element>(node)) { 813 if (ContainerNode* parent = node.parent Node())814 if (ContainerNode* parent = node.parentInComposedTree()) 814 815 return floatPropertyValueForNode(*parent, propertyId, result); 815 816 return false; … … 844 845 845 846 if (inherit) { 846 if (ContainerNode* parent = node.parent Node())847 if (ContainerNode* parent = node.parentInComposedTree()) 847 848 return floatPropertyValueForNode(*parent, propertyId, result); 848 849 } … … 951 952 Element* element = node->parentElement(); 952 953 if (element && !_caches->isBlockElement(*element)) 953 element = _blockLevelElementForNode(element->parent Node());954 element = _blockLevelElementForNode(element->parentInComposedTree()); 954 955 return element; 955 956 } … … 970 971 { 971 972 if (!is<Element>(node)) { 972 if (Node* parent = node.parent Node())973 if (Node* parent = node.parentInComposedTree()) 973 974 return colorPropertyValueForNode(*parent, propertyId); 974 975 return Color(); … … 1006 1007 1007 1008 if (inherit) { 1008 if (Node* parent = node.parent Node())1009 if (Node* parent = node.parentInComposedTree()) 1009 1010 return colorPropertyValueForNode(*parent, propertyId); 1010 1011 } … … 1262 1263 NSDictionary* HTMLConverter::aggregatedAttributesForAncestors(CharacterData& node) 1263 1264 { 1264 Node* ancestor = node.parent Node();1265 Node* ancestor = node.parentInComposedTree(); 1265 1266 while (ancestor && !is<Element>(*ancestor)) 1266 ancestor = ancestor->parent Node();1267 ancestor = ancestor->parentInComposedTree(); 1267 1268 if (!ancestor) 1268 1269 return nullptr; … … 1279 1280 ASSERT(attributesForCurrentElement); 1280 1281 1281 Node* ancestor = element.parent Node();1282 Node* ancestor = element.parentInComposedTree(); 1282 1283 while (ancestor && !is<Element>(*ancestor)) 1283 ancestor = ancestor->parent Node();1284 ancestor = ancestor->parentInComposedTree(); 1284 1285 1285 1286 if (!ancestor) { … … 1853 1854 if (displayValue == "table-row-group") { 1854 1855 // If we are starting in medias res, the first thing we see may be the tbody, so go up to the table 1855 tableElement = _blockLevelElementForNode(element.parent Node());1856 tableElement = _blockLevelElementForNode(element.parentInComposedTree()); 1856 1857 if (!tableElement || _caches->propertyValueForNode(*tableElement, CSSPropertyDisplay) != "table") 1857 1858 tableElement = &element; … … 1924 1925 } 1925 1926 } else if (element.hasTagName(brTag)) { 1926 Element* blockElement = _blockLevelElementForNode(element.parent Node());1927 Element* blockElement = _blockLevelElementForNode(element.parentInComposedTree()); 1927 1928 NSString *breakClass = element.getAttribute(classAttr); 1928 1929 NSString *blockTag = blockElement ? (NSString *)blockElement->tagName() : nil; … … 2286 2287 bool isEnd = false; 2287 2288 if (&node == m_start.containerNode()) { 2288 startOffset = m_start. offsetInContainerNode();2289 startOffset = m_start.computeOffsetInContainerNode(); 2289 2290 isStart = true; 2290 2291 _flags.reachedStart = YES; 2291 2292 } 2292 2293 if (&node == m_end.containerNode()) { 2293 endOffset = m_end. offsetInContainerNode();2294 endOffset = m_end.computeOffsetInContainerNode(); 2294 2295 isEnd = true; 2295 2296 } … … 2297 2298 if (node.isDocumentNode() || node.isDocumentFragment()) { 2298 2299 Node* child = node.firstChild(); 2300 ASSERT(child == firstChildInComposedTreeIgnoringUserAgentShadow(node)); 2299 2301 for (NSUInteger i = 0; child; i++) { 2300 2302 if (isStart && i == startOffset) … … 2306 2308 if (_flags.reachedEnd) 2307 2309 break; 2310 ASSERT(child->nextSibling() == nextSiblingInComposedTreeIgnoringUserAgentShadow(*child)); 2308 2311 child = child->nextSibling(); 2309 2312 } … … 2313 2316 NSUInteger startIndex = [_attrStr length]; 2314 2317 if (_processElement(element, depth)) { 2315 Node* child = node.firstChild(); 2316 for (NSUInteger i = 0; child; i++) { 2317 if (isStart && i == startOffset) 2318 _domRangeStartIndex = [_attrStr length]; 2319 if ((!isStart || startOffset <= i) && (!isEnd || endOffset > i)) 2320 _traverseNode(*child, depth + 1, embedded); 2321 if (isEnd && i + 1 >= endOffset) 2322 _flags.reachedEnd = YES; 2323 if (_flags.reachedEnd) 2324 break; 2325 child = child->nextSibling(); 2318 if (auto* shadowRoot = shadowRootIgnoringUserAgentShadow(element)) // Traverse through shadow root to detect start and end. 2319 _traverseNode(*shadowRoot, depth + 1, embedded); 2320 else { 2321 auto* child = firstChildInComposedTreeIgnoringUserAgentShadow(node); 2322 for (NSUInteger i = 0; child; i++) { 2323 if (isStart && i == startOffset) 2324 _domRangeStartIndex = [_attrStr length]; 2325 if ((!isStart || startOffset <= i) && (!isEnd || endOffset > i)) 2326 _traverseNode(*child, depth + 1, embedded); 2327 if (isEnd && i + 1 >= endOffset) 2328 _flags.reachedEnd = YES; 2329 if (_flags.reachedEnd) 2330 break; 2331 child = nextSiblingInComposedTreeIgnoringUserAgentShadow(*child); 2332 } 2326 2333 } 2327 2334 _exitElement(element, depth, startIndex); … … 2347 2354 bool isEnd = false; 2348 2355 if (&element == m_start.containerNode()) { 2349 startOffset = m_start. offsetInContainerNode();2356 startOffset = m_start.computeOffsetInContainerNode(); 2350 2357 isStart = true; 2351 2358 _flags.reachedStart = YES; 2352 2359 } 2353 2360 if (&element == m_end.containerNode()) { 2354 endOffset = m_end. offsetInContainerNode();2361 endOffset = m_end.computeOffsetInContainerNode(); 2355 2362 isEnd = true; 2356 2363 } … … 2359 2366 NSUInteger startIndex = [_attrStr length]; 2360 2367 if (_processElement(element, depth)) { 2361 Node* child = element.firstChild();2368 auto* child = firstChildInComposedTreeIgnoringUserAgentShadow(element); 2362 2369 for (NSUInteger i = 0; child; i++) { 2363 2370 if (isStart && i == startOffset) … … 2369 2376 if (_flags.reachedEnd) 2370 2377 break; 2371 child = child->nextSibling();2378 child = nextSiblingInComposedTreeIgnoringUserAgentShadow(*child); 2372 2379 } 2373 2380 _exitElement(element, depth, startIndex); … … 2389 2396 Node* HTMLConverterCaches::cacheAncestorsOfStartToBeConverted(const Position& start, const Position& end) 2390 2397 { 2391 Node* commonAncestor = Range::commonAncestorContainer(start.containerNode(), end.containerNode());2398 auto commonAncestor = commonShadowIncludingAncestor(start, end); 2392 2399 Node* ancestor = start.containerNode(); 2393 2400 … … 2396 2403 if (ancestor == commonAncestor) 2397 2404 break; 2398 ancestor = ancestor->parent Node();2399 } 2400 2401 return commonAncestor ;2405 ancestor = ancestor->parentInComposedTree(); 2406 } 2407 2408 return commonAncestor.get(); 2402 2409 } 2403 2410 … … 2466 2473 NSAttributedString *attributedStringFromSelection(const VisibleSelection& selection) 2467 2474 { 2468 auto range = selection.toNormalizedRange(); 2469 ASSERT(range); 2470 return attributedStringBetweenStartAndEnd(range->startPosition(), range->endPosition()); 2475 return attributedStringBetweenStartAndEnd(selection.start(), selection.end()); 2471 2476 } 2472 2477 -
trunk/Source/WebCore/editing/markup.cpp
r238771 r239190 819 819 } 820 820 821 static RefPtr<Node> commonShadowIncludingAncestor(const Position& a, const Position& b)822 {823 TreeScope* commonScope = commonTreeScope(a.containerNode(), b.containerNode());824 if (!commonScope)825 return nullptr;826 auto* nodeA = commonScope->ancestorNodeInThisScope(a.containerNode());827 ASSERT(nodeA);828 auto* nodeB = commonScope->ancestorNodeInThisScope(b.containerNode());829 ASSERT(nodeB);830 return Range::commonAncestorContainer(nodeA, nodeB);831 }832 833 821 static String serializePreservingVisualAppearanceInternal(const Position& start, const Position& end, Vector<Node*>* nodes, ResolveURLs urlsToResolve, SerializeComposedTree serializeComposedTree, 834 822 AnnotateForInterchange annotate, ConvertBlocksToInlines convertBlocksToInlines, MSOListMode msoListMode)
Note: See TracChangeset
for help on using the changeset viewer.