content property doesn't support quotes
authorcarol.szabo@nokia.com <carol.szabo@nokia.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 1 Mar 2011 22:01:36 +0000 (22:01 +0000)
committercarol.szabo@nokia.com <carol.szabo@nokia.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 1 Mar 2011 22:01:36 +0000 (22:01 +0000)
https://bugs.webkit.org/show_bug.cgi?id=6503

Reviewed by David Hyatt  <hyatt@apple.com>

Source/WebCore:

Added full support for quotes as defined by CSS 2.1.

Tests: fast/css/content/content-quotes-01.html
       fast/css/content/content-quotes-02.html
       fast/css/content/content-quotes-03.html
       fast/css/content/content-quotes-04.html
       fast/css/content/content-quotes-05.html

* Android.mk:
* CMakeLists.txt:
* GNUmakefile.am:
* WebCore.pro:
* WebCore.vcproj/WebCore.vcproj:
* WebCore.xcodeproj/project.pbxproj:
Added RenderQuote.cpp/h and QuotesData.cpp/h to the dependency lists
* css/CSSParser.cpp:
(WebCore::CSSParser::parseValue):
(WebCore::CSSParser::parseQuotes):
* css/CSSParser.h:
Added needed stylesheet parsing support for quotes,
(no-)open-quote and (no-)close-quote
* css/CSSStyleSelector.cpp:
(WebCore::CSSStyleSelector::applyProperty):
Handled setting of the new quotes RenderStyle property and added
handling of quotes for the content property.
* css/html.css:
(q:before):
(q:after):
replaced the '"' workaround with open/close-quote
* rendering/RenderBlockLineLayout.cpp:
(WebCore::dirtyLineBoxesForRenderer):
Made RenderQuote behave like RenderCounter.
Needed to ensure that the Quote text is calculated before layout,
just as it is for RenderCounter.
* rendering/RenderObject.h:
(WebCore::RenderObject::isQuote):
* rendering/RenderObjectChildList.cpp:
(WebCore::RenderObjectChildList::removeChildNode):
(WebCore::RenderObjectChildList::appendChildNode):
(WebCore::RenderObjectChildList::insertChildNode):
Handled updating of quote depth when renderers are added and removed
from the tree.
(WebCore::RenderObjectChildList::updateBeforeAfterContent):
* rendering/RenderQuote.cpp: Added.
(WebCore::adjustDepth):
(WebCore::RenderQuote::RenderQuote):
(WebCore::RenderQuote::~RenderQuote):
(WebCore::RenderQuote::renderName):
(WebCore::RenderQuote::placeQuote):
(WebCore::RenderQuote::originalText):
(WebCore::RenderQuote::computePreferredLogicalWidths):
(WebCore::RenderQuote::rendererSubtreeAttached):
(WebCore::RenderQuote::rendererRemovedFromTree):
(WebCore::RenderQuote::styleDidChange):
* rendering/RenderQuote.h: Added.
(WebCore::RenderQuote::isQuote):
(WebCore::toRenderQuote):
* rendering/RenderingAllInOne.cpp:
Included RenderQuote.cpp
* rendering/style/StyleAllInOne.cpp:
Included QuotesData.cpp
* rendering/style/ContentData.cpp:
(WebCore::ContentData::dataEquivalent):
Checked for quotetype identity.
(WebCore::ContentData::deleteContent):
Accounted for the new QUOTE_TYPE.
* rendering/style/ContentData.h:
(WebCore::ContentData::isQuote):
(WebCore::ContentData::quote):
(WebCore::ContentData::setQuote):
* rendering/style/RenderStyle.cpp:
(WebCore::RenderStyle::setContent):
* rendering/style/RenderStyle.h:
(WebCore::InheritedFlags::quotes):
(WebCore::InheritedFlags::setQuotes):
* rendering/style/RenderStyleConstants.h:
* rendering/style/StyleRareInheritedData.cpp:
(WebCore::StyleRareInheritedData::operator==):
Included quotes in equality check.
* rendering/style/StyleRareInheritedData.h:
Added quotes

LayoutTests:

Added new tests for quotes.

* fast/css/content/content-quotes-01-expected.txt: Added.
* fast/css/content/content-quotes-01.html: Added.
* fast/css/content/content-quotes-02-expected.txt: Added.
* fast/css/content/content-quotes-02.html: Added.
* fast/css/content/content-quotes-03-expected.txt: Added.
* fast/css/content/content-quotes-03.html: Added.
* fast/css/content/content-quotes-04-expected.txt: Added.
* fast/css/content/content-quotes-04.html: Added.
* fast/css/content/content-quotes-05-expected.txt: Added.
* fast/css/content/content-quotes-05.html: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@80037 268f45cc-cd09-0410-ab3c-d52691b4dbfc

41 files changed:
LayoutTests/ChangeLog
LayoutTests/fast/css/content/content-quotes-01-expected.txt [new file with mode: 0644]
LayoutTests/fast/css/content/content-quotes-01.html [new file with mode: 0644]
LayoutTests/fast/css/content/content-quotes-02-expected.txt [new file with mode: 0644]
LayoutTests/fast/css/content/content-quotes-02.html [new file with mode: 0644]
LayoutTests/fast/css/content/content-quotes-03-expected.txt [new file with mode: 0644]
LayoutTests/fast/css/content/content-quotes-03.html [new file with mode: 0644]
LayoutTests/fast/css/content/content-quotes-04-expected.txt [new file with mode: 0644]
LayoutTests/fast/css/content/content-quotes-04.html [new file with mode: 0644]
LayoutTests/fast/css/content/content-quotes-05-expected.txt [new file with mode: 0644]
LayoutTests/fast/css/content/content-quotes-05.html [new file with mode: 0644]
LayoutTests/fast/css/content/content-quotes-06-expected.txt [new file with mode: 0644]
LayoutTests/fast/css/content/content-quotes-06.html [new file with mode: 0644]
Source/WebCore/Android.mk
Source/WebCore/CMakeLists.txt
Source/WebCore/ChangeLog
Source/WebCore/GNUmakefile.am
Source/WebCore/WebCore.gypi
Source/WebCore/WebCore.pro
Source/WebCore/WebCore.vcproj/WebCore.vcproj
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/css/CSSParser.cpp
Source/WebCore/css/CSSParser.h
Source/WebCore/css/CSSStyleSelector.cpp
Source/WebCore/css/html.css
Source/WebCore/rendering/RenderBlockLineLayout.cpp
Source/WebCore/rendering/RenderObject.h
Source/WebCore/rendering/RenderObjectChildList.cpp
Source/WebCore/rendering/RenderQuote.cpp [new file with mode: 0644]
Source/WebCore/rendering/RenderQuote.h [new file with mode: 0644]
Source/WebCore/rendering/RenderingAllInOne.cpp
Source/WebCore/rendering/style/ContentData.cpp
Source/WebCore/rendering/style/ContentData.h
Source/WebCore/rendering/style/QuotesData.cpp [new file with mode: 0644]
Source/WebCore/rendering/style/QuotesData.h [new file with mode: 0644]
Source/WebCore/rendering/style/RenderStyle.cpp
Source/WebCore/rendering/style/RenderStyle.h
Source/WebCore/rendering/style/RenderStyleConstants.h
Source/WebCore/rendering/style/StyleAllInOne.cpp
Source/WebCore/rendering/style/StyleRareInheritedData.cpp
Source/WebCore/rendering/style/StyleRareInheritedData.h

index 934ebdf..3f1e9dc 100644 (file)
@@ -1,3 +1,23 @@
+2011-03-01  Carol Szabo  <carol.szabo@nokia.com>
+
+        Reviewed by David Hyatt  <hyatt@apple.com>
+
+        content property doesn't support quotes
+        https://bugs.webkit.org/show_bug.cgi?id=6503
+
+        Added new tests for quotes.
+
+        * fast/css/content/content-quotes-01-expected.txt: Added.
+        * fast/css/content/content-quotes-01.html: Added.
+        * fast/css/content/content-quotes-02-expected.txt: Added.
+        * fast/css/content/content-quotes-02.html: Added.
+        * fast/css/content/content-quotes-03-expected.txt: Added.
+        * fast/css/content/content-quotes-03.html: Added.
+        * fast/css/content/content-quotes-04-expected.txt: Added.
+        * fast/css/content/content-quotes-04.html: Added.
+        * fast/css/content/content-quotes-05-expected.txt: Added.
+        * fast/css/content/content-quotes-05.html: Added.
+
 2011-03-01  Michael Nordman  <michaeln@google.com>
 
         Reviewed by Alexey Proskuryakov.
