+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.
--- /dev/null
+<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>
--- /dev/null
+<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;"> multiple </span> shadows
+</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>
--- /dev/null
+<!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;"> multiple </span> shadows
+</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>
--- /dev/null
+<!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;"> multiple </span> shadows
+</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>
--- /dev/null
+<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;"> multiple </span> shadows
+</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>
--- /dev/null
+aba5acb31e4f0ff432b5a137eb4d35aa
\ No newline at end of file
--- /dev/null
+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
--- /dev/null
+1922b1893f2eada6115a4df2954b69e2
\ No newline at end of file
--- /dev/null
+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
--- /dev/null
+99ff166ca02c29dfa285c4f67ea4a71c
\ No newline at end of file
--- /dev/null
+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
--- /dev/null
+0924727a55c3f9468d946c5f00f87694
\ No newline at end of file
--- /dev/null
+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
--- /dev/null
+b0e494de9eefbc07ebd513ec65bfa171
\ No newline at end of file
--- /dev/null
+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
+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
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();
}
m_values.append(val);
}
+void CSSValueList::prepend(PassRefPtr<CSSValue> val)
+{
+ m_values.prepend(val);
+}
+
String CSSValueList::cssText() const
{
String result = "";
virtual unsigned short cssValueType() const;
void append(PassRefPtr<CSSValue>);
+ void prepend(PassRefPtr<CSSValue>);
virtual String cssText() const;
protected:
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);
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();
{
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) {
}
}
- // 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();
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();
}
}
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 ||
// 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();
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).
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)
selectionStrokeWidth = strokeWidth;
}
- Color stroke = pseudoStyle->textStrokeColor();
+ Color stroke = paintInfo.forceBlackText ? Color::black : pseudoStyle->textStrokeColor();
if (!stroke.isValid())
stroke = pseudoStyle->color();
if (stroke != selectionStrokeColor) {
}
}
- 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();
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;
}
}
}
-
- if (setShadow)
- paintInfo.context->clearShadow();
-
- if (textStrokeWidth > 0)
- paintInfo.context->restore();
}
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;
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);
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)
#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;
// 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)
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;
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;
};
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;
}
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;
}
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;
}
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;
}
{
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;
}
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);
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);
// 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);
}
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)
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(),
}
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,
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;
}
{
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);
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;
}
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)
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)
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);