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