diff --git a/LayoutTests/fast/css/content/content-quotes-01-expected.txt b/LayoutTests/fast/css/content/content-quotes-01-expected.txt
new file mode 100644 (file)
index 0000000..41ec8f1
--- /dev/null
@@ -0,0 +1,11 @@
+The texts between the markers should be identical.
+
+========Marker1========
+
+ab     1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+========Marker2========
+
+WWaWWbWWWWWWWW 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+========Marker3========
+
+PASSED
diff --git a/LayoutTests/fast/css/content/content-quotes-01.html b/LayoutTests/fast/css/content/content-quotes-01.html
new file mode 100644 (file)
index 0000000..eb9a40d
--- /dev/null
@@ -0,0 +1,44 @@
+<html>
+    <head>
+        <style type="text/css">
+            body { quotes: "WW" "WWWW"; }
+        </style>
+        <script type="text/javascript">
+            if (window.layoutTestController) {
+                layoutTestController.dumpAsText();
+                layoutTestController.waitUntilDone();
+            }
+
+            function run() {
+                testWidth = window.getComputedStyle(document.getElementById("testContainer"), null).getPropertyValue("width");
+                referenceWidth = window.getComputedStyle(document.getElementById("reference"), null).getPropertyValue("width");
+                if (testWidth == referenceWidth)
+                    document.getElementById("console").innerText = "PASSED";
+                else
+                    document.getElementById("console").innerText = "FAILED: testWidth=" + testWidth +"; expected " + referenceWidth;
+               if (window.layoutTestController)
+                    layoutTestController.notifyDone();
+           }
+        </script>
+    </head>
+
+    <body onload="setTimeout('run()', 0);">
+        <p id="onlyInBrowser">The texts between the markers should be identical.</p>
+        <p>========Marker1========</p>
+        <table>
+            <tr>
+                <td id="testContainer"><q>a<q>b</q></q></td>
+                <td>1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1</td>
+            </tr>
+        </table>
+        <p>========Marker2========</p>
+        <table>
+            <tr>
+                <td id="reference">WWaWWbWWWWWWWW</td>
+                <td>1 1 1 1 1 1 1 1 1 1 1  1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1</td>
+            </tr>
+        </table>
+        <p>========Marker3========</p>
+        <pre id="console"/>
+    </body>
+</html>
diff --git a/LayoutTests/fast/css/content/content-quotes-02-expected.txt b/LayoutTests/fast/css/content/content-quotes-02-expected.txt
new file mode 100644 (file)
index 0000000..ea14476
--- /dev/null
@@ -0,0 +1,9 @@
+========Marker1========
+
+abcd   1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+========Marker2========
+
+aWWWbWWWWWcWWdWWWW     1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+========Marker3========
+
+PASSED
diff --git a/LayoutTests/fast/css/content/content-quotes-02.html b/LayoutTests/fast/css/content/content-quotes-02.html
new file mode 100644 (file)
index 0000000..a1e7851
--- /dev/null
@@ -0,0 +1,49 @@
+<html>
+    <head>
+        <style type="text/css">
+            body { quotes: "WW" "WWWW" "WWW" "WWWWW"; }
+            span:before { content: no-open-quote; }
+            span:after { content: no-close-quote; }
+        </style>
+        <script type="text/javascript">
+            if (window.layoutTestController) {
+                layoutTestController.dumpAsText();
+                layoutTestController.waitUntilDone();
+            }
+
+            function run() {
+                if (window.layoutTestController)
+                    document.getElementById("onlyInBrowser").setAttribute("style", "display: none;");
+                testWidth = window.getComputedStyle(document.getElementById("testContainer"), null).getPropertyValue("width");
+                referenceWidth = window.getComputedStyle(document.getElementById("reference"), null).getPropertyValue("width");
+                if (testWidth == referenceWidth)
+                    document.getElementById("console").innerText = "PASSED";
+                else
+                    document.getElementById("console").innerText = "FAILED: testWidth=" + testWidth +"; expected " + referenceWidth;
+               document.getElementById("onlyInBrowser").setAttribute("style", "display: none;");
+               if (window.layoutTestController)
+                    layoutTestController.notifyDone();
+           }
+        </script>
+    </head>
+
+    <body onload="setTimeout('run()', 0);">
+        <p id="onlyInBrowser">The texts between the markers should be identical.</p>
+        <p>========Marker1========</p>
+        <table>
+            <tr>
+                <td id="testContainer"><span>a<q>b</q>c</span><q>d</q></td>
+                <td>1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1</td>
+            </tr>
+        </table>
+        <p>========Marker2========</p>
+        <table>
+            <tr>
+                <td id="reference">aWWWbWWWWWcWWdWWWW</td>
+                <td>1 1 1 1 1 1 1 1 1 1 1  1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1</td>
+            </tr>
+        </table>
+        <p>========Marker3========</p>
+        <pre id="console"/>
+    </body>
+</html>
diff --git a/LayoutTests/fast/css/content/content-quotes-03-expected.txt b/LayoutTests/fast/css/content/content-quotes-03-expected.txt
new file mode 100644 (file)
index 0000000..251deba
--- /dev/null
@@ -0,0 +1,9 @@
+========Marker1========
+
+ab     1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+========Marker2========
+
+aWWWbWWWWW     1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+========Marker3========
+
+PASSED
diff --git a/LayoutTests/fast/css/content/content-quotes-03.html b/LayoutTests/fast/css/content/content-quotes-03.html
new file mode 100644 (file)
index 0000000..7c1f9bd
--- /dev/null
@@ -0,0 +1,47 @@
+<html>
+    <head>
+        <style type="text/css">
+            body { quotes: "WW" "WWWW" "WWW" "WWWWW"; }
+            b:before { content: no-open-quote; }
+        </style>
+        <script type="text/javascript">
+            if (window.layoutTestController) {
+                layoutTestController.dumpAsText();
+                layoutTestController.waitUntilDone();
+            }
+
+            function run() {
+                if (window.layoutTestController)
+                    document.getElementById("onlyInBrowser").setAttribute("style", "display: none;");
+                testWidth = window.getComputedStyle(document.getElementById("testContainer"), null).getPropertyValue("width");
+                referenceWidth = window.getComputedStyle(document.getElementById("reference"), null).getPropertyValue("width");
+                if (testWidth == referenceWidth)
+                    document.getElementById("console").innerText = "PASSED";
+                else
+                    document.getElementById("console").innerText = "FAILED: testWidth=" + testWidth +"; expected " + referenceWidth;
+               if (window.layoutTestController)
+                    layoutTestController.notifyDone();
+           }
+        </script>
+    </head>
+
+    <body onload="setTimeout('run()', 0);">
+        <p id="onlyInBrowser">The texts between the markers should be identical.</p>
+        <p>========Marker1========</p>
+        <table>
+            <tr>
+                <td id="testContainer"><span><b>a</b></span><q>b</q></td>
+                <td>1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1</td>
+            </tr>
+        </table>
+        <p>========Marker2========</p>
+        <table>
+            <tr>
+                <td id="reference"><span style="font-weight: bolder;">a</span>WWWbWWWWW</td>
+                <td>1 1 1 1 1 1 1 1 1 1 1  1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1</td>
+            </tr>
+        </table>
+        <p>========Marker3========</p>
+        <pre id="console"/>
+    </body>
+</html>
diff --git a/LayoutTests/fast/css/content/content-quotes-04-expected.txt b/LayoutTests/fast/css/content/content-quotes-04-expected.txt
new file mode 100644 (file)
index 0000000..2057a40
--- /dev/null
@@ -0,0 +1,9 @@
+========Marker1========
+
+b      1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+========Marker2========
+
+WWbWWWW        1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+========Marker3========
+
+PASSED
diff --git a/LayoutTests/fast/css/content/content-quotes-04.html b/LayoutTests/fast/css/content/content-quotes-04.html
new file mode 100644 (file)
index 0000000..87029d7
--- /dev/null
@@ -0,0 +1,49 @@
+<html>
+    <head>
+        <style type="text/css">
+            body { quotes: "WW" "WWWW" "WWW" "WWWWW"; }
+            b:before { content: no-open-quote; }
+        </style>
+        <script type="text/javascript">
+            if (window.layoutTestController) {
+                layoutTestController.dumpAsText();
+                layoutTestController.waitUntilDone();
+            }
+
+            function run() {
+                if (window.layoutTestController)
+                    document.getElementById("onlyInBrowser").setAttribute("style", "display: none;");
+                el = document.getElementById("toRemove");
+                el.parentNode.removeChild(el);
+                testWidth = window.getComputedStyle(document.getElementById("testContainer"), null).getPropertyValue("width");
+                referenceWidth = window.getComputedStyle(document.getElementById("reference"), null).getPropertyValue("width");
+                if (testWidth == referenceWidth)
+                    document.getElementById("console").innerText = "PASSED";
+                else
+                    document.getElementById("console").innerText = "FAILED: testWidth=" + testWidth +"; expected " + referenceWidth;
+               if (window.layoutTestController)
+                    layoutTestController.notifyDone();
+           }
+        </script>
+    </head>
+
+    <body onload="setTimeout('run()', 0);">
+        <p id="onlyInBrowser">The texts between the markers should be identical.</p>
+        <p>========Marker1========</p>
+        <table>
+            <tr>
+                <td id="testContainer"><span><b id="toRemove">a</b></span><q>b</q></td>
+                <td>1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1</td>
+            </tr>
+        </table>
+        <p>========Marker2========</p>
+        <table>
+            <tr>
+                <td id="reference">WWbWWWW</td>
+                <td>1 1 1 1 1 1 1 1 1 1 1  1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1</td>
+            </tr>
+        </table>
+        <p>========Marker3========</p>
+        <pre id="console"/>
+    </body>
+</html>
diff --git a/LayoutTests/fast/css/content/content-quotes-05-expected.txt b/LayoutTests/fast/css/content/content-quotes-05-expected.txt
new file mode 100644 (file)
index 0000000..43eb497
--- /dev/null
@@ -0,0 +1,9 @@
+========Marker1========
+
+abc    1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+========Marker2========
+
+WWaWWWbWWWWWcWWWW      1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+========Marker3========
+
+PASSED
diff --git a/LayoutTests/fast/css/content/content-quotes-05.html b/LayoutTests/fast/css/content/content-quotes-05.html
new file mode 100644 (file)
index 0000000..422be3c
--- /dev/null
@@ -0,0 +1,47 @@
+<html>
+    <head>
+        <style type="text/css">
+            .myQuotes { quotes: "WW" "WWWW" "WWW" "WWWWW"; }
+        </style>
+        <script type="text/javascript">
+            if (window.layoutTestController) {
+                layoutTestController.dumpAsText();
+                layoutTestController.waitUntilDone();
+            }
+
+            function run() {
+                if (window.layoutTestController)
+                    document.getElementById("onlyInBrowser").setAttribute("style", "display: none;");
+                document.body.setAttribute("class", "myQuotes");
+                testWidth = window.getComputedStyle(document.getElementById("testContainer"), null).getPropertyValue("width");
+                referenceWidth = window.getComputedStyle(document.getElementById("reference"), null).getPropertyValue("width");
+                if (testWidth == referenceWidth)
+                    document.getElementById("console").innerText = "PASSED";
+                else
+                    document.getElementById("console").innerText = "FAILED: testWidth=" + testWidth +"; expected " + referenceWidth;
+               if (window.layoutTestController)
+                    layoutTestController.notifyDone();
+           }
+        </script>
+    </head>
+
+    <body onload="setTimeout('run()', 0);">
+        <p id="onlyInBrowser">The texts between the markers should be identical.</p>
+        <p>========Marker1========</p>
+        <table>
+            <tr>
+                <td id="testContainer"><q>a<q>b</q>c</q></td>
+                <td>1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1</td>
+            </tr>
+        </table>
+        <p>========Marker2========</p>
+        <table>
+            <tr>
+                <td id="reference">WWaWWWbWWWWWcWWWW</td>
+                <td>1 1 1 1 1 1 1 1 1 1 1  1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1</td>
+            </tr>
+        </table>
+        <p>========Marker3========</p>
+        <pre id="console"/>
+    </body>
+</html>
diff --git a/LayoutTests/fast/css/content/content-quotes-06-expected.txt b/LayoutTests/fast/css/content/content-quotes-06-expected.txt
new file mode 100644 (file)
index 0000000..57644ea
--- /dev/null
@@ -0,0 +1,9 @@
+========Marker1========
+
+abc    1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+========Marker2========
+
+a'b'c  1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+========Marker3========
+
+PASSED
diff --git a/LayoutTests/fast/css/content/content-quotes-06.html b/LayoutTests/fast/css/content/content-quotes-06.html
new file mode 100644 (file)
index 0000000..325a653
--- /dev/null
@@ -0,0 +1,47 @@
+<html>
+    <head>
+        <style type="text/css">
+            .initialQuotes { quotes: initial; }
+            .noQuotes { quotes: none; }
+        </style>
+        <script type="text/javascript">
+            if (window.layoutTestController) {
+                layoutTestController.dumpAsText();
+                layoutTestController.waitUntilDone();
+            }
+
+            function run() {
+                if (window.layoutTestController)
+                    document.getElementById("onlyInBrowser").setAttribute("style", "display: none;");
+                testWidth = window.getComputedStyle(document.getElementById("testContainer"), null).getPropertyValue("width");
+                referenceWidth = window.getComputedStyle(document.getElementById("reference"), null).getPropertyValue("width");
+                if (testWidth == referenceWidth)
+                    document.getElementById("console").innerText = "PASSED";
+                else
+                    document.getElementById("console").innerText = "FAILED: testWidth=" + testWidth +"; expected " + referenceWidth;
+               if (window.layoutTestController)
+                    layoutTestController.notifyDone();
+           }
+        </script>
+    </head>
+
+    <body onload="setTimeout('run()', 0);">
+        <p id="onlyInBrowser">The texts between the markers should be identical.</p>
+        <p>========Marker1========</p>
+        <table>
+            <tr>
+                <td id="testContainer" class="noQuotes"><q>a<q class="initialQuotes">b</q>c</q></td>
+                <td>1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1</td>
+            </tr>
+        </table>
+        <p>========Marker2========</p>
+        <table>
+            <tr>
+                <td id="reference">a'b'c</td>
+                <td>1 1 1 1 1 1 1 1 1 1 1  1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1</td>
+            </tr>
+        </table>
+        <p>========Marker3========</p>
+        <pre id="console"/>
+    </body>
+</html>
index 848d438..c59a09f 100644 (file)
@@ -702,6 +702,7 @@ LOCAL_SRC_FILES := $(LOCAL_SRC_FILES) \
        rendering/RenderObject.cpp \
        rendering/RenderObjectChildList.cpp \
        rendering/RenderPart.cpp \
