Box-shadow spread radius does not transition or animate correctly with CSS Transition...
authorsimon.fraser@apple.com <simon.fraser@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 7 Nov 2019 00:39:24 +0000 (00:39 +0000)
committersimon.fraser@apple.com <simon.fraser@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 7 Nov 2019 00:39:24 +0000 (00:39 +0000)
https://bugs.webkit.org/show_bug.cgi?id=202489

Reviewed by Zalan Bujtas.
Source/WebCore:

Fix box-shadow offset and spread to support subpixel values, and make the rendering subpixel-aware.
This also makes animation of shadow spread and offset be smoother on Retina displays.

Also make ShadowStyle an enum class.

Test: fast/box-shadow/hidpi-box-shadow.html

* css/CSSComputedStyleDeclaration.cpp:
(WebCore::ComputedStyleExtractor::valueForShadow):
(WebCore::ComputedStyleExtractor::valueForFilter):
* css/CSSPrimitiveValue.cpp:
(WebCore::CSSPrimitiveValue::computeLength const):
* page/animation/CSSPropertyAnimation.cpp:
(WebCore::blendFunc):
(WebCore::shadowForBlending):
* platform/animation/AnimationUtilities.h:
(WebCore::blend):
* platform/graphics/RoundedRect.h:
* rendering/InlineFlowBox.cpp:
(WebCore::InlineFlowBox::paintBoxDecorations):
* rendering/RenderBox.cpp:
(WebCore::RenderBox::paintBoxDecorations):
* rendering/RenderBoxModelObject.cpp:
(WebCore::applyBoxShadowForBackground):
(WebCore::RenderBoxModelObject::boxShadowShouldBeAppliedToBackground const):
(WebCore::areaCastingShadowInHole):
(WebCore::RenderBoxModelObject::paintBoxShadow):
Move the snapping until after we've adjusted rects for offset and spread. The "extraOffset"
computation makes the snapping a little more complex; we have to snap before and after applying
shadowOffset, and give to GraphicsContext the delta between the snapped values.
* rendering/RenderTable.cpp:
(WebCore::RenderTable::paintBoxDecorations):
* rendering/RenderTableCell.cpp:
(WebCore::RenderTableCell::paintBoxDecorations):
* rendering/style/RenderStyle.cpp:
(WebCore::RenderStyle::setTextShadow):
(WebCore::RenderStyle::getShadowExtent const):
(WebCore::RenderStyle::getShadowInsetExtent const):
(WebCore::RenderStyle::getShadowHorizontalExtent const):
(WebCore::RenderStyle::getShadowVerticalExtent const):
* rendering/style/ShadowData.cpp:
(WebCore::ShadowData::ShadowData):
(WebCore::calculateShadowExtent):
(WebCore::ShadowData::adjustRectForShadow const):
* rendering/style/ShadowData.h:
(WebCore::ShadowData::ShadowData):
(WebCore::ShadowData::x const):
(WebCore::ShadowData::y const):
(WebCore::ShadowData::location const):
(WebCore::ShadowData::paintingExtent const):
(WebCore::ShadowData::spread const):
* style/StyleBuilderCustom.h:
(WebCore::Style::BuilderCustom::applyTextOrBoxShadowValue):

LayoutTests:

* fast/box-shadow/hidpi-box-shadow-expected.html: Added.
* fast/box-shadow/hidpi-box-shadow.html: Added.

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

19 files changed:
LayoutTests/ChangeLog
LayoutTests/fast/box-shadow/hidpi-box-shadow-expected.html [new file with mode: 0644]
LayoutTests/fast/box-shadow/hidpi-box-shadow.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/css/CSSComputedStyleDeclaration.cpp
Source/WebCore/css/CSSPrimitiveValue.cpp
Source/WebCore/page/animation/CSSPropertyAnimation.cpp
Source/WebCore/platform/animation/AnimationUtilities.h
Source/WebCore/platform/graphics/RoundedRect.h
Source/WebCore/rendering/InlineFlowBox.cpp
Source/WebCore/rendering/RenderBox.cpp
Source/WebCore/rendering/RenderBoxModelObject.cpp
Source/WebCore/rendering/RenderTable.cpp
Source/WebCore/rendering/RenderTableCell.cpp
Source/WebCore/rendering/style/RenderStyle.cpp
Source/WebCore/rendering/style/ShadowData.cpp
Source/WebCore/rendering/style/ShadowData.h
Source/WebCore/style/StyleBuilderCustom.h
Tools/TestWebKitAPI/Tests/mac/FontManagerTests.mm

index ce5b661..258ae4f 100644 (file)
         https://bugs.webkit.org/show_bug.cgi?id=203089
         https://trac.webkit.org/changeset/251993
 
+2019-11-06  Simon Fraser  <simon.fraser@apple.com>
+
+        Box-shadow spread radius does not transition or animate correctly with CSS Transitions & Animations
+        https://bugs.webkit.org/show_bug.cgi?id=202489
+
+        Reviewed by Zalan Bujtas.
+
+        * fast/box-shadow/hidpi-box-shadow-expected.html: Added.
+        * fast/box-shadow/hidpi-box-shadow.html: Added.
+
 2019-11-04  Chris Dumez  <cdumez@apple.com>
 
         MediaRecorder should not prevent entering the back/forward cache
diff --git a/LayoutTests/fast/box-shadow/hidpi-box-shadow-expected.html b/LayoutTests/fast/box-shadow/hidpi-box-shadow-expected.html
new file mode 100644 (file)
index 0000000..7de059e
--- /dev/null
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<html>
+<head>
+<style>
+    .container {
+        position: relative;
+        width: 30px;
+        height: 30px;
+        margin: 20px;
+        border: 1px solid silver;
+    }
+
+    .box {
+        position: absolute;
+        background-color: gray;
+    }
+
+    .shadow {
+        position: absolute;
+        background-color: blue;
+    }
+    </style>
+</head>
+<body>
+    <div class="container">
+        <div class="shadow" style="left: 0; top: 0; width: 12px; height: 12px;"></div>
+        <div class="box" style="left: 1px; top: 1px; width: 10px; height: 10px;"></div>
+    </div>
+
+    <div class="container">
+        <div class="shadow" style="left: 0.5px; top: 0.5px; width: 11px; height: 11px;"></div>
+        <div class="box" style="left: 1px; top: 1px; width: 10px; height: 10px;"></div>
+    </div>
+
+    <div class="container">
+        <div class="shadow" style="left: 0.5px; top: 0.5px; width: 11.5px; height: 11.5px;"></div>
+        <div class="box" style="left: 1px; top: 1px; width: 10.5px; height: 10.5px;"></div>
+    </div>
+
+</body>
+</html>
diff --git a/LayoutTests/fast/box-shadow/hidpi-box-shadow.html b/LayoutTests/fast/box-shadow/hidpi-box-shadow.html
new file mode 100644 (file)
index 0000000..1f6f935
--- /dev/null
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html>
+<head>
+<style>
+    .container {
+        position: relative;
+        width: 30px;
+        height: 30px;
+        margin: 20px;
+        border: 1px solid silver;
+    }
+
+    .box {
+        position: absolute;
+        background-color: gray;
+    }
+    </style>
+</head>
+<body>
+    <div class="container">
+        <div class="box" style="left: 1px; top: 1px; width: 10px; height: 10px; box-shadow: 0 0 0 1px blue;"></div>
+    </div>
+
+    <div class="container">
+        <div class="box" style="left: 1px; top: 1px; width: 10px; height: 10px; box-shadow: 0 0 0 0.5px blue"></div>
+    </div>
+
+    <div class="container">
+        <div class="box" style="left: 1px; top: 1px; width: 10.5px; height: 10.5px; box-shadow: 0 0 0 0.5px blue"></div>
+    </div>
+
+</body>
+</html>
index 3305165..a19fa5d 100644 (file)
         (WebCore::WebAnimation::hasPendingActivity const):
         * animation/WebAnimation.h:
 
+2019-11-06  Simon Fraser  <simon.fraser@apple.com>
+
+        Box-shadow spread radius does not transition or animate correctly with CSS Transitions & Animations
+        https://bugs.webkit.org/show_bug.cgi?id=202489
+
+        Reviewed by Zalan Bujtas.
+        
+        Fix box-shadow offset and spread to support subpixel values, and make the rendering subpixel-aware.
+        This also makes animation of shadow spread and offset be smoother on Retina displays.
+
+        Also make ShadowStyle an enum class.
+
+        Test: fast/box-shadow/hidpi-box-shadow.html
+
+        * css/CSSComputedStyleDeclaration.cpp:
+        (WebCore::ComputedStyleExtractor::valueForShadow):
+        (WebCore::ComputedStyleExtractor::valueForFilter):
+        * css/CSSPrimitiveValue.cpp:
+        (WebCore::CSSPrimitiveValue::computeLength const):
+        * page/animation/CSSPropertyAnimation.cpp:
+        (WebCore::blendFunc):
+        (WebCore::shadowForBlending):
+        * platform/animation/AnimationUtilities.h:
+        (WebCore::blend):
+        * platform/graphics/RoundedRect.h:
+        * rendering/InlineFlowBox.cpp:
+        (WebCore::InlineFlowBox::paintBoxDecorations):
+        * rendering/RenderBox.cpp:
+        (WebCore::RenderBox::paintBoxDecorations):
+        * rendering/RenderBoxModelObject.cpp:
+        (WebCore::applyBoxShadowForBackground):
+        (WebCore::RenderBoxModelObject::boxShadowShouldBeAppliedToBackground const):
+        (WebCore::areaCastingShadowInHole):
+        (WebCore::RenderBoxModelObject::paintBoxShadow):
+        Move the snapping until after we've adjusted rects for offset and spread. The "extraOffset"
+        computation makes the snapping a little more complex; we have to snap before and after applying
+        shadowOffset, and give to GraphicsContext the delta between the snapped values.
+        * rendering/RenderTable.cpp:
+        (WebCore::RenderTable::paintBoxDecorations):
+        * rendering/RenderTableCell.cpp:
+        (WebCore::RenderTableCell::paintBoxDecorations):
+        * rendering/style/RenderStyle.cpp:
+        (WebCore::RenderStyle::setTextShadow):
+        (WebCore::RenderStyle::getShadowExtent const):
+        (WebCore::RenderStyle::getShadowInsetExtent const):
+        (WebCore::RenderStyle::getShadowHorizontalExtent const):
+        (WebCore::RenderStyle::getShadowVerticalExtent const):
+        * rendering/style/ShadowData.cpp:
+        (WebCore::ShadowData::ShadowData):
+        (WebCore::calculateShadowExtent):
+        (WebCore::ShadowData::adjustRectForShadow const):
+        * rendering/style/ShadowData.h:
+        (WebCore::ShadowData::ShadowData):
+        (WebCore::ShadowData::x const):
+        (WebCore::ShadowData::y const):
+        (WebCore::ShadowData::location const):
+        (WebCore::ShadowData::paintingExtent const):
+        (WebCore::ShadowData::spread const):
+        * style/StyleBuilderCustom.h:
+        (WebCore::Style::BuilderCustom::applyTextOrBoxShadowValue):
+
 2019-11-04  Chris Dumez  <cdumez@apple.com>
 
         MediaRecorder should not prevent entering the back/forward cache
index d2ac885..f654c7c 100644 (file)
@@ -613,7 +613,7 @@ Ref<CSSValue> ComputedStyleExtractor::valueForShadow(const ShadowData* shadow, C
         auto y = adjustLengthForZoom(currShadowData->y(), style, adjust);
         auto blur = adjustLengthForZoom(currShadowData->radius(), style, adjust);
         auto spread = propertyID == CSSPropertyTextShadow ? RefPtr<CSSPrimitiveValue>() : adjustLengthForZoom(currShadowData->spread(), style, adjust);
-        auto style = propertyID == CSSPropertyTextShadow || currShadowData->style() == Normal ? RefPtr<CSSPrimitiveValue>() : cssValuePool.createIdentifierValue(CSSValueInset);
+        auto style = propertyID == CSSPropertyTextShadow || currShadowData->style() == ShadowStyle::Normal ? RefPtr<CSSPrimitiveValue>() : cssValuePool.createIdentifierValue(CSSValueInset);
         auto color = cssValuePool.createColorValue(currShadowData->color());
         list->prepend(CSSShadowValue::create(WTFMove(x), WTFMove(y), WTFMove(blur), WTFMove(spread), WTFMove(style), WTFMove(color)));
     }
