Changeset 200690 in webkit


Ignore:
Timestamp:
May 11, 2016, 9:25:53 AM (9 years ago)
Author:
Chris Dumez
Message:

Optimize DataDetection's searchForLinkRemovingExistingDDLinks()
https://bugs.webkit.org/show_bug.cgi?id=157561

Reviewed by Ryosuke Niwa.

Optimize DataDetection's searchForLinkRemovingExistingDDLinks():

  1. The first loop was using Node::childNodes() to iterate over the child elements. Because of the recursive call, we may end up prepending children as we iterate over them. This is an issue because the childCount was cached before the loop and vector it would blow away the cache inside the NodeList. Switch to using ElementTraversal which should be both safer and more efficient. I don't believe we can use our nice ElementChildIterator here unfortunately as we would hit assertions due the the DOM mutations while iterating.
  2. The second loop was using again Node::childNodes() and kept calling item(0) to get the first child and move it to make it the previous sibling of its old parent. Again, using childNodes() here is super inefficient because we keep modifying the children and childNodes() returns a live NodeList. The call to NodeList::length() would cache all the children in a Vector, only to blow that cache away after removing the first child. Switch to using ContainerNode::firstChild().
  3. Drop the parentElement parameter as we can just get it from the child.
  4. Use tighter typing so we don't end up calling the implementations of insertBefore() / removeChild() that are on Node, thus unnecessarily doing a is<ContainerNode>() check every time.
  5. Pass element by reference instead of pointer as it cannot be null.
  • editing/cocoa/DataDetection.mm:

(WebCore::removeResultLinksFromAnchor):
(WebCore::searchForLinkRemovingExistingDDLinks):

