SkBitmapDevice.cpp revision 231f6b81c22001cac4ea87ea412c4d6fd10ffb8a
1/*
2 * Copyright 2013 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "SkBitmapDevice.h"
9#include "SkConfig8888.h"
10#include "SkDraw.h"
11#include "SkRasterClip.h"
12#include "SkShader.h"
13#include "SkSurface.h"
14
15#define CHECK_FOR_ANNOTATION(paint) \
16    do { if (paint.getAnnotation()) { return; } } while (0)
17
18static bool valid_for_bitmap_device(const SkImageInfo& info,
19                                    SkAlphaType* newAlphaType) {
20    if (info.width() < 0 || info.height() < 0) {
21        return false;
22    }
23
24    // TODO: can we stop supporting kUnknown in SkBitmkapDevice?
25    if (kUnknown_SkColorType == info.colorType()) {
26        if (newAlphaType) {
27            *newAlphaType = kIgnore_SkAlphaType;
28        }
29        return true;
30    }
31
32    switch (info.alphaType()) {
33        case kPremul_SkAlphaType:
34        case kOpaque_SkAlphaType:
35            break;
36        default:
37            return false;
38    }
39
40    SkAlphaType canonicalAlphaType = info.alphaType();
41
42    switch (info.colorType()) {
43        case kAlpha_8_SkColorType:
44            break;
45        case kRGB_565_SkColorType:
46            canonicalAlphaType = kOpaque_SkAlphaType;
47            break;
48        case kPMColor_SkColorType:
49            break;
50        default:
51            return false;
52    }
53
54    if (newAlphaType) {
55        *newAlphaType = canonicalAlphaType;
56    }
57    return true;
58}
59
60SkBitmapDevice::SkBitmapDevice(const SkBitmap& bitmap) : fBitmap(bitmap) {
61    SkASSERT(valid_for_bitmap_device(bitmap.info(), NULL));
62}
63
64SkBitmapDevice::SkBitmapDevice(const SkBitmap& bitmap, const SkDeviceProperties& deviceProperties)
65    : SkBaseDevice(deviceProperties)
66    , fBitmap(bitmap)
67{
68    SkASSERT(valid_for_bitmap_device(bitmap.info(), NULL));
69}
70
71#ifdef SK_SUPPORT_LEGACY_COMPATIBLEDEVICE_CONFIG
72void SkBitmapDevice::init(SkBitmap::Config config, int width, int height, bool isOpaque) {
73    fBitmap.setConfig(config, width, height, 0, isOpaque ?
74                      kOpaque_SkAlphaType : kPremul_SkAlphaType);
75
76    if (SkBitmap::kNo_Config != config) {
77        if (!fBitmap.allocPixels()) {
78            // indicate failure by zeroing our bitmap
79            fBitmap.setConfig(config, 0, 0, 0, isOpaque ?
80                              kOpaque_SkAlphaType : kPremul_SkAlphaType);
81        } else if (!isOpaque) {
82            fBitmap.eraseColor(SK_ColorTRANSPARENT);
83        }
84    }
85}
86
87SkBitmapDevice::SkBitmapDevice(SkBitmap::Config config, int width, int height, bool isOpaque) {
88    this->init(config, width, height, isOpaque);
89}
90
91SkBitmapDevice::SkBitmapDevice(SkBitmap::Config config, int width, int height, bool isOpaque,
92                               const SkDeviceProperties& deviceProperties)
93    : SkBaseDevice(deviceProperties)
94{
95    this->init(config, width, height, isOpaque);
96}
97#endif
98SkBitmapDevice* SkBitmapDevice::Create(const SkImageInfo& origInfo,
99                                       const SkDeviceProperties* props) {
100    SkImageInfo info = origInfo;
101    if (!valid_for_bitmap_device(info, &info.fAlphaType)) {
102        return NULL;
103    }
104
105    SkBitmap bitmap;
106
107    if (kUnknown_SkColorType == info.colorType()) {
108        if (!bitmap.setConfig(info)) {
109            return NULL;
110        }
111    } else {
112        if (!bitmap.allocPixels(info)) {
113            return NULL;
114        }
115        if (!bitmap.info().isOpaque()) {
116            bitmap.eraseColor(SK_ColorTRANSPARENT);
117        }
118    }
119
120    if (props) {
121        return SkNEW_ARGS(SkBitmapDevice, (bitmap, *props));
122    } else {
123        return SkNEW_ARGS(SkBitmapDevice, (bitmap));
124    }
125}
126
127SkImageInfo SkBitmapDevice::imageInfo() const {
128    return fBitmap.info();
129}
130
131void SkBitmapDevice::replaceBitmapBackendForRasterSurface(const SkBitmap& bm) {
132    SkASSERT(bm.width() == fBitmap.width());
133    SkASSERT(bm.height() == fBitmap.height());
134    fBitmap = bm;   // intent is to use bm's pixelRef (and rowbytes/config)
135    fBitmap.lockPixels();
136}
137
138SkBaseDevice* SkBitmapDevice::onCreateDevice(const SkImageInfo& info, Usage usage) {
139    return SkBitmapDevice::Create(info, &this->getDeviceProperties());
140}
141
142void SkBitmapDevice::lockPixels() {
143    if (fBitmap.lockPixelsAreWritable()) {
144        fBitmap.lockPixels();
145    }
146}
147
148void SkBitmapDevice::unlockPixels() {
149    if (fBitmap.lockPixelsAreWritable()) {
150        fBitmap.unlockPixels();
151    }
152}
153
154void SkBitmapDevice::clear(SkColor color) {
155    fBitmap.eraseColor(color);
156}
157
158const SkBitmap& SkBitmapDevice::onAccessBitmap() {
159    return fBitmap;
160}
161
162bool SkBitmapDevice::canHandleImageFilter(const SkImageFilter*) {
163    return false;
164}
165
166bool SkBitmapDevice::filterImage(const SkImageFilter* filter, const SkBitmap& src,
167                                 const SkImageFilter::Context& ctx, SkBitmap* result,
168                                 SkIPoint* offset) {
169    return false;
170}
171
172bool SkBitmapDevice::allowImageFilter(const SkImageFilter*) {
173    return true;
174}
175
176#ifdef SK_SUPPORT_LEGACY_READPIXELSCONFIG
177bool SkBitmapDevice::onReadPixels(const SkBitmap& bitmap,
178                                  int x, int y,
179                                  SkCanvas::Config8888 config8888) {
180    SkASSERT(SkBitmap::kARGB_8888_Config == bitmap.config());
181    SkASSERT(!bitmap.isNull());
182    SkASSERT(SkIRect::MakeWH(this->width(), this->height()).contains(SkIRect::MakeXYWH(x, y,
183                                                                          bitmap.width(),
184                                                                          bitmap.height())));
185
186    SkIRect srcRect = SkIRect::MakeXYWH(x, y, bitmap.width(), bitmap.height());
187    const SkBitmap& src = this->accessBitmap(false);
188
189    SkBitmap subset;
190    if (!src.extractSubset(&subset, srcRect)) {
191        return false;
192    }
193    if (kPMColor_SkColorType != subset.colorType()) {
194        // It'd be preferable to do this directly to bitmap.
195        subset.copyTo(&subset, kPMColor_SkColorType);
196    }
197    SkAutoLockPixels alp(bitmap);
198    uint32_t* bmpPixels = reinterpret_cast<uint32_t*>(bitmap.getPixels());
199    SkCopyBitmapToConfig8888(bmpPixels, bitmap.rowBytes(), config8888, subset);
200    return true;
201}
202#endif
203
204void* SkBitmapDevice::onAccessPixels(SkImageInfo* info, size_t* rowBytes) {
205    if (fBitmap.getPixels()) {
206        *info = fBitmap.info();
207        *rowBytes = fBitmap.rowBytes();
208        return fBitmap.getPixels();
209    }
210    return NULL;
211}
212
213static void rect_memcpy(void* dst, size_t dstRB, const void* src, size_t srcRB, size_t bytesPerRow,
214                        int rowCount) {
215    SkASSERT(bytesPerRow <= srcRB);
216    SkASSERT(bytesPerRow <= dstRB);
217    for (int i = 0; i < rowCount; ++i) {
218        memcpy(dst, src, bytesPerRow);
219        dst = (char*)dst + dstRB;
220        src = (const char*)src + srcRB;
221    }
222}
223
224static bool info2config8888(const SkImageInfo& info, SkCanvas::Config8888* config) {
225    bool pre;
226    switch (info.alphaType()) {
227        case kPremul_SkAlphaType:
228        case kOpaque_SkAlphaType:
229            pre = true;
230            break;
231        case kUnpremul_SkAlphaType:
232            pre = false;
233            break;
234        default:
235            return false;
236    }
237    switch (info.colorType()) {
238        case kRGBA_8888_SkColorType:
239            *config = pre ? SkCanvas::kRGBA_Premul_Config8888 : SkCanvas::kRGBA_Unpremul_Config8888;
240            return true;
241        case kBGRA_8888_SkColorType:
242            *config = pre ? SkCanvas::kBGRA_Premul_Config8888 : SkCanvas::kBGRA_Unpremul_Config8888;
243            return true;
244        default:
245            return false;
246    }
247}
248
249// TODO: make this guy real, and not rely on legacy config8888 utility
250#include "SkConfig8888.h"
251static bool copy_pixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes,
252                        const SkImageInfo& srcInfo, const void* srcPixels, size_t srcRowBytes) {
253    if (srcInfo.dimensions() != dstInfo.dimensions()) {
254        return false;
255    }
256    if (4 == srcInfo.bytesPerPixel() && 4 == dstInfo.bytesPerPixel()) {
257        SkCanvas::Config8888 srcConfig, dstConfig;
258        if (!info2config8888(srcInfo, &srcConfig) || !info2config8888(dstInfo, &dstConfig)) {
259            return false;
260        }
261        SkConvertConfig8888Pixels((uint32_t*)dstPixels, dstRowBytes, dstConfig,
262                                  (const uint32_t*)srcPixels, srcRowBytes, srcConfig,
263                                  srcInfo.width(), srcInfo.height());
264        return true;
265    }
266    if (srcInfo.colorType() == dstInfo.colorType()) {
267        switch (srcInfo.colorType()) {
268            case kRGB_565_SkColorType:
269            case kAlpha_8_SkColorType:
270                break;
271            case kARGB_4444_SkColorType:
272                if (srcInfo.alphaType() != dstInfo.alphaType()) {
273                    return false;
274                }
275                break;
276            default:
277                return false;
278        }
279        rect_memcpy(dstPixels, dstRowBytes, srcPixels, srcRowBytes,
280                    srcInfo.width() * srcInfo.bytesPerPixel(), srcInfo.height());
281    }
282    // TODO: add support for more conversions as needed
283    return false;
284}
285
286bool SkBitmapDevice::onWritePixels(const SkImageInfo& srcInfo, const void* srcPixels,
287                                   size_t srcRowBytes, int x, int y) {
288    // since we don't stop creating un-pixeled devices yet, check for no pixels here
289    if (NULL == fBitmap.getPixels()) {
290        return false;
291    }
292
293    SkImageInfo dstInfo = fBitmap.info();
294    dstInfo.fWidth = srcInfo.width();
295    dstInfo.fHeight = srcInfo.height();
296
297    void* dstPixels = fBitmap.getAddr(x, y);
298    size_t dstRowBytes = fBitmap.rowBytes();
299
300    if (copy_pixels(dstInfo, dstPixels, dstRowBytes, srcInfo, srcPixels, srcRowBytes)) {
301        fBitmap.notifyPixelsChanged();
302        return true;
303    }
304    return false;
305}
306
307bool SkBitmapDevice::onReadPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes,
308                                  int x, int y) {
309    // since we don't stop creating un-pixeled devices yet, check for no pixels here
310    if (NULL == fBitmap.getPixels()) {
311        return false;
312    }
313
314    SkImageInfo srcInfo = fBitmap.info();
315
316    // perhaps can relax these in the future
317    if (4 != dstInfo.bytesPerPixel()) {
318        return false;
319    }
320    if (4 != srcInfo.bytesPerPixel()) {
321        return false;
322    }
323
324    srcInfo.fWidth = dstInfo.width();
325    srcInfo.fHeight = dstInfo.height();
326
327    const void* srcPixels = fBitmap.getAddr(x, y);
328    const size_t srcRowBytes = fBitmap.rowBytes();
329
330    return copy_pixels(dstInfo, dstPixels, dstRowBytes, srcInfo, srcPixels, srcRowBytes);
331}
332
333///////////////////////////////////////////////////////////////////////////////
334
335void SkBitmapDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) {
336    draw.drawPaint(paint);
337}
338
339void SkBitmapDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode, size_t count,
340                                const SkPoint pts[], const SkPaint& paint) {
341    CHECK_FOR_ANNOTATION(paint);
342    draw.drawPoints(mode, count, pts, paint);
343}
344
345void SkBitmapDevice::drawRect(const SkDraw& draw, const SkRect& r, const SkPaint& paint) {
346    CHECK_FOR_ANNOTATION(paint);
347    draw.drawRect(r, paint);
348}
349
350void SkBitmapDevice::drawOval(const SkDraw& draw, const SkRect& oval, const SkPaint& paint) {
351    CHECK_FOR_ANNOTATION(paint);
352
353    SkPath path;
354    path.addOval(oval);
355    // call the VIRTUAL version, so any subclasses who do handle drawPath aren't
356    // required to override drawOval.
357    this->drawPath(draw, path, paint, NULL, true);
358}
359
360void SkBitmapDevice::drawRRect(const SkDraw& draw, const SkRRect& rrect, const SkPaint& paint) {
361    CHECK_FOR_ANNOTATION(paint);
362
363#ifdef SK_IGNORE_BLURRED_RRECT_OPT
364    SkPath  path;
365
366    path.addRRect(rrect);
367    // call the VIRTUAL version, so any subclasses who do handle drawPath aren't
368    // required to override drawRRect.
369    this->drawPath(draw, path, paint, NULL, true);
370#else
371    draw.drawRRect(rrect, paint);
372#endif
373}
374
375void SkBitmapDevice::drawPath(const SkDraw& draw, const SkPath& path,
376                              const SkPaint& paint, const SkMatrix* prePathMatrix,
377                              bool pathIsMutable) {
378    CHECK_FOR_ANNOTATION(paint);
379    draw.drawPath(path, paint, prePathMatrix, pathIsMutable);
380}
381
382void SkBitmapDevice::drawBitmap(const SkDraw& draw, const SkBitmap& bitmap,
383                                const SkMatrix& matrix, const SkPaint& paint) {
384    draw.drawBitmap(bitmap, matrix, paint);
385}
386
387void SkBitmapDevice::drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap,
388                                    const SkRect* src, const SkRect& dst,
389                                    const SkPaint& paint,
390                                    SkCanvas::DrawBitmapRectFlags flags) {
391    SkMatrix    matrix;
392    SkRect      bitmapBounds, tmpSrc, tmpDst;
393    SkBitmap    tmpBitmap;
394
395    bitmapBounds.isetWH(bitmap.width(), bitmap.height());
396
397    // Compute matrix from the two rectangles
398    if (src) {
399        tmpSrc = *src;
400    } else {
401        tmpSrc = bitmapBounds;
402    }
403    matrix.setRectToRect(tmpSrc, dst, SkMatrix::kFill_ScaleToFit);
404
405    const SkRect* dstPtr = &dst;
406    const SkBitmap* bitmapPtr = &bitmap;
407
408    // clip the tmpSrc to the bounds of the bitmap, and recompute dstRect if
409    // needed (if the src was clipped). No check needed if src==null.
410    if (src) {
411        if (!bitmapBounds.contains(*src)) {
412            if (!tmpSrc.intersect(bitmapBounds)) {
413                return; // nothing to draw
414            }
415            // recompute dst, based on the smaller tmpSrc
416            matrix.mapRect(&tmpDst, tmpSrc);
417            dstPtr = &tmpDst;
418        }
419
420        // since we may need to clamp to the borders of the src rect within
421        // the bitmap, we extract a subset.
422        SkIRect srcIR;
423        tmpSrc.roundOut(&srcIR);
424        if (!bitmap.extractSubset(&tmpBitmap, srcIR)) {
425            return;
426        }
427        bitmapPtr = &tmpBitmap;
428
429        // Since we did an extract, we need to adjust the matrix accordingly
430        SkScalar dx = 0, dy = 0;
431        if (srcIR.fLeft > 0) {
432            dx = SkIntToScalar(srcIR.fLeft);
433        }
434        if (srcIR.fTop > 0) {
435            dy = SkIntToScalar(srcIR.fTop);
436        }
437        if (dx || dy) {
438            matrix.preTranslate(dx, dy);
439        }
440
441        SkRect extractedBitmapBounds;
442        extractedBitmapBounds.isetWH(bitmapPtr->width(), bitmapPtr->height());
443        if (extractedBitmapBounds == tmpSrc) {
444            // no fractional part in src, we can just call drawBitmap
445            goto USE_DRAWBITMAP;
446        }
447    } else {
448        USE_DRAWBITMAP:
449        // We can go faster by just calling drawBitmap, which will concat the
450        // matrix with the CTM, and try to call drawSprite if it can. If not,
451        // it will make a shader and call drawRect, as we do below.
452        this->drawBitmap(draw, *bitmapPtr, matrix, paint);
453        return;
454    }
455
456    // construct a shader, so we can call drawRect with the dst
457    SkShader* s = SkShader::CreateBitmapShader(*bitmapPtr,
458                                               SkShader::kClamp_TileMode,
459                                               SkShader::kClamp_TileMode);
460    if (NULL == s) {
461        return;
462    }
463    s->setLocalMatrix(matrix);
464
465    SkPaint paintWithShader(paint);
466    paintWithShader.setStyle(SkPaint::kFill_Style);
467    paintWithShader.setShader(s)->unref();
468
469    // Call ourself, in case the subclass wanted to share this setup code
470    // but handle the drawRect code themselves.
471    this->drawRect(draw, *dstPtr, paintWithShader);
472}
473
474void SkBitmapDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
475                                int x, int y, const SkPaint& paint) {
476    draw.drawSprite(bitmap, x, y, paint);
477}
478
479void SkBitmapDevice::drawText(const SkDraw& draw, const void* text, size_t len,
480                              SkScalar x, SkScalar y, const SkPaint& paint) {
481    draw.drawText((const char*)text, len, x, y, paint);
482}
483
484void SkBitmapDevice::drawPosText(const SkDraw& draw, const void* text, size_t len,
485                                 const SkScalar xpos[], SkScalar y,
486                                 int scalarsPerPos, const SkPaint& paint) {
487    draw.drawPosText((const char*)text, len, xpos, y, scalarsPerPos, paint);
488}
489
490void SkBitmapDevice::drawTextOnPath(const SkDraw& draw, const void* text,
491                                    size_t len, const SkPath& path,
492                                    const SkMatrix* matrix,
493                                    const SkPaint& paint) {
494    draw.drawTextOnPath((const char*)text, len, path, matrix, paint);
495}
496
497void SkBitmapDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
498                                  int vertexCount,
499                                  const SkPoint verts[], const SkPoint textures[],
500                                  const SkColor colors[], SkXfermode* xmode,
501                                  const uint16_t indices[], int indexCount,
502                                  const SkPaint& paint) {
503    draw.drawVertices(vmode, vertexCount, verts, textures, colors, xmode,
504                      indices, indexCount, paint);
505}
506
507void SkBitmapDevice::drawDevice(const SkDraw& draw, SkBaseDevice* device,
508                                int x, int y, const SkPaint& paint) {
509    const SkBitmap& src = device->accessBitmap(false);
510    draw.drawSprite(src, x, y, paint);
511}
512
513SkSurface* SkBitmapDevice::newSurface(const SkImageInfo& info) {
514    return SkSurface::NewRaster(info);
515}
516
517const void* SkBitmapDevice::peekPixels(SkImageInfo* info, size_t* rowBytes) {
518    if (fBitmap.getPixels() && fBitmap.asImageInfo(info)) {
519        if (rowBytes) {
520            *rowBytes = fBitmap.rowBytes();
521        }
522        return fBitmap.getPixels();
523    }
524    return NULL;
525}
526
527///////////////////////////////////////////////////////////////////////////////
528
529bool SkBitmapDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) {
530    if (!paint.isLCDRenderText() || !paint.isAntiAlias()) {
531        // we're cool with the paint as is
532        return false;
533    }
534
535    if (SkBitmap::kARGB_8888_Config != fBitmap.config() ||
536        paint.getRasterizer() ||
537        paint.getPathEffect() ||
538        paint.isFakeBoldText() ||
539        paint.getStyle() != SkPaint::kFill_Style ||
540        !SkXfermode::IsMode(paint.getXfermode(), SkXfermode::kSrcOver_Mode)) {
541        // turn off lcd
542        flags->fFlags = paint.getFlags() & ~SkPaint::kLCDRenderText_Flag;
543        flags->fHinting = paint.getHinting();
544        return true;
545    }
546    // we're cool with the paint as is
547    return false;
548}
549