| 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
|
|
|