Location:
trunk/Source/WebCore
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r200689 r200690  
     12016-05-11  Chris Dumez  <cdumez@apple.com>
     2
     3        Optimize DataDetection's searchForLinkRemovingExistingDDLinks()
     4        https://bugs.webkit.org/show_bug.cgi?id=157561
     5
     6        Reviewed by Ryosuke Niwa.
     7
     8        Optimize DataDetection's searchForLinkRemovingExistingDDLinks():
     9        1. The first loop was using Node::childNodes() to iterate over the child
     10           elements. Because of the recursive call, we may end up prepending
     11           children as we iterate over them. This is an issue because the
     12           childCount was cached before the loop and vector it would blow away
     13           the cache inside the NodeList. Switch to using ElementTraversal which
     14           should be both safer and more efficient. I don't believe we can use
     15           our nice ElementChildIterator here unfortunately as we would hit
     16           assertions due the the DOM mutations while iterating.
     17        2. The second loop was using again Node::childNodes() and kept calling
     18           item(0) to get the first child and move it to make it the previous
     19           sibling of its old parent. Again, using childNodes() here is super
     20           inefficient because we keep modifying the children and childNodes()
     21           returns a live NodeList. The call to NodeList::length() would cache
     22           all the children in a Vector, only to blow that cache away after
     23          removing the first child. Switch to using ContainerNode::firstChild().
     24        3. Drop the parentElement parameter as we can just get it from the child.
     25        4. Use tighter typing so we don't end up calling the implementations of
     26           insertBefore() / removeChild() that are on Node, thus unnecessarily
     27           doing a is<ContainerNode>() check every time.
     28        5. Pass element by reference instead of pointer as it cannot be null.
     29
     30        * editing/cocoa/DataDetection.mm:
     31        (WebCore::removeResultLinksFromAnchor):
     32        (WebCore::searchForLinkRemovingExistingDDLinks):
     33
    1342016-05-11  Rawinder Singh  <rawinder.singh-webkit@cisra.canon.com.au>
    235
  • trunk/Source/WebCore/editing/cocoa/DataDetection.mm

    r200659 r200690  
    3030#import "CSSStyleDeclaration.h"
    3131#import "DataDetectorsSPI.h"
     32#import "ElementTraversal.h"
    3233#import "FrameView.h"
    3334#import "HTMLAnchorElement.h"
     
    249250}
    250251
    251 static void removeResultLinksFromAnchor(Node* node, Node* nodeParent)
     252static void removeResultLinksFromAnchor(Element& element)
    252253{
    253254    // Perform a depth-first search for anchor nodes, which have the DDURLScheme attribute set to true,
    254     // take their children and insert them before the anchor,
    255     // and then remove the anchor.
    256    
    257     if (!node)
     255    // take their children and insert them before the anchor, and then remove the anchor.
     256
     257    // Note that this is not using ElementChildIterator because we potentially prepend children as we iterate over them.
     258    for (auto* child = ElementTraversal::firstChild(element); child; child = ElementTraversal::nextSibling(*child))
     259        removeResultLinksFromAnchor(*child);
     260
     261    auto* elementParent = element.parentElement();
     262    if (!elementParent)
    258263        return;
    259264   
    260     BOOL nodeIsDDAnchor = is<HTMLAnchorElement>(*node) && equalIgnoringASCIICase(downcast<Element>(*node).fastGetAttribute(x_apple_data_detectorsAttr), "true");
    261    
    262     RefPtr<NodeList> children = node->childNodes();
    263     unsigned childCount = children->length();
    264     for (size_t i = 0; i < childCount; i++) {
    265         Node* child = children->item(i);
    266         if (is<Element>(*child))
    267             removeResultLinksFromAnchor(child, node);
    268     }
    269    
    270     if (nodeIsDDAnchor && nodeParent) {
    271         children = node->childNodes();
    272         childCount = children->length();
    273        
    274         // Iterate over the children and move them all onto the same level as this anchor.
    275         // Remove the anchor afterwards.
    276         for (size_t i = 0; i < childCount; i++) {
    277             Node* child = children->item(0);
    278             nodeParent->insertBefore(child, node, ASSERT_NO_EXCEPTION);
    279         }
    280         nodeParent->removeChild(node, ASSERT_NO_EXCEPTION);
    281     }
     265    bool elementIsDDAnchor = is<HTMLAnchorElement>(element) && equalIgnoringASCIICase(element.fastGetAttribute(x_apple_data_detectorsAttr), "true");
     266    if (!elementIsDDAnchor)
     267        return;
     268
     269    // Iterate over the children and move them all onto the same level as this anchor. Remove the anchor afterwards.
     270    while (auto* child = element.firstChild())
     271        elementParent->insertBefore(*child, &element);
     272
     273    elementParent->removeChild(element);
    282274}
    283275
     
    288280    while (node) {
    289281        if (is<HTMLAnchorElement>(*node)) {
    290             if (!equalIgnoringASCIICase(downcast<Element>(*node).fastGetAttribute(x_apple_data_detectorsAttr), "true"))
     282            auto& anchor = downcast<HTMLAnchorElement>(*node);
     283            if (!equalIgnoringASCIICase(anchor.fastGetAttribute(x_apple_data_detectorsAttr), "true"))
    291284                return true;
    292             removeResultLinksFromAnchor(node, node->parentElement());
     285            removeResultLinksFromAnchor(anchor);
    293286            didModifyDOM = true;
    294287        }
     
    300293            while (node) {
    301294                if (is<HTMLAnchorElement>(*node)) {
    302                     if (!equalIgnoringASCIICase(downcast<Element>(*node).fastGetAttribute(x_apple_data_detectorsAttr), "true"))
     295                    auto& anchor = downcast<HTMLAnchorElement>(*node);
     296                    if (!equalIgnoringASCIICase(anchor.fastGetAttribute(x_apple_data_detectorsAttr), "true"))
    303297                        return true;
    304                     removeResultLinksFromAnchor(node, node->parentElement());
     298                    removeResultLinksFromAnchor(anchor);
    305299                    didModifyDOM = true;
    306300                }
Note: See TracChangeset for help on using the changeset viewer.