WebCore:
authormitz@apple.com <mitz@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 28 Apr 2008 21:28:51 +0000 (21:28 +0000)
committermitz@apple.com <mitz@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 28 Apr 2008 21:28:51 +0000 (21:28 +0000)
        Reviewed by Dave Hyatt.

        - support multiple box- and text-shadows

        Tests: fast/css/shadow-multiple.html
               fast/repaint/shadow-multiple-horizontal.html
               fast/repaint/shadow-multiple-strict-horizontal.html
               fast/repaint/shadow-multiple-strict-vertical.html
               fast/repaint/shadow-multiple-vertical.html

        * css/CSSComputedStyleDeclaration.cpp:
        (WebCore::valueForShadow): Changed to account for reversing the order
        of the shadow values in the ShadowData list.

        * css/CSSValueList.cpp:
        (WebCore::CSSValueList::prepend): Added.
        * css/CSSValueList.h:

        * rendering/InlineFlowBox.cpp:
        (WebCore::InlineFlowBox::placeBoxesHorizontally): Changed to account for
        all shadows in overflow calculation.
        (WebCore::InlineFlowBox::placeBoxesVertically): Ditto.
        (WebCore::InlineFlowBox::paint): Changed to account for all shadows
        when testing for intersection with the damage rect.
        (WebCore::InlineFlowBox::paintTextDecorations): Changed to paint all
        shadows.

        * rendering/InlineTextBox.cpp:
        (WebCore::paintTextWithShadows): Factored out from paint() and changed
        to paint all shadows.
        (WebCore::InlineTextBox::paint): Moved the text painting code out to
        paintTextWithShadows(). Changed to not paint shadows for markers and
        composition underlines and in "force black text" mode.
        (WebCore::InlineTextBox::paintSelection):
        (WebCore::InlineTextBox::paintCompositionBackground):
        (WebCore::InlineTextBox::paintDecoration): Changed to paint all shadows.
        * rendering/InlineTextBox.h: Changed some public methods to private
        or protected.

        * rendering/RenderBlock.cpp:
        (WebCore::RenderBlock::overflowHeight): Changed to account for all
        shadows.
        (WebCore::RenderBlock::overflowWidth): Ditto.
        (WebCore::RenderBlock::overflowLeft): Ditto.
        (WebCore::RenderBlock::overflowTop): Ditto.
        (WebCore::RenderBlock::overflowRect): Ditto.
        (WebCore::RenderBlock::layoutBlock): Ditto.

        * rendering/RenderFlexibleBox.cpp:
        (WebCore::RenderFlexibleBox::layoutBlock): Ditto.

        * rendering/RenderLayer.cpp:
        (WebCore::RenderLayer::calculateRects): Ditto.

        * rendering/RenderObject.cpp:
        (WebCore::RenderObject::paintBoxShadow): Changed to paint all shadows.
        Changed to avoid clipping out the box if it has a fully opaque
        background.
        (WebCore::RenderObject::repaintAfterLayoutIfNeeded): Changed to account
        for all shadows.
        (WebCore::RenderObject::selectionForegroundColor): Cleaned up.
        (WebCore::RenderObject::adjustRectForOutlineAndShadow): Changed to
        account for all shadows.

        * rendering/RenderReplaced.cpp:
        (WebCore::RenderReplaced::adjustOverflowForBoxShadow): Ditto.

        * rendering/RenderStyle.cpp:
        (WebCore::RenderStyle::setTextShadow): Changed to prepend when adding
        so that the stacking order of shadows when painting will be "first o
        top".
        (WebCore::RenderStyle::setBoxShadow): Ditto.

        * rendering/RenderTable.cpp:
        (WebCore::RenderTable::layout): Changed to account for all shadows.

LayoutTests:

        Reviewed by Dave Hyatt.

        - add rendering and invalidation tests for multiple shadows

        * fast/css/shadow-multiple.html: Added.
        * fast/repaint/shadow-multiple-horizontal.html: Added.
        * fast/repaint/shadow-multiple-strict-horizontal.html: Added.
        * fast/repaint/shadow-multiple-strict-vertical.html: Added.
        * fast/repaint/shadow-multiple-vertical.html: Added.
        * platform/mac/fast/css/shadow-multiple-expected.checksum: Added.
        * platform/mac/fast/css/shadow-multiple-expected.png: Added.
        * platform/mac/fast/css/shadow-multiple-expected.txt: Added.
        * platform/mac/fast/repaint/shadow-multiple-horizontal-expected.checksum: Added.
        * platform/mac/fast/repaint/shadow-multiple-horizontal-expected.png: Added.
        * platform/mac/fast/repaint/shadow-multiple-horizontal-expected.txt: Added.
        * platform/mac/fast/repaint/shadow-multiple-strict-horizontal-expected.checksum: Added.
        * platform/mac/fast/repaint/shadow-multiple-strict-horizontal-expected.png: Added.
        * platform/mac/fast/repaint/shadow-multiple-strict-horizontal-expected.txt: Added.
        * platform/mac/fast/repaint/shadow-multiple-strict-vertical-expected.checksum: Added.
        * platform/mac/fast/repaint/shadow-multiple-strict-vertical-expected.png: Added.
        * platform/mac/fast/repaint/shadow-multiple-strict-vertical-expected.txt: Added.
        * platform/mac/fast/repaint/shadow-multiple-vertical-expected.checksum: Added.
        * platform/mac/fast/repaint/shadow-multiple-vertical-expected.png: Added.
        * platform/mac/fast/repaint/shadow-multiple-vertical-expected.txt: Added.

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

35 files changed:
LayoutTests/ChangeLog
LayoutTests/fast/css/shadow-multiple.html [new file with mode: 0644]
LayoutTests/fast/repaint/shadow-multiple-horizontal.html [new file with mode: 0644]
LayoutTests/fast/repaint/shadow-multiple-strict-horizontal.html [new file with mode: 0644]
LayoutTests/fast/repaint/shadow-multiple-strict-vertical.html [new file with mode: 0644]
LayoutTests/fast/repaint/shadow-multiple-vertical.html [new file with mode: 0644]
LayoutTests/platform/mac/fast/css/shadow-multiple-expected.checksum [new file with mode: 0644]
LayoutTests/platform/mac/fast/css/shadow-multiple-expected.png [new file with mode: 0644]
LayoutTests/platform/mac/fast/css/shadow-multiple-expected.txt [new file with mode: 0644]
LayoutTests/platform/mac/fast/repaint/shadow-multiple-horizontal-expected.checksum [new file with mode: 0644]
LayoutTests/platform/mac/fast/repaint/shadow-multiple-horizontal-expected.png [new file with mode: 0644]
LayoutTests/platform/mac/fast/repaint/shadow-multiple-horizontal-expected.txt [new file with mode: 0644]
LayoutTests/platform/mac/fast/repaint/shadow-multiple-strict-horizontal-expected.checksum [new file with mode: 0644]
LayoutTests/platform/mac/fast/repaint/shadow-multiple-strict-horizontal-expected.png [new file with mode: 0644]
LayoutTests/platform/mac/fast/repaint/shadow-multiple-strict-horizontal-expected.txt [new file with mode: 0644]
LayoutTests/platform/mac/fast/repaint/shadow-multiple-strict-vertical-expected.checksum [new file with mode: 0644]
LayoutTests/platform/mac/fast/repaint/shadow-multiple-strict-vertical-expected.png [new file with mode: 0644]
LayoutTests/platform/mac/fast/repaint/shadow-multiple-strict-vertical-expected.txt [new file with mode: 0644]
LayoutTests/platform/mac/fast/repaint/shadow-multiple-vertical-expected.checksum [new file with mode: 0644]
LayoutTests/platform/mac/fast/repaint/shadow-multiple-vertical-expected.png [new file with mode: 0644]
LayoutTests/platform/mac/fast/repaint/shadow-multiple-vertical-expected.txt [new file with mode: 0644]
WebCore/ChangeLog
WebCore/css/CSSComputedStyleDeclaration.cpp
WebCore/css/CSSValueList.cpp
WebCore/css/CSSValueList.h
WebCore/rendering/InlineFlowBox.cpp
WebCore/rendering/InlineTextBox.cpp
WebCore/rendering/InlineTextBox.h
WebCore/rendering/RenderBlock.cpp
WebCore/rendering/RenderFlexibleBox.cpp
WebCore/rendering/RenderLayer.cpp
WebCore/rendering/RenderObject.cpp
WebCore/rendering/RenderReplaced.cpp
WebCore/rendering/RenderStyle.cpp
WebCore/rendering/RenderTable.cpp

index 1c435f4..2a298aa 100644 (file)
@@ -1,3 +1,30 @@
+2008-04-28  Dan Bernstein  <mitz@apple.com>
+
+        Reviewed by Dave Hyatt.
+
+        - add rendering and invalidation tests for multiple shadows
+
+        * fast/css/shadow-multiple.html: Added.
+        * fast/repaint/shadow-multiple-horizontal.html: Added.
+        * fast/repaint/shadow-multiple-strict-horizontal.html: Added.
+        * fast/repaint/shadow-multiple-strict-vertical.html: Added.
+        * fast/repaint/shadow-multiple-vertical.html: Added.
+        * platform/mac/fast/css/shadow-multiple-expected.checksum: Added.
+        * platform/mac/fast/css/shadow-multiple-expected.png: Added.
+        * platform/mac/fast/css/shadow-multiple-expected.txt: Added.
+        * platform/mac/fast/repaint/shadow-multiple-horizontal-expected.checksum: Added.
+        * platform/mac/fast/repaint/shadow-multiple-horizontal-expected.png: Added.
+        * platform/mac/fast/repaint/shadow-multiple-horizontal-expected.txt: Added.
+        * platform/mac/fast/repaint/shadow-multiple-strict-horizontal-expected.checksum: Added.
+        * platform/mac/fast/repaint/shadow-multiple-strict-horizontal-expected.png: Added.
+        * platform/mac/fast/repaint/shadow-multiple-strict-horizontal-expected.txt: Added.
+        * platform/mac/fast/repaint/shadow-multiple-strict-vertical-expected.checksum: Added.
+        * platform/mac/fast/repaint/shadow-multiple-strict-vertical-expected.png: Added.
+        * platform/mac/fast/repaint/shadow-multiple-strict-vertical-expected.txt: Added.
+        * platform/mac/fast/repaint/shadow-multiple-vertical-expected.checksum: Added.
+        * platform/mac/fast/repaint/shadow-multiple-vertical-expected.png: Added.
+        * platform/mac/fast/repaint/shadow-multiple-vertical-expected.txt: Added.
+
 2008-04-28  David Hyatt  <hyatt@apple.com>
 
         Add layout test for canvas self-drawing bug.
