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