Index: WebCore/platform/graphics/skia/PatternSkia.cpp |
=================================================================== |
--- WebCore/platform/graphics/skia/PatternSkia.cpp (revision 8041) |
+++ WebCore/platform/graphics/skia/PatternSkia.cpp (working copy) |
@@ -34,22 +34,44 @@ |
#include "TransformationMatrix.h" |
#include "SkShader.h" |
+#include "SkCanvas.h" |
namespace WebCore { |
-static inline SkShader::TileMode shaderRule(bool shouldRepeat) |
+PlatformPatternPtr Pattern::createPlatformPattern(const TransformationMatrix& patternTransform) const |
{ |
- // FIXME: Skia does not have a "draw the tile only once" option |
- // Clamp draws the last line of the image after stopping repeating |
- return shouldRepeat ? SkShader::kRepeat_TileMode : SkShader::kClamp_TileMode; |
-} |
+ // Note: patternTransform is ignored since it seems to be applied elsewhere |
+ // (when the pattern is used?). Applying it to the pattern (i.e. |
+ // shader->setLocalMatrix) results in a double transformation. This can be |
+ // seen, for instance, as an extra offset in: |
+ // LayoutTests/fast/canvas/patternfill-repeat.html |
+ // and expanded scale and skew in: |
+ // LayoutTests/svg/W3C-SVG-1.1/pservers-grad-06-b.svg |
-PlatformPatternPtr Pattern::createPlatformPattern(const TransformationMatrix& patternTransform) const |
-{ |
SkBitmap* bm = m_tileImage->nativeImageForCurrentFrame(); |
- SkShader* shader = SkShader::CreateBitmapShader(*bm, shaderRule(m_repeatX), shaderRule(m_repeatY)); |
- shader->setLocalMatrix(patternTransform); |
- return shader; |
+ if (m_repeatX && m_repeatY) |
+ return SkShader::CreateBitmapShader(*bm, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode); |
+ |
+ // Skia does not have a "draw the tile only once" option. Clamp_TileMode |
+ // repeats the last line of the image after drawing one tile. To avoid |
+ // filling the space with arbitrary pixels, this workaround forces the |
+ // image to have a line of transparent pixels on the "repeated" edge(s), |
+ // thus causing extra space to be transparent filled. |
+ SkShader::TileMode tileModeX = m_repeatX ? SkShader::kRepeat_TileMode : SkShader::kClamp_TileMode; |
+ SkShader::TileMode tileModeY = m_repeatY ? SkShader::kRepeat_TileMode : SkShader::kClamp_TileMode; |
+ int expandW = m_repeatX ? 0 : 1; |
+ int expandH = m_repeatY ? 0 : 1; |
+ |
+ // Create a transparent bitmap 1 pixel wider and/or taller than the |
+ // original, then copy the orignal into it. |
+ // FIXME: Is there a better way to pad (not scale) an image in skia? |
+ SkBitmap bm2; |
+ bm2.setConfig(bm->config(), bm->width() + expandW, bm->height() + expandH); |
+ bm2.allocPixels(); |
+ bm2.eraseARGB(0x00, 0x00, 0x00, 0x00); |
+ SkCanvas canvas(bm2); |
+ canvas.drawBitmap(*bm, 0, 0); |
+ return SkShader::CreateBitmapShader(bm2, tileModeX, tileModeY); |
} |
} // namespace WebCore |