@@ -691,7 +691,7 @@ Ref<CSSValue> ComputedStyleExtractor::valueForFilter(const RenderStyle& style, c
                 DropShadowFilterOperation& dropShadowOperation = downcast<DropShadowFilterOperation>(filterOperation);
                 filterValue = CSSFunctionValue::create(CSSValueDropShadow);
                 // We want our computed style to look like that of a text shadow (has neither spread nor inset style).
-                ShadowData shadowData = ShadowData(dropShadowOperation.location(), dropShadowOperation.stdDeviation(), 0, Normal, false, dropShadowOperation.color());
+                ShadowData shadowData = ShadowData(dropShadowOperation.location(), dropShadowOperation.stdDeviation(), 0, ShadowStyle::Normal, false, dropShadowOperation.color());
                 filterValue->append(valueForShadow(&shadowData, CSSPropertyTextShadow, style, adjust));
                 break;
             }
index 7fafa72..38fd6da 100644 (file)
@@ -596,6 +596,11 @@ template<> double CSSPrimitiveValue::computeLength(const CSSToLengthConversionDa
     return computeLengthDouble(conversionData);
 }
 
+template<> LayoutUnit CSSPrimitiveValue::computeLength(const CSSToLengthConversionData& conversionData) const
+{
+    return LayoutUnit(computeLengthDouble(conversionData));
+}
+
 double CSSPrimitiveValue::computeLengthDouble(const CSSToLengthConversionData& conversionData) const
 {
     if (m_primitiveUnitType == CSS_CALC)
index 5991bf7..a4421cc 100644 (file)
@@ -107,10 +107,10 @@ static inline ShadowStyle blendFunc(const CSSPropertyBlendingClient* anim, Shado
     if (from == to)
         return to;
 
-    double fromVal = from == Normal ? 1 : 0;
-    double toVal = to == Normal ? 1 : 0;
+    double fromVal = from == ShadowStyle::Normal ? 1 : 0;
+    double toVal = to == ShadowStyle::Normal ? 1 : 0;
     double result = blendFunc(anim, fromVal, toVal, progress);
-    return result > 0 ? Normal : Inset;
+    return result > 0 ? ShadowStyle::Normal : ShadowStyle::Inset;
 }
 
 static inline std::unique_ptr<ShadowData> blendFunc(const CSSPropertyBlendingClient* anim, const ShadowData* from, const ShadowData* to, double progress)
@@ -759,15 +759,15 @@ static inline size_t shadowListLength(const ShadowData* shadow)
 
 static inline const ShadowData* shadowForBlending(const ShadowData* srcShadow, const ShadowData* otherShadow)
 {
-    static NeverDestroyed<ShadowData> defaultShadowData(IntPoint(), 0, 0, Normal, false, Color::transparent);
-    static NeverDestroyed<ShadowData> defaultInsetShadowData(IntPoint(), 0, 0, Inset, false, Color::transparent);
-    static NeverDestroyed<ShadowData> defaultWebKitBoxShadowData(IntPoint(), 0, 0, Normal, true, Color::transparent);
-    static NeverDestroyed<ShadowData> defaultInsetWebKitBoxShadowData(IntPoint(), 0, 0, Inset, true, Color::transparent);
+    static NeverDestroyed<ShadowData> defaultShadowData(LayoutPoint(), 0, 0, ShadowStyle::Normal, false, Color::transparent);
+    static NeverDestroyed<ShadowData> defaultInsetShadowData(LayoutPoint(), 0, 0, ShadowStyle::Inset, false, Color::transparent);
+    static NeverDestroyed<ShadowData> defaultWebKitBoxShadowData(LayoutPoint(), 0, 0, ShadowStyle::Normal, true, Color::transparent);
+    static NeverDestroyed<ShadowData> defaultInsetWebKitBoxShadowData(LayoutPoint(), 0, 0, ShadowStyle::Inset, true, Color::transparent);
 
     if (srcShadow)
         return srcShadow;
 
-    if (otherShadow->style() == Inset)
+    if (otherShadow->style() == ShadowStyle::Inset)
         return otherShadow->isWebkitBoxShadow() ? &defaultInsetWebKitBoxShadowData.get() : &defaultInsetShadowData.get();
 
     return otherShadow->isWebkitBoxShadow() ? &defaultWebKitBoxShadowData.get() : &defaultShadowData.get();
index eb08e01..fceaeda 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011 Apple Inc.  All rights reserved.
+ * Copyright (C) 2011-2019 Apple Inc.  All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
  */
 
-#ifndef AnimationUtilities_h
-#define AnimationUtilities_h
+#pragma once
 
 #include "IntPoint.h"
-#include "LayoutUnit.h"
+#include "LayoutPoint.h"
 
 namespace WebCore {
 
@@ -59,9 +58,13 @@ inline LayoutUnit blend(LayoutUnit from, LayoutUnit to, double progress)
 inline IntPoint blend(const IntPoint& from, const IntPoint& to, double progress)
 {
     return IntPoint(blend(from.x(), to.x(), progress),
-                    blend(from.y(), to.y(), progress));
+        blend(from.y(), to.y(), progress));
 }
 
-} // namespace WebCore
+inline LayoutPoint blend(const LayoutPoint& from, const LayoutPoint& to, double progress)
+{
+    return LayoutPoint(blend(from.x(), to.x(), progress),
+        blend(from.y(), to.y(), progress));
+}
 
-#endif // AnimationUtilities_h
+} // namespace WebCore
index ad8207c..117beef 100644 (file)
@@ -24,8 +24,7 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#ifndef RoundedRect_h
-#define RoundedRect_h
+#pragma once
 
 #include "FloatQuad.h"
 #include "LayoutRect.h"
@@ -132,5 +131,3 @@ inline bool operator==(const RoundedRect& a, const RoundedRect& b)
 WEBCORE_EXPORT Region approximateAsRegion(const RoundedRect&, unsigned stepLength = 20);
 
 } // namespace WebCore
