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