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