Title: [175028] trunk
Revision
175028
Author
[email protected]
Date
2014-10-22 02:22:05 -0700 (Wed, 22 Oct 2014)

Log Message

Add relList to the anchor, area and link elements
https://bugs.webkit.org/show_bug.cgi?id=137860

Patch by Dhi Aurrahman <[email protected]> on 2014-10-22
Reviewed by Darin Adler and Chris Dumez.

Source/WebCore:

Add relList to reflect the rel content attribute for anchor[1],
area[2] and link[3] elements.

[1] https://html.spec.whatwg.org/multipage/semantics.html#dom-a-rellist
[2] https://html.spec.whatwg.org/multipage/embedded-content.html#dom-area-rellist
[3] https://html.spec.whatwg.org/multipage/semantics.html#dom-link-rellist

Tests: fast/dom/rel-list-gc.html
       fast/dom/rel-list.html
       perf/rel-list-remove.html

* CMakeLists.txt:
* WebCore.vcxproj/WebCore.vcxproj:
* WebCore.vcxproj/WebCore.vcxproj.filters:
* WebCore.xcodeproj/project.pbxproj:
* dom/SpaceSplitString.cpp:
(WebCore::SpaceSplitString::set):
* html/HTMLAnchorElement.cpp:
(WebCore::HTMLAnchorElement::parseAttribute):
(WebCore::HTMLAnchorElement::relList):
(WebCore::HTMLAnchorElement::setRel): Deleted.
* html/HTMLAnchorElement.h:
* html/HTMLAnchorElement.idl:
* html/HTMLAreaElement.idl:
* html/HTMLLinkElement.cpp:
(WebCore::HTMLLinkElement::parseAttribute):
(WebCore::HTMLLinkElement::relList):
* html/HTMLLinkElement.h:
* html/HTMLLinkElement.idl:
* html/RelList.cpp: Added.
(WebCore::RelList::RelList):
(WebCore::RelList::ref):
(WebCore::RelList::deref):
(WebCore::RelList::length):
(WebCore::RelList::item):
(WebCore::RelList::element):
(WebCore::RelList::updateRelAttribute):
(WebCore::RelList::containsInternal):
(WebCore::RelList::value):
(WebCore::RelList::setValue):
* html/RelList.h: Added.

LayoutTests:

Tests relList aspects for anchor, area and list elements.
Update dom static property for-in iteration test result to include relList.

* fast/dom/rel-list-expected.txt: Added.
* fast/dom/rel-list-gc-expected.txt: Added.
* fast/dom/rel-list-gc.html: Added.
* fast/dom/rel-list.html: Added.
* js/dom/dom-static-property-for-in-iteration-expected.txt: Updated results.
* perf/rel-list-remove-expected.txt: Added.
* perf/rel-list-remove.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (175027 => 175028)


--- trunk/LayoutTests/ChangeLog	2014-10-22 07:29:26 UTC (rev 175027)
+++ trunk/LayoutTests/ChangeLog	2014-10-22 09:22:05 UTC (rev 175028)
@@ -1,3 +1,21 @@
+2014-10-22  Dhi Aurrahman  <[email protected]>
+
+        Add relList to the anchor, area and link elements
+        https://bugs.webkit.org/show_bug.cgi?id=137860
+
+        Reviewed by Darin Adler and Chris Dumez.
+
+        Tests relList aspects for anchor, area and list elements. 
+        Update dom static property for-in iteration test result to include relList.
+
+        * fast/dom/rel-list-expected.txt: Added.
+        * fast/dom/rel-list-gc-expected.txt: Added.
+        * fast/dom/rel-list-gc.html: Added.
+        * fast/dom/rel-list.html: Added.
+        * js/dom/dom-static-property-for-in-iteration-expected.txt: Updated results.
+        * perf/rel-list-remove-expected.txt: Added.
+        * perf/rel-list-remove.html: Added.
+
 2014-10-21  Brent Fulgham  <[email protected]>
 
         [Win] More rebaselines.

Added: trunk/LayoutTests/fast/dom/rel-list-expected.txt (0 => 175028)


--- trunk/LayoutTests/fast/dom/rel-list-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/fast/dom/rel-list-expected.txt	2014-10-22 09:22:05 UTC (rev 175028)
@@ -0,0 +1,378 @@
+Tests that relList works on anchor, area and link elements
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Tests relList for anchor element
+PASS element.relList == null is false
+PASS element.relList == undefined is false
+PASS element.relList instanceof DOMTokenList is true
+PASS element.relList.length is 3
+PASS element.relList.contains("a") is true
+PASS element.relList.contains("b") is true
+PASS element.relList.contains("c") is true
+PASS element.relList.contains("d") is false
+PASS element.relList.length is 3
+PASS element.relList.contains("foo") is true
+PASS element.relList.contains("bar") is true
+PASS element.relList.contains("chocolate") is true
+PASS element.relList.contains("orange") is false
+PASS element.relList.length is 0
+PASS element.relList.length is 0
+PASS element.relList.length is 2
+PASS element.relList.contains("marshmallow") is true
+PASS element.relList.contains("chips") is true
+PASS element.relList.contains("orange") is false
+PASS String(element.relList) is "x"
+PASS element.relList.length is 0
+PASS element.relList.length is 1
+PASS element.relList.length is 2
+PASS element.relList.length is 2
+PASS element.rel is "x"
+PASS element.rel is "x"
+PASS element.rel is "x  x"
+PASS element.rel is "y x"
+PASS element.rel is ""
+PASS element.rel is ""
+PASS element.rel is " y y "
+PASS element.rel is "y"
+Ensure that we can handle empty rel correctly
+PASS element.relList.toggle('x') is true
+PASS element.rel is "x"
+PASS element.relList.toggle('x') is false
+PASS element.rel is ""
+PASS element.relList.contains("x") is false
+PASS element.relList[1] is undefined.
+PASS element.relList.contains("x") is false
+PASS element.relList.contains("x") is true
+Test toggle with force argument
+PASS element.relList.toggle('x', true) is true
+PASS element.rel is "x"
+PASS element.relList.toggle('x', true) is true
+PASS element.rel is "x"
+PASS element.relList.toggle('x', false) is false
+PASS element.rel is ""
+PASS element.relList.toggle('x', false) is false
+PASS element.rel is ""
+PASS element.relList.toggle("", true) threw exception Error: SyntaxError: DOM Exception 12.
+PASS element.relList.toggle("x y", false) threw exception Error: InvalidCharacterError: DOM Exception 5.
+Testing add in presence of trailing white spaces.
+PASS element.rel is "x y"
+PASS element.rel is "x\ty"
+PASS element.rel is " y"
+Test invalid tokens
+PASS element.relList.contains("") threw exception Error: SyntaxError: DOM Exception 12.
+PASS element.relList.contains("x y") threw exception Error: InvalidCharacterError: DOM Exception 5.
+PASS element.relList.add("") threw exception Error: SyntaxError: DOM Exception 12.
+PASS element.relList.add("x y") threw exception Error: InvalidCharacterError: DOM Exception 5.
+PASS element.relList.remove("") threw exception Error: SyntaxError: DOM Exception 12.
+PASS element.relList.remove("x y") threw exception Error: InvalidCharacterError: DOM Exception 5.
+PASS element.relList.toggle("") threw exception Error: SyntaxError: DOM Exception 12.
+Indexing
+PASS element.relList[0] is "x"
+PASS element.relList.item(0) is "x"
+PASS element.relList[1] is "x"
+PASS element.relList.item(1) is "x"
+PASS element.relList[1] is "y"
+PASS element.relList.item(1) is "y"
+PASS element.relList[0] is undefined.
+PASS element.relList.item(0) is null
+PASS element.relList[4] is undefined.
+PASS element.relList.item(4) is null
+PASS element.relList[-1] is undefined.
+PASS element.relList.item(-1) is null
+PASS element.relList.item() threw exception TypeError: Not enough arguments.
+Test case since DOMTokenList is case sensitive
+PASS element.relList.contains("x") is true
+PASS element.relList.contains("X") is false
+PASS element.relList[0] is "x"
+PASS element.relList.contains() threw exception TypeError: Not enough arguments.
+PASS element.relList.contains("X") is true
+PASS element.relList.contains("x") is false
+PASS element.relList[0] is "X"
+Testing whitespace
+PASS element.relList.length is 2
+PASS element.relList.length is 2
+PASS element.relList.length is 2
+PASS element.relList.length is 2
+PASS element.relList.length is 2
+DOMTokenList presence and type
+PASS 'undefined' != typeof DOMTokenList is true
+PASS typeof DOMTokenList.prototype is "object"
+PASS typeof element.relList is "object"
+PASS element.relList.constructor is DOMTokenList
+PASS element.relList === element.relList is true
+Variadic calls
+PASS element.rel is "a b"
+PASS element.rel is "a b c"
+PASS element.rel is "a b c null d undefined 0 false"
+PASS element.rel is "a b"
+PASS element.relList.add("a", "b", "") threw exception Error: SyntaxError: DOM Exception 12.
+PASS element.rel is ""
+PASS element.relList.add("a", "b", "c d") threw exception Error: InvalidCharacterError: DOM Exception 5.
+PASS element.rel is ""
+PASS element.relList.add("a", {toString: function() { throw new Error("user error"); }}, "b") threw exception Error: user error.
+PASS element.rel is ""
+PASS element.relList.add() did not throw exception.
+PASS observer.takeRecords().length is 1
+PASS element.rel is "b d  "
+PASS element.rel is "d  "
+PASS element.rel is "a b c"
+PASS element.relList.remove("a", "b", "") threw exception Error: SyntaxError: DOM Exception 12.
+PASS element.rel is "a b"
+PASS element.relList.remove("a", {toString: function() { throw new Error("user error"); }}, "b") threw exception Error: user error.
+PASS element.rel is "a b"
+PASS element.relList.remove("a", "b", "c d") threw exception Error: InvalidCharacterError: DOM Exception 5.
+PASS element.rel is "a b"
+PASS element.relList.remove() did not throw exception.
+PASS observer.takeRecords().length is 1
+Tests relList for area element
+PASS element.relList == null is false
+PASS element.relList == undefined is false
+PASS element.relList instanceof DOMTokenList is true
+PASS element.relList.length is 3
+PASS element.relList.contains("a") is true
+PASS element.relList.contains("b") is true
+PASS element.relList.contains("c") is true
+PASS element.relList.contains("d") is false
+PASS element.relList.length is 3
+PASS element.relList.contains("foo") is true
+PASS element.relList.contains("bar") is true
+PASS element.relList.contains("chocolate") is true
+PASS element.relList.contains("orange") is false
+PASS element.relList.length is 0
+PASS element.relList.length is 0
+PASS element.relList.length is 2
+PASS element.relList.contains("marshmallow") is true
+PASS element.relList.contains("chips") is true
+PASS element.relList.contains("orange") is false
+PASS String(element.relList) is "x"
+PASS element.relList.length is 0
+PASS element.relList.length is 1
+PASS element.relList.length is 2
+PASS element.relList.length is 2
+PASS element.rel is "x"
+PASS element.rel is "x"
+PASS element.rel is "x  x"
+PASS element.rel is "y x"
+PASS element.rel is ""
+PASS element.rel is ""
+PASS element.rel is " y y "
+PASS element.rel is "y"
+Ensure that we can handle empty rel correctly
+PASS element.relList.toggle('x') is true
+PASS element.rel is "x"
+PASS element.relList.toggle('x') is false
+PASS element.rel is ""
+PASS element.relList.contains("x") is false
+PASS element.relList[1] is undefined.
+PASS element.relList.contains("x") is false
+PASS element.relList.contains("x") is true
+Test toggle with force argument
+PASS element.relList.toggle('x', true) is true
+PASS element.rel is "x"
+PASS element.relList.toggle('x', true) is true
+PASS element.rel is "x"
+PASS element.relList.toggle('x', false) is false
+PASS element.rel is ""
+PASS element.relList.toggle('x', false) is false
+PASS element.rel is ""
+PASS element.relList.toggle("", true) threw exception Error: SyntaxError: DOM Exception 12.
+PASS element.relList.toggle("x y", false) threw exception Error: InvalidCharacterError: DOM Exception 5.
+Testing add in presence of trailing white spaces.
+PASS element.rel is "x y"
+PASS element.rel is "x\ty"
+PASS element.rel is " y"
+Test invalid tokens
+PASS element.relList.contains("") threw exception Error: SyntaxError: DOM Exception 12.
+PASS element.relList.contains("x y") threw exception Error: InvalidCharacterError: DOM Exception 5.
+PASS element.relList.add("") threw exception Error: SyntaxError: DOM Exception 12.
+PASS element.relList.add("x y") threw exception Error: InvalidCharacterError: DOM Exception 5.
+PASS element.relList.remove("") threw exception Error: SyntaxError: DOM Exception 12.
+PASS element.relList.remove("x y") threw exception Error: InvalidCharacterError: DOM Exception 5.
+PASS element.relList.toggle("") threw exception Error: SyntaxError: DOM Exception 12.
+Indexing
+PASS element.relList[0] is "x"
+PASS element.relList.item(0) is "x"
+PASS element.relList[1] is "x"
+PASS element.relList.item(1) is "x"
+PASS element.relList[1] is "y"
+PASS element.relList.item(1) is "y"
+PASS element.relList[0] is undefined.
+PASS element.relList.item(0) is null
+PASS element.relList[4] is undefined.
+PASS element.relList.item(4) is null
+PASS element.relList[-1] is undefined.
+PASS element.relList.item(-1) is null
+PASS element.relList.item() threw exception TypeError: Not enough arguments.
+Test case since DOMTokenList is case sensitive
+PASS element.relList.contains("x") is true
+PASS element.relList.contains("X") is false
+PASS element.relList[0] is "x"
+PASS element.relList.contains() threw exception TypeError: Not enough arguments.
+PASS element.relList.contains("X") is true
+PASS element.relList.contains("x") is false
+PASS element.relList[0] is "X"
+Testing whitespace
+PASS element.relList.length is 2
+PASS element.relList.length is 2
+PASS element.relList.length is 2
+PASS element.relList.length is 2
+PASS element.relList.length is 2
+DOMTokenList presence and type
+PASS 'undefined' != typeof DOMTokenList is true
+PASS typeof DOMTokenList.prototype is "object"
+PASS typeof element.relList is "object"
+PASS element.relList.constructor is DOMTokenList
+PASS element.relList === element.relList is true
+Variadic calls
+PASS element.rel is "a b"
+PASS element.rel is "a b c"
+PASS element.rel is "a b c null d undefined 0 false"
+PASS element.rel is "a b"
+PASS element.relList.add("a", "b", "") threw exception Error: SyntaxError: DOM Exception 12.
+PASS element.rel is ""
+PASS element.relList.add("a", "b", "c d") threw exception Error: InvalidCharacterError: DOM Exception 5.
+PASS element.rel is ""
+PASS element.relList.add("a", {toString: function() { throw new Error("user error"); }}, "b") threw exception Error: user error.
+PASS element.rel is ""
+PASS element.relList.add() did not throw exception.
+PASS observer.takeRecords().length is 1
+PASS element.rel is "b d  "
+PASS element.rel is "d  "
+PASS element.rel is "a b c"
+PASS element.relList.remove("a", "b", "") threw exception Error: SyntaxError: DOM Exception 12.
+PASS element.rel is "a b"
+PASS element.relList.remove("a", {toString: function() { throw new Error("user error"); }}, "b") threw exception Error: user error.
+PASS element.rel is "a b"
+PASS element.relList.remove("a", "b", "c d") threw exception Error: InvalidCharacterError: DOM Exception 5.
+PASS element.rel is "a b"
+PASS element.relList.remove() did not throw exception.
+PASS observer.takeRecords().length is 1
+Tests relList for link element
+PASS element.relList == null is false
+PASS element.relList == undefined is false
+PASS element.relList instanceof DOMTokenList is true
+PASS element.relList.length is 3
+PASS element.relList.contains("a") is true
+PASS element.relList.contains("b") is true
+PASS element.relList.contains("c") is true
+PASS element.relList.contains("d") is false
+PASS element.relList.length is 3
+PASS element.relList.contains("foo") is true
+PASS element.relList.contains("bar") is true
+PASS element.relList.contains("chocolate") is true
+PASS element.relList.contains("orange") is false
+PASS element.relList.length is 0
+PASS element.relList.length is 0
+PASS element.relList.length is 2
+PASS element.relList.contains("marshmallow") is true
+PASS element.relList.contains("chips") is true
+PASS element.relList.contains("orange") is false
+PASS String(element.relList) is "x"
+PASS element.relList.length is 0
+PASS element.relList.length is 1
+PASS element.relList.length is 2
+PASS element.relList.length is 2
+PASS element.rel is "x"
+PASS element.rel is "x"
+PASS element.rel is "x  x"
+PASS element.rel is "y x"
+PASS element.rel is ""
+PASS element.rel is ""
+PASS element.rel is " y y "
+PASS element.rel is "y"
+Ensure that we can handle empty rel correctly
+PASS element.relList.toggle('x') is true
+PASS element.rel is "x"
+PASS element.relList.toggle('x') is false
+PASS element.rel is ""
+PASS element.relList.contains("x") is false
+PASS element.relList[1] is undefined.
+PASS element.relList.contains("x") is false
+PASS element.relList.contains("x") is true
+Test toggle with force argument
+PASS element.relList.toggle('x', true) is true
+PASS element.rel is "x"
+PASS element.relList.toggle('x', true) is true
+PASS element.rel is "x"
+PASS element.relList.toggle('x', false) is false
+PASS element.rel is ""
+PASS element.relList.toggle('x', false) is false
+PASS element.rel is ""
+PASS element.relList.toggle("", true) threw exception Error: SyntaxError: DOM Exception 12.
+PASS element.relList.toggle("x y", false) threw exception Error: InvalidCharacterError: DOM Exception 5.
+Testing add in presence of trailing white spaces.
+PASS element.rel is "x y"
+PASS element.rel is "x\ty"
+PASS element.rel is " y"
+Test invalid tokens
+PASS element.relList.contains("") threw exception Error: SyntaxError: DOM Exception 12.
+PASS element.relList.contains("x y") threw exception Error: InvalidCharacterError: DOM Exception 5.
+PASS element.relList.add("") threw exception Error: SyntaxError: DOM Exception 12.
+PASS element.relList.add("x y") threw exception Error: InvalidCharacterError: DOM Exception 5.
+PASS element.relList.remove("") threw exception Error: SyntaxError: DOM Exception 12.
+PASS element.relList.remove("x y") threw exception Error: InvalidCharacterError: DOM Exception 5.
+PASS element.relList.toggle("") threw exception Error: SyntaxError: DOM Exception 12.
+Indexing
+PASS element.relList[0] is "x"
+PASS element.relList.item(0) is "x"
+PASS element.relList[1] is "x"
+PASS element.relList.item(1) is "x"
+PASS element.relList[1] is "y"
+PASS element.relList.item(1) is "y"
+PASS element.relList[0] is undefined.
+PASS element.relList.item(0) is null
+PASS element.relList[4] is undefined.
+PASS element.relList.item(4) is null
+PASS element.relList[-1] is undefined.
+PASS element.relList.item(-1) is null
+PASS element.relList.item() threw exception TypeError: Not enough arguments.
+Test case since DOMTokenList is case sensitive
+PASS element.relList.contains("x") is true
+PASS element.relList.contains("X") is false
+PASS element.relList[0] is "x"
+PASS element.relList.contains() threw exception TypeError: Not enough arguments.
+PASS element.relList.contains("X") is true
+PASS element.relList.contains("x") is false
+PASS element.relList[0] is "X"
+Testing whitespace
+PASS element.relList.length is 2
+PASS element.relList.length is 2
+PASS element.relList.length is 2
+PASS element.relList.length is 2
+PASS element.relList.length is 2
+DOMTokenList presence and type
+PASS 'undefined' != typeof DOMTokenList is true
+PASS typeof DOMTokenList.prototype is "object"
+PASS typeof element.relList is "object"
+PASS element.relList.constructor is DOMTokenList
+PASS element.relList === element.relList is true
+Variadic calls
+PASS element.rel is "a b"
+PASS element.rel is "a b c"
+PASS element.rel is "a b c null d undefined 0 false"
+PASS element.rel is "a b"
+PASS element.relList.add("a", "b", "") threw exception Error: SyntaxError: DOM Exception 12.
+PASS element.rel is ""
+PASS element.relList.add("a", "b", "c d") threw exception Error: InvalidCharacterError: DOM Exception 5.
+PASS element.rel is ""
+PASS element.relList.add("a", {toString: function() { throw new Error("user error"); }}, "b") threw exception Error: user error.
+PASS element.rel is ""
+PASS element.relList.add() did not throw exception.
+PASS observer.takeRecords().length is 1
+PASS element.rel is "b d  "
+PASS element.rel is "d  "
+PASS element.rel is "a b c"
+PASS element.relList.remove("a", "b", "") threw exception Error: SyntaxError: DOM Exception 12.
+PASS element.rel is "a b"
+PASS element.relList.remove("a", {toString: function() { throw new Error("user error"); }}, "b") threw exception Error: user error.
+PASS element.rel is "a b"
+PASS element.relList.remove("a", "b", "c d") threw exception Error: InvalidCharacterError: DOM Exception 5.
+PASS element.rel is "a b"
+PASS element.relList.remove() did not throw exception.
+PASS observer.takeRecords().length is 1
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/fast/dom/rel-list-gc-expected.txt (0 => 175028)