-
-#endif // RoundedRect_h
index 9971ea1..9075774 100644 (file)
@@ -1367,7 +1367,7 @@ void InlineFlowBox::paintBoxDecorations(PaintInfo& paintInfo, const LayoutPoint&
     LayoutRect paintRect = LayoutRect(adjustedPaintoffset, frameRect.size());
     // Shadow comes first and is behind the background and border.
     if (!renderer().boxShadowShouldBeAppliedToBackground(adjustedPaintoffset, BackgroundBleedNone, this))
-        paintBoxShadow(paintInfo, lineStyle, Normal, paintRect);
+        paintBoxShadow(paintInfo, lineStyle, ShadowStyle::Normal, paintRect);
 
     auto color = lineStyle.visitedDependentColor(CSSPropertyBackgroundColor);
     auto compositeOp = renderer().document().compositeOperatorForBackgroundColor(color, renderer());
@@ -1375,7 +1375,7 @@ void InlineFlowBox::paintBoxDecorations(PaintInfo& paintInfo, const LayoutPoint&
     color = lineStyle.colorByApplyingColorFilter(color);
 
     paintFillLayers(paintInfo, color, lineStyle.backgroundLayers(), paintRect, compositeOp);
-    paintBoxShadow(paintInfo, lineStyle, Inset, paintRect);
+    paintBoxShadow(paintInfo, lineStyle, ShadowStyle::Inset, paintRect);
 
     // :first-line cannot be used to put borders on a line. Always paint borders with our
     // non-first-line style.
index 3bc0c62..e04f093 100644 (file)
@@ -1321,7 +1321,7 @@ void RenderBox::paintBoxDecorations(PaintInfo& paintInfo, const LayoutPoint& pai
     // FIXME: Should eventually give the theme control over whether the box shadow should paint, since controls could have
     // custom shadows of their own.
     if (!boxShadowShouldBeAppliedToBackground(paintRect.location(), bleedAvoidance))
-        paintBoxShadow(paintInfo, paintRect, style(), Normal);
+        paintBoxShadow(paintInfo, paintRect, style(), ShadowStyle::Normal);
 
     GraphicsContextStateSaver stateSaver(paintInfo.context(), false);
     if (bleedAvoidance == BackgroundBleedUseTransparencyLayer) {
@@ -1352,7 +1352,7 @@ void RenderBox::paintBoxDecorations(PaintInfo& paintInfo, const LayoutPoint& pai
         if (style().hasAppearance())
             theme().paintDecorations(*this, paintInfo, paintRect);
     }
-    paintBoxShadow(paintInfo, paintRect, style(), Inset);
+    paintBoxShadow(paintInfo, paintRect, style(), ShadowStyle::Inset);
 
     // The theme will tell us whether or not we should also paint the CSS border.
     if (bleedAvoidance != BackgroundBleedBackgroundOverBorder && (!style().hasAppearance() || (borderOrBackgroundPaintingIsNeeded && theme().paintBorderOnly(*this, paintInfo, paintRect))) && style().hasVisibleBorderDecoration())
index 220afd7..eef62dd 100644 (file)
@@ -680,7 +680,7 @@ RoundedRect RenderBoxModelObject::backgroundRoundedRectAdjustedForBleedAvoidance
 static void applyBoxShadowForBackground(GraphicsContext& context, const RenderStyle& style)
 {
     const ShadowData* boxShadow = style.boxShadow();
-    while (boxShadow->style() != Normal)
+    while (boxShadow->style() != ShadowStyle::Normal)
         boxShadow = boxShadow->next();
 
     FloatSize shadowOffset(boxShadow->x(), boxShadow->y());
@@ -2285,7 +2285,7 @@ bool RenderBoxModelObject::boxShadowShouldBeAppliedToBackground(const LayoutPoin
 
     bool hasOneNormalBoxShadow = false;
     for (const ShadowData* currentShadow = style().boxShadow(); currentShadow; currentShadow = currentShadow->next()) {
-        if (currentShadow->style() != Normal)
+        if (currentShadow->style() != ShadowStyle::Normal)
             continue;
 
         if (hasOneNormalBoxShadow)
@@ -2322,7 +2322,7 @@ bool RenderBoxModelObject::boxShadowShouldBeAppliedToBackground(const LayoutPoin
     return true;
 }
 
-static inline LayoutRect areaCastingShadowInHole(const LayoutRect& holeRect, int shadowExtent, int shadowSpread, const IntSize& shadowOffset)
+static inline LayoutRect areaCastingShadowInHole(const LayoutRect& holeRect, LayoutUnit shadowExtent, LayoutUnit shadowSpread, const LayoutSize& shadowOffset)
 {
     LayoutRect bounds(holeRect);
     
@@ -2343,7 +2343,7 @@ void RenderBoxModelObject::paintBoxShadow(const PaintInfo& info, const LayoutRec
     if (context.paintingDisabled() || !style.boxShadow())
         return;
 
-    RoundedRect border = (shadowStyle == Inset) ? style.getRoundedInnerBorderFor(paintRect, includeLogicalLeftEdge, includeLogicalRightEdge)
+    RoundedRect border = (shadowStyle == ShadowStyle::Inset) ? style.getRoundedInnerBorderFor(paintRect, includeLogicalLeftEdge, includeLogicalRightEdge)
         : style.getRoundedBorderFor(paintRect, includeLogicalLeftEdge, includeLogicalRightEdge);
 
     bool hasBorderRadius = style.hasBorderRadius();
@@ -2355,53 +2355,58 @@ void RenderBoxModelObject::paintBoxShadow(const PaintInfo& info, const LayoutRec
         if (shadow->style() != shadowStyle)
             continue;
 
-        // FIXME: Add subpixel support for the shadow values. Soon after the shadow offset becomes fractional,
-        // all the early snappings here need to be pushed to the actual painting operations.
-        IntSize shadowOffset(shadow->x(), shadow->y());
+        LayoutSize shadowOffset(shadow->x(), shadow->y());
+        LayoutUnit shadowPaintingExtent = shadow->paintingExtent();
+        LayoutUnit shadowSpread = shadow->spread();
         int shadowRadius = shadow->radius();
-        int shadowPaintingExtent = shadow->paintingExtent();
-        int shadowSpread = shadow->spread();
-        
+
         if (shadowOffset.isZero() && !shadowRadius && !shadowSpread)
             continue;
         
         Color shadowColor = style.colorByApplyingColorFilter(shadow->color());
 
-        if (shadow->style() == Normal) {
+        if (shadow->style() == ShadowStyle::Normal) {
             RoundedRect fillRect = border;
             fillRect.inflate(shadowSpread);
             if (fillRect.isEmpty())
                 continue;
 
-            FloatRect pixelSnappedShadowRect = snapRectToDevicePixels(border.rect(), deviceScaleFactor);
-            pixelSnappedShadowRect.inflate(shadowPaintingExtent + shadowSpread);
-            pixelSnappedShadowRect.move(shadowOffset);
+            LayoutRect shadowRect = border.rect();
+            shadowRect.inflate(shadowPaintingExtent + shadowSpread);
+            shadowRect.move(shadowOffset);
+            FloatRect pixelSnappedShadowRect = snapRectToDevicePixels(shadowRect, deviceScaleFactor);
 
             GraphicsContextStateSaver stateSaver(context);
             context.clip(pixelSnappedShadowRect);
 
-            // Move the fill just outside the clip, adding 1 pixel separation so that the fill does not
+            // Move the fill just outside the clip, adding at least 1 pixel of separation so that the fill does not
             // bleed in (due to antialiasing) if the context is transformed.
-            IntSize extraOffset(roundToInt(paintRect.width()) + std::max(0, shadowOffset.width()) + shadowPaintingExtent + 2 * shadowSpread + 1, 0);
+            LayoutUnit xOffset = paintRect.width() + std::max<LayoutUnit>(0, shadowOffset.width()) + shadowPaintingExtent + 2 * shadowSpread + LayoutUnit(1);
+            LayoutSize extraOffset(xOffset.ceil(), 0);
             shadowOffset -= extraOffset;
             fillRect.move(extraOffset);
 
+            FloatRoundedRect pixelSnappedRectToClipOut = border.pixelSnappedRoundedRectForPainting(deviceScaleFactor);
+            FloatRoundedRect pixelSnappedFillRect = fillRect.pixelSnappedRoundedRectForPainting(deviceScaleFactor);
+            
+            LayoutPoint shadowRectOrigin = fillRect.rect().location() + shadowOffset;
+            FloatPoint snappedShadowOrigin = FloatPoint(roundToDevicePixel(shadowRectOrigin.x(), deviceScaleFactor), roundToDevicePixel(shadowRectOrigin.y(), deviceScaleFactor));
+            FloatSize snappedShadowOffset = snappedShadowOrigin - pixelSnappedFillRect.rect().location();
+
             if (shadow->isWebkitBoxShadow())
-                context.setLegacyShadow(shadowOffset, shadowRadius, shadowColor);
+                context.setLegacyShadow(snappedShadowOffset, shadowRadius, shadowColor);
             else
-                context.setShadow(shadowOffset, shadowRadius, shadowColor);
+                context.setShadow(snappedShadowOffset, shadowRadius, shadowColor);
 
-            FloatRoundedRect rectToClipOut = border.pixelSnappedRoundedRectForPainting(deviceScaleFactor);
-            FloatRoundedRect pixelSnappedFillRect = fillRect.pixelSnappedRoundedRectForPainting(deviceScaleFactor);
             if (hasBorderRadius) {
                 // If the box is opaque, it is unnecessary to clip it out. However, doing so saves time
                 // when painting the shadow. On the other hand, it introduces subpixel gaps along the
                 // corners. Those are avoided by insetting the clipping path by one pixel.
                 if (hasOpaqueBackground)
-                    rectToClipOut.inflateWithRadii(-1.0f);
+                    pixelSnappedRectToClipOut.inflateWithRadii(-1.0f);
 
-                if (!rectToClipOut.isEmpty())
-                    context.clipOutRoundedRect(rectToClipOut);
+                if (!pixelSnappedRectToClipOut.isEmpty())
+                    context.clipOutRoundedRect(pixelSnappedRectToClipOut);
 
                 RoundedRect influenceRect(LayoutRect(pixelSnappedShadowRect), border.radii());
                 influenceRect.expandRadii(2 * shadowPaintingExtent + shadowSpread);
@@ -2424,18 +2429,20 @@ void RenderBoxModelObject::paintBoxShadow(const PaintInfo& info, const LayoutRec
                     // FIXME: It's not clear if this check is right. What about integral scale factors?
                     AffineTransform transform = context.getCTM();
                     if (transform.a() != 1 || (transform.d() != 1 && transform.d() != -1) || transform.b() || transform.c())
-                        rectToClipOut.inflate(-1.0f);
+                        pixelSnappedRectToClipOut.inflate(-1.0f);
                 }
 
-                if (!rectToClipOut.isEmpty())
-                    context.clipOut(rectToClipOut.rect());
+                if (!pixelSnappedRectToClipOut.isEmpty())
+                    context.clipOut(pixelSnappedRectToClipOut.rect());
+
                 context.fillRect(pixelSnappedFillRect.rect(), Color::black);
             }
         } else {
             // Inset shadow.
+            LayoutRect holeRect = border.rect();
+            holeRect.inflate(-shadowSpread);
+            FloatRect pixelSnappedHoleRect = snapRectToDevicePixels(holeRect, deviceScaleFactor);
             FloatRoundedRect pixelSnappedBorderRect = border.pixelSnappedRoundedRectForPainting(deviceScaleFactor);
-            FloatRect pixelSnappedHoleRect = pixelSnappedBorderRect.rect();
-            pixelSnappedHoleRect.inflate(-shadowSpread);
 
             if (pixelSnappedHoleRect.isEmpty()) {
                 if (hasBorderRadius)
@@ -2447,24 +2454,29 @@ void RenderBoxModelObject::paintBoxShadow(const PaintInfo& info, const LayoutRec
 
             if (!includeLogicalLeftEdge) {
                 if (isHorizontal) {
-                    pixelSnappedHoleRect.move(-std::max(shadowOffset.width(), 0) - shadowPaintingExtent, 0);
-                    pixelSnappedHoleRect.setWidth(pixelSnappedHoleRect.width() + std::max(shadowOffset.width(), 0) + shadowPaintingExtent);
+                    holeRect.move(-std::max<LayoutUnit>(shadowOffset.width(), 0) - shadowPaintingExtent, 0);
+                    holeRect.setWidth(holeRect.width() + std::max<LayoutUnit>(shadowOffset.width(), 0) + shadowPaintingExtent);
                 } else {
-                    pixelSnappedHoleRect.move(0, -std::max(shadowOffset.height(), 0) - shadowPaintingExtent);
-                    pixelSnappedHoleRect.setHeight(pixelSnappedHoleRect.height() + std::max(shadowOffset.height(), 0) + shadowPaintingExtent);
+                    holeRect.move(0, -std::max<LayoutUnit>(shadowOffset.height(), 0) - shadowPaintingExtent);
+                    holeRect.setHeight(holeRect.height() + std::max<LayoutUnit>(shadowOffset.height(), 0) + shadowPaintingExtent);
                 }
             }
+            
             if (!includeLogicalRightEdge) {
                 if (isHorizontal)
-                    pixelSnappedHoleRect.setWidth(pixelSnappedHoleRect.width() - std::min(shadowOffset.width(), 0) + shadowPaintingExtent);
+                    holeRect.setWidth(holeRect.width() - std::min<LayoutUnit>(shadowOffset.width(), 0) + shadowPaintingExtent);
                 else
-                    pixelSnappedHoleRect.setHeight(pixelSnappedHoleRect.height() - std::min(shadowOffset.height(), 0) + shadowPaintingExtent);
+                    holeRect.setHeight(holeRect.height() - std::min<LayoutUnit>(shadowOffset.height(), 0) + shadowPaintingExtent);
             }
 
+            if (!includeLogicalLeftEdge || !includeLogicalRightEdge)
+                pixelSnappedHoleRect = snapRectToDevicePixels(holeRect, deviceScaleFactor);
+
             Color fillColor(shadowColor.red(), shadowColor.green(), shadowColor.blue(), 255);
 
-            FloatRect pixelSnappedOuterRect = snapRectToDevicePixels(areaCastingShadowInHole(LayoutRect(pixelSnappedBorderRect.rect()), shadowPaintingExtent, shadowSpread, shadowOffset), deviceScaleFactor);
-            FloatRoundedRect pixelSnappedRoundedHole = FloatRoundedRect(pixelSnappedHoleRect, pixelSnappedBorderRect.radii());
+            FloatRect pixelSnappedOuterRect = snapRectToDevicePixels(areaCastingShadowInHole(holeRect, shadowPaintingExtent, shadowSpread, shadowOffset), deviceScaleFactor);
+            RoundedRect roundedHoleRect(holeRect, border.radii());
+            FloatRoundedRect pixelSnappedRoundedHole = roundedHoleRect.pixelSnappedRoundedRectForPainting(deviceScaleFactor);
 
             GraphicsContextStateSaver stateSaver(context);
             if (hasBorderRadius) {
@@ -2473,7 +2485,7 @@ void RenderBoxModelObject::paintBoxShadow(const PaintInfo& info, const LayoutRec
             } else
                 context.clip(pixelSnappedBorderRect.rect());
 
-            IntSize extraOffset(2 * roundToInt(paintRect.width()) + std::max(0, shadowOffset.width()) + shadowPaintingExtent - 2 * shadowSpread + 1, 0);
+            IntSize extraOffset(2 * roundToInt(paintRect.width()) + std::max<LayoutUnit>(0, shadowOffset.width()) + shadowPaintingExtent - 2 * shadowSpread + 1, 0);
             context.translate(extraOffset);
             shadowOffset -= extraOffset;
 
index e91a133..2b16299 100644 (file)
@@ -770,9 +770,9 @@ void RenderTable::paintBoxDecorations(PaintInfo& paintInfo, const LayoutPoint& p
     
     BackgroundBleedAvoidance bleedAvoidance = determineBackgroundBleedAvoidance(paintInfo.context());
     if (!boxShadowShouldBeAppliedToBackground(rect.location(), bleedAvoidance))
-        paintBoxShadow(paintInfo, rect, style(), Normal);
+        paintBoxShadow(paintInfo, rect, style(), ShadowStyle::Normal);
     paintBackground(paintInfo, rect, bleedAvoidance);
-    paintBoxShadow(paintInfo, rect, style(), Inset);
+    paintBoxShadow(paintInfo, rect, style(), ShadowStyle::Inset);
 
     if (style().hasVisibleBorderDecoration() && !collapseBorders())
         paintBorder(paintInfo, rect, style());
index 51a1103..c739082 100644 (file)
@@ -1318,12 +1318,12 @@ void RenderTableCell::paintBoxDecorations(PaintInfo& paintInfo, const LayoutPoin
     LayoutRect paintRect = LayoutRect(paintOffset, frameRect().size());
     adjustBorderBoxRectForPainting(paintRect);
 
-    paintBoxShadow(paintInfo, paintRect, style(), Normal);
+    paintBoxShadow(paintInfo, paintRect, style(), ShadowStyle::Normal);
     
     // Paint our cell background.
     paintBackgroundsBehindCell(paintInfo, paintOffset, this);
 
-    paintBoxShadow(paintInfo, paintRect, style(), Inset);
+    paintBoxShadow(paintInfo, paintRect, style(), ShadowStyle::Inset);
 
     if (!style().hasBorder() || table->collapseBorders())
         return;
index eeebb58..5d38726 100644 (file)
@@ -1408,7 +1408,7 @@ void RenderStyle::setPageScaleTransform(float scale)
 
 void RenderStyle::setTextShadow(std::unique_ptr<ShadowData> shadowData, bool add)
 {
-    ASSERT(!shadowData || (!shadowData->spread() && shadowData->style() == Normal));
+    ASSERT(!shadowData || (!shadowData->spread() && shadowData->style() == ShadowStyle::Normal));
 
     auto& rareData = m_rareInheritedData.access();
     if (!add) {
@@ -1882,10 +1882,10 @@ void RenderStyle::getShadowExtent(const ShadowData* shadow, LayoutUnit& top, Lay
     left = 0;
 
     for ( ; shadow; shadow = shadow->next()) {
-        if (shadow->style() == Inset)
+        if (shadow->style() == ShadowStyle::Inset)
             continue;
 
-        int extentAndSpread = shadow->paintingExtent() + shadow->spread();
+        auto extentAndSpread = shadow->paintingExtent() + shadow->spread();
         top = std::min<LayoutUnit>(top, shadow->y() - extentAndSpread);
         right = std::max<LayoutUnit>(right, shadow->x() + extentAndSpread);
         bottom = std::max<LayoutUnit>(bottom, shadow->y() + extentAndSpread);
@@ -1901,10 +1901,10 @@ LayoutBoxExtent RenderStyle::getShadowInsetExtent(const ShadowData* shadow) cons
     LayoutUnit left;
 
     for ( ; shadow; shadow = shadow->next()) {
-        if (shadow->style() == Normal)
+        if (shadow->style() == ShadowStyle::Normal)
             continue;
 
-        int extentAndSpread = shadow->paintingExtent() + shadow->spread();
+        auto extentAndSpread = shadow->paintingExtent() + shadow->spread();
         top = std::max<LayoutUnit>(top, shadow->y() + extentAndSpread);
         right = std::min<LayoutUnit>(right, shadow->x() - extentAndSpread);
         bottom = std::min<LayoutUnit>(bottom, shadow->y() - extentAndSpread);
@@ -1920,10 +1920,10 @@ void RenderStyle::getShadowHorizontalExtent(const ShadowData* shadow, LayoutUnit
     right = 0;
 
     for ( ; shadow; shadow = shadow->next()) {
-        if (shadow->style() == Inset)
+        if (shadow->style() == ShadowStyle::Inset)
             continue;
 
-        int extentAndSpread = shadow->paintingExtent() + shadow->spread();
+        auto extentAndSpread = shadow->paintingExtent() + shadow->spread();
         left = std::min<LayoutUnit>(left, shadow->x() - extentAndSpread);
         right = std::max<LayoutUnit>(right, shadow->x() + extentAndSpread);
     }
@@ -1935,10 +1935,10 @@ void RenderStyle::getShadowVerticalExtent(const ShadowData* shadow, LayoutUnit &
     bottom = 0;
 
     for ( ; shadow; shadow = shadow->next()) {
-        if (shadow->style() == Inset)
+        if (shadow->style() == ShadowStyle::Inset)
             continue;
 
-        int extentAndSpread = shadow->paintingExtent() + shadow->spread();
+        auto extentAndSpread = shadow->paintingExtent() + shadow->spread();
         top = std::min<LayoutUnit>(top, shadow->y() - extentAndSpread);
         bottom = std::max<LayoutUnit>(bottom, shadow->y() + extentAndSpread);
     }
index 3b6defc..7bf4396 100644 (file)
@@ -29,8 +29,8 @@ namespace WebCore {
 
 ShadowData::ShadowData(const ShadowData& o)
     : m_location(o.m_location)
-    , m_radius(o.m_radius)
     , m_spread(o.m_spread)
+    , m_radius(o.m_radius)
     , m_color(o.m_color)
     , m_style(o.m_style)
     , m_isWebkitBoxShadow(o.m_isWebkitBoxShadow)
@@ -58,11 +58,11 @@ bool ShadowData::operator==(const ShadowData& o) const
         && m_isWebkitBoxShadow == o.m_isWebkitBoxShadow;
 }
 
-static inline void calculateShadowExtent(const ShadowData* shadow, int additionalOutlineSize, int& shadowLeft, int& shadowRight, int& shadowTop, int& shadowBottom)
+static inline void calculateShadowExtent(const ShadowData* shadow, LayoutUnit additionalOutlineSize, LayoutUnit& shadowLeft, LayoutUnit& shadowRight, LayoutUnit& shadowTop, LayoutUnit& shadowBottom)
 {
     do {
-        int extentAndSpread = shadow->paintingExtent() + shadow->spread() + additionalOutlineSize;
-        if (shadow->style() == Normal) {
+        LayoutUnit extentAndSpread = shadow->paintingExtent() + shadow->spread() + additionalOutlineSize;
+        if (shadow->style() == ShadowStyle::Normal) {
             shadowLeft = std::min(shadow->x() - extentAndSpread, shadowLeft);
             shadowRight = std::max(shadow->x() + extentAndSpread, shadowRight);
             shadowTop = std::min(shadow->y() - extentAndSpread, shadowTop);
@@ -75,10 +75,10 @@ static inline void calculateShadowExtent(const ShadowData* shadow, int additiona
 
 void ShadowData::adjustRectForShadow(LayoutRect& rect, int additionalOutlineSize) const
 {
-    int shadowLeft = 0;
-    int shadowRight = 0;
-    int shadowTop = 0;
-    int shadowBottom = 0;
+    LayoutUnit shadowLeft;
+    LayoutUnit shadowRight;
+    LayoutUnit shadowTop;
+    LayoutUnit shadowBottom;
     calculateShadowExtent(this, additionalOutlineSize, shadowLeft, shadowRight, shadowTop, shadowBottom);
 
     rect.move(shadowLeft, shadowTop);
@@ -88,10 +88,10 @@ void ShadowData::adjustRectForShadow(LayoutRect& rect, int additionalOutlineSize
 
 void ShadowData::adjustRectForShadow(FloatRect& rect, int additionalOutlineSize) const
 {
-    int shadowLeft = 0;
-    int shadowRight = 0;
-    int shadowTop = 0;
-    int shadowBottom = 0;
+    LayoutUnit shadowLeft = 0;
+    LayoutUnit shadowRight = 0;
+    LayoutUnit shadowTop = 0;
+    LayoutUnit shadowBottom = 0;
     calculateShadowExtent(this, additionalOutlineSize, shadowLeft, shadowRight, shadowTop, shadowBottom);
 
     rect.move(shadowLeft, shadowTop);
index 0e0cdb7..353af4f 100644 (file)
 
 namespace WebCore {
 
-enum ShadowStyle { Normal, Inset };
+enum class ShadowStyle : uint8_t { Normal, Inset };
 
 // This class holds information about shadows for the text-shadow and box-shadow properties.
 
 class ShadowData {
     WTF_MAKE_FAST_ALLOCATED;
 public:
-    ShadowData()
-        : m_radius(0)
-        , m_spread(0)
-        , m_style(Normal)
-        , m_isWebkitBoxShadow(false)
-    {
-    }
+    ShadowData() = default;
 
-    ShadowData(const IntPoint& location, int radius, int spread, ShadowStyle style, bool isWebkitBoxShadow, const Color& color)
+    ShadowData(const LayoutPoint& location, int radius, LayoutUnit spread, ShadowStyle style, bool isWebkitBoxShadow, const Color& color)
         : m_location(location)
-        , m_radius(radius)
         , m_spread(spread)
+        , m_radius(radius)
         , m_color(color)
         , m_style(style)
         , m_isWebkitBoxShadow(isWebkitBoxShadow)
@@ -66,19 +60,19 @@ public:
         return !(*this == o);
     }
     
-    int x() const { return m_location.x(); }
-    int y() const { return m_location.y(); }
-    IntPoint location() const { return m_location; }
+    LayoutUnit x() const { return m_location.x(); }
+    LayoutUnit y() const { return m_location.y(); }
+    LayoutPoint location() const { return m_location; }
     int radius() const { return m_radius; }
-    int paintingExtent() const
+    LayoutUnit paintingExtent() const
     {
         // Blurring uses a Gaussian function whose std. deviation is m_radius/2, and which in theory
         // extends to infinity. In 8-bit contexts, however, rounding causes the effect to become
         // undetectable at around 1.4x the radius.
         const float radiusExtentMultiplier = 1.4;
-        return ceilf(m_radius * radiusExtentMultiplier);
+        return LayoutUnit(ceilf(m_radius * radiusExtentMultiplier));
     }
-    int spread() const { return m_spread; }
+    LayoutUnit spread() const { return m_spread; }
     ShadowStyle style() const { return m_style; }
     const Color& color() const { return m_color; }
     bool isWebkitBoxShadow() const { return m_isWebkitBoxShadow; }
@@ -90,12 +84,12 @@ public:
     void adjustRectForShadow(FloatRect&, int additionalOutlineSize = 0) const;
 
 private:
-    IntPoint m_location;
-    int m_radius; // This is the "blur radius", or twice the standard deviation of the Gaussian blur.
-    int m_spread;
+    LayoutPoint m_location;
+    LayoutUnit m_spread;
+    int m_radius { 0 }; // This is the "blur radius", or twice the standard deviation of the Gaussian blur.
     Color m_color;
-    ShadowStyle m_style;
-    bool m_isWebkitBoxShadow;
+    ShadowStyle m_style { ShadowStyle::Normal };
+    bool m_isWebkitBoxShadow { false };
     std::unique_ptr<ShadowData> m_next;
 };
 
index 84b0958..8f854b9 100644 (file)
@@ -829,17 +829,17 @@ inline void BuilderCustom::applyTextOrBoxShadowValue(BuilderState& builderState,
     for (auto& item : downcast<CSSValueList>(value)) {
         auto& shadowValue = downcast<CSSShadowValue>(item.get());
         auto conversionData = builderState.cssToLengthConversionData();
-        int x = shadowValue.x->computeLength<int>(conversionData);
-        int y = shadowValue.y->computeLength<int>(conversionData);
+        auto x = shadowValue.x->computeLength<LayoutUnit>(conversionData);
+        auto y = shadowValue.y->computeLength<LayoutUnit>(conversionData);
         int blur = shadowValue.blur ? shadowValue.blur->computeLength<int>(conversionData) : 0;
-        int spread = shadowValue.spread ? shadowValue.spread->computeLength<int>(conversionData) : 0;
-        ShadowStyle shadowStyle = shadowValue.style && shadowValue.style->valueID() == CSSValueInset ? Inset : Normal;
+        auto spread = shadowValue.spread ? shadowValue.spread->computeLength<LayoutUnit>(conversionData) : LayoutUnit(0);
+        ShadowStyle shadowStyle = shadowValue.style && shadowValue.style->valueID() == CSSValueInset ? ShadowStyle::Inset : ShadowStyle::Normal;
         Color color;
         if (shadowValue.color)
             color = builderState.colorFromPrimitiveValue(*shadowValue.color);
         else
             color = builderState.style().color();
-        auto shadowData = makeUnique<ShadowData>(IntPoint(x, y), blur, spread, shadowStyle, property == CSSPropertyWebkitBoxShadow, color.isValid() ? color : Color::transparent);
+        auto shadowData = makeUnique<ShadowData>(LayoutPoint(x, y), blur, spread, shadowStyle, property == CSSPropertyWebkitBoxShadow, color.isValid() ? color : Color::transparent);
         if (property == CSSPropertyTextShadow)
             builderState.style().setTextShadow(WTFMove(shadowData), !isFirstEntry); // add to the list if this is not the first entry
         else
index 447f28e..26605c4 100644 (file)
@@ -285,11 +285,11 @@ TEST(FontManagerTests, ChangeAttributesWithFontEffectsBox)
     fontPanel.shadowOpacity = 1;
     [fontPanel toggleShadow];
     EXPECT_WK_STREQ("baz", [webView selectedText]);
-    EXPECT_WK_STREQ("rgb(0, 0, 0) 0px 1px 8px", textShadowAroundSelection());
+    EXPECT_WK_STREQ("rgb(0, 0, 0) 0px 1.25px 8px", textShadowAroundSelection());
     {
         NSShadow *shadow = [webView typingAttributes][NSShadowAttributeName];
         EXPECT_EQ(shadow.shadowOffset.width, 0);
-        EXPECT_EQ(shadow.shadowOffset.height, 1);
+        EXPECT_EQ(shadow.shadowOffset.height, 1.25);
         EXPECT_EQ(shadow.shadowBlurRadius, 8);
         EXPECT_TRUE([shadow.shadowColor isEqual:[NSColor colorWithRed:0 green:0 blue:0 alpha:1]]);
     }
@@ -306,7 +306,7 @@ TEST(FontManagerTests, ChangeAttributesWithFontEffectsBox)
     [fontPanel chooseUnderlineMenuItemWithTitle:@"single"];
     [fontPanel chooseStrikeThroughMenuItemWithTitle:@"single"];
     EXPECT_WK_STREQ("foo bar baz", [webView selectedText]);
-    EXPECT_WK_STREQ("rgba(0, 0, 0, 0.2) 0px 1px 5px", textShadowAroundSelection());
+    EXPECT_WK_STREQ("rgba(0, 0, 0, 0.2) 0px 1.25px 5px", textShadowAroundSelection());
     EXPECT_WK_STREQ("underline line-through", textDecorationsAroundSelection());
     {
         NSDictionary *typingAttributes = [webView typingAttributes];
@@ -315,7 +315,7 @@ TEST(FontManagerTests, ChangeAttributesWithFontEffectsBox)
 
         NSShadow *shadow = typingAttributes[NSShadowAttributeName];
         EXPECT_EQ(shadow.shadowOffset.width, 0);
-        EXPECT_EQ(shadow.shadowOffset.height, 1);
+        EXPECT_EQ(shadow.shadowOffset.height, 1.25);
         EXPECT_EQ(shadow.shadowBlurRadius, 5);
         EXPECT_TRUE([shadow.shadowColor isEqual:[NSColor colorWithRed:0 green:0 blue:0 alpha:0.2]]);
     }