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