--- trunk/LayoutTests/fast/dom/rel-list-gc-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/fast/dom/rel-list-gc-expected.txt	2014-10-22 09:22:05 UTC (rev 175028)
@@ -0,0 +1,13 @@
+Tests relList gc for anchor element
+PASS element.relList.life is 42
+PASS element.relList.life is 42
+Tests relList gc for area element
+PASS element.relList.life is 42
+PASS element.relList.life is 42
+Tests relList gc for link element
+PASS element.relList.life is 42
+PASS element.relList.life is 42
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/fast/dom/rel-list-gc.html (0 => 175028)


--- trunk/LayoutTests/fast/dom/rel-list-gc.html	                        (rev 0)
+++ trunk/LayoutTests/fast/dom/rel-list-gc.html	2014-10-22 09:22:05 UTC (rev 175028)
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src=""
+</head>
+<script>
+var element;
+
+function test(type)
+{
+    element = document.createElement(type);
+    var relList = element.relList;
+    element.relList.life = 42;
+    shouldEvaluateTo('element.relList.life', 42);
+    relList = null;
+    gc();
+    shouldEvaluateTo('element.relList.life', 42);
+}
+
+debug('Tests relList gc for anchor element');
+test('a');
+debug('Tests relList gc for area element');
+test('area');
+debug('Tests relList gc for link element');
+test('link');
+
+</script>
+<script src=""
+</body>
+</html>
\ No newline at end of file