+       rendering/RenderQuote.cpp \
        rendering/RenderReplaced.cpp \
        rendering/RenderReplica.cpp \
 
@@ -791,6 +792,7 @@ LOCAL_SRC_FILES := $(LOCAL_SRC_FILES) \
        rendering/style/FillLayer.cpp \
        rendering/style/KeyframeList.cpp \
        rendering/style/NinePieceImage.cpp \
+       rendering/style/QuotesData.cpp \
        rendering/style/RenderStyle.cpp \
 
 ifeq ($(ENABLE_SVG), true)
index c02265c..1503ea4 100644 (file)
@@ -1377,6 +1377,7 @@ SET(WebCore_SOURCES
     rendering/RenderObjectChildList.cpp
     rendering/RenderPart.cpp
     rendering/RenderProgress.cpp
+    rendering/RenderQuote.cpp
     rendering/RenderReplaced.cpp
     rendering/RenderReplica.cpp
     rendering/RenderRuby.cpp
@@ -1414,6 +1415,7 @@ SET(WebCore_SOURCES
     rendering/style/FillLayer.cpp
     rendering/style/KeyframeList.cpp
     rendering/style/NinePieceImage.cpp
+    rendering/style/QuotesData.cpp
     rendering/style/RenderStyle.cpp
     rendering/style/ShadowData.cpp
     rendering/style/StyleBackgroundData.cpp
index e75cfef..2ce586a 100644 (file)
@@ -1,3 +1,92 @@
+2011-03-01  Carol Szabo  <carol.szabo@nokia.com>
+
+        Reviewed by David Hyatt  <hyatt@apple.com>
+
+        content property doesn't support quotes
+        https://bugs.webkit.org/show_bug.cgi?id=6503
+
+        Added full support for quotes as defined by CSS 2.1.
+
+        Tests: fast/css/content/content-quotes-01.html
+               fast/css/content/content-quotes-02.html
+               fast/css/content/content-quotes-03.html
+               fast/css/content/content-quotes-04.html
+               fast/css/content/content-quotes-05.html
+
+        * Android.mk:
+        * CMakeLists.txt:
+        * GNUmakefile.am:
+        * WebCore.pro:
+        * WebCore.vcproj/WebCore.vcproj:
+        * WebCore.xcodeproj/project.pbxproj:
+        Added RenderQuote.cpp/h and QuotesData.cpp/h to the dependency lists
+        * css/CSSParser.cpp:
+        (WebCore::CSSParser::parseValue):
+        (WebCore::CSSParser::parseQuotes):
+        * css/CSSParser.h:
+        Added needed stylesheet parsing support for quotes,
+        (no-)open-quote and (no-)close-quote
+        * css/CSSStyleSelector.cpp:
+        (WebCore::CSSStyleSelector::applyProperty):
+        Handled setting of the new quotes RenderStyle property and added
+        handling of quotes for the content property.
+        * css/html.css:
+        (q:before):
+        (q:after):
+        replaced the '"' workaround with open/close-quote
+        * rendering/RenderBlockLineLayout.cpp:
+        (WebCore::dirtyLineBoxesForRenderer):
+        Made RenderQuote behave like RenderCounter.
+        Needed to ensure that the Quote text is calculated before layout,
+        just as it is for RenderCounter.
+        * rendering/RenderObject.h:
+        (WebCore::RenderObject::isQuote):
+        * rendering/RenderObjectChildList.cpp:
+        (WebCore::RenderObjectChildList::removeChildNode):
+        (WebCore::RenderObjectChildList::appendChildNode):
+        (WebCore::RenderObjectChildList::insertChildNode):
+        Handled updating of quote depth when renderers are added and removed
+        from the tree.
+        (WebCore::RenderObjectChildList::updateBeforeAfterContent):
+        * rendering/RenderQuote.cpp: Added.
+        (WebCore::adjustDepth):
+        (WebCore::RenderQuote::RenderQuote):
+        (WebCore::RenderQuote::~RenderQuote):
+        (WebCore::RenderQuote::renderName):
+        (WebCore::RenderQuote::placeQuote):
+        (WebCore::RenderQuote::originalText):
+        (WebCore::RenderQuote::computePreferredLogicalWidths):
+        (WebCore::RenderQuote::rendererSubtreeAttached):
+        (WebCore::RenderQuote::rendererRemovedFromTree):
+        (WebCore::RenderQuote::styleDidChange):
+        * rendering/RenderQuote.h: Added.
+        (WebCore::RenderQuote::isQuote):
+        (WebCore::toRenderQuote):
+        * rendering/RenderingAllInOne.cpp:
+        Included RenderQuote.cpp
+        * rendering/style/StyleAllInOne.cpp:
+        Included QuotesData.cpp
+        * rendering/style/ContentData.cpp:
+        (WebCore::ContentData::dataEquivalent):
+        Checked for quotetype identity.
+        (WebCore::ContentData::deleteContent):
+        Accounted for the new QUOTE_TYPE.
+        * rendering/style/ContentData.h:
+        (WebCore::ContentData::isQuote):
+        (WebCore::ContentData::quote):
+        (WebCore::ContentData::setQuote):
+        * rendering/style/RenderStyle.cpp:
+        (WebCore::RenderStyle::setContent):
+        * rendering/style/RenderStyle.h:
+        (WebCore::InheritedFlags::quotes):
+        (WebCore::InheritedFlags::setQuotes):
+        * rendering/style/RenderStyleConstants.h:
+        * rendering/style/StyleRareInheritedData.cpp:
+        (WebCore::StyleRareInheritedData::operator==):
+        Included quotes in equality check.
+        * rendering/style/StyleRareInheritedData.h:
+        Added quotes
+
 2011-03-01  Michael Nordman  <michaeln@google.com>
 
         Reviewed by Alexey Proskuryakov.
index 7ea2e51..28b5393 100644 (file)
@@ -2828,6 +2828,8 @@ webcore_sources += \
        Source/WebCore/rendering/RenderPart.h \
        Source/WebCore/rendering/RenderProgress.cpp \
        Source/WebCore/rendering/RenderProgress.h \
+       Source/WebCore/rendering/RenderQuote.cpp \
+       Source/WebCore/rendering/RenderQuote.h \
        Source/WebCore/rendering/RenderReplaced.cpp \
        Source/WebCore/rendering/RenderReplaced.h \
        Source/WebCore/rendering/RenderReplica.cpp \
@@ -2930,6 +2932,8 @@ webcore_sources += \
        Source/WebCore/rendering/style/NinePieceImage.cpp \
        Source/WebCore/rendering/style/NinePieceImage.h \
        Source/WebCore/rendering/style/OutlineValue.h \
+       Source/WebCore/rendering/style/QuotesData.cpp \
+       Source/WebCore/rendering/style/QuotesData.h \
        Source/WebCore/rendering/style/RenderStyleConstants.h \
        Source/WebCore/rendering/style/RenderStyle.cpp \
        Source/WebCore/rendering/style/RenderStyle.h \
index e340444..4ae5937 100644 (file)
             'rendering/style/NinePieceImage.cpp',
             'rendering/style/NinePieceImage.h',
             'rendering/style/OutlineValue.h',
+            'rendering/style/QuotesData.cpp',
+            'rendering/style/QuotesData.h',
             'rendering/style/RenderStyle.cpp',
             'rendering/style/RenderStyle.h',
             'rendering/style/RenderStyleConstants.h',
             'rendering/RenderPart.h',
             'rendering/RenderProgress.cpp',
             'rendering/RenderProgress.h',
+            'rendering/RenderQuote.cpp',
+            'rendering/RenderQuote.h',
             'rendering/RenderReplaced.cpp',
             'rendering/RenderReplaced.h',
             'rendering/RenderReplica.cpp',
index 458d6a2..912567c 100644 (file)
@@ -1088,6 +1088,7 @@ SOURCES += \
     rendering/RenderObjectChildList.cpp \
     rendering/RenderPart.cpp \
     rendering/RenderProgress.cpp \
+    rendering/RenderQuote.cpp \
     rendering/RenderReplaced.cpp \
     rendering/RenderReplica.cpp \
     rendering/RenderRuby.cpp \
@@ -1123,6 +1124,7 @@ SOURCES += \
     rendering/style/FillLayer.cpp \
     rendering/style/KeyframeList.cpp \
     rendering/style/NinePieceImage.cpp \
+    rendering/style/QuotesData.cpp \
     rendering/style/RenderStyle.cpp \
     rendering/style/ShadowData.cpp \
     rendering/style/StyleBackgroundData.cpp \
@@ -2075,6 +2077,7 @@ HEADERS += \
     rendering/RenderObject.h \
     rendering/RenderPart.h \
     rendering/RenderProgress.h \
+    rendering/RenderQuote.h \
     rendering/RenderReplaced.h \
     rendering/RenderReplica.h \
     rendering/RenderRuby.h \
@@ -2112,6 +2115,7 @@ HEADERS += \
     rendering/style/FillLayer.h \
     rendering/style/KeyframeList.h \
     rendering/style/NinePieceImage.h \
+    rendering/style/QuotesData.h \
     rendering/style/RenderStyle.h \
     rendering/style/ShadowData.h \
     rendering/style/StyleBackgroundData.h \
index 46ccc2c..5350344 100755 (executable)
                                >
                        </File>
                        <File
+                               RelativePath="..\rendering\RenderQuote.cpp"
+                               >
+                               <FileConfiguration
+                                       Name="Debug|Win32"
+                                       ExcludedFromBuild="true"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Release|Win32"
+                                       ExcludedFromBuild="true"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Debug_Cairo_CFLite|Win32"
+                                       ExcludedFromBuild="true"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Release_Cairo_CFLite|Win32"
+                                       ExcludedFromBuild="true"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Debug_All|Win32"
+                                       ExcludedFromBuild="true"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Release_LTCG|Win32"
+                                       ExcludedFromBuild="true"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                       />
+                               </FileConfiguration>
+                       </File>
+                       <File
+                               RelativePath="..\rendering\RenderQuote.h"
+                               >
+                       </File>
+                       <File
                                RelativePath="..\rendering\RenderReplaced.cpp"
                                >
                                <FileConfiguration
                                        >
                                </File>
                                <File
+                                       RelativePath="..\rendering\style\QuotesData.cpp"
+                                       >
+                                       <FileConfiguration
+                                               Name="Debug|Win32"
+                                               ExcludedFromBuild="true"
+                                               >
+                                               <Tool
+                                                       Name="VCCLCompilerTool"
+                                               />
+                                       </FileConfiguration>
+                                       <FileConfiguration
+                                               Name="Release|Win32"
+                                               ExcludedFromBuild="true"
+                                               >
+                                               <Tool
+                                                       Name="VCCLCompilerTool"
+                                               />
+                                       </FileConfiguration>
+                                       <FileConfiguration
+                                               Name="Debug_Cairo_CFLite|Win32"
+                                               ExcludedFromBuild="true"
+                                               >
+                                               <Tool
+                                                       Name="VCCLCompilerTool"
+                                               />
+                                       </FileConfiguration>
+                                       <FileConfiguration
+                                               Name="Release_Cairo_CFLite|Win32"
+                                               ExcludedFromBuild="true"
+                                               >
+                                               <Tool
+                                                       Name="VCCLCompilerTool"
+                                               />
+                                       </FileConfiguration>
+                                       <FileConfiguration
+                                               Name="Debug_All|Win32"
+                                               ExcludedFromBuild="true"
+                                               >
+                                               <Tool
+                                                       Name="VCCLCompilerTool"
+                                               />
+                                       </FileConfiguration>
+                                       <FileConfiguration
+                                               Name="Release_LTCG|Win32"
+                                               ExcludedFromBuild="true"
+                                               >
+                                               <Tool
+                                                       Name="VCCLCompilerTool"
+                                               />
+                                       </FileConfiguration>
+                               </File>
+                               <File
+                                       RelativePath="..\rendering\style\QuotesData.h"
+                                       >
+                               </File>
+                               <File
                                        RelativePath="..\rendering\style\RenderStyle.cpp"
                                        >
                                        <FileConfiguration
index 40d69b9..e632963 100644 (file)
                9392F1440AD185FE00691BD4 /* RenderCounter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9392F1430AD185FE00691BD4 /* RenderCounter.cpp */; };
                9392F14C0AD1861B00691BD4 /* CounterNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 9392F14B0AD1861B00691BD4 /* CounterNode.h */; };
                9392F1500AD1862300691BD4 /* CounterNode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9392F14F0AD1862300691BD4 /* CounterNode.cpp */; };
