OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2008 Google Inc. All rights reserved. | 2 * Copyright (C) 2008 Google Inc. All rights reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions | 5 * modification, are permitted provided that the following conditions |
6 * are met: | 6 * are met: |
7 * | 7 * |
8 * 1. Redistributions of source code must retain the above copyright | 8 * 1. Redistributions of source code must retain the above copyright |
9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
10 * 2. Redistributions in binary form must reproduce the above copyright | 10 * 2. Redistributions in binary form must reproduce the above copyright |
(...skipping 22 matching lines...) Expand all Loading... |
33 #include "NativeImageSkia.h" | 33 #include "NativeImageSkia.h" |
34 #include "TransformationMatrix.h" | 34 #include "TransformationMatrix.h" |
35 | 35 |
36 #include "SkShader.h" | 36 #include "SkShader.h" |
37 #include "SkCanvas.h" | 37 #include "SkCanvas.h" |
38 | 38 |
39 namespace WebCore { | 39 namespace WebCore { |
40 | 40 |
41 PlatformPatternPtr Pattern::createPlatformPattern(const TransformationMatrix& pa
tternTransform) const | 41 PlatformPatternPtr Pattern::createPlatformPattern(const TransformationMatrix& pa
tternTransform) const |
42 { | 42 { |
43 // Note: patternTransform is ignored since it seems to be applied elsewhere | 43 // Note: |patternTransform| is ignored since it is a global transformation |
44 // (when the pattern is used?). Applying it to the pattern (i.e. | 44 // applied by the GraphicsContext. Pattern-specific transformation is stored |
45 // shader->setLocalMatrix) results in a double transformation. This can be | 45 // in |m_patternSpaceTransformation|. |
46 // seen, for instance, as an extra offset in: | |
47 // LayoutTests/fast/canvas/patternfill-repeat.html | |
48 // and expanded scale and skew in: | |
49 // LayoutTests/svg/W3C-SVG-1.1/pservers-grad-06-b.svg | |
50 | 46 |
51 SkBitmap* bm = m_tileImage->nativeImageForCurrentFrame(); | 47 SkBitmap* bm = m_tileImage->nativeImageForCurrentFrame(); |
52 if (m_repeatX && m_repeatY) | 48 SkShader* shader = NULL; |
53 return SkShader::CreateBitmapShader(*bm, SkShader::kRepeat_TileMode, SkS
hader::kRepeat_TileMode); | |
54 | 49 |
55 // Skia does not have a "draw the tile only once" option. Clamp_TileMode | 50 if (m_repeatX && m_repeatY) { |
56 // repeats the last line of the image after drawing one tile. To avoid | 51 shader = SkShader::CreateBitmapShader(*bm, SkShader::kRepeat_TileMode, S
kShader::kRepeat_TileMode); |
57 // filling the space with arbitrary pixels, this workaround forces the | 52 } else { |
58 // image to have a line of transparent pixels on the "repeated" edge(s), | 53 // Skia does not have a "draw the tile only once" option. Clamp_TileMode |
59 // thus causing extra space to be transparent filled. | 54 // repeats the last line of the image after drawing one tile. To avoid |
60 SkShader::TileMode tileModeX = m_repeatX ? SkShader::kRepeat_TileMode : SkSh
ader::kClamp_TileMode; | 55 // filling the space with arbitrary pixels, this workaround forces the |
61 SkShader::TileMode tileModeY = m_repeatY ? SkShader::kRepeat_TileMode : SkSh
ader::kClamp_TileMode; | 56 // image to have a line of transparent pixels on the "repeated" edge(s), |
62 int expandW = m_repeatX ? 0 : 1; | 57 // thus causing extra space to be transparent filled. |
63 int expandH = m_repeatY ? 0 : 1; | 58 SkShader::TileMode tileModeX = m_repeatX ? SkShader::kRepeat_TileMode :
SkShader::kClamp_TileMode; |
| 59 SkShader::TileMode tileModeY = m_repeatY ? SkShader::kRepeat_TileMode :
SkShader::kClamp_TileMode; |
| 60 int expandW = m_repeatX ? 0 : 1; |
| 61 int expandH = m_repeatY ? 0 : 1; |
64 | 62 |
65 // Create a transparent bitmap 1 pixel wider and/or taller than the | 63 // Create a transparent bitmap 1 pixel wider and/or taller than the |
66 // original, then copy the orignal into it. | 64 // original, then copy the orignal into it. |
67 // FIXME: Is there a better way to pad (not scale) an image in skia? | 65 // FIXME: Is there a better way to pad (not scale) an image in skia? |
68 SkBitmap bm2; | 66 SkBitmap bm2; |
69 bm2.setConfig(bm->config(), bm->width() + expandW, bm->height() + expandH); | 67 bm2.setConfig(bm->config(), bm->width() + expandW, bm->height() + expand
H); |
70 bm2.allocPixels(); | 68 bm2.allocPixels(); |
71 bm2.eraseARGB(0x00, 0x00, 0x00, 0x00); | 69 bm2.eraseARGB(0x00, 0x00, 0x00, 0x00); |
72 SkCanvas canvas(bm2); | 70 SkCanvas canvas(bm2); |
73 canvas.drawBitmap(*bm, 0, 0); | 71 canvas.drawBitmap(*bm, 0, 0); |
74 return SkShader::CreateBitmapShader(bm2, tileModeX, tileModeY); | 72 shader = SkShader::CreateBitmapShader(bm2, tileModeX, tileModeY); |
| 73 } |
| 74 |
| 75 // The local transform is saved in m_patternSpaceTransformation, and we need |
| 76 // to apply it to the pattern. But Skia seems to have a problem with |
| 77 // positive translations in tile mode, so adjust the translation to an |
| 78 // equivalent negative value if we are in tile mode. |
| 79 // For example: |
| 80 // transform.e() == 56 (X translation) |
| 81 // bm->width() == 20 (Pattern width) |
| 82 // To make it look the same, we can have a X translation of -6, -26, etc. |
| 83 // An equivalent negative translation would be 56 less some multiple of 20, |
| 84 // e.g. -6, -26, -46. We can obtain the first such number that satisfies |
| 85 // this property by doing 56 - 3 * 20 = -6. The value of such multiple is |
| 86 // obtained by ceil(56 / 20) = 3. |
| 87 double translateX = 0.0; |
| 88 double translateY = 0.0; |
| 89 TransformationMatrix transform = m_patternSpaceTransformation; |
| 90 if (m_repeatX && bm->width() && transform.e() > 0.0) { |
| 91 translateX = -bm->width() * ceil(transform.e() / bm->width()); |
| 92 } |
| 93 if (m_repeatY && bm->height() && transform.f() > 0.0) { |
| 94 translateY = -bm->height() * ceil(transform.f() / bm->height()); |
| 95 } |
| 96 // Note that transform.translate(x, y) is to apply translation to the |
| 97 // current matrix, not setting the translation. |
| 98 shader->setLocalMatrix(transform.translate(translateX, translateY)); |
| 99 return shader; |
75 } | 100 } |
76 | 101 |
77 } // namespace WebCore | 102 } // namespace WebCore |
OLD | NEW |