<!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>[184116] 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/184116">184116</a></dd>
<dt>Author</dt> <dd>commit-queue@webkit.org</dd>
<dt>Date</dt> <dd>2015-05-11 12:54:15 -0700 (Mon, 11 May 2015)</dd>
</dl>

<h3>Log Message</h3>
<pre>[Content Extensions] Support domain-specific rules and exceptions.
https://bugs.webkit.org/show_bug.cgi?id=144833

Patch by Alex Christensen &lt;achristensen@webkit.org&gt; on 2015-05-11
Reviewed by Darin Adler.

Source/WebCore:

Test: http/tests/contentextensions/domain-rules.html
(And lots of API tests)

This patch adds if-domain and unless-domain to the trigger in the JSON format.
if-domain makes the rule apply only to domains in the list.
unless-domain makes the rule apply to domains that are not in the list.

All rules without if-domain or unless-domain are compiled into a set of DFAs.  This behavior is unchanged.
All rules with if-domain or unless-domain are compiled into a separate set of DFAs.
The domains are also compiled into another set of DFAs.  This makes 3 arrays of DFA bytecode instead of 1.

If there are no domain specific rules, there is no change in behavior.
If there are domain specific rules, the URL will be checked for matches in both
filtersWithoutDomainsBytecode and filtersWithDomainsBytecode.  If there are matches from
filtersWithDomainsBytecode then the domain of the main document will be checked with
domainFiltersBytecode to see which of the matches applies to this domain.

* contentextensions/CombinedURLFilters.cpp:
(WebCore::ContentExtensions::CombinedURLFilters::isEmpty):
(WebCore::ContentExtensions::CombinedURLFilters::addDomain):
* contentextensions/CombinedURLFilters.h:
Added addDomain, which adds characters from a domain to the prefix tree directly without using YARR.
* contentextensions/CompiledContentExtension.cpp:
(WebCore::ContentExtensions::CompiledContentExtension::globalDisplayNoneSelectors):
* contentextensions/CompiledContentExtension.h:
* contentextensions/ContentExtensionCompiler.cpp:
(WebCore::ContentExtensions::serializeActions):
(WebCore::ContentExtensions::compileRuleList):
Separate the rules into rules with domains and rules without domains and compile to bytecode.
* contentextensions/ContentExtensionCompiler.h:
Updated compiler interface to reflect the slightly more complicated structure.
* contentextensions/ContentExtensionError.cpp:
(WebCore::ContentExtensions::contentExtensionErrorCategory):
* contentextensions/ContentExtensionError.h:
Added new parsing errors.
* contentextensions/ContentExtensionParser.cpp:
(WebCore::ContentExtensions::getDomainList):
(WebCore::ContentExtensions::loadTrigger):
(WebCore::ContentExtensions::loadEncodedRules):
* contentextensions/ContentExtensionRule.h:
(WebCore::ContentExtensions::Trigger::operator==):
Parse the new domain structures from JSON into the Trigger structure.
* contentextensions/ContentExtensionsBackend.cpp:
(WebCore::ContentExtensions::ContentExtensionsBackend::actionsForResourceLoad):
Interpret as much bytecode as necessary to determine which rules apply to this URL and domain.
* contentextensions/DFABytecode.h:
(WebCore::ContentExtensions::instructionSizeWithArguments):
* contentextensions/DFABytecodeCompiler.cpp:
(WebCore::ContentExtensions::DFABytecodeCompiler::emitAppendAction):
(WebCore::ContentExtensions::DFABytecodeCompiler::emitTestFlagsAndAppendAction):
(WebCore::ContentExtensions::DFABytecodeCompiler::compileNode):
* contentextensions/DFABytecodeCompiler.h:
* contentextensions/DFABytecodeInterpreter.cpp:
(WebCore::ContentExtensions::DFABytecodeInterpreter::interpretAppendAction):
(WebCore::ContentExtensions::DFABytecodeInterpreter::interpretTestFlagsAndAppendAction):
(WebCore::ContentExtensions::DFABytecodeInterpreter::actionsFromDFARoot):
(WebCore::ContentExtensions::DFABytecodeInterpreter::interpret):
* contentextensions/DFABytecodeInterpreter.h:
* loader/ResourceLoadInfo.h:
Keep track of which actions have an if-domain trigger.  If an action is in the
filtersWithDomainsBytecode, then it either has an if-domain or an unless-domain in its trigger.
This requires additional information in the bytecode, so there are two new bytecode types.

Source/WebKit2:

* Shared/WebCompiledContentExtension.cpp:
(WebKit::WebCompiledContentExtension::filtersWithoutDomainsBytecode):
(WebKit::WebCompiledContentExtension::filtersWithoutDomainsBytecodeLength):
(WebKit::WebCompiledContentExtension::filtersWithDomainsBytecode):
(WebKit::WebCompiledContentExtension::filtersWithDomainsBytecodeLength):
(WebKit::WebCompiledContentExtension::domainFiltersBytecode):
(WebKit::WebCompiledContentExtension::domainFiltersBytecodeLength):
(WebKit::WebCompiledContentExtension::bytecode): Deleted.
(WebKit::WebCompiledContentExtension::bytecodeLength): Deleted.
* Shared/WebCompiledContentExtension.h:
* Shared/WebCompiledContentExtensionData.cpp:
(WebKit::WebCompiledContentExtensionData::encode):
(WebKit::WebCompiledContentExtensionData::decode):
* Shared/WebCompiledContentExtensionData.h:
(WebKit::WebCompiledContentExtensionData::WebCompiledContentExtensionData):
* UIProcess/API/APIUserContentExtensionStore.cpp:
(API::ContentExtensionMetaData::fileSize):
(API::encodeContentExtensionMetaData):
(API::decodeContentExtensionMetaData):
(API::compiledToFile):
(API::createExtension):
Keep track of 3 different types of bytecode to be able to handle domain-specific rules.

Tools:

* TestWebKitAPI/Tests/WebCore/ContentExtensions.cpp:
(TestWebKitAPI::InMemoryCompiledContentExtension::createFromFilter):
(TestWebKitAPI::InMemoryCompiledContentExtension::create):
(TestWebKitAPI::InMemoryCompiledContentExtension::InMemoryCompiledContentExtension):
Moved CompiledContentExtensionData from ContentExtensionCompiler.h because it is only used for testing.
(TestWebKitAPI::mainDocumentRequest):
(TestWebKitAPI::subResourceRequest):
(TestWebKitAPI::TEST_F):
(TestWebKitAPI::checkCompilerError):
Added tests for parsing and functionality of if-domain and unless-domain.

LayoutTests:

* http/tests/contentextensions/domain-rules-expected.txt: Added.
* http/tests/contentextensions/domain-rules.html: Added.
* http/tests/contentextensions/domain-rules.html.json: 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="#trunkSourceWebCorecontentextensionsCombinedURLFilterscpp">trunk/Source/WebCore/contentextensions/CombinedURLFilters.cpp</a></li>
<li><a href="#trunkSourceWebCorecontentextensionsCombinedURLFiltersh">trunk/Source/WebCore/contentextensions/CombinedURLFilters.h</a></li>
<li><a href="#trunkSourceWebCorecontentextensionsCompiledContentExtensioncpp">trunk/Source/WebCore/contentextensions/CompiledContentExtension.cpp</a></li>
<li><a href="#trunkSourceWebCorecontentextensionsCompiledContentExtensionh">trunk/Source/WebCore/contentextensions/CompiledContentExtension.h</a></li>
<li><a href="#trunkSourceWebCorecontentextensionsContentExtensionCompilercpp">trunk/Source/WebCore/contentextensions/ContentExtensionCompiler.cpp</a></li>
<li><a href="#trunkSourceWebCorecontentextensionsContentExtensionCompilerh">trunk/Source/WebCore/contentextensions/ContentExtensionCompiler.h</a></li>
<li><a href="#trunkSourceWebCorecontentextensionsContentExtensionErrorcpp">trunk/Source/WebCore/contentextensions/ContentExtensionError.cpp</a></li>
<li><a href="#trunkSourceWebCorecontentextensionsContentExtensionErrorh">trunk/Source/WebCore/contentextensions/ContentExtensionError.h</a></li>
<li><a href="#trunkSourceWebCorecontentextensionsContentExtensionParsercpp">trunk/Source/WebCore/contentextensions/ContentExtensionParser.cpp</a></li>
<li><a href="#trunkSourceWebCorecontentextensionsContentExtensionRuleh">trunk/Source/WebCore/contentextensions/ContentExtensionRule.h</a></li>
<li><a href="#trunkSourceWebCorecontentextensionsContentExtensionsBackendcpp">trunk/Source/WebCore/contentextensions/ContentExtensionsBackend.cpp</a></li>
<li><a href="#trunkSourceWebCorecontentextensionsDFABytecodeh">trunk/Source/WebCore/contentextensions/DFABytecode.h</a></li>
<li><a href="#trunkSourceWebCorecontentextensionsDFABytecodeCompilercpp">trunk/Source/WebCore/contentextensions/DFABytecodeCompiler.cpp</a></li>
<li><a href="#trunkSourceWebCorecontentextensionsDFABytecodeCompilerh">trunk/Source/WebCore/contentextensions/DFABytecodeCompiler.h</a></li>
<li><a href="#trunkSourceWebCorecontentextensionsDFABytecodeInterpretercpp">trunk/Source/WebCore/contentextensions/DFABytecodeInterpreter.cpp</a></li>
<li><a href="#trunkSourceWebCorecontentextensionsDFABytecodeInterpreterh">trunk/Source/WebCore/contentextensions/DFABytecodeInterpreter.h</a></li>
<li><a href="#trunkSourceWebCoreloaderResourceLoadInfoh">trunk/Source/WebCore/loader/ResourceLoadInfo.h</a></li>
<li><a href="#trunkSourceWebKit2ChangeLog">trunk/Source/WebKit2/ChangeLog</a></li>
<li><a href="#trunkSourceWebKit2SharedWebCompiledContentExtensioncpp">trunk/Source/WebKit2/Shared/WebCompiledContentExtension.cpp</a></li>
<li><a href="#trunkSourceWebKit2SharedWebCompiledContentExtensionh">trunk/Source/WebKit2/Shared/WebCompiledContentExtension.h</a></li>
<li><a href="#trunkSourceWebKit2SharedWebCompiledContentExtensionDatacpp">trunk/Source/WebKit2/Shared/WebCompiledContentExtensionData.cpp</a></li>
<li><a href="#trunkSourceWebKit2SharedWebCompiledContentExtensionDatah">trunk/Source/WebKit2/Shared/WebCompiledContentExtensionData.h</a></li>
<li><a href="#trunkSourceWebKit2UIProcessAPIAPIUserContentExtensionStorecpp">trunk/Source/WebKit2/UIProcess/API/APIUserContentExtensionStore.cpp</a></li>
<li><a href="#trunkToolsChangeLog">trunk/Tools/ChangeLog</a></li>
<li><a href="#trunkToolsTestWebKitAPITestsWebCoreContentExtensionscpp">trunk/Tools/TestWebKitAPI/Tests/WebCore/ContentExtensions.cpp</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestshttptestscontentextensionsdomainrulesexpectedtxt">trunk/LayoutTests/http/tests/contentextensions/domain-rules-expected.txt</a></li>
<li><a href="#trunkLayoutTestshttptestscontentextensionsdomainruleshtml">trunk/LayoutTests/http/tests/contentextensions/domain-rules.html</a></li>
<li><a href="#trunkLayoutTestshttptestscontentextensionsdomainruleshtmljson">trunk/LayoutTests/http/tests/contentextensions/domain-rules.html.json</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (184115 => 184116)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2015-05-11 19:32:59 UTC (rev 184115)
+++ trunk/LayoutTests/ChangeLog        2015-05-11 19:54:15 UTC (rev 184116)
</span><span class="lines">@@ -1,3 +1,14 @@
</span><ins>+2015-05-11  Alex Christensen  &lt;achristensen@webkit.org&gt;
+
+        [Content Extensions] Support domain-specific rules and exceptions.
+        https://bugs.webkit.org/show_bug.cgi?id=144833
+
+        Reviewed by Darin Adler.
+
+        * http/tests/contentextensions/domain-rules-expected.txt: Added.
+        * http/tests/contentextensions/domain-rules.html: Added.
+        * http/tests/contentextensions/domain-rules.html.json: Added.
+
</ins><span class="cx"> 2015-05-10  Filip Pizlo  &lt;fpizlo@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         We shouldn't promote LoadVarargs to a sequence of GetStacks and PutStacks if doing so would exceed the LoadVarargs' limit
</span></span></pre></div>
<a id="trunkLayoutTestshttptestscontentextensionsdomainrulesexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/http/tests/contentextensions/domain-rules-expected.txt (0 => 184116)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/http/tests/contentextensions/domain-rules-expected.txt                                (rev 0)
+++ trunk/LayoutTests/http/tests/contentextensions/domain-rules-expected.txt        2015-05-11 19:54:15 UTC (rev 184116)
</span><span class="lines">@@ -0,0 +1,21 @@
</span><ins>+layer at (0,0) size 800x600
+  RenderView at (0,0) size 800x600
+layer at (0,0) size 800x600
+  RenderBlock {HTML} at (0,0) size 800x600
+    RenderBody {BODY} at (8,8) size 784x584
+      RenderText {#text} at (0,0) size 200x18
+        text run at (0,0) width 200: &quot;The images below should load.&quot;
+      RenderBR {BR} at (199,14) size 1x0
+      RenderImage {IMG} at (0,18) size 100x100
+      RenderBR {BR} at (100,118) size 0x0
+      RenderImage {IMG} at (0,118) size 100x100
+      RenderBR {BR} at (100,218) size 0x0
+      RenderText {#text} at (0,218) size 242x18
+        text run at (0,218) width 242: &quot;The images below should be blocked.&quot;
+      RenderBR {BR} at (241,232) size 1x0
+      RenderImage {IMG} at (0,236) size 0x0
+      RenderBR {BR} at (0,236) size 0x0
+      RenderImage {IMG} at (0,236) size 0x0
+      RenderBR {BR} at (0,236) size 0x0
+      RenderImage {IMG} at (0,236) size 0x0
+      RenderBR {BR} at (0,236) size 0x0
</ins></span></pre></div>
<a id="trunkLayoutTestshttptestscontentextensionsdomainruleshtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/http/tests/contentextensions/domain-rules.html (0 => 184116)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/http/tests/contentextensions/domain-rules.html                                (rev 0)
+++ trunk/LayoutTests/http/tests/contentextensions/domain-rules.html        2015-05-11 19:54:15 UTC (rev 184116)
</span><span class="lines">@@ -0,0 +1,9 @@
</span><ins>+&lt;body&gt;
+The images below should load.&lt;br&gt;
+&lt;img src=&quot;http://127.0.0.1:8000/resources/square100.png?should_not_be_blocked_1&quot;&gt;&lt;br&gt;
+&lt;img src=&quot;http://127.0.0.1:8000/resources/square100.png?should_not_be_blocked_2&quot;&gt;&lt;br&gt;
+The images below should be blocked.&lt;br&gt;
+&lt;img src=&quot;http://127.0.0.1:8000/resources/square100.png?should_be_blocked_1&quot;&gt;&lt;br&gt;
+&lt;img src=&quot;http://127.0.0.1:8000/resources/square100.png?should_be_blocked_2&quot;&gt;&lt;br&gt;
+&lt;img src=&quot;http://127.0.0.1:8000/resources/square100.png?should_be_blocked_3&quot;&gt;&lt;br&gt;
+&lt;/body&gt;
</ins></span></pre></div>
<a id="trunkLayoutTestshttptestscontentextensionsdomainruleshtmljson"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/http/tests/contentextensions/domain-rules.html.json (0 => 184116)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/http/tests/contentextensions/domain-rules.html.json                                (rev 0)
+++ trunk/LayoutTests/http/tests/contentextensions/domain-rules.html.json        2015-05-11 19:54:15 UTC (rev 184116)
</span><span class="lines">@@ -0,0 +1,46 @@
</span><ins>+[
+    {
+        &quot;action&quot;: {
+            &quot;type&quot;: &quot;block&quot;
+        },
+        &quot;trigger&quot;: {
+            &quot;url-filter&quot;: &quot;should_be_blocked_1&quot;
+        }
+    },
+    {
+        &quot;action&quot;: {
+            &quot;type&quot;: &quot;block&quot;
+        },
+        &quot;trigger&quot;: {
+            &quot;url-filter&quot;: &quot;should_be_blocked_2&quot;,
+            &quot;if-domain&quot;: [&quot;127.0.0.1&quot;]
+        }
+    },
+    {
+        &quot;action&quot;: {
+            &quot;type&quot;: &quot;block&quot;
+        },
+        &quot;trigger&quot;: {
+            &quot;url-filter&quot;: &quot;should_be_blocked_3&quot;,
+            &quot;unless-domain&quot;: [&quot;this domain should not match&quot;]
+        }
+    },
+    {
+        &quot;action&quot;: {
+            &quot;type&quot;: &quot;block&quot;
+        },
+        &quot;trigger&quot;: {
+            &quot;url-filter&quot;: &quot;should_not_be_blocked_1&quot;,
+            &quot;if-domain&quot;: [&quot;this domain should not match either&quot;]
+        }
+    },
+    {
+        &quot;action&quot;: {
+            &quot;type&quot;: &quot;block&quot;
+        },
+        &quot;trigger&quot;: {
+            &quot;url-filter&quot;: &quot;should_not_be_blocked_2&quot;,
+            &quot;unless-domain&quot;: [&quot;127.0.0.1&quot;]
+        }
+    }
+]
</ins></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (184115 => 184116)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2015-05-11 19:32:59 UTC (rev 184115)
+++ trunk/Source/WebCore/ChangeLog        2015-05-11 19:54:15 UTC (rev 184116)
</span><span class="lines">@@ -1,3 +1,73 @@
</span><ins>+2015-05-11  Alex Christensen  &lt;achristensen@webkit.org&gt;
+
+        [Content Extensions] Support domain-specific rules and exceptions.
+        https://bugs.webkit.org/show_bug.cgi?id=144833
+
+        Reviewed by Darin Adler.
+
+        Test: http/tests/contentextensions/domain-rules.html
+        (And lots of API tests)
+
+        This patch adds if-domain and unless-domain to the trigger in the JSON format.
+        if-domain makes the rule apply only to domains in the list.
+        unless-domain makes the rule apply to domains that are not in the list.
+        
+        All rules without if-domain or unless-domain are compiled into a set of DFAs.  This behavior is unchanged.
+        All rules with if-domain or unless-domain are compiled into a separate set of DFAs.
+        The domains are also compiled into another set of DFAs.  This makes 3 arrays of DFA bytecode instead of 1.
+        
+        If there are no domain specific rules, there is no change in behavior.
+        If there are domain specific rules, the URL will be checked for matches in both
+        filtersWithoutDomainsBytecode and filtersWithDomainsBytecode.  If there are matches from 
+        filtersWithDomainsBytecode then the domain of the main document will be checked with 
+        domainFiltersBytecode to see which of the matches applies to this domain.
+
+        * contentextensions/CombinedURLFilters.cpp:
+        (WebCore::ContentExtensions::CombinedURLFilters::isEmpty):
+        (WebCore::ContentExtensions::CombinedURLFilters::addDomain):
+        * contentextensions/CombinedURLFilters.h:
+        Added addDomain, which adds characters from a domain to the prefix tree directly without using YARR.
+        * contentextensions/CompiledContentExtension.cpp:
+        (WebCore::ContentExtensions::CompiledContentExtension::globalDisplayNoneSelectors):
+        * contentextensions/CompiledContentExtension.h:
+        * contentextensions/ContentExtensionCompiler.cpp:
+        (WebCore::ContentExtensions::serializeActions):
+        (WebCore::ContentExtensions::compileRuleList):
+        Separate the rules into rules with domains and rules without domains and compile to bytecode.
+        * contentextensions/ContentExtensionCompiler.h:
+        Updated compiler interface to reflect the slightly more complicated structure.
+        * contentextensions/ContentExtensionError.cpp:
+        (WebCore::ContentExtensions::contentExtensionErrorCategory):
+        * contentextensions/ContentExtensionError.h:
+        Added new parsing errors.
+        * contentextensions/ContentExtensionParser.cpp:
+        (WebCore::ContentExtensions::getDomainList):
+        (WebCore::ContentExtensions::loadTrigger):
+        (WebCore::ContentExtensions::loadEncodedRules):
+        * contentextensions/ContentExtensionRule.h:
+        (WebCore::ContentExtensions::Trigger::operator==):
+        Parse the new domain structures from JSON into the Trigger structure.
+        * contentextensions/ContentExtensionsBackend.cpp:
+        (WebCore::ContentExtensions::ContentExtensionsBackend::actionsForResourceLoad):
+        Interpret as much bytecode as necessary to determine which rules apply to this URL and domain.
+        * contentextensions/DFABytecode.h:
+        (WebCore::ContentExtensions::instructionSizeWithArguments):
+        * contentextensions/DFABytecodeCompiler.cpp:
+        (WebCore::ContentExtensions::DFABytecodeCompiler::emitAppendAction):
+        (WebCore::ContentExtensions::DFABytecodeCompiler::emitTestFlagsAndAppendAction):
+        (WebCore::ContentExtensions::DFABytecodeCompiler::compileNode):
+        * contentextensions/DFABytecodeCompiler.h:
+        * contentextensions/DFABytecodeInterpreter.cpp:
+        (WebCore::ContentExtensions::DFABytecodeInterpreter::interpretAppendAction):
+        (WebCore::ContentExtensions::DFABytecodeInterpreter::interpretTestFlagsAndAppendAction):
+        (WebCore::ContentExtensions::DFABytecodeInterpreter::actionsFromDFARoot):
+        (WebCore::ContentExtensions::DFABytecodeInterpreter::interpret):
+        * contentextensions/DFABytecodeInterpreter.h:
+        * loader/ResourceLoadInfo.h:
+        Keep track of which actions have an if-domain trigger.  If an action is in the 
+        filtersWithDomainsBytecode, then it either has an if-domain or an unless-domain in its trigger.
+        This requires additional information in the bytecode, so there are two new bytecode types.
+
</ins><span class="cx"> 2015-05-11  Yoav Weiss  &lt;yoav@yoav.ws&gt;
</span><span class="cx"> 
</span><span class="cx">         Add srcset, sizes and picture to the features json
</span></span></pre></div>
<a id="trunkSourceWebCorecontentextensionsCombinedURLFilterscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/contentextensions/CombinedURLFilters.cpp (184115 => 184116)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/contentextensions/CombinedURLFilters.cpp        2015-05-11 19:32:59 UTC (rev 184115)
+++ trunk/Source/WebCore/contentextensions/CombinedURLFilters.cpp        2015-05-11 19:54:15 UTC (rev 184116)
</span><span class="lines">@@ -115,11 +115,40 @@
</span><span class="cx"> {
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-bool CombinedURLFilters::isEmpty()
</del><ins>+bool CombinedURLFilters::isEmpty() const
</ins><span class="cx"> {
</span><span class="cx">     return m_prefixTreeRoot-&gt;edges.isEmpty();
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void CombinedURLFilters::addDomain(uint64_t actionId, const String&amp; domain)
+{
+    // This is like adding (.|^)domain$ by adding two Vector&lt;Term&gt;'s,
+    // but interpreting domain as a series of characters, not a regular expression.
+    // This way a domain of &quot;webkit.org&quot; will match &quot;bugs.webkit.org&quot; and &quot;webkit.org&quot;.
+    // FIXME: Add support for matching only subdomains or no subdomains.
+    Vector&lt;Term&gt; prependDot;
+    Vector&lt;Term&gt; prependBeginningOfLine;
+    prependDot.reserveInitialCapacity(domain.length() + 3);
+    prependBeginningOfLine.reserveInitialCapacity(domain.length() + 1); // This is just no .* at the beginning.
+    
+    Term canonicalDotStar(Term::UniversalTransition);
+    canonicalDotStar.quantify(AtomQuantifier::ZeroOrMore);
+    prependDot.uncheckedAppend(canonicalDotStar);
+    prependDot.uncheckedAppend(Term('.', true));
+    
+    for (unsigned i = 0; i &lt; domain.length(); i++) {
+        ASSERT(isASCII(domain[i]));
+        ASSERT(!isASCIIUpper(domain[i]));
+        prependDot.uncheckedAppend(Term(domain[i], true));
+        prependBeginningOfLine.uncheckedAppend(Term(domain[i], true));
+    }
+    prependDot.uncheckedAppend(Term::EndOfLineAssertionTerm);
+    prependBeginningOfLine.uncheckedAppend(Term::EndOfLineAssertionTerm);
+    
+    addPattern(actionId, prependDot);
+    addPattern(actionId, prependBeginningOfLine);
+}
+
</ins><span class="cx"> void CombinedURLFilters::addPattern(uint64_t actionId, const Vector&lt;Term&gt;&amp; pattern)
</span><span class="cx"> {
</span><span class="cx">     ASSERT_WITH_MESSAGE(!pattern.isEmpty(), &quot;The parser should have excluded empty patterns before reaching CombinedURLFilters.&quot;);
</span></span></pre></div>
<a id="trunkSourceWebCorecontentextensionsCombinedURLFiltersh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/contentextensions/CombinedURLFilters.h (184115 => 184116)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/contentextensions/CombinedURLFilters.h        2015-05-11 19:32:59 UTC (rev 184115)
+++ trunk/Source/WebCore/contentextensions/CombinedURLFilters.h        2015-05-11 19:54:15 UTC (rev 184116)
</span><span class="lines">@@ -30,6 +30,7 @@
</span><span class="cx"> 
</span><span class="cx"> #include &quot;ContentExtensionsDebugging.h&quot;
</span><span class="cx"> #include &quot;NFA.h&quot;
</span><ins>+#include &lt;wtf/Forward.h&gt;
</ins><span class="cx"> #include &lt;wtf/Vector.h&gt;
</span><span class="cx"> 
</span><span class="cx"> namespace WebCore {
</span><span class="lines">@@ -44,10 +45,11 @@
</span><span class="cx">     CombinedURLFilters();
</span><span class="cx">     ~CombinedURLFilters();
</span><span class="cx"> 
</span><del>-    void addPattern(uint64_t patternId, const Vector&lt;Term&gt;&amp; pattern);
</del><ins>+    void addPattern(uint64_t actionId, const Vector&lt;Term&gt;&amp; pattern);
+    void addDomain(uint64_t actionId, const String&amp; domain);
</ins><span class="cx"> 
</span><span class="cx">     void processNFAs(size_t maxNFASize, std::function&lt;void(NFA&amp;&amp;)&gt; handler);
</span><del>-    bool isEmpty();
</del><ins>+    bool isEmpty() const;
</ins><span class="cx"> 
</span><span class="cx"> #if CONTENT_EXTENSIONS_PERFORMANCE_REPORTING
</span><span class="cx">     size_t memoryUsed() const;
</span></span></pre></div>
<a id="trunkSourceWebCorecontentextensionsCompiledContentExtensioncpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/contentextensions/CompiledContentExtension.cpp (184115 => 184116)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/contentextensions/CompiledContentExtension.cpp        2015-05-11 19:32:59 UTC (rev 184115)
+++ trunk/Source/WebCore/contentextensions/CompiledContentExtension.cpp        2015-05-11 19:54:15 UTC (rev 184116)
</span><span class="lines">@@ -38,7 +38,7 @@
</span><span class="cx"> 
</span><span class="cx"> Vector&lt;String&gt; CompiledContentExtension::globalDisplayNoneSelectors(Vector&lt;bool&gt;&amp; pagesUsed)
</span><span class="cx"> {
</span><del>-    DFABytecodeInterpreter interpreter(bytecode(), bytecodeLength(), pagesUsed);
</del><ins>+    DFABytecodeInterpreter interpreter(filtersWithoutDomainsBytecode(), filtersWithoutDomainsBytecodeLength(), pagesUsed);
</ins><span class="cx">     DFABytecodeInterpreter::Actions actionLocations = interpreter.actionsFromDFARoot();
</span><span class="cx">     
</span><span class="cx">     Vector&lt;Action&gt; globalActions;
</span></span></pre></div>
<a id="trunkSourceWebCorecontentextensionsCompiledContentExtensionh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/contentextensions/CompiledContentExtension.h (184115 => 184116)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/contentextensions/CompiledContentExtension.h        2015-05-11 19:32:59 UTC (rev 184115)
+++ trunk/Source/WebCore/contentextensions/CompiledContentExtension.h        2015-05-11 19:54:15 UTC (rev 184116)
</span><span class="lines">@@ -40,8 +40,12 @@
</span><span class="cx"> public:
</span><span class="cx">     virtual ~CompiledContentExtension();
</span><span class="cx"> 
</span><del>-    virtual const DFABytecode* bytecode() const = 0;
-    virtual unsigned bytecodeLength() const = 0;
</del><ins>+    virtual const DFABytecode* filtersWithoutDomainsBytecode() const = 0;
+    virtual unsigned filtersWithoutDomainsBytecodeLength() const = 0;
+    virtual const DFABytecode* filtersWithDomainsBytecode() const = 0;
+    virtual unsigned filtersWithDomainsBytecodeLength() const = 0;
+    virtual const DFABytecode* domainFiltersBytecode() const = 0;
+    virtual unsigned domainFiltersBytecodeLength() const = 0;
</ins><span class="cx">     virtual const SerializedActionByte* actions() const = 0;
</span><span class="cx">     virtual unsigned actionsLength() const = 0;
</span><span class="cx">     Vector&lt;String&gt; globalDisplayNoneSelectors(Vector&lt;bool&gt;&amp; pagesUsed);
</span></span></pre></div>
<a id="trunkSourceWebCorecontentextensionsContentExtensionCompilercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/contentextensions/ContentExtensionCompiler.cpp (184115 => 184116)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/contentextensions/ContentExtensionCompiler.cpp        2015-05-11 19:32:59 UTC (rev 184115)
+++ trunk/Source/WebCore/contentextensions/ContentExtensionCompiler.cpp        2015-05-11 19:54:15 UTC (rev 184116)
</span><span class="lines">@@ -96,8 +96,10 @@
</span><span class="cx">             continue;
</span><span class="cx">         }
</span><span class="cx">         
</span><del>-        // Identical sequential actions should not be rewritten.
-        if (ruleIndex &amp;&amp; rule.action() == ruleList[ruleIndex - 1].action()) {
</del><ins>+        // Identical sequential actions should not be rewritten unless there are domains in the trigger.
+        // If there are domains in the trigger, we need to distinguish the actions by index to tell if we need to apply it
+        // by comparing the output of the filters with domains and the domain filters.
+        if (ruleIndex &amp;&amp; rule.action() == ruleList[ruleIndex - 1].action() &amp;&amp; rule.trigger().domains.isEmpty()) {
</ins><span class="cx">             actionLocations.append(actionLocations[ruleIndex - 1]);
</span><span class="cx">             continue;
</span><span class="cx">         }
</span><span class="lines">@@ -156,8 +158,13 @@
</span><span class="cx"> 
</span><span class="cx">     UniversalActionLocationsSet universalActionLocations;
</span><span class="cx"> 
</span><del>-    CombinedURLFilters combinedURLFilters;
-    URLFilterParser urlFilterParser(combinedURLFilters);
</del><ins>+    // FIXME: These don't all need to be in memory at the same time.
+    CombinedURLFilters filtersWithoutDomains;
+    CombinedURLFilters filtersWithDomains;
+    CombinedURLFilters domainFilters;
+    URLFilterParser filtersWithoutDomainParser(filtersWithoutDomains);
+    URLFilterParser filtersWithDomainParser(filtersWithDomains);
+    
</ins><span class="cx">     bool ignorePreviousRulesSeen = false;
</span><span class="cx">     for (unsigned ruleIndex = 0; ruleIndex &lt; parsedRuleList.size(); ++ruleIndex) {
</span><span class="cx">         const ContentExtensionRule&amp; contentExtensionRule = parsedRuleList[ruleIndex];
</span><span class="lines">@@ -166,18 +173,39 @@
</span><span class="cx"> 
</span><span class="cx">         // High bits are used for flags. This should match how they are used in DFABytecodeCompiler::compileNode.
</span><span class="cx">         uint64_t actionLocationAndFlags = (static_cast&lt;uint64_t&gt;(trigger.flags) &lt;&lt; 32) | static_cast&lt;uint64_t&gt;(actionLocations[ruleIndex]);
</span><del>-        URLFilterParser::ParseStatus status = urlFilterParser.addPattern(trigger.urlFilter, trigger.urlFilterIsCaseSensitive, actionLocationAndFlags);
-
-        if (status == URLFilterParser::MatchesEverything) {
-            if (ignorePreviousRulesSeen)
-                return ContentExtensionError::RegexMatchesEverythingAfterIgnorePreviousRules;
-            universalActionLocations.add(actionLocationAndFlags);
</del><ins>+        URLFilterParser::ParseStatus status = URLFilterParser::Ok;
+        if (trigger.domains.isEmpty()) {
+            ASSERT(trigger.domainCondition == Trigger::DomainCondition::None);
+            status = filtersWithoutDomainParser.addPattern(trigger.urlFilter, trigger.urlFilterIsCaseSensitive, actionLocationAndFlags);
+            if (status == URLFilterParser::MatchesEverything) {
+                if (ignorePreviousRulesSeen)
+                    return ContentExtensionError::RegexMatchesEverythingAfterIgnorePreviousRules;
+                universalActionLocations.add(actionLocationAndFlags);
+                status = URLFilterParser::Ok;
+            }
+            if (status != URLFilterParser::Ok) {
+                dataLogF(&quot;Error while parsing %s: %s\n&quot;, trigger.urlFilter.utf8().data(), URLFilterParser::statusString(status).utf8().data());
+                return ContentExtensionError::JSONInvalidRegex;
+            }
+        } else {
+            if (trigger.domainCondition == Trigger::DomainCondition::IfDomain)
+                actionLocationAndFlags |= IfDomainFlag;
+            else {
+                ASSERT(trigger.domainCondition == Trigger::DomainCondition::UnlessDomain);
+                ASSERT(!(actionLocationAndFlags &amp; IfDomainFlag));
+            }
+            
+            status = filtersWithDomainParser.addPattern(trigger.urlFilter, trigger.urlFilterIsCaseSensitive, actionLocationAndFlags);
+            if (status == URLFilterParser::MatchesEverything)
+                return ContentExtensionError::RegexMatchesEverythingWithDomains;
+            if (status != URLFilterParser::Ok) {
+                dataLogF(&quot;Error while parsing %s: %s\n&quot;, trigger.urlFilter.utf8().data(), URLFilterParser::statusString(status).utf8().data());
+                return ContentExtensionError::JSONInvalidRegex;
+            }
+            for (const String&amp; domain : trigger.domains)
+                domainFilters.addDomain(actionLocationAndFlags, domain);
</ins><span class="cx">         }
</span><del>-
-        if (status != URLFilterParser::Ok &amp;&amp; status != URLFilterParser::MatchesEverything) {
-            dataLogF(&quot;Error while parsing %s: %s\n&quot;, trigger.urlFilter.utf8().data(), URLFilterParser::statusString(status).utf8().data());
-            return ContentExtensionError::JSONInvalidRegex;
-        }
</del><ins>+        ASSERT(status == URLFilterParser::Ok);
</ins><span class="cx">         
</span><span class="cx">         if (contentExtensionRule.action().type() == ActionType::IgnorePreviousRules)
</span><span class="cx">             ignorePreviousRulesSeen = true;
</span><span class="lines">@@ -192,7 +220,9 @@
</span><span class="cx">     dataLogF(&quot;    Time spent partitioning the rules into groups: %f\n&quot;, (patternPartitioningEnd - patternPartitioningStart));
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><del>-    LOG_LARGE_STRUCTURES(combinedURLFilters, combinedURLFilters.memoryUsed());
</del><ins>+    LOG_LARGE_STRUCTURES(filtersWithoutDomains, filtersWithoutDomains.memoryUsed());
+    LOG_LARGE_STRUCTURES(filtersWithDomains, filtersWithDomains.memoryUsed());
+    LOG_LARGE_STRUCTURES(domainFilters, domainFilters.memoryUsed());
</ins><span class="cx"> 
</span><span class="cx"> #if CONTENT_EXTENSIONS_PERFORMANCE_REPORTING
</span><span class="cx">     double totalNFAToByteCodeBuildTimeStart = monotonicallyIncreasingTime();
</span><span class="lines">@@ -203,8 +233,9 @@
</span><span class="cx">     
</span><span class="cx">     bool firstNFASeen = false;
</span><span class="cx">     // FIXME: Combine small NFAs to reduce the number of NFAs.
</span><del>-    combinedURLFilters.processNFAs(maxNFASize, [&amp;](NFA&amp;&amp; nfa) {
</del><ins>+    filtersWithoutDomains.processNFAs(maxNFASize, [&amp;](NFA&amp;&amp; nfa) {
</ins><span class="cx"> #if CONTENT_EXTENSIONS_STATE_MACHINE_DEBUGGING
</span><ins>+        dataLogF(&quot;filtersWithoutDomains NFA\n&quot;);
</ins><span class="cx">         nfa.debugPrintDot();
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><span class="lines">@@ -216,7 +247,7 @@
</span><span class="cx">         dfa.minimize();
</span><span class="cx"> 
</span><span class="cx"> #if CONTENT_EXTENSIONS_STATE_MACHINE_DEBUGGING
</span><del>-        WTFLogAlways(&quot;DFA&quot;);
</del><ins>+        dataLogF(&quot;filtersWithoutDomains DFA\n&quot;);
</ins><span class="cx">         dfa.debugPrintDot();
</span><span class="cx"> #endif
</span><span class="cx">         ASSERT_WITH_MESSAGE(!dfa.nodes[dfa.root].hasActions(), &quot;All actions on the DFA root should come from regular expressions that match everything.&quot;);
</span><span class="lines">@@ -230,11 +261,11 @@
</span><span class="cx">         DFABytecodeCompiler compiler(dfa, bytecode);
</span><span class="cx">         compiler.compile();
</span><span class="cx">         LOG_LARGE_STRUCTURES(bytecode, bytecode.capacity() * sizeof(uint8_t));
</span><del>-        client.writeBytecode(WTF::move(bytecode));
</del><ins>+        client.writeFiltersWithoutDomainsBytecode(WTF::move(bytecode));
</ins><span class="cx"> 
</span><span class="cx">         firstNFASeen = true;
</span><span class="cx">     });
</span><del>-    ASSERT(combinedURLFilters.isEmpty());
</del><ins>+    ASSERT(filtersWithoutDomains.isEmpty());
</ins><span class="cx"> 
</span><span class="cx">     if (!firstNFASeen) {
</span><span class="cx">         // Our bytecode interpreter expects to have at least one DFA, so if we haven't seen any
</span><span class="lines">@@ -249,12 +280,62 @@
</span><span class="cx">         DFABytecodeCompiler compiler(dummyDFA, bytecode);
</span><span class="cx">         compiler.compile();
</span><span class="cx">         LOG_LARGE_STRUCTURES(bytecode, bytecode.capacity() * sizeof(uint8_t));
</span><del>-        client.writeBytecode(WTF::move(bytecode));
</del><ins>+        client.writeFiltersWithoutDomainsBytecode(WTF::move(bytecode));
</ins><span class="cx">     }
</span><del>-
</del><span class="cx">     LOG_LARGE_STRUCTURES(universalActionLocations, universalActionLocations.capacity() * sizeof(unsigned));
</span><span class="cx">     universalActionLocations.clear();
</span><ins>+    
+    filtersWithDomains.processNFAs(maxNFASize, [&amp;](NFA&amp;&amp; nfa) {
+#if CONTENT_EXTENSIONS_STATE_MACHINE_DEBUGGING
+        dataLogF(&quot;filtersWithDomains NFA\n&quot;);
+        nfa.debugPrintDot();
+#endif
+        LOG_LARGE_STRUCTURES(nfa, nfa.memoryUsed());
+        DFA dfa = NFAToDFA::convert(nfa);
+#if CONTENT_EXTENSIONS_STATE_MACHINE_DEBUGGING
+        dataLogF(&quot;filtersWithDomains PRE MINIMIZING DFA\n&quot;);
+        dfa.debugPrintDot();
+#endif
+        LOG_LARGE_STRUCTURES(dfa, dfa.memoryUsed());
+        // Minimizing this DFA would not be effective because all actions with domains are unique.
+#if CONTENT_EXTENSIONS_STATE_MACHINE_DEBUGGING
+        dataLogF(&quot;filtersWithDomains POST MINIMIZING DFA\n&quot;);
+        dfa.debugPrintDot();
+#endif
+        ASSERT_WITH_MESSAGE(!dfa.nodes[dfa.root].hasActions(), &quot;Filters with domains that match everything are not allowed right now.&quot;);
+        
+        Vector&lt;DFABytecode&gt; bytecode;
+        DFABytecodeCompiler compiler(dfa, bytecode);
+        compiler.compile();
+        LOG_LARGE_STRUCTURES(bytecode, bytecode.capacity() * sizeof(uint8_t));
+        client.writeFiltersWithDomainsBytecode(WTF::move(bytecode));
+    });
+    ASSERT(filtersWithDomains.isEmpty());
</ins><span class="cx"> 
</span><ins>+    domainFilters.processNFAs(maxNFASize, [&amp;](NFA&amp;&amp; nfa) {
+#if CONTENT_EXTENSIONS_STATE_MACHINE_DEBUGGING
+        dataLogF(&quot;domainFilters NFA\n&quot;);
+        nfa.debugPrintDot();
+#endif
+        LOG_LARGE_STRUCTURES(nfa, nfa.memoryUsed());
+        DFA dfa = NFAToDFA::convert(nfa);
+#if CONTENT_EXTENSIONS_STATE_MACHINE_DEBUGGING
+        dataLogF(&quot;domainFilters DFA\n&quot;);
+        dfa.debugPrintDot();
+#endif
+        LOG_LARGE_STRUCTURES(dfa, dfa.memoryUsed());
+        // Minimizing this DFA would not be effective because all actions are unique
+        // and because of the tree-like structure of this DFA.
+        ASSERT_WITH_MESSAGE(!dfa.nodes[dfa.root].hasActions(), &quot;There should not be any domains that match everything.&quot;);
+        
+        Vector&lt;DFABytecode&gt; bytecode;
+        DFABytecodeCompiler compiler(dfa, bytecode);
+        compiler.compile();
+        LOG_LARGE_STRUCTURES(bytecode, bytecode.capacity() * sizeof(uint8_t));
+        client.writeDomainFiltersBytecode(WTF::move(bytecode));
+    });
+    ASSERT(domainFilters.isEmpty());    
+    
</ins><span class="cx"> #if CONTENT_EXTENSIONS_PERFORMANCE_REPORTING
</span><span class="cx">     double totalNFAToByteCodeBuildTimeEnd = monotonicallyIncreasingTime();
</span><span class="cx">     dataLogF(&quot;    Time spent building and compiling the DFAs: %f\n&quot;, (totalNFAToByteCodeBuildTimeEnd - totalNFAToByteCodeBuildTimeStart));
</span></span></pre></div>
<a id="trunkSourceWebCorecontentextensionsContentExtensionCompilerh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/contentextensions/ContentExtensionCompiler.h (184115 => 184116)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/contentextensions/ContentExtensionCompiler.h        2015-05-11 19:32:59 UTC (rev 184115)
+++ trunk/Source/WebCore/contentextensions/ContentExtensionCompiler.h        2015-05-11 19:54:15 UTC (rev 184116)
</span><span class="lines">@@ -36,17 +36,15 @@
</span><span class="cx"> namespace WebCore {
</span><span class="cx"> namespace ContentExtensions {
</span><span class="cx"> 
</span><del>-struct CompiledContentExtensionData {
-    Vector&lt;DFABytecode&gt; bytecode;
-    Vector&lt;SerializedActionByte&gt; actions;
-};
-
</del><span class="cx"> class ContentExtensionCompilationClient {
</span><span class="cx"> public:
</span><span class="cx">     virtual ~ContentExtensionCompilationClient() { }
</span><span class="cx">     
</span><del>-    virtual void writeBytecode(Vector&lt;DFABytecode&gt;&amp;&amp;) = 0;
</del><ins>+    // Functions should be called in this order. All except writeActions and finalize can be called multiple times, though.
</ins><span class="cx">     virtual void writeActions(Vector&lt;SerializedActionByte&gt;&amp;&amp;) = 0;
</span><ins>+    virtual void writeFiltersWithoutDomainsBytecode(Vector&lt;DFABytecode&gt;&amp;&amp;) = 0;
+    virtual void writeFiltersWithDomainsBytecode(Vector&lt;DFABytecode&gt;&amp;&amp;) = 0;
+    virtual void writeDomainFiltersBytecode(Vector&lt;DFABytecode&gt;&amp;&amp;) = 0;
</ins><span class="cx">     virtual void finalize() = 0;
</span><span class="cx"> };
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCorecontentextensionsContentExtensionErrorcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/contentextensions/ContentExtensionError.cpp (184115 => 184116)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/contentextensions/ContentExtensionError.cpp        2015-05-11 19:32:59 UTC (rev 184115)
+++ trunk/Source/WebCore/contentextensions/ContentExtensionError.cpp        2015-05-11 19:54:15 UTC (rev 184116)
</span><span class="lines">@@ -77,6 +77,14 @@
</span><span class="cx">                 return &quot;Invalid or unsupported regular expression.&quot;;
</span><span class="cx">             case ContentExtensionError::RegexMatchesEverythingAfterIgnorePreviousRules:
</span><span class="cx">                 return &quot;Regular expressions that match everything are only allowed before the first ignore-previous-rules.&quot;;
</span><ins>+            case ContentExtensionError::RegexMatchesEverythingWithDomains:
+                return &quot;Regular expressions that match everything are not allowed with unless- or if-domain.&quot;;
+            case ContentExtensionError::JSONInvalidDomainList:
+                return &quot;Invalid domain list.&quot;;
+            case ContentExtensionError::JSONDomainNotLowerCaseASCII:
+                return &quot;Domains must be lower case ASCII.  Use punycode to encode non-ASCII characters.&quot;;
+            case ContentExtensionError::JSONUnlessAndIfDomain:
+                return &quot;A trigger cannot have both unless- and if-domain.&quot;;
</ins><span class="cx">             }
</span><span class="cx"> 
</span><span class="cx">             return std::string();
</span></span></pre></div>
<a id="trunkSourceWebCorecontentextensionsContentExtensionErrorh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/contentextensions/ContentExtensionError.h (184115 => 184116)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/contentextensions/ContentExtensionError.h        2015-05-11 19:32:59 UTC (rev 184115)
+++ trunk/Source/WebCore/contentextensions/ContentExtensionError.h        2015-05-11 19:54:15 UTC (rev 184116)
</span><span class="lines">@@ -49,6 +49,9 @@
</span><span class="cx">     JSONInvalidTriggerFlagsArray,
</span><span class="cx">     JSONInvalidObjectInTriggerFlagsArray,
</span><span class="cx">     JSONInvalidStringInTriggerFlagsArray,
</span><ins>+    JSONInvalidDomainList,
+    JSONDomainNotLowerCaseASCII,
+    JSONUnlessAndIfDomain,
</ins><span class="cx">     
</span><span class="cx">     JSONInvalidAction,
</span><span class="cx">     JSONInvalidActionType,
</span><span class="lines">@@ -56,9 +59,10 @@
</span><span class="cx">     JSONInvalidRegex,
</span><span class="cx">     
</span><span class="cx">     RegexMatchesEverythingAfterIgnorePreviousRules,
</span><ins>+    RegexMatchesEverythingWithDomains,
</ins><span class="cx"> };
</span><span class="cx"> 
</span><del>-const std::error_category&amp; contentExtensionErrorCategory();
</del><ins>+WEBCORE_EXPORT const std::error_category&amp; contentExtensionErrorCategory();
</ins><span class="cx"> 
</span><span class="cx"> inline std::error_code make_error_code(ContentExtensionError error)
</span><span class="cx"> {
</span></span></pre></div>
<a id="trunkSourceWebCorecontentextensionsContentExtensionParsercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/contentextensions/ContentExtensionParser.cpp (184115 => 184116)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/contentextensions/ContentExtensionParser.cpp        2015-05-11 19:32:59 UTC (rev 184115)
+++ trunk/Source/WebCore/contentextensions/ContentExtensionParser.cpp        2015-05-11 19:54:15 UTC (rev 184116)
</span><span class="lines">@@ -46,6 +46,41 @@
</span><span class="cx"> namespace WebCore {
</span><span class="cx"> 
</span><span class="cx"> namespace ContentExtensions {
</span><ins>+    
+static bool containsOnlyASCIIWithNoUppercase(const String&amp; domain)
+{
+    for (unsigned i = 0; i &lt; domain.length(); ++i) {
+        UChar c = domain.at(i);
+        if (!isASCII(c) || isASCIIUpper(c))
+            return false;
+    }
+    return true;
+}
+    
+static std::error_code getDomainList(ExecState&amp; exec, JSObject* arrayObject, Vector&lt;String&gt;&amp; vector)
+{
+    ASSERT(vector.isEmpty());
+    if (!arrayObject || !isJSArray(arrayObject))
+        return ContentExtensionError::JSONInvalidDomainList;
+    JSArray* array = jsCast&lt;JSArray*&gt;(arrayObject);
+    
+    unsigned length = array-&gt;length();
+    for (unsigned i = 0; i &lt; length; ++i) {
+        // FIXME: JSObject::getIndex should be marked as const.
+        JSValue value = array-&gt;getIndex(&amp;exec, i);
+        if (exec.hadException() || !value.isString())
+            return ContentExtensionError::JSONInvalidDomainList;
+        
+        // Domains should be punycode encoded lower case.
+        const String&amp; domain = jsCast&lt;JSString*&gt;(value)-&gt;value(&amp;exec);
+        if (domain.isEmpty())
+            return ContentExtensionError::JSONInvalidDomainList;
+        if (!containsOnlyASCIIWithNoUppercase(domain))
+            return ContentExtensionError::JSONDomainNotLowerCaseASCII;
+        vector.append(domain);
+    }
+    return { };
+}
</ins><span class="cx"> 
</span><span class="cx"> static std::error_code getTypeFlags(ExecState&amp; exec, const JSValue&amp; typeValue, ResourceFlags&amp; flags, uint16_t (*stringToType)(const String&amp;))
</span><span class="cx"> {
</span><span class="lines">@@ -109,6 +144,29 @@
</span><span class="cx">             return typeFlagsError;
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    JSValue ifDomain = triggerObject.get(&amp;exec, Identifier::fromString(&amp;exec, &quot;if-domain&quot;));
+    if (!exec.hadException() &amp;&amp; ifDomain.isObject()) {
+        auto ifDomainError = getDomainList(exec, asObject(ifDomain), trigger.domains);
+        if (ifDomainError)
+            return ifDomainError;
+        if (trigger.domains.isEmpty())
+            return ContentExtensionError::JSONInvalidDomainList;
+        ASSERT(trigger.domainCondition == Trigger::DomainCondition::None);
+        trigger.domainCondition = Trigger::DomainCondition::IfDomain;
+    }
+    
+    JSValue unlessDomain = triggerObject.get(&amp;exec, Identifier::fromString(&amp;exec, &quot;unless-domain&quot;));
+    if (!exec.hadException() &amp;&amp; unlessDomain.isObject()) {
+        if (trigger.domainCondition != Trigger::DomainCondition::None)
+            return ContentExtensionError::JSONUnlessAndIfDomain;
+        auto unlessDomainError = getDomainList(exec, asObject(unlessDomain), trigger.domains);
+        if (unlessDomainError)
+            return unlessDomainError;
+        if (trigger.domains.isEmpty())
+            return ContentExtensionError::JSONInvalidDomainList;
+        trigger.domainCondition = Trigger::DomainCondition::UnlessDomain;
+    }
+
</ins><span class="cx">     return { };
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -160,6 +218,7 @@
</span><span class="cx"> 
</span><span class="cx"> static std::error_code loadEncodedRules(ExecState&amp; exec, const String&amp; rules, Vector&lt;ContentExtensionRule&gt;&amp; ruleList)
</span><span class="cx"> {
</span><ins>+    // FIXME: JSONParse should require callbacks instead of an ExecState.
</ins><span class="cx">     JSValue decodedRules = JSONParse(&amp;exec, rules);
</span><span class="cx"> 
</span><span class="cx">     if (exec.hadException() || !decodedRules)
</span></span></pre></div>
<a id="trunkSourceWebCorecontentextensionsContentExtensionRuleh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/contentextensions/ContentExtensionRule.h (184115 => 184116)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/contentextensions/ContentExtensionRule.h        2015-05-11 19:32:59 UTC (rev 184115)
+++ trunk/Source/WebCore/contentextensions/ContentExtensionRule.h        2015-05-11 19:54:15 UTC (rev 184116)
</span><span class="lines">@@ -45,11 +45,25 @@
</span><span class="cx">     String urlFilter;
</span><span class="cx">     bool urlFilterIsCaseSensitive { false };
</span><span class="cx">     ResourceFlags flags { 0 };
</span><ins>+    Vector&lt;String&gt; domains;
+    enum class DomainCondition {
+        None,
+        IfDomain,
+        UnlessDomain,
+    } domainCondition { DomainCondition::None };
+    
+    ~Trigger()
+    {
+        ASSERT(domains.isEmpty() == (domainCondition == DomainCondition::None));
+    }
+    
</ins><span class="cx">     bool operator==(const Trigger&amp; other) const
</span><span class="cx">     {
</span><span class="cx">         return urlFilter == other.urlFilter
</span><span class="cx">             &amp;&amp; urlFilterIsCaseSensitive == other.urlFilterIsCaseSensitive
</span><del>-            &amp;&amp; flags == other.flags;
</del><ins>+            &amp;&amp; flags == other.flags
+            &amp;&amp; domains == other.domains
+            &amp;&amp; domainCondition == other.domainCondition;
</ins><span class="cx">     }
</span><span class="cx"> };
</span><span class="cx">     
</span></span></pre></div>
<a id="trunkSourceWebCorecontentextensionsContentExtensionsBackendcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/contentextensions/ContentExtensionsBackend.cpp (184115 => 184116)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/contentextensions/ContentExtensionsBackend.cpp        2015-05-11 19:32:59 UTC (rev 184115)
+++ trunk/Source/WebCore/contentextensions/ContentExtensionsBackend.cpp        2015-05-11 19:54:15 UTC (rev 184116)
</span><span class="lines">@@ -88,9 +88,41 @@
</span><span class="cx">     for (auto&amp; contentExtension : m_contentExtensions.values()) {
</span><span class="cx">         RELEASE_ASSERT(contentExtension);
</span><span class="cx">         const CompiledContentExtension&amp; compiledExtension = contentExtension-&gt;compiledExtension();
</span><del>-        DFABytecodeInterpreter interpreter(compiledExtension.bytecode(), compiledExtension.bytecodeLength(), contentExtension-&gt;m_pagesUsed);
-        DFABytecodeInterpreter::Actions triggeredActions = interpreter.interpret(urlCString, flags);
</del><span class="cx">         
</span><ins>+        // FIXME: These should use a different Vector&lt;bool&gt; to keep track of which memory pages are used when doing memory reporting. Or just remove the memory reporting completely.
+        DFABytecodeInterpreter withoutDomainsInterpreter(compiledExtension.filtersWithoutDomainsBytecode(), compiledExtension.filtersWithoutDomainsBytecodeLength(), contentExtension-&gt;m_pagesUsed);
+        DFABytecodeInterpreter::Actions triggeredActions = withoutDomainsInterpreter.interpret(urlCString, flags);
+        
+        // Check to see if there are any actions triggered with if- or unless-domain and check the domain if there are.
+        DFABytecodeInterpreter withDomainsInterpreter(compiledExtension.filtersWithDomainsBytecode(), compiledExtension.filtersWithDomainsBytecodeLength(), contentExtension-&gt;m_pagesUsed);
+        
+        DFABytecodeInterpreter::Actions withDomainsPossibleActions = withDomainsInterpreter.interpret(urlCString, flags);
+        if (!withDomainsPossibleActions.isEmpty()) {
+            DFABytecodeInterpreter domainsInterpreter(compiledExtension.domainFiltersBytecode(), compiledExtension.domainFiltersBytecodeLength(), contentExtension-&gt;m_pagesUsed);
+            DFABytecodeInterpreter::Actions domainsActions = domainsInterpreter.interpret(resourceLoadInfo.mainDocumentURL.host().utf8(), flags);
+            
+            DFABytecodeInterpreter::Actions ifDomainActions;
+            DFABytecodeInterpreter::Actions unlessDomainActions;
+            for (uint64_t action : domainsActions) {
+                if (action &amp; IfDomainFlag)
+                    ifDomainActions.add(action);
+                else
+                    unlessDomainActions.add(action);
+            }
+            
+            for (uint64_t action : withDomainsPossibleActions) {
+                if (ifDomainActions.contains(action)) {
+                    // If an if-domain trigger matches, add the action.
+                    ASSERT(action &amp; IfDomainFlag);
+                    triggeredActions.add(action &amp; ~IfDomainFlag);
+                } else if (!(action &amp; IfDomainFlag) &amp;&amp; !unlessDomainActions.contains(action)) {
+                    // If this action did not need an if-domain, it must have been an unless-domain rule.
+                    // Add the action unless it matched an unless-domain trigger.
+                    triggeredActions.add(action);
+                }
+            }
+        }
+        
</ins><span class="cx">         const SerializedActionByte* actions = compiledExtension.actions();
</span><span class="cx">         const unsigned actionsLength = compiledExtension.actionsLength();
</span><span class="cx">         
</span><span class="lines">@@ -114,8 +146,9 @@
</span><span class="cx">             }
</span><span class="cx">         }
</span><span class="cx">         if (!sawIgnorePreviousRules) {
</span><del>-            DFABytecodeInterpreter::Actions universalActions = interpreter.actionsFromDFARoot();
-            for (auto actionLocation : universalActions) {
</del><ins>+            DFABytecodeInterpreter::Actions universalActions = withoutDomainsInterpreter.actionsFromDFARoot();
+            for (uint64_t actionLocation : universalActions) {
+                // FIXME: We shouldn't deserialize an action all the way if it is a css-display-none selector.
</ins><span class="cx">                 Action action = Action::deserialize(actions, actionsLength, static_cast&lt;unsigned&gt;(actionLocation));
</span><span class="cx">                 action.setExtensionIdentifier(contentExtension-&gt;identifier());
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCorecontentextensionsDFABytecodeh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/contentextensions/DFABytecode.h (184115 => 184116)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/contentextensions/DFABytecode.h        2015-05-11 19:32:59 UTC (rev 184115)
+++ trunk/Source/WebCore/contentextensions/DFABytecode.h        2015-05-11 19:54:15 UTC (rev 184116)
</span><span class="lines">@@ -52,11 +52,13 @@
</span><span class="cx">     // AppendAction has one argument:
</span><span class="cx">     // The action to append (4 bytes).
</span><span class="cx">     AppendAction,
</span><ins>+    AppendActionWithIfDomain,
</ins><span class="cx">     
</span><span class="cx">     // TestFlagsAndAppendAction has two arguments:
</span><del>-    // The flags to check before appending (2 bytes),
-    // The action to append (4bytes).
</del><ins>+    // The flags to check before appending (2 bytes).
+    // The action to append (4 bytes).
</ins><span class="cx">     TestFlagsAndAppendAction,
</span><ins>+    TestFlagsAndAppendActionWithIfDomain,
</ins><span class="cx"> 
</span><span class="cx">     // Terminate has no arguments.
</span><span class="cx">     Terminate,
</span><span class="lines">@@ -76,8 +78,10 @@
</span><span class="cx">     case DFABytecodeInstruction::CheckValueRangeCaseInsensitive:
</span><span class="cx">         return sizeof(DFABytecodeInstruction) + sizeof(uint8_t) + sizeof(uint8_t) + sizeof(unsigned);
</span><span class="cx">     case DFABytecodeInstruction::AppendAction:
</span><ins>+    case DFABytecodeInstruction::AppendActionWithIfDomain:
</ins><span class="cx">         return sizeof(DFABytecodeInstruction) + sizeof(unsigned);
</span><span class="cx">     case DFABytecodeInstruction::TestFlagsAndAppendAction:
</span><ins>+    case DFABytecodeInstruction::TestFlagsAndAppendActionWithIfDomain:
</ins><span class="cx">         return sizeof(DFABytecodeInstruction) + sizeof(uint16_t) + sizeof(unsigned);
</span><span class="cx">     case DFABytecodeInstruction::Terminate:
</span><span class="cx">         return sizeof(DFABytecodeInstruction);
</span></span></pre></div>
<a id="trunkSourceWebCorecontentextensionsDFABytecodeCompilercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/contentextensions/DFABytecodeCompiler.cpp (184115 => 184116)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/contentextensions/DFABytecodeCompiler.cpp        2015-05-11 19:32:59 UTC (rev 184115)
+++ trunk/Source/WebCore/contentextensions/DFABytecodeCompiler.cpp        2015-05-11 19:54:15 UTC (rev 184116)
</span><span class="lines">@@ -48,16 +48,22 @@
</span><span class="cx">     *reinterpret_cast&lt;unsigned*&gt;(&amp;bytecode[index]) = value;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void DFABytecodeCompiler::emitAppendAction(unsigned action)
</del><ins>+void DFABytecodeCompiler::emitAppendAction(unsigned action, bool ifDomain)
</ins><span class="cx"> {
</span><del>-    append&lt;DFABytecodeInstruction&gt;(m_bytecode, DFABytecodeInstruction::AppendAction);
</del><ins>+    if (ifDomain)
+        append&lt;DFABytecodeInstruction&gt;(m_bytecode, DFABytecodeInstruction::AppendActionWithIfDomain);
+    else
+        append&lt;DFABytecodeInstruction&gt;(m_bytecode, DFABytecodeInstruction::AppendAction);
</ins><span class="cx">     append&lt;unsigned&gt;(m_bytecode, action);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void DFABytecodeCompiler::emitTestFlagsAndAppendAction(uint16_t flags, unsigned action)
</del><ins>+void DFABytecodeCompiler::emitTestFlagsAndAppendAction(uint16_t flags, unsigned action, bool ifDomain)
</ins><span class="cx"> {
</span><span class="cx">     ASSERT(flags);
</span><del>-    append&lt;DFABytecodeInstruction&gt;(m_bytecode, DFABytecodeInstruction::TestFlagsAndAppendAction);
</del><ins>+    if (ifDomain)
+        append&lt;DFABytecodeInstruction&gt;(m_bytecode, DFABytecodeInstruction::TestFlagsAndAppendActionWithIfDomain);
+    else
+        append&lt;DFABytecodeInstruction&gt;(m_bytecode, DFABytecodeInstruction::TestFlagsAndAppendAction);
</ins><span class="cx">     append&lt;uint16_t&gt;(m_bytecode, flags);
</span><span class="cx">     append&lt;unsigned&gt;(m_bytecode, action);
</span><span class="cx"> }
</span><span class="lines">@@ -106,11 +112,11 @@
</span><span class="cx">         m_nodeStartOffsets[index] = m_bytecode.size();
</span><span class="cx"> 
</span><span class="cx">     for (uint64_t action : node.actions(m_dfa)) {
</span><del>-        // High bits are used to store flags. See compileRuleList.
</del><ins>+        // High bits are used to store flags. A boolean is stored in the 48th bit. See compileRuleList.
</ins><span class="cx">         if (action &amp; 0xFFFF00000000)
</span><del>-            emitTestFlagsAndAppendAction(static_cast&lt;uint16_t&gt;(action &gt;&gt; 32), static_cast&lt;unsigned&gt;(action));
</del><ins>+            emitTestFlagsAndAppendAction(static_cast&lt;uint16_t&gt;(action &gt;&gt; 32), static_cast&lt;unsigned&gt;(action), action &amp; IfDomainFlag);
</ins><span class="cx">         else
</span><del>-            emitAppendAction(static_cast&lt;unsigned&gt;(action));
</del><ins>+            emitAppendAction(static_cast&lt;unsigned&gt;(action), action &amp; IfDomainFlag);
</ins><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     // If we jump to the root, we don't want to re-add its actions to a HashSet.
</span></span></pre></div>
<a id="trunkSourceWebCorecontentextensionsDFABytecodeCompilerh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/contentextensions/DFABytecodeCompiler.h (184115 => 184116)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/contentextensions/DFABytecodeCompiler.h        2015-05-11 19:32:59 UTC (rev 184115)
+++ trunk/Source/WebCore/contentextensions/DFABytecodeCompiler.h        2015-05-11 19:54:15 UTC (rev 184116)
</span><span class="lines">@@ -66,8 +66,8 @@
</span><span class="cx">     void compileNodeTransitions(const DFANode&amp;);
</span><span class="cx">     void compileCheckForRange(const Range&amp;);
</span><span class="cx"> 
</span><del>-    void emitAppendAction(unsigned);
-    void emitTestFlagsAndAppendAction(uint16_t flags, unsigned);
</del><ins>+    void emitAppendAction(unsigned, bool ifDomain);
+    void emitTestFlagsAndAppendAction(uint16_t flags, unsigned, bool ifDomain);
</ins><span class="cx">     void emitJump(unsigned destinationNodeIndex);
</span><span class="cx">     void emitCheckValue(uint8_t value, unsigned destinationNodeIndex, bool caseSensitive);
</span><span class="cx">     void emitCheckValueRange(uint8_t lowValue, uint8_t highValue, unsigned destinationNodeIndex, bool caseSensitive);
</span></span></pre></div>
<a id="trunkSourceWebCorecontentextensionsDFABytecodeInterpretercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/contentextensions/DFABytecodeInterpreter.cpp (184115 => 184116)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/contentextensions/DFABytecodeInterpreter.cpp        2015-05-11 19:32:59 UTC (rev 184115)
+++ trunk/Source/WebCore/contentextensions/DFABytecodeInterpreter.cpp        2015-05-11 19:54:15 UTC (rev 184116)
</span><span class="lines">@@ -50,18 +50,20 @@
</span><span class="cx">     return *reinterpret_cast&lt;const IntType*&gt;(&amp;bytecode[index]);
</span><span class="cx"> }
</span><span class="cx">     
</span><del>-void DFABytecodeInterpreter::interpretAppendAction(unsigned&amp; programCounter, Actions&amp; actions)
</del><ins>+void DFABytecodeInterpreter::interpretAppendAction(unsigned&amp; programCounter, Actions&amp; actions, bool ifDomain)
</ins><span class="cx"> {
</span><del>-    ASSERT(getBits&lt;DFABytecodeInstruction&gt;(m_bytecode, m_bytecodeLength, programCounter, m_pagesUsed) == DFABytecodeInstruction::AppendAction);
-    actions.add(static_cast&lt;uint64_t&gt;(getBits&lt;unsigned&gt;(m_bytecode, m_bytecodeLength, programCounter + sizeof(DFABytecode), m_pagesUsed)));
</del><ins>+    ASSERT(getBits&lt;DFABytecodeInstruction&gt;(m_bytecode, m_bytecodeLength, programCounter, m_pagesUsed) == DFABytecodeInstruction::AppendAction
+        || getBits&lt;DFABytecodeInstruction&gt;(m_bytecode, m_bytecodeLength, programCounter, m_pagesUsed) == DFABytecodeInstruction::AppendActionWithIfDomain);
+    actions.add((ifDomain ? IfDomainFlag : 0) | static_cast&lt;uint64_t&gt;(getBits&lt;unsigned&gt;(m_bytecode, m_bytecodeLength, programCounter + sizeof(DFABytecode), m_pagesUsed)));
</ins><span class="cx">     programCounter += instructionSizeWithArguments(DFABytecodeInstruction::AppendAction);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void DFABytecodeInterpreter::interpretTestFlagsAndAppendAction(unsigned&amp; programCounter, uint16_t flags, Actions&amp; actions)
</del><ins>+void DFABytecodeInterpreter::interpretTestFlagsAndAppendAction(unsigned&amp; programCounter, uint16_t flags, Actions&amp; actions, bool ifDomain)
</ins><span class="cx"> {
</span><del>-    ASSERT(getBits&lt;DFABytecodeInstruction&gt;(m_bytecode, m_bytecodeLength, programCounter, m_pagesUsed) == DFABytecodeInstruction::TestFlagsAndAppendAction);
</del><ins>+    ASSERT(getBits&lt;DFABytecodeInstruction&gt;(m_bytecode, m_bytecodeLength, programCounter, m_pagesUsed) == DFABytecodeInstruction::TestFlagsAndAppendAction
+        || getBits&lt;DFABytecodeInstruction&gt;(m_bytecode, m_bytecodeLength, programCounter, m_pagesUsed) == DFABytecodeInstruction::TestFlagsAndAppendActionWithIfDomain);
</ins><span class="cx">     if (flags &amp; getBits&lt;uint16_t&gt;(m_bytecode, m_bytecodeLength, programCounter + sizeof(DFABytecode), m_pagesUsed))
</span><del>-        actions.add(static_cast&lt;uint64_t&gt;(getBits&lt;unsigned&gt;(m_bytecode, m_bytecodeLength, programCounter + sizeof(DFABytecode) + sizeof(uint16_t), m_pagesUsed)));
</del><ins>+        actions.add((ifDomain ? IfDomainFlag : 0) | static_cast&lt;uint64_t&gt;(getBits&lt;unsigned&gt;(m_bytecode, m_bytecodeLength, programCounter + sizeof(DFABytecode) + sizeof(uint16_t), m_pagesUsed)));
</ins><span class="cx">     programCounter += instructionSizeWithArguments(DFABytecodeInstruction::TestFlagsAndAppendAction);
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -76,7 +78,7 @@
</span><span class="cx">     while (programCounter &lt; dfaBytecodeLength) {
</span><span class="cx">         DFABytecodeInstruction instruction = static_cast&lt;DFABytecodeInstruction&gt;(m_bytecode[programCounter]);
</span><span class="cx">         if (instruction == DFABytecodeInstruction::AppendAction)
</span><del>-            interpretAppendAction(programCounter, actions);
</del><ins>+            interpretAppendAction(programCounter, actions, false);
</ins><span class="cx">         else if (instruction == DFABytecodeInstruction::TestFlagsAndAppendAction)
</span><span class="cx">             programCounter += instructionSizeWithArguments(DFABytecodeInstruction::TestFlagsAndAppendAction);
</span><span class="cx">         else
</span><span class="lines">@@ -107,7 +109,7 @@
</span><span class="cx">                 if (instruction == DFABytecodeInstruction::AppendAction)
</span><span class="cx">                     programCounter += instructionSizeWithArguments(DFABytecodeInstruction::AppendAction);
</span><span class="cx">                 else if (instruction == DFABytecodeInstruction::TestFlagsAndAppendAction)
</span><del>-                    interpretTestFlagsAndAppendAction(programCounter, flags, actions);
</del><ins>+                    interpretTestFlagsAndAppendAction(programCounter, flags, actions, false);
</ins><span class="cx">                 else
</span><span class="cx">                     break;
</span><span class="cx">             }
</span><span class="lines">@@ -203,12 +205,20 @@
</span><span class="cx">                 break;
</span><span class="cx">                     
</span><span class="cx">             case DFABytecodeInstruction::AppendAction:
</span><del>-                interpretAppendAction(programCounter, actions);
</del><ins>+                interpretAppendAction(programCounter, actions, false);
</ins><span class="cx">                 break;
</span><span class="cx">                     
</span><ins>+            case DFABytecodeInstruction::AppendActionWithIfDomain:
+                interpretAppendAction(programCounter, actions, true);
+                break;
+                    
</ins><span class="cx">             case DFABytecodeInstruction::TestFlagsAndAppendAction:
</span><del>-                interpretTestFlagsAndAppendAction(programCounter, flags, actions);
</del><ins>+                interpretTestFlagsAndAppendAction(programCounter, flags, actions, false);
</ins><span class="cx">                 break;
</span><ins>+            
+            case DFABytecodeInstruction::TestFlagsAndAppendActionWithIfDomain:
+                interpretTestFlagsAndAppendAction(programCounter, flags, actions, true);
+                break;
</ins><span class="cx">                     
</span><span class="cx">             default:
</span><span class="cx">                 RELEASE_ASSERT_NOT_REACHED(); // Invalid bytecode.
</span></span></pre></div>
<a id="trunkSourceWebCorecontentextensionsDFABytecodeInterpreterh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/contentextensions/DFABytecodeInterpreter.h (184115 => 184116)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/contentextensions/DFABytecodeInterpreter.h        2015-05-11 19:32:59 UTC (rev 184115)
+++ trunk/Source/WebCore/contentextensions/DFABytecodeInterpreter.h        2015-05-11 19:54:15 UTC (rev 184116)
</span><span class="lines">@@ -63,8 +63,8 @@
</span><span class="cx">     Actions actionsFromDFARoot();
</span><span class="cx"> 
</span><span class="cx"> private:
</span><del>-    void interpretAppendAction(unsigned&amp; programCounter, Actions&amp;);
-    void interpretTestFlagsAndAppendAction(unsigned&amp; programCounter, uint16_t flags, Actions&amp;);
</del><ins>+    void interpretAppendAction(unsigned&amp; programCounter, Actions&amp;, bool ifDomain);
+    void interpretTestFlagsAndAppendAction(unsigned&amp; programCounter, uint16_t flags, Actions&amp;, bool ifDomain);
</ins><span class="cx">     const DFABytecode* m_bytecode;
</span><span class="cx">     const unsigned m_bytecodeLength;
</span><span class="cx">     Vector&lt;bool&gt;&amp; m_pagesUsed;
</span></span></pre></div>
<a id="trunkSourceWebCoreloaderResourceLoadInfoh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/loader/ResourceLoadInfo.h (184115 => 184116)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/loader/ResourceLoadInfo.h        2015-05-11 19:32:59 UTC (rev 184115)
+++ trunk/Source/WebCore/loader/ResourceLoadInfo.h        2015-05-11 19:54:15 UTC (rev 184116)
</span><span class="lines">@@ -53,6 +53,12 @@
</span><span class="cx"> 
</span><span class="cx"> typedef uint16_t ResourceFlags;
</span><span class="cx"> 
</span><ins>+// The first 32 bits of a uint64_t action are used for the action location.
+// The next 16 bits are used for the flags (ResourceType and LoadType).
+// The next bit is used to mark actions that are from a rule with an if-domain condition.
+// The values -1 and -2 are used for removed and empty values in HashTables.
+const uint64_t IfDomainFlag = 0x0001000000000000;
+
</ins><span class="cx"> ResourceType toResourceType(CachedResource::Type);
</span><span class="cx"> uint16_t readResourceType(const String&amp;);
</span><span class="cx"> uint16_t readLoadType(const String&amp;);
</span></span></pre></div>
<a id="trunkSourceWebKit2ChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/ChangeLog (184115 => 184116)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/ChangeLog        2015-05-11 19:32:59 UTC (rev 184115)
+++ trunk/Source/WebKit2/ChangeLog        2015-05-11 19:54:15 UTC (rev 184116)
</span><span class="lines">@@ -1,3 +1,33 @@
</span><ins>+2015-05-11  Alex Christensen  &lt;achristensen@webkit.org&gt;
+
+        [Content Extensions] Support domain-specific rules and exceptions.
+        https://bugs.webkit.org/show_bug.cgi?id=144833
+
+        Reviewed by Darin Adler.
+
+        * Shared/WebCompiledContentExtension.cpp:
+        (WebKit::WebCompiledContentExtension::filtersWithoutDomainsBytecode):
+        (WebKit::WebCompiledContentExtension::filtersWithoutDomainsBytecodeLength):
+        (WebKit::WebCompiledContentExtension::filtersWithDomainsBytecode):
+        (WebKit::WebCompiledContentExtension::filtersWithDomainsBytecodeLength):
+        (WebKit::WebCompiledContentExtension::domainFiltersBytecode):
+        (WebKit::WebCompiledContentExtension::domainFiltersBytecodeLength):
+        (WebKit::WebCompiledContentExtension::bytecode): Deleted.
+        (WebKit::WebCompiledContentExtension::bytecodeLength): Deleted.
+        * Shared/WebCompiledContentExtension.h:
+        * Shared/WebCompiledContentExtensionData.cpp:
+        (WebKit::WebCompiledContentExtensionData::encode):
+        (WebKit::WebCompiledContentExtensionData::decode):
+        * Shared/WebCompiledContentExtensionData.h:
+        (WebKit::WebCompiledContentExtensionData::WebCompiledContentExtensionData):
+        * UIProcess/API/APIUserContentExtensionStore.cpp:
+        (API::ContentExtensionMetaData::fileSize):
+        (API::encodeContentExtensionMetaData):
+        (API::decodeContentExtensionMetaData):
+        (API::compiledToFile):
+        (API::createExtension):
+        Keep track of 3 different types of bytecode to be able to handle domain-specific rules.
+
</ins><span class="cx"> 2015-05-11  Tim Horton  &lt;timothy_horton@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Page overlay action context override should indicate the source of the request
</span></span></pre></div>
<a id="trunkSourceWebKit2SharedWebCompiledContentExtensioncpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/Shared/WebCompiledContentExtension.cpp (184115 => 184116)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/Shared/WebCompiledContentExtension.cpp        2015-05-11 19:32:59 UTC (rev 184115)
+++ trunk/Source/WebKit2/Shared/WebCompiledContentExtension.cpp        2015-05-11 19:54:15 UTC (rev 184116)
</span><span class="lines">@@ -44,16 +44,36 @@
</span><span class="cx"> {
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-const WebCore::ContentExtensions::DFABytecode* WebCompiledContentExtension::bytecode() const
</del><ins>+const WebCore::ContentExtensions::DFABytecode* WebCompiledContentExtension::filtersWithoutDomainsBytecode() const
</ins><span class="cx"> {
</span><del>-    return static_cast&lt;const WebCore::ContentExtensions::DFABytecode*&gt;(m_data.data-&gt;data()) + m_data.bytecodeOffset;
</del><ins>+    return static_cast&lt;const WebCore::ContentExtensions::DFABytecode*&gt;(m_data.data-&gt;data()) + m_data.filtersWithoutDomainsBytecodeOffset;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-unsigned WebCompiledContentExtension::bytecodeLength() const
</del><ins>+unsigned WebCompiledContentExtension::filtersWithoutDomainsBytecodeLength() const
</ins><span class="cx"> {
</span><del>-    return m_data.bytecodeSize;
</del><ins>+    return m_data.filtersWithoutDomainsBytecodeSize;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+const WebCore::ContentExtensions::DFABytecode* WebCompiledContentExtension::filtersWithDomainsBytecode() const
+{
+    return static_cast&lt;const WebCore::ContentExtensions::DFABytecode*&gt;(m_data.data-&gt;data()) + m_data.filtersWithDomainsBytecodeOffset;
+}
+
+unsigned WebCompiledContentExtension::filtersWithDomainsBytecodeLength() const
+{
+    return m_data.filtersWithDomainsBytecodeSize;
+}
+
+const WebCore::ContentExtensions::DFABytecode* WebCompiledContentExtension::domainFiltersBytecode() const
+{
+    return static_cast&lt;const WebCore::ContentExtensions::DFABytecode*&gt;(m_data.data-&gt;data()) + m_data.domainFiltersBytecodeOffset;
+}
+
+unsigned WebCompiledContentExtension::domainFiltersBytecodeLength() const
+{
+    return m_data.domainFiltersBytecodeSize;
+}
+
</ins><span class="cx"> const WebCore::ContentExtensions::SerializedActionByte* WebCompiledContentExtension::actions() const
</span><span class="cx"> {
</span><span class="cx">     return static_cast&lt;const WebCore::ContentExtensions::SerializedActionByte*&gt;(m_data.data-&gt;data()) + m_data.actionsOffset;
</span></span></pre></div>
<a id="trunkSourceWebKit2SharedWebCompiledContentExtensionh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/Shared/WebCompiledContentExtension.h (184115 => 184116)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/Shared/WebCompiledContentExtension.h        2015-05-11 19:32:59 UTC (rev 184115)
+++ trunk/Source/WebKit2/Shared/WebCompiledContentExtension.h        2015-05-11 19:54:15 UTC (rev 184116)
</span><span class="lines">@@ -44,8 +44,13 @@
</span><span class="cx"> private:
</span><span class="cx">     WebCompiledContentExtension(WebCompiledContentExtensionData&amp;&amp;);
</span><span class="cx"> 
</span><del>-    virtual const WebCore::ContentExtensions::DFABytecode* bytecode() const override;
-    virtual unsigned bytecodeLength() const override;
</del><ins>+    virtual const WebCore::ContentExtensions::DFABytecode* filtersWithoutDomainsBytecode() const override;
+    virtual unsigned filtersWithoutDomainsBytecodeLength() const override;
+    virtual const WebCore::ContentExtensions::DFABytecode* filtersWithDomainsBytecode() const override;
+    virtual unsigned filtersWithDomainsBytecodeLength() const override;
+    virtual const WebCore::ContentExtensions::DFABytecode* domainFiltersBytecode() const override;
+    virtual unsigned domainFiltersBytecodeLength() const override;
+    
</ins><span class="cx">     virtual const WebCore::ContentExtensions::SerializedActionByte* actions() const override;
</span><span class="cx">     virtual unsigned actionsLength() const override;
</span><span class="cx">     
</span></span></pre></div>
<a id="trunkSourceWebKit2SharedWebCompiledContentExtensionDatacpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/Shared/WebCompiledContentExtensionData.cpp (184115 => 184116)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/Shared/WebCompiledContentExtensionData.cpp        2015-05-11 19:32:59 UTC (rev 184115)
+++ trunk/Source/WebKit2/Shared/WebCompiledContentExtensionData.cpp        2015-05-11 19:54:15 UTC (rev 184116)
</span><span class="lines">@@ -40,8 +40,12 @@
</span><span class="cx"> 
</span><span class="cx">     encoder &lt;&lt; actionsOffset;
</span><span class="cx">     encoder &lt;&lt; actionsSize;
</span><del>-    encoder &lt;&lt; bytecodeOffset;
-    encoder &lt;&lt; bytecodeSize;
</del><ins>+    encoder &lt;&lt; filtersWithoutDomainsBytecodeOffset;
+    encoder &lt;&lt; filtersWithoutDomainsBytecodeSize;
+    encoder &lt;&lt; filtersWithDomainsBytecodeOffset;
+    encoder &lt;&lt; filtersWithDomainsBytecodeSize;
+    encoder &lt;&lt; domainFiltersBytecodeOffset;
+    encoder &lt;&lt; domainFiltersBytecodeSize;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> bool WebCompiledContentExtensionData::decode(IPC::ArgumentDecoder&amp; decoder, WebCompiledContentExtensionData&amp; compiledContentExtensionData)
</span><span class="lines">@@ -55,10 +59,18 @@
</span><span class="cx">         return false;
</span><span class="cx">     if (!decoder.decode(compiledContentExtensionData.actionsSize))
</span><span class="cx">         return false;
</span><del>-    if (!decoder.decode(compiledContentExtensionData.bytecodeOffset))
</del><ins>+    if (!decoder.decode(compiledContentExtensionData.filtersWithoutDomainsBytecodeOffset))
</ins><span class="cx">         return false;
</span><del>-    if (!decoder.decode(compiledContentExtensionData.bytecodeSize))
</del><ins>+    if (!decoder.decode(compiledContentExtensionData.filtersWithoutDomainsBytecodeSize))
</ins><span class="cx">         return false;
</span><ins>+    if (!decoder.decode(compiledContentExtensionData.filtersWithDomainsBytecodeOffset))
+        return false;
+    if (!decoder.decode(compiledContentExtensionData.filtersWithDomainsBytecodeSize))
+        return false;
+    if (!decoder.decode(compiledContentExtensionData.domainFiltersBytecodeOffset))
+        return false;
+    if (!decoder.decode(compiledContentExtensionData.domainFiltersBytecodeSize))
+        return false;
</ins><span class="cx"> 
</span><span class="cx">     return true;
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkSourceWebKit2SharedWebCompiledContentExtensionDatah"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/Shared/WebCompiledContentExtensionData.h (184115 => 184116)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/Shared/WebCompiledContentExtensionData.h        2015-05-11 19:32:59 UTC (rev 184115)
+++ trunk/Source/WebKit2/Shared/WebCompiledContentExtensionData.h        2015-05-11 19:54:15 UTC (rev 184116)
</span><span class="lines">@@ -45,13 +45,17 @@
</span><span class="cx">     {
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    WebCompiledContentExtensionData(RefPtr&lt;SharedMemory&gt;&amp;&amp; data, NetworkCache::Data fileData, unsigned actionsOffset, unsigned actionsSize, unsigned bytecodeOffset, unsigned bytecodeSize)
</del><ins>+    WebCompiledContentExtensionData(RefPtr&lt;SharedMemory&gt;&amp;&amp; data, NetworkCache::Data fileData, unsigned actionsOffset, unsigned actionsSize, unsigned filtersWithoutDomainsBytecodeOffset, unsigned filtersWithoutDomainsBytecodeSize, unsigned filtersWithDomainsBytecodeOffset, unsigned filtersWithDomainsBytecodeSize, unsigned domainFiltersBytecodeOffset, unsigned domainFiltersBytecodeSize)
</ins><span class="cx">         : data(WTF::move(data))
</span><span class="cx">         , fileData(fileData)
</span><span class="cx">         , actionsOffset(actionsOffset)
</span><span class="cx">         , actionsSize(actionsSize)
</span><del>-        , bytecodeOffset(bytecodeOffset)
-        , bytecodeSize(bytecodeSize)
</del><ins>+        , filtersWithoutDomainsBytecodeOffset(filtersWithoutDomainsBytecodeOffset)
+        , filtersWithoutDomainsBytecodeSize(filtersWithoutDomainsBytecodeSize)
+        , filtersWithDomainsBytecodeOffset(filtersWithDomainsBytecodeOffset)
+        , filtersWithDomainsBytecodeSize(filtersWithDomainsBytecodeSize)
+        , domainFiltersBytecodeOffset(domainFiltersBytecodeOffset)
+        , domainFiltersBytecodeSize(domainFiltersBytecodeSize)
</ins><span class="cx">     {
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -62,8 +66,12 @@
</span><span class="cx">     NetworkCache::Data fileData;
</span><span class="cx">     unsigned actionsOffset { 0 };
</span><span class="cx">     unsigned actionsSize { 0 };
</span><del>-    unsigned bytecodeOffset { 0 };
-    unsigned bytecodeSize { 0 };
</del><ins>+    unsigned filtersWithoutDomainsBytecodeOffset { 0 };
+    unsigned filtersWithoutDomainsBytecodeSize { 0 };
+    unsigned filtersWithDomainsBytecodeOffset { 0 };
+    unsigned filtersWithDomainsBytecodeSize { 0 };
+    unsigned domainFiltersBytecodeOffset { 0 };
+    unsigned domainFiltersBytecodeSize { 0 };
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkSourceWebKit2UIProcessAPIAPIUserContentExtensionStorecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/UIProcess/API/APIUserContentExtensionStore.cpp (184115 => 184116)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/UIProcess/API/APIUserContentExtensionStore.cpp        2015-05-11 19:32:59 UTC (rev 184115)
+++ trunk/Source/WebKit2/UIProcess/API/APIUserContentExtensionStore.cpp        2015-05-11 19:54:15 UTC (rev 184116)
</span><span class="lines">@@ -74,11 +74,22 @@
</span><span class="cx">     return WebCore::pathByAppendingComponent(base, &quot;ContentExtension-&quot; + WebCore::encodeForFileName(identifier));
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-const size_t ContentExtensionFileHeaderSize = sizeof(uint32_t) + 2 * sizeof(uint64_t);
</del><ins>+const size_t ContentExtensionFileHeaderSize = sizeof(uint32_t) + 4 * sizeof(uint64_t);
</ins><span class="cx"> struct ContentExtensionMetaData {
</span><del>-    uint32_t version { 1 };
</del><ins>+    uint32_t version { 2 };
</ins><span class="cx">     uint64_t actionsSize { 0 };
</span><del>-    uint64_t bytecodeSize { 0 };
</del><ins>+    uint64_t filtersWithoutDomainsBytecodeSize { 0 };
+    uint64_t filtersWithDomainBytecodeSize { 0 };
+    uint64_t domainFiltersBytecodeSize { 0 };
+    
+    size_t fileSize() const
+    {
+        return ContentExtensionFileHeaderSize
+            + actionsSize
+            + filtersWithoutDomainsBytecodeSize
+            + filtersWithDomainBytecodeSize
+            + domainFiltersBytecodeSize;
+    }
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> static Data encodeContentExtensionMetaData(const ContentExtensionMetaData&amp; metaData)
</span><span class="lines">@@ -87,7 +98,9 @@
</span><span class="cx"> 
</span><span class="cx">     encoder &lt;&lt; metaData.version;
</span><span class="cx">     encoder &lt;&lt; metaData.actionsSize;
</span><del>-    encoder &lt;&lt; metaData.bytecodeSize;
</del><ins>+    encoder &lt;&lt; metaData.filtersWithoutDomainsBytecodeSize;
+    encoder &lt;&lt; metaData.filtersWithDomainBytecodeSize;
+    encoder &lt;&lt; metaData.domainFiltersBytecodeSize;
</ins><span class="cx"> 
</span><span class="cx">     ASSERT(encoder.bufferSize() == ContentExtensionFileHeaderSize);
</span><span class="cx">     return Data(encoder.buffer(), encoder.bufferSize());
</span><span class="lines">@@ -107,8 +120,12 @@
</span><span class="cx">             return false;
</span><span class="cx">         if (!decoder.decode(metaData.actionsSize))
</span><span class="cx">             return false;
</span><del>-        if (!decoder.decode(metaData.bytecodeSize))
</del><ins>+        if (!decoder.decode(metaData.filtersWithoutDomainsBytecodeSize))
</ins><span class="cx">             return false;
</span><ins>+        if (!decoder.decode(metaData.filtersWithDomainBytecodeSize))
+            return false;
+        if (!decoder.decode(metaData.domainFiltersBytecodeSize))
+            return false;
</ins><span class="cx">         success = true;
</span><span class="cx">         return false;
</span><span class="cx">     });
</span><span class="lines">@@ -163,39 +180,62 @@
</span><span class="cx">             : m_fileHandle(fileHandle)
</span><span class="cx">             , m_metaData(metaData)
</span><span class="cx">         {
</span><ins>+            ASSERT(!metaData.actionsSize);
+            ASSERT(!metaData.filtersWithoutDomainsBytecodeSize);
+            ASSERT(!metaData.filtersWithDomainBytecodeSize);
+            ASSERT(!metaData.domainFiltersBytecodeSize);
</ins><span class="cx">         }
</span><del>-
-        virtual void writeBytecode(Vector&lt;DFABytecode&gt;&amp;&amp; bytecode) override
</del><ins>+        
+        virtual void writeFiltersWithoutDomainsBytecode(Vector&lt;DFABytecode&gt;&amp;&amp; bytecode)
</ins><span class="cx">         {
</span><del>-            m_bytecodeWritten += bytecode.size();
-            write(Data(bytecode.data(), bytecode.size()));
</del><ins>+            ASSERT(!m_filtersWithDomainBytecodeWritten);
+            ASSERT(!m_domainFiltersBytecodeWritten);
+            m_filtersWithoutDomainsBytecodeWritten += bytecode.size();
+            writeToFile(Data(bytecode.data(), bytecode.size()));
</ins><span class="cx">         }
</span><ins>+        
+        virtual void writeFiltersWithDomainsBytecode(Vector&lt;DFABytecode&gt;&amp;&amp; bytecode)
+        {
+            ASSERT(!m_domainFiltersBytecodeWritten);
+            m_filtersWithDomainBytecodeWritten += bytecode.size();
+            writeToFile(Data(bytecode.data(), bytecode.size()));
+        }
+        
+        virtual void writeDomainFiltersBytecode(Vector&lt;DFABytecode&gt;&amp;&amp; bytecode)
+        {
+            m_domainFiltersBytecodeWritten += bytecode.size();
+            writeToFile(Data(bytecode.data(), bytecode.size()));
+        }
</ins><span class="cx"> 
</span><span class="cx">         virtual void writeActions(Vector&lt;SerializedActionByte&gt;&amp;&amp; actions) override
</span><span class="cx">         {
</span><del>-            ASSERT(!m_bytecodeWritten);
</del><ins>+            ASSERT(!m_filtersWithoutDomainsBytecodeWritten);
+            ASSERT(!m_filtersWithDomainBytecodeWritten);
+            ASSERT(!m_domainFiltersBytecodeWritten);
</ins><span class="cx">             ASSERT(!m_actionsWritten);
</span><span class="cx">             m_actionsWritten += actions.size();
</span><del>-            write(Data(actions.data(), actions.size()));
</del><ins>+            writeToFile(Data(actions.data(), actions.size()));
</ins><span class="cx">         }
</span><span class="cx">         
</span><span class="cx">         virtual void finalize() override
</span><span class="cx">         {
</span><span class="cx">             m_metaData.actionsSize = m_actionsWritten;
</span><del>-            m_metaData.bytecodeSize = m_bytecodeWritten;
</del><ins>+            m_metaData.filtersWithoutDomainsBytecodeSize = m_filtersWithoutDomainsBytecodeWritten;
+            m_metaData.filtersWithDomainBytecodeSize = m_filtersWithDomainBytecodeWritten;
+            m_metaData.domainFiltersBytecodeSize = m_domainFiltersBytecodeWritten;
</ins><span class="cx">             
</span><span class="cx">             Data header = encodeContentExtensionMetaData(m_metaData);
</span><span class="cx">             if (!m_fileError &amp;&amp; WebCore::seekFile(m_fileHandle, 0ll, WebCore::FileSeekOrigin::SeekFromBeginning) == -1) {
</span><span class="cx">                 WebCore::closeFile(m_fileHandle);
</span><span class="cx">                 m_fileError = true;
</span><span class="cx">             }
</span><del>-            write(header);
</del><ins>+            writeToFile(header);
</ins><span class="cx">         }
</span><span class="cx">         
</span><span class="cx">         bool hadErrorWhileWritingToFile() { return m_fileError; }
</span><span class="cx"> 
</span><span class="cx">     private:
</span><del>-        void write(const Data&amp; data)
</del><ins>+        void writeToFile(const Data&amp; data)
</ins><span class="cx">         {
</span><span class="cx">             if (!m_fileError &amp;&amp; !writeDataToFile(data, m_fileHandle)) {
</span><span class="cx">                 WebCore::closeFile(m_fileHandle);
</span><span class="lines">@@ -205,7 +245,9 @@
</span><span class="cx">         
</span><span class="cx">         WebCore::PlatformFileHandle m_fileHandle;
</span><span class="cx">         ContentExtensionMetaData&amp; m_metaData;
</span><del>-        size_t m_bytecodeWritten { 0 };
</del><ins>+        size_t m_filtersWithoutDomainsBytecodeWritten { 0 };
+        size_t m_filtersWithDomainBytecodeWritten { 0 };
+        size_t m_domainFiltersBytecodeWritten { 0 };
</ins><span class="cx">         size_t m_actionsWritten { 0 };
</span><span class="cx">         bool m_fileError { false };
</span><span class="cx">     };
</span><span class="lines">@@ -228,7 +270,7 @@
</span><span class="cx">     if (compilationClient.hadErrorWhileWritingToFile())
</span><span class="cx">         return UserContentExtensionStore::Error::CompileFailed;
</span><span class="cx">     
</span><del>-    mappedData = mapFile(temporaryFileHandle, 0, ContentExtensionFileHeaderSize + metaData.actionsSize + metaData.bytecodeSize);
</del><ins>+    mappedData = mapFile(temporaryFileHandle, 0, metaData.fileSize());
</ins><span class="cx">     WebCore::closeFile(temporaryFileHandle);
</span><span class="cx"> 
</span><span class="cx">     if (mappedData.isNull())
</span><span class="lines">@@ -248,8 +290,18 @@
</span><span class="cx">         fileData,
</span><span class="cx">         ContentExtensionFileHeaderSize,
</span><span class="cx">         metaData.actionsSize,
</span><del>-        ContentExtensionFileHeaderSize + metaData.actionsSize,
-        metaData.bytecodeSize
</del><ins>+        ContentExtensionFileHeaderSize
+            + metaData.actionsSize,
+        metaData.filtersWithoutDomainsBytecodeSize,
+        ContentExtensionFileHeaderSize
+            + metaData.actionsSize
+            + metaData.filtersWithoutDomainsBytecodeSize,
+        metaData.filtersWithDomainBytecodeSize,
+        ContentExtensionFileHeaderSize
+            + metaData.actionsSize
+            + metaData.filtersWithoutDomainsBytecodeSize
+            + metaData.filtersWithDomainBytecodeSize,
+        metaData.domainFiltersBytecodeSize
</ins><span class="cx">     );
</span><span class="cx">     auto compiledContentExtension = WebKit::WebCompiledContentExtension::create(WTF::move(compiledContentExtensionData));
</span><span class="cx">     return API::UserContentExtension::create(identifier, WTF::move(compiledContentExtension));
</span></span></pre></div>
<a id="trunkToolsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Tools/ChangeLog (184115 => 184116)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/ChangeLog        2015-05-11 19:32:59 UTC (rev 184115)
+++ trunk/Tools/ChangeLog        2015-05-11 19:54:15 UTC (rev 184116)
</span><span class="lines">@@ -1,3 +1,21 @@
</span><ins>+2015-05-11  Alex Christensen  &lt;achristensen@webkit.org&gt;
+
+        [Content Extensions] Support domain-specific rules and exceptions.
+        https://bugs.webkit.org/show_bug.cgi?id=144833
+
+        Reviewed by Darin Adler.
+
+        * TestWebKitAPI/Tests/WebCore/ContentExtensions.cpp:
+        (TestWebKitAPI::InMemoryCompiledContentExtension::createFromFilter):
+        (TestWebKitAPI::InMemoryCompiledContentExtension::create):
+        (TestWebKitAPI::InMemoryCompiledContentExtension::InMemoryCompiledContentExtension):
+        Moved CompiledContentExtensionData from ContentExtensionCompiler.h because it is only used for testing.
+        (TestWebKitAPI::mainDocumentRequest):
+        (TestWebKitAPI::subResourceRequest):
+        (TestWebKitAPI::TEST_F):
+        (TestWebKitAPI::checkCompilerError):
+        Added tests for parsing and functionality of if-domain and unless-domain.
+
</ins><span class="cx"> 2015-05-11  Ryosuke Niwa  &lt;rniwa@webkit.org&gt;
</span><span class="cx"> 
</span><span class="cx">         run-benchmark should support Chrome Canary and Firefox Nightly
</span></span></pre></div>
<a id="trunkToolsTestWebKitAPITestsWebCoreContentExtensionscpp"></a>
<div class="modfile"><h4>Modified: trunk/Tools/TestWebKitAPI/Tests/WebCore/ContentExtensions.cpp (184115 => 184116)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/Tests/WebCore/ContentExtensions.cpp        2015-05-11 19:32:59 UTC (rev 184115)
+++ trunk/Tools/TestWebKitAPI/Tests/WebCore/ContentExtensions.cpp        2015-05-11 19:54:15 UTC (rev 184116)
</span><span class="lines">@@ -80,34 +80,62 @@
</span><span class="cx">     }
</span><span class="cx"> };
</span><span class="cx"> 
</span><del>-class InMemoryContentExtensionCompilationClient final : public WebCore::ContentExtensions::ContentExtensionCompilationClient {
</del><ins>+struct CompiledContentExtensionData {
+    Vector&lt;ContentExtensions::SerializedActionByte&gt; actions;
+    Vector&lt;ContentExtensions::DFABytecode&gt; filtersWithoutDomains;
+    Vector&lt;ContentExtensions::DFABytecode&gt; filtersWithDomains;
+    Vector&lt;ContentExtensions::DFABytecode&gt; domainFilters;
+};
+
+class InMemoryContentExtensionCompilationClient final : public ContentExtensions::ContentExtensionCompilationClient {
</ins><span class="cx"> public:
</span><del>-    InMemoryContentExtensionCompilationClient(WebCore::ContentExtensions::CompiledContentExtensionData&amp; data)
</del><ins>+    InMemoryContentExtensionCompilationClient(CompiledContentExtensionData&amp; data)
</ins><span class="cx">         : m_data(data)
</span><span class="cx">     {
</span><del>-        EXPECT_EQ(data.bytecode.size(), 0ull);
</del><span class="cx">         EXPECT_EQ(data.actions.size(), 0ull);
</span><ins>+        EXPECT_EQ(data.filtersWithoutDomains.size(), 0ull);
+        EXPECT_EQ(data.filtersWithDomains.size(), 0ull);
+        EXPECT_EQ(data.domainFilters.size(), 0ull);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    virtual void writeBytecode(Vector&lt;WebCore::ContentExtensions::DFABytecode&gt;&amp;&amp; bytecode) override
</del><ins>+    virtual void writeActions(Vector&lt;ContentExtensions::SerializedActionByte&gt;&amp;&amp; actions) override
</ins><span class="cx">     {
</span><span class="cx">         EXPECT_FALSE(finalized);
</span><del>-        m_data.bytecode.appendVector(bytecode);
</del><ins>+        EXPECT_EQ(m_data.actions.size(), 0ull);
+        EXPECT_EQ(m_data.filtersWithoutDomains.size(), 0ull);
+        EXPECT_EQ(m_data.filtersWithDomains.size(), 0ull);
+        EXPECT_EQ(m_data.domainFilters.size(), 0ull);
+        m_data.actions.appendVector(actions);
</ins><span class="cx">     }
</span><span class="cx">     
</span><del>-    virtual void writeActions(Vector&lt;WebCore::ContentExtensions::SerializedActionByte&gt;&amp;&amp; actions) override
</del><ins>+    virtual void writeFiltersWithoutDomainsBytecode(Vector&lt;ContentExtensions::DFABytecode&gt;&amp;&amp; bytecode) override
</ins><span class="cx">     {
</span><span class="cx">         EXPECT_FALSE(finalized);
</span><del>-        m_data.actions.appendVector(actions);
</del><ins>+        EXPECT_EQ(m_data.filtersWithDomains.size(), 0ull);
+        EXPECT_EQ(m_data.domainFilters.size(), 0ull);
+        m_data.filtersWithoutDomains.appendVector(bytecode);
</ins><span class="cx">     }
</span><span class="cx">     
</span><ins>+    virtual void writeFiltersWithDomainsBytecode(Vector&lt;ContentExtensions::DFABytecode&gt;&amp;&amp; bytecode) override
+    {
+        EXPECT_FALSE(finalized);
+        EXPECT_EQ(m_data.domainFilters.size(), 0ull);
+        m_data.filtersWithDomains.appendVector(bytecode);
+    }
+    
+    virtual void writeDomainFiltersBytecode(Vector&lt;ContentExtensions::DFABytecode&gt;&amp;&amp; bytecode) override
+    {
+        EXPECT_FALSE(finalized);
+        m_data.domainFilters.appendVector(bytecode);
+    }
+    
</ins><span class="cx">     virtual void finalize() override
</span><span class="cx">     {
</span><span class="cx">         finalized = true;
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx"> private:
</span><del>-    WebCore::ContentExtensions::CompiledContentExtensionData&amp; m_data;
</del><ins>+    CompiledContentExtensionData&amp; m_data;
</ins><span class="cx">     bool finalized { false };
</span><span class="cx"> };
</span><span class="cx"> 
</span><span class="lines">@@ -115,16 +143,19 @@
</span><span class="cx"> public:
</span><span class="cx">     static RefPtr&lt;InMemoryCompiledContentExtension&gt; createFromFilter(String&amp;&amp; filter)
</span><span class="cx">     {
</span><del>-        WebCore::ContentExtensions::CompiledContentExtensionData extensionData;
</del><ins>+        CompiledContentExtensionData extensionData;
</ins><span class="cx">         InMemoryContentExtensionCompilationClient client(extensionData);
</span><span class="cx">         auto compilerError = ContentExtensions::compileRuleList(client, WTF::move(filter));
</span><del>-        if (compilerError)
</del><ins>+        if (compilerError) {
+            // Compiling should always succeed here. We have other tests for compile failures.
+            EXPECT_TRUE(false);
</ins><span class="cx">             return nullptr;
</span><ins>+        }
</ins><span class="cx"> 
</span><span class="cx">         return InMemoryCompiledContentExtension::create(WTF::move(extensionData));
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    static RefPtr&lt;InMemoryCompiledContentExtension&gt; create(ContentExtensions::CompiledContentExtensionData&amp;&amp; data)
</del><ins>+    static RefPtr&lt;InMemoryCompiledContentExtension&gt; create(CompiledContentExtensionData&amp;&amp; data)
</ins><span class="cx">     {
</span><span class="cx">         return adoptRef(new InMemoryCompiledContentExtension(WTF::move(data)));
</span><span class="cx">     }
</span><span class="lines">@@ -133,18 +164,22 @@
</span><span class="cx">     {
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    virtual const ContentExtensions::DFABytecode* bytecode() const override { return m_data.bytecode.data(); }
-    virtual unsigned bytecodeLength() const override { return m_data.bytecode.size(); }
</del><span class="cx">     virtual const ContentExtensions::SerializedActionByte* actions() const override { return m_data.actions.data(); }
</span><span class="cx">     virtual unsigned actionsLength() const override { return m_data.actions.size(); }
</span><ins>+    virtual const ContentExtensions::DFABytecode* filtersWithoutDomainsBytecode() const override { return m_data.filtersWithoutDomains.data(); }
+    virtual unsigned filtersWithoutDomainsBytecodeLength() const override { return m_data.filtersWithoutDomains.size(); }
+    virtual const ContentExtensions::DFABytecode* filtersWithDomainsBytecode() const override { return m_data.filtersWithDomains.data(); }
+    virtual unsigned filtersWithDomainsBytecodeLength() const override { return m_data.filtersWithDomains.size(); }
+    virtual const ContentExtensions::DFABytecode* domainFiltersBytecode() const override { return m_data.domainFilters.data(); }
+    virtual unsigned domainFiltersBytecodeLength() const override { return m_data.domainFilters.size(); }
</ins><span class="cx"> 
</span><span class="cx"> private:
</span><del>-    InMemoryCompiledContentExtension(ContentExtensions::CompiledContentExtensionData&amp;&amp; data)
</del><ins>+    InMemoryCompiledContentExtension(CompiledContentExtensionData&amp;&amp; data)
</ins><span class="cx">         : m_data(WTF::move(data))
</span><span class="cx">     {
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    ContentExtensions::CompiledContentExtensionData m_data;
</del><ins>+    CompiledContentExtensionData m_data;
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> void static testRequest(ContentExtensions::ContentExtensionsBackend contentExtensionsBackend, const ResourceLoadInfo&amp; resourceLoadInfo, Vector&lt;ContentExtensions::ActionType&gt; expectedActions, bool ignorePreviousRules = false)
</span><span class="lines">@@ -164,11 +199,16 @@
</span><span class="cx">         EXPECT_EQ(actions[actions.size() - 1].type(), ContentExtensions::ActionType::CSSDisplayNoneStyleSheet);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-ResourceLoadInfo mainDocumentRequest(const char* url, ResourceType resourceType = ResourceType::Document)
</del><ins>+static ResourceLoadInfo mainDocumentRequest(const char* url, ResourceType resourceType = ResourceType::Document)
</ins><span class="cx"> {
</span><span class="cx">     return { URL(URL(), url), URL(URL(), url), resourceType };
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+static ResourceLoadInfo subResourceRequest(const char* url, const char* mainDocumentURL, ResourceType resourceType = ResourceType::Document)
+{
+    return { URL(URL(), url), URL(URL(), mainDocumentURL), resourceType };
+}
+
</ins><span class="cx"> ContentExtensions::ContentExtensionsBackend makeBackend(const char* json)
</span><span class="cx"> {
</span><span class="cx">     auto extension = InMemoryCompiledContentExtension::createFromFilter(json);
</span><span class="lines">@@ -362,6 +402,79 @@
</span><span class="cx">     testRequest(backend, mainDocumentRequest(&quot;https://post.org/post&quot;), { });
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+TEST_F(ContentExtensionTest, DomainTriggers)
+{
+    auto ifDomainBackend = makeBackend(&quot;[{\&quot;action\&quot;:{\&quot;type\&quot;:\&quot;block\&quot;},\&quot;trigger\&quot;:{\&quot;url-filter\&quot;:\&quot;test\\\\.html\&quot;, \&quot;if-domain\&quot;:[\&quot;webkit.org\&quot;]}}]&quot;);
+    testRequest(ifDomainBackend, mainDocumentRequest(&quot;http://webkit.org/test.htm&quot;), { });
+    testRequest(ifDomainBackend, mainDocumentRequest(&quot;http://bugs.webkit.org/test.htm&quot;), { });
+    testRequest(ifDomainBackend, mainDocumentRequest(&quot;http://webkit.org/test.html&quot;), { ContentExtensions::ActionType::BlockLoad });
+    testRequest(ifDomainBackend, mainDocumentRequest(&quot;http://bugs.webkit.org/test.html&quot;), { ContentExtensions::ActionType::BlockLoad });
+    testRequest(ifDomainBackend, mainDocumentRequest(&quot;http://not_webkit.org/test.htm&quot;), { });
+    testRequest(ifDomainBackend, mainDocumentRequest(&quot;http://webkit.organization/test.htm&quot;), { });
+    testRequest(ifDomainBackend, mainDocumentRequest(&quot;http://not_webkit.org/test.html&quot;), { });
+    testRequest(ifDomainBackend, mainDocumentRequest(&quot;http://webkit.organization/test.html&quot;), { });
+    
+    auto unlessDomainBackend = makeBackend(&quot;[{\&quot;action\&quot;:{\&quot;type\&quot;:\&quot;block\&quot;},\&quot;trigger\&quot;:{\&quot;url-filter\&quot;:\&quot;test\\\\.html\&quot;, \&quot;unless-domain\&quot;:[\&quot;webkit.org\&quot;]}}]&quot;);
+    testRequest(unlessDomainBackend, mainDocumentRequest(&quot;http://webkit.org/test.htm&quot;), { });
+    testRequest(unlessDomainBackend, mainDocumentRequest(&quot;http://bugs.webkit.org/test.htm&quot;), { });
+    testRequest(unlessDomainBackend, mainDocumentRequest(&quot;http://webkit.org/test.html&quot;), { });
+    testRequest(unlessDomainBackend, mainDocumentRequest(&quot;http://bugs.webkit.org/test.html&quot;), { });
+    testRequest(unlessDomainBackend, mainDocumentRequest(&quot;http://not_webkit.org/test.htm&quot;), { });
+    testRequest(unlessDomainBackend, mainDocumentRequest(&quot;http://webkit.organization/test.htm&quot;), { });
+    testRequest(unlessDomainBackend, mainDocumentRequest(&quot;http://not_webkit.org/test.html&quot;), { ContentExtensions::ActionType::BlockLoad });
+    testRequest(unlessDomainBackend, mainDocumentRequest(&quot;http://webkit.organization/test.html&quot;), { ContentExtensions::ActionType::BlockLoad });
+
+    auto combinedBackend1 = makeBackend(&quot;[{\&quot;action\&quot;:{\&quot;type\&quot;:\&quot;block\&quot;},\&quot;trigger\&quot;:{\&quot;url-filter\&quot;:\&quot;test_block_load\&quot;, \&quot;if-domain\&quot;:[\&quot;webkit.org\&quot;]}},&quot;
+        &quot;{\&quot;action\&quot;:{\&quot;type\&quot;:\&quot;block-cookies\&quot;},\&quot;trigger\&quot;:{\&quot;url-filter\&quot;:\&quot;test_block_cookies\&quot;, \&quot;unless-domain\&quot;:[\&quot;webkit.org\&quot;]}}]&quot;);
+    testRequest(combinedBackend1, mainDocumentRequest(&quot;http://webkit.org&quot;), { });
+    testRequest(combinedBackend1, mainDocumentRequest(&quot;http://not_webkit.org&quot;), { });
+    testRequest(combinedBackend1, mainDocumentRequest(&quot;http://webkit.org/test_block_load.html&quot;), { ContentExtensions::ActionType::BlockLoad });
+    testRequest(combinedBackend1, subResourceRequest(&quot;http://whatwg.org/test_block_load.html&quot;, &quot;http://webkit.org/&quot;), { ContentExtensions::ActionType::BlockLoad });
+    testRequest(combinedBackend1, subResourceRequest(&quot;http://whatwg.org/shouldnt_match.html&quot;, &quot;http://webkit.org/&quot;), { });
+    testRequest(combinedBackend1, subResourceRequest(&quot;http://whatwg.org/test_block_load.html&quot;, &quot;http://not_webkit.org/&quot;), { });
+    testRequest(combinedBackend1, subResourceRequest(&quot;http://whatwg.org/shouldnt_match.html&quot;, &quot;http://not_webkit.org/&quot;), { });
+    testRequest(combinedBackend1, mainDocumentRequest(&quot;http://webkit.org/test_block_cookies.html&quot;), { });
+    testRequest(combinedBackend1, subResourceRequest(&quot;http://whatwg.org/test_block_cookies.html&quot;, &quot;http://webkit.org/&quot;), { });
+    testRequest(combinedBackend1, subResourceRequest(&quot;http://whatwg.org/shouldnt_match.html&quot;, &quot;http://webkit.org/&quot;), { });
+    testRequest(combinedBackend1, subResourceRequest(&quot;http://whatwg.org/test_block_cookies.html&quot;, &quot;http://not_webkit.org/path/to/main/document.html&quot;), { ContentExtensions::ActionType::BlockCookies });
+    testRequest(combinedBackend1, subResourceRequest(&quot;http://whatwg.org/shouldnt_match.html&quot;, &quot;http://not_webkit.org/&quot;), { });
+    
+    auto combinedBackend2 = makeBackend(&quot;[{\&quot;action\&quot;:{\&quot;type\&quot;:\&quot;block\&quot;},\&quot;trigger\&quot;:{\&quot;url-filter\&quot;:\&quot;test_block_load\\\\.html\&quot;, \&quot;if-domain\&quot;:[\&quot;webkit.org\&quot;]}},&quot;
+        &quot;{\&quot;action\&quot;:{\&quot;type\&quot;:\&quot;block-cookies\&quot;},\&quot;trigger\&quot;:{\&quot;url-filter\&quot;:\&quot;test_block_cookies\\\\.html\&quot;, \&quot;unless-domain\&quot;:[\&quot;w3c.org\&quot;]}},&quot;
+        &quot;{\&quot;action\&quot;:{\&quot;type\&quot;:\&quot;css-display-none\&quot;,\&quot;selector\&quot;:\&quot;.hidden\&quot;},\&quot;trigger\&quot;:{\&quot;url-filter\&quot;:\&quot;test_css\\\\.html\&quot;}}]&quot;);
+    testRequest(combinedBackend2, mainDocumentRequest(&quot;http://webkit.org/test_css.html&quot;), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+    testRequest(combinedBackend2, mainDocumentRequest(&quot;http://webkit.org/test_css.htm&quot;), { });
+    testRequest(combinedBackend2, mainDocumentRequest(&quot;http://webkit.org/test_block_load.html&quot;), { ContentExtensions::ActionType::BlockLoad });
+    testRequest(combinedBackend2, mainDocumentRequest(&quot;http://not_webkit.org/test_block_load.html&quot;), { });
+    testRequest(combinedBackend2, mainDocumentRequest(&quot;http://not_webkit.org/test_css.html&quot;), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+    testRequest(combinedBackend2, mainDocumentRequest(&quot;http://webkit.org/TEST_CSS.hTmL/test_block_load.html&quot;), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockLoad});
+    testRequest(combinedBackend2, mainDocumentRequest(&quot;http://w3c.org/test_css.html&quot;), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+    testRequest(combinedBackend2, mainDocumentRequest(&quot;http://w3c.org/test_block_load.html&quot;), { });
+    testRequest(combinedBackend2, mainDocumentRequest(&quot;http://w3c.org/test_block_cookies.html&quot;), { });
+    testRequest(combinedBackend2, mainDocumentRequest(&quot;http://w3c.org/test_css.html/test_block_cookies.html&quot;), { ContentExtensions::ActionType::CSSDisplayNoneSelector });
+    testRequest(combinedBackend2, mainDocumentRequest(&quot;http://not_w3c.org/test_block_cookies.html&quot;), { ContentExtensions::ActionType::BlockCookies });
+    testRequest(combinedBackend2, mainDocumentRequest(&quot;http://not_w3c.org/test_css.html/test_block_cookies.html&quot;), { ContentExtensions::ActionType::CSSDisplayNoneSelector, ContentExtensions::ActionType::BlockCookies });
+
+    auto ifDomainWithFlagsBackend = makeBackend(&quot;[{\&quot;action\&quot;:{\&quot;type\&quot;:\&quot;block\&quot;},\&quot;trigger\&quot;:{\&quot;url-filter\&quot;:\&quot;test\&quot;, \&quot;if-domain\&quot;:[\&quot;webkit.org\&quot;],\&quot;resource-type\&quot;:[\&quot;image\&quot;]}}]&quot;);
+    testRequest(ifDomainWithFlagsBackend, mainDocumentRequest(&quot;http://webkit.org/test.html&quot;), { });
+    testRequest(ifDomainWithFlagsBackend, mainDocumentRequest(&quot;http://webkit.org/test.png&quot;, ResourceType::Image), { ContentExtensions::ActionType::BlockLoad });
+    testRequest(ifDomainWithFlagsBackend, mainDocumentRequest(&quot;http://not_webkit.org/test.html&quot;), { });
+    testRequest(ifDomainWithFlagsBackend, mainDocumentRequest(&quot;http://not_webkit.org/test.png&quot;, ResourceType::Image), { });
+
+    auto unlessDomainWithFlagsBackend = makeBackend(&quot;[{\&quot;action\&quot;:{\&quot;type\&quot;:\&quot;block\&quot;},\&quot;trigger\&quot;:{\&quot;url-filter\&quot;:\&quot;test\&quot;, \&quot;unless-domain\&quot;:[\&quot;webkit.org\&quot;],\&quot;resource-type\&quot;:[\&quot;image\&quot;]}}]&quot;);
+    testRequest(unlessDomainWithFlagsBackend, mainDocumentRequest(&quot;http://webkit.org/test.html&quot;), { });
+    testRequest(unlessDomainWithFlagsBackend, mainDocumentRequest(&quot;http://webkit.org/test.png&quot;, ResourceType::Image), { });
+    testRequest(unlessDomainWithFlagsBackend, mainDocumentRequest(&quot;http://not_webkit.org/test.html&quot;), { });
+    testRequest(unlessDomainWithFlagsBackend, mainDocumentRequest(&quot;http://not_webkit.org/test.png&quot;, ResourceType::Image), { ContentExtensions::ActionType::BlockLoad });
+
+    // Domains should not be interepted as regular expressions.
+    auto domainRegexBackend = makeBackend(&quot;[{\&quot;action\&quot;:{\&quot;type\&quot;:\&quot;block\&quot;},\&quot;trigger\&quot;:{\&quot;url-filter\&quot;:\&quot;test\\\\.html\&quot;, \&quot;if-domain\&quot;:[\&quot;we?bkit.org\&quot;]}}]&quot;);
+    testRequest(domainRegexBackend, mainDocumentRequest(&quot;http://webkit.org/test.html&quot;), { });
+    testRequest(domainRegexBackend, mainDocumentRequest(&quot;http://wbkit.org/test.html&quot;), { });
+    
+    // FIXME: Add and test domain-specific popup-only blocking (with layout tests).
+}
+    
</ins><span class="cx"> TEST_F(ContentExtensionTest, TermsKnownToMatchAnything)
</span><span class="cx"> {
</span><span class="cx">     auto backend = makeBackend(&quot;[{\&quot;action\&quot;:{\&quot;type\&quot;:\&quot;block\&quot;},\&quot;trigger\&quot;:{\&quot;url-filter\&quot;:\&quot;^pre1.*post1$\&quot;}},&quot;
</span><span class="lines">@@ -577,12 +690,14 @@
</span><span class="cx">     EXPECT_EQ(1ul, createNFAs(combinedURLFilters).size());
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void checkCompilerError(const char* json, ContentExtensions::ContentExtensionError expectedError)
</del><ins>+void checkCompilerError(const char* json, std::error_code expectedError)
</ins><span class="cx"> {
</span><del>-    WebCore::ContentExtensions::CompiledContentExtensionData extensionData;
</del><ins>+    CompiledContentExtensionData extensionData;
</ins><span class="cx">     InMemoryContentExtensionCompilationClient client(extensionData);
</span><span class="cx">     std::error_code compilerError = ContentExtensions::compileRuleList(client, json);
</span><del>-    EXPECT_EQ(compilerError.value(), static_cast&lt;int&gt;(expectedError));
</del><ins>+    EXPECT_EQ(compilerError.value(), expectedError.value());
+    if (compilerError.value())
+        EXPECT_STREQ(compilerError.category().name(), expectedError.category().name());
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> TEST_F(ContentExtensionTest, InvalidJSON)
</span><span class="lines">@@ -605,11 +720,38 @@
</span><span class="cx">         ContentExtensions::ContentExtensionError::JSONInvalidTriggerFlagsArray);
</span><span class="cx">     checkCompilerError(&quot;[{\&quot;action\&quot;:{\&quot;type\&quot;:\&quot;block\&quot;},\&quot;trigger\&quot;:{\&quot;url-filter\&quot;:\&quot;webkit.org\&quot;,\&quot;load-type\&quot;:[\&quot;invalid\&quot;]}}]&quot;,
</span><span class="cx">         ContentExtensions::ContentExtensionError::JSONInvalidStringInTriggerFlagsArray);
</span><ins>+    checkCompilerError(&quot;[{\&quot;action\&quot;:{\&quot;type\&quot;:\&quot;block\&quot;},\&quot;trigger\&quot;:{\&quot;url-filter\&quot;:\&quot;webkit.org\&quot;,\&quot;load-type\&quot;:[5]}}]&quot;,
+        ContentExtensions::ContentExtensionError::JSONInvalidStringInTriggerFlagsArray);
</ins><span class="cx">     checkCompilerError(&quot;[{\&quot;action\&quot;:{\&quot;type\&quot;:\&quot;block\&quot;},\&quot;trigger\&quot;:{\&quot;url-filter\&quot;:\&quot;webkit.org\&quot;,\&quot;resource-type\&quot;:{}}}]&quot;,
</span><span class="cx">         ContentExtensions::ContentExtensionError::JSONInvalidTriggerFlagsArray);
</span><span class="cx">     checkCompilerError(&quot;[{\&quot;action\&quot;:{\&quot;type\&quot;:\&quot;block\&quot;},\&quot;trigger\&quot;:{\&quot;url-filter\&quot;:\&quot;webkit.org\&quot;,\&quot;resource-type\&quot;:[\&quot;invalid\&quot;]}}]&quot;,
</span><span class="cx">         ContentExtensions::ContentExtensionError::JSONInvalidStringInTriggerFlagsArray);
</span><ins>+    checkCompilerError(&quot;[{\&quot;action\&quot;:{\&quot;type\&quot;:\&quot;block\&quot;},\&quot;trigger\&quot;:{\&quot;url-filter\&quot;:\&quot;webkit.org\&quot;,\&quot;resource-type\&quot;:[5]}}]&quot;,
+        ContentExtensions::ContentExtensionError::JSONInvalidStringInTriggerFlagsArray);
+    
+    checkCompilerError(&quot;[{\&quot;action\&quot;:{\&quot;type\&quot;:\&quot;block\&quot;},\&quot;trigger\&quot;:{\&quot;url-filter\&quot;:\&quot;webkit.org\&quot;,\&quot;if-domain\&quot;:{}}}]&quot;, ContentExtensions::ContentExtensionError::JSONInvalidDomainList);
+    checkCompilerError(&quot;[{\&quot;action\&quot;:{\&quot;type\&quot;:\&quot;block\&quot;},\&quot;trigger\&quot;:{\&quot;url-filter\&quot;:\&quot;webkit.org\&quot;,\&quot;if-domain\&quot;:[5]}}]&quot;, ContentExtensions::ContentExtensionError::JSONInvalidDomainList);
+    checkCompilerError(&quot;[{\&quot;action\&quot;:{\&quot;type\&quot;:\&quot;block\&quot;},\&quot;trigger\&quot;:{\&quot;url-filter\&quot;:\&quot;webkit.org\&quot;,\&quot;if-domain\&quot;:[\&quot;a\&quot;]}}]&quot;, { });
+    checkCompilerError(&quot;[{\&quot;action\&quot;:{\&quot;type\&quot;:\&quot;block\&quot;},\&quot;trigger\&quot;:{\&quot;url-filter\&quot;:\&quot;webkit.org\&quot;,\&quot;unless-domain\&quot;:{}}}]&quot;, ContentExtensions::ContentExtensionError::JSONInvalidDomainList);
+    checkCompilerError(&quot;[{\&quot;action\&quot;:{\&quot;type\&quot;:\&quot;block\&quot;},\&quot;trigger\&quot;:{\&quot;url-filter\&quot;:\&quot;webkit.org\&quot;,\&quot;unless-domain\&quot;:[5]}}]&quot;, ContentExtensions::ContentExtensionError::JSONInvalidDomainList);
+    checkCompilerError(&quot;[{\&quot;action\&quot;:{\&quot;type\&quot;:\&quot;block\&quot;},\&quot;trigger\&quot;:{\&quot;url-filter\&quot;:\&quot;webkit.org\&quot;,\&quot;unless-domain\&quot;:[\&quot;\&quot;]}}]&quot;, ContentExtensions::ContentExtensionError::JSONInvalidDomainList);
+    checkCompilerError(&quot;[{\&quot;action\&quot;:{\&quot;type\&quot;:\&quot;block\&quot;},\&quot;trigger\&quot;:{\&quot;url-filter\&quot;:\&quot;webkit.org\&quot;,\&quot;unless-domain\&quot;:[\&quot;A\&quot;]}}]&quot;, ContentExtensions::ContentExtensionError::JSONDomainNotLowerCaseASCII);
+    checkCompilerError(&quot;[{\&quot;action\&quot;:{\&quot;type\&quot;:\&quot;block\&quot;},\&quot;trigger\&quot;:{\&quot;url-filter\&quot;:\&quot;webkit.org\&quot;,\&quot;unless-domain\&quot;:[\&quot;\\u00DC\&quot;]}}]&quot;, ContentExtensions::ContentExtensionError::JSONDomainNotLowerCaseASCII);
+    checkCompilerError(&quot;[{\&quot;action\&quot;:{\&quot;type\&quot;:\&quot;block\&quot;},\&quot;trigger\&quot;:{\&quot;url-filter\&quot;:\&quot;webkit.org\&quot;,\&quot;unless-domain\&quot;:[\&quot;0\&quot;]}}]&quot;, { });
+    checkCompilerError(&quot;[{\&quot;action\&quot;:{\&quot;type\&quot;:\&quot;block\&quot;},\&quot;trigger\&quot;:{\&quot;url-filter\&quot;:\&quot;webkit.org\&quot;,\&quot;unless-domain\&quot;:[\&quot;a\&quot;]}}]&quot;, { });
</ins><span class="cx"> 
</span><ins>+    checkCompilerError(&quot;[{\&quot;action\&quot;:{\&quot;type\&quot;:\&quot;block\&quot;},\&quot;trigger\&quot;:{\&quot;url-filter\&quot;:\&quot;webkit.org\&quot;,\&quot;if-domain\&quot;:[],\&quot;unless-domain\&quot;:[\&quot;a\&quot;]}}]&quot;, ContentExtensions::ContentExtensionError::JSONInvalidDomainList);
+    checkCompilerError(&quot;[{\&quot;action\&quot;:{\&quot;type\&quot;:\&quot;block\&quot;},\&quot;trigger\&quot;:{\&quot;url-filter\&quot;:\&quot;webkit.org\&quot;,\&quot;unless-domain\&quot;:[]}}]&quot;, ContentExtensions::ContentExtensionError::JSONInvalidDomainList);
+    checkCompilerError(&quot;[{\&quot;action\&quot;:{\&quot;type\&quot;:\&quot;block\&quot;},\&quot;trigger\&quot;:{\&quot;url-filter\&quot;:\&quot;webkit.org\&quot;,\&quot;if-domain\&quot;:5}}]&quot;, { });
+    checkCompilerError(&quot;[{\&quot;action\&quot;:{\&quot;type\&quot;:\&quot;block\&quot;},\&quot;trigger\&quot;:{\&quot;url-filter\&quot;:\&quot;webkit.org\&quot;,\&quot;unless-domain\&quot;:5}}]&quot;, { });
+    checkCompilerError(&quot;[{\&quot;action\&quot;:{\&quot;type\&quot;:\&quot;block\&quot;},\&quot;trigger\&quot;:{\&quot;url-filter\&quot;:\&quot;webkit.org\&quot;,\&quot;if-domain\&quot;:5,\&quot;unless-domain\&quot;:5}}]&quot;, { });
+    checkCompilerError(&quot;[{\&quot;action\&quot;:{\&quot;type\&quot;:\&quot;block\&quot;},\&quot;trigger\&quot;:{\&quot;url-filter\&quot;:\&quot;webkit.org\&quot;,\&quot;if-domain\&quot;:[]}}]&quot;, ContentExtensions::ContentExtensionError::JSONInvalidDomainList);
+    
+    checkCompilerError(&quot;[{\&quot;action\&quot;:{\&quot;type\&quot;:\&quot;block\&quot;},\&quot;trigger\&quot;:{\&quot;url-filter\&quot;:\&quot;webkit.org\&quot;,\&quot;if-domain\&quot;:[\&quot;a\&quot;],\&quot;unless-domain\&quot;:[]}}]&quot;, ContentExtensions::ContentExtensionError::JSONUnlessAndIfDomain);
+    checkCompilerError(&quot;[{\&quot;action\&quot;:{\&quot;type\&quot;:\&quot;block\&quot;},\&quot;trigger\&quot;:{\&quot;url-filter\&quot;:\&quot;webkit.org\&quot;,\&quot;if-domain\&quot;:[\&quot;a\&quot;],\&quot;unless-domain\&quot;:[\&quot;a\&quot;]}}]&quot;, ContentExtensions::ContentExtensionError::JSONUnlessAndIfDomain);
+
+    checkCompilerError(&quot;[{\&quot;action\&quot;:{\&quot;type\&quot;:\&quot;block\&quot;},\&quot;trigger\&quot;:{\&quot;url-filter\&quot;:\&quot;webkit.org\&quot;, \&quot;unexpected-identifier-should-be-ignored\&quot;:5}}]&quot;, { });
+
</ins><span class="cx">     checkCompilerError(&quot;[{\&quot;action\&quot;:5,\&quot;trigger\&quot;:{\&quot;url-filter\&quot;:\&quot;webkit.org\&quot;}}]&quot;,
</span><span class="cx">         ContentExtensions::ContentExtensionError::JSONInvalidAction);
</span><span class="cx">     checkCompilerError(&quot;[{\&quot;action\&quot;:{\&quot;type\&quot;:\&quot;invalid\&quot;},\&quot;trigger\&quot;:{\&quot;url-filter\&quot;:\&quot;webkit.org\&quot;}}]&quot;,
</span><span class="lines">@@ -620,6 +762,8 @@
</span><span class="cx">     checkCompilerError(&quot;[{\&quot;action\&quot;:{\&quot;type\&quot;:\&quot;ignore-previous-rules\&quot;},\&quot;trigger\&quot;:{\&quot;url-filter\&quot;:\&quot;webkit.org\&quot;}},&quot;
</span><span class="cx">         &quot;{\&quot;action\&quot;:{\&quot;type\&quot;:\&quot;css-display-none\&quot;,\&quot;selector\&quot;:\&quot;.hidden\&quot;},\&quot;trigger\&quot;:{\&quot;url-filter\&quot;:\&quot;.*\&quot;}}]&quot;,
</span><span class="cx">         ContentExtensions::ContentExtensionError::RegexMatchesEverythingAfterIgnorePreviousRules);
</span><ins>+    checkCompilerError(&quot;[{\&quot;action\&quot;:{\&quot;type\&quot;:\&quot;block\&quot;},\&quot;trigger\&quot;:{\&quot;url-filter\&quot;:\&quot;.*\&quot;,\&quot;if-domain\&quot;:[\&quot;a\&quot;]}}]&quot;, ContentExtensions::ContentExtensionError::RegexMatchesEverythingWithDomains);
+    checkCompilerError(&quot;[{\&quot;action\&quot;:{\&quot;type\&quot;:\&quot;block\&quot;},\&quot;trigger\&quot;:{\&quot;url-filter\&quot;:\&quot;.*\&quot;,\&quot;unless-domain\&quot;:[\&quot;a\&quot;]}}]&quot;, ContentExtensions::ContentExtensionError::RegexMatchesEverythingWithDomains);
</ins><span class="cx">     checkCompilerError(&quot;[{\&quot;action\&quot;:{\&quot;type\&quot;:\&quot;block\&quot;},\&quot;trigger\&quot;:{\&quot;url-filter\&quot;:\&quot;[\&quot;}}]&quot;,
</span><span class="cx">         ContentExtensions::ContentExtensionError::JSONInvalidRegex);
</span><span class="cx"> }
</span></span></pre>
</div>
</div>

</body>
</html>