+               9392F1420AD185F400691BD4 /* RenderQuote.h in Headers */ = {isa = PBXBuildFile; fileRef = 9392F1410AD185F400691BD4 /* RenderQuote.h */; };
+               9392F1440AD185FE00691BD4 /* RenderQuote.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9392F1430AD185FE00691BD4 /* RenderQuote.cpp */; };
                939885C308B7E3D100E707C4 /* EventNames.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 939885C108B7E3D100E707C4 /* EventNames.cpp */; };
                939885C408B7E3D100E707C4 /* EventNames.h in Headers */ = {isa = PBXBuildFile; fileRef = 939885C208B7E3D100E707C4 /* EventNames.h */; settings = {ATTRIBUTES = (Private, ); }; };
                939B02EE0EA2DBC400C54570 /* WidthIterator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 939B02EC0EA2DBC400C54570 /* WidthIterator.cpp */; };
                BCEF43CF0E673DA1001C1287 /* StyleImage.h in Headers */ = {isa = PBXBuildFile; fileRef = BCEF43CE0E673DA1001C1287 /* StyleImage.h */; settings = {ATTRIBUTES = (Private, ); }; };
                BCEF43DD0E674012001C1287 /* NinePieceImage.h in Headers */ = {isa = PBXBuildFile; fileRef = BCEF43DC0E674012001C1287 /* NinePieceImage.h */; settings = {ATTRIBUTES = (Private, ); }; };
                BCEF43E00E674110001C1287 /* NinePieceImage.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BCEF43DF0E674110001C1287 /* NinePieceImage.cpp */; };
+               9392F1420AD185F400691BD4 /* QuotesData.h in Sources */ = {isa = PBXBuildFile; fileRef = 9392F1420AD185F400691BD4 /* QutoesData.h */; };
+               9392F1420AD185F400691BD4 /* QuotesData.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9392F1420AD185F400691BD4 /* QutoesData.cpp */; };
                BCEF444A0E6745E0001C1287 /* StyleGeneratedImage.h in Headers */ = {isa = PBXBuildFile; fileRef = BCEF44490E6745E0001C1287 /* StyleGeneratedImage.h */; settings = {ATTRIBUTES = (Private, ); }; };
                BCEF444D0E674628001C1287 /* StyleCachedImage.h in Headers */ = {isa = PBXBuildFile; fileRef = BCEF444C0E674628001C1287 /* StyleCachedImage.h */; settings = {ATTRIBUTES = (Private, ); }; };
                BCEF447A0E6747D0001C1287 /* StyleCachedImage.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BCEF44790E6747D0001C1287 /* StyleCachedImage.cpp */; };
                9392F1430AD185FE00691BD4 /* RenderCounter.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = RenderCounter.cpp; sourceTree = "<group>"; };
                9392F14B0AD1861B00691BD4 /* CounterNode.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = CounterNode.h; sourceTree = "<group>"; };
                9392F14F0AD1862300691BD4 /* CounterNode.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = CounterNode.cpp; sourceTree = "<group>"; };
+               9392F1410AD185F400691BD4 /* RenderQuote.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = RenderQuote.h; sourceTree = "<group>"; };
+               9392F1430AD185FE00691BD4 /* RenderQuote.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = RenderQuote.cpp; sourceTree = "<group>"; };
                93955A4103D72932008635CE /* RenderTreeAsText.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = RenderTreeAsText.h; sourceTree = "<group>"; tabWidth = 8; usesTabs = 0; };
                93955A4203D72932008635CE /* RenderTreeAsText.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RenderTreeAsText.cpp; sourceTree = "<group>"; tabWidth = 8; usesTabs = 0; };
                939885C108B7E3D100E707C4 /* EventNames.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; path = EventNames.cpp; sourceTree = "<group>"; tabWidth = 8; usesTabs = 0; };
                BCEF43CE0E673DA1001C1287 /* StyleImage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StyleImage.h; path = style/StyleImage.h; sourceTree = "<group>"; };
                BCEF43DC0E674012001C1287 /* NinePieceImage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NinePieceImage.h; path = style/NinePieceImage.h; sourceTree = "<group>"; };
                BCEF43DF0E674110001C1287 /* NinePieceImage.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = NinePieceImage.cpp; path = style/NinePieceImage.cpp; sourceTree = "<group>"; };
+               9392F1420AD185F400691BD4 /* QuotesData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = QuotesData.h; path = style/QuotesData.h; sourceTree = "<group>"; };
+               9392F1420AD185F400691BD4 /* QuotesData.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = QuotesData.cpp; path = style/QuotesData.cpp; sourceTree = "<group>"; };
                BCEF44490E6745E0001C1287 /* StyleGeneratedImage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StyleGeneratedImage.h; path = style/StyleGeneratedImage.h; sourceTree = "<group>"; };
                BCEF444C0E674628001C1287 /* StyleCachedImage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StyleCachedImage.h; path = style/StyleCachedImage.h; sourceTree = "<group>"; };
                BCEF44790E6747D0001C1287 /* StyleCachedImage.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = StyleCachedImage.cpp; path = style/StyleCachedImage.cpp; sourceTree = "<group>"; };
                                BCEF43DF0E674110001C1287 /* NinePieceImage.cpp */,
                                BCEF43DC0E674012001C1287 /* NinePieceImage.h */,
                                BC5EB5DC0E81B8DD00B25965 /* OutlineValue.h */,
+                               9392F1420AD185F400691BD4 /* QuotesData.cpp */,
+                               9392F1420AD185F400691BD4 /* QuotesData.h */,
                                BC8C8FAB0DDCD31B00B592F4 /* RenderStyle.cpp */,
                                BC8C8FAC0DDCD31B00B592F4 /* RenderStyle.h */,
                                BC5EB6670E81CB7100B25965 /* RenderStyleConstants.h */,
                                A871DECF0A1530C700B12A68 /* RenderPart.h */,
                                A43BF59A1149292800C643CA /* RenderProgress.cpp */,
                                A43BF59B1149292800C643CA /* RenderProgress.h */,
+                               9392F1430AD185FE00691BD4 /* RenderQuote.cpp */,
+                               9392F1410AD185F400691BD4 /* RenderQuote.h */,
                                A871DFDE0A15376B00B12A68 /* RenderReplaced.cpp */,
                                A871DFDF0A15376B00B12A68 /* RenderReplaced.h */,
                                BCA846D40DC67A350026C309 /* RenderReplica.cpp */,
                                E4D687790ED7AE4F006EA978 /* PurgeableBuffer.h in Headers */,
                                7E33CD01127F340D00BE8F17 /* PurgePriority.h in Headers */,
                                550A0BCA085F6039007353D6 /* QualifiedName.h in Headers */,
+                               9392F1420AD185F400691BD4 /* QuotesData.h in Headers */,
                                B22279720D00BF220071B782 /* RadialGradientAttributes.h in Headers */,
                                F55B3DCC1251F12D003EF269 /* RadioInputType.h in Headers */,
                                93F1991808245E59001E9ABC /* Range.h in Headers */,
                                BCFA930810333193007B25D1 /* RenderOverflow.h in Headers */,
                                A871DED70A1530C700B12A68 /* RenderPart.h in Headers */,
                                A43BF59D1149292800C643CA /* RenderProgress.h in Headers */,
+                               9392F1420AD185F400691BD4 /* RenderQuote.h in Headers */,
                                A871DFE30A15376B00B12A68 /* RenderReplaced.h in Headers */,
                                BCA846D70DC67A350026C309 /* RenderReplica.h in Headers */,
                                1479FAEE109AE37500DED655 /* RenderRuby.h in Headers */,
                                1A7FA61B0DDA3BBE0028F8A5 /* NetworkStateNotifier.cpp in Sources */,
                                1A7FA6490DDA3CBA0028F8A5 /* NetworkStateNotifierMac.cpp in Sources */,
                                BCEF43E00E674110001C1287 /* NinePieceImage.cpp in Sources */,
+                               9392F1420AD185F400691BD4 /* QuotesData.cpp in Sources */,
                                A8C4A80009D563270003AC8D /* Node.cpp in Sources */,
                                854FE7300A2297BE0058D7AD /* NodeFilter.cpp in Sources */,
                                854FE7320A2297BE0058D7AD /* NodeFilterCondition.cpp in Sources */,
                                BC60EFB70F33A0E700812A93 /* RenderObjectChildList.cpp in Sources */,
                                A871DED00A1530C700B12A68 /* RenderPart.cpp in Sources */,
                                A43BF59C1149292800C643CA /* RenderProgress.cpp in Sources */,
+                               9392F1440AD185FE00691BD4 /* RenderQuote.cpp in Sources */,
                                A871DFE20A15376B00B12A68 /* RenderReplaced.cpp in Sources */,
                                BCA846D60DC67A350026C309 /* RenderReplica.cpp in Sources */,
                                1479FAED109AE37500DED655 /* RenderRuby.cpp in Sources */,
index e49f792..ce0c039 100644 (file)
@@ -634,6 +634,8 @@ bool CSSParser::parseValue(int propId, bool important)
     case CSSPropertyQuotes:               // [<string> <string>]+ | none | inherit
         if (id)
             validPrimitive = true;
+        else
+            return parseQuotes(propId, important);
         break;
     case CSSPropertyUnicodeBidi:         // normal | embed | bidi-override | inherit
         if (id == CSSValueNormal ||
@@ -2354,6 +2356,28 @@ CSSParser::SizeParameterType CSSParser::parseSizeParameter(CSSValueList* parsedV
     }
 }
 
+// [ <string> <string> ]+ | inherit | none
+// inherit and none are handled in parseValue.
+bool CSSParser::parseQuotes(int propId, bool important)
+{
+    RefPtr<CSSValueList> values = CSSValueList::createCommaSeparated();
+    while (CSSParserValue* val = m_valueList->current()) {
+        RefPtr<CSSValue> parsedValue;
+        if (val->unit == CSSPrimitiveValue::CSS_STRING)
+            parsedValue = CSSPrimitiveValue::create(val->string, CSSPrimitiveValue::CSS_STRING);
+        else
+            break;
+        values->append(parsedValue.release());
+        m_valueList->next();
+    }
+    if (values->length()) {
+        addProperty(propId, values.release(), important);
+        m_valueList->next();
+        return true;
+    }
+    return false;
+}
+
 // [ <string> | <uri> | <counter> | attr(X) | open-quote | close-quote | no-open-quote | no-close-quote ]+ | inherit
 // in CSS 2.1 this got somewhat reduced:
 // [ <string> | attr(X) | open-quote | close-quote | no-open-quote | no-close-quote ]+ | inherit
index 6ccfbe2..99b9c44 100644 (file)
@@ -79,6 +79,7 @@ namespace WebCore {
         bool parseShorthand(int propId, const int* properties, int numProperties, bool important);
         bool parse4Values(int propId, const int* properties, bool important);
         bool parseContent(int propId, bool important);
+        bool parseQuotes(int propId, bool important);
 
         PassRefPtr<CSSValue> parseAttr(CSSParserValueList* args);
 
index 36d4158..cbb8e47 100644 (file)
@@ -71,6 +71,7 @@
 #include "PageGroup.h"
 #include "Pair.h"
 #include "PerspectiveTransformOperation.h"
+#include "QuotesData.h"
 #include "Rect.h"
 #include "RenderScrollbar.h"
 #include "RenderScrollbarTheme.h"
@@ -4726,36 +4727,59 @@ void CSSStyleSelector::applyProperty(int id, CSSValue *value)
             
             CSSPrimitiveValue* contentValue = static_cast<CSSPrimitiveValue*>(item);
             switch (contentValue->primitiveType()) {
-                case CSSPrimitiveValue::CSS_STRING:
-                    m_style->setContent(contentValue->getStringValue().impl(), didSet);
+            case CSSPrimitiveValue::CSS_STRING:
+                m_style->setContent(contentValue->getStringValue().impl(), didSet);
+                didSet = true;
+                break;
+            case CSSPrimitiveValue::CSS_ATTR: {
+                // FIXME: Can a namespace be specified for an attr(foo)?
+                if (m_style->styleType() == NOPSEUDO)
+                    m_style->setUnique();
+                else
+                    m_parentStyle->setUnique();
+                QualifiedName attr(nullAtom, contentValue->getStringValue().impl(), nullAtom);
+                m_style->setContent(m_element->getAttribute(attr).impl(), didSet);
+                didSet = true;
+                // register the fact that the attribute value affects the style
+                m_selectorAttrs.add(attr.localName().impl());
+                break;
+            }
+            case CSSPrimitiveValue::CSS_URI: {
+                if (!contentValue->isImageValue())
+                    break;
+                m_style->setContent(cachedOrPendingFromValue(CSSPropertyContent, static_cast<CSSImageValue*>(contentValue)), didSet);
+                didSet = true;
+                break;
+            }
+            case CSSPrimitiveValue::CSS_COUNTER: {
+                Counter* counterValue = contentValue->getCounterValue();
+                OwnPtr<CounterContent> counter = adoptPtr(new CounterContent(counterValue->identifier(),
+                    (EListStyleType)counterValue->listStyleNumber(), counterValue->separator()));
+                m_style->setContent(counter.release(), didSet);
+                didSet = true;
+                break;
+            }
+            case CSSPrimitiveValue::CSS_IDENT:
+                switch (contentValue->getIdent()) {
+                case CSSValueOpenQuote:
+                    m_style->setContent(OPEN_QUOTE, didSet);
                     didSet = true;
                     break;
-                case CSSPrimitiveValue::CSS_ATTR: {
-                    // FIXME: Can a namespace be specified for an attr(foo)?
-                    if (m_style->styleType() == NOPSEUDO)
-                        m_style->setUnique();
-                    else
-                        m_parentStyle->setUnique();
-                    QualifiedName attr(nullAtom, contentValue->getStringValue().impl(), nullAtom);
-                    m_style->setContent(m_element->getAttribute(attr).impl(), didSet);
+                case CSSValueCloseQuote:
+                    m_style->setContent(CLOSE_QUOTE, didSet);
                     didSet = true;
-                    // register the fact that the attribute value affects the style
-                    m_selectorAttrs.add(attr.localName().impl());
                     break;
-                }
-                case CSSPrimitiveValue::CSS_URI: {
-                    if (!contentValue->isImageValue())
-                        break;
-                    m_style->setContent(cachedOrPendingFromValue(CSSPropertyContent, static_cast<CSSImageValue*>(contentValue)), didSet);
+                case CSSValueNoOpenQuote:
+                    m_style->setContent(NO_OPEN_QUOTE, didSet);
                     didSet = true;
                     break;
-                }
-                case CSSPrimitiveValue::CSS_COUNTER: {
-                    Counter* counterValue = contentValue->getCounterValue();
-                    OwnPtr<CounterContent> counter = adoptPtr(new CounterContent(counterValue->identifier(),
-                        (EListStyleType)counterValue->listStyleNumber(), counterValue->separator()));
-                    m_style->setContent(counter.release(), didSet);
+                case CSSValueNoCloseQuote:
+                    m_style->setContent(NO_CLOSE_QUOTE, didSet);
                     didSet = true;
+                    break;
+                default:
+                    // normal and none do not have any effect.
+                    {}
                 }
             }
         }
@@ -4763,6 +4787,37 @@ void CSSStyleSelector::applyProperty(int id, CSSValue *value)
             m_style->clearContent();
         return;
     }
+    case CSSPropertyQuotes:
+        if (isInherit) {
+            if (m_parentStyle)
+                m_style->setQuotes(m_parentStyle->quotes());
+            return;
+        }
+        if (isInitial) {
+            m_style->setQuotes(0);
+            return;
+        }
+        if (value->isValueList()) {
+            CSSValueList* list = static_cast<CSSValueList*>(value);
+            size_t length = list->length();
+            QuotesData* data = QuotesData::create(length);
+            if (!data)
+                return; // Out of memory
+            String* quotes = data->data();
+            for (size_t i = 0; i < length; i++) {
+                CSSValue* item = list->itemWithoutBoundsCheck(i);
+                ASSERT(item->isPrimitiveValue());
+                primitiveValue = static_cast<CSSPrimitiveValue*>(item);
+                ASSERT(primitiveValue->primitiveType() == CSSPrimitiveValue::CSS_STRING);
+                quotes[i] = primitiveValue->getStringValue();
+            }
+            m_style->setQuotes(adoptRef(data));
+        } else if (primitiveValue) {
+            ASSERT(primitiveValue->primitiveType() == CSSPrimitiveValue::CSS_IDENT);
+            if (primitiveValue->getIdent() == CSSValueNone)
+                m_style->setQuotes(adoptRef(QuotesData::create(0)));
+        }
+        return;
 
     case CSSPropertyCounterIncrement:
         applyCounterList(style(), value->isValueList() ? static_cast<CSSValueList*>(value) : 0, false);
@@ -6004,7 +6059,6 @@ void CSSStyleSelector::applyProperty(int id, CSSValue *value)
 
     case CSSPropertyFontStretch:
     case CSSPropertyPage:
-    case CSSPropertyQuotes:
     case CSSPropertyTextLineThrough:
     case CSSPropertyTextLineThroughColor:
     case CSSPropertyTextLineThroughMode:
