Commit a7e84a02 authored by fmalita's avatar fmalita Committed by Commit bot

Clamp background tiles when possible

We're currently always drawing tiled backgrounds in repeat/repeat mode,
even if we need tiling in one dimension only.

This has the unexpected side effect of opposite edge bleed, in the
dimension which doesn't require tiling, when rasterized for hidpi
devices (DSF causing Skia to sample across the tile boundary).

Detect cases where tile repetition is not needed, and strength-reduce the
shader tile mode accordingly.

Also make Image::drawPattern() protected, as it is only used in subclasses.

BUG=673261
R=reed@google.com,fs@opera.com,schenney@chromium.org

Review-Url: https://codereview.chromium.org/2582383002
Cr-Commit-Position: refs/heads/master@{#439529}
parent 67b6497f
<!DOCTYPE html>
<style>
#div-horizontal {
width: 200px;
height: 100px;
background-color: green;
}
#div-vertical {
width: 100px;
height: 200px;
background-color: green;
}
</style>
<script src="resources/srcset-helper.js"></script>
<div id="div-horizontal"></div>
<br>
<div id="div-vertical"></div>
<!DOCTYPE html>
<style>
#div-horizontal {
width: 200px;
height: 100px;
/* red band at the bottom */
background-image: url("data:image/svg+xml,\
<svg xmlns='http://www.w3.org/2000/svg' width='120' height='120'>\
<rect width='100%' height='100%' fill='red'/>\
<rect width='100%' height='100' fill='green'/>\
</svg>");
}
#div-vertical {
width: 100px;
height: 200px;
/* red band on the right */
background-image: url("data:image/svg+xml,\
<svg xmlns='http://www.w3.org/2000/svg' width='120' height='120'>\
<rect width='100%' height='100%' fill='red'/>\
<rect width='100' height='100%' fill='green'/>\
</svg>");
}
</style>
<script src="resources/srcset-helper.js"></script>
<!-- There should be no bleeding due to repeat edge wrapping in the dimension
fully covered by the tile -->
<div id="div-horizontal"></div>
<br>
<div id="div-vertical"></div>
...@@ -84,6 +84,14 @@ class SVGImageForContainer final : public Image { ...@@ -84,6 +84,14 @@ class SVGImageForContainer final : public Image {
ImageClampingMode, ImageClampingMode,
const ColorBehavior&) override; const ColorBehavior&) override;
// FIXME: Implement this to be less conservative.
bool currentFrameKnownToBeOpaque(MetadataMode = UseCurrentMetadata) override {
return false;
}
sk_sp<SkImage> imageForCurrentFrame(const ColorBehavior&) override;
protected:
void drawPattern(GraphicsContext&, void drawPattern(GraphicsContext&,
const FloatRect&, const FloatRect&,
const FloatSize&, const FloatSize&,
...@@ -92,13 +100,6 @@ class SVGImageForContainer final : public Image { ...@@ -92,13 +100,6 @@ class SVGImageForContainer final : public Image {
const FloatRect&, const FloatRect&,
const FloatSize& repeatSpacing) override; const FloatSize& repeatSpacing) override;
// FIXME: Implement this to be less conservative.
bool currentFrameKnownToBeOpaque(MetadataMode = UseCurrentMetadata) override {
return false;
}
sk_sp<SkImage> imageForCurrentFrame(const ColorBehavior&) override;
private: private:
SVGImageForContainer(SVGImage* image, SVGImageForContainer(SVGImage* image,
const FloatSize& containerSize, const FloatSize& containerSize,
......
...@@ -225,10 +225,11 @@ namespace { ...@@ -225,10 +225,11 @@ namespace {
sk_sp<SkShader> createPatternShader(const SkImage* image, sk_sp<SkShader> createPatternShader(const SkImage* image,
const SkMatrix& shaderMatrix, const SkMatrix& shaderMatrix,
const SkPaint& paint, const SkPaint& paint,
const FloatSize& spacing) { const FloatSize& spacing,
SkShader::TileMode tmx,
SkShader::TileMode tmy) {
if (spacing.isZero()) if (spacing.isZero())
return image->makeShader(SkShader::kRepeat_TileMode, return image->makeShader(tmx, tmy, &shaderMatrix);
SkShader::kRepeat_TileMode, &shaderMatrix);
// Arbitrary tiling is currently only supported for SkPictureShader, so we use // Arbitrary tiling is currently only supported for SkPictureShader, so we use
// that instead of a plain bitmap shader to implement spacing. // that instead of a plain bitmap shader to implement spacing.
...@@ -239,9 +240,17 @@ sk_sp<SkShader> createPatternShader(const SkImage* image, ...@@ -239,9 +240,17 @@ sk_sp<SkShader> createPatternShader(const SkImage* image,
SkCanvas* canvas = recorder.beginRecording(tileRect); SkCanvas* canvas = recorder.beginRecording(tileRect);
canvas->drawImage(image, 0, 0, &paint); canvas->drawImage(image, 0, 0, &paint);
return SkShader::MakePictureShader( return SkShader::MakePictureShader(recorder.finishRecordingAsPicture(), tmx,
recorder.finishRecordingAsPicture(), SkShader::kRepeat_TileMode, tmy, &shaderMatrix, nullptr);
SkShader::kRepeat_TileMode, &shaderMatrix, nullptr); }
SkShader::TileMode computeTileMode(float left,
float right,
float min,
float max) {
DCHECK(left < right);
return left >= min && right <= max ? SkShader::kClamp_TileMode
: SkShader::kRepeat_TileMode;
} }
} // anonymous namespace } // anonymous namespace
...@@ -286,6 +295,14 @@ void Image::drawPattern(GraphicsContext& context, ...@@ -286,6 +295,14 @@ void Image::drawPattern(GraphicsContext& context,
if (!image) if (!image)
return; return;
const FloatSize tileSize(
image->width() * scale.width() + repeatSpacing.width(),
image->height() * scale.height() + repeatSpacing.height());
const auto tmx = computeTileMode(destRect.x(), destRect.maxX(), adjustedX,
adjustedX + tileSize.width());
const auto tmy = computeTileMode(destRect.y(), destRect.maxY(), adjustedY,
adjustedY + tileSize.height());
{ {
SkPaint paint = context.fillPaint(); SkPaint paint = context.fillPaint();
paint.setColor(SK_ColorBLACK); paint.setColor(SK_ColorBLACK);
...@@ -293,10 +310,11 @@ void Image::drawPattern(GraphicsContext& context, ...@@ -293,10 +310,11 @@ void Image::drawPattern(GraphicsContext& context,
paint.setFilterQuality( paint.setFilterQuality(
context.computeFilterQuality(this, destRect, normSrcRect)); context.computeFilterQuality(this, destRect, normSrcRect));
paint.setAntiAlias(context.shouldAntialias()); paint.setAntiAlias(context.shouldAntialias());
paint.setShader(createPatternShader( paint.setShader(
image.get(), localMatrix, paint, createPatternShader(image.get(), localMatrix, paint,
FloatSize(repeatSpacing.width() / scale.width(), FloatSize(repeatSpacing.width() / scale.width(),
repeatSpacing.height() / scale.height()))); repeatSpacing.height() / scale.height()),
tmx, tmy));
context.drawRect(destRect, paint); context.drawRect(destRect, paint);
} }
......
...@@ -156,14 +156,6 @@ class PLATFORM_EXPORT Image : public ThreadSafeRefCounted<Image> { ...@@ -156,14 +156,6 @@ class PLATFORM_EXPORT Image : public ThreadSafeRefCounted<Image> {
virtual sk_sp<SkImage> imageForCurrentFrame(const ColorBehavior&) = 0; virtual sk_sp<SkImage> imageForCurrentFrame(const ColorBehavior&) = 0;
virtual PassRefPtr<Image> imageForDefaultFrame(); virtual PassRefPtr<Image> imageForDefaultFrame();
virtual void drawPattern(GraphicsContext&,
const FloatRect&,
const FloatSize&,
const FloatPoint& phase,
SkBlendMode,
const FloatRect&,
const FloatSize& repeatSpacing = FloatSize());
enum ImageClampingMode { enum ImageClampingMode {
ClampImageToSourceRect, ClampImageToSourceRect,
DoNotClampImageToSourceRect DoNotClampImageToSourceRect
...@@ -213,6 +205,14 @@ class PLATFORM_EXPORT Image : public ThreadSafeRefCounted<Image> { ...@@ -213,6 +205,14 @@ class PLATFORM_EXPORT Image : public ThreadSafeRefCounted<Image> {
TileRule vRule, TileRule vRule,
SkBlendMode); SkBlendMode);
virtual void drawPattern(GraphicsContext&,
const FloatRect&,
const FloatSize&,
const FloatPoint& phase,
SkBlendMode,
const FloatRect&,
const FloatSize& repeatSpacing = FloatSize());
private: private:
RefPtr<SharedBuffer> m_encodedImageData; RefPtr<SharedBuffer> m_encodedImageData;
// TODO(Oilpan): consider having Image on the Oilpan heap and // TODO(Oilpan): consider having Image on the Oilpan heap and
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment