SkDevice.cpp revision e303fcf68d6fee2bf9ee0c4f6fb330a2c3e41a01
1
2/*
3 * Copyright 2011 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8#include "SkDevice.h"
9#include "SkDraw.h"
10#include "SkMetaData.h"
11#include "SkRect.h"
12
13///////////////////////////////////////////////////////////////////////////////
14
15SkDevice::SkDevice(const SkBitmap& bitmap) : fBitmap(bitmap) {
16    fOrigin.setZero();
17    fMetaData = NULL;
18}
19
20SkDevice::SkDevice(SkBitmap::Config config, int width, int height, bool isOpaque) {
21    fOrigin.setZero();
22    fMetaData = NULL;
23
24    fBitmap.setConfig(config, width, height);
25    fBitmap.allocPixels();
26    fBitmap.setIsOpaque(isOpaque);
27    if (!isOpaque) {
28        fBitmap.eraseColor(0);
29    }
30}
31
32SkDevice::~SkDevice() {
33    delete fMetaData;
34}
35
36SkDevice* SkDevice::createCompatibleDevice(SkBitmap::Config config,
37                                           int width, int height,
38                                           bool isOpaque) {
39    return this->onCreateCompatibleDevice(config, width, height,
40                                          isOpaque, kGeneral_Usage);
41}
42
43SkDevice* SkDevice::createCompatibleDeviceForSaveLayer(SkBitmap::Config config,
44                                                       int width, int height,
45                                                       bool isOpaque) {
46    return this->onCreateCompatibleDevice(config, width, height,
47                                          isOpaque, kSaveLayer_Usage);
48}
49
50SkDevice* SkDevice::onCreateCompatibleDevice(SkBitmap::Config config,
51                                             int width, int height,
52                                             bool isOpaque,
53                                             Usage usage) {
54    return SkNEW_ARGS(SkDevice,(config, width, height, isOpaque));
55}
56
57SkMetaData& SkDevice::getMetaData() {
58    // metadata users are rare, so we lazily allocate it. If that changes we
59    // can decide to just make it a field in the device (rather than a ptr)
60    if (NULL == fMetaData) {
61        fMetaData = new SkMetaData;
62    }
63    return *fMetaData;
64}
65
66void SkDevice::lockPixels() {
67    if (fBitmap.lockPixelsAreWritable()) {
68        fBitmap.lockPixels();
69    }
70}
71
72void SkDevice::unlockPixels() {
73    if (fBitmap.lockPixelsAreWritable()) {
74        fBitmap.unlockPixels();
75    }
76}
77
78const SkBitmap& SkDevice::accessBitmap(bool changePixels) {
79    this->onAccessBitmap(&fBitmap);
80    if (changePixels) {
81        fBitmap.notifyPixelsChanged();
82    }
83    return fBitmap;
84}
85
86void SkDevice::getGlobalBounds(SkIRect* bounds) const {
87    if (bounds) {
88        bounds->setXYWH(fOrigin.x(), fOrigin.y(),
89                        fBitmap.width(), fBitmap.height());
90    }
91}
92
93void SkDevice::clear(SkColor color) {
94    fBitmap.eraseColor(color);
95}
96
97void SkDevice::onAccessBitmap(SkBitmap* bitmap) {}
98
99void SkDevice::setMatrixClip(const SkMatrix& matrix, const SkRegion& region,
100                             const SkClipStack& clipStack) {
101}
102
103///////////////////////////////////////////////////////////////////////////////
104
105bool SkDevice::readPixels(SkBitmap* bitmap, int x, int y,
106                          SkCanvas::Config8888 config8888) {
107    if (SkBitmap::kARGB_8888_Config != bitmap->config() ||
108        NULL != bitmap->getTexture()) {
109        return false;
110    }
111
112    const SkBitmap& src = this->accessBitmap(false);
113
114    SkIRect srcRect = SkIRect::MakeXYWH(x, y, bitmap->width(),
115                                              bitmap->height());
116    SkIRect devbounds = SkIRect::MakeWH(src.width(), src.height());
117    if (!srcRect.intersect(devbounds)) {
118        return false;
119    }
120
121    SkBitmap tmp;
122    SkBitmap* bmp;
123    if (bitmap->isNull()) {
124        tmp.setConfig(SkBitmap::kARGB_8888_Config, bitmap->width(),
125                                                   bitmap->height());
126        if (!tmp.allocPixels()) {
127            return false;
128        }
129        bmp = &tmp;
130    } else {
131        bmp = bitmap;
132    }
133
134    SkIRect subrect = srcRect;
135    subrect.offset(-x, -y);
136    SkBitmap bmpSubset;
137    bmp->extractSubset(&bmpSubset, subrect);
138
139    bool result = this->onReadPixels(bmpSubset,
140                                     srcRect.fLeft,
141                                     srcRect.fTop,
142                                     config8888);
143    if (result && bmp == &tmp) {
144        tmp.swap(*bitmap);
145    }
146    return result;
147}
148
149#ifdef SK_CPU_LENDIAN
150    #if   24 == SK_A32_SHIFT && 16 == SK_R32_SHIFT && \
151           8 == SK_G32_SHIFT &&  0 == SK_B32_SHIFT
152        const SkCanvas::Config8888 SkDevice::kPMColorAlias =
153            SkCanvas::kBGRA_Premul_Config8888;
154    #elif 24 == SK_A32_SHIFT &&  0 == SK_R32_SHIFT && \
155           8 == SK_G32_SHIFT && 16 == SK_B32_SHIFT
156        const SkCanvas::Config8888 SkDevice::kPMColorAlias =
157            SkCanvas::kRGBA_Premul_Config8888;
158    #else
159        const SkCanvas::Config8888 SkDevice::kPMColorAlias =
160            (SkCanvas::Config8888) -1;
161    #endif
162#else
163    #if    0 == SK_A32_SHIFT &&   8 == SK_R32_SHIFT && \
164          16 == SK_G32_SHIFT &&  24 == SK_B32_SHIFT
165        const SkCanvas::Config8888 SkDevice::kPMColorAlias =
166            SkCanvas::kBGRA_Premul_Config8888;
167    #elif  0 == SK_A32_SHIFT &&  24 == SK_R32_SHIFT && \
168          16 == SK_G32_SHIFT &&   8 == SK_B32_SHIFT
169        const SkCanvas::Config8888 SkDevice::kPMColorAlias =
170            SkCanvas::kRGBA_Premul_Config8888;
171    #else
172        const SkCanvas::Config8888 SkDevice::kPMColorAlias =
173            (SkCanvas::Config8888) -1;
174    #endif
175#endif
176
177#include <SkConfig8888.h>
178
179bool SkDevice::onReadPixels(const SkBitmap& bitmap,
180                            int x, int y,
181                            SkCanvas::Config8888 config8888) {
182    SkASSERT(SkBitmap::kARGB_8888_Config == bitmap.config());
183    SkASSERT(!bitmap.isNull());
184    SkASSERT(SkIRect::MakeWH(this->width(), this->height()).contains(SkIRect::MakeXYWH(x, y, bitmap.width(), bitmap.height())));
185
186    SkIRect srcRect = SkIRect::MakeXYWH(x, y, bitmap.width(),
187                                              bitmap.height());
188    const SkBitmap& src = this->accessBitmap(false);
189
190    SkBitmap subset;
191    if (!src.extractSubset(&subset, srcRect)) {
192        return false;
193    }
194    if (SkBitmap::kARGB_8888_Config != subset.config()) {
195        // It'd be preferable to do this directly to bitmap.
196        subset.copyTo(&subset, SkBitmap::kARGB_8888_Config);
197    }
198    SkAutoLockPixels alp(bitmap);
199    uint32_t* bmpPixels = reinterpret_cast<uint32_t*>(bitmap.getPixels());
200    if ((SkCanvas::kNative_Premul_Config8888 == config8888 ||
201         kPMColorAlias == config8888)) {
202        SkCopyARGB8888BitmapTo(bmpPixels, bitmap.rowBytes(), subset);
203    } else {
204        SkCopyBitmapToConfig8888(bmpPixels,
205                                 bitmap.rowBytes(),
206                                 config8888,
207                                 subset);
208    }
209    return true;
210}
211
212void SkDevice::writePixels(const SkBitmap& bitmap,
213                           int x, int y,
214                           SkCanvas::Config8888 config8888) {
215    if (bitmap.isNull() || bitmap.getTexture()) {
216        return;
217    }
218    const SkBitmap* sprite = &bitmap;
219    // check whether we have to handle a config8888 that doesn't match SkPMColor
220    if (SkBitmap::kARGB_8888_Config == bitmap.config() &&
221        SkCanvas::kNative_Premul_Config8888 != config8888 &&
222        kPMColorAlias != config8888) {
223
224        // We're going to have to convert from a config8888 to the native config
225        // First we clip to the device bounds.
226        SkBitmap dstBmp = this->accessBitmap(true);
227        SkIRect spriteRect = SkIRect::MakeXYWH(x, y,
228                                               bitmap.width(), bitmap.height());
229        SkIRect devRect = SkIRect::MakeWH(dstBmp.width(), dstBmp.height());
230        if (!spriteRect.intersect(devRect)) {
231            return;
232        }
233
234        // write directly to the device if it has pixels and is SkPMColor
235        bool drawSprite;
236        if (SkBitmap::kARGB_8888_Config == dstBmp.config() && !dstBmp.isNull()) {
237            // we can write directly to the dst when doing the conversion
238            dstBmp.extractSubset(&dstBmp, spriteRect);
239            drawSprite = false;
240        } else {
241            // we convert to a temporary bitmap and draw that as a sprite
242            dstBmp.setConfig(SkBitmap::kARGB_8888_Config,
243                             spriteRect.width(),
244                             spriteRect.height());
245            if (!dstBmp.allocPixels()) {
246                return;
247            }
248            drawSprite = true;
249        }
250
251        // copy pixels to dstBmp and convert from config8888 to native config.
252        SkAutoLockPixels alp(bitmap);
253        uint32_t* srcPixels = bitmap.getAddr32(spriteRect.fLeft - x,
254                                               spriteRect.fTop - y);
255        SkCopyConfig8888ToBitmap(dstBmp,
256                                 srcPixels,
257                                 bitmap.rowBytes(),
258                                 config8888);
259
260        if (drawSprite) {
261            // we've clipped the sprite when we made a copy
262            x = spriteRect.fLeft;
263            y = spriteRect.fTop;
264            sprite = &dstBmp;
265        } else {
266            return;
267        }
268    }
269
270    SkPaint paint;
271    paint.setXfermodeMode(SkXfermode::kSrc_Mode);
272    SkCanvas canvas(this);
273    canvas.drawSprite(*sprite, x, y, &paint);
274}
275
276///////////////////////////////////////////////////////////////////////////////
277
278void SkDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) {
279    draw.drawPaint(paint);
280}
281
282void SkDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode, size_t count,
283                              const SkPoint pts[], const SkPaint& paint) {
284    draw.drawPoints(mode, count, pts, paint);
285}
286
287void SkDevice::drawRect(const SkDraw& draw, const SkRect& r,
288                            const SkPaint& paint) {
289    draw.drawRect(r, paint);
290}
291
292void SkDevice::drawPath(const SkDraw& draw, const SkPath& path,
293                        const SkPaint& paint, const SkMatrix* prePathMatrix,
294                        bool pathIsMutable) {
295    draw.drawPath(path, paint, prePathMatrix, pathIsMutable);
296}
297
298void SkDevice::drawBitmap(const SkDraw& draw, const SkBitmap& bitmap,
299                          const SkIRect* srcRect,
300                          const SkMatrix& matrix, const SkPaint& paint) {
301    SkBitmap        tmp;    // storage if we need a subset of bitmap
302    const SkBitmap* bitmapPtr = &bitmap;
303
304    if (srcRect) {
305        if (!bitmap.extractSubset(&tmp, *srcRect)) {
306            return;     // extraction failed
307        }
308        bitmapPtr = &tmp;
309    }
310    draw.drawBitmap(*bitmapPtr, matrix, paint);
311}
312
313void SkDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
314                              int x, int y, const SkPaint& paint) {
315    draw.drawSprite(bitmap, x, y, paint);
316}
317
318void SkDevice::drawText(const SkDraw& draw, const void* text, size_t len,
319                            SkScalar x, SkScalar y, const SkPaint& paint) {
320    draw.drawText((const char*)text, len, x, y, paint);
321}
322
323void SkDevice::drawPosText(const SkDraw& draw, const void* text, size_t len,
324                               const SkScalar xpos[], SkScalar y,
325                               int scalarsPerPos, const SkPaint& paint) {
326    draw.drawPosText((const char*)text, len, xpos, y, scalarsPerPos, paint);
327}
328
329void SkDevice::drawTextOnPath(const SkDraw& draw, const void* text,
330                                  size_t len, const SkPath& path,
331                                  const SkMatrix* matrix,
332                                  const SkPaint& paint) {
333    draw.drawTextOnPath((const char*)text, len, path, matrix, paint);
334}
335
336#ifdef SK_BUILD_FOR_ANDROID
337void SkDevice::drawPosTextOnPath(const SkDraw& draw, const void* text, size_t len,
338                                     const SkPoint pos[], const SkPaint& paint,
339                                     const SkPath& path, const SkMatrix* matrix) {
340    draw.drawPosTextOnPath((const char*)text, len, pos, paint, path, matrix);
341}
342#endif
343
344void SkDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
345                                int vertexCount,
346                                const SkPoint verts[], const SkPoint textures[],
347                                const SkColor colors[], SkXfermode* xmode,
348                                const uint16_t indices[], int indexCount,
349                                const SkPaint& paint) {
350    draw.drawVertices(vmode, vertexCount, verts, textures, colors, xmode,
351                      indices, indexCount, paint);
352}
353
354void SkDevice::drawDevice(const SkDraw& draw, SkDevice* device,
355                              int x, int y, const SkPaint& paint) {
356    draw.drawSprite(device->accessBitmap(false), x, y, paint);
357}
358
359///////////////////////////////////////////////////////////////////////////////
360
361bool SkDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) {
362    if (!paint.isLCDRenderText() || !paint.isAntiAlias()) {
363        // we're cool with the paint as is
364        return false;
365    }
366
367    if (SkBitmap::kARGB_8888_Config != fBitmap.config() ||
368#ifndef SK_ENABLE_FAST_SHADERMASK
369        paint.getShader() ||
370        paint.getMaskFilter() ||
371        paint.getColorFilter() ||
372#endif
373        paint.getRasterizer() ||
374        paint.getPathEffect() ||
375        paint.isFakeBoldText() ||
376        paint.getStyle() != SkPaint::kFill_Style ||
377        !SkXfermode::IsMode(paint.getXfermode(), SkXfermode::kSrcOver_Mode)) {
378        // turn off lcd
379        flags->fFlags = paint.getFlags() & ~SkPaint::kLCDRenderText_Flag;
380        flags->fHinting = paint.getHinting();
381        return true;
382    }
383    // we're cool with the paint as is
384    return false;
385}
386
387