Added: trunk/LayoutTests/fast/dom/rel-list.html (0 => 175028)


--- trunk/LayoutTests/fast/dom/rel-list.html	                        (rev 0)
+++ trunk/LayoutTests/fast/dom/rel-list.html	2014-10-22 09:22:05 UTC (rev 175028)
@@ -0,0 +1,303 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src=""
+</head>
+<body>
+<a id="a" rel="a b c"></a>
+<area id="area" rel="a b c"></area>
+<link id="link" rel="a b c">
+<script>
+description('Tests that relList works on anchor, area and link elements');
+
+var element;
+var type;
+var observer;
+
+function createElement(rel)
+{
+    element = document.createElement(type);
+    element.rel = rel;
+}
+
+function test() 
+{
+    element = document.getElementById(type);
+    shouldBeFalse('element.relList == null');
+    shouldBeFalse('element.relList == undefined');
+    shouldBeTrue('element.relList instanceof DOMTokenList');
+    shouldBe('element.relList.length', '3');
+    shouldBeTrue('element.relList.contains("a")');
+    shouldBeTrue('element.relList.contains("b")');
+    shouldBeTrue('element.relList.contains("c")');
+    shouldBeFalse('element.relList.contains("d")');
+
+    createElement("foo bar chocolate");
+    shouldBe('element.relList.length', '3');
+    shouldBeTrue('element.relList.contains("foo")');
+    shouldBeTrue('element.relList.contains("bar")');
+    shouldBeTrue('element.relList.contains("chocolate")');
+    shouldBeFalse('element.relList.contains("orange")');
+
+    element.removeAttribute('rel');
+    shouldBe('element.relList.length', '0');
+    
+    element.setAttribute('rel', '');
+    shouldBe('element.relList.length', '0');
+
+    element.setAttribute('rel', 'marshmallow chips');
+    shouldBe('element.relList.length', '2');
+    shouldBeTrue('element.relList.contains("marshmallow")');
+    shouldBeTrue('element.relList.contains("chips")');
+    shouldBeFalse('element.relList.contains("orange")');
+
+    createElement('x');
+    element.relList = 'y';
+    shouldBeEqualToString('String(element.relList)', 'x');
+
+    createElement('');
+    shouldEvaluateTo('element.relList.length', 0);
+
+    createElement('x');
+    shouldEvaluateTo('element.relList.length', 1);
+
+    createElement('x x');
+    shouldEvaluateTo('element.relList.length', 2);
+
+    createElement('x y');
+    shouldEvaluateTo('element.relList.length', 2);
+
+    createElement('');
+    element.relList.add('x');
+    shouldBeEqualToString('element.rel', 'x');
+
+    createElement('x');
+    element.relList.add('x');
+    shouldBeEqualToString('element.rel', 'x');
+
+    createElement('x  x');
+    element.relList.add('x');
+    shouldBeEqualToString('element.rel', 'x  x');
+
+    createElement('y');
+    element.relList.add('x');
+    shouldBeEqualToString('element.rel', 'y x');
+
+    createElement('');
+    element.relList.remove('x');
+    shouldBeEqualToString('element.rel', '');
+
+    createElement('x');
+    element.relList.remove('x');
+    shouldBeEqualToString('element.rel', '');
+
+    createElement(' y x  y ');
+    element.relList.remove('x');
+    shouldBeEqualToString('element.rel', ' y y ');
+
+    createElement(' x y  x ');
+    element.relList.remove('x');
+    shouldBeEqualToString('element.rel', 'y');
+
+    debug('Ensure that we can handle empty rel correctly');
+    element = document.createElement(type);
+    shouldBeTrue("element.relList.toggle('x')");
+    shouldBeEqualToString('element.rel', 'x');
+    shouldBeFalse("element.relList.toggle('x')");
+    shouldBeEqualToString('element.rel', '');
+
+    element = document.createElement(type);
+    shouldBeFalse('element.relList.contains("x")');
+    shouldBeUndefined('element.relList[1]');
+    element.relList.remove('x');
+    shouldBeFalse('element.relList.contains("x")');
+    element.relList.add('x');
+    shouldBeTrue('element.relList.contains("x")');
+
+    debug('Test toggle with force argument');
+    createElement('');
+    shouldBeTrue("element.relList.toggle('x', true)");
+    shouldBeEqualToString('element.rel', 'x');
+    shouldBeTrue("element.relList.toggle('x', true)");
+    shouldBeEqualToString('element.rel', 'x');
+    shouldBeFalse("element.relList.toggle('x', false)");
+    shouldBeEqualToString('element.rel', '');
+    shouldBeFalse("element.relList.toggle('x', false)");
+    shouldBeEqualToString('element.rel', '');
+    shouldThrow('element.relList.toggle("", true)');
+    shouldThrow('element.relList.toggle("x y", false)');
+
+    debug('Testing add in presence of trailing white spaces.');
+    createElement('x ');
+    element.relList.add('y');
+    shouldBeEqualToString('element.rel', 'x y');
+
+    createElement('x\t');
+    element.relList.add('y');
+    shouldBeEqualToString('element.rel', 'x\ty');
+
+    createElement(' ');
+    element.relList.add('y');
+    shouldBeEqualToString('element.rel', ' y');
+
+    debug('Test invalid tokens');
+
+    createElement('x');
+    shouldThrow('element.relList.contains("")');
+
+    createElement('x y');
+    shouldThrow('element.relList.contains("x y")');
+
+    createElement('');
+    shouldThrow('element.relList.add("")');
+
+    createElement('');
+    shouldThrow('element.relList.add("x y")');
+
+    createElement('');
+    shouldThrow('element.relList.remove("")');
+
+    createElement('');
+    shouldThrow('element.relList.remove("x y")');
+
+    createElement('');
+    shouldThrow('element.relList.toggle("")');
+
+    debug('Indexing');
+    createElement('x');
+    shouldBeEqualToString('element.relList[0]', 'x');
+    shouldBeEqualToString('element.relList.item(0)', 'x');
+
+    createElement('x x');
+    shouldBeEqualToString('element.relList[1]', 'x');
+    shouldBeEqualToString('element.relList.item(1)', 'x');
+
+    createElement('x y');
+    shouldBeEqualToString('element.relList[1]', 'y');
+    shouldBeEqualToString('element.relList.item(1)', 'y');
+
+    createElement('');
+    shouldBeUndefined('element.relList[0]');
+    shouldBeNull('element.relList.item(0)');
+
+    createElement('x y z');
+    shouldBeUndefined('element.relList[4]');
+    shouldBeNull('element.relList.item(4)');
+    shouldBeUndefined('element.relList[-1]');
+    shouldBeNull('element.relList.item(-1)');
+    shouldThrow('element.relList.item()');
+
+    debug('Test case since DOMTokenList is case sensitive');
+    createElement('x');
+    shouldBeTrue('element.relList.contains("x")');
+    shouldBeFalse('element.relList.contains("X")');
+    shouldBeEqualToString('element.relList[0]', 'x');
+    shouldThrow('element.relList.contains()');
+
+    createElement('X');
+    shouldBeTrue('element.relList.contains("X")');
+    shouldBeFalse('element.relList.contains("x")');
+    shouldBeEqualToString('element.relList[0]', 'X');
+
+    debug('Testing whitespace');
+    createElement('x\u0020y');
+    shouldEvaluateTo('element.relList.length', 2);
+
+    createElement('x\u0009y');
+    shouldEvaluateTo('element.relList.length', 2);
+
+    createElement('x\u000Ay');
+    shouldEvaluateTo('element.relList.length', 2);
+
+    createElement('x\u000Cy');
+    shouldEvaluateTo('element.relList.length', 2);
+
+    createElement('x\u000Dy');
+    shouldEvaluateTo('element.relList.length', 2);
+
+    debug('DOMTokenList presence and type');
+    shouldBeTrue('\'undefined\' != typeof DOMTokenList');
+
+    shouldBeEqualToString('typeof DOMTokenList.prototype', 'object');
+
+    createElement('x');
+    shouldBeEqualToString('typeof element.relList', 'object');
+    shouldEvaluateTo('element.relList.constructor', 'DOMTokenList');
+    shouldBeTrue('element.relList === element.relList');
+
+    debug('Variadic calls');
+
+    createElement('');
+    element.relList.add('a', 'b');
+    shouldBeEqualToString('element.rel', 'a b');
+
+    element.relList.add('a', 'b', 'c');
+    shouldBeEqualToString('element.rel', 'a b c');
+
+    element.relList.add(null, {toString: function() { return 'd' }}, undefined, 0, false);
+    shouldBeEqualToString('element.rel', 'a b c null d undefined 0 false');
+
+    createElement('');
+    element.relList.add('a', 'b', 'a');
+    shouldBeEqualToString('element.rel', 'a b');
+
+    createElement('');
+    shouldThrow('element.relList.add("a", "b", "")');
+    shouldBeEqualToString('element.rel', '');
+    shouldThrow('element.relList.add("a", "b", "c d")');
+    shouldBeEqualToString('element.rel', '');
+    shouldThrow('element.relList.add("a", {toString: function() { throw new Error("user error"); }}, "b")', '"Error: user error"');
+    shouldBeEqualToString('element.rel', '');
+
+    createElement('');
+    shouldNotThrow('element.relList.add()');
+
+    createElement('');
+    observer = new WebKitMutationObserver(function() {});
+    observer.observe(element, {attributes: true});
+    element.relList.add('a', 'c');
+    shouldBe('observer.takeRecords().length', '1');
+
+    createElement('a b c d  ');
+    element.relList.remove('a', 'c');
+    shouldBeEqualToString('element.rel', 'b d  ');
+
+    element.relList.remove('b', 'b');
+    shouldBeEqualToString('element.rel', 'd  ');
+
+    createElement('a b c null d undefined 0 false');
+    element.relList.remove(null, {toString: function() { return 'd' }}, undefined, 0, false);
+    shouldBeEqualToString('element.rel', 'a b c');
+
+    createElement('a b');
+    shouldThrow('element.relList.remove("a", "b", "")');
+
+    shouldBeEqualToString('element.rel', 'a b');
+    shouldThrow('element.relList.remove("a", {toString: function() { throw new Error("user error"); }}, "b")', '"Error: user error"');
+    shouldBeEqualToString('element.rel', 'a b');
+
+    shouldThrow('element.relList.remove("a", "b", "c d")');
+    shouldBeEqualToString('element.rel', 'a b');
+    shouldNotThrow('element.relList.remove()');
+
+    createElement('a b c');
+    observer = new WebKitMutationObserver(function() {});
+    observer.observe(element, {attributes: true});
+    element.relList.remove('a', 'c');
+    shouldBe('observer.takeRecords().length', '1');
+}
+
+debug('Tests relList for anchor element');
+type = 'a';
+test();
+debug('Tests relList for area element');
+type = 'area';
+test();
+debug('Tests relList for link element');
+type = 'link';
+test();
+
+</script>
+<script src=""
+</body>
+</html>
\ No newline at end of file

