SkDevice.cpp revision 6850eab42ba4c2a7033a99824b02a2846ce0ef2a
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    static const int NATIVE_A_IDX = SK_A32_SHIFT / 8;
163    static const int NATIVE_R_IDX = SK_R32_SHIFT / 8;
164    static const int NATIVE_G_IDX = SK_G32_SHIFT / 8;
165    static const int NATIVE_B_IDX = SK_B32_SHIFT / 8;
166#else
167    #if    0 == SK_A32_SHIFT &&   8 == SK_R32_SHIFT && \
168          16 == SK_G32_SHIFT &&  24 == SK_B32_SHIFT
169        const SkCanvas::Config8888 SkDevice::kPMColorAlias =
170            SkCanvas::kBGRA_Premul_Config8888;
171    #elif  0 == SK_A32_SHIFT &&  24 == SK_R32_SHIFT && \
172          16 == SK_G32_SHIFT &&   8 == 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    static const int NATIVE_A_IDX = 3 - (SK_A32_SHIFT / 8);
180    static const int NATIVE_R_IDX = 3 - (SK_R32_SHIFT / 8);
181    static const int NATIVE_G_IDX = 3 - (SK_G32_SHIFT / 8);
182    static const int NATIVE_B_IDX = 3 - (SK_B32_SHIFT / 8);
183#endif
184
185#include <SkColorPriv.h>
186
187namespace {
188
189template <int A_IDX, int R_IDX, int G_IDX, int B_IDX>
190inline uint32_t pack_config8888(uint32_t a, uint32_t r,
191                                uint32_t g, uint32_t b) {
192#ifdef SK_CPU_LENDIAN
193    return (a << (A_IDX * 8)) | (r << (R_IDX * 8)) |
194           (g << (G_IDX * 8)) | (b << (B_IDX * 8));
195#else
196    return (a << ((3-A_IDX) * 8)) | (r << ((3-R_IDX) * 8)) |
197           (g << ((3-G_IDX) * 8)) | (b << ((3-B_IDX) * 8));
198#endif
199}
200
201template <bool UNPM, int A_IDX, int R_IDX, int G_IDX, int B_IDX>
202inline void bitmap_copy_to_config8888(const SkBitmap& srcBmp,
203                                        uint32_t* dstPixels,
204                                        size_t dstRowBytes) {
205    SkASSERT(SkBitmap::kARGB_8888_Config == srcBmp.config());
206    SkAutoLockPixels alp(srcBmp);
207    int w = srcBmp.width();
208    int h = srcBmp.height();
209    size_t srcRowBytes = srcBmp.rowBytes();
210
211    intptr_t src = reinterpret_cast<intptr_t>(srcBmp.getPixels());
212    intptr_t dst = reinterpret_cast<intptr_t>(dstPixels);
213
214    for (int y = 0; y < h; ++y) {
215        const SkPMColor* srcRow = reinterpret_cast<SkPMColor*>(src);
216        uint32_t* dstRow  = reinterpret_cast<uint32_t*>(dst);
217        for (int x = 0; x < w; ++x) {
218            SkPMColor pmcolor = srcRow[x];
219            if (UNPM) {
220                U8CPU a, r, g, b;
221                a = SkGetPackedA32(pmcolor);
222                if (a) {
223                    // We're doing the explicit divide to match WebKit layout
224                    // test expectations. We can modify and rebaseline if there
225                    // it can be shown that there is a more performant way to
226                    // unpremul.
227                    r = SkGetPackedR32(pmcolor) * 0xff / a;
228                    g = SkGetPackedG32(pmcolor) * 0xff / a;
229                    b = SkGetPackedB32(pmcolor) * 0xff / a;
230                    dstRow[x] = pack_config8888<A_IDX, R_IDX,
231                                                G_IDX, B_IDX>(a, r, g, b);
232                } else {
233                    dstRow[x] = 0;
234                }
235            } else {
236                dstRow[x] = pack_config8888<A_IDX, R_IDX,
237                                            G_IDX, B_IDX>(
238                                                   SkGetPackedA32(pmcolor),
239                                                   SkGetPackedR32(pmcolor),
240                                                   SkGetPackedG32(pmcolor),
241                                                   SkGetPackedB32(pmcolor));
242            }
243        }
244        dst += dstRowBytes;
245        src += srcRowBytes;
246    }
247}
248
249inline void bitmap_copy_to_native(const SkBitmap& srcBmp,
250                                  uint32_t* dstPixels,
251                                  size_t dstRowBytes) {
252    SkASSERT(SkBitmap::kARGB_8888_Config == srcBmp.config());
253
254    SkAutoLockPixels alp(srcBmp);
255
256    int w = srcBmp.width();
257    int h = srcBmp.height();
258    size_t srcRowBytes = srcBmp.rowBytes();
259
260    size_t tightRowBytes = w * 4;
261
262    char* src = reinterpret_cast<char*>(srcBmp.getPixels());
263    char* dst = reinterpret_cast<char*>(dstPixels);
264
265    if (tightRowBytes == srcRowBytes &&
266        tightRowBytes == dstRowBytes) {
267        memcpy(dst, src, tightRowBytes * h);
268    } else {
269        for (int y = 0; y < h; ++y) {
270            memcpy(dst, src, tightRowBytes);
271            dst += dstRowBytes;
272            src += srcRowBytes;
273        }
274    }
275}
276
277}
278
279bool SkDevice::onReadPixels(const SkBitmap& bitmap,
280                            int x, int y,
281                            SkCanvas::Config8888 config8888) {
282    SkASSERT(SkBitmap::kARGB_8888_Config == bitmap.config());
283    SkASSERT(!bitmap.isNull());
284    SkASSERT(SkIRect::MakeWH(this->width(), this->height()).contains(SkIRect::MakeXYWH(x, y, bitmap.width(), bitmap.height())));
285
286    SkIRect srcRect = SkIRect::MakeXYWH(x, y, bitmap.width(),
287                                              bitmap.height());
288    const SkBitmap& src = this->accessBitmap(false);
289
290    SkBitmap subset;
291    if (!src.extractSubset(&subset, srcRect)) {
292        return false;
293    }
294    if (SkBitmap::kARGB_8888_Config != subset.config()) {
295        // It'd be preferable to do this directly to bitmap.
296        subset.copyTo(&subset, SkBitmap::kARGB_8888_Config);
297    }
298    SkAutoLockPixels alp(bitmap);
299    uint32_t* bmpPixels = reinterpret_cast<uint32_t*>(bitmap.getPixels());
300    if ((SkCanvas::kNative_Premul_Config8888 == config8888 ||
301         kPMColorAlias == config8888)) {
302        bitmap_copy_to_native(subset, bmpPixels, bitmap.rowBytes());
303    } else {
304        switch (config8888) {
305            case SkCanvas::kNative_Premul_Config8888:
306                bitmap_copy_to_config8888<false,
307                                          NATIVE_A_IDX, NATIVE_R_IDX,
308                                          NATIVE_G_IDX, NATIVE_B_IDX>(
309                                                subset,
310                                                bmpPixels,
311                                                bitmap.rowBytes());
312                break;
313            case SkCanvas::kNative_Unpremul_Config8888:
314                bitmap_copy_to_config8888<true,
315                                          NATIVE_A_IDX, NATIVE_R_IDX,
316                                          NATIVE_G_IDX, NATIVE_B_IDX>(
317                                                subset,
318                                                bmpPixels,
319                                                bitmap.rowBytes());
320                break;
321            case SkCanvas::kBGRA_Premul_Config8888:
322                bitmap_copy_to_config8888<false, 3, 2, 1, 0> (
323                                        subset, bmpPixels, bitmap.rowBytes());
324                break;
325            case SkCanvas::kBGRA_Unpremul_Config8888:
326                bitmap_copy_to_config8888<true, 3, 2, 1, 0> (
327                                        subset, bmpPixels, bitmap.rowBytes());
328                break;
329            case SkCanvas::kRGBA_Premul_Config8888:
330                bitmap_copy_to_config8888<false, 3, 0, 1, 2> (
331                                        subset, bmpPixels, bitmap.rowBytes());
332                break;
333            case SkCanvas::kRGBA_Unpremul_Config8888:
334                bitmap_copy_to_config8888<true, 3, 0, 1, 2> (
335                                        subset, bmpPixels, bitmap.rowBytes());
336                break;
337            default:
338                SkASSERT(false && "unexpected Config8888");
339                break;
340        }
341    }
342    return true;
343}
344
345void SkDevice::writePixels(const SkBitmap& bitmap, int x, int y) {
346    SkPaint paint;
347    paint.setXfermodeMode(SkXfermode::kSrc_Mode);
348
349    SkCanvas canvas(this);
350    canvas.drawSprite(bitmap, x, y, &paint);
351}
352
353///////////////////////////////////////////////////////////////////////////////
354
355void SkDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) {
356    draw.drawPaint(paint);
357}
358
359void SkDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode, size_t count,
360                              const SkPoint pts[], const SkPaint& paint) {
361    draw.drawPoints(mode, count, pts, paint);
362}
363
364void SkDevice::drawRect(const SkDraw& draw, const SkRect& r,
365                            const SkPaint& paint) {
366    draw.drawRect(r, paint);
367}
368
369void SkDevice::drawPath(const SkDraw& draw, const SkPath& path,
370                        const SkPaint& paint, const SkMatrix* prePathMatrix,
371                        bool pathIsMutable) {
372    draw.drawPath(path, paint, prePathMatrix, pathIsMutable);
373}
374
375void SkDevice::drawBitmap(const SkDraw& draw, const SkBitmap& bitmap,
376                          const SkIRect* srcRect,
377                          const SkMatrix& matrix, const SkPaint& paint) {
378    SkBitmap        tmp;    // storage if we need a subset of bitmap
379    const SkBitmap* bitmapPtr = &bitmap;
380
381    if (srcRect) {
382        if (!bitmap.extractSubset(&tmp, *srcRect)) {
383            return;     // extraction failed
384        }
385        bitmapPtr = &tmp;
386    }
387    draw.drawBitmap(*bitmapPtr, matrix, paint);
388}
389
390void SkDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
391                              int x, int y, const SkPaint& paint) {
392    draw.drawSprite(bitmap, x, y, paint);
393}
394
395void SkDevice::drawText(const SkDraw& draw, const void* text, size_t len,
396                            SkScalar x, SkScalar y, const SkPaint& paint) {
397    draw.drawText((const char*)text, len, x, y, paint);
398}
399
400void SkDevice::drawPosText(const SkDraw& draw, const void* text, size_t len,
401                               const SkScalar xpos[], SkScalar y,
402                               int scalarsPerPos, const SkPaint& paint) {
403    draw.drawPosText((const char*)text, len, xpos, y, scalarsPerPos, paint);
404}
405
406void SkDevice::drawTextOnPath(const SkDraw& draw, const void* text,
407                                  size_t len, const SkPath& path,
408                                  const SkMatrix* matrix,
409                                  const SkPaint& paint) {
410    draw.drawTextOnPath((const char*)text, len, path, matrix, paint);
411}
412
413#ifdef ANDROID
414void SkDevice::drawPosTextOnPath(const SkDraw& draw, const void* text, size_t len,
415                                     const SkPoint pos[], const SkPaint& paint,
416                                     const SkPath& path, const SkMatrix* matrix) {
417    draw.drawPosTextOnPath((const char*)text, len, pos, paint, path, matrix);
418}
419#endif
420
421void SkDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
422                                int vertexCount,
423                                const SkPoint verts[], const SkPoint textures[],
424                                const SkColor colors[], SkXfermode* xmode,
425                                const uint16_t indices[], int indexCount,
426                                const SkPaint& paint) {
427    draw.drawVertices(vmode, vertexCount, verts, textures, colors, xmode,
428                      indices, indexCount, paint);
429}
430
431void SkDevice::drawDevice(const SkDraw& draw, SkDevice* device,
432                              int x, int y, const SkPaint& paint) {
433    draw.drawSprite(device->accessBitmap(false), x, y, paint);
434}
435
436///////////////////////////////////////////////////////////////////////////////
437
438bool SkDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) {
439    if (!paint.isLCDRenderText() || !paint.isAntiAlias()) {
440        // we're cool with the paint as is
441        return false;
442    }
443
444    if (SkBitmap::kARGB_8888_Config != fBitmap.config() ||
445        paint.getShader() ||
446        paint.getXfermode() || // unless its srcover
447        paint.getMaskFilter() ||
448        paint.getRasterizer() ||
449        paint.getColorFilter() ||
450        paint.getPathEffect() ||
451        paint.isFakeBoldText() ||
452        paint.getStyle() != SkPaint::kFill_Style) {
453        // turn off lcd
454        flags->fFlags = paint.getFlags() & ~SkPaint::kLCDRenderText_Flag;
455        flags->fHinting = paint.getHinting();
456        return true;
457    }
458    // we're cool with the paint as is
459    return false;
460}
461
462