1/*
2 * Copyright (C) 2008 Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * 1.  Redistributions of source code must retain the above copyright
9 *     notice, this list of conditions and the following disclaimer.
10 * 2.  Redistributions in binary form must reproduce the above copyright
11 *     notice, this list of conditions and the following disclaimer in the
12 *     documentation and/or other materials provided with the distribution.
13 * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14 *     its contributors may be used to endorse or promote products derived
15 *     from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include "config.h"
30#include "Pattern.h"
31
32#include "AffineTransform.h"
33#include "Image.h"
34#include "NativeImageSkia.h"
35
36#include "SkCanvas.h"
37#include "SkColor.h"
38#include "SkColorShader.h"
39#include "SkShader.h"
40
41namespace WebCore {
42
43void Pattern::platformDestroy()
44{
45    SkSafeUnref(m_pattern);
46    m_pattern = 0;
47}
48
49PlatformPatternPtr Pattern::platformPattern(const AffineTransform& patternTransform)
50{
51    if (m_pattern)
52        return m_pattern;
53
54    // Note: patternTransform is ignored since it seems to be applied elsewhere
55    // (when the pattern is used?). Applying it to the pattern (i.e.
56    // shader->setLocalMatrix) results in a double transformation. This can be
57    // seen, for instance, as an extra offset in:
58    // LayoutTests/fast/canvas/patternfill-repeat.html
59    // and expanded scale and skew in:
60    // LayoutTests/svg/W3C-SVG-1.1/pservers-grad-06-b.svg
61
62    SkBitmap* bm = m_tileImage->nativeImageForCurrentFrame();
63    // If we don't have a bitmap, return a transparent shader.
64    if (!bm)
65        m_pattern = new SkColorShader(SkColorSetARGB(0, 0, 0, 0));
66
67    else if (m_repeatX && m_repeatY)
68        m_pattern = SkShader::CreateBitmapShader(*bm, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode);
69
70    else {
71
72        // Skia does not have a "draw the tile only once" option. Clamp_TileMode
73        // repeats the last line of the image after drawing one tile. To avoid
74        // filling the space with arbitrary pixels, this workaround forces the
75        // image to have a line of transparent pixels on the "repeated" edge(s),
76        // thus causing extra space to be transparent filled.
77        SkShader::TileMode tileModeX = m_repeatX ? SkShader::kRepeat_TileMode : SkShader::kClamp_TileMode;
78        SkShader::TileMode tileModeY = m_repeatY ? SkShader::kRepeat_TileMode : SkShader::kClamp_TileMode;
79        int expandW = m_repeatX ? 0 : 1;
80        int expandH = m_repeatY ? 0 : 1;
81
82        // Create a transparent bitmap 1 pixel wider and/or taller than the
83        // original, then copy the orignal into it.
84        // FIXME: Is there a better way to pad (not scale) an image in skia?
85        SkBitmap bm2;
86        bm2.setConfig(bm->config(), bm->width() + expandW, bm->height() + expandH);
87        bm2.allocPixels();
88        bm2.eraseARGB(0x00, 0x00, 0x00, 0x00);
89        SkCanvas canvas(bm2);
90        canvas.drawBitmap(*bm, 0, 0);
91        m_pattern = SkShader::CreateBitmapShader(bm2, tileModeX, tileModeY);
92    }
93    m_pattern->setLocalMatrix(m_patternSpaceTransformation);
94    return m_pattern;
95}
96
97void Pattern::setPlatformPatternSpaceTransform()
98{
99    if (m_pattern)
100        m_pattern->setLocalMatrix(m_patternSpaceTransformation);
101}
102
103} // namespace WebCore
104