Index: WebCore/platform/graphics/skia/PatternSkia.cpp |
=================================================================== |
--- WebCore/platform/graphics/skia/PatternSkia.cpp (revision 11353) |
+++ WebCore/platform/graphics/skia/PatternSkia.cpp (working copy) |
@@ -40,38 +40,63 @@ |
PlatformPatternPtr Pattern::createPlatformPattern(const TransformationMatrix& patternTransform) const |
{ |
- // 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 |
+ // Note: |patternTransform| is ignored since it is a global transformation |
+ // applied by the GraphicsContext. Pattern-specific transformation is stored |
+ // in |m_patternSpaceTransformation|. |
SkBitmap* bm = m_tileImage->nativeImageForCurrentFrame(); |
- if (m_repeatX && m_repeatY) |
- return SkShader::CreateBitmapShader(*bm, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode); |
+ SkShader* shader = NULL; |
- // 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; |
+ if (m_repeatX && m_repeatY) { |
+ shader = SkShader::CreateBitmapShader(*bm, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode); |
+ } else { |
+ // 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); |
+ // 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); |
+ shader = SkShader::CreateBitmapShader(bm2, tileModeX, tileModeY); |
+ } |
+ |
+ // The local transform is saved in m_patternSpaceTransformation, and we need |
+ // to apply it to the pattern. But Skia seems to have a problem with |
+ // positive translations in tile mode, so adjust the translation to an |
+ // equivalent negative value if we are in tile mode. |
+ // For example: |
+ // transform.e() == 56 (X translation) |
+ // bm->width() == 20 (Pattern width) |
+ // To make it look the same, we can have a X translation of -6, -26, etc. |
+ // An equivalent negative translation would be 56 less some multiple of 20, |
+ // e.g. -6, -26, -46. We can obtain the first such number that satisfies |
+ // this property by doing 56 - 3 * 20 = -6. The value of such multiple is |
+ // obtained by ceil(56 / 20) = 3. |
+ double translateX = 0.0; |
+ double translateY = 0.0; |
+ TransformationMatrix transform = m_patternSpaceTransformation; |
+ if (m_repeatX && bm->width() && transform.e() > 0.0) { |
+ translateX = -bm->width() * ceil(transform.e() / bm->width()); |
+ } |
+ if (m_repeatY && bm->height() && transform.f() > 0.0) { |
+ translateY = -bm->height() * ceil(transform.f() / bm->height()); |
+ } |
+ // Note that transform.translate(x, y) is to apply translation to the |
+ // current matrix, not setting the translation. |
+ shader->setLocalMatrix(transform.translate(translateX, translateY)); |
+ return shader; |
} |
} // namespace WebCore |