WebCore: Layout and rendering of CSS text-emphasis
authormitz@apple.com <mitz@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 17 Dec 2010 19:31:16 +0000 (19:31 +0000)
committermitz@apple.com <mitz@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 17 Dec 2010 19:31:16 +0000 (19:31 +0000)
Final part of <rdar://problem/7720300> Support the CSS3 text-emphasis property
https://bugs.webkit.org/show_bug.cgi?id=48539

Reviewed by Dave Hyatt.

Tests: fast/text/emphasis-vertical.html
       fast/text/emphasis.html

Emphasis marks behave like they are stuck just above the ascender (or just below the
descender). They occupy space in the leading and in padding, and only grow the line space
if they cannot fit.

* rendering/InlineFlowBox.cpp:
(WebCore::InlineFlowBox::placeBoxesInBlockDirection): Renamed the containsRuby parameter to
hasAnnotationsBefore, and added hasAnnotationsAfter. Line annotations include ruby and text emphasis
marks.
(WebCore::InlineFlowBox::addTextBoxVisualOverflow): Added overflow from emphasis marks.
(WebCore::InlineFlowBox::computeOverAnnotationAdjustment): Remaned computeBlockDirectionRubyAdjustment()
to this and added adjustment for text emphasis marks.
(WebCore::InlineFlowBox::computeUnderAnnotationAdjustment): Added. Similar to the previous function,
but for annotations under the glyphs. These can only be text emphasis marks.
* rendering/InlineFlowBox.h:
* rendering/InlineTextBox.cpp:
(WebCore::paintTextWithShadows): Paint emphasis marks.
(WebCore::InlineTextBox::paint): Ditto.
* rendering/RenderBlockLineLayout.cpp:
(WebCore::RenderBlock::layoutInlineChildren): Generalized the code that adjusts the last line for
ruby in flipped writing mode to also adjust the last line for emphasis marks under the line in non-
flipped writing mode.
* rendering/RenderObject.cpp:
(WebCore::RenderObject::selectionColor): Added this helper method which generalizes selectionForegroundColor().
(WebCore::RenderObject::selectionForegroundColor): Moved most of the code to selectionColor().
(WebCore::RenderObject::selectionEmphasisMarkColor): Added.
* rendering/RenderObject.h:
* rendering/RootInlineBox.cpp:
(WebCore::RootInlineBox::RootInlineBox): Updated initialization for new members.
(WebCore::RootInlineBox::alignBoxesInBlockDirection): Update new members.
(WebCore::RootInlineBox::beforeAnnotationsAdjustment): Renamed blockDirectionRubyAdjustment() to this
and extended to deal with annotations over and under the line and the previous line. If both lines have
annotations into the space between the lines, maintain separation so that the annotations do not overlap.
* rendering/RootInlineBox.h:
(WebCore::RootInlineBox::hasAnnotationsBefore): Added this accessor.
(WebCore::RootInlineBox::hasAnnotationsAfter): Ditto.

LayoutTests: <rdar://problem/7720300> Support the CSS3 text-emphasis property
https://bugs.webkit.org/show_bug.cgi?id=48539

Reviewed by Dave Hyatt.

* fast/text/emphasis-vertical.html: Added.
* fast/text/emphasis.html: Added.
* platform/mac/fast/text/emphasis-expected.checksum: Added.
* platform/mac/fast/text/emphasis-expected.png: Added.
* platform/mac/fast/text/emphasis-expected.txt: Added.
* platform/mac/fast/text/emphasis-vertical-expected.checksum: Added.
* platform/mac/fast/text/emphasis-vertical-expected.png: Added.
* platform/mac/fast/text/emphasis-vertical-expected.txt: Added.

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

18 files changed:
LayoutTests/ChangeLog
LayoutTests/fast/text/emphasis-vertical.html [new file with mode: 0644]
LayoutTests/fast/text/emphasis.html [new file with mode: 0644]
LayoutTests/platform/mac/fast/text/emphasis-expected.checksum [new file with mode: 0644]
LayoutTests/platform/mac/fast/text/emphasis-expected.png [new file with mode: 0644]
LayoutTests/platform/mac/fast/text/emphasis-expected.txt [new file with mode: 0644]
LayoutTests/platform/mac/fast/text/emphasis-vertical-expected.checksum [new file with mode: 0644]
LayoutTests/platform/mac/fast/text/emphasis-vertical-expected.png [new file with mode: 0644]
LayoutTests/platform/mac/fast/text/emphasis-vertical-expected.txt [new file with mode: 0644]
WebCore/ChangeLog
WebCore/rendering/InlineFlowBox.cpp
WebCore/rendering/InlineFlowBox.h
WebCore/rendering/InlineTextBox.cpp
WebCore/rendering/RenderBlockLineLayout.cpp
WebCore/rendering/RenderObject.cpp
WebCore/rendering/RenderObject.h
WebCore/rendering/RootInlineBox.cpp
WebCore/rendering/RootInlineBox.h

index 49a9dbe..dafc157 100644 (file)
@@ -1,3 +1,19 @@
+2010-12-17  Dan Bernstein  <mitz@apple.com>
+
+        Reviewed by Dave Hyatt.
+
+        <rdar://problem/7720300> Support the CSS3 text-emphasis property
+        https://bugs.webkit.org/show_bug.cgi?id=48539
+
+        * fast/text/emphasis-vertical.html: Added.
+        * fast/text/emphasis.html: Added.
+        * platform/mac/fast/text/emphasis-expected.checksum: Added.
+        * platform/mac/fast/text/emphasis-expected.png: Added.
+        * platform/mac/fast/text/emphasis-expected.txt: Added.
+        * platform/mac/fast/text/emphasis-vertical-expected.checksum: Added.
+        * platform/mac/fast/text/emphasis-vertical-expected.png: Added.
+        * platform/mac/fast/text/emphasis-vertical-expected.txt: Added.
+
 2010-12-17  Antonio Gomes  <agomes@rim.com>
 
         Unreviewed fix for Windows bots.