Modified: trunk/LayoutTests/js/dom/dom-static-property-for-in-iteration-expected.txt (175027 => 175028)


--- trunk/LayoutTests/js/dom/dom-static-property-for-in-iteration-expected.txt	2014-10-22 07:29:26 UTC (rev 175027)
+++ trunk/LayoutTests/js/dom/dom-static-property-for-in-iteration-expected.txt	2014-10-22 09:22:05 UTC (rev 175028)
@@ -27,6 +27,7 @@
 PASS a["search"] is 
 PASS a["origin"] is file://
 PASS a["text"] is nerget
+PASS a["relList"] is 
 PASS a["title"] is 
 PASS a["lang"] is 
 PASS a["translate"] is true
@@ -49,7 +50,7 @@
 PASS a["style"] is [object CSSStyleDeclaration]
 PASS a["id"] is foo
 PASS a["offsetLeft"] is 8
-PASS a["offsetTop"] is 774
+PASS a["offsetTop"] is 789
 PASS a["offsetWidth"] is 39
 PASS a["offsetHeight"] is 18
 PASS a["clientLeft"] is 0

Added: trunk/LayoutTests/perf/rel-list-remove-expected.txt (0 => 175028)


--- trunk/LayoutTests/perf/rel-list-remove-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/perf/rel-list-remove-expected.txt	2014-10-22 09:22:05 UTC (rev 175028)
@@ -0,0 +1,8 @@
+Tests that relList remove is linear.
+PASS
+PASS
+PASS
+PASS
+PASS
+PASS
+

Added: trunk/LayoutTests/perf/rel-list-remove.html (0 => 175028)


--- trunk/LayoutTests/perf/rel-list-remove.html	                        (rev 0)
+++ trunk/LayoutTests/perf/rel-list-remove.html	2014-10-22 09:22:05 UTC (rev 175028)
@@ -0,0 +1,42 @@
+<script src=""
+<script>
+
+var element, rel, relToRemove, type;
+
+// Test 1 tests that remove is linear when there are N rels.
+
+function setupFunction1(magnitude)
+{
+    element = document.createElement(type);
+    relToRemove = 'b';
+    rel = Array(magnitude).join('a ') + relToRemove;
+}
+
+// Test 2 tests that remove is linear when the length of the rel is N.
+
+function setupFunction2(magnitude)
+{
+    element = document.createElement(type);
+    relToRemove = Array(magnitude + 1).join('a');
+    rel = relToRemove;
+}
+
+function test(magnitude)
+{
+    element.rel = rel;
+    element.relList.remove(relToRemove);
+}
+
+Magnitude.description('Tests that relList remove is linear.');
+type = 'a'
+Magnitude.run(setupFunction1, test, Magnitude.LINEAR);
+Magnitude.run(setupFunction2, test, Magnitude.LINEAR);
+type = 'area'
+Magnitude.run(setupFunction1, test, Magnitude.LINEAR);
+Magnitude.run(setupFunction2, test, Magnitude.LINEAR);
+type = 'link'
+Magnitude.run(setupFunction1, test, Magnitude.LINEAR);
+Magnitude.run(setupFunction2, test, Magnitude.LINEAR);
+
+</script>
+</body>

Modified: trunk/Source/WebCore/CMakeLists.txt (175027 => 175028)


--- trunk/Source/WebCore/CMakeLists.txt	2014-10-22 07:29:26 UTC (rev 175027)
+++ trunk/Source/WebCore/CMakeLists.txt	2014-10-22 09:22:05 UTC (rev 175028)
@@ -1647,6 +1647,7 @@
     html/RadioInputType.cpp
     html/RadioNodeList.cpp
     html/RangeInputType.cpp
+    html/RelList.cpp
     html/ResetInputType.cpp
     html/SearchInputType.cpp
     html/StepRange.cpp

Modified: trunk/Source/WebCore/ChangeLog (175027 => 175028)


--- trunk/Source/WebCore/ChangeLog	2014-10-22 07:29:26 UTC (rev 175027)
+++ trunk/Source/WebCore/ChangeLog	2014-10-22 09:22:05 UTC (rev 175028)
@@ -1,3 +1,52 @@
+2014-10-22  Dhi Aurrahman  <[email protected]>
+
+        Add relList to the anchor, area and link elements
+        https://bugs.webkit.org/show_bug.cgi?id=137860
+
+        Reviewed by Darin Adler and Chris Dumez.
+
+        Add relList to reflect the rel content attribute for anchor[1],
+        area[2] and link[3] elements.
+
+        [1] https://html.spec.whatwg.org/multipage/semantics.html#dom-a-rellist 
+        [2] https://html.spec.whatwg.org/multipage/embedded-content.html#dom-area-rellist
+        [3] https://html.spec.whatwg.org/multipage/semantics.html#dom-link-rellist
+
+        Tests: fast/dom/rel-list-gc.html
+               fast/dom/rel-list.html
+               perf/rel-list-remove.html
+
+        * CMakeLists.txt:
+        * WebCore.vcxproj/WebCore.vcxproj:
+        * WebCore.vcxproj/WebCore.vcxproj.filters:
+        * WebCore.xcodeproj/project.pbxproj:
+        * dom/SpaceSplitString.cpp:
+        (WebCore::SpaceSplitString::set):
+        * html/HTMLAnchorElement.cpp:
+        (WebCore::HTMLAnchorElement::parseAttribute):
+        (WebCore::HTMLAnchorElement::relList):
+        (WebCore::HTMLAnchorElement::setRel): Deleted.
+        * html/HTMLAnchorElement.h:
+        * html/HTMLAnchorElement.idl:
+        * html/HTMLAreaElement.idl:
+        * html/HTMLLinkElement.cpp:
+        (WebCore::HTMLLinkElement::parseAttribute):
+        (WebCore::HTMLLinkElement::relList):
+        * html/HTMLLinkElement.h:
+        * html/HTMLLinkElement.idl:
+        * html/RelList.cpp: Added.
+        (WebCore::RelList::RelList):
+        (WebCore::RelList::ref):
+        (WebCore::RelList::deref):
+        (WebCore::RelList::length):
+        (WebCore::RelList::item):
+        (WebCore::RelList::element):
+        (WebCore::RelList::updateRelAttribute):
+        (WebCore::RelList::containsInternal):
+        (WebCore::RelList::value):
+        (WebCore::RelList::setValue):
+        * html/RelList.h: Added.
+
 2014-10-21  Andy Estes  <[email protected]>
 
         One more iOS build fix after r175013.

Modified: trunk/Source/WebCore/WebCore.vcxproj/WebCore.vcxproj (175027 => 175028)


--- trunk/Source/WebCore/WebCore.vcxproj/WebCore.vcxproj	2014-10-22 07:29:26 UTC (rev 175027)
+++ trunk/Source/WebCore/WebCore.vcxproj/WebCore.vcxproj	2014-10-22 09:22:05 UTC (rev 175028)
@@ -16059,6 +16059,7 @@
     <ClCompile Include="..\html\RadioInputType.cpp" />
     <ClCompile Include="..\html\RadioNodeList.cpp" />
     <ClCompile Include="..\html\RangeInputType.cpp" />
+    <ClCompile Include="..\html\RelList.cpp" />
     <ClCompile Include="..\html\ResetInputType.cpp" />
     <ClCompile Include="..\html\SearchInputType.cpp" />
     <ClCompile Include="..\html\StepRange.cpp" />
@@ -20836,6 +20837,7 @@
     <ClInclude Include="..\html\RadioInputType.h" />
     <ClInclude Include="..\html\RadioNodeList.h" />
     <ClInclude Include="..\html\RangeInputType.h" />
+    <ClInclude Include="..\html\RelList.h" />
     <ClInclude Include="..\html\ResetInputType.h" />
     <ClInclude Include="..\html\SearchInputType.h" />
     <ClInclude Include="..\html\StepRange.h" />

Modified: trunk/Source/WebCore/WebCore.vcxproj/WebCore.vcxproj.filters (175027 => 175028)


--- trunk/Source/WebCore/WebCore.vcxproj/WebCore.vcxproj.filters	2014-10-22 07:29:26 UTC (rev 175027)
+++ trunk/Source/WebCore/WebCore.vcxproj/WebCore.vcxproj.filters	2014-10-22 09:22:05 UTC (rev 175028)
@@ -4053,6 +4053,9 @@
     <ClCompile Include="..\html\RangeInputType.cpp">
       <Filter>html</Filter>
     </ClCompile>
+    <ClCompile Include="..\html\RelList.cpp">
+      <Filter>html</Filter>
+    </ClCompile>
     <ClCompile Include="..\html\ResetInputType.cpp">
       <Filter>html</Filter>
     </ClCompile>
@@ -11208,6 +11211,9 @@
     <ClInclude Include="..\html\RangeInputType.h">
       <Filter>html</Filter>
     </ClInclude>
+    <ClInclude Include="..\html\RelList.h">
+      <Filter>html</Filter>
+    </ClInclude>
     <ClInclude Include="..\html\ResetInputType.h">
       <Filter>html</Filter>
     </ClInclude>

Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (175027 => 175028)


--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2014-10-22 07:29:26 UTC (rev 175027)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2014-10-22 09:22:05 UTC (rev 175028)
@@ -4691,6 +4691,8 @@
 		B2ED97710B1F55CE00257D0F /* GraphicsContextCG.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B2ED97700B1F55CE00257D0F /* GraphicsContextCG.cpp */; };
 		B2F34FE60E82F81400F627CD /* DNS.h in Headers */ = {isa = PBXBuildFile; fileRef = B2F34FE50E82F81400F627CD /* DNS.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		B2F34FE90E82F82700F627CD /* DNSCFNet.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B2F34FE80E82F82700F627CD /* DNSCFNet.cpp */; };
+		B2F78CFD19F2F02D0049696C /* RelList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B2F78CFB19F2F02D0049696C /* RelList.cpp */; };
+		B2F78CFE19F2F02D0049696C /* RelList.h in Headers */ = {isa = PBXBuildFile; fileRef = B2F78CFC19F2F02D0049696C /* RelList.h */; };
 		B2FA3D360AB75A6F000E5AC4 /* JSSVGAnimateColorElement.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B2FA3C4E0AB75A6E000E5AC4 /* JSSVGAnimateColorElement.cpp */; };
 		B2FA3D370AB75A6F000E5AC4 /* JSSVGAnimateColorElement.h in Headers */ = {isa = PBXBuildFile; fileRef = B2FA3C4F0AB75A6E000E5AC4 /* JSSVGAnimateColorElement.h */; };
 		B2FA3D380AB75A6F000E5AC4 /* JSSVGAnimatedAngle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B2FA3C500AB75A6E000E5AC4 /* JSSVGAnimatedAngle.cpp */; };
