<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[164924] trunk</title>
</head>
<body>
<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; }
#msg dl a { font-weight: bold}
#msg dl a:link { color:#fc3; }
#msg dl a:active { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/164924">164924</a></dd>
<dt>Author</dt> <dd>benjamin@webkit.org</dd>
<dt>Date</dt> <dd>2014-03-01 14:09:48 -0800 (Sat, 01 Mar 2014)</dd>
</dl>
<h3>Log Message</h3>
<pre>Optimized querySelector(All) when selector contains #id
https://bugs.webkit.org/show_bug.cgi?id=116502
Reviewed by Andreas Kling.
Source/WebCore:
Test: fast/selectors/querySelector-id-filtering.html
The idea of this patch is to perform querySelector on a subtree
rooted at the last element with #id matching. For example, if we have the selector
"#foobar div a", we start by looking for the element with ID foobar in the TreeScope
cache, and start matching the children from there.
The idea comes from Rune for
https://chromium.googlesource.com/chromium/blink/+/1cd83d3588973a02ab15d94b1b05a28620853624
but the code as diverged too much so it had to be reimplemented specifically for WebKit.
* css/CSSSelectorList.cpp:
(WebCore::CSSSelectorList::CSSSelectorList):
(WebCore::CSSSelectorList::operator=):
* css/CSSSelectorList.h:
(WebCore::CSSSelectorList::~CSSSelectorList):
* css/StyleRule.h:
(WebCore::StyleRule::wrapperAdoptSelectorList):
(WebCore::StyleRulePage::wrapperAdoptSelectorList):
* dom/SelectorQuery.cpp:
(WebCore::isSingleTagNameSelector):
(WebCore::isSingleClassNameSelector):
(WebCore::findIdMatchingType):
(WebCore::SelectorDataList::SelectorDataList):
(WebCore::filterRootById):
(WebCore::SelectorDataList::executeCompiledSimpleSelectorChecker):
(WebCore::SelectorDataList::execute):
(WebCore::SelectorQuery::SelectorQuery):
(WebCore::SelectorQueryCache::add):
* dom/SelectorQuery.h:
(WebCore::SelectorDataList::SelectorData::SelectorData):
LayoutTests:
* fast/selectors/querySelector-id-filtering-expected.txt: Added.
* fast/selectors/querySelector-id-filtering.html: Added.</pre>
<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCorecssCSSSelectorListcpp">trunk/Source/WebCore/css/CSSSelectorList.cpp</a></li>
<li><a href="#trunkSourceWebCorecssCSSSelectorListh">trunk/Source/WebCore/css/CSSSelectorList.h</a></li>
<li><a href="#trunkSourceWebCorecssStyleRuleh">trunk/Source/WebCore/css/StyleRule.h</a></li>
<li><a href="#trunkSourceWebCoredomSelectorQuerycpp">trunk/Source/WebCore/dom/SelectorQuery.cpp</a></li>
<li><a href="#trunkSourceWebCoredomSelectorQueryh">trunk/Source/WebCore/dom/SelectorQuery.h</a></li>
</ul>
<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsfastselectorsquerySelectoridfilteringexpectedtxt">trunk/LayoutTests/fast/selectors/querySelector-id-filtering-expected.txt</a></li>
<li><a href="#trunkLayoutTestsfastselectorsquerySelectoridfilteringhtml">trunk/LayoutTests/fast/selectors/querySelector-id-filtering.html</a></li>
</ul>
</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (164923 => 164924)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2014-03-01 19:57:40 UTC (rev 164923)
+++ trunk/LayoutTests/ChangeLog        2014-03-01 22:09:48 UTC (rev 164924)
</span><span class="lines">@@ -1,3 +1,13 @@
</span><ins>+2014-03-01 Benjamin Poulain <benjamin@webkit.org>
+
+ Optimized querySelector(All) when selector contains #id
+ https://bugs.webkit.org/show_bug.cgi?id=116502
+
+ Reviewed by Andreas Kling.
+
+ * fast/selectors/querySelector-id-filtering-expected.txt: Added.
+ * fast/selectors/querySelector-id-filtering.html: Added.
+
</ins><span class="cx"> 2014-02-28 Alexey Proskuryakov <ap@apple.com>
</span><span class="cx">
</span><span class="cx"> Node::compareDocumentPosition leaks memory structure
</span></span></pre></div>
<a id="trunkLayoutTestsfastselectorsquerySelectoridfilteringexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/selectors/querySelector-id-filtering-expected.txt (0 => 164924)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/selectors/querySelector-id-filtering-expected.txt         (rev 0)
+++ trunk/LayoutTests/fast/selectors/querySelector-id-filtering-expected.txt        2014-03-01 22:09:48 UTC (rev 164924)
</span><span class="lines">@@ -0,0 +1,44 @@
</span><ins>+Test various cases when we constrain a selector matching to a subtree selected by #ID
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Missing id.
+PASS document.body.querySelectorAll("#notThere *").length is 0
+
+Trivial filtering.
+PASS document.body.querySelectorAll("#simple li").length is 1
+PASS document.body.querySelectorAll("#simple li")[0].id is "simpleTarget"
+
+ID is adjacent of target.
+PASS document.body.querySelectorAll("#directAdjacentRoot+div li").length is 1
+PASS document.body.querySelectorAll("#directAdjacentRoot+div li")[0].id is "directAdjacentTarget"
+PASS document.body.querySelectorAll("#indirectAdjacentRoot~div li").length is 1
+PASS document.body.querySelectorAll("#indirectAdjacentRoot~div li")[0].id is "indirectAdjacentTarget"
+
+Duplicated IDs.
+PASS document.body.querySelectorAll("#duplicated li").length is 3
+PASS document.body.querySelectorAll("#duplicated li")[0].id is "duplicatedTarget1"
+PASS document.body.querySelectorAll("#duplicated li")[1].id is "duplicatedTarget2"
+PASS document.body.querySelectorAll("#duplicated li")[2].id is "duplicatedTarget3"
+PASS document.body.querySelectorAll("#duplicated+div li").length is 2
+PASS document.body.querySelectorAll("#duplicated+div li")[0].id is "siblingOfDuplicated1"
+PASS document.body.querySelectorAll("#duplicated+div li")[1].id is "siblingOfDuplicated2"
+
+Duplicated IDs with a non-duplicated ancestor.
+PASS document.body.querySelectorAll("#nonDuplicatedParentOfDuplicate #deduplicated li").length is 3
+PASS document.body.querySelectorAll("#nonDuplicatedParentOfDuplicate #deduplicated li")[0].id is "deduplicatedTarget1"
+PASS document.body.querySelectorAll("#nonDuplicatedParentOfDuplicate #deduplicated li")[1].id is "deduplicatedTarget2"
+PASS document.body.querySelectorAll("#nonDuplicatedParentOfDuplicate #deduplicated li")[2].id is "deduplicatedTarget3"
+PASS document.body.querySelectorAll("#nonDuplicatedParentOfDuplicate #deduplicated+div li").length is 2
+PASS document.body.querySelectorAll("#nonDuplicatedParentOfDuplicate #deduplicated+div li")[0].id is "siblingOfDeduplicated1"
+PASS document.body.querySelectorAll("#nonDuplicatedParentOfDuplicate #deduplicated+div li")[1].id is "siblingOfDeduplicated2"
+PASS document.body.querySelectorAll("#nonDuplicatedParentOfDuplicate+div li").length is 1
+PASS document.body.querySelectorAll("#nonDuplicatedParentOfDuplicate+div li")[0].id is "siblingOfNonDuplicatedParentOfDuplicate"
+
+Sibling of HTML document.
+PASS document.body.querySelectorAll("#htmlDocument~* *").length is 0
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="trunkLayoutTestsfastselectorsquerySelectoridfilteringhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/selectors/querySelector-id-filtering.html (0 => 164924)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/selectors/querySelector-id-filtering.html         (rev 0)
+++ trunk/LayoutTests/fast/selectors/querySelector-id-filtering.html        2014-03-01 22:09:48 UTC (rev 164924)
</span><span class="lines">@@ -0,0 +1,138 @@
</span><ins>+<!doctype html>
+<html id=htmlDocument>
+<head>
+<script src="../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<div style="display:none">
+ <!-- Simple case -->
+ <div id=simple>
+ <ul>
+ <li id=simpleTarget></li>
+ </ul>
+ </div>
+
+ <!-- Duplicated IDs case -->
+ <div id=duplicated>
+ <ul>
+ <li id=duplicatedTarget1></li>
+ </ul>
+ <div id=duplicated>
+ <ul>
+ <li id=duplicatedTarget2></li>
+ </ul>
+ </div>
+ </div>
+ <div>
+ <ul>
+ <li id=siblingOfDuplicated1></li>
+ </ul>
+ </div>
+
+ <div id=duplicated>
+ <ul>
+ <li id=duplicatedTarget3></li>
+ </ul>
+ </div>
+ <div>
+ <ul>
+ <li id=siblingOfDuplicated2></li>
+ </ul>
+ </div>
+
+ <!-- Duplicated IDs in a non-duplicated ID -->
+ <div id=nonDuplicatedParentOfDuplicate>
+ <div id=deduplicated>
+ <ul>
+ <li id=deduplicatedTarget1></li>
+ </ul>
+ <div id=deduplicated>
+ <ul>
+ <li id=deduplicatedTarget2></li>
+ </ul>
+ </div>
+ </div>
+ <div>
+ <ul>
+ <li id=siblingOfDeduplicated1></li>
+ </ul>
+ </div>
+
+ <div id=deduplicated>
+ <ul>
+ <li id=deduplicatedTarget3></li>
+ </ul>
+ </div>
+ <div>
+ <ul>
+ <li id=siblingOfDeduplicated2></li>
+ </ul>
+ </div>
+ </div>
+ <div>
+ <ul>
+ <li id=siblingOfNonDuplicatedParentOfDuplicate></li>
+ </ul>
+ </div>
+
+ <!-- ID adjacent of target -->
+ <div id=directAdjacentRoot></div>
+ <div>
+ <ul>
+ <li id="directAdjacentTarget"></li>
+ </ul>
+ </div>
+
+ <!-- ID indirect adjacent of target -->
+ <div id=indirectAdjacentRoot></div>
+ <div></div>
+ <div></div>
+ <div>
+ <ul>
+ <li id="indirectAdjacentTarget"></li>
+ </ul>
+ </div>
+</div>
+</body>
+<script>
+description('Test various cases when we constrain a selector matching to a subtree selected by #ID');
+
+debug("Missing id.");
+shouldBe('document.body.querySelectorAll("#notThere *").length', '0');
+
+debug("<br>Trivial filtering.");
+shouldBe('document.body.querySelectorAll("#simple li").length', '1');
+shouldBeEqualToString('document.body.querySelectorAll("#simple li")[0].id', 'simpleTarget');
+
+debug("<br>ID is adjacent of target.");
+shouldBe('document.body.querySelectorAll("#directAdjacentRoot+div li").length', '1');
+shouldBeEqualToString('document.body.querySelectorAll("#directAdjacentRoot+div li")[0].id', 'directAdjacentTarget');
+shouldBe('document.body.querySelectorAll("#indirectAdjacentRoot~div li").length', '1');
+shouldBeEqualToString('document.body.querySelectorAll("#indirectAdjacentRoot~div li")[0].id', 'indirectAdjacentTarget');
+
+debug("<br>Duplicated IDs.");
+shouldBe('document.body.querySelectorAll("#duplicated li").length', '3');
+shouldBeEqualToString('document.body.querySelectorAll("#duplicated li")[0].id', 'duplicatedTarget1');
+shouldBeEqualToString('document.body.querySelectorAll("#duplicated li")[1].id', 'duplicatedTarget2');
+shouldBeEqualToString('document.body.querySelectorAll("#duplicated li")[2].id', 'duplicatedTarget3');
+shouldBe('document.body.querySelectorAll("#duplicated+div li").length', '2');
+shouldBeEqualToString('document.body.querySelectorAll("#duplicated+div li")[0].id', 'siblingOfDuplicated1');
+shouldBeEqualToString('document.body.querySelectorAll("#duplicated+div li")[1].id', 'siblingOfDuplicated2');
+
+debug("<br>Duplicated IDs with a non-duplicated ancestor.");
+shouldBe('document.body.querySelectorAll("#nonDuplicatedParentOfDuplicate #deduplicated li").length', '3');
+shouldBeEqualToString('document.body.querySelectorAll("#nonDuplicatedParentOfDuplicate #deduplicated li")[0].id', 'deduplicatedTarget1');
+shouldBeEqualToString('document.body.querySelectorAll("#nonDuplicatedParentOfDuplicate #deduplicated li")[1].id', 'deduplicatedTarget2');
+shouldBeEqualToString('document.body.querySelectorAll("#nonDuplicatedParentOfDuplicate #deduplicated li")[2].id', 'deduplicatedTarget3');
+shouldBe('document.body.querySelectorAll("#nonDuplicatedParentOfDuplicate #deduplicated+div li").length', '2');
+shouldBeEqualToString('document.body.querySelectorAll("#nonDuplicatedParentOfDuplicate #deduplicated+div li")[0].id', 'siblingOfDeduplicated1');
+shouldBeEqualToString('document.body.querySelectorAll("#nonDuplicatedParentOfDuplicate #deduplicated+div li")[1].id', 'siblingOfDeduplicated2');
+shouldBe('document.body.querySelectorAll("#nonDuplicatedParentOfDuplicate+div li").length', '1');
+shouldBeEqualToString('document.body.querySelectorAll("#nonDuplicatedParentOfDuplicate+div li")[0].id', 'siblingOfNonDuplicatedParentOfDuplicate');
+
+debug("<br>Sibling of HTML document.");
+shouldBe('document.body.querySelectorAll("#htmlDocument~* *").length', '0');
+
+</script>
+<script src="../../resources/js-test-post.js"></script>
+</html>
</ins></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (164923 => 164924)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2014-03-01 19:57:40 UTC (rev 164923)
+++ trunk/Source/WebCore/ChangeLog        2014-03-01 22:09:48 UTC (rev 164924)
</span><span class="lines">@@ -1,3 +1,42 @@
</span><ins>+2014-03-01 Benjamin Poulain <benjamin@webkit.org>
+
+ Optimized querySelector(All) when selector contains #id
+ https://bugs.webkit.org/show_bug.cgi?id=116502
+
+ Reviewed by Andreas Kling.
+
+ Test: fast/selectors/querySelector-id-filtering.html
+
+ The idea of this patch is to perform querySelector on a subtree
+ rooted at the last element with #id matching. For example, if we have the selector
+ "#foobar div a", we start by looking for the element with ID foobar in the TreeScope
+ cache, and start matching the children from there.
+
+ The idea comes from Rune for
+ https://chromium.googlesource.com/chromium/blink/+/1cd83d3588973a02ab15d94b1b05a28620853624
+ but the code as diverged too much so it had to be reimplemented specifically for WebKit.
+
+ * css/CSSSelectorList.cpp:
+ (WebCore::CSSSelectorList::CSSSelectorList):
+ (WebCore::CSSSelectorList::operator=):
+ * css/CSSSelectorList.h:
+ (WebCore::CSSSelectorList::~CSSSelectorList):
+ * css/StyleRule.h:
+ (WebCore::StyleRule::wrapperAdoptSelectorList):
+ (WebCore::StyleRulePage::wrapperAdoptSelectorList):
+ * dom/SelectorQuery.cpp:
+ (WebCore::isSingleTagNameSelector):
+ (WebCore::isSingleClassNameSelector):
+ (WebCore::findIdMatchingType):
+ (WebCore::SelectorDataList::SelectorDataList):
+ (WebCore::filterRootById):
+ (WebCore::SelectorDataList::executeCompiledSimpleSelectorChecker):
+ (WebCore::SelectorDataList::execute):
+ (WebCore::SelectorQuery::SelectorQuery):
+ (WebCore::SelectorQueryCache::add):
+ * dom/SelectorQuery.h:
+ (WebCore::SelectorDataList::SelectorData::SelectorData):
+
</ins><span class="cx"> 2014-02-28 Alexey Proskuryakov <ap@apple.com>
</span><span class="cx">
</span><span class="cx"> Node::compareDocumentPosition leaks memory structure
</span></span></pre></div>
<a id="trunkSourceWebCorecssCSSSelectorListcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/css/CSSSelectorList.cpp (164923 => 164924)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/css/CSSSelectorList.cpp        2014-03-01 19:57:40 UTC (rev 164923)
+++ trunk/Source/WebCore/css/CSSSelectorList.cpp        2014-03-01 22:09:48 UTC (rev 164924)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2008, 2012, 2013 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2008, 2012, 2013, 2014 Apple Inc. All rights reserved.
</ins><span class="cx"> * Copyright (C) 2009 Google Inc. All rights reserved.
</span><span class="cx"> *
</span><span class="cx"> * Redistribution and use in source and binary forms, with or without
</span><span class="lines">@@ -32,11 +32,6 @@
</span><span class="cx">
</span><span class="cx"> namespace WebCore {
</span><span class="cx">
</span><del>-CSSSelectorList::~CSSSelectorList()
-{
- deleteSelectors();
-}
-
</del><span class="cx"> CSSSelectorList::CSSSelectorList(const CSSSelectorList& other)
</span><span class="cx"> {
</span><span class="cx"> unsigned otherComponentCount = other.componentCount();
</span><span class="lines">@@ -45,11 +40,10 @@
</span><span class="cx"> new (NotNull, &m_selectorArray[i]) CSSSelector(other.m_selectorArray[i]);
</span><span class="cx"> }
</span><span class="cx">
</span><del>-void CSSSelectorList::adopt(CSSSelectorList& list)
</del><ins>+CSSSelectorList::CSSSelectorList(CSSSelectorList&& other)
+ : m_selectorArray(other.m_selectorArray)
</ins><span class="cx"> {
</span><del>- deleteSelectors();
- m_selectorArray = list.m_selectorArray;
- list.m_selectorArray = 0;
</del><ins>+ other.m_selectorArray = nullptr;
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> void CSSSelectorList::adoptSelectorVector(Vector<std::unique_ptr<CSSParserSelector>>& selectorVector)
</span><span class="lines">@@ -97,6 +91,14 @@
</span><span class="cx"> return (current - m_selectorArray) + 1;
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+CSSSelectorList& CSSSelectorList::operator=(CSSSelectorList&& other)
+{
+ deleteSelectors();
+ m_selectorArray = other.m_selectorArray;
+ other.m_selectorArray = nullptr;
+ return *this;
+}
+
</ins><span class="cx"> void CSSSelectorList::deleteSelectors()
</span><span class="cx"> {
</span><span class="cx"> if (!m_selectorArray)
</span></span></pre></div>
<a id="trunkSourceWebCorecssCSSSelectorListh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/css/CSSSelectorList.h (164923 => 164924)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/css/CSSSelectorList.h        2014-03-01 19:57:40 UTC (rev 164923)
+++ trunk/Source/WebCore/css/CSSSelectorList.h        2014-03-01 22:09:48 UTC (rev 164924)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2008 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2008, 2014 Apple Inc. All rights reserved.
</ins><span class="cx"> *
</span><span class="cx"> * Redistribution and use in source and binary forms, with or without
</span><span class="cx"> * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -38,10 +38,10 @@
</span><span class="cx"> public:
</span><span class="cx"> CSSSelectorList() : m_selectorArray(0) { }
</span><span class="cx"> CSSSelectorList(const CSSSelectorList&);
</span><ins>+ CSSSelectorList(CSSSelectorList&&);
</ins><span class="cx">
</span><del>- ~CSSSelectorList();
</del><ins>+ ~CSSSelectorList() { deleteSelectors(); }
</ins><span class="cx">
</span><del>- void adopt(CSSSelectorList& list);
</del><span class="cx"> void adoptSelectorVector(Vector<std::unique_ptr<CSSParserSelector>>& selectorVector);
</span><span class="cx"> void adoptSelectorArray(CSSSelector* selectors) { ASSERT(!m_selectorArray); m_selectorArray = selectors; }
</span><span class="cx">
</span><span class="lines">@@ -67,6 +67,8 @@
</span><span class="cx">
</span><span class="cx"> unsigned componentCount() const;
</span><span class="cx">
</span><ins>+ CSSSelectorList& operator=(CSSSelectorList&&);
+
</ins><span class="cx"> private:
</span><span class="cx"> void deleteSelectors();
</span><span class="cx">
</span></span></pre></div>
<a id="trunkSourceWebCorecssStyleRuleh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/css/StyleRule.h (164923 => 164924)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/css/StyleRule.h        2014-03-01 19:57:40 UTC (rev 164923)
+++ trunk/Source/WebCore/css/StyleRule.h        2014-03-01 22:09:48 UTC (rev 164924)
</span><span class="lines">@@ -118,7 +118,7 @@
</span><span class="cx"> MutableStyleProperties& mutableProperties();
</span><span class="cx">
</span><span class="cx"> void parserAdoptSelectorVector(Vector<std::unique_ptr<CSSParserSelector>>& selectors) { m_selectorList.adoptSelectorVector(selectors); }
</span><del>- void wrapperAdoptSelectorList(CSSSelectorList& selectors) { m_selectorList.adopt(selectors); }
</del><ins>+ void wrapperAdoptSelectorList(CSSSelectorList& selectors) { m_selectorList = std::move(selectors); }
</ins><span class="cx"> void parserAdoptSelectorArray(CSSSelector* selectors) { m_selectorList.adoptSelectorArray(selectors); }
</span><span class="cx">
</span><span class="cx"> PassRef<StyleRule> copy() const { return adoptRef(*new StyleRule(*this)); }
</span><span class="lines">@@ -173,7 +173,7 @@
</span><span class="cx"> MutableStyleProperties& mutableProperties();
</span><span class="cx">
</span><span class="cx"> void parserAdoptSelectorVector(Vector<std::unique_ptr<CSSParserSelector>>& selectors) { m_selectorList.adoptSelectorVector(selectors); }
</span><del>- void wrapperAdoptSelectorList(CSSSelectorList& selectors) { m_selectorList.adopt(selectors); }
</del><ins>+ void wrapperAdoptSelectorList(CSSSelectorList& selectors) { m_selectorList = std::move(selectors); }
</ins><span class="cx">
</span><span class="cx"> PassRef<StyleRulePage> copy() const { return adoptRef(*new StyleRulePage(*this)); }
</span><span class="cx">
</span></span></pre></div>
<a id="trunkSourceWebCoredomSelectorQuerycpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/dom/SelectorQuery.cpp (164923 => 164924)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/dom/SelectorQuery.cpp        2014-03-01 19:57:40 UTC (rev 164923)
+++ trunk/Source/WebCore/dom/SelectorQuery.cpp        2014-03-01 22:09:48 UTC (rev 164924)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2011, 2013 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2011, 2013, 2014 Apple Inc. All rights reserved.
</ins><span class="cx"> *
</span><span class="cx"> * Redistribution and use in source and binary forms, with or without
</span><span class="cx"> * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -35,10 +35,41 @@
</span><span class="cx">
</span><span class="cx"> namespace WebCore {
</span><span class="cx">
</span><del>-void SelectorDataList::initialize(const CSSSelectorList& selectorList)
</del><ins>+#if !ASSERT_DISABLED
+static bool isSingleTagNameSelector(const CSSSelector& selector)
</ins><span class="cx"> {
</span><del>- ASSERT(m_selectors.isEmpty());
</del><ins>+ return selector.isLastInTagHistory() && selector.m_match == CSSSelector::Tag;
+}
</ins><span class="cx">
</span><ins>+static bool isSingleClassNameSelector(const CSSSelector& selector)
+{
+ return selector.isLastInTagHistory() && selector.m_match == CSSSelector::Class;
+}
+#endif
+
+enum class IdMatchingType : uint8_t {
+ None,
+ Rightmost,
+ Filter
+};
+
+static IdMatchingType findIdMatchingType(const CSSSelector& firstSelector)
+{
+ bool inRightmost = true;
+ for (const CSSSelector* selector = &firstSelector; selector; selector = selector->tagHistory()) {
+ if (selector->m_match == CSSSelector::Id) {
+ if (inRightmost)
+ return IdMatchingType::Rightmost;
+ return IdMatchingType::Filter;
+ }
+ if (selector->relation() != CSSSelector::SubSelector)
+ inRightmost = false;
+ }
+ return IdMatchingType::None;
+}
+
+SelectorDataList::SelectorDataList(const CSSSelectorList& selectorList)
+{
</ins><span class="cx"> unsigned selectorCount = 0;
</span><span class="cx"> for (const CSSSelector* selector = selectorList.first(); selector; selector = CSSSelectorList::next(selector))
</span><span class="cx"> selectorCount++;
</span><span class="lines">@@ -46,6 +77,39 @@
</span><span class="cx"> m_selectors.reserveInitialCapacity(selectorCount);
</span><span class="cx"> for (const CSSSelector* selector = selectorList.first(); selector; selector = CSSSelectorList::next(selector))
</span><span class="cx"> m_selectors.uncheckedAppend(SelectorData(selector, SelectorCheckerFastPath::canUse(selector)));
</span><ins>+
+ if (selectorCount == 1) {
+ const CSSSelector& selector = *m_selectors.first().selector;
+ if (selector.isLastInTagHistory()) {
+ switch (selector.m_match) {
+ case CSSSelector::Tag:
+ m_matchType = TagNameMatch;
+ break;
+ case CSSSelector::Class:
+ m_matchType = ClassNameMatch;
+ break;
+ case CSSSelector::Id:
+ m_matchType = RightMostWithIdMatch;
+ break;
+ default:
+ m_matchType = CompilableSingle;
+ break;
+ }
+ } else {
+ switch (findIdMatchingType(selector)) {
+ case IdMatchingType::None:
+ m_matchType = CompilableSingle;
+ break;
+ case IdMatchingType::Rightmost:
+ m_matchType = RightMostWithIdMatch;
+ break;
+ case IdMatchingType::Filter:
+ m_matchType = CompilableSingleWithRootFilter;
+ break;
+ }
+ }
+ } else
+ m_matchType = MultipleSelectorMatch;
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> inline bool SelectorDataList::selectorMatches(const SelectorData& selectorData, Element& element, const ContainerNode& rootNode) const
</span><span class="lines">@@ -157,10 +221,45 @@
</span><span class="cx"> SelectorQueryTrait::appendOutputForElement(output, element);
</span><span class="cx"> }
</span><span class="cx">
</span><del>-static bool isSingleTagNameSelector(const CSSSelector& selector)
</del><ins>+#if ENABLE(CSS_SELECTOR_JIT)
+static ContainerNode& filterRootById(ContainerNode& rootNode, const CSSSelector& firstSelector)
</ins><span class="cx"> {
</span><del>- return selector.isLastInTagHistory() && selector.m_match == CSSSelector::Tag;
</del><ins>+ if (!rootNode.inDocument())
+ return rootNode;
+ if (rootNode.document().inQuirksMode())
+ return rootNode;
+
+ // If there was an Id match in the rightmost Simple Selector, we should be in a RightMostWithIdMatch, not in filter.
+ // Thus we can skip the rightmost match.
+ const CSSSelector* selector = &firstSelector;
+ do {
+ ASSERT(selector->m_match != CSSSelector::Id);
+ if (selector->relation() != CSSSelector::SubSelector)
+ break;
+ selector = selector->tagHistory();
+ } while (selector);
+
+ bool inAdjacentChain = false;
+ for (; selector; selector = selector->tagHistory()) {
+ if (selector->m_match == CSSSelector::Id) {
+ const AtomicString& idToMatch = selector->value();
+ if (ContainerNode* searchRoot = rootNode.treeScope().getElementById(idToMatch)) {
+ if (LIKELY(!rootNode.treeScope().containsMultipleElementsWithId(idToMatch))) {
+ if (inAdjacentChain)
+ searchRoot = searchRoot->parentNode();
+ if (searchRoot && (isTreeScopeRoot(rootNode) || searchRoot == &rootNode || searchRoot->isDescendantOf(&rootNode)))
+ return *searchRoot;
+ }
+ }
+ }
+ if (selector->relation() == CSSSelector::DirectAdjacent || selector->relation() == CSSSelector::IndirectAdjacent)
+ inAdjacentChain = true;
+ else
+ inAdjacentChain = false;
+ }
+ return rootNode;
</ins><span class="cx"> }
</span><ins>+#endif
</ins><span class="cx">
</span><span class="cx"> template <typename SelectorQueryTrait>
</span><span class="cx"> static inline void elementsForLocalName(const ContainerNode& rootNode, const AtomicString& localName, typename SelectorQueryTrait::OutputType& output)
</span><span class="lines">@@ -215,11 +314,6 @@
</span><span class="cx"> }
</span><span class="cx"> }
</span><span class="cx">
</span><del>-static bool isSingleClassNameSelector(const CSSSelector& selector)
-{
- return selector.isLastInTagHistory() && selector.m_match == CSSSelector::Class;
-}
-
</del><span class="cx"> template <typename SelectorQueryTrait>
</span><span class="cx"> ALWAYS_INLINE void SelectorDataList::executeSingleClassNameSelectorData(const ContainerNode& rootNode, const SelectorData& selectorData, typename SelectorQueryTrait::OutputType& output) const
</span><span class="cx"> {
</span><span class="lines">@@ -278,59 +372,91 @@
</span><span class="cx"> }
</span><span class="cx"> }
</span><span class="cx"> }
</span><del>-
-template <typename SelectorQueryTrait>
-ALWAYS_INLINE void SelectorDataList::executeCompiledSelectorCheckerWithContext(const ContainerNode& rootNode, SelectorCompiler::SelectorCheckerWithCheckingContext selectorChecker, const SelectorCompiler::CheckingContext& context, typename SelectorQueryTrait::OutputType& output) const
-{
- for (auto& element : descendantsOfType<Element>(const_cast<ContainerNode&>(rootNode))) {
- if (selectorChecker(&element, &context)) {
- SelectorQueryTrait::appendOutputForElement(output, &element);
- if (SelectorQueryTrait::shouldOnlyMatchFirstElement)
- return;
- }
- }
-}
</del><span class="cx"> #endif // ENABLE(CSS_SELECTOR_JIT)
</span><span class="cx">
</span><span class="cx"> template <typename SelectorQueryTrait>
</span><span class="cx"> ALWAYS_INLINE void SelectorDataList::execute(ContainerNode& rootNode, typename SelectorQueryTrait::OutputType& output) const
</span><span class="cx"> {
</span><del>- if (m_selectors.size() == 1) {
- const SelectorData& selectorData = m_selectors[0];
- if (const CSSSelector* idSelector = selectorForIdLookup(rootNode, *selectorData.selector))
- executeFastPathForIdSelector<SelectorQueryTrait>(rootNode, selectorData, idSelector, output);
- else if (isSingleTagNameSelector(*selectorData.selector))
- executeSingleTagNameSelectorData<SelectorQueryTrait>(rootNode, selectorData, output);
- else if (isSingleClassNameSelector(*selectorData.selector))
- executeSingleClassNameSelectorData<SelectorQueryTrait>(rootNode, selectorData, output);
- else {
</del><ins>+ ContainerNode* searchRootNode = &rootNode;
+ switch (m_matchType) {
+ case RightMostWithIdMatch:
+ if (const CSSSelector* idSelector = selectorForIdLookup(*searchRootNode, *m_selectors.first().selector)) {
+ executeFastPathForIdSelector<SelectorQueryTrait>(*searchRootNode, m_selectors.first(), idSelector, output);
+ break;
+ }
+ FALLTHROUGH;
+ case CompilableSingleWithRootFilter:
+ case CompilableSingle:
+ {
</ins><span class="cx"> #if ENABLE(CSS_SELECTOR_JIT)
</span><del>- void* compiledSelectorChecker = selectorData.compiledSelectorCodeRef.code().executableAddress();
- if (!compiledSelectorChecker && selectorData.compilationStatus == SelectorCompilationStatus::NotCompiled) {
- JSC::VM* vm = rootNode.document().scriptExecutionContext()->vm();
- selectorData.compilationStatus = SelectorCompiler::compileSelector(selectorData.selector, vm, SelectorCompiler::SelectorContext::QuerySelector, selectorData.compiledSelectorCodeRef);
- RELEASE_ASSERT(selectorData.compilationStatus != SelectorCompilationStatus::SelectorCheckerWithCheckingContext);
- compiledSelectorChecker = selectorData.compiledSelectorCodeRef.code().executableAddress();
- }
</del><ins>+ const SelectorData& selectorData = m_selectors.first();
+ ASSERT(m_matchType == RightMostWithIdMatch || selectorData.compilationStatus == SelectorCompilationStatus::NotCompiled);
</ins><span class="cx">
</span><del>- if (compiledSelectorChecker) {
- SelectorCompiler::SimpleSelectorChecker selectorChecker = SelectorCompiler::simpleSelectorCheckerFunction(compiledSelectorChecker, selectorData.compilationStatus);
- executeCompiledSimpleSelectorChecker<SelectorQueryTrait>(rootNode, selectorChecker, output);
- return;
</del><ins>+ JSC::VM* vm = searchRootNode->document().scriptExecutionContext()->vm();
+ selectorData.compilationStatus = SelectorCompiler::compileSelector(selectorData.selector, vm, SelectorCompiler::SelectorContext::QuerySelector, selectorData.compiledSelectorCodeRef);
+ RELEASE_ASSERT(selectorData.compilationStatus != SelectorCompilationStatus::SelectorCheckerWithCheckingContext);
+
+ if (selectorData.compilationStatus == SelectorCompilationStatus::SimpleSelectorChecker) {
+ if (m_matchType == CompilableSingle) {
+ m_matchType = CompiledSingle;
+ goto CompiledSingleCase;
</ins><span class="cx"> }
</span><ins>+ if (m_matchType == CompilableSingleWithRootFilter) {
+ m_matchType = CompiledSingleWithRootFilter;
+ goto CompiledSingleWithRootFilterCase;
+ }
+ goto CompiledSingleCase;
+ }
+ if (m_matchType != RightMostWithIdMatch)
+ m_matchType = SingleSelector;
+ goto SingleSelectorCase;
+ ASSERT_NOT_REACHED();
+ break;
+#else
+ FALLTHROUGH;
</ins><span class="cx"> #endif // ENABLE(CSS_SELECTOR_JIT)
</span><del>-
- executeSingleSelectorData<SelectorQueryTrait>(rootNode, selectorData, output);
</del><span class="cx"> }
</span><del>- return;
</del><ins>+ case CompiledSingleWithRootFilter:
+#if ENABLE(CSS_SELECTOR_JIT)
+ CompiledSingleWithRootFilterCase:
+ searchRootNode = &filterRootById(*searchRootNode, *m_selectors.first().selector);
+#endif // ENABLE(CSS_SELECTOR_JIT)
+ FALLTHROUGH;
+ case CompiledSingle:
+#if ENABLE(CSS_SELECTOR_JIT)
+ {
+ CompiledSingleCase:
+ const SelectorData& selectorData = m_selectors.first();
+ void* compiledSelectorChecker = selectorData.compiledSelectorCodeRef.code().executableAddress();
+ SelectorCompiler::SimpleSelectorChecker selectorChecker = SelectorCompiler::simpleSelectorCheckerFunction(compiledSelectorChecker, selectorData.compilationStatus);
+ executeCompiledSimpleSelectorChecker<SelectorQueryTrait>(*searchRootNode, selectorChecker, output);
+ break;
+ }
+#else
+ FALLTHROUGH;
+#endif // ENABLE(CSS_SELECTOR_JIT)
+ case SingleSelector:
+#if ENABLE(CSS_SELECTOR_JIT)
+ SingleSelectorCase:
+#endif
+ executeSingleSelectorData<SelectorQueryTrait>(*searchRootNode, m_selectors.first(), output);
+ break;
+ case TagNameMatch:
+ executeSingleTagNameSelectorData<SelectorQueryTrait>(*searchRootNode, m_selectors.first(), output);
+ break;
+ case ClassNameMatch:
+ executeSingleClassNameSelectorData<SelectorQueryTrait>(*searchRootNode, m_selectors.first(), output);
+ break;
+ case MultipleSelectorMatch:
+ executeSingleMultiSelectorData<SelectorQueryTrait>(*searchRootNode, output);
+ break;
</ins><span class="cx"> }
</span><del>- executeSingleMultiSelectorData<SelectorQueryTrait>(rootNode, output);
</del><span class="cx"> }
</span><span class="cx">
</span><del>-SelectorQuery::SelectorQuery(const CSSSelectorList& selectorList)
</del><ins>+SelectorQuery::SelectorQuery(CSSSelectorList&& selectorList)
</ins><span class="cx"> : m_selectorList(selectorList)
</span><ins>+ , m_selectors(m_selectorList)
</ins><span class="cx"> {
</span><del>- m_selectors.initialize(m_selectorList);
</del><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> SelectorQuery* SelectorQueryCache::add(const String& selectors, Document& document, ExceptionCode& ec)
</span><span class="lines">@@ -358,7 +484,7 @@
</span><span class="cx"> if (m_entries.size() == maximumSelectorQueryCacheSize)
</span><span class="cx"> m_entries.remove(m_entries.begin());
</span><span class="cx">
</span><del>- return m_entries.add(selectors, std::make_unique<SelectorQuery>(selectorList)).iterator->value.get();
</del><ins>+ return m_entries.add(selectors, std::make_unique<SelectorQuery>(std::move(selectorList))).iterator->value.get();
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> void SelectorQueryCache::invalidate()
</span></span></pre></div>
<a id="trunkSourceWebCoredomSelectorQueryh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/dom/SelectorQuery.h (164923 => 164924)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/dom/SelectorQuery.h        2014-03-01 19:57:40 UTC (rev 164923)
+++ trunk/Source/WebCore/dom/SelectorQuery.h        2014-03-01 22:09:48 UTC (rev 164924)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2011, 2013 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2011, 2013, 2014 Apple Inc. All rights reserved.
</ins><span class="cx"> *
</span><span class="cx"> * Redistribution and use in source and binary forms, with or without
</span><span class="cx"> * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -46,21 +46,25 @@
</span><span class="cx">
</span><span class="cx"> class SelectorDataList {
</span><span class="cx"> public:
</span><del>- void initialize(const CSSSelectorList&);
</del><ins>+ explicit SelectorDataList(const CSSSelectorList&);
</ins><span class="cx"> bool matches(Element&) const;
</span><span class="cx"> RefPtr<NodeList> queryAll(ContainerNode& rootNode) const;
</span><span class="cx"> Element* queryFirst(ContainerNode& rootNode) const;
</span><span class="cx">
</span><span class="cx"> private:
</span><span class="cx"> struct SelectorData {
</span><del>- SelectorData(const CSSSelector* selector, bool isFastCheckable) : selector(selector), isFastCheckable(isFastCheckable) { }
</del><ins>+ SelectorData(const CSSSelector* selector, bool isFastCheckable)
+ : selector(selector)
+ , isFastCheckable(isFastCheckable)
+ {
+ }
+
</ins><span class="cx"> const CSSSelector* selector;
</span><del>- bool isFastCheckable;
-
</del><span class="cx"> #if ENABLE(CSS_SELECTOR_JIT)
</span><ins>+ mutable JSC::MacroAssemblerCodeRef compiledSelectorCodeRef;
</ins><span class="cx"> mutable SelectorCompilationStatus compilationStatus;
</span><del>- mutable JSC::MacroAssemblerCodeRef compiledSelectorCodeRef;
</del><span class="cx"> #endif // ENABLE(CSS_SELECTOR_JIT)
</span><ins>+ bool isFastCheckable;
</ins><span class="cx"> };
</span><span class="cx">
</span><span class="cx"> bool selectorMatches(const SelectorData&, Element&, const ContainerNode& rootNode) const;
</span><span class="lines">@@ -73,10 +77,20 @@
</span><span class="cx"> template <typename SelectorQueryTrait> void executeSingleMultiSelectorData(const ContainerNode& rootNode, typename SelectorQueryTrait::OutputType&) const;
</span><span class="cx"> #if ENABLE(CSS_SELECTOR_JIT)
</span><span class="cx"> template <typename SelectorQueryTrait> void executeCompiledSimpleSelectorChecker(const ContainerNode& rootNode, SelectorCompiler::SimpleSelectorChecker, typename SelectorQueryTrait::OutputType&) const;
</span><del>- template <typename SelectorQueryTrait> void executeCompiledSelectorCheckerWithContext(const ContainerNode& rootNode, SelectorCompiler::SelectorCheckerWithCheckingContext, const SelectorCompiler::CheckingContext&, typename SelectorQueryTrait::OutputType&) const;
</del><span class="cx"> #endif // ENABLE(CSS_SELECTOR_JIT)
</span><span class="cx">
</span><span class="cx"> Vector<SelectorData> m_selectors;
</span><ins>+ mutable enum MatchType {
+ CompilableSingle,
+ CompilableSingleWithRootFilter,
+ CompiledSingle,
+ CompiledSingleWithRootFilter,
+ SingleSelector,
+ RightMostWithIdMatch,
+ TagNameMatch,
+ ClassNameMatch,
+ MultipleSelectorMatch,
+ } m_matchType;
</ins><span class="cx"> };
</span><span class="cx">
</span><span class="cx"> class SelectorQuery {
</span><span class="lines">@@ -84,14 +98,14 @@
</span><span class="cx"> WTF_MAKE_FAST_ALLOCATED;
</span><span class="cx">
</span><span class="cx"> public:
</span><del>- explicit SelectorQuery(const CSSSelectorList&);
</del><ins>+ explicit SelectorQuery(CSSSelectorList&&);
</ins><span class="cx"> bool matches(Element&) const;
</span><span class="cx"> RefPtr<NodeList> queryAll(ContainerNode& rootNode) const;
</span><span class="cx"> Element* queryFirst(ContainerNode& rootNode) const;
</span><span class="cx">
</span><span class="cx"> private:
</span><ins>+ CSSSelectorList m_selectorList;
</ins><span class="cx"> SelectorDataList m_selectors;
</span><del>- CSSSelectorList m_selectorList;
</del><span class="cx"> };
</span><span class="cx">
</span><span class="cx"> class SelectorQueryCache {
</span></span></pre>
</div>
</div>
</body>
</html>