<!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>[177333] 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/177333">177333</a></dd>
<dt>Author</dt> <dd>commit-queue@webkit.org</dd>
<dt>Date</dt> <dd>2014-12-15 21:56:33 -0800 (Mon, 15 Dec 2014)</dd>
</dl>

<h3>Log Message</h3>
<pre>Extend :lang()'s selector checker to handle ranges with '*' properly and perform matching within the ASCII range
https://bugs.webkit.org/show_bug.cgi?id=139340

Patch by Dhi Aurrahman &lt;diorahman@rockybars.com&gt; on 2014-12-15
Reviewed by Benjamin Poulain.

Source/WebCore:

Asterisk is considered as a valid subtag of a language range to express wildcard matching
in :lang()'s extended filtering procedure. The matching rules introduced by language
range with '*' is outlined in [1].

The matching of subtags is performed case-insensitively within the ASCII range[2].

[1] www.ietf.org/rfc/rfc4647.txt
[2] http://dev.w3.org/csswg/selectors4/#the-lang-pseudo

Test: fast/selectors/lang-equal-ignoring-case.html
      fast/selectors/lang-valid-extended-filtering.html

* css/SelectorCheckerTestFunctions.h:
(WebCore::equalIgnoringCaseWithinASCIIRange): Handle matching case-insensitively within the ASCII range.
(WebCore::containslanguageSubtagMatchingRange):
(WebCore::matchesLangPseudoClass):

LayoutTests:

* fast/selectors/lang-equal-ignoring-ascii-case-expected.txt: Added.
* fast/selectors/lang-equal-ignoring-ascii-case.html: Added.
* fast/selectors/lang-extended-filtering-expected.txt: Updated.
* fast/selectors/lang-extended-filtering.html: Updated.
* fast/selectors/lang-valid-extended-filtering-expected.txt: Added.
* fast/selectors/lang-valid-extended-filtering.html: Added.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkLayoutTestsfastselectorslangextendedfilteringexpectedtxt">trunk/LayoutTests/fast/selectors/lang-extended-filtering-expected.txt</a></li>
<li><a href="#trunkLayoutTestsfastselectorslangextendedfilteringhtml">trunk/LayoutTests/fast/selectors/lang-extended-filtering.html</a></li>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCorecssSelectorCheckerTestFunctionsh">trunk/Source/WebCore/css/SelectorCheckerTestFunctions.h</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsfastselectorslangequalignoringasciicaseexpectedtxt">trunk/LayoutTests/fast/selectors/lang-equal-ignoring-ascii-case-expected.txt</a></li>
<li><a href="#trunkLayoutTestsfastselectorslangequalignoringasciicasehtml">trunk/LayoutTests/fast/selectors/lang-equal-ignoring-ascii-case.html</a></li>
<li><a href="#trunkLayoutTestsfastselectorslangvalidextendedfilteringexpectedtxt">trunk/LayoutTests/fast/selectors/lang-valid-extended-filtering-expected.txt</a></li>
<li><a href="#trunkLayoutTestsfastselectorslangvalidextendedfilteringhtml">trunk/LayoutTests/fast/selectors/lang-valid-extended-filtering.html</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (177332 => 177333)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2014-12-16 04:51:22 UTC (rev 177332)
+++ trunk/LayoutTests/ChangeLog        2014-12-16 05:56:33 UTC (rev 177333)
</span><span class="lines">@@ -1,3 +1,17 @@
</span><ins>+2014-12-15  Dhi Aurrahman  &lt;diorahman@rockybars.com&gt;
+
+        Extend :lang()'s selector checker to handle ranges with '*' properly and perform matching within the ASCII range
+        https://bugs.webkit.org/show_bug.cgi?id=139340
+
+        Reviewed by Benjamin Poulain.
+
+        * fast/selectors/lang-equal-ignoring-ascii-case-expected.txt: Added.
+        * fast/selectors/lang-equal-ignoring-ascii-case.html: Added.
+        * fast/selectors/lang-extended-filtering-expected.txt: Updated.
+        * fast/selectors/lang-extended-filtering.html: Updated.
+        * fast/selectors/lang-valid-extended-filtering-expected.txt: Added.
+        * fast/selectors/lang-valid-extended-filtering.html: Added.
+
</ins><span class="cx"> 2014-12-15  Said Abou-Hallawa  &lt;sabouhallawa@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Import Mozilla test suite for SVG.
</span></span></pre></div>
<a id="trunkLayoutTestsfastselectorslangequalignoringasciicaseexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/selectors/lang-equal-ignoring-ascii-case-expected.txt (0 => 177333)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/selectors/lang-equal-ignoring-ascii-case-expected.txt                                (rev 0)
+++ trunk/LayoutTests/fast/selectors/lang-equal-ignoring-ascii-case-expected.txt        2014-12-16 05:56:33 UTC (rev 177333)
</span><span class="lines">@@ -0,0 +1,27 @@
</span><ins>+Verify :lang()'s equal ignoring ascii case
+
+On success, you will see a series of &quot;PASS&quot; messages, followed by &quot;TEST COMPLETE&quot;.
+
+
+PASS document.querySelector(':lang(Aà)') is document.getElementById('a')
+PASS document.querySelector(':lang(aÀ)') is null
+PASS document.querySelector(':lang(AÀ)') is null
+PASS document.querySelector(':lang(Cč)') is document.getElementById('c')
+PASS document.querySelector(':lang(cÄŒ)') is null
+PASS document.querySelector(':lang(CÄŒ)') is null
+PASS document.querySelector(':lang(eê)') is document.getElementById('e')
+PASS document.querySelector(':lang(eÊ)') is null
+PASS document.querySelector(':lang(EÊ)') is null
+PASS document.querySelector(':lang(Iį)') is document.getElementById('i')
+PASS document.querySelector(':lang(iÄ®)') is null
+PASS document.querySelector(':lang(IÄ®)') is null
+PASS document.querySelector(':lang(uû)') is document.getElementById('u')
+PASS document.querySelector(':lang(uÛ)') is null
+PASS document.querySelector(':lang(UÛ)') is null
+PASS document.querySelector(':lang(oø)') is document.getElementById('o')
+PASS document.querySelector(':lang(oØ)') is null
+PASS document.querySelector(':lang(OØ)') is null
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="trunkLayoutTestsfastselectorslangequalignoringasciicasehtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/selectors/lang-equal-ignoring-ascii-case.html (0 => 177333)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/selectors/lang-equal-ignoring-ascii-case.html                                (rev 0)
+++ trunk/LayoutTests/fast/selectors/lang-equal-ignoring-ascii-case.html        2014-12-16 05:56:33 UTC (rev 177333)
</span><span class="lines">@@ -0,0 +1,42 @@
</span><ins>+&lt;!doctype html&gt;
+&lt;html&gt;
+&lt;head&gt;
+&lt;script src=&quot;../../resources/js-test-pre.js&quot;&gt;&lt;/script&gt;
+&lt;/head&gt;
+&lt;body&gt;
+    &lt;div id=&quot;a&quot; lang=&quot;aà&quot;&gt;&lt;/div&gt;
+    &lt;div id=&quot;c&quot; lang=&quot;cč&quot;&gt;&lt;/div&gt;
+    &lt;div id=&quot;e&quot; lang=&quot;eê&quot;&gt;&lt;/div&gt;
+    &lt;div id=&quot;i&quot; lang=&quot;iį&quot;&gt;&lt;/div&gt;
+    &lt;div id=&quot;u&quot; lang=&quot;uû&quot;&gt;&lt;/div&gt;
+    &lt;div id=&quot;o&quot; lang=&quot;oø&quot;&gt;&lt;/div&gt;
+&lt;script&gt;
+description('Verify :lang()\'s equal ignoring ascii case');
+
+shouldBe(&quot;document.querySelector(':lang(Aà)')&quot;, &quot;document.getElementById('a')&quot;);
+shouldBeNull(&quot;document.querySelector(':lang(aÀ)')&quot;);
+shouldBeNull(&quot;document.querySelector(':lang(AÀ)')&quot;);
+
+shouldBe(&quot;document.querySelector(':lang(Cč)')&quot;, &quot;document.getElementById('c')&quot;);
+shouldBeNull(&quot;document.querySelector(':lang(cČ)')&quot;);
+shouldBeNull(&quot;document.querySelector(':lang(CČ)')&quot;);
+
+shouldBe(&quot;document.querySelector(':lang(eê)')&quot;, &quot;document.getElementById('e')&quot;);
+shouldBeNull(&quot;document.querySelector(':lang(eÊ)')&quot;);
+shouldBeNull(&quot;document.querySelector(':lang(EÊ)')&quot;);
+
+shouldBe(&quot;document.querySelector(':lang(Iį)')&quot;, &quot;document.getElementById('i')&quot;);
+shouldBeNull(&quot;document.querySelector(':lang(iĮ)')&quot;);
+shouldBeNull(&quot;document.querySelector(':lang(IĮ)')&quot;);
+
+shouldBe(&quot;document.querySelector(':lang(uû)')&quot;, &quot;document.getElementById('u')&quot;);
+shouldBeNull(&quot;document.querySelector(':lang(uÛ)')&quot;);
+shouldBeNull(&quot;document.querySelector(':lang(UÛ)')&quot;);
+
+shouldBe(&quot;document.querySelector(':lang(oø)')&quot;, &quot;document.getElementById('o')&quot;);
+shouldBeNull(&quot;document.querySelector(':lang(oØ)')&quot;);
+shouldBeNull(&quot;document.querySelector(':lang(OØ)')&quot;);
+&lt;/script&gt;
+&lt;script src=&quot;../../resources/js-test-post.js&quot;&gt;&lt;/script&gt;
+&lt;/body&gt;
+&lt;/html&gt;
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkLayoutTestsfastselectorslangextendedfilteringexpectedtxt"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/fast/selectors/lang-extended-filtering-expected.txt (177332 => 177333)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/selectors/lang-extended-filtering-expected.txt        2014-12-16 04:51:22 UTC (rev 177332)
+++ trunk/LayoutTests/fast/selectors/lang-extended-filtering-expected.txt        2014-12-16 05:56:33 UTC (rev 177333)
</span><span class="lines">@@ -1,4 +1,4 @@
</span><del>-Verify selector specifying extended filetring of :lang() pseudo class
</del><ins>+Verify selector specifying extended filtering of :lang() pseudo class
</ins><span class="cx"> 
</span><span class="cx"> On success, you will see a series of &quot;PASS&quot; messages, followed by &quot;TEST COMPLETE&quot;.
</span><span class="cx"> 
</span><span class="lines">@@ -79,9 +79,73 @@
</span><span class="cx"> PASS document.querySelectorAll(&quot;:lang(tic-tac-toe)&quot;).length is 1
</span><span class="cx"> PASS document.querySelectorAll(&quot;:lang(tic-toe-tac)&quot;).length is 0
</span><span class="cx"> 
</span><ins>+PASS document.querySelectorAll(&quot;:lang(\\*)&quot;).length is 35
+PASS document.querySelectorAll(&quot;:lang(*-CH)&quot;).length is 5
+
+PASS document.querySelectorAll(&quot;:lang(a)&quot;).length is 2
+PASS document.querySelectorAll(&quot;:lang(a-\\*)&quot;).length is 1
+PASS document.querySelectorAll(&quot;:lang(*-fr-\\*)&quot;).length is 2
+PASS document.querySelectorAll(&quot;:lang(*-\\*-lang)&quot;).length is 2
+PASS document.querySelectorAll(&quot;:lang(*-\\*-aa-bb-cc-dd)&quot;).length is 3
+PASS document.querySelectorAll(&quot;:lang(*-\\*-\\*-bb-cc-dd)&quot;).length is 3
+PASS document.querySelectorAll(&quot;:lang(*-\\*-\\*-\\*-cc-dd)&quot;).length is 3
+PASS document.querySelectorAll(&quot;:lang(*-\\*-\\*-\\*-\\*-dd)&quot;).length is 3
+PASS document.querySelectorAll(&quot;:lang(*-\\*-\\*-\\*-\\*-\\*)&quot;).length is 3
+PASS document.querySelectorAll(&quot;:lang(*-\\*-aa-\\*-cc-\\*)&quot;).length is 3
+PASS document.querySelectorAll(&quot;:lang(*-\\*-\\*-bb-\\*)&quot;).length is 3
+PASS document.querySelectorAll(&quot;:lang(fooÉ)&quot;).length is 1
+PASS document.querySelectorAll(&quot;:lang(fOOÉ)&quot;).length is 1
+PASS document.querySelectorAll(&quot;:lang(FoOÉ)&quot;).length is 1
+PASS document.querySelectorAll(&quot;:lang(FOOÉ)&quot;).length is 1
+PASS document.querySelectorAll(&quot;:lang(fooé)&quot;).length is 0
+PASS document.querySelectorAll(&quot;:lang(FOOé)&quot;).length is 0
+PASS document.querySelectorAll(&quot;:lang(foöÉ-bÁr)&quot;).length is 1
+PASS document.querySelectorAll(&quot;:lang(FoöÉ-bÁr)&quot;).length is 1
+PASS document.querySelectorAll(&quot;:lang(FOöÉ-bÁr)&quot;).length is 1
+PASS document.querySelectorAll(&quot;:lang(FOòÉ-bÁr)&quot;).length is 0
+PASS document.querySelectorAll(&quot;:lang(FOòę-bÁr)&quot;).length is 0
+PASS document.querySelectorAll(&quot;:lang(foöÉ-\\*)&quot;).length is 1
+PASS document.querySelectorAll(&quot;:lang(\\*-bÁr)&quot;).length is 1
+PASS document.querySelectorAll(&quot;:lang(\\*-BÁr)&quot;).length is 1
+PASS document.querySelectorAll(&quot;:lang(\\*-BÁR)&quot;).length is 1
+PASS document.querySelectorAll(&quot;:lang(\\*-Bár)&quot;).length is 0
+PASS document.querySelectorAll(&quot;:lang(\\*-báR)&quot;).length is 0
+PASS document.querySelectorAll(&quot;:lang(\\*-BáR)&quot;).length is 0
+
+PASS document.querySelectorAll(&quot;:lang(FOöÉ-BÁr)&quot;).length is 1
+PASS document.querySelectorAll(&quot;:lang(FOöÉ-BÁ)&quot;).length is 0
+PASS document.querySelectorAll(&quot;:lang(FOöÉ-B)&quot;).length is 0
+PASS document.querySelectorAll(&quot;:lang(f-BÁr)&quot;).length is 0
+PASS document.querySelectorAll(&quot;:lang(fO-BÁr)&quot;).length is 0
+PASS document.querySelectorAll(&quot;:lang(fOö-BÁr)&quot;).length is 0
+PASS document.querySelectorAll(&quot;:lang(FOöÉ-BÁr1)&quot;).length is 0
+PASS document.querySelectorAll(&quot;:lang(FOöÉ-BÁr12)&quot;).length is 0
+PASS document.querySelectorAll(&quot;:lang(FOöÉ-BÁr123)&quot;).length is 0
+PASS document.querySelectorAll(&quot;:lang(F-Xe)&quot;).length is 0
+PASS document.querySelectorAll(&quot;:lang(Fr-Xe)&quot;).length is 0
+PASS document.querySelectorAll(&quot;:lang(fr-Xe)&quot;).length is 0
+PASS document.querySelectorAll(&quot;:lang(fr-Xen)&quot;).length is 0
+PASS document.querySelectorAll(&quot;:lang(fr-Xeno)&quot;).length is 0
+PASS document.querySelectorAll(&quot;:lang(fr-Xenom)&quot;).length is 0
+PASS document.querySelectorAll(&quot;:lang(fr-Xenomo)&quot;).length is 0
+PASS document.querySelectorAll(&quot;:lang(fr-Xenomor)&quot;).length is 0
+PASS document.querySelectorAll(&quot;:lang(fr-Xenomorp)&quot;).length is 0
+PASS document.querySelectorAll(&quot;:lang(fr-Xènömòrph)&quot;).length is 0
+PASS document.querySelectorAll(&quot;:lang(FR-XENOMORPH)&quot;).length is 1
+PASS document.querySelectorAll(&quot;:lang(foöÉbÁr)&quot;).length is 1
+PASS document.querySelectorAll(&quot;:lang(foöÉbÁ)&quot;).length is 0
+PASS document.querySelectorAll(&quot;:lang(foöÉb)&quot;).length is 0
+PASS document.querySelectorAll(&quot;:lang(foöÉ)&quot;).length is 1
+PASS document.querySelectorAll(&quot;:lang(foö)&quot;).length is 0
+PASS document.querySelectorAll(&quot;:lang(fo)&quot;).length is 0
+PASS document.querySelectorAll(&quot;:lang(f)&quot;).length is 0
+
+PASS document.querySelectorAll(&quot;:lang(*)&quot;).length threw exception Error: SyntaxError: DOM Exception 12.
+PASS document.querySelectorAll(&quot;:lang(*foöÉ)&quot;).length threw exception Error: SyntaxError: DOM Exception 12.
</ins><span class="cx"> PASS document.querySelectorAll(&quot;:lang(--en--)&quot;).length threw exception Error: SyntaxError: DOM Exception 12.
</span><span class="cx"> PASS document.querySelectorAll(&quot;:lang(---en---)&quot;).length threw exception Error: SyntaxError: DOM Exception 12.
</span><span class="cx"> PASS document.querySelectorAll(&quot;:lang(en us- de- fr-).length&quot;) threw exception Error: SyntaxError: DOM Exception 12.
</span><ins>+PASS document.querySelectorAll(&quot;:lang(-\\* \\*-)&quot;).length threw exception Error: SyntaxError: DOM Exception 12.
</ins><span class="cx"> PASS successfullyParsed is true
</span><span class="cx"> 
</span><span class="cx"> TEST COMPLETE
</span></span></pre></div>
<a id="trunkLayoutTestsfastselectorslangextendedfilteringhtml"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/fast/selectors/lang-extended-filtering.html (177332 => 177333)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/selectors/lang-extended-filtering.html        2014-12-16 04:51:22 UTC (rev 177332)
+++ trunk/LayoutTests/fast/selectors/lang-extended-filtering.html        2014-12-16 05:56:33 UTC (rev 177333)
</span><span class="lines">@@ -37,8 +37,26 @@
</span><span class="cx">     &lt;div lang=&quot;cocoa-1-bar&quot;&gt;&lt;/div&gt;
</span><span class="cx">     &lt;div lang=&quot;cocoa-a-bar&quot;&gt;&lt;/div&gt;
</span><span class="cx"> 
</span><ins>+    &lt;div lang=&quot;a&quot;&gt;&lt;/div&gt;
+    &lt;div lang=&quot;a-fr-lang&quot;&gt;&lt;/div&gt;
+    &lt;div lang=&quot;b-fr-lang&quot;&gt;&lt;/div&gt;
+
+    &lt;div lang=&quot;de-CH&quot;&gt;&lt;/div&gt;
+    &lt;div lang=&quot;it-CH&quot;&gt;&lt;/div&gt;
+    &lt;div lang=&quot;fr-CH&quot;&gt;&lt;/div&gt;
+    &lt;div lang=&quot;rm-CH&quot;&gt;&lt;/div&gt;
+    &lt;div lang=&quot;es-CH&quot;&gt;&lt;/div&gt;
+
+    &lt;div lang=&quot;es1-KK-aa-bb-cc-dd&quot;&gt;&lt;/div&gt;
+    &lt;div lang=&quot;es2-KL-aa-bb-cc-dd&quot;&gt;&lt;/div&gt;
+    &lt;div lang=&quot;es3-KM-aa-bb-cc-dd&quot;&gt;&lt;/div&gt;
+
+    &lt;div lang=&quot;fooÉ&quot;&gt;&lt;/div&gt;
+    &lt;div lang=&quot;foöÉ-bÁr&quot;&gt;&lt;/div&gt;
+    &lt;div lang=&quot;foöÉbÁr&quot;&gt;&lt;/div&gt;
+
</ins><span class="cx">     &lt;script&gt;
</span><del>-    description('Verify selector specifying extended filetring of :lang() pseudo class');
</del><ins>+    description('Verify selector specifying extended filtering of :lang() pseudo class');
</ins><span class="cx"> 
</span><span class="cx">     shouldBe('document.querySelectorAll(&quot;:lang(en)&quot;).length', '3');
</span><span class="cx">     shouldBe('document.querySelectorAll(&quot;:lang(en-)&quot;).length', '2');
</span><span class="lines">@@ -138,9 +156,87 @@
</span><span class="cx"> 
</span><span class="cx">     debug('');
</span><span class="cx"> 
</span><ins>+    shouldBe('document.querySelectorAll(&quot;:lang(\\\\*)&quot;).length', '35');
+    shouldBe('document.querySelectorAll(&quot;:lang(*-CH)&quot;).length', '5');
+
+    debug('');  
+
+    shouldBe('document.querySelectorAll(&quot;:lang(a)&quot;).length', '2');
+    shouldBe('document.querySelectorAll(&quot;:lang(a-\\\\*)&quot;).length', '1');
+    shouldBe('document.querySelectorAll(&quot;:lang(*-fr-\\\\*)&quot;).length', '2');
+    shouldBe('document.querySelectorAll(&quot;:lang(*-\\\\*-lang)&quot;).length', '2');   
+
+    shouldBe('document.querySelectorAll(&quot;:lang(*-\\\\*-aa-bb-cc-dd)&quot;).length', '3');
+    shouldBe('document.querySelectorAll(&quot;:lang(*-\\\\*-\\\\*-bb-cc-dd)&quot;).length', '3');
+    shouldBe('document.querySelectorAll(&quot;:lang(*-\\\\*-\\\\*-\\\\*-cc-dd)&quot;).length', '3');
+    shouldBe('document.querySelectorAll(&quot;:lang(*-\\\\*-\\\\*-\\\\*-\\\\*-dd)&quot;).length', '3');
+    shouldBe('document.querySelectorAll(&quot;:lang(*-\\\\*-\\\\*-\\\\*-\\\\*-\\\\*)&quot;).length', '3');
+    shouldBe('document.querySelectorAll(&quot;:lang(*-\\\\*-aa-\\\\*-cc-\\\\*)&quot;).length', '3');
+    shouldBe('document.querySelectorAll(&quot;:lang(*-\\\\*-\\\\*-bb-\\\\*)&quot;).length', '3');
+
+    shouldBe('document.querySelectorAll(&quot;:lang(fooÉ)&quot;).length', '1');
+    shouldBe('document.querySelectorAll(&quot;:lang(fOOÉ)&quot;).length', '1');
+    shouldBe('document.querySelectorAll(&quot;:lang(FoOÉ)&quot;).length', '1');
+    shouldBe('document.querySelectorAll(&quot;:lang(FOOÉ)&quot;).length', '1');
+    shouldBe('document.querySelectorAll(&quot;:lang(fooé)&quot;).length', '0');
+    shouldBe('document.querySelectorAll(&quot;:lang(FOOé)&quot;).length', '0');
+
+    shouldBe('document.querySelectorAll(&quot;:lang(foöÉ-bÁr)&quot;).length', '1');
+    shouldBe('document.querySelectorAll(&quot;:lang(FoöÉ-bÁr)&quot;).length', '1');
+    shouldBe('document.querySelectorAll(&quot;:lang(FOöÉ-bÁr)&quot;).length', '1');
+    shouldBe('document.querySelectorAll(&quot;:lang(FOòÉ-bÁr)&quot;).length', '0');
+    shouldBe('document.querySelectorAll(&quot;:lang(FOòę-bÁr)&quot;).length', '0');
+
+    shouldBe('document.querySelectorAll(&quot;:lang(foöÉ-\\\\*)&quot;).length', '1');
+    shouldBe('document.querySelectorAll(&quot;:lang(\\\\*-bÁr)&quot;).length', '1');
+    shouldBe('document.querySelectorAll(&quot;:lang(\\\\*-BÁr)&quot;).length', '1');
+    shouldBe('document.querySelectorAll(&quot;:lang(\\\\*-BÁR)&quot;).length', '1');
+    shouldBe('document.querySelectorAll(&quot;:lang(\\\\*-Bár)&quot;).length', '0');
+    shouldBe('document.querySelectorAll(&quot;:lang(\\\\*-báR)&quot;).length', '0');
+    shouldBe('document.querySelectorAll(&quot;:lang(\\\\*-BáR)&quot;).length', '0');
+
+    debug('');
+
+    shouldBe('document.querySelectorAll(&quot;:lang(FOöÉ-BÁr)&quot;).length', '1');
+    shouldBe('document.querySelectorAll(&quot;:lang(FOöÉ-BÁ)&quot;).length', '0');
+    shouldBe('document.querySelectorAll(&quot;:lang(FOöÉ-B)&quot;).length', '0');
+
+    shouldBe('document.querySelectorAll(&quot;:lang(f-BÁr)&quot;).length', '0');
+    shouldBe('document.querySelectorAll(&quot;:lang(fO-BÁr)&quot;).length', '0');
+    shouldBe('document.querySelectorAll(&quot;:lang(fOö-BÁr)&quot;).length', '0');
+    shouldBe('document.querySelectorAll(&quot;:lang(FOöÉ-BÁr1)&quot;).length', '0');
+    shouldBe('document.querySelectorAll(&quot;:lang(FOöÉ-BÁr12)&quot;).length', '0');
+    shouldBe('document.querySelectorAll(&quot;:lang(FOöÉ-BÁr123)&quot;).length', '0');
+
+    shouldBe('document.querySelectorAll(&quot;:lang(F-Xe)&quot;).length', '0');
+    shouldBe('document.querySelectorAll(&quot;:lang(Fr-Xe)&quot;).length', '0');
+    shouldBe('document.querySelectorAll(&quot;:lang(fr-Xe)&quot;).length', '0');
+    shouldBe('document.querySelectorAll(&quot;:lang(fr-Xen)&quot;).length', '0');
+    shouldBe('document.querySelectorAll(&quot;:lang(fr-Xeno)&quot;).length', '0');
+    shouldBe('document.querySelectorAll(&quot;:lang(fr-Xenom)&quot;).length', '0');
+    shouldBe('document.querySelectorAll(&quot;:lang(fr-Xenomo)&quot;).length', '0');
+    shouldBe('document.querySelectorAll(&quot;:lang(fr-Xenomor)&quot;).length', '0');
+    shouldBe('document.querySelectorAll(&quot;:lang(fr-Xenomorp)&quot;).length', '0');
+    shouldBe('document.querySelectorAll(&quot;:lang(fr-Xènömòrph)&quot;).length', '0');
+    shouldBe('document.querySelectorAll(&quot;:lang(FR-XENOMORPH)&quot;).length', '1');
+
+    shouldBe('document.querySelectorAll(&quot;:lang(foöÉbÁr)&quot;).length', '1');
+    shouldBe('document.querySelectorAll(&quot;:lang(foöÉbÁ)&quot;).length', '0');
+    shouldBe('document.querySelectorAll(&quot;:lang(foöÉb)&quot;).length', '0');
+    shouldBe('document.querySelectorAll(&quot;:lang(foöÉ)&quot;).length', '1');
+    shouldBe('document.querySelectorAll(&quot;:lang(foö)&quot;).length', '0');
+    shouldBe('document.querySelectorAll(&quot;:lang(fo)&quot;).length', '0');
+    shouldBe('document.querySelectorAll(&quot;:lang(f)&quot;).length', '0');
+
+    debug('');
+
+    shouldThrow('document.querySelectorAll(&quot;:lang(*)&quot;).length');
+    shouldThrow('document.querySelectorAll(&quot;:lang(*foöÉ)&quot;).length');
</ins><span class="cx">     shouldThrow('document.querySelectorAll(&quot;:lang(--en--)&quot;).length');
</span><span class="cx">     shouldThrow('document.querySelectorAll(&quot;:lang(---en---)&quot;).length');
</span><span class="cx">     shouldThrow('document.querySelectorAll(&quot;:lang(en us- de- fr-).length&quot;)');
</span><ins>+    shouldThrow('document.querySelectorAll(&quot;:lang(-\\\\* \\\\*-)&quot;).length');
+
</ins><span class="cx">     &lt;/script&gt;
</span><span class="cx">     &lt;script src=&quot;../../resources/js-test-post.js&quot;&gt;&lt;/script&gt;
</span><span class="cx"> &lt;/body&gt;
</span></span></pre></div>
<a id="trunkLayoutTestsfastselectorslangvalidextendedfilteringexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/selectors/lang-valid-extended-filtering-expected.txt (0 => 177333)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/selectors/lang-valid-extended-filtering-expected.txt                                (rev 0)
+++ trunk/LayoutTests/fast/selectors/lang-valid-extended-filtering-expected.txt        2014-12-16 05:56:33 UTC (rev 177333)
</span><span class="lines">@@ -0,0 +1,594 @@
</span><ins>+Verify selector specifying extended filtering of :lang() pseudo class
+
+On success, you will see a series of &quot;PASS&quot; messages, followed by &quot;TEST COMPLETE&quot;.
+
+
+- af-ZA
+PASS document.querySelectorAll(':lang(af)').length == 1 is true
+PASS document.querySelectorAll(':lang(af-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(af-ZA)').length == 1 is true
+PASS document.querySelectorAll(':lang(af-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(*-ZA)').length == 1 is true
+
+- ar-AE
+PASS document.querySelectorAll(':lang(ar)').length == 1 is true
+PASS document.querySelectorAll(':lang(ar-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(ar-AE)').length == 1 is true
+PASS document.querySelectorAll(':lang(ar-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(*-AE)').length == 1 is true
+
+- ar-BH
+PASS document.querySelectorAll(':lang(ar)').length == 1 is true
+PASS document.querySelectorAll(':lang(ar-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(ar-BH)').length == 1 is true
+PASS document.querySelectorAll(':lang(ar-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(*-BH)').length == 1 is true
+
+- ar-YE
+PASS document.querySelectorAll(':lang(ar)').length == 1 is true
+PASS document.querySelectorAll(':lang(ar-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(ar-YE)').length == 1 is true
+PASS document.querySelectorAll(':lang(ar-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(*-YE)').length == 1 is true
+
+- art-lojban
+PASS document.querySelectorAll(':lang(art)').length == 1 is true
+PASS document.querySelectorAll(':lang(art-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(art-lojban)').length == 1 is true
+PASS document.querySelectorAll(':lang(art-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(*-lojban)').length == 1 is true
+
+- az-Arab-IR
+PASS document.querySelectorAll(':lang(az)').length == 1 is true
+PASS document.querySelectorAll(':lang(az-\\*-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(az-Arab)').length == 1 is true
+PASS document.querySelectorAll(':lang(az-\\*-IR)').length == 1 is true
+PASS document.querySelectorAll(':lang(az-Arab-IR)').length == 1 is true
+PASS document.querySelectorAll(':lang(az-Arab-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(*-Arab-IR)').length == 1 is true
+
+- be-BY
+PASS document.querySelectorAll(':lang(be)').length == 1 is true
+PASS document.querySelectorAll(':lang(be-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(be-BY)').length == 1 is true
+PASS document.querySelectorAll(':lang(be-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(*-BY)').length == 1 is true
+
+- bg-BG
+PASS document.querySelectorAll(':lang(bg)').length == 1 is true
+PASS document.querySelectorAll(':lang(bg-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(bg-BG)').length == 1 is true
+PASS document.querySelectorAll(':lang(bg-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(*-BG)').length == 1 is true
+
+- ca-ES
+PASS document.querySelectorAll(':lang(ca)').length == 1 is true
+PASS document.querySelectorAll(':lang(ca-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(ca-ES)').length == 1 is true
+PASS document.querySelectorAll(':lang(ca-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(*-ES)').length == 1 is true
+
+- cs-CZ
+PASS document.querySelectorAll(':lang(cs)').length == 1 is true
+PASS document.querySelectorAll(':lang(cs-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(cs-CZ)').length == 1 is true
+PASS document.querySelectorAll(':lang(cs-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(*-CZ)').length == 1 is true
+
+- cy-GB
+PASS document.querySelectorAll(':lang(cy)').length == 1 is true
+PASS document.querySelectorAll(':lang(cy-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(cy-GB)').length == 1 is true
+PASS document.querySelectorAll(':lang(cy-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(*-GB)').length == 1 is true
+
+- de-AT
+PASS document.querySelectorAll(':lang(de)').length == 1 is true
+PASS document.querySelectorAll(':lang(de-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(de-AT)').length == 1 is true
+PASS document.querySelectorAll(':lang(de-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(*-AT)').length == 1 is true
+
+- de-CH
+PASS document.querySelectorAll(':lang(de)').length == 1 is true
+PASS document.querySelectorAll(':lang(de-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(de-CH)').length == 1 is true
+PASS document.querySelectorAll(':lang(de-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(*-CH)').length == 1 is true
+
+- de-CH-1996
+PASS document.querySelectorAll(':lang(de)').length == 1 is true
+PASS document.querySelectorAll(':lang(de-\\*-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(de-CH)').length == 1 is true
+PASS document.querySelectorAll(':lang(de-\\*-1996)').length == 1 is true
+PASS document.querySelectorAll(':lang(de-CH-1996)').length == 1 is true
+PASS document.querySelectorAll(':lang(de-CH-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(*-CH-1996)').length == 1 is true
+
+- de-CH-1997
+PASS document.querySelectorAll(':lang(de)').length == 1 is true
+PASS document.querySelectorAll(':lang(de-\\*-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(de-CH)').length == 1 is true
+PASS document.querySelectorAll(':lang(de-\\*-1997)').length == 1 is true
+PASS document.querySelectorAll(':lang(de-CH-1997)').length == 1 is true
+PASS document.querySelectorAll(':lang(de-CH-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(*-CH-1997)').length == 1 is true
+
+- de-DE
+PASS document.querySelectorAll(':lang(de)').length == 1 is true
+PASS document.querySelectorAll(':lang(de-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(de-DE)').length == 1 is true
+PASS document.querySelectorAll(':lang(de-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(*-DE)').length == 1 is true
+
+- de-DE-1996
+PASS document.querySelectorAll(':lang(de)').length == 1 is true
+PASS document.querySelectorAll(':lang(de-\\*-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(de-DE)').length == 1 is true
+PASS document.querySelectorAll(':lang(de-\\*-1996)').length == 1 is true
+PASS document.querySelectorAll(':lang(de-DE-1996)').length == 1 is true
+PASS document.querySelectorAll(':lang(de-DE-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(*-DE-1996)').length == 1 is true
+
+- de-Latn-DE
+PASS document.querySelectorAll(':lang(de)').length == 1 is true
+PASS document.querySelectorAll(':lang(de-\\*-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(de-Latn)').length == 1 is true
+PASS document.querySelectorAll(':lang(de-\\*-DE)').length == 1 is true
+PASS document.querySelectorAll(':lang(de-Latn-DE)').length == 1 is true
+PASS document.querySelectorAll(':lang(de-Latn-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(*-Latn-DE)').length == 1 is true
+
+- de-Latf-DE
+PASS document.querySelectorAll(':lang(de)').length == 1 is true
+PASS document.querySelectorAll(':lang(de-\\*-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(de-Latf)').length == 1 is true
+PASS document.querySelectorAll(':lang(de-\\*-DE)').length == 1 is true
+PASS document.querySelectorAll(':lang(de-Latf-DE)').length == 1 is true
+PASS document.querySelectorAll(':lang(de-Latf-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(*-Latf-DE)').length == 1 is true
+
+- de-Latn-DE-1996
+PASS document.querySelectorAll(':lang(de)').length == 1 is true
+PASS document.querySelectorAll(':lang(de-\\*-\\*-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(de-Latn)').length == 1 is true
+PASS document.querySelectorAll(':lang(de-\\*-DE-1996)').length == 1 is true
+PASS document.querySelectorAll(':lang(de-Latn-DE)').length == 1 is true
+PASS document.querySelectorAll(':lang(de-Latn-\\*-1996)').length == 1 is true
+PASS document.querySelectorAll(':lang(de-Latn-DE-1996)').length == 1 is true
+PASS document.querySelectorAll(':lang(de-Latn-DE-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(*-Latn-DE-1996)').length == 1 is true
+
+- en-US
+PASS document.querySelectorAll(':lang(en)').length == 1 is true
+PASS document.querySelectorAll(':lang(en-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(en-US)').length == 1 is true
+PASS document.querySelectorAll(':lang(en-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(*-US)').length == 1 is true
+
+- en-GB
+PASS document.querySelectorAll(':lang(en)').length == 1 is true
+PASS document.querySelectorAll(':lang(en-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(en-GB)').length == 1 is true
+PASS document.querySelectorAll(':lang(en-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(*-GB)').length == 1 is true
+
+- en-Latn-Brai
+PASS document.querySelectorAll(':lang(en)').length == 1 is true
+PASS document.querySelectorAll(':lang(en-\\*-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(en-Latn)').length == 1 is true
+PASS document.querySelectorAll(':lang(en-\\*-Brai)').length == 1 is true
+PASS document.querySelectorAll(':lang(en-Latn-Brai)').length == 1 is true
+PASS document.querySelectorAll(':lang(en-Latn-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(*-Latn-Brai)').length == 1 is true
+
+- es-ES
+PASS document.querySelectorAll(':lang(es)').length == 1 is true
+PASS document.querySelectorAll(':lang(es-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(es-ES)').length == 1 is true
+PASS document.querySelectorAll(':lang(es-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(*-ES)').length == 1 is true
+
+- es-ES-valencia
+PASS document.querySelectorAll(':lang(es)').length == 1 is true
+PASS document.querySelectorAll(':lang(es-\\*-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(es-ES)').length == 1 is true
+PASS document.querySelectorAll(':lang(es-\\*-valencia)').length == 1 is true
+PASS document.querySelectorAll(':lang(es-ES-valencia)').length == 1 is true
+PASS document.querySelectorAll(':lang(es-ES-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(*-ES-valencia)').length == 1 is true
+
+- es-AR
+PASS document.querySelectorAll(':lang(es)').length == 1 is true
+PASS document.querySelectorAll(':lang(es-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(es-AR)').length == 1 is true
+PASS document.querySelectorAll(':lang(es-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(*-AR)').length == 1 is true
+
+- fr-BE
+PASS document.querySelectorAll(':lang(fr)').length == 1 is true
+PASS document.querySelectorAll(':lang(fr-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(fr-BE)').length == 1 is true
+PASS document.querySelectorAll(':lang(fr-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(*-BE)').length == 1 is true
+
+- fr-CA
+PASS document.querySelectorAll(':lang(fr)').length == 1 is true
+PASS document.querySelectorAll(':lang(fr-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(fr-CA)').length == 1 is true
+PASS document.querySelectorAll(':lang(fr-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(*-CA)').length == 1 is true
+
+- fr-CH
+PASS document.querySelectorAll(':lang(fr)').length == 1 is true
+PASS document.querySelectorAll(':lang(fr-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(fr-CH)').length == 1 is true
+PASS document.querySelectorAll(':lang(fr-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(*-CH)').length == 1 is true
+
+- fr-FR
+PASS document.querySelectorAll(':lang(fr)').length == 1 is true
+PASS document.querySelectorAll(':lang(fr-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(fr-FR)').length == 1 is true
+PASS document.querySelectorAll(':lang(fr-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(*-FR)').length == 1 is true
+
+- fr-LU
+PASS document.querySelectorAll(':lang(fr)').length == 1 is true
+PASS document.querySelectorAll(':lang(fr-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(fr-LU)').length == 1 is true
+PASS document.querySelectorAll(':lang(fr-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(*-LU)').length == 1 is true
+
+- fr-MC
+PASS document.querySelectorAll(':lang(fr)').length == 1 is true
+PASS document.querySelectorAll(':lang(fr-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(fr-MC)').length == 1 is true
+PASS document.querySelectorAll(':lang(fr-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(*-MC)').length == 1 is true
+
+- gl-ES
+PASS document.querySelectorAll(':lang(gl)').length == 1 is true
+PASS document.querySelectorAll(':lang(gl-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(gl-ES)').length == 1 is true
+PASS document.querySelectorAll(':lang(gl-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(*-ES)').length == 1 is true
+
+- gu-IN
+PASS document.querySelectorAll(':lang(gu)').length == 1 is true
+PASS document.querySelectorAll(':lang(gu-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(gu-IN)').length == 1 is true
+PASS document.querySelectorAll(':lang(gu-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(*-IN)').length == 1 is true
+
+- hr-BA
+PASS document.querySelectorAll(':lang(hr)').length == 1 is true
+PASS document.querySelectorAll(':lang(hr-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(hr-BA)').length == 1 is true
+PASS document.querySelectorAll(':lang(hr-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(*-BA)').length == 1 is true
+
+- id-ID
+PASS document.querySelectorAll(':lang(id)').length == 1 is true
+PASS document.querySelectorAll(':lang(id-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(id-ID)').length == 1 is true
+PASS document.querySelectorAll(':lang(id-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(*-ID)').length == 1 is true
+
+- i-klingon
+PASS document.querySelectorAll(':lang(i)').length == 1 is true
+PASS document.querySelectorAll(':lang(i-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(i-klingon)').length == 1 is true
+PASS document.querySelectorAll(':lang(i-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(*-klingon)').length == 1 is true
+
+- ja-JP
+PASS document.querySelectorAll(':lang(ja)').length == 1 is true
+PASS document.querySelectorAll(':lang(ja-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(ja-JP)').length == 1 is true
+PASS document.querySelectorAll(':lang(ja-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(*-JP)').length == 1 is true
+
+- ko-KR
+PASS document.querySelectorAll(':lang(ko)').length == 1 is true
+PASS document.querySelectorAll(':lang(ko-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(ko-KR)').length == 1 is true
+PASS document.querySelectorAll(':lang(ko-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(*-KR)').length == 1 is true
+
+- lt-LT
+PASS document.querySelectorAll(':lang(lt)').length == 1 is true
+PASS document.querySelectorAll(':lang(lt-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(lt-LT)').length == 1 is true
+PASS document.querySelectorAll(':lang(lt-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(*-LT)').length == 1 is true
+
+- mi-NZ
+PASS document.querySelectorAll(':lang(mi)').length == 1 is true
+PASS document.querySelectorAll(':lang(mi-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(mi-NZ)').length == 1 is true
+PASS document.querySelectorAll(':lang(mi-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(*-NZ)').length == 1 is true
+
+- mn-MN
+PASS document.querySelectorAll(':lang(mn)').length == 1 is true
+PASS document.querySelectorAll(':lang(mn-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(mn-MN)').length == 1 is true
+PASS document.querySelectorAll(':lang(mn-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(*-MN)').length == 1 is true
+
+- nl-BE
+PASS document.querySelectorAll(':lang(nl)').length == 1 is true
+PASS document.querySelectorAll(':lang(nl-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(nl-BE)').length == 1 is true
+PASS document.querySelectorAll(':lang(nl-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(*-BE)').length == 1 is true
+
+- nl-NL
+PASS document.querySelectorAll(':lang(nl)').length == 1 is true
+PASS document.querySelectorAll(':lang(nl-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(nl-NL)').length == 1 is true
+PASS document.querySelectorAll(':lang(nl-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(*-NL)').length == 1 is true
+
+- pl-PL
+PASS document.querySelectorAll(':lang(pl)').length == 1 is true
+PASS document.querySelectorAll(':lang(pl-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(pl-PL)').length == 1 is true
+PASS document.querySelectorAll(':lang(pl-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(*-PL)').length == 1 is true
+
+- qu-BO
+PASS document.querySelectorAll(':lang(qu)').length == 1 is true
+PASS document.querySelectorAll(':lang(qu-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(qu-BO)').length == 1 is true
+PASS document.querySelectorAll(':lang(qu-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(*-BO)').length == 1 is true
+
+- se-FI
+PASS document.querySelectorAll(':lang(se)').length == 1 is true
+PASS document.querySelectorAll(':lang(se-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(se-FI)').length == 1 is true
+PASS document.querySelectorAll(':lang(se-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(*-FI)').length == 1 is true
+
+- se-NO
+PASS document.querySelectorAll(':lang(se)').length == 1 is true
+PASS document.querySelectorAll(':lang(se-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(se-NO)').length == 1 is true
+PASS document.querySelectorAll(':lang(se-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(*-NO)').length == 1 is true
+
+- sgn-BE-FR
+PASS document.querySelectorAll(':lang(sgn)').length == 1 is true
+PASS document.querySelectorAll(':lang(sgn-\\*-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(sgn-BE)').length == 1 is true
+PASS document.querySelectorAll(':lang(sgn-\\*-FR)').length == 1 is true
+PASS document.querySelectorAll(':lang(sgn-BE-FR)').length == 1 is true
+PASS document.querySelectorAll(':lang(sgn-BE-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(*-BE-FR)').length == 1 is true
+
+- sgn-BE-NL
+PASS document.querySelectorAll(':lang(sgn)').length == 1 is true
+PASS document.querySelectorAll(':lang(sgn-\\*-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(sgn-BE)').length == 1 is true
+PASS document.querySelectorAll(':lang(sgn-\\*-NL)').length == 1 is true
+PASS document.querySelectorAll(':lang(sgn-BE-NL)').length == 1 is true
+PASS document.querySelectorAll(':lang(sgn-BE-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(*-BE-NL)').length == 1 is true
+
+- sgn-CH-DE
+PASS document.querySelectorAll(':lang(sgn)').length == 1 is true
+PASS document.querySelectorAll(':lang(sgn-\\*-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(sgn-CH)').length == 1 is true
+PASS document.querySelectorAll(':lang(sgn-\\*-DE)').length == 1 is true
+PASS document.querySelectorAll(':lang(sgn-CH-DE)').length == 1 is true
+PASS document.querySelectorAll(':lang(sgn-CH-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(*-CH-DE)').length == 1 is true
+
+- sr-Latn-RS
+PASS document.querySelectorAll(':lang(sr)').length == 1 is true
+PASS document.querySelectorAll(':lang(sr-\\*-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(sr-Latn)').length == 1 is true
+PASS document.querySelectorAll(':lang(sr-\\*-RS)').length == 1 is true
+PASS document.querySelectorAll(':lang(sr-Latn-RS)').length == 1 is true
+PASS document.querySelectorAll(':lang(sr-Latn-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(*-Latn-RS)').length == 1 is true
+
+- sv-SE
+PASS document.querySelectorAll(':lang(sv)').length == 1 is true
+PASS document.querySelectorAll(':lang(sv-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(sv-SE)').length == 1 is true
+PASS document.querySelectorAll(':lang(sv-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(*-SE)').length == 1 is true
+
+- syr-SY
+PASS document.querySelectorAll(':lang(syr)').length == 1 is true
+PASS document.querySelectorAll(':lang(syr-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(syr-SY)').length == 1 is true
+PASS document.querySelectorAll(':lang(syr-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(*-SY)').length == 1 is true
+
+- tt-RU
+PASS document.querySelectorAll(':lang(tt)').length == 1 is true
+PASS document.querySelectorAll(':lang(tt-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(tt-RU)').length == 1 is true
+PASS document.querySelectorAll(':lang(tt-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(*-RU)').length == 1 is true
+
+- uz-UZ
+PASS document.querySelectorAll(':lang(uz)').length == 1 is true
+PASS document.querySelectorAll(':lang(uz-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(uz-UZ)').length == 1 is true
+PASS document.querySelectorAll(':lang(uz-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(*-UZ)').length == 1 is true
+
+- vi-VN
+PASS document.querySelectorAll(':lang(vi)').length == 1 is true
+PASS document.querySelectorAll(':lang(vi-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(vi-VN)').length == 1 is true
+PASS document.querySelectorAll(':lang(vi-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(*-VN)').length == 1 is true
+
+- xh-ZA
+PASS document.querySelectorAll(':lang(xh)').length == 1 is true
+PASS document.querySelectorAll(':lang(xh-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(xh-ZA)').length == 1 is true
+PASS document.querySelectorAll(':lang(xh-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(*-ZA)').length == 1 is true
+
+- yue-Hant-HK
+PASS document.querySelectorAll(':lang(yue)').length == 1 is true
+PASS document.querySelectorAll(':lang(yue-\\*-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(yue-Hant)').length == 1 is true
+PASS document.querySelectorAll(':lang(yue-\\*-HK)').length == 1 is true
+PASS document.querySelectorAll(':lang(yue-Hant-HK)').length == 1 is true
+PASS document.querySelectorAll(':lang(yue-Hant-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(*-Hant-HK)').length == 1 is true
+
+- zh-yue-Hant-HK
+PASS document.querySelectorAll(':lang(zh)').length == 1 is true
+PASS document.querySelectorAll(':lang(zh-\\*-\\*-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(zh-yue)').length == 1 is true
+PASS document.querySelectorAll(':lang(zh-\\*-Hant-HK)').length == 1 is true
+PASS document.querySelectorAll(':lang(zh-yue-Hant)').length == 1 is true
+PASS document.querySelectorAll(':lang(zh-yue-\\*-HK)').length == 1 is true
+PASS document.querySelectorAll(':lang(zh-yue-Hant-HK)').length == 1 is true
+PASS document.querySelectorAll(':lang(zh-yue-Hant-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(*-yue-Hant-HK)').length == 1 is true
+
+- zh-CN
+PASS document.querySelectorAll(':lang(zh)').length == 1 is true
+PASS document.querySelectorAll(':lang(zh-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(zh-CN)').length == 1 is true
+PASS document.querySelectorAll(':lang(zh-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(*-CN)').length == 1 is true
+
+- zh-Hant-CN
+PASS document.querySelectorAll(':lang(zh)').length == 1 is true
+PASS document.querySelectorAll(':lang(zh-\\*-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(zh-Hant)').length == 1 is true
+PASS document.querySelectorAll(':lang(zh-\\*-CN)').length == 1 is true
+PASS document.querySelectorAll(':lang(zh-Hant-CN)').length == 1 is true
+PASS document.querySelectorAll(':lang(zh-Hant-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(*-Hant-CN)').length == 1 is true
+
+- zh-Hans-CN
+PASS document.querySelectorAll(':lang(zh)').length == 1 is true
+PASS document.querySelectorAll(':lang(zh-\\*-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(zh-Hans)').length == 1 is true
+PASS document.querySelectorAll(':lang(zh-\\*-CN)').length == 1 is true
+PASS document.querySelectorAll(':lang(zh-Hans-CN)').length == 1 is true
+PASS document.querySelectorAll(':lang(zh-Hans-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(*-Hans-CN)').length == 1 is true
+
+- zh-Hant
+PASS document.querySelectorAll(':lang(zh)').length == 1 is true
+PASS document.querySelectorAll(':lang(zh-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(zh-Hant)').length == 1 is true
+PASS document.querySelectorAll(':lang(zh-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(*-Hant)').length == 1 is true
+
+- de-CH
+PASS document.querySelectorAll(':lang(de)').length == 1 is true
+PASS document.querySelectorAll(':lang(de-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(de-CH)').length == 1 is true
+PASS document.querySelectorAll(':lang(de-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(*-CH)').length == 1 is true
+
+- it-CH
+PASS document.querySelectorAll(':lang(it)').length == 1 is true
+PASS document.querySelectorAll(':lang(it-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(it-CH)').length == 1 is true
+PASS document.querySelectorAll(':lang(it-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(*-CH)').length == 2 is true
+
+- fr-CH
+PASS document.querySelectorAll(':lang(fr)').length == 1 is true
+PASS document.querySelectorAll(':lang(fr-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(fr-CH)').length == 1 is true
+PASS document.querySelectorAll(':lang(fr-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(*-CH)').length == 3 is true
+
+- rm-CH
+PASS document.querySelectorAll(':lang(rm)').length == 1 is true
+PASS document.querySelectorAll(':lang(rm-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(rm-CH)').length == 1 is true
+PASS document.querySelectorAll(':lang(rm-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(*-CH)').length == 4 is true
+
+- de-CH,it-CH,fr-CH,rm-CH
+PASS document.querySelectorAll(':lang(*-CH)').length == 4 is true
+
+- hi-IN
+PASS document.querySelectorAll(':lang(hi)').length == 1 is true
+PASS document.querySelectorAll(':lang(hi-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(hi-IN)').length == 1 is true
+PASS document.querySelectorAll(':lang(hi-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(*-IN)').length == 1 is true
+
+- gu-IN
+PASS document.querySelectorAll(':lang(gu)').length == 1 is true
+PASS document.querySelectorAll(':lang(gu-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(gu-IN)').length == 1 is true
+PASS document.querySelectorAll(':lang(gu-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(*-IN)').length == 2 is true
+
+- kok-IN
+PASS document.querySelectorAll(':lang(kok)').length == 1 is true
+PASS document.querySelectorAll(':lang(kok-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(kok-IN)').length == 1 is true
+PASS document.querySelectorAll(':lang(kok-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(*-IN)').length == 3 is true
+
+- hi-IN,gu-IN,kok-IN
+PASS document.querySelectorAll(':lang(*-IN)').length == 3 is true
+
+- xa-ZA
+PASS document.querySelectorAll(':lang(xa)').length == 1 is true
+PASS document.querySelectorAll(':lang(xa-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(xa-ZA)').length == 1 is true
+PASS document.querySelectorAll(':lang(xa-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(*-ZA)').length == 1 is true
+
+- zu-ZA
+PASS document.querySelectorAll(':lang(zu)').length == 1 is true
+PASS document.querySelectorAll(':lang(zu-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(zu-ZA)').length == 1 is true
+PASS document.querySelectorAll(':lang(zu-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(*-ZA)').length == 2 is true
+
+- xa-ZA,zu-ZA
+PASS document.querySelectorAll(':lang(*-ZA)').length == 2 is true
+
+- se-FI
+PASS document.querySelectorAll(':lang(se)').length == 1 is true
+PASS document.querySelectorAll(':lang(se-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(se-FI)').length == 1 is true
+PASS document.querySelectorAll(':lang(se-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(*-FI)').length == 1 is true
+
+- sv-FI
+PASS document.querySelectorAll(':lang(sv)').length == 1 is true
+PASS document.querySelectorAll(':lang(sv-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(sv-FI)').length == 1 is true
+PASS document.querySelectorAll(':lang(sv-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(*-FI)').length == 2 is true
+
+- se-FI,sv-FI
+PASS document.querySelectorAll(':lang(*-FI)').length == 2 is true
+
+- ur-PK
+PASS document.querySelectorAll(':lang(ur)').length == 1 is true
+PASS document.querySelectorAll(':lang(ur-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(ur-PK)').length == 1 is true
+PASS document.querySelectorAll(':lang(ur-\\*)').length == 1 is true
+PASS document.querySelectorAll(':lang(*-PK)').length == 1 is true
+
+- ur-PK
+PASS document.querySelectorAll(':lang(*-PK)').length == 1 is true
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="trunkLayoutTestsfastselectorslangvalidextendedfilteringhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/selectors/lang-valid-extended-filtering.html (0 => 177333)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/selectors/lang-valid-extended-filtering.html                                (rev 0)
+++ trunk/LayoutTests/fast/selectors/lang-valid-extended-filtering.html        2014-12-16 05:56:33 UTC (rev 177333)
</span><span class="lines">@@ -0,0 +1,156 @@
</span><ins>+&lt;!doctype html&gt;
+&lt;html&gt;
+&lt;head&gt;
+&lt;script src=&quot;../../resources/js-test-pre.js&quot;&gt;&lt;/script&gt;
+&lt;style id=&quot;style-container&quot;&gt;
+&lt;/style&gt;
+&lt;/head&gt;
+&lt;body&gt;
+&lt;div id=&quot;target&quot;&gt;&lt;/div&gt;
+&lt;div id=&quot;target1&quot;&gt;&lt;/div&gt;
+&lt;div id=&quot;target2&quot;&gt;&lt;/div&gt;
+&lt;div id=&quot;target3&quot;&gt;&lt;/div&gt;
+&lt;div id=&quot;target4&quot;&gt;&lt;/div&gt;
+&lt;/body&gt;
+&lt;script&gt;
+description('Verify selector specifying extended filtering of :lang() pseudo class');
+
+function testValidLanguageSelectorOnSingleElement(language, length) {
+    var range = language;
+    var rangeSubtags = language.split('-');
+    var target = document.querySelector('#target').setAttribute('lang', language);
+    var currentRange = rangeSubtags[0];
+    var suffixRange = '';
+
+    length = length || 1;
+    debug('- ' + language);
+
+    for (var i = 0; i &lt; rangeSubtags.length; i++){
+        shouldBeTrue(&quot;document.querySelectorAll(':lang(&quot; + currentRange + &quot;)').length == 1&quot;);
+        currentRange += '-' + rangeSubtags[i + 1];
+
+        var asteriskRange = rangeSubtags[0];
+        for (var j = 1; j &lt; rangeSubtags.length; j++) {
+            if (i == j || i == 0) {
+                asteriskRange += '-\\\\*';
+            } else {
+                asteriskRange += '-' + rangeSubtags[j];  
+            }
+        }
+        shouldBeTrue(&quot;document.querySelectorAll(':lang(&quot; + asteriskRange + &quot;)').length == 1&quot;);
+        if (i &gt; 0)
+            suffixRange += '-' + rangeSubtags[i];  
+    }
+    shouldBeTrue(&quot;document.querySelectorAll(':lang(*&quot; + suffixRange + &quot;)').length == &quot; + length);
+    document.querySelector('#target').removeAttribute('lang');
+
+    debug('');
+}
+
+function testValidLanguageSelectorOnMultipleElementsWithFirstAsterisk(languages) {
+    for (var i = 0; i &lt; languages.length; i++) {
+        var language = languages[i];
+        testValidLanguageSelectorOnSingleElement(language, i + 1);
+        document.querySelector('#target' + (i + 1)).setAttribute('lang', language);
+    }
+
+    debug('- ' + languages);
+    for (var i = 0; i &lt; languages.length; i++) {
+        var language = languages[i];
+        var ranges = language.split('-');
+        var range = '*';
+        for (var j = 1; j &lt; ranges.length; j++) {
+            range += '-' + ranges[j];
+        }
+    }
+    shouldBeTrue(&quot;document.querySelectorAll(':lang(&quot; + range + &quot;)').length == &quot; + languages.length);
+    debug('');
+}
+
+var validLanguagesOnSingleElement = [
+    &quot;af-ZA&quot;,
+    &quot;ar-AE&quot;,
+    &quot;ar-BH&quot;,
+    &quot;ar-YE&quot;,
+    &quot;art-lojban&quot;,
+    &quot;az-Arab-IR&quot;,
+    &quot;be-BY&quot;,
+    &quot;bg-BG&quot;,
+    &quot;ca-ES&quot;,
+    &quot;cs-CZ&quot;,
+    &quot;cy-GB&quot;,
+    &quot;de-AT&quot;,
+    &quot;de-CH&quot;,
+    &quot;de-CH-1996&quot;,
+    &quot;de-CH-1997&quot;,
+    &quot;de-DE&quot;,
+    &quot;de-DE-1996&quot;,
+    &quot;de-Latn-DE&quot;,
+    &quot;de-Latf-DE&quot;,
+    &quot;de-Latn-DE-1996&quot;,
+    &quot;en-US&quot;,
+    &quot;en-GB&quot;,
+    &quot;en-Latn-Brai&quot;,
+    &quot;es-ES&quot;,
+    &quot;es-ES-valencia&quot;,
+    &quot;es-AR&quot;,
+    &quot;fr-BE&quot;,
+    &quot;fr-CA&quot;,
+    &quot;fr-CH&quot;,
+    &quot;fr-FR&quot;,
+    &quot;fr-LU&quot;,
+    &quot;fr-MC&quot;,
+    &quot;gl-ES&quot;,
+    &quot;gu-IN&quot;,
+    &quot;hr-BA&quot;,
+    &quot;id-ID&quot;,
+    &quot;i-klingon&quot;,
+    &quot;ja-JP&quot;,
+    &quot;ko-KR&quot;,
+    &quot;lt-LT&quot;,
+    &quot;mi-NZ&quot;,
+    &quot;mn-MN&quot;,
+    &quot;nl-BE&quot;,
+    &quot;nl-NL&quot;,
+    &quot;pl-PL&quot;,
+    &quot;qu-BO&quot;,
+    &quot;se-FI&quot;,
+    &quot;se-NO&quot;,
+    &quot;sgn-BE-FR&quot;,
+    &quot;sgn-BE-NL&quot;,
+    &quot;sgn-CH-DE&quot;,
+    &quot;sr-Latn-RS&quot;,
+    &quot;sv-SE&quot;,
+    &quot;syr-SY&quot;,
+    &quot;tt-RU&quot;,
+    &quot;uz-UZ&quot;,
+    &quot;vi-VN&quot;,
+    &quot;xh-ZA&quot;,
+    &quot;yue-Hant-HK&quot;,
+    &quot;zh-yue-Hant-HK&quot;,
+    &quot;zh-CN&quot;,
+    &quot;zh-Hant-CN&quot;,
+    &quot;zh-Hans-CN&quot;,
+    &quot;zh-Hant&quot;
+];
+
+var validLanguagesOnMultipleElements = [
+    [&quot;de-CH&quot;, &quot;it-CH&quot;, &quot;fr-CH&quot;, &quot;rm-CH&quot;],
+    [&quot;hi-IN&quot;, &quot;gu-IN&quot;, &quot;kok-IN&quot;],
+    [&quot;xa-ZA&quot;, &quot;zu-ZA&quot;],
+    [&quot;se-FI&quot;, &quot;sv-FI&quot;],
+    [&quot;ur-PK&quot;],
+];
+
+for (var i = 0; i &lt; validLanguagesOnSingleElement.length; ++i) {
+    var lang = validLanguagesOnSingleElement[i];
+    testValidLanguageSelectorOnSingleElement(lang);
+}
+
+for (var i = 0; i &lt; validLanguagesOnMultipleElements.length; ++i) {
+    var lang = validLanguagesOnMultipleElements[i];
+    testValidLanguageSelectorOnMultipleElementsWithFirstAsterisk(lang);
+}
+&lt;/script&gt;
+&lt;script src=&quot;../../resources/js-test-post.js&quot;&gt;&lt;/script&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (177332 => 177333)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2014-12-16 04:51:22 UTC (rev 177332)
+++ trunk/Source/WebCore/ChangeLog        2014-12-16 05:56:33 UTC (rev 177333)
</span><span class="lines">@@ -1,3 +1,27 @@
</span><ins>+2014-12-15  Dhi Aurrahman  &lt;diorahman@rockybars.com&gt;
+
+        Extend :lang()'s selector checker to handle ranges with '*' properly and perform matching within the ASCII range
+        https://bugs.webkit.org/show_bug.cgi?id=139340
+
+        Reviewed by Benjamin Poulain.
+
+        Asterisk is considered as a valid subtag of a language range to express wildcard matching 
+        in :lang()'s extended filtering procedure. The matching rules introduced by language 
+        range with '*' is outlined in [1].
+
+        The matching of subtags is performed case-insensitively within the ASCII range[2].
+
+        [1] www.ietf.org/rfc/rfc4647.txt
+        [2] http://dev.w3.org/csswg/selectors4/#the-lang-pseudo
+
+        Test: fast/selectors/lang-equal-ignoring-case.html
+              fast/selectors/lang-valid-extended-filtering.html
+
+        * css/SelectorCheckerTestFunctions.h:
+        (WebCore::equalIgnoringCaseWithinASCIIRange): Handle matching case-insensitively within the ASCII range.
+        (WebCore::containslanguageSubtagMatchingRange):
+        (WebCore::matchesLangPseudoClass):
+
</ins><span class="cx"> 2014-12-15  Chris Dumez  &lt;cdumez@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         [iOS] Add feature counting support
</span></span></pre></div>
<a id="trunkSourceWebCorecssSelectorCheckerTestFunctionsh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/css/SelectorCheckerTestFunctions.h (177332 => 177333)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/css/SelectorCheckerTestFunctions.h        2014-12-16 04:51:22 UTC (rev 177332)
+++ trunk/Source/WebCore/css/SelectorCheckerTestFunctions.h        2014-12-16 05:56:33 UTC (rev 177333)
</span><span class="lines">@@ -121,13 +121,24 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> #if ENABLE(CSS_SELECTORS_LEVEL4)
</span><ins>+inline bool equalIgnoringASCIICase(const String&amp; a, const String&amp; b)
+{
+    if (a.length() != b.length()) 
+        return false;
+    for (size_t i = 0; i &lt; a.length(); ++i) {
+        if (toASCIILower(a[i]) != toASCIILower(b[i]))
+            return false;
+    }
+    return true;
+}
+
</ins><span class="cx"> inline bool containslanguageSubtagMatchingRange(const Vector&lt;String&gt;&amp; languageSubtags, const String&amp; range, size_t&amp; position)
</span><span class="cx"> {
</span><span class="cx">     for (size_t languageSubtagIndex = position; languageSubtagIndex &lt; languageSubtags.size(); ++languageSubtagIndex) {
</span><span class="cx">         const String&amp; currentLanguageSubtag = languageSubtags[languageSubtagIndex];
</span><del>-        if (currentLanguageSubtag.length() == 1)
</del><ins>+        if (currentLanguageSubtag.length() == 1 &amp;&amp; range != &quot;*&quot;)
</ins><span class="cx">             return false;
</span><del>-        if (equalIgnoringCase(range, currentLanguageSubtag)) {
</del><ins>+        if (equalIgnoringASCIICase(range, currentLanguageSubtag) || range == &quot;*&quot;) {
</ins><span class="cx">             position = languageSubtagIndex + 1;
</span><span class="cx">             return true;
</span><span class="cx">         }
</span><span class="lines">@@ -158,15 +169,19 @@
</span><span class="cx">     language.string().split('-', true, languageSubtags);
</span><span class="cx"> 
</span><span class="cx">     for (const AtomicString&amp; range : ranges) {
</span><del>-        if (equalIgnoringCase(language, range) &amp;&amp; !language.contains('-'))
</del><ins>+        if (range == &quot;*&quot;)
</ins><span class="cx">             return true;
</span><span class="cx"> 
</span><ins>+        if (equalIgnoringASCIICase(language, range) &amp;&amp; !language.contains('-'))
+            return true;
+
</ins><span class="cx">         range.string().split('-', true, rangeSubtags);
</span><span class="cx"> 
</span><span class="cx">         if (rangeSubtags.size() &gt; languageSubtags.size()) 
</span><span class="cx">             continue;
</span><span class="cx"> 
</span><del>-        if (!equalIgnoringCase(rangeSubtags.first(), languageSubtags.first())) 
</del><ins>+        const String&amp; firstRangeSubtag = rangeSubtags.first();
+        if (!equalIgnoringASCIICase(firstRangeSubtag, languageSubtags.first()) &amp;&amp; firstRangeSubtag != &quot;*&quot;) 
</ins><span class="cx">             continue;
</span><span class="cx"> 
</span><span class="cx">         size_t lastMatchedLanguageSubtagIndex = 1;
</span></span></pre>
</div>
</div>

</body>
</html>