if (context->paintingDisabled() || !style.boxShadow())
return;
- RoundedRect border = (shadowStyle == Inset)
- ? style.getRoundedInnerBorderFor(paintRect, includeLogicalLeftEdge, includeLogicalRightEdge)
+ RoundedRect border = (shadowStyle == Inset) ? style.getRoundedInnerBorderFor(paintRect, includeLogicalLeftEdge, includeLogicalRightEdge)
: style.getRoundedBorderFor(paintRect, &view(), includeLogicalLeftEdge, includeLogicalRightEdge);
bool hasBorderRadius = style.hasBorderRadius();
bool isHorizontal = style.isHorizontalWritingMode();
+ float deviceScaleFactor = document().deviceScaleFactor();
bool hasOpaqueBackground = style.visitedDependentColor(CSSPropertyBackgroundColor).isValid() && style.visitedDependentColor(CSSPropertyBackgroundColor).alpha() == 255;
for (const ShadowData* shadow = style.boxShadow(); shadow; shadow = shadow->next()) {
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());
int shadowRadius = shadow->radius();
int shadowPaintingExtent = shadow->paintingExtent();
if (fillRect.isEmpty())
continue;
- IntRect shadowRect(border.rect());
- shadowRect.inflate(shadowPaintingExtent + shadowSpread);
- shadowRect.move(shadowOffset);
+ FloatRect pixelSnappedShadowRect = pixelSnappedForPainting(border.rect(), deviceScaleFactor);
+ pixelSnappedShadowRect.inflate(shadowPaintingExtent + shadowSpread);
+ pixelSnappedShadowRect.move(shadowOffset);
GraphicsContextStateSaver stateSaver(*context);
- context->clip(shadowRect);
+ context->clip(pixelSnappedShadowRect);
// Move the fill just outside the clip, adding 1 pixel separation so that the fill does not
// bleed in (due to antialiasing) if the context is transformed.
- IntSize extraOffset(paintRect.pixelSnappedWidth() + std::max(0, shadowOffset.width()) + shadowPaintingExtent + 2 * shadowSpread + 1, 0);
+ IntSize extraOffset(roundToInt(paintRect.width()) + std::max(0, shadowOffset.width()) + shadowPaintingExtent + 2 * shadowSpread + 1, 0);
shadowOffset -= extraOffset;
fillRect.move(extraOffset);
else
context->setShadow(shadowOffset, shadowRadius, shadowColor, style.colorSpace());
+ FloatRoundedRect rectToClipOut = border.pixelSnappedRoundedRectForPainting(deviceScaleFactor);
+ FloatRoundedRect pixelSnappedFillRect = fillRect.pixelSnappedRoundedRectForPainting(deviceScaleFactor);
if (hasBorderRadius) {
- RoundedRect rectToClipOut = border;
-
// 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);
- }
+ if (hasOpaqueBackground)
+ rectToClipOut.inflateWithRadii(LayoutUnit::fromPixel(-1));
if (!rectToClipOut.isEmpty())
- context->clipOutRoundedRect(FloatRoundedRect(rectToClipOut));
+ context->clipOutRoundedRect(rectToClipOut);
- RoundedRect influenceRect(shadowRect, border.radii());
+ RoundedRect influenceRect(LayoutRect(pixelSnappedShadowRect), border.radii());
influenceRect.expandRadii(2 * shadowPaintingExtent + shadowSpread);
+
if (allCornersClippedOut(influenceRect, info.rect))
- context->fillRect(fillRect.rect(), Color::black, style.colorSpace());
+ context->fillRect(pixelSnappedFillRect.rect(), Color::black, style.colorSpace());
else {
- fillRect.expandRadii(shadowSpread);
- if (!fillRect.isRenderable())
- fillRect.adjustRadii();
- context->fillRoundedRect(FloatRoundedRect(fillRect), Color::black, style.colorSpace());
+ pixelSnappedFillRect.expandRadii(shadowSpread);
+ if (!pixelSnappedFillRect.isRenderable())
+ pixelSnappedFillRect.adjustRadii();
+ context->fillRoundedRect(pixelSnappedFillRect, Color::black, style.colorSpace());
}
} else {
- LayoutRect rectToClipOut = border.rect();
-
// 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
// edges if they are not pixel-aligned. Those are avoided by insetting the clipping path
// 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);
+ rectToClipOut.inflate(LayoutUnit::fromPixel(-1).toFloat());
}
if (!rectToClipOut.isEmpty())
- context->clipOut(rectToClipOut);
- context->fillRect(fillRect.rect(), Color::black, style.colorSpace());
+ context->clipOut(rectToClipOut.rect());
+ context->fillRect(pixelSnappedFillRect.rect(), Color::black, style.colorSpace());
}
} else {
// Inset shadow.
- IntRect holeRect(border.rect());
- holeRect.inflate(-shadowSpread);
+ FloatRoundedRect pixelSnappedBorderRect = border.pixelSnappedRoundedRectForPainting(deviceScaleFactor);
+ FloatRect pixelSnappedHoleRect = pixelSnappedBorderRect.rect();
+ pixelSnappedHoleRect.inflate(-shadowSpread);
- if (holeRect.isEmpty()) {
+ if (pixelSnappedHoleRect.isEmpty()) {
if (hasBorderRadius)
- context->fillRoundedRect(FloatRoundedRect(border), shadowColor, style.colorSpace());
+ context->fillRoundedRect(pixelSnappedBorderRect, shadowColor, style.colorSpace());
else
- context->fillRect(border.rect(), shadowColor, style.colorSpace());
+ context->fillRect(pixelSnappedBorderRect.rect(), shadowColor, style.colorSpace());
continue;
}
if (!includeLogicalLeftEdge) {
if (isHorizontal) {
- holeRect.move(-std::max(shadowOffset.width(), 0) - shadowPaintingExtent, 0);
- holeRect.setWidth(holeRect.width() + std::max(shadowOffset.width(), 0) + shadowPaintingExtent);
+ pixelSnappedHoleRect.move(-std::max(shadowOffset.width(), 0) - shadowPaintingExtent, 0);
+ pixelSnappedHoleRect.setWidth(pixelSnappedHoleRect.width() + std::max(shadowOffset.width(), 0) + shadowPaintingExtent);
} else {
- holeRect.move(0, -std::max(shadowOffset.height(), 0) - shadowPaintingExtent);
- holeRect.setHeight(holeRect.height() + std::max(shadowOffset.height(), 0) + shadowPaintingExtent);
+ pixelSnappedHoleRect.move(0, -std::max(shadowOffset.height(), 0) - shadowPaintingExtent);
+ pixelSnappedHoleRect.setHeight(pixelSnappedHoleRect.height() + std::max(shadowOffset.height(), 0) + shadowPaintingExtent);
}
}
if (!includeLogicalRightEdge) {
if (isHorizontal)
- holeRect.setWidth(holeRect.width() - std::min(shadowOffset.width(), 0) + shadowPaintingExtent);
+ pixelSnappedHoleRect.setWidth(pixelSnappedHoleRect.width() - std::min(shadowOffset.width(), 0) + shadowPaintingExtent);
else
- holeRect.setHeight(holeRect.height() - std::min(shadowOffset.height(), 0) + shadowPaintingExtent);
+ pixelSnappedHoleRect.setHeight(pixelSnappedHoleRect.height() - std::min(shadowOffset.height(), 0) + shadowPaintingExtent);
}
Color fillColor(shadowColor.red(), shadowColor.green(), shadowColor.blue(), 255);
- LayoutRect outerRect = areaCastingShadowInHole(border.rect(), shadowPaintingExtent, shadowSpread, shadowOffset);
- RoundedRect roundedHole(holeRect, border.radii());
+ FloatRect pixelSnappedOuterRect = pixelSnappedForPainting(areaCastingShadowInHole(LayoutRect(pixelSnappedBorderRect.rect()), shadowPaintingExtent, shadowSpread, shadowOffset), deviceScaleFactor);
+ FloatRoundedRect pixelSnappedRoundedHole = FloatRoundedRect(pixelSnappedHoleRect, pixelSnappedBorderRect.radii());
GraphicsContextStateSaver stateSaver(*context);
if (hasBorderRadius) {
Path path;
- path.addRoundedRect(border);
+ path.addRoundedRect(pixelSnappedBorderRect);
context->clip(path);
- roundedHole.shrinkRadii(shadowSpread);
+ pixelSnappedRoundedHole.shrinkRadii(shadowSpread);
} else
- context->clip(border.rect());
+ context->clip(pixelSnappedBorderRect.rect());
- IntSize extraOffset(2 * paintRect.pixelSnappedWidth() + std::max(0, shadowOffset.width()) + shadowPaintingExtent - 2 * shadowSpread + 1, 0);
+ IntSize extraOffset(2 * roundToInt(paintRect.width()) + std::max(0, shadowOffset.width()) + shadowPaintingExtent - 2 * shadowSpread + 1, 0);
context->translate(extraOffset.width(), extraOffset.height());
shadowOffset -= extraOffset;
else
context->setShadow(shadowOffset, shadowRadius, shadowColor, style.colorSpace());
- context->fillRectWithRoundedHole(outerRect, FloatRoundedRect(roundedHole), fillColor, style.colorSpace());
+ context->fillRectWithRoundedHole(pixelSnappedOuterRect, pixelSnappedRoundedHole, fillColor, style.colorSpace());
}
}
}