diff --git a/LayoutTests/fast/css/shadow-multiple.html b/LayoutTests/fast/css/shadow-multiple.html
new file mode 100644 (file)
index 0000000..ecdb0b5
--- /dev/null
@@ -0,0 +1,34 @@
+<style>
+    span::selection { color: purple; }
+    div.roundedRect {
+        width: 100px;
+        height: 100px;
+        margin: 50px;
+        -webkit-border-radius: 25px;
+        -webkit-box-shadow: hsla(20, 100%, 50%, 1) 7px 4px 0
+                          , hsla(60, 100%, 50%, 1) -8px 14px 2px
+                          , hsla(100, 100%, 50%, 1) -21px -12px 5px;
+     }
+</style>
+<div style="
+    font-family: Lucida Grande;
+    font-weight: bold;
+    font-size: 48px;
+    margin: 20px;
+    text-shadow: hsla(20, 100%, 50%, 1) 7px 4px 0
+               , hsla(60, 100%, 50%, 1) -8px 14px 2px
+               , hsla(100, 100%, 50%, 1) -21px -12px 5px;
+">
+    <span style="-webkit-text-stroke: 1px; -webkit-text-fill-color: transparent;">This</span>
+    <span style="-webkit-text-stroke: 1px; -webkit-text-fill-color: white;">text</span>
+    <span style="color: rgba(0, 0, 0, 0.3);">casts</span>
+    <span id="selectMe">multiple</span>
+    shadows
+</div>
+<script>
+    var text = document.getElementById("selectMe").firstChild;
+    getSelection().setBaseAndExtent(text, 0, text, 6);
+</script>
+<div class="roundedRect"></div>
+<div class="roundedRect" style="background-color: white;"></div>
+<div class="roundedRect" style="background-color: rgba(0, 0, 0, 0.2);"></div>
diff --git a/LayoutTests/fast/repaint/shadow-multiple-horizontal.html b/LayoutTests/fast/repaint/shadow-multiple-horizontal.html
new file mode 100644 (file)
index 0000000..fa7f308
--- /dev/null
@@ -0,0 +1,27 @@
+<script type="text/javascript">
+    if (window.layoutTestController) {
+        layoutTestController.testRepaint();
+        layoutTestController.repaintSweepHorizontally();
+    }
+</script>
+<div style="
+    font-family: Lucida Grande;
+    font-weight: bold;
+    font-size: 48px;
+    margin: 20px;
+    text-shadow: hsla(20, 100%, 50%, 1) 7px 4px 0
+               , hsla(60, 100%, 50%, 1) -8px 14px 2px
+               , hsla(100, 100%, 50%, 1) -21px -12px 5px;
+">
+    <span style="text-decoration: overline underline line-through;">&nbsp; &nbsp; &nbsp; multiple &nbsp; &nbsp;</span> &nbsp; &nbsp; shadows &nbsp; &nbsp; &nbsp;
+</div>
+<div style="
+    width: 100px;
+    height: 100px;
+    margin: 100px;
+    -webkit-border-radius: 25px;
+    -webkit-box-shadow: hsla(20, 100%, 50%, 1) 7px 4px 0
+                      , hsla(60, 100%, 50%, 1) -8px 14px 2px
+                      , hsla(100, 100%, 50%, 1) -21px -12px 5px;
+">
+</div>
diff --git a/LayoutTests/fast/repaint/shadow-multiple-strict-horizontal.html b/LayoutTests/fast/repaint/shadow-multiple-strict-horizontal.html
new file mode 100644 (file)
index 0000000..9282507
--- /dev/null
@@ -0,0 +1,28 @@
+<!DOCTYPE HTML>
+<script type="text/javascript">
+    if (window.layoutTestController) {
+        layoutTestController.testRepaint();
+        layoutTestController.repaintSweepHorizontally();
+    }
+</script>
+<div style="
+    font-family: Lucida Grande;
+    font-weight: bold;
+    font-size: 48px;
+    margin: 20px;
+    text-shadow: hsla(20, 100%, 50%, 1) 7px 4px 0
+               , hsla(60, 100%, 50%, 1) -8px 14px 2px
+               , hsla(100, 100%, 50%, 1) -21px -12px 5px;
+">
+    <span style="text-decoration: overline underline line-through;">&nbsp; &nbsp; &nbsp; multiple &nbsp; &nbsp;</span> &nbsp; &nbsp; shadows &nbsp; &nbsp; &nbsp;
+</div>
+<div style="
+    width: 100px;
+    height: 100px;
+    margin: 100px;
+    -webkit-border-radius: 25px;
+    -webkit-box-shadow: hsla(20, 100%, 50%, 1) 7px 4px 0
+                      , hsla(60, 100%, 50%, 1) -8px 14px 2px
+                      , hsla(100, 100%, 50%, 1) -21px -12px 5px;
+">
+</div>
diff --git a/LayoutTests/fast/repaint/shadow-multiple-strict-vertical.html b/LayoutTests/fast/repaint/shadow-multiple-strict-vertical.html
new file mode 100644 (file)
index 0000000..4473ea8
--- /dev/null
@@ -0,0 +1,26 @@
+<!DOCTYPE HTML>
+<script type="text/javascript">
+    if (window.layoutTestController)
+        layoutTestController.testRepaint();
+</script>
+<div style="
+    font-family: Lucida Grande;
+    font-weight: bold;
+    font-size: 48px;
+    margin: 20px;
+    text-shadow: hsla(20, 100%, 50%, 1) 7px 4px 0
+               , hsla(60, 100%, 50%, 1) -8px 14px 2px
+               , hsla(100, 100%, 50%, 1) -21px -12px 5px;
+">
+    <span style="text-decoration: overline underline line-through;">&nbsp; &nbsp; &nbsp; multiple &nbsp; &nbsp;</span> &nbsp; &nbsp; shadows &nbsp; &nbsp; &nbsp;
+</div>
+<div style="
+    width: 100px;
+    height: 100px;
+    margin: 100px;
+    -webkit-border-radius: 25px;
+    -webkit-box-shadow: hsla(20, 100%, 50%, 1) 7px 4px 0
+                      , hsla(60, 100%, 50%, 1) -8px 14px 2px
+                      , hsla(100, 100%, 50%, 1) -21px -12px 5px;
+">
+</div>
diff --git a/LayoutTests/fast/repaint/shadow-multiple-vertical.html b/LayoutTests/fast/repaint/shadow-multiple-vertical.html
new file mode 100644 (file)
index 0000000..93ea364
--- /dev/null
@@ -0,0 +1,25 @@
+<script type="text/javascript">
+    if (window.layoutTestController)
+        layoutTestController.testRepaint();
+</script>
+<div style="
+    font-family: Lucida Grande;
+    font-weight: bold;
+    font-size: 48px;
+    margin: 20px;
+    text-shadow: hsla(20, 100%, 50%, 1) 7px 4px 0
+               , hsla(60, 100%, 50%, 1) -8px 14px 2px
+               , hsla(100, 100%, 50%, 1) -21px -12px 5px;
+">
+    <span style="text-decoration: overline underline line-through;">&nbsp; &nbsp; &nbsp; multiple &nbsp; &nbsp;</span> &nbsp; &nbsp; shadows &nbsp; &nbsp; &nbsp;
+</div>
+<div style="
+    width: 100px;
+    height: 100px;
+    margin: 100px;
+    -webkit-border-radius: 25px;
+    -webkit-box-shadow: hsla(20, 100%, 50%, 1) 7px 4px 0
+                      , hsla(60, 100%, 50%, 1) -8px 14px 2px
+                      , hsla(100, 100%, 50%, 1) -21px -12px 5px;
+">
+</div>
diff --git a/LayoutTests/platform/mac/fast/css/shadow-multiple-expected.checksum b/LayoutTests/platform/mac/fast/css/shadow-multiple-expected.checksum
new file mode 100644 (file)
index 0000000..5d3e34c
--- /dev/null
@@ -0,0 +1 @@
+aba5acb31e4f0ff432b5a137eb4d35aa
\ No newline at end of file
diff --git a/LayoutTests/platform/mac/fast/css/shadow-multiple-expected.png b/LayoutTests/platform/mac/fast/css/shadow-multiple-expected.png
new file mode 100644 (file)
index 0000000..3b9c1a1
Binary files /dev/null and b/LayoutTests/platform/mac/fast/css/shadow-multiple-expected.png differ
diff --git a/LayoutTests/platform/mac/fast/css/shadow-multiple-expected.txt b/LayoutTests/platform/mac/fast/css/shadow-multiple-expected.txt
new file mode 100644 (file)
index 0000000..88a76ef
--- /dev/null
@@ -0,0 +1,31 @@
+layer at (0,0) size 785x632
+  RenderView at (0,0) size 785x600
+layer at (0,0) size 785x632
+  RenderBlock {HTML} at (0,0) size 785x632
+    RenderBody {BODY} at (8,20) size 769x562
+      RenderBlock {DIV} at (20,0) size 729x112
+        RenderInline {SPAN} at (0,0) size 108x56 [textStrokeWidth=1.00]
+          RenderText {#text} at (0,0) size 108x56
+            text run at (0,0) width 108: "This"
+        RenderText {#text} at (108,0) size 16x56
+          text run at (108,0) width 16: " "
+        RenderInline {SPAN} at (0,0) size 96x56 [textFillColor=#FFFFFF] [textStrokeWidth=1.00]
+          RenderText {#text} at (124,0) size 96x56
+            text run at (124,0) width 96: "text"
+        RenderText {#text} at (220,0) size 16x56
+          text run at (220,0) width 16: " "
+        RenderInline {SPAN} at (0,0) size 128x56 [color=#0000004C]
+          RenderText {#text} at (236,0) size 128x56
+            text run at (236,0) width 128: "casts"
+        RenderText {#text} at (364,0) size 16x56
+          text run at (364,0) width 16: " "
+        RenderInline {SPAN} at (0,0) size 205x56
+          RenderText {#text} at (380,0) size 205x56
+            text run at (380,0) width 205: "multiple"
+        RenderText {#text} at (0,56) size 218x56
+          text run at (0,56) width 218: "shadows"
+      RenderBlock {DIV} at (50,162) size 100x100
+      RenderBlock {DIV} at (50,312) size 100x100 [bgcolor=#FFFFFF]
+      RenderBlock {DIV} at (50,462) size 100x100 [bgcolor=#00000033]
+selection start: position 0 of child 0 {#text} of child 7 {SPAN} of child 0 {DIV} of child 1 {BODY} of child 0 {HTML} of document
+selection end:   position 6 of child 0 {#text} of child 7 {SPAN} of child 0 {DIV} of child 1 {BODY} of child 0 {HTML} of document
diff --git a/LayoutTests/platform/mac/fast/repaint/shadow-multiple-horizontal-expected.checksum b/LayoutTests/platform/mac/fast/repaint/shadow-multiple-horizontal-expected.checksum
new file mode 100644 (file)
index 0000000..5c58254
--- /dev/null
@@ -0,0 +1 @@
+1922b1893f2eada6115a4df2954b69e2
\ No newline at end of file
diff --git a/LayoutTests/platform/mac/fast/repaint/shadow-multiple-horizontal-expected.png b/LayoutTests/platform/mac/fast/repaint/shadow-multiple-horizontal-expected.png
new file mode 100644 (file)
index 0000000..85fd1f3
Binary files /dev/null and b/LayoutTests/platform/mac/fast/repaint/shadow-multiple-horizontal-expected.png differ
diff --git a/LayoutTests/platform/mac/fast/repaint/shadow-multiple-horizontal-expected.txt b/LayoutTests/platform/mac/fast/repaint/shadow-multiple-horizontal-expected.txt
new file mode 100644 (file)
index 0000000..b2a126b
--- /dev/null
@@ -0,0 +1,13 @@
+layer at (0,0) size 800x600
+  RenderView at (0,0) size 800x600
+layer at (0,0) size 800x600
+  RenderBlock {HTML} at (0,0) size 800x600
+    RenderBody {BODY} at (8,20) size 784x480
+      RenderBlock {DIV} at (20,0) size 744x112
+        RenderInline {SPAN} at (0,0) size 365x56
+          RenderText {#text} at (0,0) size 365x56
+            text run at (0,0) width 365: "      multiple    "
+        RenderText {#text} at (365,0) size 727x112
+          text run at (365,0) width 362: "     shadows    "
+          text run at (0,56) width 16: " "
+      RenderBlock {DIV} at (100,212) size 100x100
diff --git a/LayoutTests/platform/mac/fast/repaint/shadow-multiple-strict-horizontal-expected.checksum b/LayoutTests/platform/mac/fast/repaint/shadow-multiple-strict-horizontal-expected.checksum
new file mode 100644 (file)
index 0000000..d87057d
--- /dev/null
@@ -0,0 +1 @@
+99ff166ca02c29dfa285c4f67ea4a71c
\ No newline at end of file
diff --git a/LayoutTests/platform/mac/fast/repaint/shadow-multiple-strict-horizontal-expected.png b/LayoutTests/platform/mac/fast/repaint/shadow-multiple-strict-horizontal-expected.png
new file mode 100644 (file)
index 0000000..b466d84
Binary files /dev/null and b/LayoutTests/platform/mac/fast/repaint/shadow-multiple-strict-horizontal-expected.png differ
diff --git a/LayoutTests/platform/mac/fast/repaint/shadow-multiple-strict-horizontal-expected.txt b/LayoutTests/platform/mac/fast/repaint/shadow-multiple-strict-horizontal-expected.txt
new file mode 100644 (file)
index 0000000..32a1717
--- /dev/null
@@ -0,0 +1,13 @@
+layer at (0,0) size 800x600
+  RenderView at (0,0) size 800x600
+layer at (0,0) size 800x432
+  RenderBlock {HTML} at (0,0) size 800x432
+    RenderBody {BODY} at (8,20) size 784x312
+      RenderBlock {DIV} at (20,0) size 744x112
+        RenderInline {SPAN} at (0,0) size 365x56
+          RenderText {#text} at (0,0) size 365x56
+            text run at (0,0) width 365: "      multiple    "
+        RenderText {#text} at (365,0) size 727x112
+          text run at (365,0) width 362: "     shadows    "
+          text run at (0,56) width 16: " "
+      RenderBlock {DIV} at (100,212) size 100x100
diff --git a/LayoutTests/platform/mac/fast/repaint/shadow-multiple-strict-vertical-expected.checksum b/LayoutTests/platform/mac/fast/repaint/shadow-multiple-strict-vertical-expected.checksum
new file mode 100644 (file)
index 0000000..9a7186a
--- /dev/null
@@ -0,0 +1 @@
+0924727a55c3f9468d946c5f00f87694
\ No newline at end of file
diff --git a/LayoutTests/platform/mac/fast/repaint/shadow-multiple-strict-vertical-expected.png b/LayoutTests/platform/mac/fast/repaint/shadow-multiple-strict-vertical-expected.png
new file mode 100644 (file)
index 0000000..c3ec227
Binary files /dev/null and b/LayoutTests/platform/mac/fast/repaint/shadow-multiple-strict-vertical-expected.png differ
diff --git a/LayoutTests/platform/mac/fast/repaint/shadow-multiple-strict-vertical-expected.txt b/LayoutTests/platform/mac/fast/repaint/shadow-multiple-strict-vertical-expected.txt
new file mode 100644 (file)
index 0000000..32a1717
--- /dev/null
@@ -0,0 +1,13 @@
+layer at (0,0) size 800x600
+  RenderView at (0,0) size 800x600
+layer at (0,0) size 800x432
+  RenderBlock {HTML} at (0,0) size 800x432
+    RenderBody {BODY} at (8,20) size 784x312
+      RenderBlock {DIV} at (20,0) size 744x112
+        RenderInline {SPAN} at (0,0) size 365x56
+          RenderText {#text} at (0,0) size 365x56
+            text run at (0,0) width 365: "      multiple    "
+        RenderText {#text} at (365,0) size 727x112
+          text run at (365,0) width 362: "     shadows    "
+          text run at (0,56) width 16: " "
+      RenderBlock {DIV} at (100,212) size 100x100
diff --git a/LayoutTests/platform/mac/fast/repaint/shadow-multiple-vertical-expected.checksum b/LayoutTests/platform/mac/fast/repaint/shadow-multiple-vertical-expected.checksum
new file mode 100644 (file)
index 0000000..7cbf568
--- /dev/null
@@ -0,0 +1 @@
+b0e494de9eefbc07ebd513ec65bfa171
\ No newline at end of file
diff --git a/LayoutTests/platform/mac/fast/repaint/shadow-multiple-vertical-expected.png b/LayoutTests/platform/mac/fast/repaint/shadow-multiple-vertical-expected.png
new file mode 100644 (file)
index 0000000..1cbb1b4
Binary files /dev/null and b/LayoutTests/platform/mac/fast/repaint/shadow-multiple-vertical-expected.png differ
diff --git a/LayoutTests/platform/mac/fast/repaint/shadow-multiple-vertical-expected.txt b/LayoutTests/platform/mac/fast/repaint/shadow-multiple-vertical-expected.txt
new file mode 100644 (file)
index 0000000..b2a126b
--- /dev/null
@@ -0,0 +1,13 @@
+layer at (0,0) size 800x600
+  RenderView at (0,0) size 800x600
+layer at (0,0) size 800x600
+  RenderBlock {HTML} at (0,0) size 800x600
+    RenderBody {BODY} at (8,20) size 784x480
+      RenderBlock {DIV} at (20,0) size 744x112
+        RenderInline {SPAN} at (0,0) size 365x56
+          RenderText {#text} at (0,0) size 365x56
+            text run at (0,0) width 365: "      multiple    "
+        RenderText {#text} at (365,0) size 727x112
+          text run at (365,0) width 362: "     shadows    "
+          text run at (0,56) width 16: " "
+      RenderBlock {DIV} at (100,212) size 100x100
index 85ca246..7a7953d 100644 (file)
@@ -1,3 +1,81 @@
+2008-04-28  Dan Bernstein  <mitz@apple.com>
+
+        Reviewed by Dave Hyatt.
+
+        - support multiple box- and text-shadows
+
+        Tests: fast/css/shadow-multiple.html
+               fast/repaint/shadow-multiple-horizontal.html
+               fast/repaint/shadow-multiple-strict-horizontal.html
+               fast/repaint/shadow-multiple-strict-vertical.html
+               fast/repaint/shadow-multiple-vertical.html
+
+        * css/CSSComputedStyleDeclaration.cpp:
+        (WebCore::valueForShadow): Changed to account for reversing the order
+        of the shadow values in the ShadowData list.
+
+        * css/CSSValueList.cpp:
+        (WebCore::CSSValueList::prepend): Added.
+        * css/CSSValueList.h:
+
+        * rendering/InlineFlowBox.cpp:
+        (WebCore::InlineFlowBox::placeBoxesHorizontally): Changed to account for
+        all shadows in overflow calculation.
+        (WebCore::InlineFlowBox::placeBoxesVertically): Ditto.
+        (WebCore::InlineFlowBox::paint): Changed to account for all shadows
+        when testing for intersection with the damage rect.
+        (WebCore::InlineFlowBox::paintTextDecorations): Changed to paint all
+        shadows.
+
+        * rendering/InlineTextBox.cpp:
+        (WebCore::paintTextWithShadows): Factored out from paint() and changed
+        to paint all shadows.
+        (WebCore::InlineTextBox::paint): Moved the text painting code out to
+        paintTextWithShadows(). Changed to not paint shadows for markers and
+        composition underlines and in "force black text" mode.
+        (WebCore::InlineTextBox::paintSelection):
+        (WebCore::InlineTextBox::paintCompositionBackground):
+        (WebCore::InlineTextBox::paintDecoration): Changed to paint all shadows.
+        * rendering/InlineTextBox.h: Changed some public methods to private
+        or protected.
+
+        * rendering/RenderBlock.cpp:
+        (WebCore::RenderBlock::overflowHeight): Changed to account for all
+        shadows.
+        (WebCore::RenderBlock::overflowWidth): Ditto.
+        (WebCore::RenderBlock::overflowLeft): Ditto.
+        (WebCore::RenderBlock::overflowTop): Ditto.
+        (WebCore::RenderBlock::overflowRect): Ditto.
+        (WebCore::RenderBlock::layoutBlock): Ditto.
+
+        * rendering/RenderFlexibleBox.cpp:
+        (WebCore::RenderFlexibleBox::layoutBlock): Ditto.
+
+        * rendering/RenderLayer.cpp:
+        (WebCore::RenderLayer::calculateRects): Ditto.
+
+        * rendering/RenderObject.cpp:
+        (WebCore::RenderObject::paintBoxShadow): Changed to paint all shadows.
+        Changed to avoid clipping out the box if it has a fully opaque
+        background.
+        (WebCore::RenderObject::repaintAfterLayoutIfNeeded): Changed to account
+        for all shadows.
+        (WebCore::RenderObject::selectionForegroundColor): Cleaned up.
+        (WebCore::RenderObject::adjustRectForOutlineAndShadow): Changed to
+        account for all shadows.
+
+        * rendering/RenderReplaced.cpp:
+        (WebCore::RenderReplaced::adjustOverflowForBoxShadow): Ditto.
+
+        * rendering/RenderStyle.cpp:
+        (WebCore::RenderStyle::setTextShadow): Changed to prepend when adding
+        so that the stacking order of shadows when painting will be "first o
+        top".
+        (WebCore::RenderStyle::setBoxShadow): Ditto.
+
+        * rendering/RenderTable.cpp:
+        (WebCore::RenderTable::layout): Changed to account for all shadows.
+
 2008-04-28  Adam Roben  <aroben@apple.com>
 
         Fix some more Windows build errors in COMPtr
index ae45b35..f5a6ad7 100644 (file)
@@ -243,7 +243,7 @@ static PassRefPtr<CSSValue> valueForShadow(const ShadowData* shadow)
         RefPtr<CSSPrimitiveValue> y = new CSSPrimitiveValue(s->y, CSSPrimitiveValue::CSS_PX);
         RefPtr<CSSPrimitiveValue> blur = new CSSPrimitiveValue(s->blur, CSSPrimitiveValue::CSS_PX);
         RefPtr<CSSPrimitiveValue> color = new CSSPrimitiveValue(s->color.rgb());
-        list->append(new ShadowValue(x.release(), y.release(), blur.release(), color.release()));
+        list->prepend(new ShadowValue(x.release(), y.release(), blur.release(), color.release()));
     }
     return list.release();
 }
index 8df6a9f..628e988 100644 (file)
@@ -52,6 +52,11 @@ void CSSValueList::append(PassRefPtr<CSSValue> val)
     m_values.append(val);
 }
 
+void CSSValueList::prepend(PassRefPtr<CSSValue> val)
+{
+    m_values.prepend(val);
+}
+
 String CSSValueList::cssText() const
 {
     String result = "";
index cff0a99..acc51be 100644 (file)
@@ -43,6 +43,7 @@ public:
     virtual unsigned short cssValueType() const;
 
     void append(PassRefPtr<CSSValue>);
+    void prepend(PassRefPtr<CSSValue>);
     virtual String cssText() const;
 
 protected:
index 58a08bb..90ce338 100644 (file)
@@ -277,9 +277,9 @@ int InlineFlowBox::placeBoxesHorizontally(int x, int& leftPosition, int& rightPo
 
     int boxShadowLeft = 0;
     int boxShadowRight = 0;
-    if (ShadowData* boxShadow = object()->style(m_firstLine)->boxShadow()) {
-        boxShadowLeft = min(boxShadow->x - boxShadow->blur, 0);
-        boxShadowRight = max(boxShadow->x + boxShadow->blur, 0);
+    for (ShadowData* boxShadow = object()->style(m_firstLine)->boxShadow(); boxShadow; boxShadow = boxShadow->next) {
+        boxShadowLeft = min(boxShadow->x - boxShadow->blur, boxShadowLeft);
+        boxShadowRight = max(boxShadow->x + boxShadow->blur, boxShadowRight);
     }
     leftPosition = min(x + boxShadowLeft, leftPosition);
 
@@ -511,11 +511,16 @@ void InlineFlowBox::placeBoxesVertically(int y, int maxHeight, int maxAscent, bo
                 overflowBottom = max(overflowBottom, shadow->y + shadow->blur);
             }
 
-            if (ShadowData* boxShadow = curr->object()->style(m_firstLine)->boxShadow()) {
+            for (ShadowData* boxShadow = curr->object()->style(m_firstLine)->boxShadow(); boxShadow; boxShadow = boxShadow->next) {
                 overflowTop = min(overflowTop, boxShadow->y - boxShadow->blur);
                 overflowBottom = max(overflowBottom, boxShadow->y + boxShadow->blur);
             }
 
+            for (ShadowData* textShadow = curr->object()->style(m_firstLine)->textShadow(); textShadow; textShadow = textShadow->next) {
+                overflowTop = min(overflowTop, textShadow->y - textShadow->blur);
+                overflowBottom = max(overflowBottom, textShadow->y + textShadow->blur);
+            }
+
             if (curr->isInlineFlowBox()) {
                 newHeight += curr->object()->borderTop() + curr->object()->paddingTop() +
                             curr->object()->borderBottom() + curr->object()->paddingBottom();
@@ -599,11 +604,18 @@ void InlineFlowBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty)
 {
     int xPos = tx + m_x - object()->maximalOutlineSize(paintInfo.phase);
     int w = width() + 2 * object()->maximalOutlineSize(paintInfo.phase);
-    if (ShadowData* boxShadow = object()->style(m_firstLine)->boxShadow()) {
-        int shadowLeft = min(boxShadow->x - boxShadow->blur, 0);
-        xPos += shadowLeft;
-        w += -shadowLeft + max(boxShadow->x + boxShadow->blur, 0);
+    int shadowLeft = 0;
+    int shadowRight = 0;
+    for (ShadowData* boxShadow = object()->style(m_firstLine)->boxShadow(); boxShadow; boxShadow = boxShadow->next) {
+        shadowLeft = min(boxShadow->x - boxShadow->blur, shadowLeft);
+        shadowRight = max(boxShadow->x + boxShadow->blur, shadowRight);
+    }
+    for (ShadowData* textShadow = object()->style(m_firstLine)->textShadow(); textShadow; textShadow = textShadow->next) {
+        shadowLeft = min(textShadow->x - textShadow->blur, shadowLeft);
+        shadowRight = max(textShadow->x + textShadow->blur, shadowRight);
     }
+    xPos += shadowLeft;
+    w += -shadowLeft + shadowRight;
     bool intersectsDamageRect = xPos < paintInfo.rect.right() && xPos + w > paintInfo.rect.x();
 
     if (intersectsDamageRect && paintInfo.phase != PaintPhaseChildOutlines) {
@@ -877,15 +889,6 @@ void InlineFlowBox::paintTextDecorations(RenderObject::PaintInfo& paintInfo, int
             }
         }
 
-        // Set up the appropriate text-shadow effect for the decoration.
-        // FIXME: Support multiple shadow effects.  Need more from the CG API before we can do this.
-        bool setShadow = false;
-        if (styleToUse->textShadow()) {
-            context->setShadow(IntSize(styleToUse->textShadow()->x, styleToUse->textShadow()->y),
-                               styleToUse->textShadow()->blur, styleToUse->textShadow()->color);
-            setShadow = true;
-        }
-
         // We must have child boxes and have decorations defined.
         tx += borderLeft() + paddingLeft();
 
@@ -894,26 +897,66 @@ void InlineFlowBox::paintTextDecorations(RenderObject::PaintInfo& paintInfo, int
         if (!parent())
             object()->getTextDecorationColors(deco, underline, overline, linethrough);
 
-        if (styleToUse->font() != context->font())
-            context->setFont(styleToUse->font());
-
         bool isPrinting = object()->document()->printing();
         context->setStrokeThickness(1.0f); // FIXME: We should improve this rule and not always just assume 1.
-        if (deco & UNDERLINE && !paintedChildren) {
-            context->setStrokeColor(underline);
-            // Leave one pixel of white between the baseline and the underline.
-            context->drawLineForText(IntPoint(tx, ty + m_baseline + 1), w, isPrinting);
-        }
-        if (deco & OVERLINE && !paintedChildren) {
-            context->setStrokeColor(overline);
-            context->drawLineForText(IntPoint(tx, ty), w, isPrinting);
-        }
-        if (deco & LINE_THROUGH && paintedChildren) {
-            context->setStrokeColor(linethrough);
-            context->drawLineForText(IntPoint(tx, ty + 2 * m_baseline / 3), w, isPrinting);
+
+        bool paintUnderline = deco & UNDERLINE && !paintedChildren;
+        bool paintOverline = deco & OVERLINE && !paintedChildren;
+        bool paintLineThrough = deco & LINE_THROUGH && paintedChildren;
+
+        bool linesAreOpaque = !isPrinting && (!paintUnderline || underline.alpha() == 255) && (!paintOverline || overline.alpha() == 255) && (!paintLineThrough || linethrough.alpha() == 255);
+
+        bool setClip = false;
+        int extraOffset = 0;
+        ShadowData* shadow = styleToUse->textShadow();
+        if (!linesAreOpaque && shadow && shadow->next) {
+            context->save();
+            IntRect clipRect(tx, ty, w, m_baseline + 2);
+            for (ShadowData* s = shadow; s; s = s->next) {
+                IntRect shadowRect(tx, ty, w, m_baseline + 2);
+                shadowRect.inflate(s->blur);
+                shadowRect.move(s->x, s->y);
+                clipRect.unite(shadowRect);
+                extraOffset = max(extraOffset, max(0, s->y) + s->blur);
+            }
+            context->save();
+            context->clip(clipRect);
+            extraOffset += m_baseline + 2;
+            ty += extraOffset;
+            setClip = true;
         }
 
-        if (setShadow)
+        bool setShadow = false;
+        do {
+            if (shadow) {
+                if (!shadow->next) {
+                    // The last set of lines paints normally inside the clip.
+                    ty -= extraOffset;
+                    extraOffset = 0;
+                }
+                context->setShadow(IntSize(shadow->x, shadow->y - extraOffset), shadow->blur, shadow->color);
+                setShadow = true;
+                shadow = shadow->next;
+            }
+
+            if (paintUnderline) {
+                context->setStrokeColor(underline);
+                // Leave one pixel of white between the baseline and the underline.
+                context->drawLineForText(IntPoint(tx, ty + m_baseline + 1), w, isPrinting);
+            }
+            if (paintOverline) {
+                context->setStrokeColor(overline);
+                context->drawLineForText(IntPoint(tx, ty), w, isPrinting);
+            }
+            if (paintLineThrough) {
+                context->setStrokeColor(linethrough);
+                context->drawLineForText(IntPoint(tx, ty + 2 * m_baseline / 3), w, isPrinting);
+            }
+        } while (shadow);
+
+        if (setClip)
+            context->restore();
+        else if (setShadow)
             context->clearShadow();
     }
 }
index a79feeb..14b9400 100644 (file)
@@ -232,6 +232,52 @@ bool InlineTextBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& re
     return false;
 }
 
+static void paintTextWithShadows(GraphicsContext* context, const TextRun& textRun, int startOffset, int endOffset, const IntPoint& textOrigin, int x, int y, int w, int h, ShadowData* shadow, bool stroked)
+{
+    while (true) {
+        IntSize extraOffset;
+
+        if (shadow) {
+            IntSize shadowOffset(shadow->x, shadow->y);
+            int shadowBlur = shadow->blur;
+            const Color& shadowColor = shadow->color;
+
+            if (shadow->next || stroked) {
+                IntRect shadowRect(x, y, w, h);
+                shadowRect.inflate(shadowBlur);
+                shadowRect.move(shadowOffset);
+                context->save();
+                context->clip(shadowRect);
+
+                extraOffset = IntSize(0, 2 * h + max(0, shadowOffset.height()) + shadowBlur);
+                shadowOffset -= extraOffset;
+            }
+            context->setShadow(shadowOffset, shadowBlur, shadowColor);
+        }
+
+        if (startOffset <= endOffset)
+            context->drawText(textRun, textOrigin + extraOffset, startOffset, endOffset);
+        else {
+            if (endOffset > 0)
+                context->drawText(textRun, textOrigin + extraOffset,  0, endOffset);
+            if (startOffset < textRun.length())
+                context->drawText(textRun, textOrigin + extraOffset, startOffset);
+        }
+
+        if (!shadow)
+            break;
+
+        if (shadow->next || stroked)
+            context->restore();
+        else
+            context->clearShadow();
+
+        shadow = shadow->next;
+        if (stroked)
+            continue;
+    }
+}
+
 void InlineTextBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty)
 {
     if (isLineBreak() || !object()->shouldPaintWithinRoot(paintInfo) || object()->style()->visibility() != VISIBLE ||
@@ -253,6 +299,8 @@ void InlineTextBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty)
         // When only painting the selection, don't bother to paint if there is none.
         return;
 
+    GraphicsContext* context = paintInfo.context;
+
     // Determine whether or not we have composition underlines to draw.
     bool containsComposition = object()->document()->frame()->editor()->compositionNode() == object()->node();
     bool useCustomUnderlines = containsComposition && object()->document()->frame()->editor()->compositionUsesCustomUnderlines();
@@ -261,27 +309,27 @@ void InlineTextBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty)
     RenderStyle* styleToUse = object()->style(m_firstLine);
     int d = styleToUse->textDecorationsInEffect();
     const Font* font = &styleToUse->font();
-    if (*font != paintInfo.context->font())
-        paintInfo.context->setFont(*font);
+    if (*font != context->font())
+        context->setFont(*font);
 
     // 1. Paint backgrounds behind text if needed. Examples of such backgrounds include selection
     // and composition underlines.
     if (paintInfo.phase != PaintPhaseSelection && paintInfo.phase != PaintPhaseTextClip && !isPrinting) {
 #if PLATFORM(MAC)
         // Custom highlighters go behind everything else.
-        if (styleToUse->highlight() != nullAtom && !paintInfo.context->paintingDisabled())
+        if (styleToUse->highlight() != nullAtom && !context->paintingDisabled())
             paintCustomHighlight(tx, ty, styleToUse->highlight());
 #endif
 
         if (containsComposition && !useCustomUnderlines)
-            paintCompositionBackground(paintInfo.context, tx, ty, styleToUse, font,
+            paintCompositionBackground(context, tx, ty, styleToUse, font,
                 object()->document()->frame()->editor()->compositionStart(),
                 object()->document()->frame()->editor()->compositionEnd());
 
-        paintDocumentMarkers(paintInfo.context, tx, ty, styleToUse, font, true);
+        paintDocumentMarkers(context, tx, ty, styleToUse, font, true);
 
         if (haveSelection && !useCustomUnderlines)
-            paintSelection(paintInfo.context, tx, ty, styleToUse, font);
+            paintSelection(context, tx, ty, styleToUse, font);
     }
 
     // 2. Now paint the foreground, including text and decorations like underline/overline (in quirks mode only).
@@ -290,74 +338,54 @@ void InlineTextBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty)
 
     Color textFillColor;
     Color textStrokeColor;
-    Color shadowColor;
     float textStrokeWidth = styleToUse->textStrokeWidth();
+    ShadowData* textShadow = paintInfo.forceBlackText ? 0 : styleToUse->textShadow();
 
     if (paintInfo.forceBlackText) {
         textFillColor = Color::black;
         textStrokeColor = Color::black;
-        shadowColor = Color::black;
     } else {
         textFillColor = styleToUse->textFillColor();
         if (!textFillColor.isValid())
             textFillColor = styleToUse->color();
-        
+
         // Make the text fill color legible against a white background
         if (styleToUse->forceBackgroundsToWhite())
             textFillColor = correctedTextColor(textFillColor, Color::white);
-            
+
         textStrokeColor = styleToUse->textStrokeColor();
         if (!textStrokeColor.isValid())
             textStrokeColor = styleToUse->color();
-        
+
         // Make the text stroke color legible against a white background
         if (styleToUse->forceBackgroundsToWhite())
             textStrokeColor = correctedTextColor(textStrokeColor, Color::white);
-            
-        shadowColor = styleToUse->textShadow() ? styleToUse->textShadow()->color : Color::black;
-    }
-
-    // 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.
-    if (textStrokeWidth > 0)
-        paintInfo.context->save();
-
-    updateGraphicsContext(paintInfo.context, textFillColor, textStrokeColor, textStrokeWidth);
-
-    // Set a text shadow if we have one.
-    // FIXME: Support multiple shadow effects.  Need more from the CG API before
-    // we can do this.
-    bool setShadow = false;
-    if (styleToUse->textShadow()) {
-        paintInfo.context->setShadow(IntSize(styleToUse->textShadow()->x, styleToUse->textShadow()->y),
-                                     styleToUse->textShadow()->blur, shadowColor);
-        setShadow = true;
     }
 
     bool paintSelectedTextOnly = (paintInfo.phase == PaintPhaseSelection);
-    bool paintSelectedTextSeparately = false; // Whether or not we have to do multiple paints.  Only
-                                              // necessary when a custom ::selection foreground color is applied.
+    bool paintSelectedTextSeparately = false;
+
     Color selectionFillColor = textFillColor;
     Color selectionStrokeColor = textStrokeColor;
     float selectionStrokeWidth = textStrokeWidth;
-    ShadowData* selectionTextShadow = 0;
+    ShadowData* selectionShadow = textShadow;
     if (haveSelection) {
         // Check foreground color first.
-        Color foreground = object()->selectionForegroundColor();
+        Color foreground = paintInfo.forceBlackText ? Color::black : object()->selectionForegroundColor();
         if (foreground.isValid() && foreground != selectionFillColor) {
             if (!paintSelectedTextOnly)
                 paintSelectedTextSeparately = true;
             selectionFillColor = foreground;
         }
-        RenderStyle* pseudoStyle = object()->getPseudoStyle(RenderStyle::SELECTION);
-        if (pseudoStyle) {
-            if (pseudoStyle->textShadow()) {
+
+        if (RenderStyle* pseudoStyle = object()->getPseudoStyle(RenderStyle::SELECTION)) {
+            ShadowData* shadow = paintInfo.forceBlackText ? 0 : pseudoStyle->textShadow();
+            if (shadow != selectionShadow) {
                 if (!paintSelectedTextOnly)
                     paintSelectedTextSeparately = true;
-                if (pseudoStyle->textShadow())
-                    selectionTextShadow = pseudoStyle->textShadow();
+                selectionShadow = shadow;
             }
-            
+
             float strokeWidth = pseudoStyle->textStrokeWidth();
             if (strokeWidth != selectionStrokeWidth) {
                 if (!paintSelectedTextOnly)
@@ -365,7 +393,7 @@ void InlineTextBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty)
                 selectionStrokeWidth = strokeWidth;
             }
 
-            Color stroke = pseudoStyle->textStrokeColor();
+            Color stroke = paintInfo.forceBlackText ? Color::black : pseudoStyle->textStrokeColor();
             if (!stroke.isValid())
                 stroke = pseudoStyle->color();
             if (stroke != selectionStrokeColor) {
@@ -376,63 +404,51 @@ void InlineTextBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty)
         }
     }
 
-    StringImpl* textStr = textObject()->text();
-
-    if (!paintSelectedTextOnly && !paintSelectedTextSeparately) {
-        // paint all the text
-        // FIXME: Handle RTL direction, handle reversed strings.  For now truncation can only be turned on
-        // for non-reversed LTR strings.
-        int endPoint = m_len;
-        if (m_truncation != cNoTruncation)
-            endPoint = m_truncation;
-        paintInfo.context->drawText(TextRun(textStr->characters() + m_start, endPoint, textObject()->allowTabs(), textPos(), m_toAdd, direction() == RTL, m_dirOverride || styleToUse->visuallyOrdered()),
-                                    IntPoint(m_x + tx, m_y + ty + m_baseline));
-    } else {
-        int sPos, ePos;
+    IntPoint textOrigin(m_x + tx, m_y + ty + m_baseline);
+    TextRun textRun(textObject()->text()->characters() + m_start, m_len, textObject()->allowTabs(), textPos(), m_toAdd, direction() == RTL, m_dirOverride || styleToUse->visuallyOrdered());
+
+    int sPos;
+    int ePos;
+    if (paintSelectedTextOnly || paintSelectedTextSeparately)
         selectionStartEnd(sPos, ePos);
-        if (paintSelectedTextSeparately) {
-            // paint only the text that is not selected
-            if (sPos >= ePos)
-                paintInfo.context->drawText(TextRun(textStr->characters() + m_start, m_len, textObject()->allowTabs(), textPos(), m_toAdd, direction() == RTL, m_dirOverride || styleToUse->visuallyOrdered()),
-                                            IntPoint(m_x + tx, m_y + ty + m_baseline));
-            else {
-                if (sPos - 1 >= 0)
-                    paintInfo.context->drawText(TextRun(textStr->characters() + m_start, m_len, textObject()->allowTabs(), textPos(), m_toAdd, direction() == RTL, m_dirOverride || styleToUse->visuallyOrdered()),
-                                                IntPoint(m_x + tx, m_y + ty + m_baseline),  0, sPos);
-                if (ePos < m_start + m_len)
-                    paintInfo.context->drawText(TextRun(textStr->characters() + m_start, m_len, textObject()->allowTabs(), textPos(), m_toAdd, direction() == RTL, m_dirOverride || styleToUse->visuallyOrdered()),
-                                                IntPoint(m_x + tx, m_y + ty + m_baseline), ePos);
-            }
-        }
 
-        if (sPos < ePos) {
-            // paint only the text that is selected
-            if (selectionStrokeWidth > 0)
-                paintInfo.context->save();
-        
-            updateGraphicsContext(paintInfo.context, selectionFillColor, selectionStrokeColor, selectionStrokeWidth);
-
-            if (selectionTextShadow)
-                paintInfo.context->setShadow(IntSize(selectionTextShadow->x, selectionTextShadow->y),
-                                             selectionTextShadow->blur, selectionTextShadow->color);
-            paintInfo.context->drawText(TextRun(textStr->characters() + m_start, m_len, textObject()->allowTabs(), textPos(), m_toAdd, direction() == RTL, m_dirOverride || styleToUse->visuallyOrdered()),
-                                        IntPoint(m_x + tx, m_y + ty + m_baseline), sPos, ePos);
-            if (selectionTextShadow)
-                paintInfo.context->clearShadow();
-                
-            if (selectionStrokeWidth > 0)
-                paintInfo.context->restore();
-        }
+    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.
+        if (textStrokeWidth > 0)
+            context->save();
+
+        updateGraphicsContext(context, textFillColor, textStrokeColor, textStrokeWidth);
+        if (!paintSelectedTextSeparately) {
+            // FIXME: Truncate right-to-left text correctly.
+            paintTextWithShadows(context, textRun, 0, m_truncation == cNoTruncation ? m_len : m_truncation, textOrigin, m_x + tx, m_y + ty, width(), height(), textShadow, textStrokeWidth > 0);
+        } else
+            paintTextWithShadows(context, textRun, ePos, sPos, textOrigin, m_x + tx, m_y + ty, width(), height(), textShadow, textStrokeWidth > 0);
+
+        if (textStrokeWidth > 0)
+            context->restore();
+    }
+
+    if ((paintSelectedTextOnly || paintSelectedTextSeparately) && sPos < ePos) {
+        // paint only the text that is selected
+        if (selectionStrokeWidth > 0)
+            context->save();
+
+        updateGraphicsContext(context, selectionFillColor, selectionStrokeColor, selectionStrokeWidth);
+        paintTextWithShadows(context, textRun, sPos, ePos, textOrigin, m_x + tx, m_y + ty, width(), height(), selectionShadow, selectionStrokeWidth > 0);
+
+        if (selectionStrokeWidth > 0)
+            context->restore();
     }
 
     // Paint decorations
     if (d != TDNONE && paintInfo.phase != PaintPhaseSelection && styleToUse->htmlHacks()) {
-        paintInfo.context->setStrokeColor(styleToUse->color());
-        paintDecoration(paintInfo.context, tx, ty, d);
+        context->setStrokeColor(styleToUse->color());
+        paintDecoration(context, tx, ty, d, textShadow);
     }
 
     if (paintInfo.phase == PaintPhaseForeground) {
-        paintDocumentMarkers(paintInfo.context, tx, ty, styleToUse, font, false);
+        paintDocumentMarkers(context, tx, ty, styleToUse, font, false);
 
         if (useCustomUnderlines) {
             const Vector<CompositionUnderline>& underlines = object()->document()->frame()->editor()->customCompositionUnderlines();
@@ -449,7 +465,7 @@ void InlineTextBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty)
                 
                 if (underline.startOffset <= end()) {
                     // underline intersects this run.  Paint it.
-                    paintCompositionUnderline(paintInfo.context, tx, ty, underline);
+                    paintCompositionUnderline(context, tx, ty, underline);
                     if (underline.endOffset > end() + 1)
                         // underline also runs into the next run. Bail now, no more marker advancement.
                         break;
@@ -459,12 +475,6 @@ void InlineTextBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty)
             }
         }
     }
-
-    if (setShadow)
-        paintInfo.context->clearShadow();
-        
-    if (textStrokeWidth > 0)
-        paintInfo.context->restore();
 }
 
 void InlineTextBox::selectionStartEnd(int& sPos, int& ePos)
@@ -485,7 +495,7 @@ void InlineTextBox::selectionStartEnd(int& sPos, int& ePos)
     ePos = min(endPos - m_start, (int)m_len);
 }
 
-void InlineTextBox::paintSelection(GraphicsContext* p, int tx, int ty, RenderStyle* style, const Font* f)
+void InlineTextBox::paintSelection(GraphicsContext* context, int tx, int ty, RenderStyle* style, const Font* f)
 {
     // See if we have a selection to paint at all.
     int sPos, ePos;
@@ -503,17 +513,17 @@ void InlineTextBox::paintSelection(GraphicsContext* p, int tx, int ty, RenderSty
     if (textColor == c)
         c = Color(0xff - c.red(), 0xff - c.green(), 0xff - c.blue());
 
-    p->save();
-    updateGraphicsContext(p, c, c, 0);  // Don't draw text at all!
+    context->save();
+    updateGraphicsContext(context, c, c, 0);  // Don't draw text at all!
     int y = selectionTop();
     int h = selectionHeight();
-    p->clip(IntRect(m_x + tx, y + ty, m_width, h));
-    p->drawHighlightForText(TextRun(textObject()->text()->characters() + m_start, m_len, textObject()->allowTabs(), textPos(), m_toAdd, direction() == RTL, m_dirOverride || style->visuallyOrdered()),
+    context->clip(IntRect(m_x + tx, y + ty, m_width, h));
+    context->drawHighlightForText(TextRun(textObject()->text()->characters() + m_start, m_len, textObject()->allowTabs(), textPos(), m_toAdd, direction() == RTL, m_dirOverride || style->visuallyOrdered()),
                             IntPoint(m_x + tx, y + ty), h, c, sPos, ePos);
-    p->restore();
+    context->restore();
 }
 
-void InlineTextBox::paintCompositionBackground(GraphicsContext* p, int tx, int ty, RenderStyle* style, const Font* f, int startPos, int endPos)
+void InlineTextBox::paintCompositionBackground(GraphicsContext* context, int tx, int ty, RenderStyle* style, const Font* f, int startPos, int endPos)
 {
     int offset = m_start;
     int sPos = max(startPos - offset, 0);
@@ -522,17 +532,17 @@ void InlineTextBox::paintCompositionBackground(GraphicsContext* p, int tx, int t
     if (sPos >= ePos)
         return;
 
-    p->save();
+    context->save();
 
     Color c = Color(225, 221, 85);
     
-    updateGraphicsContext(p, c, c, 0); // Don't draw text at all!
+    updateGraphicsContext(context, c, c, 0); // Don't draw text at all!
 
     int y = selectionTop();
     int h = selectionHeight();
-    p->drawHighlightForText(TextRun(textObject()->text()->characters() + m_start, m_len, textObject()->allowTabs(), textPos(), m_toAdd, direction() == RTL, m_dirOverride || style->visuallyOrdered()),
+    context->drawHighlightForText(TextRun(textObject()->text()->characters() + m_start, m_len, textObject()->allowTabs(), textPos(), m_toAdd, direction() == RTL, m_dirOverride || style->visuallyOrdered()),
                             IntPoint(m_x + tx, y + ty), h, c, sPos, ePos);
-    p->restore();
+    context->restore();
 }
 
 #if PLATFORM(MAC)
@@ -555,7 +565,7 @@ void InlineTextBox::paintCustomHighlight(int tx, int ty, const AtomicString& typ
 
 #endif
 
-void InlineTextBox::paintDecoration(GraphicsContext* context, int tx, int ty, int deco)
+void InlineTextBox::paintDecoration(GraphicsContext* context, int tx, int ty, int deco, ShadowData* shadow)
 {
     tx += m_x;
     ty += m_y;
@@ -573,19 +583,60 @@ void InlineTextBox::paintDecoration(GraphicsContext* context, int tx, int ty, in
     // Use a special function for underlines to get the positioning exactly right.
     bool isPrinting = textObject()->document()->printing();
     context->setStrokeThickness(1.0f); // FIXME: We should improve this rule and not always just assume 1.
-    if (deco & UNDERLINE) {
-        context->setStrokeColor(underline);
-        // Leave one pixel of white between the baseline and the underline.
-        context->drawLineForText(IntPoint(tx, ty + m_baseline + 1), width, isPrinting);
-    }
-    if (deco & OVERLINE) {
-        context->setStrokeColor(overline);
-        context->drawLineForText(IntPoint(tx, ty), width, isPrinting);
-    }
-    if (deco & LINE_THROUGH) {
-        context->setStrokeColor(linethrough);
-        context->drawLineForText(IntPoint(tx, ty + 2 * m_baseline / 3), width, isPrinting);
+
+    bool linesAreOpaque = !isPrinting && (!(deco & UNDERLINE) || underline.alpha() == 255) && (!(deco & OVERLINE) || overline.alpha() == 255) && (!(deco & LINE_THROUGH) || linethrough.alpha() == 255);
+
+    bool setClip = false;
+    int extraOffset = 0;
+    if (!linesAreOpaque && shadow && shadow->next) {
+        context->save();
+        IntRect clipRect(tx, ty, width, m_baseline + 2);
+        for (ShadowData* s = shadow; s; s = s->next) {
+            IntRect shadowRect(tx, ty, width, m_baseline + 2);
+            shadowRect.inflate(s->blur);
+            shadowRect.move(s->x, s->y);
+            clipRect.unite(shadowRect);
+            extraOffset = max(extraOffset, max(0, s->y) + s->blur);
+        }
+        context->save();
+        context->clip(clipRect);
+        extraOffset += m_baseline + 2;
+        ty += extraOffset;
+        setClip = true;
     }
+
+    bool setShadow = false;
+    do {
+        if (shadow) {
+            if (!shadow->next) {
+                // The last set of lines paints normally inside the clip.
+                ty -= extraOffset;
+                extraOffset = 0;
+            }
+            context->setShadow(IntSize(shadow->x, shadow->y - extraOffset), shadow->blur, shadow->color);
+            setShadow = true;
+            shadow = shadow->next;
+        }
+
+        if (deco & UNDERLINE) {
+            context->setStrokeColor(underline);
+            // Leave one pixel of white between the baseline and the underline.
+            context->drawLineForText(IntPoint(tx, ty + m_baseline + 1), width, isPrinting);
+        }
+        if (deco & OVERLINE) {
+            context->setStrokeColor(overline);
+            context->drawLineForText(IntPoint(tx, ty), width, isPrinting);
+        }
+        if (deco & LINE_THROUGH) {
+            context->setStrokeColor(linethrough);
+            context->drawLineForText(IntPoint(tx, ty + 2 * m_baseline / 3), width, isPrinting);
+        }
+    } while (shadow);
+
+    if (setClip)
+        context->restore();
+    else if (setShadow)
+        context->clearShadow();
 }
 
 void InlineTextBox::paintSpellingOrGrammarMarker(GraphicsContext* pt, int tx, int ty, DocumentMarker marker, RenderStyle* style, const Font* f, bool grammar)
index f6fa7da..d8a250b 100644 (file)
@@ -97,16 +97,6 @@ public:
     virtual bool isText() const { return m_treatAsText; }
     void setIsText(bool b) { m_treatAsText = b; }
 
-    void paintDecoration(GraphicsContext*, int tx, int ty, int decoration);
-    void paintSelection(GraphicsContext*, int tx, int ty, RenderStyle*, const Font*);
-    void paintCompositionBackground(GraphicsContext*, int tx, int ty, RenderStyle*, const Font*, int startPos, int endPos);
-    void paintDocumentMarkers(GraphicsContext*, int tx, int ty, RenderStyle*, const Font*, bool background);
-    void paintSpellingOrGrammarMarker(GraphicsContext*, int tx, int ty, DocumentMarker, RenderStyle*, const Font*, bool grammar);
-    void paintTextMatchMarker(GraphicsContext*, int tx, int ty, DocumentMarker, RenderStyle*, const Font*);
-    void paintCompositionUnderline(GraphicsContext*, int tx, int ty, const CompositionUnderline&);
-#if PLATFORM(MAC)
-    void paintCustomHighlight(int tx, int ty, const AtomicString& type);
-#endif
     virtual int caretMinOffset() const;
     virtual int caretMaxOffset() const;
     virtual unsigned caretMaxRenderedOffset() const;
@@ -123,7 +113,19 @@ public:
     unsigned short m_truncation; // Where to truncate when text overflow is applied.  We use special constants to
                       // denote no truncation (the whole run paints) and full truncation (nothing paints at all).
 
+protected:
+    void paintCompositionBackground(GraphicsContext*, int tx, int ty, RenderStyle*, const Font*, int startPos, int endPos);
+    void paintDocumentMarkers(GraphicsContext*, int tx, int ty, RenderStyle*, const Font*, bool background);
+    void paintCompositionUnderline(GraphicsContext*, int tx, int ty, const CompositionUnderline&);
+#if PLATFORM(MAC)
+    void paintCustomHighlight(int tx, int ty, const AtomicString& type);
+#endif
+
 private:
+    void paintDecoration(GraphicsContext*, int tx, int ty, int decoration, ShadowData* shadow);
+    void paintSelection(GraphicsContext*, int tx, int ty, RenderStyle*, const Font*);
+    void paintSpellingOrGrammarMarker(GraphicsContext*, int tx, int ty, DocumentMarker, RenderStyle*, const Font*, bool grammar);
+    void paintTextMatchMarker(GraphicsContext*, int tx, int ty, DocumentMarker, RenderStyle*, const Font*);
     friend class RenderText;
 };
 
index 28e9caf..bb38177 100644 (file)
@@ -377,9 +377,10 @@ void RenderBlock::removeChild(RenderObject *oldChild)
 int RenderBlock::overflowHeight(bool includeInterior) const
 {
     if (!includeInterior && hasOverflowClip()) {
-        if (ShadowData* boxShadow = style()->boxShadow())
-            return m_height + max(boxShadow->y + boxShadow->blur, 0);
-        return m_height;
+        int shadowHeight = 0;
+        for (ShadowData* boxShadow = style()->boxShadow(); boxShadow; boxShadow = boxShadow->next)
+            shadowHeight = max(boxShadow->y + boxShadow->blur, shadowHeight);
+        return m_height + shadowHeight;
     }
     return m_overflowHeight;
 }
@@ -387,9 +388,10 @@ int RenderBlock::overflowHeight(bool includeInterior) const
 int RenderBlock::overflowWidth(bool includeInterior) const
 {
     if (!includeInterior && hasOverflowClip()) {
-        if (ShadowData* boxShadow = style()->boxShadow())
-            return m_width + max(boxShadow->x + boxShadow->blur, 0);
-        return m_width;
+        int shadowWidth = 0;
+        for (ShadowData* boxShadow = style()->boxShadow(); boxShadow; boxShadow = boxShadow->next)
+            shadowWidth = max(boxShadow->x + boxShadow->blur, shadowWidth);
+        return m_width + shadowWidth;
     }
     return m_overflowWidth;
 }
@@ -397,9 +399,10 @@ int RenderBlock::overflowWidth(bool includeInterior) const
 int RenderBlock::overflowLeft(bool includeInterior) const
 {
     if (!includeInterior && hasOverflowClip()) {
-        if (ShadowData* boxShadow = style()->boxShadow())
-            return min(boxShadow->x - boxShadow->blur, 0);
-        return 0;
+        int shadowLeft = 0;
+        for (ShadowData* boxShadow = style()->boxShadow(); boxShadow; boxShadow = boxShadow->next)
+            shadowLeft = min(boxShadow->x - boxShadow->blur, shadowLeft);
+        return shadowLeft;
     }
     return m_overflowLeft;
 }
@@ -407,9 +410,10 @@ int RenderBlock::overflowLeft(bool includeInterior) const
 int RenderBlock::overflowTop(bool includeInterior) const
 {
     if (!includeInterior && hasOverflowClip()) {
-        if (ShadowData* boxShadow = style()->boxShadow())
-            return min(boxShadow->y - boxShadow->blur, 0);
-        return 0;
+        int shadowTop = 0;
+        for (ShadowData* boxShadow = style()->boxShadow(); boxShadow; boxShadow = boxShadow->next)
+            shadowTop = min(boxShadow->y - boxShadow->blur, shadowTop);
+        return shadowTop;
     }
     return m_overflowTop;
 }
@@ -418,15 +422,21 @@ IntRect RenderBlock::overflowRect(bool includeInterior) const
 {
     if (!includeInterior && hasOverflowClip()) {
         IntRect box = borderBox();
-        if (ShadowData* boxShadow = style()->boxShadow()) {
-            int shadowLeft = min(boxShadow->x - boxShadow->blur, 0);
-            int shadowRight = max(boxShadow->x + boxShadow->blur, 0);
-            int shadowTop = min(boxShadow->y - boxShadow->blur, 0);
-            int shadowBottom = max(boxShadow->y + boxShadow->blur, 0);
-            box.move(shadowLeft, shadowTop);
-            box.setWidth(box.width() - shadowLeft + shadowRight);
-            box.setHeight(box.height() - shadowTop + shadowBottom);
+        int shadowLeft = 0;
+        int shadowRight = 0;
+        int shadowTop = 0;
+        int shadowBottom = 0;
+
+        for (ShadowData* boxShadow = style()->boxShadow(); boxShadow; boxShadow = boxShadow->next) {
+            shadowLeft = min(boxShadow->x - boxShadow->blur, shadowLeft);
+            shadowRight = max(boxShadow->x + boxShadow->blur, shadowRight);
+            shadowTop = min(boxShadow->y - boxShadow->blur, shadowTop);
+            shadowBottom = max(boxShadow->y + boxShadow->blur, shadowBottom);
         }
+
+        box.move(shadowLeft, shadowTop);
+        box.setWidth(box.width() - shadowLeft + shadowRight);
+        box.setHeight(box.height() - shadowTop + shadowBottom);
         return box;
     }
 
@@ -636,7 +646,7 @@ void RenderBlock::layoutBlock(bool relayoutChildren)
     m_overflowHeight = max(m_overflowHeight, m_height);
 
     if (!hasOverflowClip()) {
-        if (ShadowData* boxShadow = style()->boxShadow()) {
+        for (ShadowData* boxShadow = style()->boxShadow(); boxShadow; boxShadow = boxShadow->next) {
             m_overflowLeft = min(m_overflowLeft, boxShadow->x - boxShadow->blur);
             m_overflowWidth = max(m_overflowWidth, m_width + boxShadow->x + boxShadow->blur);
             m_overflowTop = min(m_overflowTop, boxShadow->y - boxShadow->blur);
index 13d6d91..f83c742 100644 (file)
@@ -289,7 +289,7 @@ void RenderFlexibleBox::layoutBlock(bool relayoutChildren)
         m_overflowWidth = m_width;
 
     if (!hasOverflowClip()) {
-        if (ShadowData* boxShadow = style()->boxShadow()) {
+        for (ShadowData* boxShadow = style()->boxShadow(); boxShadow; boxShadow = boxShadow->next) {
             m_overflowLeft = min(m_overflowLeft, boxShadow->x - boxShadow->blur);
             m_overflowWidth = max(m_overflowWidth, m_width + boxShadow->x + boxShadow->blur);
             m_overflowTop = min(m_overflowTop, boxShadow->y - boxShadow->blur);
index 1db15d5..86248ff 100644 (file)
@@ -1934,11 +1934,15 @@ void RenderLayer::calculateRects(const RenderLayer* rootLayer, const IntRect& pa
         // If we establish a clip at all, then go ahead and make sure our background
         // rect is intersected with our layer's bounds.
         if (ShadowData* boxShadow = renderer()->style()->boxShadow()) {
-            IntRect shadowRect = layerBounds;
-            shadowRect.move(boxShadow->x, boxShadow->y);
-            shadowRect.inflate(boxShadow->blur);
-            shadowRect.unite(layerBounds);
-            backgroundRect.intersect(shadowRect);
+            IntRect overflow = layerBounds;
+            do {
+                IntRect shadowRect = layerBounds;
+                shadowRect.move(boxShadow->x, boxShadow->y);
+                shadowRect.inflate(boxShadow->blur);
+                overflow.unite(shadowRect);
+                boxShadow = boxShadow->next;
+            } while (boxShadow);
+            backgroundRect.intersect(overflow);
         } else
             backgroundRect.intersect(layerBounds);
     }
index 8b1fb44..5f65c4e 100644 (file)
@@ -1635,26 +1635,45 @@ void RenderObject::paintBorder(GraphicsContext* graphicsContext, int tx, int ty,
 
 void RenderObject::paintBoxShadow(GraphicsContext* context, int tx, int ty, int w, int h, const RenderStyle* s, bool begin, bool end)
 {
-    if (!s->boxShadow())
-        return;
-    
     // FIXME: Deal with border-image.  Would be great to use border-image as a mask.
-    context->save();
-    context->setShadow(IntSize(s->boxShadow()->x, s->boxShadow()->y),
-                               s->boxShadow()->blur, s->boxShadow()->color);
+
     IntRect rect(tx, ty, w, h);
-    if (s->hasBorderRadius()) {
-        IntSize topLeft = begin ? s->borderTopLeftRadius() : IntSize();
-        IntSize topRight = end ? s->borderTopRightRadius() : IntSize();
-        IntSize bottomLeft = begin ? s->borderBottomLeftRadius() : IntSize();
-        IntSize bottomRight = end ? s->borderBottomRightRadius() : IntSize();
-        context->clipOutRoundedRect(rect, topLeft, topRight, bottomLeft, bottomRight);
-        context->fillRoundedRect(rect, topLeft, topRight, bottomLeft, bottomRight, Color::black);
-    } else {
-        context->clipOut(rect);
-        context->fillRect(IntRect(tx, ty, w, h), Color::black);
+    bool hasBorderRadius = s->hasBorderRadius();
+    bool hasOpaqueBackground = s->backgroundColor().isValid() && s->backgroundColor().alpha() == 255;
+    for (ShadowData* shadow = s->boxShadow(); shadow; shadow = shadow->next) {
+        context->save();
+
+        IntSize shadowOffset(shadow->x, shadow->y);
+        int shadowBlur = shadow->blur;
+        IntRect fillRect(rect);
+
+        if (hasBorderRadius) {
+            IntRect shadowRect(rect);
+            shadowRect.inflate(shadowBlur);
+            shadowRect.move(shadowOffset);
+            context->clip(shadowRect);
+
+            IntSize extraOffset(w + max(0, shadowOffset.width()) + shadowBlur, 0);
+            shadowOffset -= extraOffset;
+            fillRect.move(extraOffset);
+        }
+
+        context->setShadow(shadowOffset, shadowBlur, shadow->color);
+        if (hasBorderRadius) {
+            IntSize topLeft = begin ? s->borderTopLeftRadius() : IntSize();
+            IntSize topRight = end ? s->borderTopRightRadius() : IntSize();
+            IntSize bottomLeft = begin ? s->borderBottomLeftRadius() : IntSize();
+            IntSize bottomRight = end ? s->borderBottomRightRadius() : IntSize();
+            if (!hasOpaqueBackground)
+                context->clipOutRoundedRect(rect, topLeft, topRight, bottomLeft, bottomRight);
+            context->fillRoundedRect(fillRect, topLeft, topRight, bottomLeft, bottomRight, Color::black);
+        } else {
+            if (!hasOpaqueBackground)
+                context->clipOut(rect);
+            context->fillRect(fillRect, Color::black);
+        }
+        context->restore();
     }
-    context->restore();
 }
 
 void RenderObject::addLineBoxRects(Vector<IntRect>&, unsigned startOffset, unsigned endOffset, bool useSelectionHeight)
@@ -1887,7 +1906,10 @@ bool RenderObject::repaintAfterLayoutIfNeeded(const IntRect& oldBounds, const In
     ShadowData* boxShadow = style()->boxShadow();
     int width = abs(newOutlineBox.width() - oldOutlineBox.width());
     if (width) {
-        int shadowRight = boxShadow ? max(boxShadow->x + boxShadow->blur, 0) : 0;
+        int shadowRight = 0;
+        for (ShadowData* shadow = boxShadow; shadow; shadow = shadow->next)
+            shadowRight = max(shadow->x + shadow->blur, shadowRight);
+
         int borderWidth = max(-outlineStyle->outlineOffset(), max(borderRight(), max(style()->borderTopRightRadius().width(), style()->borderBottomRightRadius().width()))) + max(ow, shadowRight);
         IntRect rightRect(newOutlineBox.x() + min(newOutlineBox.width(), oldOutlineBox.width()) - borderWidth,
             newOutlineBox.y(),
@@ -1901,7 +1923,10 @@ bool RenderObject::repaintAfterLayoutIfNeeded(const IntRect& oldBounds, const In
     }
     int height = abs(newOutlineBox.height() - oldOutlineBox.height());
     if (height) {
-        int shadowBottom = boxShadow ? max(boxShadow->y + boxShadow->blur, 0) : 0;
+        int shadowBottom = 0;
+        for (ShadowData* shadow = boxShadow; shadow; shadow = shadow->next)
+            shadowBottom = max(shadow->y + shadow->blur, shadowBottom);
+
         int borderHeight = max(-outlineStyle->outlineOffset(), max(borderBottom(), max(style()->borderBottomLeftRadius().height(), style()->borderBottomRightRadius().height()))) + max(ow, shadowBottom);
         IntRect bottomRect(newOutlineBox.x(),
             min(newOutlineBox.bottom(), oldOutlineBox.bottom()) - borderHeight,
@@ -2014,17 +2039,17 @@ Color RenderObject::selectionBackgroundColor() const
 Color RenderObject::selectionForegroundColor() const
 {
     Color color;
-    if (style()->userSelect() != SELECT_NONE) {
-        RenderStyle* pseudoStyle = getPseudoStyle(RenderStyle::SELECTION);
-        if (pseudoStyle) {
-            color = pseudoStyle->textFillColor();
-            if (!color.isValid())
-                color = pseudoStyle->color();
-        } else
-            color = document()->frame()->selectionController()->isFocusedAndActive() ?
-                    theme()->platformActiveSelectionForegroundColor() :
-                    theme()->platformInactiveSelectionForegroundColor();
-    }
+    if (style()->userSelect() == SELECT_NONE)
+        return color;
+
+    if (RenderStyle* pseudoStyle = getPseudoStyle(RenderStyle::SELECTION)) {
+        color = pseudoStyle->textFillColor();
+        if (!color.isValid())
+            color = pseudoStyle->color();
+    } else
+        color = document()->frame()->selectionController()->isFocusedAndActive() ?
+                theme()->platformActiveSelectionForegroundColor() :
+                theme()->platformInactiveSelectionForegroundColor();
 
     return color;
 }
@@ -3002,10 +3027,20 @@ void RenderObject::adjustRectForOutlineAndShadow(IntRect& rect) const
 {
     int outlineSize = !isInline() && continuation() ? continuation()->style()->outlineSize() : style()->outlineSize();
     if (ShadowData* boxShadow = style()->boxShadow()) {
-        int shadowLeft = min(boxShadow->x - boxShadow->blur - outlineSize, 0);
-        int shadowRight = max(boxShadow->x + boxShadow->blur + outlineSize, 0);
-        int shadowTop = min(boxShadow->y - boxShadow->blur - outlineSize, 0);
-        int shadowBottom = max(boxShadow->y + boxShadow->blur + outlineSize, 0);
+        int shadowLeft = 0;
+        int shadowRight = 0;
+        int shadowTop = 0;
+        int shadowBottom = 0;
+
+        do {
+            shadowLeft = min(boxShadow->x - boxShadow->blur - outlineSize, shadowLeft);
+            shadowRight = max(boxShadow->x + boxShadow->blur + outlineSize, shadowRight);
+            shadowTop = min(boxShadow->y - boxShadow->blur - outlineSize, shadowTop);
+            shadowBottom = max(boxShadow->y + boxShadow->blur + outlineSize, shadowBottom);
+
+            boxShadow = boxShadow->next;
+        } while (boxShadow);
+
         rect.move(shadowLeft, shadowTop);
         rect.setWidth(rect.width() - shadowLeft + shadowRight);
         rect.setHeight(rect.height() - shadowTop + shadowBottom);
index 91e90f4..6e4ac76 100644 (file)
@@ -304,21 +304,21 @@ void RenderReplaced::setIntrinsicSize(const IntSize& size)
 
 void RenderReplaced::adjustOverflowForBoxShadow()
 {
-    if (ShadowData* boxShadow = style()->boxShadow()) {
-        if (!gOverflowRectMap)
-            gOverflowRectMap = new OverflowRectMap();
-
+    IntRect overflow;
+    for (ShadowData* boxShadow = style()->boxShadow(); boxShadow; boxShadow = boxShadow->next) {
         IntRect shadow = borderBox();
         shadow.move(boxShadow->x, boxShadow->y);
         shadow.inflate(boxShadow->blur);
-        shadow.unite(borderBox());
-
-        gOverflowRectMap->set(this, shadow);
-        m_hasOverflow = true;
-        return;
+        overflow.unite(shadow);
     }
 
-    if (m_hasOverflow) {
+    if (!overflow.isEmpty()) {
+        if (!gOverflowRectMap)
+            gOverflowRectMap = new OverflowRectMap();
+        overflow.unite(borderBox());
+        gOverflowRectMap->set(this, overflow);
+        m_hasOverflow = true;
+    } else if (m_hasOverflow) {
         gOverflowRectMap->remove(this);
         m_hasOverflow = false;
     }
index 5abfcf5..c72210e 100644 (file)
@@ -1763,9 +1763,8 @@ void RenderStyle::setTextShadow(ShadowData* val, bool add)
         return;
     }
 
-    ShadowData* last = rareData->textShadow;
-    while (last->next) last = last->next;
-    last->next = val;
+    val->next = rareData->textShadow;
+    rareData->textShadow = val;
 }
 
 void RenderStyle::setBoxShadow(ShadowData* val, bool add)
@@ -1777,9 +1776,8 @@ void RenderStyle::setBoxShadow(ShadowData* val, bool add)
         return;
     }
 
-    ShadowData* last = rareData->m_boxShadow;
-    while (last->next) last = last->next;
-    last->next = val;
+    val->next = rareData->m_boxShadow;
+    rareData->m_boxShadow = val;
 }
 
 ShadowData::ShadowData(const ShadowData& o)
index 35681a3..9db648b 100644 (file)
@@ -408,7 +408,7 @@ void RenderTable::layout()
     layoutPositionedObjects(true);
 
     if (!hasOverflowClip()) {
-        if (ShadowData* boxShadow = style()->boxShadow()) {
+        for (ShadowData* boxShadow = style()->boxShadow(); boxShadow; boxShadow = boxShadow->next) {
             m_overflowLeft = min(m_overflowLeft, boxShadow->x - boxShadow->blur);
             m_overflowWidth = max(m_overflowWidth, m_width + boxShadow->x + boxShadow->blur);
             m_overflowTop = min(m_overflowTop, boxShadow->y - boxShadow->blur);