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 kN32_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
71SkBitmapDevice* SkBitmapDevice::Create(const SkImageInfo& origInfo,
72                                       const SkDeviceProperties* props) {
73    SkImageInfo info = origInfo;
74    if (!valid_for_bitmap_device(info, &info.fAlphaType)) {
75        return NULL;
76    }
77
78    SkBitmap bitmap;
79
80    if (kUnknown_SkColorType == info.colorType()) {
81        if (!bitmap.setInfo(info)) {
82            return NULL;
83        }
84    } else {
85        if (!bitmap.allocPixels(info)) {
86            return NULL;
87        }
88        if (!bitmap.info().isOpaque()) {
89            bitmap.eraseColor(SK_ColorTRANSPARENT);
90        }
91    }
92
93    if (props) {
94        return SkNEW_ARGS(SkBitmapDevice, (bitmap, *props));
95    } else {
96        return SkNEW_ARGS(SkBitmapDevice, (bitmap));
97    }
98}
99
100SkImageInfo SkBitmapDevice::imageInfo() const {
101    return fBitmap.info();
102}
103
104void SkBitmapDevice::replaceBitmapBackendForRasterSurface(const SkBitmap& bm) {
105    SkASSERT(bm.width() == fBitmap.width());
106    SkASSERT(bm.height() == fBitmap.height());
107    fBitmap = bm;   // intent is to use bm's pixelRef (and rowbytes/config)
108    fBitmap.lockPixels();
109}
110
111SkBaseDevice* SkBitmapDevice::onCreateDevice(const SkImageInfo& info, Usage usage) {
112    return SkBitmapDevice::Create(info, &this->getDeviceProperties());
113}
114
115void SkBitmapDevice::lockPixels() {
116    if (fBitmap.lockPixelsAreWritable()) {
117        fBitmap.lockPixels();
118    }
119}
120
121void SkBitmapDevice::unlockPixels() {
122    if (fBitmap.lockPixelsAreWritable()) {
123        fBitmap.unlockPixels();
124    }
125}
126
127void SkBitmapDevice::clear(SkColor color) {
128    fBitmap.eraseColor(color);
129}
130
131const SkBitmap& SkBitmapDevice::onAccessBitmap() {
132    return fBitmap;
133}
134
135bool SkBitmapDevice::canHandleImageFilter(const SkImageFilter*) {
136    return false;
137}
138
139bool SkBitmapDevice::filterImage(const SkImageFilter* filter, const SkBitmap& src,
140                                 const SkImageFilter::Context& ctx, SkBitmap* result,
141                                 SkIPoint* offset) {
142    return false;
143}
144
145bool SkBitmapDevice::allowImageFilter(const SkImageFilter*) {
146    return true;
147}
148
149void* SkBitmapDevice::onAccessPixels(SkImageInfo* info, size_t* rowBytes) {
150    if (fBitmap.getPixels()) {
151        *info = fBitmap.info();
152        *rowBytes = fBitmap.rowBytes();
153        return fBitmap.getPixels();
154    }
155    return NULL;
156}
157
158static void rect_memcpy(void* dst, size_t dstRB, const void* src, size_t srcRB, size_t bytesPerRow,
159                        int rowCount) {
160    SkASSERT(bytesPerRow <= srcRB);
161    SkASSERT(bytesPerRow <= dstRB);
162    for (int i = 0; i < rowCount; ++i) {
163        memcpy(dst, src, bytesPerRow);
164        dst = (char*)dst + dstRB;
165        src = (const char*)src + srcRB;
166    }
167}
168
169#include "SkConfig8888.h"
170
171static bool copy_pixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes,
172                        const SkImageInfo& srcInfo, const void* srcPixels, size_t srcRowBytes) {
173    if (srcInfo.dimensions() != dstInfo.dimensions()) {
174        return false;
175    }
176    if (4 == srcInfo.bytesPerPixel() && 4 == dstInfo.bytesPerPixel()) {
177        SkDstPixelInfo dstPI;
178        dstPI.fColorType = dstInfo.colorType();
179        dstPI.fAlphaType = dstInfo.alphaType();
180        dstPI.fPixels = dstPixels;
181        dstPI.fRowBytes = dstRowBytes;
182
183        SkSrcPixelInfo srcPI;
184        srcPI.fColorType = srcInfo.colorType();
185        srcPI.fAlphaType = srcInfo.alphaType();
186        srcPI.fPixels = srcPixels;
187        srcPI.fRowBytes = srcRowBytes;
188
189        return srcPI.convertPixelsTo(&dstPI, srcInfo.width(), srcInfo.height());
190    }
191    if (srcInfo.colorType() == dstInfo.colorType()) {
192        switch (srcInfo.colorType()) {
193            case kRGB_565_SkColorType:
194            case kAlpha_8_SkColorType:
195                break;
196            case kARGB_4444_SkColorType:
197                if (srcInfo.alphaType() != dstInfo.alphaType()) {
198                    return false;
199                }
200                break;
201            default:
202                return false;
203        }
204        rect_memcpy(dstPixels, dstRowBytes, srcPixels, srcRowBytes,
205                    srcInfo.width() * srcInfo.bytesPerPixel(), srcInfo.height());
206    }
207    // TODO: add support for more conversions as needed
208    return false;
209}
210
211bool SkBitmapDevice::onWritePixels(const SkImageInfo& srcInfo, const void* srcPixels,
212                                   size_t srcRowBytes, int x, int y) {
213    // since we don't stop creating un-pixeled devices yet, check for no pixels here
214    if (NULL == fBitmap.getPixels()) {
215        return false;
216    }
217
218    SkImageInfo dstInfo = fBitmap.info();
219    dstInfo.fWidth = srcInfo.width();
220    dstInfo.fHeight = srcInfo.height();
221
222    void* dstPixels = fBitmap.getAddr(x, y);
223    size_t dstRowBytes = fBitmap.rowBytes();
224
225    if (copy_pixels(dstInfo, dstPixels, dstRowBytes, srcInfo, srcPixels, srcRowBytes)) {
226        fBitmap.notifyPixelsChanged();
227        return true;
228    }
229    return false;
230}
231
232bool SkBitmapDevice::onReadPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes,
233                                  int x, int y) {
234    // since we don't stop creating un-pixeled devices yet, check for no pixels here
235    if (NULL == fBitmap.getPixels()) {
236        return false;
237    }
238
239    SkImageInfo srcInfo = fBitmap.info();
240
241    // perhaps can relax these in the future
242    if (4 != dstInfo.bytesPerPixel()) {
243        return false;
244    }
245    if (4 != srcInfo.bytesPerPixel()) {
246        return false;
247    }
248
249    srcInfo.fWidth = dstInfo.width();
250    srcInfo.fHeight = dstInfo.height();
251
252    const void* srcPixels = fBitmap.getAddr(x, y);
253    const size_t srcRowBytes = fBitmap.rowBytes();
254
255    return copy_pixels(dstInfo, dstPixels, dstRowBytes, srcInfo, srcPixels, srcRowBytes);
256}
257
258///////////////////////////////////////////////////////////////////////////////
259
260void SkBitmapDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) {
261    draw.drawPaint(paint);
262}
263
264void SkBitmapDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode, size_t count,
265                                const SkPoint pts[], const SkPaint& paint) {
266    CHECK_FOR_ANNOTATION(paint);
267    draw.drawPoints(mode, count, pts, paint);
268}
269
270void SkBitmapDevice::drawRect(const SkDraw& draw, const SkRect& r, const SkPaint& paint) {
271    CHECK_FOR_ANNOTATION(paint);
272    draw.drawRect(r, paint);
273}
274
275void SkBitmapDevice::drawOval(const SkDraw& draw, const SkRect& oval, const SkPaint& paint) {
276    CHECK_FOR_ANNOTATION(paint);
277
278    SkPath path;
279    path.addOval(oval);
280    // call the VIRTUAL version, so any subclasses who do handle drawPath aren't
281    // required to override drawOval.
282    this->drawPath(draw, path, paint, NULL, true);
283}
284
285void SkBitmapDevice::drawRRect(const SkDraw& draw, const SkRRect& rrect, const SkPaint& paint) {
286    CHECK_FOR_ANNOTATION(paint);
287
288#ifdef SK_IGNORE_BLURRED_RRECT_OPT
289    SkPath  path;
290
291    path.addRRect(rrect);
292    // call the VIRTUAL version, so any subclasses who do handle drawPath aren't
293    // required to override drawRRect.
294    this->drawPath(draw, path, paint, NULL, true);
295#else
296    draw.drawRRect(rrect, paint);
297#endif
298}
299
300void SkBitmapDevice::drawPath(const SkDraw& draw, const SkPath& path,
301                              const SkPaint& paint, const SkMatrix* prePathMatrix,
302                              bool pathIsMutable) {
303    CHECK_FOR_ANNOTATION(paint);
304    draw.drawPath(path, paint, prePathMatrix, pathIsMutable);
305}
306
307void SkBitmapDevice::drawBitmap(const SkDraw& draw, const SkBitmap& bitmap,
308                                const SkMatrix& matrix, const SkPaint& paint) {
309    draw.drawBitmap(bitmap, matrix, paint);
310}
311
312void SkBitmapDevice::drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap,
313                                    const SkRect* src, const SkRect& dst,
314                                    const SkPaint& paint,
315                                    SkCanvas::DrawBitmapRectFlags flags) {
316    SkMatrix    matrix;
317    SkRect      bitmapBounds, tmpSrc, tmpDst;
318    SkBitmap    tmpBitmap;
319
320    bitmapBounds.isetWH(bitmap.width(), bitmap.height());
321
322    // Compute matrix from the two rectangles
323    if (src) {
324        tmpSrc = *src;
325    } else {
326        tmpSrc = bitmapBounds;
327    }
328    matrix.setRectToRect(tmpSrc, dst, SkMatrix::kFill_ScaleToFit);
329
330    const SkRect* dstPtr = &dst;
331    const SkBitmap* bitmapPtr = &bitmap;
332
333    // clip the tmpSrc to the bounds of the bitmap, and recompute dstRect if
334    // needed (if the src was clipped). No check needed if src==null.
335    if (src) {
336        if (!bitmapBounds.contains(*src)) {
337            if (!tmpSrc.intersect(bitmapBounds)) {
338                return; // nothing to draw
339            }
340            // recompute dst, based on the smaller tmpSrc
341            matrix.mapRect(&tmpDst, tmpSrc);
342            dstPtr = &tmpDst;
343        }
344
345        // since we may need to clamp to the borders of the src rect within
346        // the bitmap, we extract a subset.
347        SkIRect srcIR;
348        tmpSrc.roundOut(&srcIR);
349        if (!bitmap.extractSubset(&tmpBitmap, srcIR)) {
350            return;
351        }
352        bitmapPtr = &tmpBitmap;
353
354        // Since we did an extract, we need to adjust the matrix accordingly
355        SkScalar dx = 0, dy = 0;
356        if (srcIR.fLeft > 0) {
357            dx = SkIntToScalar(srcIR.fLeft);
358        }
359        if (srcIR.fTop > 0) {
360            dy = SkIntToScalar(srcIR.fTop);
361        }
362        if (dx || dy) {
363            matrix.preTranslate(dx, dy);
364        }
365
366        SkRect extractedBitmapBounds;
367        extractedBitmapBounds.isetWH(bitmapPtr->width(), bitmapPtr->height());
368        if (extractedBitmapBounds == tmpSrc) {
369            // no fractional part in src, we can just call drawBitmap
370            goto USE_DRAWBITMAP;
371        }
372    } else {
373        USE_DRAWBITMAP:
374        // We can go faster by just calling drawBitmap, which will concat the
375        // matrix with the CTM, and try to call drawSprite if it can. If not,
376        // it will make a shader and call drawRect, as we do below.
377        this->drawBitmap(draw, *bitmapPtr, matrix, paint);
378        return;
379    }
380
381    // construct a shader, so we can call drawRect with the dst
382    SkShader* s = SkShader::CreateBitmapShader(*bitmapPtr,
383                                               SkShader::kClamp_TileMode,
384                                               SkShader::kClamp_TileMode,
385                                               &matrix);
386    if (NULL == s) {
387        return;
388    }
389
390    SkPaint paintWithShader(paint);
391    paintWithShader.setStyle(SkPaint::kFill_Style);
392    paintWithShader.setShader(s)->unref();
393
394    // Call ourself, in case the subclass wanted to share this setup code
395    // but handle the drawRect code themselves.
396    this->drawRect(draw, *dstPtr, paintWithShader);
397}
398
399void SkBitmapDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
400                                int x, int y, const SkPaint& paint) {
401    draw.drawSprite(bitmap, x, y, paint);
402}
403
404void SkBitmapDevice::drawText(const SkDraw& draw, const void* text, size_t len,
405                              SkScalar x, SkScalar y, const SkPaint& paint) {
406    draw.drawText((const char*)text, len, x, y, paint);
407}
408
409void SkBitmapDevice::drawPosText(const SkDraw& draw, const void* text, size_t len,
410                                 const SkScalar xpos[], SkScalar y,
411                                 int scalarsPerPos, const SkPaint& paint) {
412    draw.drawPosText((const char*)text, len, xpos, y, scalarsPerPos, paint);
413}
414
415void SkBitmapDevice::drawTextOnPath(const SkDraw& draw, const void* text,
416                                    size_t len, const SkPath& path,
417                                    const SkMatrix* matrix,
418                                    const SkPaint& paint) {
419    draw.drawTextOnPath((const char*)text, len, path, matrix, paint);
420}
421
422void SkBitmapDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
423                                  int vertexCount,
424                                  const SkPoint verts[], const SkPoint textures[],
425                                  const SkColor colors[], SkXfermode* xmode,
426                                  const uint16_t indices[], int indexCount,
427                                  const SkPaint& paint) {
428    draw.drawVertices(vmode, vertexCount, verts, textures, colors, xmode,
429                      indices, indexCount, paint);
430}
431
432void SkBitmapDevice::drawDevice(const SkDraw& draw, SkBaseDevice* device,
433                                int x, int y, const SkPaint& paint) {
434    const SkBitmap& src = device->accessBitmap(false);
435    draw.drawSprite(src, x, y, paint);
436}
437
438SkSurface* SkBitmapDevice::newSurface(const SkImageInfo& info) {
439    return SkSurface::NewRaster(info);
440}
441
442const void* SkBitmapDevice::peekPixels(SkImageInfo* info, size_t* rowBytes) {
443    const SkImageInfo bmInfo = fBitmap.info();
444    if (fBitmap.getPixels() && (kUnknown_SkColorType != bmInfo.colorType())) {
445        if (info) {
446            *info = bmInfo;
447        }
448        if (rowBytes) {
449            *rowBytes = fBitmap.rowBytes();
450        }
451        return fBitmap.getPixels();
452    }
453    return NULL;
454}
455
456///////////////////////////////////////////////////////////////////////////////
457
458bool SkBitmapDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) {
459    if (!paint.isLCDRenderText() || !paint.isAntiAlias()) {
460        // we're cool with the paint as is
461        return false;
462    }
463
464    if (kN32_SkColorType != fBitmap.colorType() ||
465        paint.getRasterizer() ||
466        paint.getPathEffect() ||
467        paint.isFakeBoldText() ||
468        paint.getStyle() != SkPaint::kFill_Style ||
469        !SkXfermode::IsMode(paint.getXfermode(), SkXfermode::kSrcOver_Mode)) {
470        // turn off lcd
471        flags->fFlags = paint.getFlags() & ~SkPaint::kLCDRenderText_Flag;
472        flags->fHinting = paint.getHinting();
473        return true;
474    }
475    // we're cool with the paint as is
476    return false;
477}
478