@@ -12061,6 +12063,8 @@
 		B2ED97700B1F55CE00257D0F /* GraphicsContextCG.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = GraphicsContextCG.cpp; sourceTree = "<group>"; };
 		B2F34FE50E82F81400F627CD /* DNS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DNS.h; sourceTree = "<group>"; };
 		B2F34FE80E82F82700F627CD /* DNSCFNet.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DNSCFNet.cpp; sourceTree = "<group>"; };
+		B2F78CFB19F2F02D0049696C /* RelList.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RelList.cpp; sourceTree = "<group>"; };
+		B2F78CFC19F2F02D0049696C /* RelList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RelList.h; sourceTree = "<group>"; };
 		B2FA3C4E0AB75A6E000E5AC4 /* JSSVGAnimateColorElement.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = JSSVGAnimateColorElement.cpp; sourceTree = "<group>"; };
 		B2FA3C4F0AB75A6E000E5AC4 /* JSSVGAnimateColorElement.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = JSSVGAnimateColorElement.h; sourceTree = "<group>"; };
 		B2FA3C500AB75A6E000E5AC4 /* JSSVGAnimatedAngle.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = JSSVGAnimatedAngle.cpp; sourceTree = "<group>"; };
@@ -17914,6 +17918,8 @@
 				B658FFA41522EFAA00DD5595 /* RadioNodeList.h */,
 				F55B3D991251F12D003EF269 /* RangeInputType.cpp */,
 				F55B3D9A1251F12D003EF269 /* RangeInputType.h */,
+				B2F78CFB19F2F02D0049696C /* RelList.cpp */,
+				B2F78CFC19F2F02D0049696C /* RelList.h */,
 				F55B3D9B1251F12D003EF269 /* ResetInputType.cpp */,
 				F55B3D9C1251F12D003EF269 /* ResetInputType.h */,
 				F55B3D9D1251F12D003EF269 /* SearchInputType.cpp */,
@@ -24670,6 +24676,7 @@
 				E157A8F118185425009F821D /* JSCryptoAlgorithmBuilder.h in Headers */,
 				E1C657131815F9DD00256CDD /* JSCryptoAlgorithmDictionary.h in Headers */,
 				E157A8E11817331C009F821D /* JSCryptoKey.h in Headers */,
+				B2F78CFE19F2F02D0049696C /* RelList.h in Headers */,
 				E1F80B8E183172B5007885C3 /* JSCryptoKeyPair.h in Headers */,
 				E125F85218283A5600D84CD9 /* JSCryptoKeySerializationJWK.h in Headers */,
 				E125F83E182411E700D84CD9 /* JSCryptoOperationData.h in Headers */,
@@ -27402,6 +27409,7 @@
 				CECADFC6153778FF00E37068 /* DictationAlternative.cpp in Sources */,
 				CECADFC8153778FF00E37068 /* DictationCommand.cpp in Sources */,
 				D0BD4F5C1408850F006839B6 /* DictationCommandIOS.cpp in Sources */,
+				B2F78CFD19F2F02D0049696C /* RelList.cpp in Sources */,
 				312D67B11535691F00563D0D /* Dictionary.cpp in Sources */,
 				FDAF19981513D131008DB0C3 /* DirectConvolver.cpp in Sources */,
 				49FC7A501444AF5F00A5D864 /* DisplayRefreshMonitor.cpp in Sources */,

Modified: trunk/Source/WebCore/dom/SpaceSplitString.cpp (175027 => 175028)


--- trunk/Source/WebCore/dom/SpaceSplitString.cpp	2014-10-22 07:29:26 UTC (rev 175027)
+++ trunk/Source/WebCore/dom/SpaceSplitString.cpp	2014-10-22 09:22:05 UTC (rev 175028)
@@ -94,6 +94,10 @@
 
 void SpaceSplitString::set(const AtomicString& inputString, bool shouldFoldCase)
 {
+    if (inputString.isNull()) {
+        clear();
+        return;
+    }
     m_data = SpaceSplitStringData::create(shouldFoldCase ? inputString.convertToASCIILowercase() : inputString);
 }
 

Modified: trunk/Source/WebCore/html/HTMLAnchorElement.cpp (175027 => 175028)


--- trunk/Source/WebCore/html/HTMLAnchorElement.cpp	2014-10-22 07:29:26 UTC (rev 175027)
+++ trunk/Source/WebCore/html/HTMLAnchorElement.cpp	2014-10-22 09:22:05 UTC (rev 175028)
@@ -41,6 +41,7 @@
 #include "MouseEvent.h"
 #include "PingLoader.h"
 #include "PlatformMouseEvent.h"
+#include "RelList.h"
 #include "RenderImage.h"
 #include "ResourceRequest.h"
 #include "SVGImage.h"
@@ -261,8 +262,12 @@
         invalidateCachedVisitedLinkHash();
     } else if (name == nameAttr || name == titleAttr) {
         // Do nothing.
-    } else if (name == relAttr)
-        setRel(value);
+    } else if (name == relAttr) {
+        if (SpaceSplitString::spaceSplitStringContainsValue(value, "noreferrer", true))
+            m_linkRelations |= RelationNoReferrer;
+        if (m_relList)
+            m_relList->updateRelAttribute(value);
+    }
     else
         HTMLElement::parseAttribute(name, value);
 }
@@ -310,10 +315,11 @@
     return m_linkRelations & relation;
 }
 
-void HTMLAnchorElement::setRel(const String& value)
+DOMTokenList& HTMLAnchorElement::relList()
 {
-    if (SpaceSplitString::spaceSplitStringContainsValue(value, "noreferrer", true))
-        m_linkRelations |= RelationNoReferrer;
+    if (!m_relList) 
+        m_relList = std::make_unique<RelList>(*this);
+    return *m_relList;
 }
 
 const AtomicString& HTMLAnchorElement::name() const

Modified: trunk/Source/WebCore/html/HTMLAnchorElement.h (175027 => 175028)


--- trunk/Source/WebCore/html/HTMLAnchorElement.h	2014-10-22 07:29:26 UTC (rev 175027)
+++ trunk/Source/WebCore/html/HTMLAnchorElement.h	2014-10-22 09:22:05 UTC (rev 175028)
@@ -30,6 +30,8 @@
 
 namespace WebCore {
 
+class RelList;
+
 // Link relation bitmask values.
 // FIXME: Uncomment as the various link relations are implemented.
 enum {
@@ -97,11 +99,12 @@
     virtual bool willRespondToMouseClickEvents() override;
 
     bool hasRel(uint32_t relation) const;
-    void setRel(const String&);
     
     LinkHash visitedLinkHash() const;
     void invalidateCachedVisitedLinkHash() { m_cachedVisitedLinkHash = 0; }
 
+    DOMTokenList& relList();
+
 protected:
     HTMLAnchorElement(const QualifiedName&, Document&);
 
@@ -140,6 +143,8 @@
     bool m_wasShiftKeyDownOnMouseDown : 1;
     uint32_t m_linkRelations : 30;
     mutable LinkHash m_cachedVisitedLinkHash;
+
+    std::unique_ptr<RelList> m_relList;
 };
 
 inline LinkHash HTMLAnchorElement::visitedLinkHash() const

Modified: trunk/Source/WebCore/html/HTMLAnchorElement.idl (175027 => 175028)


--- trunk/Source/WebCore/html/HTMLAnchorElement.idl	2014-10-22 07:29:26 UTC (rev 175027)
+++ trunk/Source/WebCore/html/HTMLAnchorElement.idl	2014-10-22 09:22:05 UTC (rev 175028)
@@ -66,5 +66,7 @@
     // Objective-C extension:
     readonly attribute URL absoluteLinkURL;
 #endif
+
+    readonly attribute DOMTokenList relList;
 };
 

