<!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>[181405] 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/181405">181405</a></dd>
<dt>Author</dt> <dd>benjamin@webkit.org</dd>
<dt>Date</dt> <dd>2015-03-11 14:08:51 -0700 (Wed, 11 Mar 2015)</dd>
</dl>

<h3>Log Message</h3>
<pre>Add basic support for BOL and EOL assertions to the URL Filter parser
https://bugs.webkit.org/show_bug.cgi?id=142568

Patch by Benjamin Poulain &lt;bpoulain@apple.com&gt; on 2015-03-11
Reviewed by Alex Christensen.

Source/WebCore:

This patch adds heavily restricted support for BOL and EOL to the URL filter parser.

Both assertions must be the first/last term of their pattern. Any advanced combination
results in a parsing error.

The BOL assertion is easy to represent: currently, any pattern starts at the beginning
of a line and the NFA are generated accordingly.

I had two options to represent the EOL assertion:
1) Add a new special transition on EOL.
2) Add a new vector of actions to the states, conditional to the EOL input.

I picked the first option to avoid growing every state by a vector
that would be empty in the vast majority of cases.


On the matching side, the interpreter was modified to support transitions on '\0'.
DFABytecodeInstruction::CheckValue now stops when running on a character after
the end of the string.

DFABytecodeInstruction::Jump gets two fixes: First we now account for the index
to avoid going past the end of the input. Second, stop on '\0' too... the reason
is that the unconditional jump is only used for fallback edges of the DFA, fallback
edge are not supposed to accept '\0'.

* contentextensions/DFA.cpp:
(WebCore::ContentExtensions::printTransitions):
* contentextensions/DFABytecodeInterpreter.cpp:
(WebCore::ContentExtensions::DFABytecodeInterpreter::interpret):
* contentextensions/DFANode.h:
* contentextensions/NFA.cpp:
(WebCore::ContentExtensions::NFA::addTransition):
(WebCore::ContentExtensions::NFA::addEpsilonTransition):
(WebCore::ContentExtensions::printTransitions):
* contentextensions/NFANode.h:
* contentextensions/NFAToDFA.cpp:
(WebCore::ContentExtensions::populateTransitions):
(WebCore::ContentExtensions::NFAToDFA::convert):
* contentextensions/URLFilterParser.cpp:
(WebCore::ContentExtensions::Term::Term):
(WebCore::ContentExtensions::Term::isEndOfLineAssertion):
(WebCore::ContentExtensions::GraphBuilder::assertionBOL):
(WebCore::ContentExtensions::GraphBuilder::assertionEOL):
(WebCore::ContentExtensions::GraphBuilder::sinkFloatingTermIfNecessary):

Tools:

* TestWebKitAPI/Tests/WebCore/ContentExtensions.cpp:
(TestWebKitAPI::TEST_F):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCorecontentextensionsDFAcpp">trunk/Source/WebCore/contentextensions/DFA.cpp</a></li>
<li><a href="#trunkSourceWebCorecontentextensionsDFABytecodeInterpretercpp">trunk/Source/WebCore/contentextensions/DFABytecodeInterpreter.cpp</a></li>
<li><a href="#trunkSourceWebCorecontentextensionsDFANodeh">trunk/Source/WebCore/contentextensions/DFANode.h</a></li>
<li><a href="#trunkSourceWebCorecontentextensionsNFAcpp">trunk/Source/WebCore/contentextensions/NFA.cpp</a></li>
<li><a href="#trunkSourceWebCorecontentextensionsNFANodeh">trunk/Source/WebCore/contentextensions/NFANode.h</a></li>
<li><a href="#trunkSourceWebCorecontentextensionsNFAToDFAcpp">trunk/Source/WebCore/contentextensions/NFAToDFA.cpp</a></li>
<li><a href="#trunkSourceWebCorecontentextensionsURLFilterParsercpp">trunk/Source/WebCore/contentextensions/URLFilterParser.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>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (181404 => 181405)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2015-03-11 21:03:24 UTC (rev 181404)
+++ trunk/Source/WebCore/ChangeLog        2015-03-11 21:08:51 UTC (rev 181405)
</span><span class="lines">@@ -1,3 +1,55 @@
</span><ins>+2015-03-11  Benjamin Poulain  &lt;bpoulain@apple.com&gt;
+
+        Add basic support for BOL and EOL assertions to the URL Filter parser
+        https://bugs.webkit.org/show_bug.cgi?id=142568
+
+        Reviewed by Alex Christensen.
+
+        This patch adds heavily restricted support for BOL and EOL to the URL filter parser.
+
+        Both assertions must be the first/last term of their pattern. Any advanced combination
+        results in a parsing error.
+
+        The BOL assertion is easy to represent: currently, any pattern starts at the beginning
+        of a line and the NFA are generated accordingly.
+
+        I had two options to represent the EOL assertion:
+        1) Add a new special transition on EOL.
+        2) Add a new vector of actions to the states, conditional to the EOL input.
+
+        I picked the first option to avoid growing every state by a vector
+        that would be empty in the vast majority of cases.
+
+
+        On the matching side, the interpreter was modified to support transitions on '\0'.
+        DFABytecodeInstruction::CheckValue now stops when running on a character after
+        the end of the string.
+
+        DFABytecodeInstruction::Jump gets two fixes: First we now account for the index
+        to avoid going past the end of the input. Second, stop on '\0' too... the reason
+        is that the unconditional jump is only used for fallback edges of the DFA, fallback
+        edge are not supposed to accept '\0'.
+
+        * contentextensions/DFA.cpp:
+        (WebCore::ContentExtensions::printTransitions):
+        * contentextensions/DFABytecodeInterpreter.cpp:
+        (WebCore::ContentExtensions::DFABytecodeInterpreter::interpret):
+        * contentextensions/DFANode.h:
+        * contentextensions/NFA.cpp:
+        (WebCore::ContentExtensions::NFA::addTransition):
+        (WebCore::ContentExtensions::NFA::addEpsilonTransition):
+        (WebCore::ContentExtensions::printTransitions):
+        * contentextensions/NFANode.h:
+        * contentextensions/NFAToDFA.cpp:
+        (WebCore::ContentExtensions::populateTransitions):
+        (WebCore::ContentExtensions::NFAToDFA::convert):
+        * contentextensions/URLFilterParser.cpp:
+        (WebCore::ContentExtensions::Term::Term):
+        (WebCore::ContentExtensions::Term::isEndOfLineAssertion):
+        (WebCore::ContentExtensions::GraphBuilder::assertionBOL):
+        (WebCore::ContentExtensions::GraphBuilder::assertionEOL):
+        (WebCore::ContentExtensions::GraphBuilder::sinkFloatingTermIfNecessary):
+
</ins><span class="cx"> 2015-03-11  Jer Noble  &lt;jer.noble@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         [Mac] Update fullscreen placeholder UI to use Vibrancy.
</span></span></pre></div>
<a id="trunkSourceWebCorecontentextensionsDFAcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/contentextensions/DFA.cpp (181404 => 181405)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/contentextensions/DFA.cpp        2015-03-11 21:03:24 UTC (rev 181404)
+++ trunk/Source/WebCore/contentextensions/DFA.cpp        2015-03-11 21:08:51 UTC (rev 181405)
</span><span class="lines">@@ -78,7 +78,7 @@
</span><span class="cx"> static void printTransitions(const Vector&lt;DFANode&gt;&amp; graph, unsigned sourceNodeId)
</span><span class="cx"> {
</span><span class="cx">     const DFANode&amp; sourceNode = graph[sourceNodeId];
</span><del>-    const HashMap&lt;uint16_t, unsigned&gt;&amp; transitions = sourceNode.transitions;
</del><ins>+    const DFANodeTransitions&amp; transitions = sourceNode.transitions;
</ins><span class="cx"> 
</span><span class="cx">     if (transitions.isEmpty() &amp;&amp; !sourceNode.hasFallbackTransition)
</span><span class="cx">         return;
</span></span></pre></div>
<a id="trunkSourceWebCorecontentextensionsDFABytecodeInterpretercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/contentextensions/DFABytecodeInterpreter.cpp (181404 => 181405)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/contentextensions/DFABytecodeInterpreter.cpp        2015-03-11 21:03:24 UTC (rev 181404)
+++ trunk/Source/WebCore/contentextensions/DFABytecodeInterpreter.cpp        2015-03-11 21:08:51 UTC (rev 181405)
</span><span class="lines">@@ -48,6 +48,7 @@
</span><span class="cx">     
</span><span class="cx">     unsigned programCounter = 0;
</span><span class="cx">     unsigned urlIndex = 0;
</span><ins>+    bool urlIndexIsAfterEndOfString = false;
</ins><span class="cx">     Actions actions;
</span><span class="cx">     
</span><span class="cx">     // This should always terminate if interpreting correctly compiled bytecode.
</span><span class="lines">@@ -59,17 +60,23 @@
</span><span class="cx">             return actions;
</span><span class="cx"> 
</span><span class="cx">         case DFABytecodeInstruction::CheckValue:
</span><ins>+            if (urlIndexIsAfterEndOfString)
+                return actions;
+
</ins><span class="cx">             // Check to see if the next character in the url is the value stored with the bytecode.
</span><del>-            if (!url[urlIndex])
-                return actions; // Reached null character at end.
</del><span class="cx">             if (url[urlIndex] == getBits&lt;uint8_t&gt;(m_bytecode, m_bytecodeLength, programCounter + sizeof(DFABytecode))) {
</span><span class="cx">                 programCounter = getBits&lt;unsigned&gt;(m_bytecode, m_bytecodeLength, programCounter + sizeof(DFABytecode) + sizeof(uint8_t));
</span><ins>+                if (!url[urlIndex])
+                    urlIndexIsAfterEndOfString = true;
</ins><span class="cx">                 urlIndex++; // This represents an edge in the DFA.
</span><span class="cx">             } else
</span><span class="cx">                 programCounter += instructionSizeWithArguments(DFABytecodeInstruction::CheckValue);
</span><span class="cx">             break;
</span><span class="cx"> 
</span><span class="cx">         case DFABytecodeInstruction::Jump:
</span><ins>+            if (!url[urlIndex] || urlIndexIsAfterEndOfString)
+                return actions;
+
</ins><span class="cx">             programCounter = getBits&lt;unsigned&gt;(m_bytecode, m_bytecodeLength, programCounter + sizeof(DFABytecode));
</span><span class="cx">             urlIndex++; // This represents an edge in the DFA.
</span><span class="cx">             break;
</span><span class="lines">@@ -82,7 +89,8 @@
</span><span class="cx">         default:
</span><span class="cx">             RELEASE_ASSERT_NOT_REACHED(); // Invalid bytecode.
</span><span class="cx">         }
</span><del>-        ASSERT(urlIndex &lt;= urlCString.length()); // We should always terminate at a null character at the end of a String.
</del><ins>+        // We should always terminate before or at a null character at the end of a String.
+        ASSERT(urlIndex &lt;= urlCString.length() || (urlIndexIsAfterEndOfString &amp;&amp; urlIndex &lt;= urlCString.length() + 1));
</ins><span class="cx">     }
</span><span class="cx">     RELEASE_ASSERT_NOT_REACHED();
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkSourceWebCorecontentextensionsDFANodeh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/contentextensions/DFANode.h (181404 => 181405)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/contentextensions/DFANode.h        2015-03-11 21:03:24 UTC (rev 181404)
+++ trunk/Source/WebCore/contentextensions/DFANode.h        2015-03-11 21:08:51 UTC (rev 181405)
</span><span class="lines">@@ -38,9 +38,12 @@
</span><span class="cx"> 
</span><span class="cx"> // A DFANode abstract the transition table out of a DFA state. If a state is accepting, the DFANode also have
</span><span class="cx"> // the actions for that state.
</span><ins>+
+typedef HashMap&lt;uint16_t, unsigned, DefaultHash&lt;uint16_t&gt;::Hash, WTF::UnsignedWithZeroKeyHashTraits&lt;uint16_t&gt;&gt; DFANodeTransitions;
+
</ins><span class="cx"> class DFANode {
</span><span class="cx"> public:
</span><del>-    HashMap&lt;uint16_t, unsigned&gt; transitions;
</del><ins>+    DFANodeTransitions transitions;
</ins><span class="cx">     bool hasFallbackTransition = false;
</span><span class="cx">     unsigned fallbackTransition;
</span><span class="cx">     Vector&lt;uint64_t&gt; actions;
</span></span></pre></div>
<a id="trunkSourceWebCorecontentextensionsNFAcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/contentextensions/NFA.cpp (181404 => 181405)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/contentextensions/NFA.cpp        2015-03-11 21:03:24 UTC (rev 181404)
+++ trunk/Source/WebCore/contentextensions/NFA.cpp        2015-03-11 21:08:51 UTC (rev 181405)
</span><span class="lines">@@ -51,13 +51,12 @@
</span><span class="cx"> {
</span><span class="cx">     ASSERT(from &lt; m_nodes.size());
</span><span class="cx">     ASSERT(to &lt; m_nodes.size());
</span><del>-    ASSERT(character);
</del><span class="cx"> 
</span><span class="cx">     NFANode&amp; fromNode = m_nodes[from];
</span><span class="cx">     if (fromNode.transitionsOnAnyCharacter.contains(to))
</span><span class="cx">         return;
</span><span class="cx"> 
</span><del>-    auto addResult = m_nodes[from].transitions.add(character, HashSet&lt;unsigned, DefaultHash&lt;unsigned&gt;::Hash, WTF::UnsignedWithZeroKeyHashTraits&lt;unsigned&gt;&gt;());
</del><ins>+    auto addResult = m_nodes[from].transitions.add(character, NFANodeIndexSet());
</ins><span class="cx">     addResult.iterator-&gt;value.add(to);
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -66,7 +65,7 @@
</span><span class="cx">     ASSERT(from &lt; m_nodes.size());
</span><span class="cx">     ASSERT(to &lt; m_nodes.size());
</span><span class="cx"> 
</span><del>-    auto addResult = m_nodes[from].transitions.add(epsilonTransitionCharacter, HashSet&lt;unsigned, DefaultHash&lt;unsigned&gt;::Hash, WTF::UnsignedWithZeroKeyHashTraits&lt;unsigned&gt;&gt;());
</del><ins>+    auto addResult = m_nodes[from].transitions.add(epsilonTransitionCharacter, NFANodeIndexSet());
</ins><span class="cx">     addResult.iterator-&gt;value.add(to);
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -133,13 +132,13 @@
</span><span class="cx"> static void printTransitions(const Vector&lt;NFANode&gt;&amp; graph, unsigned sourceNode, uint16_t epsilonTransitionCharacter)
</span><span class="cx"> {
</span><span class="cx">     const NFANode&amp; node = graph[sourceNode];
</span><del>-    const HashMap&lt;uint16_t, HashSet&lt;unsigned, DefaultHash&lt;unsigned&gt;::Hash, WTF::UnsignedWithZeroKeyHashTraits&lt;unsigned&gt;&gt;&gt;&amp; transitions = node.transitions;
</del><ins>+    const HashMap&lt;uint16_t, NFANodeIndexSet, DefaultHash&lt;uint16_t&gt;::Hash, WTF::UnsignedWithZeroKeyHashTraits&lt;uint16_t&gt;&gt;&amp; transitions = node.transitions;
</ins><span class="cx"> 
</span><del>-    HashMap&lt;unsigned, HashSet&lt;uint16_t&gt;, DefaultHash&lt;unsigned&gt;::Hash, WTF::UnsignedWithZeroKeyHashTraits&lt;unsigned&gt;&gt; transitionsPerTarget;
</del><ins>+    HashMap&lt;unsigned, HashSet&lt;uint16_t, DefaultHash&lt;uint16_t&gt;::Hash, WTF::UnsignedWithZeroKeyHashTraits&lt;uint16_t&gt;&gt;, DefaultHash&lt;unsigned&gt;::Hash, WTF::UnsignedWithZeroKeyHashTraits&lt;unsigned&gt;&gt; transitionsPerTarget;
</ins><span class="cx"> 
</span><span class="cx">     for (const auto&amp; transition : transitions) {
</span><span class="cx">         for (unsigned targetNode : transition.value) {
</span><del>-            transitionsPerTarget.add(targetNode, HashSet&lt;uint16_t&gt;());
</del><ins>+            transitionsPerTarget.add(targetNode, HashSet&lt;uint16_t, DefaultHash&lt;uint16_t&gt;::Hash, WTF::UnsignedWithZeroKeyHashTraits&lt;uint16_t&gt;&gt;());
</ins><span class="cx">             transitionsPerTarget.find(targetNode)-&gt;value.add(transition.key);
</span><span class="cx">         }
</span><span class="cx">     }
</span></span></pre></div>
<a id="trunkSourceWebCorecontentextensionsNFANodeh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/contentextensions/NFANode.h (181404 => 181405)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/contentextensions/NFANode.h        2015-03-11 21:03:24 UTC (rev 181404)
+++ trunk/Source/WebCore/contentextensions/NFANode.h        2015-03-11 21:08:51 UTC (rev 181405)
</span><span class="lines">@@ -38,10 +38,14 @@
</span><span class="cx"> namespace ContentExtensions {
</span><span class="cx"> 
</span><span class="cx"> // A NFANode abstract the transition table out of a NFA state.
</span><ins>+
+typedef HashSet&lt;unsigned, DefaultHash&lt;unsigned&gt;::Hash, WTF::UnsignedWithZeroKeyHashTraits&lt;unsigned&gt;&gt; NFANodeIndexSet;
+typedef HashMap&lt;uint16_t, NFANodeIndexSet, DefaultHash&lt;uint16_t&gt;::Hash, WTF::UnsignedWithZeroKeyHashTraits&lt;uint16_t&gt;&gt; NFANodeTransitions;
+
</ins><span class="cx"> class NFANode {
</span><span class="cx"> public:
</span><del>-    HashMap&lt;uint16_t, HashSet&lt;unsigned, DefaultHash&lt;unsigned&gt;::Hash, WTF::UnsignedWithZeroKeyHashTraits&lt;unsigned&gt;&gt;&gt; transitions;
-    HashSet&lt;unsigned, DefaultHash&lt;unsigned&gt;::Hash, WTF::UnsignedWithZeroKeyHashTraits&lt;unsigned&gt;&gt; transitionsOnAnyCharacter;
</del><ins>+    HashMap&lt;uint16_t, NFANodeIndexSet, DefaultHash&lt;uint16_t&gt;::Hash, WTF::UnsignedWithZeroKeyHashTraits&lt;uint16_t&gt;&gt; transitions;
+    NFANodeIndexSet transitionsOnAnyCharacter;
</ins><span class="cx"> 
</span><span class="cx">     Vector&lt;uint64_t&gt; finalRuleIds;
</span><span class="cx"> #if CONTENT_EXTENSIONS_STATE_MACHINE_DEBUGGING
</span></span></pre></div>
<a id="trunkSourceWebCorecontentextensionsNFAToDFAcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/contentextensions/NFAToDFA.cpp (181404 => 181405)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/contentextensions/NFAToDFA.cpp        2015-03-11 21:03:24 UTC (rev 181404)
+++ trunk/Source/WebCore/contentextensions/NFAToDFA.cpp        2015-03-11 21:08:51 UTC (rev 181405)
</span><span class="lines">@@ -41,7 +41,7 @@
</span><span class="cx"> 
</span><span class="cx"> // FIXME: set a better initial size.
</span><span class="cx"> // FIXME: include the hash inside NodeIdSet.
</span><del>-typedef HashSet&lt;unsigned, DefaultHash&lt;unsigned&gt;::Hash, WTF::UnsignedWithZeroKeyHashTraits&lt;unsigned&gt;&gt; NodeIdSet;
</del><ins>+typedef NFANodeIndexSet NodeIdSet;
</ins><span class="cx"> 
</span><span class="cx"> static inline void epsilonClosureExcludingSelf(const Vector&lt;NFANode&gt;&amp; nfaGraph, unsigned nodeId, unsigned epsilonTransitionCharacter, Vector&lt;unsigned&gt;&amp; output)
</span><span class="cx"> {
</span><span class="lines">@@ -322,7 +322,8 @@
</span><span class="cx">                 targetSet.add(targetNodId);
</span><span class="cx">                 extendSetWithClosure(nfaNodeclosures, targetNodId, targetSet);
</span><span class="cx">             }
</span><del>-            targetSet.add(setFallbackTransition.begin(), setFallbackTransition.end());
</del><ins>+            if (transitionSlot.key)
+                targetSet.add(setFallbackTransition.begin(), setFallbackTransition.end());
</ins><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="lines">@@ -365,7 +366,6 @@
</span><span class="cx">         NodeIdSet setFallbackTransition;
</span><span class="cx">         populateTransitions(transitionsFromClosedSet, setFallbackTransition, *uniqueNodeIdSetImpl, nfaGraph, nfaNodeClosures);
</span><span class="cx"> 
</span><del>-        // FIXME: there should not be any transition on key 0.
</del><span class="cx">         for (unsigned key = 0; key &lt; transitionsFromClosedSet.size(); ++key) {
</span><span class="cx">             NodeIdSet&amp; targetNodeSet = transitionsFromClosedSet[key];
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCorecontentextensionsURLFilterParsercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/contentextensions/URLFilterParser.cpp (181404 => 181405)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/contentextensions/URLFilterParser.cpp        2015-03-11 21:03:24 UTC (rev 181404)
+++ trunk/Source/WebCore/contentextensions/URLFilterParser.cpp        2015-03-11 21:08:51 UTC (rev 181405)
</span><span class="lines">@@ -81,6 +81,13 @@
</span><span class="cx">         new (NotNull, &amp;m_atomData.group) Group();
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    enum EndOfLineAssertionTermTag { EndOfLineAssertionTerm };
+    explicit Term(EndOfLineAssertionTermTag)
+        : Term(CharacterSetTerm, false)
+    {
+        m_atomData.characterSet.characters.set(0);
+    }
+
</ins><span class="cx">     Term(const Term&amp; other)
</span><span class="cx">         : m_termType(other.m_termType)
</span><span class="cx">         , m_quantifier(other.m_quantifier)
</span><span class="lines">@@ -212,6 +219,11 @@
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    bool isEndOfLineAssertion() const
+    {
+        return m_termType == TermType::CharacterSet &amp;&amp; m_atomData.characterSet.characters.bitCount() == 1 &amp;&amp; m_atomData.characterSet.characters.get(0);
+    }
+
</ins><span class="cx">     Term&amp; operator=(const Term&amp; other)
</span><span class="cx">     {
</span><span class="cx">         destroy();
</span><span class="lines">@@ -498,12 +510,22 @@
</span><span class="cx"> 
</span><span class="cx">     void assertionBOL()
</span><span class="cx">     {
</span><del>-        fail(ASCIILiteral(&quot;Line boundary assertions are not supported yet.&quot;));
</del><ins>+        if (hasError())
+            return;
+
+        if (m_subtreeStart != m_subtreeEnd || m_floatingTerm.isValid() || !m_openGroups.isEmpty())
+            fail(ASCIILiteral(&quot;Start of line assertion can only appear as the first term in a filter.&quot;));
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     void assertionEOL()
</span><span class="cx">     {
</span><del>-        fail(ASCIILiteral(&quot;Line boundary assertions are not supported yet.&quot;));
</del><ins>+        if (hasError())
+            return;
+
+        sinkFloatingTermIfNecessary();
+        ASSERT(!m_floatingTerm.isValid());
+
+        m_floatingTerm = Term(Term::EndOfLineAssertionTerm);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     void assertionWordBoundary(bool)
</span><span class="lines">@@ -614,6 +636,15 @@
</span><span class="cx"> 
</span><span class="cx">         ASSERT(m_lastPrefixTreeEntry);
</span><span class="cx"> 
</span><ins>+        if (m_hasProcessedEndOfLineAssertion) {
+            fail(ASCIILiteral(&quot;The end of line assertion must be the last term in an expression.&quot;));
+            m_floatingTerm = Term();
+            return;
+        }
+
+        if (m_floatingTerm.isEndOfLineAssertion())
+            m_hasProcessedEndOfLineAssertion = true;
+
</ins><span class="cx">         if (!m_openGroups.isEmpty()) {
</span><span class="cx">             m_openGroups.last().extendGroupSubpattern(m_floatingTerm);
</span><span class="cx">             m_floatingTerm = Term();
</span><span class="lines">@@ -656,6 +687,7 @@
</span><span class="cx">     PrefixTreeEntry* m_lastPrefixTreeEntry;
</span><span class="cx">     Deque&lt;Term&gt; m_openGroups;
</span><span class="cx">     Term m_floatingTerm;
</span><ins>+    bool m_hasProcessedEndOfLineAssertion { false };
</ins><span class="cx"> 
</span><span class="cx">     PrefixTreeEntry* m_newPrefixSubtreeRoot = nullptr;
</span><span class="cx">     Term m_newPrefixStaringPoint;
</span></span></pre></div>
<a id="trunkToolsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Tools/ChangeLog (181404 => 181405)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/ChangeLog        2015-03-11 21:03:24 UTC (rev 181404)
+++ trunk/Tools/ChangeLog        2015-03-11 21:08:51 UTC (rev 181405)
</span><span class="lines">@@ -1,3 +1,13 @@
</span><ins>+2015-03-11  Benjamin Poulain  &lt;bpoulain@apple.com&gt;
+
+        Add basic support for BOL and EOL assertions to the URL Filter parser
+        https://bugs.webkit.org/show_bug.cgi?id=142568
+
+        Reviewed by Alex Christensen.
+
+        * TestWebKitAPI/Tests/WebCore/ContentExtensions.cpp:
+        (TestWebKitAPI::TEST_F):
+
</ins><span class="cx"> 2015-03-11  Carlos Garcia Campos  &lt;cgarcia@igalia.com&gt;
</span><span class="cx"> 
</span><span class="cx">         [GTK] Add support for handling TLS errors to MiniBrowser
</span></span></pre></div>
<a id="trunkToolsTestWebKitAPITestsWebCoreContentExtensionscpp"></a>
<div class="modfile"><h4>Modified: trunk/Tools/TestWebKitAPI/Tests/WebCore/ContentExtensions.cpp (181404 => 181405)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/Tests/WebCore/ContentExtensions.cpp        2015-03-11 21:03:24 UTC (rev 181404)
+++ trunk/Tools/TestWebKitAPI/Tests/WebCore/ContentExtensions.cpp        2015-03-11 21:08:51 UTC (rev 181405)
</span><span class="lines">@@ -157,4 +157,62 @@
</span><span class="cx">     testURL(backend, URL(URL(), &quot;http://webkit.org/fobar&quot;), { });
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+const char* matchPastEndOfStringFilter = &quot;[{\&quot;action\&quot;:{\&quot;type\&quot;:\&quot;block\&quot;},\&quot;trigger\&quot;:{\&quot;url-filter\&quot;:\&quot;.+\&quot;}}]&quot;;
+
+TEST_F(ContentExtensionTest, MatchPastEndOfString)
+{
+    auto extensionData = ContentExtensions::compileRuleList(matchPastEndOfStringFilter);
+    auto extension = InMemoryCompiledContentExtension::create(WTF::move(extensionData));
+
+    ContentExtensions::ContentExtensionsBackend backend;
+    backend.addContentExtension(&quot;MatchPastEndOfString&quot;, extension);
+
+    testURL(backend, URL(URL(), &quot;http://webkit.org/&quot;), { ContentExtensions::ActionType::BlockLoad });
+    testURL(backend, URL(URL(), &quot;http://webkit.org/foo&quot;), { ContentExtensions::ActionType::BlockLoad });
+    testURL(backend, URL(URL(), &quot;http://webkit.org/foobar&quot;), { ContentExtensions::ActionType::BlockLoad });
+    testURL(backend, URL(URL(), &quot;http://webkit.org/foobarbar&quot;), { ContentExtensions::ActionType::BlockLoad });
+    testURL(backend, URL(URL(), &quot;http://webkit.org/foofoobar&quot;), { ContentExtensions::ActionType::BlockLoad });
+    testURL(backend, URL(URL(), &quot;http://webkit.org/foobarfoobar&quot;), { ContentExtensions::ActionType::BlockLoad });
+    testURL(backend, URL(URL(), &quot;http://webkit.org/foob&quot;), { ContentExtensions::ActionType::BlockLoad });
+    testURL(backend, URL(URL(), &quot;http://webkit.org/foor&quot;), { ContentExtensions::ActionType::BlockLoad });
+}
+
+const char* startOfLineAssertionFilter = &quot;[{\&quot;action\&quot;:{\&quot;type\&quot;:\&quot;block\&quot;},\&quot;trigger\&quot;:{\&quot;url-filter\&quot;:\&quot;^foobar\&quot;}}]&quot;;
+
+TEST_F(ContentExtensionTest, StartOfLineAssertion)
+{
+    auto extensionData = ContentExtensions::compileRuleList(startOfLineAssertionFilter);
+    auto extension = InMemoryCompiledContentExtension::create(WTF::move(extensionData));
+
+    ContentExtensions::ContentExtensionsBackend backend;
+    backend.addContentExtension(&quot;StartOfLineAssertion&quot;, extension);
+
+    testURL(backend, URL(URL(), &quot;foobar://webkit.org/foobar&quot;), { ContentExtensions::ActionType::BlockLoad });
+    testURL(backend, URL(URL(), &quot;foobars:///foobar&quot;), { ContentExtensions::ActionType::BlockLoad });
+    testURL(backend, URL(URL(), &quot;foobarfoobar:///foobarfoobarfoobar&quot;), { ContentExtensions::ActionType::BlockLoad });
+
+    testURL(backend, URL(URL(), &quot;http://webkit.org/foobarfoo&quot;), { });
+    testURL(backend, URL(URL(), &quot;http://webkit.org/foobarf&quot;), { });
+    testURL(backend, URL(URL(), &quot;http://foobar.org/&quot;), { });
+    testURL(backend, URL(URL(), &quot;http://foobar.org/&quot;), { });
+}
+
+const char* endOfLineAssertionFilter = &quot;[{\&quot;action\&quot;:{\&quot;type\&quot;:\&quot;block\&quot;},\&quot;trigger\&quot;:{\&quot;url-filter\&quot;:\&quot;.*foobar$\&quot;}}]&quot;;
+
+TEST_F(ContentExtensionTest, EndOfLineAssertion)
+{
+    auto extensionData = ContentExtensions::compileRuleList(endOfLineAssertionFilter);
+    auto extension = InMemoryCompiledContentExtension::create(WTF::move(extensionData));
+
+    ContentExtensions::ContentExtensionsBackend backend;
+    backend.addContentExtension(&quot;EndOfLineAssertion&quot;, extension);
+
+    testURL(backend, URL(URL(), &quot;http://webkit.org/foobar&quot;), { ContentExtensions::ActionType::BlockLoad });
+    testURL(backend, URL(URL(), &quot;file:///foobar&quot;), { ContentExtensions::ActionType::BlockLoad });
+    testURL(backend, URL(URL(), &quot;file:///foobarfoobarfoobar&quot;), { ContentExtensions::ActionType::BlockLoad });
+
+    testURL(backend, URL(URL(), &quot;http://webkit.org/foobarfoo&quot;), { });
+    testURL(backend, URL(URL(), &quot;http://webkit.org/foobarf&quot;), { });
+}
+
</ins><span class="cx"> } // namespace TestWebKitAPI
</span></span></pre>
</div>
</div>

</body>
</html>