diff --git a/LayoutTests/fast/text/emphasis-vertical.html b/LayoutTests/fast/text/emphasis-vertical.html
new file mode 100644 (file)
index 0000000..1da6087
--- /dev/null
@@ -0,0 +1,32 @@
+<!doctype html>
+<meta http-equiv="content-type" content="text/html; charset=UTF-8">
+<style>
+    body {
+        -webkit-writing-mode: vertical-rl;
+        font-size: 18px;
+        font-family: "HiraMinPro-W3";
+    }
+
+    div {
+        border: solid;
+        height: 360px;
+        float: left;
+        margin: 8px;
+    }
+</style>
+
+<div>
+    せっかく見つけたすばらしい記事<span style="-webkit-text-emphasis: '@';">がどこにあったか忘れてしま</span>った経験はありますか<span style="-webkit-text-emphasis: '*'; -webkit-text-emphasis-position: under;">ならタイトルとアドレスだけでなく、</span>訪問したウェブページのコンテンツからも検索することができます。
+</div>
+
+<div>
+    せっか<span style="-webkit-text-emphasis: filled red;">く見つけたす</span><span style="-webkit-text-emphasis: open green;">ばらしい</span><span style="-webkit-text-emphasis: circle;">記事がど</span><span style="-webkit-text-emphasis: dot;">こにあっ</span><span style="-webkit-text-emphasis: double-circle;">たか忘れてし</span><span style="-webkit-text-emphasis: sesame;">まった経験</span><span style="-webkit-text-emphasis: triangle;">はありますか</span><span style="-webkit-text-emphasis: open dot;">ならタイトルと</span><span style="-webkit-text-emphasis: open double-circle;">アドレスだけでな</span><span style="-webkit-text-emphasis: open sesame;">く、訪問したウ</span><span style="-webkit-text-emphasis: open triangle;">ェブページのコンテ</span>ンツからも検索することができます。
+</div>
+
+<div style="-webkit-writing-mode: vertical-lr;">
+    せっか<span style="-webkit-text-emphasis: filled red;">く見つけたす</span><span style="-webkit-text-emphasis: open green;">ばらしい</span><span style="-webkit-text-emphasis: circle;">記事がど</span><span style="-webkit-text-emphasis: dot;">こにあっ</span><span style="-webkit-text-emphasis: double-circle;">たか忘れてし</span><span style="-webkit-text-emphasis: sesame;">まった経験</span><span style="-webkit-text-emphasis: triangle;">はありますか</span><span style="-webkit-text-emphasis: open dot;">ならタイトルと</span><span style="-webkit-text-emphasis: open double-circle;">アドレスだけでな</span><span style="-webkit-text-emphasis: open sesame;">く、訪問したウ</span><span style="-webkit-text-emphasis: open triangle;">ェブページのコンテ</span>ンツからも検索することができます。
+</div>
+
+<div style="line-height: 2;">
+    せっかく見つけたすばらしい記事<span style="-webkit-text-emphasis: filled;">がどこにあったか忘れてしま</span>った経験はありますか<span style="-webkit-text-emphasis: open; -webkit-text-emphasis-position: under;">ならタイトルとアドレスだけでなく、</span>訪問したウェブページのコンテンツからも検索することができます。
+</div>
diff --git a/LayoutTests/fast/text/emphasis.html b/LayoutTests/fast/text/emphasis.html
new file mode 100644 (file)
index 0000000..3386816
--- /dev/null
@@ -0,0 +1,90 @@
+<!doctype html>
+<meta http-equiv="content-type" content="text/html; charset=UTF-8">
+<style>
+    body {
+        font-size: 24px;
+    }
+
+    div {
+        border: solid;
+        width: 360px;
+        float: left;
+        margin: 8px;
+    }
+
+    span::selection {
+        background-color: brown;
+        color: yellow;
+    }
+
+    #special-span::selection {
+        -webkit-text-emphasis-color: lightgreen;
+    }
+</style>
+<div>
+    Lorem ipsum dolor sit amet,
+    <span style="-webkit-text-emphasis: '@ignored';">consectetur adipiscing</span>
+    elit. Aliquam
+    <span style="-webkit-text-emphasis: '*'; -webkit-text-emphasis-position: under;">odio sapien</span>,
+    lobortis eu iaculis vel, scelerisque nec dolor.
+</div>
+
+<div style="text-rendering: optimizelegibility;">
+    Lorem ipsum dolor sit amet,
+    <span style="-webkit-text-emphasis: '@';">consectetur adipiscing</span>
+    elit. Aliquam
+    <span style="-webkit-text-emphasis: '*does not matter'; -webkit-text-emphasis-position: under;">odio sa&#x0300;pien</span>,
+    lobortis eu iaculis vel, scelerisque nec dolor.
+</div>
+
+<div>
+    Lorem <span style="-webkit-text-emphasis: filled red;">ipsum</span>
+    <span style="-webkit-text-emphasis: open green;">dolor</span>
+    <span style="-webkit-text-emphasis: circle;">sit</span>
+    <span style="-webkit-text-emphasis: dot;">amet</span>,
+    <span style="-webkit-text-emphasis: double-circle;">consectetur</span>
+    <span style="-webkit-text-emphasis: sesame;">adipiscing</span>
+    <span style="-webkit-text-emphasis: triangle;">elit</span>.
+
+    <span style="-webkit-text-emphasis: open dot;">Aliquam</span>,
+    <span style="-webkit-text-emphasis: open double-circle;">odio</span>
+    <span style="-webkit-text-emphasis: open sesame;">sapien</span>,
+    <span style="-webkit-text-emphasis: open triangle;">lobortis</span>
+    eu iaculis vel, scelerisque nec dolor.
+</div>
+
+<div style="-webkit-writing-mode: horizontal-bt;">
+    Lorem <span style="-webkit-text-emphasis: filled red;">ipsum</span>
+    <span style="-webkit-text-emphasis: open green;">dolor</span>
+    <span style="-webkit-text-emphasis: circle;">sit</span>
+    <span style="-webkit-text-emphasis: dot;">amet</span>,
+    <span style="-webkit-text-emphasis: double-circle;">consectetur</span>
+    <span style="-webkit-text-emphasis: sesame;">adipiscing</span>
+    <span style="-webkit-text-emphasis: triangle;">elit</span>.
+
+    <span style="-webkit-text-emphasis: open dot;">Aliquam</span>,
+    <span style="-webkit-text-emphasis: open double-circle;">odio</span>
+    <span style="-webkit-text-emphasis: open sesame;">sapien</span>,
+    <span style="-webkit-text-emphasis: open triangle;">lobortis</span>
+    eu iaculis vel, scelerisque nec dolor.
+</div>
+
+<div style="line-height: 2;">
+    Lorem ipsum dolor sit amet,
+    <span style="-webkit-text-emphasis: '@';">consectetur adipiscing</span>
+    elit. Aliquam
+    <span style="-webkit-text-emphasis: '*'; -webkit-text-emphasis-position: under;">odio sapien</span>,
+    lobortis eu iaculis vel, scelerisque nec dolor.
+</div>
+
+<div>
+    Lorem ipsum dolor sit amet,
+    <span id="first-span" style="-webkit-text-emphasis: '@';">consectetur adipiscing</span>
+    elit. Aliquam
+    <span id="special-span" style="-webkit-text-emphasis: '*'; -webkit-text-emphasis-position: under;">odio sapien</span>,
+    lobortis eu iaculis vel, scelerisque nec dolor.
+</div>
+
+<script>
+    getSelection().setBaseAndExtent(document.getElementById("first-span").firstChild, 10, document.getElementById("special-span").firstChild, 7);
+</script>
diff --git a/LayoutTests/platform/mac/fast/text/emphasis-expected.checksum b/LayoutTests/platform/mac/fast/text/emphasis-expected.checksum
new file mode 100644 (file)
index 0000000..a1103bf
--- /dev/null
@@ -0,0 +1 @@
+ac0ea7816c98391f044f711d99596b0f
\ No newline at end of file
diff --git a/LayoutTests/platform/mac/fast/text/emphasis-expected.png b/LayoutTests/platform/mac/fast/text/emphasis-expected.png
new file mode 100644 (file)
index 0000000..aa3bcb2
Binary files /dev/null and b/LayoutTests/platform/mac/fast/text/emphasis-expected.png differ
diff --git a/LayoutTests/platform/mac/fast/text/emphasis-expected.txt b/LayoutTests/platform/mac/fast/text/emphasis-expected.txt
new file mode 100644 (file)
index 0000000..2c1e640
--- /dev/null
@@ -0,0 +1,191 @@
+layer at (0,0) size 800x600
+  RenderView at (0,0) size 800x600
+layer at (0,0) size 800x8
+  RenderBlock {HTML} at (0,0) size 800x8
+    RenderBody {BODY} at (8,8) size 784x0
+      RenderBlock (floating) {DIV} at (8,8) size 366x146 [border: (3px solid #000000)]
+        RenderText {#text} at (3,3) size 276x28
+          text run at (3,3) width 276: "Lorem ipsum dolor sit amet,"
+        RenderInline {SPAN} at (0,0) size 217x28
+          RenderText {#text} at (3,45) size 217x28
+            text run at (3,45) width 217: "consectetur adipiscing"
+        RenderText {#text} at (220,45) size 135x28
+          text run at (220,45) width 6: " "
+          text run at (226,45) width 129: "elit. Aliquam"
+        RenderInline {SPAN} at (0,0) size 111x28
+          RenderText {#text} at (3,73) size 111x28
+            text run at (3,73) width 111: "odio sapien"
+        RenderText {#text} at (114,73) size 338x70
+          text run at (114,73) width 12: ", "
+          text run at (126,73) width 215: "lobortis eu iaculis vel,"
+          text run at (3,115) width 211: "scelerisque nec dolor."
+      RenderBlock (floating) {DIV} at (390,8) size 366x146 [border: (3px solid #000000)]
+        RenderText {#text} at (3,3) size 276x28
+          text run at (3,3) width 276: "Lorem ipsum dolor sit amet,"
+        RenderInline {SPAN} at (0,0) size 217x28
+          RenderText {#text} at (3,45) size 217x28
+            text run at (3,45) width 217: "consectetur adipiscing"
+        RenderText {#text} at (220,45) size 135x28
+          text run at (220,45) width 6: " "
+          text run at (226,45) width 129: "elit. Aliquam"
+        RenderInline {SPAN} at (0,0) size 111x28
+          RenderText {#text} at (3,73) size 111x28
+            text run at (3,73) width 111: "odio sa\x{300}pien"
+        RenderText {#text} at (114,73) size 338x70
+          text run at (114,73) width 12: ", "
+          text run at (126,73) width 215: "lobortis eu iaculis vel,"
+          text run at (3,115) width 210: "scelerisque nec dolor."
+      RenderBlock (floating) {DIV} at (8,170) size 366x162 [border: (3px solid #000000)]
+        RenderText {#text} at (3,18) size 71x28
+          text run at (3,18) width 71: "Lorem "
+        RenderInline {SPAN} at (0,0) size 59x28
+          RenderText {#text} at (74,18) size 59x28
+            text run at (74,18) width 59: "ipsum"
+        RenderText {#text} at (133,18) size 6x28
+          text run at (133,18) width 6: " "
+        RenderInline {SPAN} at (0,0) size 51x28
+          RenderText {#text} at (139,18) size 51x28
+            text run at (139,18) width 51: "dolor"
+        RenderText {#text} at (190,18) size 6x28
+          text run at (190,18) width 6: " "
+        RenderInline {SPAN} at (0,0) size 23x28
+          RenderText {#text} at (196,18) size 23x28
+            text run at (196,18) width 23: "sit"
+        RenderText {#text} at (219,18) size 6x28
+          text run at (219,18) width 6: " "
+        RenderInline {SPAN} at (0,0) size 48x28
+          RenderText {#text} at (225,18) size 48x28
+            text run at (225,18) width 48: "amet"
+        RenderText {#text} at (273,18) size 6x28
+          text run at (273,18) width 6: ","
+        RenderInline {SPAN} at (0,0) size 111x28
+          RenderText {#text} at (3,61) size 111x28
+            text run at (3,61) width 111: "consectetur"
+        RenderText {#text} at (114,61) size 6x28
+          text run at (114,61) width 6: " "
+        RenderInline {SPAN} at (0,0) size 100x28
+          RenderText {#text} at (120,61) size 100x28
+            text run at (120,61) width 100: "adipiscing"
+        RenderText {#text} at (220,61) size 6x28
+          text run at (220,61) width 6: " "
+        RenderInline {SPAN} at (0,0) size 32x28
+          RenderText {#text} at (226,61) size 32x28
+            text run at (226,61) width 32: "elit"
+        RenderText {#text} at (258,61) size 12x28
+          text run at (258,61) width 12: ". "
+        RenderInline {SPAN} at (0,0) size 85x28
+          RenderText {#text} at (270,61) size 85x28
+            text run at (270,61) width 85: "Aliquam"
+        RenderText {#text} at (355,61) size 6x28
+          text run at (355,61) width 6: ","
+        RenderInline {SPAN} at (0,0) size 43x28
+          RenderText {#text} at (3,103) size 43x28
+            text run at (3,103) width 43: "odio"
+        RenderText {#text} at (46,103) size 6x28
+          text run at (46,103) width 6: " "
+        RenderInline {SPAN} at (0,0) size 62x28
+          RenderText {#text} at (52,103) size 62x28
+            text run at (52,103) width 62: "sapien"
+        RenderText {#text} at (114,103) size 12x28
+          text run at (114,103) width 12: ", "
+        RenderInline {SPAN} at (0,0) size 74x28
+          RenderText {#text} at (126,103) size 74x28
+            text run at (126,103) width 74: "lobortis"
+        RenderText {#text} at (200,103) size 338x56
+          text run at (200,103) width 6: " "
+          text run at (206,103) width 135: "eu iaculis vel,"
+          text run at (3,131) width 211: "scelerisque nec dolor."
+      RenderBlock (floating) {DIV} at (390,170) size 366x162 [border: (3px solid #000000)]
+        RenderText {#text} at (3,3) size 71x28
+          text run at (3,3) width 71: "Lorem "
+        RenderInline {SPAN} at (0,0) size 59x28
+          RenderText {#text} at (74,3) size 59x28
+            text run at (74,3) width 59: "ipsum"
+        RenderText {#text} at (133,3) size 6x28
+          text run at (133,3) width 6: " "
+        RenderInline {SPAN} at (0,0) size 51x28
+          RenderText {#text} at (139,3) size 51x28
+            text run at (139,3) width 51: "dolor"
+        RenderText {#text} at (190,3) size 6x28
+          text run at (190,3) width 6: " "
+        RenderInline {SPAN} at (0,0) size 23x28
+          RenderText {#text} at (196,3) size 23x28
+            text run at (196,3) width 23: "sit"
+        RenderText {#text} at (219,3) size 6x28
+          text run at (219,3) width 6: " "
+        RenderInline {SPAN} at (0,0) size 48x28
+          RenderText {#text} at (225,3) size 48x28
+            text run at (225,3) width 48: "amet"
+        RenderText {#text} at (273,3) size 6x28
+          text run at (273,3) width 6: ","
+        RenderInline {SPAN} at (0,0) size 111x28
+          RenderText {#text} at (3,46) size 111x28
+            text run at (3,46) width 111: "consectetur"
+        RenderText {#text} at (114,46) size 6x28
+          text run at (114,46) width 6: " "
+        RenderInline {SPAN} at (0,0) size 100x28
+          RenderText {#text} at (120,46) size 100x28
+            text run at (120,46) width 100: "adipiscing"
+        RenderText {#text} at (220,46) size 6x28
+          text run at (220,46) width 6: " "
+        RenderInline {SPAN} at (0,0) size 32x28
+          RenderText {#text} at (226,46) size 32x28
+            text run at (226,46) width 32: "elit"
+        RenderText {#text} at (258,46) size 12x28
+          text run at (258,46) width 12: ". "
+        RenderInline {SPAN} at (0,0) size 85x28
+          RenderText {#text} at (270,46) size 85x28
+            text run at (270,46) width 85: "Aliquam"
+        RenderText {#text} at (355,46) size 6x28
+          text run at (355,46) width 6: ","
+        RenderInline {SPAN} at (0,0) size 43x28
+          RenderText {#text} at (3,89) size 43x28
+            text run at (3,89) width 43: "odio"
+        RenderText {#text} at (46,89) size 6x28
+          text run at (46,89) width 6: " "
+        RenderInline {SPAN} at (0,0) size 62x28
+          RenderText {#text} at (52,89) size 62x28
+            text run at (52,89) width 62: "sapien"
+        RenderText {#text} at (114,89) size 12x28
+          text run at (114,89) width 12: ", "
+        RenderInline {SPAN} at (0,0) size 74x28
+          RenderText {#text} at (126,89) size 74x28
+            text run at (126,89) width 74: "lobortis"
+        RenderText {#text} at (200,89) size 338x70
+          text run at (200,89) width 6: " "
+          text run at (206,89) width 135: "eu iaculis vel,"
+          text run at (3,131) width 211: "scelerisque nec dolor."
+      RenderBlock (floating) {DIV} at (8,348) size 366x198 [border: (3px solid #000000)]
+        RenderText {#text} at (3,13) size 276x28
+          text run at (3,13) width 276: "Lorem ipsum dolor sit amet,"
+        RenderInline {SPAN} at (0,0) size 217x28
+          RenderText {#text} at (3,61) size 217x28
+            text run at (3,61) width 217: "consectetur adipiscing"
+        RenderText {#text} at (220,61) size 135x28
+          text run at (220,61) width 6: " "
+          text run at (226,61) width 129: "elit. Aliquam"
+        RenderInline {SPAN} at (0,0) size 111x28
+          RenderText {#text} at (3,109) size 111x28
+            text run at (3,109) width 111: "odio sapien"
+        RenderText {#text} at (114,109) size 338x76
+          text run at (114,109) width 12: ", "
+          text run at (126,109) width 215: "lobortis eu iaculis vel,"
+          text run at (3,157) width 211: "scelerisque nec dolor."
+      RenderBlock (floating) {DIV} at (390,348) size 366x146 [border: (3px solid #000000)]
+        RenderText {#text} at (3,3) size 276x28
+          text run at (3,3) width 276: "Lorem ipsum dolor sit amet,"
+        RenderInline {SPAN} at (0,0) size 217x28
+          RenderText {#text} at (3,45) size 217x28
+            text run at (3,45) width 217: "consectetur adipiscing"
+        RenderText {#text} at (220,45) size 135x28
+          text run at (220,45) width 6: " "
+          text run at (226,45) width 129: "elit. Aliquam"
+        RenderInline {SPAN} at (0,0) size 111x28
+          RenderText {#text} at (3,73) size 111x28
+            text run at (3,73) width 111: "odio sapien"
+        RenderText {#text} at (114,73) size 338x70
+          text run at (114,73) width 12: ", "
+          text run at (126,73) width 215: "lobortis eu iaculis vel,"
+          text run at (3,115) width 211: "scelerisque nec dolor."
+selection start: position 10 of child 0 {#text} of child 1 {SPAN} of child 10 {DIV} of body
+selection end:   position 7 of child 0 {#text} of child 3 {SPAN} of child 10 {DIV} of body
diff --git a/LayoutTests/platform/mac/fast/text/emphasis-vertical-expected.checksum b/LayoutTests/platform/mac/fast/text/emphasis-vertical-expected.checksum
new file mode 100644 (file)
index 0000000..53314cd
--- /dev/null
@@ -0,0 +1 @@
+e2ff18c7ece03dd6a7c05aaea8f908bf
\ No newline at end of file
diff --git a/LayoutTests/platform/mac/fast/text/emphasis-vertical-expected.png b/LayoutTests/platform/mac/fast/text/emphasis-vertical-expected.png
new file mode 100644 (file)
index 0000000..d4cc53c
Binary files /dev/null and b/LayoutTests/platform/mac/fast/text/emphasis-vertical-expected.png differ
diff --git a/LayoutTests/platform/mac/fast/text/emphasis-vertical-expected.txt b/LayoutTests/platform/mac/fast/text/emphasis-vertical-expected.txt
new file mode 100644 (file)
index 0000000..6dc6c0d
--- /dev/null
@@ -0,0 +1,123 @@
+layer at (0,0) size 800x600
+  RenderView at (0,0) size 800x600
+layer at (792,0) size 8x600
+  RenderBlock {HTML} at (0,0) size 8x600
+    RenderBody {BODY} at (8,8) size 0x584
+      RenderBlock (floating) {DIV} at (8,8) size 154x366 [border: (3px solid #000000)]
+        RenderText {#text} at (14,3) size 19x272
+          text run at (14,3) width 272: "\x{305B}\x{3063}\x{304B}\x{304F}\x{898B}\x{3064}\x{3051}\x{305F}\x{3059}\x{3070}\x{3089}\x{3057}\x{3044}\x{8A18}\x{4E8B}"
+        RenderInline {SPAN} at (0,0) size 49x345
+          RenderText {#text} at (14,275) size 49x345
+            text run at (14,275) width 73: "\x{304C}\x{3069}\x{3053}\x{306B}"
+            text run at (44,3) width 164: "\x{3042}\x{3063}\x{305F}\x{304B}\x{5FD8}\x{308C}\x{3066}\x{3057}\x{307E}"
+        RenderText {#text} at (44,167) size 46x328
+          text run at (44,167) width 164: "\x{3063}\x{305F}\x{7D4C}\x{9A13}\x{306F}\x{3042}\x{308A}\x{307E}\x{3059}"
+          text run at (71,3) width 19: "\x{304B}"
+        RenderInline {SPAN} at (0,0) size 19x322
+          RenderText {#text} at (71,22) size 19x322
+            text run at (71,22) width 322: "\x{306A}\x{3089}\x{30BF}\x{30A4}\x{30C8}\x{30EB}\x{3068}\x{30A2}\x{30C9}\x{30EC}\x{30B9}\x{3060}\x{3051}\x{3067}\x{306A}\x{304F}\x{3001}"
+        RenderText {#text} at (71,344) size 76x360
+          text run at (71,344) width 19: "\x{8A2A}"
+          text run at (101,3) width 345: "\x{554F}\x{3057}\x{305F}\x{30A6}\x{30A7}\x{30D6}\x{30DA}\x{30FC}\x{30B8}\x{306E}\x{30B3}\x{30F3}\x{30C6}\x{30F3}\x{30C4}\x{304B}\x{3089}\x{3082}\x{691C}"
+          text run at (128,3) width 200: "\x{7D22}\x{3059}\x{308B}\x{3053}\x{3068}\x{304C}\x{3067}\x{304D}\x{307E}\x{3059}\x{3002}"
+      RenderBlock (floating) {DIV} at (178,8) size 157x366 [border: (3px solid #000000)]
+        RenderText {#text} at (14,3) size 19x55
+          text run at (14,3) width 55: "\x{305B}\x{3063}\x{304B}"
+        RenderInline {SPAN} at (0,0) size 19x114
+          RenderText {#text} at (14,58) size 19x114
+            text run at (14,58) width 114: "\x{304F}\x{898B}\x{3064}\x{3051}\x{305F}\x{3059}"
+        RenderInline {SPAN} at (0,0) size 19x76
+          RenderText {#text} at (14,172) size 19x76
+            text run at (14,172) width 76: "\x{3070}\x{3089}\x{3057}\x{3044}"
+        RenderInline {SPAN} at (0,0) size 19x76
+          RenderText {#text} at (14,248) size 19x76
+            text run at (14,248) width 76: "\x{8A18}\x{4E8B}\x{304C}\x{3069}"
+        RenderInline {SPAN} at (0,0) size 49x358
+          RenderText {#text} at (14,324) size 49x358
+            text run at (14,324) width 37: "\x{3053}\x{306B}"
+            text run at (44,3) width 37: "\x{3042}\x{3063}"
+        RenderInline {SPAN} at (0,0) size 19x114
+          RenderText {#text} at (44,40) size 19x114
+            text run at (44,40) width 114: "\x{305F}\x{304B}\x{5FD8}\x{308C}\x{3066}\x{3057}"
+        RenderInline {SPAN} at (0,0) size 19x94
+          RenderText {#text} at (44,154) size 19x94
+            text run at (44,154) width 94: "\x{307E}\x{3063}\x{305F}\x{7D4C}\x{9A13}"
+        RenderInline {SPAN} at (0,0) size 49x336
+          RenderText {#text} at (44,248) size 49x336
+            text run at (44,248) width 91: "\x{306F}\x{3042}\x{308A}\x{307E}\x{3059}"
+            text run at (74,3) width 19: "\x{304B}"
+        RenderInline {SPAN} at (0,0) size 19x133
+          RenderText {#text} at (74,22) size 19x133
+            text run at (74,22) width 133: "\x{306A}\x{3089}\x{30BF}\x{30A4}\x{30C8}\x{30EB}\x{3068}"
+        RenderInline {SPAN} at (0,0) size 19x152
+          RenderText {#text} at (74,155) size 19x152
+            text run at (74,155) width 152: "\x{30A2}\x{30C9}\x{30EC}\x{30B9}\x{3060}\x{3051}\x{3067}\x{306A}"
+        RenderInline {SPAN} at (0,0) size 49x359
+          RenderText {#text} at (74,307) size 49x359
+            text run at (74,307) width 55: "\x{304F}\x{3001}\x{8A2A}"
+            text run at (104,3) width 73: "\x{554F}\x{3057}\x{305F}\x{30A6}"
+        RenderInline {SPAN} at (0,0) size 19x170
+          RenderText {#text} at (104,76) size 19x170
+            text run at (104,76) width 170: "\x{30A7}\x{30D6}\x{30DA}\x{30FC}\x{30B8}\x{306E}\x{30B3}\x{30F3}\x{30C6}"
+        RenderText {#text} at (104,246) size 46x352
+          text run at (104,246) width 109: "\x{30F3}\x{30C4}\x{304B}\x{3089}\x{3082}\x{691C}"
+          text run at (131,3) width 200: "\x{7D22}\x{3059}\x{308B}\x{3053}\x{3068}\x{304C}\x{3067}\x{304D}\x{307E}\x{3059}\x{3002}"
+      RenderBlock (floating) {DIV} at (351,8) size 153x366 [border: (3px solid #000000)]
+        RenderText {#text} at (7,3) size 19x55
+          text run at (7,3) width 55: "\x{305B}\x{3063}\x{304B}"
+        RenderInline {SPAN} at (0,0) size 19x114
+          RenderText {#text} at (7,58) size 19x114
+            text run at (7,58) width 114: "\x{304F}\x{898B}\x{3064}\x{3051}\x{305F}\x{3059}"
+        RenderInline {SPAN} at (0,0) size 19x76
+          RenderText {#text} at (7,172) size 19x76
+            text run at (7,172) width 76: "\x{3070}\x{3089}\x{3057}\x{3044}"
+        RenderInline {SPAN} at (0,0) size 19x76
+          RenderText {#text} at (7,248) size 19x76
+            text run at (7,248) width 76: "\x{8A18}\x{4E8B}\x{304C}\x{3069}"
+        RenderInline {SPAN} at (0,0) size 49x358
+          RenderText {#text} at (7,324) size 49x358
+            text run at (7,324) width 37: "\x{3053}\x{306B}"
+            text run at (37,3) width 37: "\x{3042}\x{3063}"
+        RenderInline {SPAN} at (0,0) size 19x114
+          RenderText {#text} at (37,40) size 19x114
+            text run at (37,40) width 114: "\x{305F}\x{304B}\x{5FD8}\x{308C}\x{3066}\x{3057}"
+        RenderInline {SPAN} at (0,0) size 19x94
+          RenderText {#text} at (37,154) size 19x94
+            text run at (37,154) width 94: "\x{307E}\x{3063}\x{305F}\x{7D4C}\x{9A13}"
+        RenderInline {SPAN} at (0,0) size 49x336
+          RenderText {#text} at (37,248) size 49x336
+            text run at (37,248) width 91: "\x{306F}\x{3042}\x{308A}\x{307E}\x{3059}"
+            text run at (67,3) width 19: "\x{304B}"
+        RenderInline {SPAN} at (0,0) size 19x133
+          RenderText {#text} at (67,22) size 19x133
+            text run at (67,22) width 133: "\x{306A}\x{3089}\x{30BF}\x{30A4}\x{30C8}\x{30EB}\x{3068}"
+        RenderInline {SPAN} at (0,0) size 19x152
+          RenderText {#text} at (67,155) size 19x152
+            text run at (67,155) width 152: "\x{30A2}\x{30C9}\x{30EC}\x{30B9}\x{3060}\x{3051}\x{3067}\x{306A}"
+        RenderInline {SPAN} at (0,0) size 49x359
+          RenderText {#text} at (67,307) size 49x359
+            text run at (67,307) width 55: "\x{304F}\x{3001}\x{8A2A}"
+            text run at (97,3) width 73: "\x{554F}\x{3057}\x{305F}\x{30A6}"
+        RenderInline {SPAN} at (0,0) size 19x170
+          RenderText {#text} at (97,76) size 19x170
+            text run at (97,76) width 170: "\x{30A7}\x{30D6}\x{30DA}\x{30FC}\x{30B8}\x{306E}\x{30B3}\x{30F3}\x{30C6}"
+        RenderText {#text} at (97,246) size 49x352
+          text run at (97,246) width 109: "\x{30F3}\x{30C4}\x{304B}\x{3089}\x{3082}\x{691C}"
+          text run at (127,3) width 200: "\x{7D22}\x{3059}\x{308B}\x{3053}\x{3068}\x{304C}\x{3067}\x{304D}\x{307E}\x{3059}\x{3002}"
+      RenderBlock (floating) {DIV} at (520,8) size 189x366 [border: (3px solid #000000)]
+        RenderText {#text} at (14,3) size 19x272
+          text run at (14,3) width 272: "\x{305B}\x{3063}\x{304B}\x{304F}\x{898B}\x{3064}\x{3051}\x{305F}\x{3059}\x{3070}\x{3089}\x{3057}\x{3044}\x{8A18}\x{4E8B}"
+        RenderInline {SPAN} at (0,0) size 55x345
+          RenderText {#text} at (14,275) size 55x345
+            text run at (14,275) width 73: "\x{304C}\x{3069}\x{3053}\x{306B}"
+            text run at (50,3) width 164: "\x{3042}\x{3063}\x{305F}\x{304B}\x{5FD8}\x{308C}\x{3066}\x{3057}\x{307E}"
+        RenderText {#text} at (50,167) size 55x328
+          text run at (50,167) width 164: "\x{3063}\x{305F}\x{7D4C}\x{9A13}\x{306F}\x{3042}\x{308A}\x{307E}\x{3059}"
+          text run at (86,3) width 19: "\x{304B}"
+        RenderInline {SPAN} at (0,0) size 19x322
+          RenderText {#text} at (86,22) size 19x322
+            text run at (86,22) width 322: "\x{306A}\x{3089}\x{30BF}\x{30A4}\x{30C8}\x{30EB}\x{3068}\x{30A2}\x{30C9}\x{30EC}\x{30B9}\x{3060}\x{3051}\x{3067}\x{306A}\x{304F}\x{3001}"
+        RenderText {#text} at (86,344) size 91x360
+          text run at (86,344) width 19: "\x{8A2A}"
+          text run at (122,3) width 345: "\x{554F}\x{3057}\x{305F}\x{30A6}\x{30A7}\x{30D6}\x{30DA}\x{30FC}\x{30B8}\x{306E}\x{30B3}\x{30F3}\x{30C6}\x{30F3}\x{30C4}\x{304B}\x{3089}\x{3082}\x{691C}"
+          text run at (158,3) width 200: "\x{7D22}\x{3059}\x{308B}\x{3053}\x{3068}\x{304C}\x{3067}\x{304D}\x{307E}\x{3059}\x{3002}"
index 3bdfe9f..70f021c 100644 (file)
@@ -1,3 +1,50 @@
+2010-12-17  Dan Bernstein  <mitz@apple.com>
+
+        Reviewed by Dave Hyatt.
+
+        Layout and rendering of CSS text-emphasis
+        Final part of <rdar://problem/7720300> Support the CSS3 text-emphasis property
+        https://bugs.webkit.org/show_bug.cgi?id=48539
+
+        Tests: fast/text/emphasis-vertical.html
+               fast/text/emphasis.html
+
+        Emphasis marks behave like they are stuck just above the ascender (or just below the
+        descender). They occupy space in the leading and in padding, and only grow the line space
+        if they cannot fit.
+
+        * rendering/InlineFlowBox.cpp:
+        (WebCore::InlineFlowBox::placeBoxesInBlockDirection): Renamed the containsRuby parameter to
+        hasAnnotationsBefore, and added hasAnnotationsAfter. Line annotations include ruby and text emphasis
+        marks.
+        (WebCore::InlineFlowBox::addTextBoxVisualOverflow): Added overflow from emphasis marks.
+        (WebCore::InlineFlowBox::computeOverAnnotationAdjustment): Remaned computeBlockDirectionRubyAdjustment()
+        to this and added adjustment for text emphasis marks.
+        (WebCore::InlineFlowBox::computeUnderAnnotationAdjustment): Added. Similar to the previous function,
+        but for annotations under the glyphs. These can only be text emphasis marks.
+        * rendering/InlineFlowBox.h:
+        * rendering/InlineTextBox.cpp:
+        (WebCore::paintTextWithShadows): Paint emphasis marks.
+        (WebCore::InlineTextBox::paint): Ditto.
+        * rendering/RenderBlockLineLayout.cpp:
+        (WebCore::RenderBlock::layoutInlineChildren): Generalized the code that adjusts the last line for
+        ruby in flipped writing mode to also adjust the last line for emphasis marks under the line in non-
+        flipped writing mode.
+        * rendering/RenderObject.cpp:
+        (WebCore::RenderObject::selectionColor): Added this helper method which generalizes selectionForegroundColor().
+        (WebCore::RenderObject::selectionForegroundColor): Moved most of the code to selectionColor().
+        (WebCore::RenderObject::selectionEmphasisMarkColor): Added.
+        * rendering/RenderObject.h:
+        * rendering/RootInlineBox.cpp:
+        (WebCore::RootInlineBox::RootInlineBox): Updated initialization for new members.
+        (WebCore::RootInlineBox::alignBoxesInBlockDirection): Update new members.
+        (WebCore::RootInlineBox::beforeAnnotationsAdjustment): Renamed blockDirectionRubyAdjustment() to this
+        and extended to deal with annotations over and under the line and the previous line. If both lines have
+        annotations into the space between the lines, maintain separation so that the annotations do not overlap.
+        * rendering/RootInlineBox.h:
+        (WebCore::RootInlineBox::hasAnnotationsBefore): Added this accessor.
+        (WebCore::RootInlineBox::hasAnnotationsAfter): Ditto.
+
 2010-12-17  W. James MacLean  <wjmaclean@chromium.org>
 
         Reviewed by James Robinson.
index 70b8615..f140ae2 100644 (file)
@@ -572,7 +572,7 @@ void InlineFlowBox::computeLogicalBoxHeights(int& maxPositionTop, int& maxPositi
 }
 
 void InlineFlowBox::placeBoxesInBlockDirection(int top, int maxHeight, int maxAscent, bool strictMode, int& lineTop, int& lineBottom, bool& setLineTop,
-                                               int& lineTopIncludingMargins, int& lineBottomIncludingMargins, bool& containsRuby, FontBaseline baselineType)
+                                               int& lineTopIncludingMargins, int& lineBottomIncludingMargins, bool& hasAnnotationsBefore, bool& hasAnnotationsAfter, FontBaseline baselineType)
 {
     if (isRootInlineBox())
         setLogicalTop(top + maxAscent - baselinePosition(baselineType)); // Place our root box.
@@ -586,7 +586,7 @@ void InlineFlowBox::placeBoxesInBlockDirection(int top, int maxHeight, int maxAs
         bool isInlineFlow = curr->isInlineFlowBox();
         if (isInlineFlow)
             static_cast<InlineFlowBox*>(curr)->placeBoxesInBlockDirection(top, maxHeight, maxAscent, strictMode, lineTop, lineBottom, setLineTop,
-                                                                          lineTopIncludingMargins, lineBottomIncludingMargins, containsRuby, baselineType);
+                                                                          lineTopIncludingMargins, lineBottomIncludingMargins, hasAnnotationsBefore, hasAnnotationsAfter, baselineType);
 
         bool childAffectsTopBottomPos = true;
         if (curr->logicalTop() == PositionTop)
@@ -630,7 +630,11 @@ void InlineFlowBox::placeBoxesInBlockDirection(int top, int maxHeight, int maxAs
                 // Treat the leading on the first and last lines of ruby runs as not being part of the overall lineTop/lineBottom.
                 // Really this is a workaround hack for the fact that ruby should have been done as line layout and not done using
                 // inline-block.
-                containsRuby = true;
+                if (!renderer()->style()->isFlippedLinesWritingMode())
+                    hasAnnotationsBefore = true;
+                else
+                    hasAnnotationsAfter = true;
+
                 RenderRubyRun* rubyRun = static_cast<RenderRubyRun*>(curr->renderer());
                 if (RenderRubyBase* rubyBase = rubyRun->rubyBase()) {
                     int bottomRubyBaseLeading = (curr->logicalHeight() - rubyBase->logicalBottom()) + rubyBase->logicalHeight() - (rubyBase->lastRootBox() ? rubyBase->lastRootBox()->lineBottom() : 0);
@@ -639,7 +643,14 @@ void InlineFlowBox::placeBoxesInBlockDirection(int top, int maxHeight, int maxAs
                     boxHeight -= (topRubyBaseLeading + bottomRubyBaseLeading);
                 }
             }
-            
+            if (curr->isInlineTextBox() && curr->renderer()->style(m_firstLine)->textEmphasisMark() != TextEmphasisMarkNone) {
+                bool emphasisMarkIsOver = curr->renderer()->style(m_firstLine)->textEmphasisPosition() == TextEmphasisPositionOver;
+                if (emphasisMarkIsOver != curr->renderer()->style(m_firstLine)->isFlippedLinesWritingMode())
+                    hasAnnotationsBefore = true;
+                else
+                    hasAnnotationsAfter = true;
+            }
+
             if (!setLineTop) {
                 setLineTop = true;
                 lineTop = newLogicalTop;
@@ -716,38 +727,47 @@ void InlineFlowBox::addBoxShadowVisualOverflow(IntRect& logicalVisualOverflow)
 
 void InlineFlowBox::addTextBoxVisualOverflow(const InlineTextBox* textBox, GlyphOverflowAndFallbackFontsMap& textBoxDataMap, IntRect& logicalVisualOverflow)
 {
-    int strokeOverflow = static_cast<int>(ceilf(renderer()->style()->textStrokeWidth() / 2.0f));
+    RenderStyle* style = renderer()->style(m_firstLine);
+    int strokeOverflow = static_cast<int>(ceilf(style->textStrokeWidth() / 2.0f));
 
     GlyphOverflowAndFallbackFontsMap::iterator it = textBoxDataMap.find(textBox);
     GlyphOverflow* glyphOverflow = it == textBoxDataMap.end() ? 0 : &it->second.second;
 
-    bool isFlippedLine = renderer()->style(m_firstLine)->isFlippedLinesWritingMode();
+    bool isFlippedLine = style->isFlippedLinesWritingMode();
 
     int topGlyphEdge = glyphOverflow ? (isFlippedLine ? glyphOverflow->bottom : glyphOverflow->top) : 0;
     int bottomGlyphEdge = glyphOverflow ? (isFlippedLine ? glyphOverflow->top : glyphOverflow->bottom) : 0;
     int leftGlyphEdge = glyphOverflow ? glyphOverflow->left : 0;
     int rightGlyphEdge = glyphOverflow ? glyphOverflow->right : 0;
-    
+
     int topGlyphOverflow = -strokeOverflow - topGlyphEdge;
     int bottomGlyphOverflow = strokeOverflow + bottomGlyphEdge;
     int leftGlyphOverflow = -strokeOverflow - leftGlyphEdge;
     int rightGlyphOverflow = strokeOverflow + rightGlyphEdge;
 
+    if (style->textEmphasisMark() != TextEmphasisMarkNone) {
+        int emphasisMarkHeight = style->font().emphasisMarkHeight(style->textEmphasisMarkString());
+        if (style->textEmphasisPosition() == TextEmphasisPositionOver)
+            topGlyphOverflow = min(topGlyphOverflow, -emphasisMarkHeight);
+        else
+            bottomGlyphOverflow = max(bottomGlyphOverflow, emphasisMarkHeight);
+    }
+
     // If letter-spacing is negative, we should factor that into right layout overflow. (Even in RTL, letter-spacing is
     // applied to the right, so this is not an issue with left overflow.
-    int letterSpacing = min(0, (int)renderer()->style(m_firstLine)->font().letterSpacing());
+    int letterSpacing = min(0, (int)style->font().letterSpacing());
     rightGlyphOverflow -= letterSpacing;
 
     int textShadowLogicalTop;
     int textShadowLogicalBottom;
-    renderer()->style(m_firstLine)->getTextShadowBlockDirectionExtent(textShadowLogicalTop, textShadowLogicalBottom);
+    style->getTextShadowBlockDirectionExtent(textShadowLogicalTop, textShadowLogicalBottom);
     
     int childOverflowLogicalTop = min(textShadowLogicalTop + topGlyphOverflow, topGlyphOverflow);
     int childOverflowLogicalBottom = max(textShadowLogicalBottom + bottomGlyphOverflow, bottomGlyphOverflow);
    
     int textShadowLogicalLeft;
     int textShadowLogicalRight;
-    renderer()->style(m_firstLine)->getTextShadowInlineDirectionExtent(textShadowLogicalLeft, textShadowLogicalRight);
+    style->getTextShadowInlineDirectionExtent(textShadowLogicalLeft, textShadowLogicalRight);
    
     int childOverflowLogicalLeft = min(textShadowLogicalLeft + leftGlyphOverflow, leftGlyphOverflow);
     int childOverflowLogicalRight = max(textShadowLogicalRight + rightGlyphOverflow, rightGlyphOverflow);
@@ -1239,7 +1259,7 @@ void InlineFlowBox::clearTruncation()
         box->clearTruncation();
 }
 
-int InlineFlowBox::computeBlockDirectionRubyAdjustment(int allowedPosition) const
+int InlineFlowBox::computeOverAnnotationAdjustment(int allowedPosition) const
 {
     int result = 0;
     for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) {
@@ -1247,7 +1267,7 @@ int InlineFlowBox::computeBlockDirectionRubyAdjustment(int allowedPosition) cons
             continue; // Positioned placeholders don't affect calculations.
         
         if (curr->isInlineFlowBox())
-            result = max(result, static_cast<InlineFlowBox*>(curr)->computeBlockDirectionRubyAdjustment(allowedPosition));
+            result = max(result, static_cast<InlineFlowBox*>(curr)->computeOverAnnotationAdjustment(allowedPosition));
         
         if (curr->renderer()->isReplaced() && curr->renderer()->isRubyRun()) {
             RenderRubyRun* rubyRun = static_cast<RenderRubyRun*>(curr->renderer());
@@ -1269,6 +1289,45 @@ int InlineFlowBox::computeBlockDirectionRubyAdjustment(int allowedPosition) cons
                 result = max(result, bottomOfLastRubyTextLine - allowedPosition);
             }
         }
+
+        if (curr->isInlineTextBox()) {
+            RenderStyle* style = curr->renderer()->style(m_firstLine);
+            if (style->textEmphasisMark() != TextEmphasisMarkNone && style->textEmphasisPosition() == TextEmphasisPositionOver) {
+                if (!style->isFlippedLinesWritingMode()) {
+                    int topOfEmphasisMark = curr->logicalTop() - style->font().emphasisMarkHeight(style->textEmphasisMarkString());
+                    result = max(result, allowedPosition - topOfEmphasisMark);
+                } else {
+                    int bottomOfEmphasisMark = curr->logicalBottom() + style->font().emphasisMarkHeight(style->textEmphasisMarkString());
+                    result = max(result, bottomOfEmphasisMark - allowedPosition);
+                }
+            }
+        }
+    }
+    return result;
+}
+
+int InlineFlowBox::computeUnderAnnotationAdjustment(int allowedPosition) const
+{
+    int result = 0;
+    for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) {
+        if (curr->renderer()->isPositioned())
+            continue; // Positioned placeholders don't affect calculations.
+
+        if (curr->isInlineFlowBox())
+            result = max(result, static_cast<InlineFlowBox*>(curr)->computeUnderAnnotationAdjustment(allowedPosition));
+
+        if (curr->isInlineTextBox()) {
+            RenderStyle* style = curr->renderer()->style(m_firstLine);
+            if (style->textEmphasisMark() != TextEmphasisMarkNone && style->textEmphasisPosition() == TextEmphasisPositionUnder) {
+                if (!style->isFlippedLinesWritingMode()) {
+                    int bottomOfEmphasisMark = curr->logicalBottom() + style->font().emphasisMarkHeight(style->textEmphasisMarkString());
+                    result = max(result, bottomOfEmphasisMark - allowedPosition);
+                } else {
+                    int topOfEmphasisMark = curr->logicalTop() - style->font().emphasisMarkHeight(style->textEmphasisMarkString());
+                    result = max(result, allowedPosition - topOfEmphasisMark);
+                }
+            }
+        }
     }
     return result;
 }
index 19f9d16..63263fd 100644 (file)
@@ -161,11 +161,13 @@ public:
     void adjustMaxAscentAndDescent(int& maxAscent, int& maxDescent,
                                    int maxPositionTop, int maxPositionBottom);
     void placeBoxesInBlockDirection(int logicalTop, int maxHeight, int maxAscent, bool strictMode, int& lineTop, int& lineBottom, bool& setLineTop,
-                                    int& lineTopIncludingMargins, int& lineBottomIncludingMargins, bool& containsRuby, FontBaseline);
+                                    int& lineTopIncludingMargins, int& lineBottomIncludingMargins, bool& hasAnnotationsBefore, bool& hasAnnotationsAfter, FontBaseline);
     void flipLinesInBlockDirection(int lineTop, int lineBottom);
     bool requiresIdeographicBaseline(const GlyphOverflowAndFallbackFontsMap&) const;
-    int computeBlockDirectionRubyAdjustment(int allowedPosition) const;
-    
+
+    int computeOverAnnotationAdjustment(int allowedPosition) const;
+    int computeUnderAnnotationAdjustment(int allowedPosition) const;
+
     void computeOverflow(int lineTop, int lineBottom, bool strictMode, GlyphOverflowAndFallbackFontsMap&);
     
     void removeChild(InlineBox* child);
index b77ee9e..5196854 100644 (file)
@@ -352,7 +352,7 @@ FloatSize InlineTextBox::applyShadowToGraphicsContext(GraphicsContext* context,
     return extraOffset;
 }
 
-static void paintTextWithShadows(GraphicsContext* context, const Font& font, const TextRun& textRun, int startOffset, int endOffset, int truncationPoint, const IntPoint& textOrigin,
+static void paintTextWithShadows(GraphicsContext* context, const Font& font, const TextRun& textRun, const AtomicString& emphasisMark, int emphasisMarkOffset, int startOffset, int endOffset, int truncationPoint, const IntPoint& textOrigin,
                                  const IntRect& boxRect, const ShadowData* shadow, bool stroked, bool horizontal)
 {
     Color fillColor = context->fillColor();
@@ -368,13 +368,23 @@ static void paintTextWithShadows(GraphicsContext* context, const Font& font, con
         else if (!opaque)
             context->setFillColor(fillColor, fillColorSpace);
 
-        if (startOffset <= endOffset)
-            context->drawText(font, textRun, textOrigin + extraOffset, startOffset, endOffset);
-        else {
-            if (endOffset > 0)
-                context->drawText(font, textRun, textOrigin + extraOffset,  0, endOffset);
-            if (startOffset < truncationPoint)
-                context->drawText(font, textRun, textOrigin + extraOffset, startOffset, truncationPoint);
+        if (startOffset <= endOffset) {
+            if (emphasisMark.isEmpty())
+                context->drawText(font, textRun, textOrigin + extraOffset, startOffset, endOffset);
+            else
+                context->drawEmphasisMarks(font, textRun, emphasisMark, textOrigin + extraOffset + IntSize(0, emphasisMarkOffset), startOffset, endOffset);
+        } else {
+            if (endOffset > 0) {
+                if (emphasisMark.isEmpty())
+                    context->drawText(font, textRun, textOrigin + extraOffset,  0, endOffset);
+                else
+                    context->drawEmphasisMarks(font, textRun, emphasisMark, textOrigin + extraOffset + IntSize(0, emphasisMarkOffset),  0, endOffset);
+            } if (startOffset < truncationPoint) {
+                if (emphasisMark.isEmpty())
+                    context->drawText(font, textRun, textOrigin + extraOffset, startOffset, truncationPoint);
+                else
+                    context->drawEmphasisMarks(font, textRun, emphasisMark, textOrigin + extraOffset + IntSize(0, emphasisMarkOffset),  startOffset, truncationPoint);
+            }
         }
 
         if (!shadow)
@@ -488,12 +498,14 @@ void InlineTextBox::paint(PaintInfo& paintInfo, int tx, int ty)
     // 2. Now paint the foreground, including text and decorations like underline/overline (in quirks mode only).
     Color textFillColor;
     Color textStrokeColor;
+    Color emphasisMarkColor;
     float textStrokeWidth = styleToUse->textStrokeWidth();
     const ShadowData* textShadow = paintInfo.forceBlackText ? 0 : styleToUse->textShadow();
 
     if (paintInfo.forceBlackText) {
         textFillColor = Color::black;
         textStrokeColor = Color::black;
+        emphasisMarkColor = Color::black;
     } else {
         textFillColor = styleToUse->visitedDependentColor(CSSPropertyWebkitTextFillColor);
         
@@ -506,6 +518,12 @@ void InlineTextBox::paint(PaintInfo& paintInfo, int tx, int ty)
         // Make the text stroke color legible against a white background
         if (styleToUse->forceBackgroundsToWhite())
             textStrokeColor = correctedTextColor(textStrokeColor, Color::white);
+
+        emphasisMarkColor = styleToUse->visitedDependentColor(CSSPropertyWebkitTextEmphasisColor);
+        
+        // Make the text stroke color legible against a white background
+        if (styleToUse->forceBackgroundsToWhite())
+            emphasisMarkColor = correctedTextColor(emphasisMarkColor, Color::white);
     }
 
     bool paintSelectedTextOnly = (paintInfo.phase == PaintPhaseSelection);
@@ -513,6 +531,7 @@ void InlineTextBox::paint(PaintInfo& paintInfo, int tx, int ty)
 
     Color selectionFillColor = textFillColor;
     Color selectionStrokeColor = textStrokeColor;
+    Color selectionEmphasisMarkColor = emphasisMarkColor;
     float selectionStrokeWidth = textStrokeWidth;
     const ShadowData* selectionShadow = textShadow;
     if (haveSelection) {
@@ -524,6 +543,13 @@ void InlineTextBox::paint(PaintInfo& paintInfo, int tx, int ty)
             selectionFillColor = foreground;
         }
 
+        Color emphasisMarkForeground = paintInfo.forceBlackText ? Color::black : renderer()->selectionEmphasisMarkColor();
+        if (emphasisMarkForeground.isValid() && emphasisMarkForeground != selectionEmphasisMarkColor) {
+            if (!paintSelectedTextOnly)
+                paintSelectedTextSeparately = true;
+            selectionEmphasisMarkColor = emphasisMarkForeground;
+        }
+
         if (RenderStyle* pseudoStyle = renderer()->getCachedPseudoStyle(SELECTION)) {
             const ShadowData* shadow = paintInfo.forceBlackText ? 0 : pseudoStyle->textShadow();
             if (shadow != selectionShadow) {
@@ -567,6 +593,15 @@ void InlineTextBox::paint(PaintInfo& paintInfo, int tx, int ty)
         length = m_truncation;
     }
 
+    int emphasisMarkOffset = 0;
+    const AtomicString& emphasisMark = styleToUse->textEmphasisMarkString();
+    if (!emphasisMark.isEmpty()) {
+        if (styleToUse->textEmphasisPosition() == TextEmphasisPositionOver)
+            emphasisMarkOffset = -font.ascent() - font.emphasisMarkDescent(emphasisMark);
+        else
+            emphasisMarkOffset = font.descent() + font.emphasisMarkAscent(emphasisMark);
+    }
+
     if (!paintSelectedTextOnly) {
         // For stroked painting, we have to change the text drawing mode.  It's probably dangerous to leave that mutated as a side
         // effect, so only when we know we're stroking, do a save/restore.
@@ -576,9 +611,18 @@ void InlineTextBox::paint(PaintInfo& paintInfo, int tx, int ty)
         updateGraphicsContext(context, textFillColor, textStrokeColor, textStrokeWidth, styleToUse->colorSpace());
         if (!paintSelectedTextSeparately || ePos <= sPos) {
             // FIXME: Truncate right-to-left text correctly.
-            paintTextWithShadows(context, font, textRun, 0, length, length, textOrigin, boxRect, textShadow, textStrokeWidth > 0, isHorizontal());
+            paintTextWithShadows(context, font, textRun, nullAtom, 0, 0, length, length, textOrigin, boxRect, textShadow, textStrokeWidth > 0, isHorizontal());
         } else
-            paintTextWithShadows(context, font, textRun, ePos, sPos, length, textOrigin, boxRect, textShadow, textStrokeWidth > 0, isHorizontal());
+            paintTextWithShadows(context, font, textRun, nullAtom, 0, ePos, sPos, length, textOrigin, boxRect, textShadow, textStrokeWidth > 0, isHorizontal());
+
+        if (!emphasisMark.isEmpty()) {
+            updateGraphicsContext(context, emphasisMarkColor, textStrokeColor, textStrokeWidth, styleToUse->colorSpace());
+            if (!paintSelectedTextSeparately || ePos <= sPos) {
+                // FIXME: Truncate right-to-left text correctly.
+                paintTextWithShadows(context, font, textRun, emphasisMark, emphasisMarkOffset, 0, length, length, textOrigin, boxRect, textShadow, textStrokeWidth > 0, isHorizontal());
+            } else
+                paintTextWithShadows(context, font, textRun, emphasisMark, emphasisMarkOffset, ePos, sPos, length, textOrigin, boxRect, textShadow, textStrokeWidth > 0, isHorizontal());
+        }
 
         if (textStrokeWidth > 0)
             context->restore();
@@ -590,8 +634,11 @@ void InlineTextBox::paint(PaintInfo& paintInfo, int tx, int ty)
             context->save();
 
         updateGraphicsContext(context, selectionFillColor, selectionStrokeColor, selectionStrokeWidth, styleToUse->colorSpace());
-        paintTextWithShadows(context, font, textRun, sPos, ePos, length, textOrigin, boxRect, selectionShadow, selectionStrokeWidth > 0, isHorizontal());
-
+        paintTextWithShadows(context, font, textRun, nullAtom, 0, sPos, ePos, length, textOrigin, boxRect, selectionShadow, selectionStrokeWidth > 0, isHorizontal());
+        if (!emphasisMark.isEmpty()) {
+            updateGraphicsContext(context, selectionEmphasisMarkColor, textStrokeColor, textStrokeWidth, styleToUse->colorSpace());
+            paintTextWithShadows(context, font, textRun, emphasisMark, emphasisMarkOffset, sPos, ePos, length, textOrigin, boxRect, selectionShadow, selectionStrokeWidth > 0, isHorizontal());
+        }
         if (selectionStrokeWidth > 0)
             context->restore();
     }
index f46da11..8960dea 100644 (file)
@@ -913,16 +913,18 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintLogica
         }
     }
 
-    // Expand the last line to accommodate Ruby in flipped lines writing modes (the Ruby is on
-    // the after side in this case).
-    int lastLineRubyAdjustment = 0;
-    if (lastRootBox() && style()->isFlippedLinesWritingMode()) {
+    // Expand the last line to accommodate Ruby and emphasis marks.
+    int lastLineAnnotationsAdjustment = 0;
+    if (lastRootBox()) {
         int lowestAllowedPosition = max(lastRootBox()->lineBottom(), logicalHeight() + paddingAfter());
-        lastLineRubyAdjustment = lastRootBox()->computeBlockDirectionRubyAdjustment(lowestAllowedPosition);
+        if (!style()->isFlippedLinesWritingMode())
+            lastLineAnnotationsAdjustment = lastRootBox()->computeUnderAnnotationAdjustment(lowestAllowedPosition);
+        else
+            lastLineAnnotationsAdjustment = lastRootBox()->computeOverAnnotationAdjustment(lowestAllowedPosition);
     }
-    
+
     // Now add in the bottom border/padding.
-    setLogicalHeight(logicalHeight() + lastLineRubyAdjustment + borderAfter() + paddingAfter() + scrollbarLogicalHeight());
+    setLogicalHeight(logicalHeight() + lastLineAnnotationsAdjustment + borderAfter() + paddingAfter() + scrollbarLogicalHeight());
 
     if (!firstLineBox() && hasLineIfEmpty())
         setLogicalHeight(logicalHeight() + lineHeight(true, style()->isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes));
index 8802fb8..3930910 100644 (file)
@@ -1593,7 +1593,7 @@ Color RenderObject::selectionBackgroundColor() const
     return color;
 }
 
-Color RenderObject::selectionForegroundColor() const
+Color RenderObject::selectionColor(int colorProperty) const
 {
     Color color;
     // If the element is unselectable, or we are only painting the selection,
@@ -1603,7 +1603,7 @@ Color RenderObject::selectionForegroundColor() const
         return color;
 
     if (RefPtr<RenderStyle> pseudoStyle = getUncachedPseudoStyle(SELECTION)) {
-        color = pseudoStyle->visitedDependentColor(CSSPropertyWebkitTextFillColor);
+        color = pseudoStyle->visitedDependentColor(colorProperty);
         if (!color.isValid())
             color = pseudoStyle->visitedDependentColor(CSSPropertyColor);
     } else
@@ -1614,6 +1614,16 @@ Color RenderObject::selectionForegroundColor() const
     return color;
 }
 
+Color RenderObject::selectionForegroundColor() const
+{
+    return selectionColor(CSSPropertyWebkitTextFillColor);
+}
+
+Color RenderObject::selectionEmphasisMarkColor() const
+{
+    return selectionColor(CSSPropertyWebkitTextEmphasisColor);
+}
+
 #if ENABLE(DRAG_SUPPORT)
 Node* RenderObject::draggableNode(bool dhtmlOK, bool uaOK, int x, int y, bool& dhtmlWillDrag) const
 {
index d254986..9cb4e36 100644 (file)
@@ -674,6 +674,7 @@ public:
     // Obtains the selection colors that should be used when painting a selection.
     Color selectionBackgroundColor() const;
     Color selectionForegroundColor() const;
+    Color selectionEmphasisMarkColor() const;
 
     // Whether or not a given block needs to paint selection gaps.
     virtual bool shouldPaintSelectionGaps() const { return false; }
@@ -795,6 +796,8 @@ protected:
 private:
     RenderStyle* firstLineStyleSlowCase() const;
     StyleDifference adjustStyleDifference(StyleDifference, unsigned contextSensitiveProperties) const;
+
+    Color selectionColor(int colorProperty) const;
     
     RefPtr<RenderStyle> m_style;
 
index 3bcaa18..5961d19 100644 (file)
@@ -48,7 +48,8 @@ RootInlineBox::RootInlineBox(RenderBlock* block)
     , m_paginationStrut(0)
     , m_blockLogicalHeight(0)
     , m_baselineType(AlphabeticBaseline)
-    , m_containsRuby(false)
+    , m_hasAnnotationsBefore(false)
+    , m_hasAnnotationsAfter(false)
 {
     setIsHorizontal(block->style()->isHorizontalWritingMode());
 }
@@ -248,19 +249,20 @@ int RootInlineBox::alignBoxesInBlockDirection(int heightOfBlock, GlyphOverflowAn
     int lineTopIncludingMargins = heightOfBlock;
     int lineBottomIncludingMargins = heightOfBlock;
     bool setLineTop = false;
-    bool containsRuby = false;
+    bool hasAnnotationsBefore = false;
+    bool hasAnnotationsAfter = false;
     placeBoxesInBlockDirection(heightOfBlock, maxHeight, maxAscent, noQuirksMode, lineTop, lineBottom, setLineTop,
-                               lineTopIncludingMargins, lineBottomIncludingMargins, containsRuby, m_baselineType);
+                               lineTopIncludingMargins, lineBottomIncludingMargins, hasAnnotationsBefore, hasAnnotationsAfter, m_baselineType);
+    m_hasAnnotationsBefore = hasAnnotationsBefore;
+    m_hasAnnotationsAfter = hasAnnotationsAfter;
     setLineTopBottomPositions(lineTop, lineBottom);
 
-    m_containsRuby = containsRuby;
-    
-    int rubyAdjustment = blockDirectionRubyAdjustment();
-    if (rubyAdjustment) {
+    int annotationsAdjustment = beforeAnnotationsAdjustment();
+    if (annotationsAdjustment) {
         // FIXME: Need to handle pagination here. We might have to move to the next page/column as a result of the
         // ruby expansion.
-        adjustBlockDirectionPosition(rubyAdjustment);
-        heightOfBlock += rubyAdjustment;
+        adjustBlockDirectionPosition(annotationsAdjustment);
+        heightOfBlock += annotationsAdjustment;
     }
 
     // Detect integer overflow.
@@ -270,19 +272,35 @@ int RootInlineBox::alignBoxesInBlockDirection(int heightOfBlock, GlyphOverflowAn
     return heightOfBlock + maxHeight;
 }
 
-int RootInlineBox::blockDirectionRubyAdjustment() const
+int RootInlineBox::beforeAnnotationsAdjustment() const
 {
+    int result = 0;
+
     if (!renderer()->style()->isFlippedLinesWritingMode()) {
-        if (!containsRuby())
-            return 0;
-        int highestAllowedPosition = prevRootBox() ? min(prevRootBox()->lineBottom(), lineTop()) : block()->borderBefore();
-        return computeBlockDirectionRubyAdjustment(highestAllowedPosition);
-    } else if (prevRootBox() && prevRootBox()->containsRuby()) {
-        // We have to compute the Ruby expansion for the previous line to see how much we should move.
-        int lowestAllowedPosition = max(prevRootBox()->lineBottom(), lineTop());
-        return prevRootBox()->computeBlockDirectionRubyAdjustment(lowestAllowedPosition);
+        // Annotations under the previous line may push us down.
+        if (prevRootBox() && prevRootBox()->hasAnnotationsAfter())
+            result = prevRootBox()->computeUnderAnnotationAdjustment(lineTop());
+
+        if (!hasAnnotationsBefore())
+            return result;
+
+        // Annotations over this line may push us further down.
+        int highestAllowedPosition = prevRootBox() ? min(prevRootBox()->lineBottom(), lineTop()) + result : block()->borderBefore();
+        result =  computeOverAnnotationAdjustment(highestAllowedPosition);
+    } else {
+        // Annotations under this line may push us up.
+        if (hasAnnotationsBefore())
+            result = computeUnderAnnotationAdjustment(prevRootBox() ? prevRootBox()->lineBottom() : block()->borderBefore());
+
+        if (!prevRootBox() || !prevRootBox()->hasAnnotationsAfter())
+            return result;
+
+        // We have to compute the expansion for annotations over the previous line to see how much we should move.
+        int lowestAllowedPosition = max(prevRootBox()->lineBottom(), lineTop()) + result;
+        result = prevRootBox()->computeOverAnnotationAdjustment(lowestAllowedPosition);
     }
-    return 0;
+
+    return result;
 }
 
 GapRects RootInlineBox::lineSelectionGap(RenderBlock* rootBlock, const IntPoint& rootBlockPhysicalPosition, const IntSize& offsetFromRootBlock, 
index 12c7233..9fe80a1 100644 (file)
@@ -128,7 +128,8 @@ public:
     
     FontBaseline baselineType() const { return m_baselineType; }
 
-    bool containsRuby() const { return m_containsRuby; }
+    bool hasAnnotationsBefore() const { return m_hasAnnotationsBefore; }
+    bool hasAnnotationsAfter() const { return m_hasAnnotationsAfter; }
 
     IntRect paddedLayoutOverflowRect(int endPadding) const;
 
@@ -136,7 +137,7 @@ private:
     bool hasEllipsisBox() const { return m_hasEllipsisBoxOrHyphen; }
     void setHasEllipsisBox(bool hasEllipsisBox) { m_hasEllipsisBoxOrHyphen = hasEllipsisBox; }
 
-    int blockDirectionRubyAdjustment() const;
+    int beforeAnnotationsAdjustment() const;
 
     // Where this line ended.  The exact object and the position within that object are stored so that
     // we can create an InlineIterator beginning just after the end of this line.
@@ -160,7 +161,8 @@ private:
     FontBaseline m_baselineType;
     
     // If the line contains any ruby runs, then this will be true.
-    bool m_containsRuby : 1;
+    bool m_hasAnnotationsBefore : 1;
+    bool m_hasAnnotationsAfter : 1;
 
     WTF::Unicode::Direction m_lineBreakBidiStatusEor : 5;
     WTF::Unicode::Direction m_lineBreakBidiStatusLastStrong : 5;