Modified: trunk/Source/WebCore/html/HTMLAreaElement.idl (175027 => 175028)


--- trunk/Source/WebCore/html/HTMLAreaElement.idl	2014-10-22 07:29:26 UTC (rev 175027)
+++ trunk/Source/WebCore/html/HTMLAreaElement.idl	2014-10-22 09:22:05 UTC (rev 175028)
@@ -24,6 +24,7 @@
     [Reflect, URL] attribute DOMString href;
     [Reflect] attribute boolean noHref;
     [Reflect] attribute DOMString ping;
+    [Reflect] attribute DOMString rel;
     [Reflect] attribute DOMString shape;
     [Reflect] attribute DOMString target;
 
@@ -43,5 +44,7 @@
     // Objective-C extension:
     readonly attribute URL absoluteLinkURL;
 #endif
+
+    readonly attribute DOMTokenList relList;
 };
 

Modified: trunk/Source/WebCore/html/HTMLLinkElement.cpp (175027 => 175028)


--- trunk/Source/WebCore/html/HTMLLinkElement.cpp	2014-10-22 07:29:26 UTC (rev 175027)
+++ trunk/Source/WebCore/html/HTMLLinkElement.cpp	2014-10-22 09:22:05 UTC (rev 175028)
@@ -46,6 +46,7 @@
 #include "MediaQueryEvaluator.h"
 #include "MouseEvent.h"
 #include "Page.h"
+#include "RelList.h"
 #include "RenderStyle.h"
 #include "SecurityOrigin.h"
 #include "Settings.h"
@@ -139,6 +140,8 @@
 {
     if (name == relAttr) {
         m_relAttribute = LinkRelAttribute(value);
+        if (m_relList)
+            m_relList->updateRelAttribute(value);
         process();
     } else if (name == hrefAttr) {
         bool wasLink = isLink();
@@ -381,6 +384,13 @@
         linkLoadingErrored();
 }
 
+DOMTokenList& HTMLLinkElement::relList()
+{
+    if (!m_relList) 
+        m_relList = std::make_unique<RelList>(*this);
+    return *m_relList;
+}
+
 void HTMLLinkElement::notifyLoadedSheetAndAllCriticalSubresources(bool errorOccurred)
 {
     if (m_firedLoad)

Modified: trunk/Source/WebCore/html/HTMLLinkElement.h (175027 => 175028)


--- trunk/Source/WebCore/html/HTMLLinkElement.h	2014-10-22 07:29:26 UTC (rev 175027)
+++ trunk/Source/WebCore/html/HTMLLinkElement.h	2014-10-22 09:22:05 UTC (rev 175028)
@@ -37,6 +37,7 @@
 namespace WebCore {
 
 class HTMLLinkElement;
+class RelList;
 class URL;
 
 template<typename T> class EventSender;
@@ -71,6 +72,8 @@
     void dispatchPendingEvent(LinkEventSender*);
     static void dispatchPendingLoadEvents();
 
+    DOMTokenList& relList();
+
 private:
     virtual void parseAttribute(const QualifiedName&, const AtomicString&) override;
 
@@ -100,7 +103,6 @@
     virtual void defaultEventHandler(Event*) override;
     void handleClick(Event&);
 
-private:
     HTMLLinkElement(const QualifiedName&, Document&, bool createdByParser);
 
     virtual void addSubresourceAttributeURLs(ListHashSet<URL>&) const override;
@@ -138,6 +140,8 @@
     bool m_loadedSheet;
 
     PendingSheetType m_pendingSheetType;
+
+    std::unique_ptr<RelList> m_relList;
 };
 
 } //namespace

Modified: trunk/Source/WebCore/html/HTMLLinkElement.idl (175027 => 175028)


--- trunk/Source/WebCore/html/HTMLLinkElement.idl	2014-10-22 07:29:26 UTC (rev 175027)
+++ trunk/Source/WebCore/html/HTMLLinkElement.idl	2014-10-22 09:22:05 UTC (rev 175028)
@@ -40,5 +40,7 @@
     // Objective-C extension:
     readonly attribute URL absoluteLinkURL;
 #endif
+
+    readonly attribute DOMTokenList relList;
 };
 

Added: trunk/Source/WebCore/html/RelList.cpp (0 => 175028)


--- trunk/Source/WebCore/html/RelList.cpp	                        (rev 0)
+++ trunk/Source/WebCore/html/RelList.cpp	2014-10-22 09:22:05 UTC (rev 175028)
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2014 Dhi Aurrahman <[email protected]>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1.  Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ * 2.  Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "RelList.h"
+
+#include "Element.h"
+#include "HTMLNames.h"
+
+namespace WebCore {
+
+RelList::RelList(Element& element) 
+    : m_element(element)
+    , m_relAttributeValue(SpaceSplitString(element.fastGetAttribute(HTMLNames::relAttr), false))
+{
+}
+
+void RelList::ref()
+{
+    m_element.ref();
+}
+
+void RelList::deref()
+{
+    m_element.deref();
+}
+
+unsigned RelList::length() const
+{
+    return m_relAttributeValue.size();
+}
+
+const AtomicString RelList::item(unsigned index) const
+{
+    if (index >= length())
+        return nullAtom;
+    return m_relAttributeValue[index];
+}
+
+Element* RelList::element() const
+{
+    return &m_element;
+}
+
+void RelList::updateRelAttribute(const AtomicString& value)
+{
+    m_relAttributeValue.set(value, false);
+}
+
+bool RelList::containsInternal(const AtomicString& token) const
+{
+    return m_relAttributeValue.contains(token);
+}
+
+AtomicString RelList::value() const
+{
+    return m_element.fastGetAttribute(HTMLNames::relAttr);
+}
+
+void RelList::setValue(const AtomicString& value)
+{
+    m_element.setAttribute(HTMLNames::relAttr, value);
+}
+
+} // namespace WebCore
+

Added: trunk/Source/WebCore/html/RelList.h (0 => 175028)


--- trunk/Source/WebCore/html/RelList.h	                        (rev 0)
+++ trunk/Source/WebCore/html/RelList.h	2014-10-22 09:22:05 UTC (rev 175028)
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2014 Dhi Aurrahman <[email protected]>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1.  Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ * 2.  Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef RelList_h
+#define RelList_h
+
+#include "DOMTokenList.h"
+#include "SpaceSplitString.h"
+
+namespace WebCore {
+
+class Element;
+
+class RelList final : public DOMTokenList {
+public:
+    RelList(Element&);
+    void updateRelAttribute(const AtomicString&);
+
+private:
+    virtual void ref() override;
+    virtual void deref() override;
+    virtual unsigned length() const override;
+    virtual const AtomicString item(unsigned index) const override;
+    virtual Element* element() const override;
+    virtual bool containsInternal(const AtomicString&) const override;
+    virtual AtomicString value() const override;
+    virtual void setValue(const AtomicString&) override;
+    
+    Element& m_element;
+    mutable SpaceSplitString m_relAttributeValue;
+};
+
+} // namespace WebCore
+
+#endif // RelList_h
+
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to