1/*
2 * Copyright (C) 2011 Research In Motion Limited. All rights reserved.
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
17 */
18
19#ifndef InstrumentedPlatformCanvas_h
20#define InstrumentedPlatformCanvas_h
21
22#include "SkCanvas.h"
23
24#define DEBUG_SKIA_DRAWING 0
25#if DEBUG_SKIA_DRAWING
26#include "AndroidLog.h" // NOTE: AndroidLog.h normally shouldn't be included in a header
27#include "FloatRect.h"
28#define WRAPCANVAS_LOG_ENTRY(...) {ALOGD("non-rect %s, m_isSolidColor %d", __FUNCTION__, m_isSolidColor);}
29#else
30#define WRAPCANVAS_LOG_ENTRY(...) ((void)0)
31#endif
32
33namespace WebCore {
34
35class InstrumentedPlatformCanvas : public SkCanvas {
36public:
37    InstrumentedPlatformCanvas(int width, int height, Color initialColor)
38        : m_size(width, height)
39        , m_isSolidColor(true)
40        , m_solidColor(initialColor)
41    {
42    }
43
44    virtual ~InstrumentedPlatformCanvas() { }
45
46    bool isSolidColor() const { return m_isSolidColor; }
47    Color solidColor() const { return m_solidColor; }
48
49    // overrides from SkCanvas
50    virtual int save(SaveFlags flags = kMatrixClip_SaveFlag)
51    {
52        WRAPCANVAS_LOG_ENTRY("");
53        return SkCanvas::save(flags);
54    }
55
56    virtual int saveLayer(const SkRect* bounds, const SkPaint* paint, SaveFlags flags)
57    {
58        WRAPCANVAS_LOG_ENTRY("");
59        m_isSolidColor = false;
60        return SkCanvas::saveLayer(bounds, paint, flags);
61    }
62
63    virtual void restore()
64    {
65        WRAPCANVAS_LOG_ENTRY("");
66        SkCanvas::restore();
67    }
68
69    virtual bool translate(SkScalar dx, SkScalar dy)
70    {
71        WRAPCANVAS_LOG_ENTRY("");
72        return SkCanvas::translate(dx, dy);
73    }
74
75    virtual bool scale(SkScalar sx, SkScalar sy)
76    {
77        WRAPCANVAS_LOG_ENTRY("");
78        return SkCanvas::scale(sx, sy);
79    }
80
81    virtual bool rotate(SkScalar degrees)
82    {
83        WRAPCANVAS_LOG_ENTRY("");
84        return SkCanvas::rotate(degrees);
85    }
86
87    virtual bool skew(SkScalar sx, SkScalar sy)
88    {
89        WRAPCANVAS_LOG_ENTRY("");
90        return SkCanvas::skew(sx, sy);
91    }
92
93    virtual bool concat(const SkMatrix& matrix)
94    {
95        WRAPCANVAS_LOG_ENTRY("");
96        return SkCanvas::concat(matrix);
97    }
98
99    virtual void setMatrix(const SkMatrix& matrix)
100    {
101        WRAPCANVAS_LOG_ENTRY("");
102        SkCanvas::setMatrix(matrix);
103    }
104
105    virtual bool clipRect(const SkRect& rect, SkRegion::Op op)
106    {
107        WRAPCANVAS_LOG_ENTRY("");
108        return SkCanvas::clipRect(rect, op);
109    }
110
111    virtual bool clipPath(const SkPath& path, SkRegion::Op op)
112    {
113        WRAPCANVAS_LOG_ENTRY("");
114        m_isSolidColor = false;
115        return SkCanvas::clipPath(path, op);
116    }
117
118    virtual bool clipRegion(const SkRegion& region, SkRegion::Op op)
119    {
120        WRAPCANVAS_LOG_ENTRY("");
121        if (!region.isRect())
122            m_isSolidColor = false;
123        return SkCanvas::clipRegion(region, op);
124    }
125
126    virtual void clear(SkColor color)
127    {
128        WRAPCANVAS_LOG_ENTRY("");
129        m_isSolidColor = true;
130        m_solidColor = Color(color);
131        SkCanvas::clear(color);
132    }
133
134    virtual void drawPaint(const SkPaint& paint)
135    {
136        WRAPCANVAS_LOG_ENTRY("");
137        m_isSolidColor = false;
138        SkCanvas::drawPaint(paint);
139    }
140
141    virtual void drawPoints(PointMode mode, size_t count, const SkPoint pts[],
142            const SkPaint& paint)
143    {
144        WRAPCANVAS_LOG_ENTRY("");
145        m_isSolidColor = false;
146        SkCanvas::drawPoints(mode, count, pts, paint);
147    }
148
149    bool rectFullyOverlaps(const SkRect& rect)
150    {
151        IntRect canvasRect(IntPoint(), m_size);
152        if (getTotalMatrix().rectStaysRect()
153            && getTotalClip().contains(canvasRect)) {
154            const SkMatrix& matrix = getTotalMatrix();
155            SkRect mapped;
156            matrix.mapRect(&mapped, rect);
157            return mapped.contains(canvasRect);
158        }
159        return false;
160    }
161
162    virtual void drawRect(const SkRect& rect, const SkPaint& paint)
163    {
164
165#if DEBUG_SKIA_DRAWING
166        FloatRect rectToDraw = rect;
167        ALOGD("drawrect " FLOAT_RECT_FORMAT ", is solid %d", FLOAT_RECT_ARGS(rectToDraw), m_isSolidColor);
168#endif
169
170        if (m_isSolidColor) {
171            Color color = solidColor(paint);
172            if (color != m_solidColor) {
173                if (color.isValid() && rectFullyOverlaps(rect))
174                    m_solidColor = color;
175                else
176                    m_isSolidColor = false;
177            }
178        }
179
180        SkCanvas::drawRect(rect, paint);
181    }
182
183    virtual void drawPath(const SkPath& path, const SkPaint& paint)
184    {
185        WRAPCANVAS_LOG_ENTRY("");
186        m_isSolidColor = false;
187        SkCanvas::drawPath(path, paint);
188    }
189
190    virtual void drawBitmap(const SkBitmap& bitmap, SkScalar left,
191            SkScalar top, const SkPaint* paint)
192    {
193        WRAPCANVAS_LOG_ENTRY("");
194        m_isSolidColor = false;
195        SkCanvas::drawBitmap(bitmap, left, top, paint);
196    }
197
198    virtual void drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src,
199            const SkRect& dst, const SkPaint* paint)
200    {
201        WRAPCANVAS_LOG_ENTRY("");
202        m_isSolidColor = false;
203        SkCanvas::drawBitmapRectToRect(bitmap, src, dst, paint);
204    }
205
206    virtual void drawBitmapMatrix(const SkBitmap& bitmap,
207            const SkMatrix& matrix, const SkPaint* paint)
208    {
209        WRAPCANVAS_LOG_ENTRY("");
210        m_isSolidColor = false;
211        SkCanvas::drawBitmapMatrix(bitmap, matrix, paint);
212    }
213
214    virtual void drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
215                                const SkRect& dst, const SkPaint* paint = 0)
216    {
217        WRAPCANVAS_LOG_ENTRY("");
218        m_isSolidColor = false;
219        SkCanvas::drawBitmapNine(bitmap, center, dst, paint);
220    }
221
222    virtual void drawSprite(const SkBitmap& bitmap, int left, int top,
223            const SkPaint* paint)
224    {
225        WRAPCANVAS_LOG_ENTRY("");
226        m_isSolidColor = false;
227        SkCanvas::drawSprite(bitmap, left, top, paint);
228    }
229
230    virtual void drawText(const void* text, size_t byteLength, SkScalar x,
231            SkScalar y, const SkPaint& paint)
232    {
233        WRAPCANVAS_LOG_ENTRY("");
234        m_isSolidColor = false;
235        SkCanvas::drawText(text, byteLength, x, y, paint);
236    }
237
238    virtual void drawPosText(const void* text, size_t byteLength,
239            const SkPoint pos[], const SkPaint& paint)
240    {
241        WRAPCANVAS_LOG_ENTRY("");
242        m_isSolidColor = false;
243        SkCanvas::drawPosText(text, byteLength, pos, paint);
244    }
245
246    virtual void drawPosTextH(const void* text, size_t byteLength,
247            const SkScalar xpos[], SkScalar constY, const SkPaint& paint)
248    {
249        WRAPCANVAS_LOG_ENTRY("");
250        m_isSolidColor = false;
251        SkCanvas::drawPosTextH(text, byteLength, xpos, constY, paint);
252    }
253
254    virtual void drawTextOnPath(const void* text, size_t byteLength,
255            const SkPath& path, const SkMatrix* matrix, const SkPaint& paint)
256    {
257        WRAPCANVAS_LOG_ENTRY("");
258        m_isSolidColor = false;
259        SkCanvas::drawTextOnPath(text, byteLength, path, matrix, paint);
260    }
261
262    virtual void drawPicture(SkPicture& picture)
263    {
264        WRAPCANVAS_LOG_ENTRY("");
265        m_isSolidColor = false;
266        SkCanvas::drawPicture(picture);
267    }
268
269    virtual void drawVertices(VertexMode mode, int vertexCount,
270            const SkPoint vertices[], const SkPoint texs[],
271            const SkColor colors[], SkXfermode* xfermode,
272            const uint16_t indices[], int indexCount, const SkPaint& paint)
273    {
274        WRAPCANVAS_LOG_ENTRY("");
275        m_isSolidColor = false;
276        SkCanvas::drawVertices(mode, vertexCount, vertices, texs,
277                               colors, xfermode, indices, indexCount, paint);
278    }
279
280    virtual void drawData(const void* data, size_t size)
281    {
282        WRAPCANVAS_LOG_ENTRY("");
283        m_isSolidColor = false;
284        SkCanvas::drawData(data, size);
285    }
286
287private:
288    Color solidColor(const SkPaint& paint)
289    {
290        if (paint.getStyle() != SkPaint::kFill_Style)
291            return Color();
292        if (paint.getLooper() || paint.getShader())
293            return Color();
294
295        SkXfermode::Mode mode;
296        SkXfermode::AsMode(paint.getXfermode(), &mode);
297        if (mode == SkXfermode::kClear_Mode)
298            return Color(0, 0, 0, 0);
299
300        if ((mode == SkXfermode::kSrcOver_Mode && paint.getAlpha() == 255)
301            || mode == SkXfermode::kSrc_Mode)
302            return Color(paint.getColor());
303        return Color();
304    }
305
306    IntSize m_size;
307    bool m_isSolidColor;
308    Color m_solidColor;
309    SkPaint m_solidPaint;
310};
311
312} // namespace WebCore
313
314#endif // InstrumentedPlatformCanvas_h
315