index 3dbc0c5..61178d0 100644 (file)
@@ -113,13 +113,11 @@ q {
 }
 
 q:before {
-    content: '"'
-    /* FIXME: content: open-quote; */
+    content: open-quote;
 }
 
 q:after {
-    content: '"'
-    /* FIXME: content: close-quote; */
+    content: close-quote;
 }
 
 center {
index a3296a4..8d8f4ad 100644 (file)
@@ -178,7 +178,7 @@ static inline InlineBox* createInlineBoxForRenderer(RenderObject* obj, bool isRo
 static inline void dirtyLineBoxesForRenderer(RenderObject* o, bool fullLayout)
 {
     if (o->isText()) {
-        if (o->preferredLogicalWidthsDirty() && o->isCounter())
+        if (o->preferredLogicalWidthsDirty() && (o->isCounter() || o->isQuote()))
             toRenderText(o)->computePreferredLogicalWidths(0); // FIXME: Counters depend on this hack. No clue why. Should be investigated and removed.
         toRenderText(o)->dirtyLineBoxes(fullLayout);
     } else
index 6adce17..8b9fa38 100644 (file)
@@ -252,6 +252,7 @@ public:
     virtual bool isBlockFlow() const { return false; }
     virtual bool isBoxModelObject() const { return false; }
     virtual bool isCounter() const { return false; }
+    virtual bool isQuote() const { return false; }
     virtual bool isDetails() const { return false; }
     virtual bool isDetailsMarker() const { return false; }
     virtual bool isEmbeddedObject() const { return false; }
index 6a773dc..4df7180 100644 (file)
@@ -36,6 +36,7 @@
 #include "RenderInline.h"
 #include "RenderLayer.h"
 #include "RenderListItem.h"
+#include "RenderQuote.h"
 #include "RenderStyle.h"
 #include "RenderTextFragment.h"
 #include "RenderView.h"
@@ -130,6 +131,7 @@ RenderObject* RenderObjectChildList::removeChildNode(RenderObject* owner, Render
 
     if (oldChild->m_hasCounterNodeMap)
         RenderCounter::destroyCounterNodes(oldChild);
+    RenderQuote::rendererRemovedFromTree(oldChild);
 
     if (AXObjectCache::accessibilityEnabled())
         owner->document()->axObjectCache()->childrenChanged(owner);
@@ -177,8 +179,8 @@ void RenderObjectChildList::appendChildNode(RenderObject* owner, RenderObject* n
         if (!newChild->isFloatingOrPositioned() && owner->childrenInline())
             owner->dirtyLinesFromChangedChild(newChild);
     }
-
     RenderCounter::rendererSubtreeAttached(newChild);
+    RenderQuote::rendererSubtreeAttached(newChild);
     newChild->setNeedsLayoutAndPrefWidthsRecalc(); // Goes up the containing block hierarchy.
     if (!owner->normalChildNeedsLayout())
         owner->setChildNeedsLayout(true); // We may supply the static position for an absolute positioned child.
@@ -239,6 +241,7 @@ void RenderObjectChildList::insertChildNode(RenderObject* owner, RenderObject* c
     }
 
     RenderCounter::rendererSubtreeAttached(child);
+    RenderQuote::rendererSubtreeAttached(child);
     child->setNeedsLayoutAndPrefWidthsRecalc();
     if (!owner->normalChildNeedsLayout())
         owner->setChildNeedsLayout(true); // We may supply the static position for an absolute positioned child.
@@ -460,10 +463,14 @@ void RenderObjectChildList::updateBeforeAfterContent(RenderObject* owner, Pseudo
                 renderer = image;
                 break;
             }
-            case CONTENT_COUNTER:
-                renderer = new (owner->renderArena()) RenderCounter(owner->document(), *content->counter());
-                renderer->setStyle(pseudoElementStyle);
-                break;
+        case CONTENT_COUNTER:
+            renderer = new (owner->renderArena()) RenderCounter(owner->document(), *content->counter());
+            renderer->setStyle(pseudoElementStyle);
+            break;
+        case CONTENT_QUOTE:
+            renderer = new (owner->renderArena()) RenderQuote(owner->document(), content->quote());
+            renderer->setStyle(pseudoElementStyle);
+            break;
         }
 
         if (renderer) {
diff --git a/Source/WebCore/rendering/RenderQuote.cpp b/Source/WebCore/rendering/RenderQuote.cpp
new file mode 100644 (file)
index 0000000..7639582
--- /dev/null
@@ -0,0 +1,330 @@
+/**
+ * Copyright (C) 2011 Nokia Inc.  All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "RenderQuote.h"
+
+#include "Document.h"
+#include "Element.h"
+#include "HTMLElement.h"
+#include "QuotesData.h"
+#include "RenderStyle.h"
+#include <algorithm>
+#include <wtf/text/AtomicString.h>
+
+#define UNKNOWN_DEPTH -1
+
+namespace WebCore {
+static inline void adjustDepth(int &depth, QuoteType type)
+{
+    switch (type) {
+    case OPEN_QUOTE:
+    case NO_OPEN_QUOTE:
+        ++depth;
+        break;
+    case CLOSE_QUOTE:
+    case NO_CLOSE_QUOTE:
+        if (depth)
+            --depth;
+        break;
+    default:
+        ASSERT_NOT_REACHED();
+    }
+}
+
+RenderQuote::RenderQuote(Document* node, QuoteType quote)
+    : RenderText(node, StringImpl::empty())
+    , m_type(quote)
+    , m_depth(UNKNOWN_DEPTH)
+    , m_next(0)
+    , m_previous(0)
+{
+}
+
+RenderQuote::~RenderQuote()
+{
+}
+
+const char* RenderQuote::renderName() const
+{
+    return "RenderQuote";
+}
+
+// This function places a list of quote renderers starting at "this" in the list of quote renderers already
+// in the document's renderer tree.
+// The assumptions are made (for performance):
+// 1. The list of quotes already in the renderers tree of the document is already in a consistent state
+// (All quote renderers are linked and have the correct depth set)
+// 2. The quote renderers of the inserted list are in a tree of renderers of their own which has been just
+// inserted in the main renderer tree with its root as child of some renderer.
+// 3. The quote renderers in the inserted list have depths consistent with their position in the list relative
+// to "this", thus if "this" does not need to change its depth upon insertion, the other renderers in the list don't
+// need to either.
+void RenderQuote::placeQuote()
+{
+    RenderQuote* head = this;
+    ASSERT(!head->m_previous);
+    RenderQuote* tail = 0;
+    for (RenderObject* predecessor = head->previousInPreOrder(); predecessor; predecessor = predecessor->previousInPreOrder()) {
+        if (!predecessor->isQuote())
+            continue;
+        head->m_previous = toRenderQuote(predecessor);
+        if (head->m_previous->m_next) {
+            // We need to splice the list of quotes headed by head into the document's list of quotes.
+            tail = head;
+            while (tail->m_next)
+                 tail = tail->m_next;
+            tail->m_next = head->m_previous->m_next;
+            ASSERT(tail->m_next->m_previous == head->m_previous);
+            tail->m_next->m_previous =  tail;
+            tail = tail->m_next; // This marks the splicing point here there may be a depth discontinuity
+        }
+        head->m_previous->m_next = head;
+        ASSERT(head->m_previous->m_depth != UNKNOWN_DEPTH);
+        break;
+    }
+    int newDepth;
+    if (!head->m_previous) {
+        newDepth = 0;
+        goto skipNewDepthCalc;
+    }
+    newDepth = head->m_previous->m_depth;
+    do {
+        adjustDepth(newDepth, head->m_previous->m_type);
+skipNewDepthCalc:
+        if (head->m_depth == newDepth) { // All remaining depth should be correct except if splicing was done.
+            if (!tail) // We've done the post splicing section already or there was no splicing.
+                break;
+            head = tail; // Continue after the splicing point
+            tail = 0; // Mark the possible splicing point discontinuity fixed.
+            newDepth = head->m_previous->m_depth;
+            continue;
+        }
+        head->m_depth = newDepth;
+        // FIXME: If the width and height of the quotation characters does not change we may only need to
+        // Invalidate the renderer's area not a relayout.
+        head->setNeedsLayoutAndPrefWidthsRecalc();
+        head = head->m_next;
+        if (head == tail) // We are at the splicing point
+            tail = 0; // Mark the possible depth discontinuity fixed.
+    } while (head);
+}
+
+#define ARRAY_SIZE(Carray) (sizeof(Carray) / sizeof(*Carray))
+#define LANGUAGE_DATA(name, languageSourceArray) { name, languageSourceArray, ARRAY_SIZE(languageSourceArray) }
+#define U(x) ((const UChar*)L##x)
+
+static const UChar* simpleQuotes[] = {U("\""), U("\""), U("'"), U("'")};
+
+static const UChar* englishQuotes[] = {U("\x201C"), U("\x201D"), U("\x2018"), U("\x2019")};
+static const UChar* norwegianQuotes[] = { U("\x00AB"), U("\x00BB"), U("\x2039"), U("\x203A") };
+static const UChar* romanianQuotes[] = { U("\x201E"), U("\x201D")};
+static const UChar* russianQuotes[] = { U("\x00AB"), U("\x00BB"), U("\x201E"), U("\x201C") };
+#undef U
+
+struct LanguageData {
+    const char *name;
+    const UChar* const* const array;
+    const int arraySize;
+    bool operator<(const LanguageData& compareTo) const
+    {
+        return strcmp(name, compareTo.name);
+    }
+};
+
+// Data mast be alphabetically sorted and in all lower case for fast comparison
+LanguageData languageData[] = {
+    LANGUAGE_DATA("en", englishQuotes),
+    LANGUAGE_DATA("no", norwegianQuotes),
+    LANGUAGE_DATA("ro", romanianQuotes),
+    LANGUAGE_DATA("ru", russianQuotes)
+};
+#undef LANGUAGE_DATA
+const LanguageData* const languageDataEnd = languageData + ARRAY_SIZE(languageData);
+
+#define defaultLanguageQuotesSource simpleQuotes
+#define defaultLanguageQuotesCount ARRAY_SIZE(defaultLanguageQuotesSource)
+
+static QuotesData* defaultLanguageQuotesValue = 0;
+static const QuotesData* defaultLanguageQuotes()
+{
+    if (!defaultLanguageQuotesValue) {
+        defaultLanguageQuotesValue = QuotesData::create(defaultLanguageQuotesCount);
+        if (!defaultLanguageQuotesValue)
+            return 0;
+        String* data = defaultLanguageQuotesValue->data();
+        for (size_t i = 0; i < defaultLanguageQuotesCount; ++i)
+            data[i] = defaultLanguageQuotesSource[i];
+    }
+    return defaultLanguageQuotesValue;
+}
+#undef defaultLanguageQuotesSource
+#undef defaultLanguageQuotesCount
+
+typedef HashMap<RefPtr<AtomicStringImpl>, QuotesData* > QuotesMap;
+
+static QuotesMap& quotesMap()
+{
+    DEFINE_STATIC_LOCAL(QuotesMap, staticQuotesMap, ());
+    return staticQuotesMap;
+}
+
+static const QuotesData* quotesForLanguage(AtomicStringImpl* language)
+{
+    QuotesData* returnValue;
+    AtomicString lower(language->lower());
+    returnValue = quotesMap().get(lower.impl());
+    if (returnValue)
+        return returnValue;
+    CString s(static_cast<const String&>(lower).ascii());
+    LanguageData request = { s.buffer()->data(), 0, 0 };
+    const LanguageData* lowerBound = std::lower_bound<const LanguageData*, const LanguageData>(languageData, languageDataEnd, request);
+    if (lowerBound == languageDataEnd)
+        return defaultLanguageQuotes();
+    if (strncmp(lowerBound->name, request.name, strlen(lowerBound->name)))
+        return defaultLanguageQuotes();
+    returnValue = QuotesData::create(lowerBound->arraySize);
+    if (!returnValue)
+        return defaultLanguageQuotes();
+    String* data = returnValue->data();
+    for (int i = 0; i < lowerBound->arraySize; ++i)
+        data[i] = lowerBound->array[i];
+    quotesMap().set(lower.impl(), returnValue);
+    return returnValue;
+}
+#undef ARRAY_SIZE
+
+static const QuotesData* defaultQuotes(const RenderObject* object)
+{
+    static String langString = "lang";
+    Node* node =  object->generatingNode();
+    Element* element;
+    if (!node) {
+        element = object->document()->body();
+        if (!element)
+            element = object->document()->documentElement();
+    } else if (!node->isElementNode()) {
+        element = node->parentElement();
+        if (!element)
+            return defaultLanguageQuotes();
+    } else
+      element = toElement(node);
+    const AtomicString* language;
+    while ((language = &element->getAttribute(langString)) && language->isNull()) {
+        element = element->parentElement();
+        if (!element)
+            return defaultLanguageQuotes();
+    }
+    return quotesForLanguage(language->impl());
+}
+
+PassRefPtr<StringImpl> RenderQuote::originalText() const
+{
+    if (!parent())
+        return 0;
+    ASSERT(m_depth != UNKNOWN_DEPTH);
+    const QuotesData* quotes = style()->quotes();
+    if (!quotes)
+        quotes = defaultQuotes(this);
+    if (!quotes->length)
+        return emptyAtom.impl();
+    int index = m_depth * 2;
+    switch (m_type) {
+    case NO_OPEN_QUOTE:
+    case NO_CLOSE_QUOTE:
+        return String("").impl();
+    case CLOSE_QUOTE:
+        if (index)
+            --index;
+        else
+            ++index;
+        break;
+    case OPEN_QUOTE:
+        break;
+    default:
+        ASSERT_NOT_REACHED();
+        return emptyAtom.impl();
+    }
+    if (index >= quotes->length)
+        index = (quotes->length-2) | (index & 1);
+    if (index < 0)
+        return emptyAtom.impl();
+    return quotes->data()[index].impl();
+}
+
+void RenderQuote::computePreferredLogicalWidths(float lead)
+{
+    setTextInternal(originalText());
+    RenderText::computePreferredLogicalWidths(lead);
+}
+
+void RenderQuote::rendererSubtreeAttached(RenderObject* renderer)
+{
+    if (renderer->documentBeingDestroyed())
+        return;
+    for (RenderObject* descendant = renderer; descendant; descendant = descendant->nextInPreOrder(renderer))
+        if (descendant->isQuote()) {
+            toRenderQuote(descendant)->placeQuote();
+            break;
+        }
+}
+
+void RenderQuote::rendererRemovedFromTree(RenderObject* subtreeRoot)
+{
+    if (subtreeRoot->documentBeingDestroyed())
+        return;
+    for (RenderObject* descendant = subtreeRoot; descendant; descendant = descendant->nextInPreOrder(subtreeRoot))
+        if (descendant->isQuote()) {
+            RenderQuote* removedQuote = toRenderQuote(descendant);
+            RenderQuote* lastQuoteBefore = removedQuote->m_previous;
+            removedQuote->m_previous = 0;
+            int depth = removedQuote->m_depth;
+            for (descendant = descendant->nextInPreOrder(subtreeRoot); descendant; descendant = descendant->nextInPreOrder(subtreeRoot))
+                if (descendant->isQuote())
+                    removedQuote = toRenderQuote(descendant);
+            RenderQuote* quoteAfter = removedQuote->m_next;
+            removedQuote->m_next = 0;
+            if (lastQuoteBefore)
+                lastQuoteBefore->m_next = quoteAfter;
+            if (quoteAfter) {
+                quoteAfter->m_previous = lastQuoteBefore;
+                do {
+                    if (depth == quoteAfter->m_depth)
+                        break;
+                    quoteAfter->m_depth = depth;
+                    quoteAfter->setNeedsLayoutAndPrefWidthsRecalc();
+                    adjustDepth(depth, quoteAfter->m_type);
+                    quoteAfter = quoteAfter->m_next;
+                } while (quoteAfter);
+            }
+            break;
+        }
+}
+
+void RenderQuote::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
+{
+    const QuotesData* newQuotes = style()->quotes();
+    const QuotesData* oldQuotes = oldStyle ? oldStyle->quotes() : 0;
+    if (!((newQuotes && oldQuotes && (*newQuotes == *oldQuotes)) || (!newQuotes && !oldQuotes)))
+        setNeedsLayoutAndPrefWidthsRecalc();
+    RenderText::styleDidChange(diff, oldStyle);
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/rendering/RenderQuote.h b/Source/WebCore/rendering/RenderQuote.h
new file mode 100644 (file)
index 0000000..d9e5437
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2011 Nokia Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef RenderQuote_h
+#define RenderQuote_h
+
+#include "RenderStyleConstants.h"
+#include "RenderText.h"
+
+namespace WebCore {
+
+class RenderQuote : public RenderText {
+public:
+    RenderQuote(Document*, const QuoteType);
+    virtual ~RenderQuote();
+
+    static void rendererSubtreeAttached(RenderObject*);
+    static void rendererRemovedFromTree(RenderObject*);
+protected:
+    virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle);
+private:
+    virtual const char* renderName() const;
+    virtual bool isQuote() const { return true; };
+    virtual PassRefPtr<StringImpl> originalText() const;
+    virtual void computePreferredLogicalWidths(float leadWidth);
+    QuoteType m_type;
+    int m_depth;
+    RenderQuote* m_next;
+    RenderQuote* m_previous;
+    void placeQuote();
+};
+
+inline RenderQuote* toRenderQuote(RenderObject* object)
+{
+    ASSERT(!object || object->isQuote());
+    return static_cast<RenderQuote*>(object);
+}
+
+// This will catch anyone doing an unnecessary cast.
+void toRenderQuote(const RenderQuote*);
+
+} // namespace WebCore
+
+#endif // RenderQuote_h
index b7d7fa1..c9f6707 100644 (file)
@@ -79,6 +79,7 @@
 #include "RenderObjectChildList.cpp"
 #include "RenderPart.cpp"
 #include "RenderProgress.cpp"
+#include "RenderQuote.cpp"
 #include "RenderReplaced.cpp"
 #include "RenderReplica.cpp"
 #include "RenderRuby.cpp"
index d150f77..ab504fd 100644 (file)
@@ -51,6 +51,8 @@ bool ContentData::dataEquivalent(const ContentData& other) const
         return StyleImage::imagesEquivalent(image(), other.image());
     case CONTENT_COUNTER:
         return *counter() == *other.counter();
+    case CONTENT_QUOTE:
+        return quote() == other.quote();
     }
 
     ASSERT_NOT_REACHED();
@@ -71,6 +73,8 @@ void ContentData::deleteContent()
     case CONTENT_COUNTER:
         delete m_content.m_counter;
         break;
+    case CONTENT_QUOTE:
+        break;
     }
 
     m_type = CONTENT_NONE;
index 15f6912..cce3754 100644 (file)
@@ -51,6 +51,7 @@ public:
     bool isCounter() const { return m_type == CONTENT_COUNTER; }
     bool isImage() const { return m_type == CONTENT_OBJECT; }
     bool isNone() const { return m_type == CONTENT_NONE; }
+    bool isQuote() const { return m_type == CONTENT_QUOTE; }
     bool isText() const { return m_type == CONTENT_TEXT; }
 
     StyleContentType type() const { return m_type; }
@@ -93,6 +94,18 @@ public:
         m_content.m_counter = counter.leakPtr();
     }
 
+    QuoteType quote() const
+    {
+        ASSERT(isQuote());
+        return m_content.m_quote;
+    }
+    void setQuote(QuoteType type)
+    {
+        deleteContent();
+        m_type = CONTENT_QUOTE;
+        m_content.m_quote = type;
+    }
+
     ContentData* next() const { return m_next.get(); }
     void setNext(PassOwnPtr<ContentData> next) { m_next = next; }
 
@@ -104,6 +117,7 @@ private:
         StyleImage* m_image;
         StringImpl* m_text;
         CounterContent* m_counter;
+        QuoteType m_quote;
     } m_content;
     OwnPtr<ContentData> m_next;
 };
diff --git a/Source/WebCore/rendering/style/QuotesData.cpp b/Source/WebCore/rendering/style/QuotesData.cpp
new file mode 100644 (file)
index 0000000..829fe3f
--- /dev/null
@@ -0,0 +1,60 @@
+/**
+ * Copyright (C) 2011 Nokia Inc.  All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "QuotesData.h"
+
+namespace WebCore {
+
+QuotesData* QuotesData::create(int stringCount)
+{
+    char* tmp = new char[sizeof(QuotesData)+sizeof(String)*stringCount];
+    if (!tmp)
+        return 0;
+    new (tmp) QuotesData(stringCount);
+    for (int i = 0; i < stringCount; ++i)
+        new (tmp +sizeof(QuotesData) + sizeof(String)*i) String();
+    return reinterpret_cast<QuotesData*>(tmp);
+}
+
+bool QuotesData::operator==(const QuotesData& other) const
+{
+    if (this == &other)
+        return true;
+    if (!&other || !this)
+        return false;
+    if (length != other.length)
+        return false;
+    const String* myData = data();
+    const String* otherData = other.data();
+    for (int i = length-1; i >= 0; --i)
+        if (myData[i] != otherData[i])
+            return false;
+    return true;
+}
+
+QuotesData::~QuotesData()
+{
+    String* p = data();
+    for (int i = 0; i < length; ++i)
+        p[i].~String();
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/rendering/style/QuotesData.h b/Source/WebCore/rendering/style/QuotesData.h
new file mode 100644 (file)
index 0000000..df8a6dd
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2011 Nokia Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef QuotesData_h
+#define QuotesData_h
+
+#include <wtf/RefPtr.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+class QuotesData : public RefCounted<QuotesData> {
+public:
+    virtual ~QuotesData();
+    static QuotesData* create(int stringCount);
+    String* data() { return reinterpret_cast<String*>(this+1); }
+    const String* data() const { return reinterpret_cast<const String*>(this+1); }
+    int length;
+    bool operator==(const QuotesData&) const;
+    void operator delete(void* p) { delete[] static_cast<char*>(p); }
+private:
+    QuotesData(int stringCount) : length(stringCount) {}
+};
+
+}
+#endif // QuotesData_h
index b76a350..81da41c 100644 (file)
@@ -27,6 +27,7 @@
 #include "CSSPropertyNames.h"
 #include "CSSStyleSelector.h"
 #include "FontSelector.h"
+#include "QuotesData.h"
 #include "RenderArena.h"
 #include "RenderObject.h"
 #include "ScaleTransformOperation.h"
@@ -605,6 +606,13 @@ void RenderStyle::setCursorList(PassRefPtr<CursorList> other)
     rareInheritedData.access()->cursorData = other;
 }
 
+void RenderStyle::setQuotes(PassRefPtr<QuotesData> q)
+{
+    if (*rareInheritedData->quotes.get() == *q.get())
+        return;
+    rareInheritedData.access()->quotes = q;
+}
+
 void RenderStyle::clearCursorList()
 {
     if (rareInheritedData->cursorData)
@@ -672,6 +680,11 @@ void RenderStyle::setContent(PassOwnPtr<CounterContent> counter, bool add)
     prepareToSetContent(0, add)->setCounter(counter);
 }
 
+void RenderStyle::setContent(QuoteType quote, bool add)
+{
+    prepareToSetContent(0, add)->setQuote(quote);
+}
+
 void RenderStyle::applyTransform(TransformationMatrix& transform, const IntSize& borderBoxSize, ApplyTransformOrigin applyOrigin) const
 {
     // transform-origin brackets the transform with translate operations.
index 18a3c95..479949d 100644 (file)
@@ -1134,10 +1134,14 @@ public:
     void setContent(PassRefPtr<StringImpl>, bool add = false);
     void setContent(PassRefPtr<StyleImage>, bool add = false);
     void setContent(PassOwnPtr<CounterContent>, bool add = false);
+    void setContent(QuoteType, bool add = false);
 
     const CounterDirectiveMap* counterDirectives() const;
     CounterDirectiveMap& accessCounterDirectives();
 
+    QuotesData* quotes() const { return rareInheritedData->quotes.get(); }
+    void setQuotes(PassRefPtr<QuotesData>);
+
     const AtomicString& hyphenString() const;
 
     bool inheritedNotEqual(const RenderStyle*) const;
index 44cd3f5..3c62dbe 100644 (file)
@@ -297,7 +297,11 @@ enum EListStyleType {
 };
 
 enum StyleContentType {
-    CONTENT_NONE, CONTENT_OBJECT, CONTENT_TEXT, CONTENT_COUNTER
+    CONTENT_NONE, CONTENT_OBJECT, CONTENT_TEXT, CONTENT_COUNTER, CONTENT_QUOTE
+};
+
+enum QuoteType {
+    OPEN_QUOTE, CLOSE_QUOTE, NO_OPEN_QUOTE, NO_CLOSE_QUOTE
 };
 
 enum EBorderFit { BorderFitBorder, BorderFitLines };
index 25b539f..967fa00 100644 (file)
@@ -30,6 +30,7 @@
 #include "FillLayer.cpp"
 #include "KeyframeList.cpp"
 #include "NinePieceImage.cpp"
+#include "QuotesData.cpp"
 #include "RenderStyle.cpp"
 #include "SVGRenderStyle.cpp"
 #include "SVGRenderStyleDefs.cpp"
index 6b8e039..fb0d2e8 100644 (file)
@@ -23,6 +23,7 @@
 #include "StyleRareInheritedData.h"
 
 #include "CursorList.h"
+#include "QuotesData.h"
 #include "RenderStyle.h"
 #include "RenderStyleConstants.h"
 #include "ShadowData.h"
@@ -132,7 +133,8 @@ bool StyleRareInheritedData::operator==(const StyleRareInheritedData& o) const
         && textEmphasisPosition == o.textEmphasisPosition
         && hyphenationString == o.hyphenationString
         && hyphenationLocale == o.hyphenationLocale
-        && textEmphasisCustomMark == o.textEmphasisCustomMark;
+        && textEmphasisCustomMark == o.textEmphasisCustomMark
+        && *quotes == *o.quotes;
 }
 
 bool StyleRareInheritedData::shadowDataEquivalent(const StyleRareInheritedData& o) const
index d26ca83..fc56e30 100644 (file)
@@ -34,6 +34,7 @@
 namespace WebCore {
 
 class CursorList;
+class QuotesData;
 class ShadowData;
 
 // This struct is for rarely used inherited CSS3, CSS2, and WebKit-specific properties.
@@ -88,6 +89,7 @@ public:
     AtomicString hyphenationLocale;
 
     AtomicString textEmphasisCustomMark;
+    RefPtr<QuotesData> quotes;
 
 private:
     StyleRareInheritedData();