SkBitmapDevice.cpp revision 385fe4d4b62d7d1dd76116dd570df3290a2f487b
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 "SkMatrix.h"
12#include "SkPaint.h"
13#include "SkPath.h"
14#include "SkPixelRef.h"
15#include "SkPixmap.h"
16#include "SkShader.h"
17#include "SkSurface.h"
18#include "SkXfermode.h"
19
20class SkColorTable;
21
22#define CHECK_FOR_ANNOTATION(paint) \
23    do { if (paint.getAnnotation()) { return; } } while (0)
24
25static bool valid_for_bitmap_device(const SkImageInfo& info,
26                                    SkAlphaType* newAlphaType) {
27    if (info.width() < 0 || info.height() < 0) {
28        return false;
29    }
30
31    // TODO: can we stop supporting kUnknown in SkBitmkapDevice?
32    if (kUnknown_SkColorType == info.colorType()) {
33        if (newAlphaType) {
34            *newAlphaType = kUnknown_SkAlphaType;
35        }
36        return true;
37    }
38
39    switch (info.alphaType()) {
40        case kPremul_SkAlphaType:
41        case kOpaque_SkAlphaType:
42            break;
43        default:
44            return false;
45    }
46
47    SkAlphaType canonicalAlphaType = info.alphaType();
48
49    switch (info.colorType()) {
50        case kAlpha_8_SkColorType:
51            break;
52        case kRGB_565_SkColorType:
53            canonicalAlphaType = kOpaque_SkAlphaType;
54            break;
55        case kN32_SkColorType:
56            break;
57        default:
58            return false;
59    }
60
61    if (newAlphaType) {
62        *newAlphaType = canonicalAlphaType;
63    }
64    return true;
65}
66
67SkBitmapDevice::SkBitmapDevice(const SkBitmap& bitmap)
68    : INHERITED(SkSurfaceProps(SkSurfaceProps::kLegacyFontHost_InitType))
69    , fBitmap(bitmap) {
70    SkASSERT(valid_for_bitmap_device(bitmap.info(), NULL));
71}
72
73SkBitmapDevice* SkBitmapDevice::Create(const SkImageInfo& info) {
74    return Create(info, SkSurfaceProps(SkSurfaceProps::kLegacyFontHost_InitType));
75}
76
77SkBitmapDevice::SkBitmapDevice(const SkBitmap& bitmap, const SkSurfaceProps& surfaceProps)
78    : INHERITED(surfaceProps)
79    , fBitmap(bitmap) {
80    SkASSERT(valid_for_bitmap_device(bitmap.info(), NULL));
81}
82
83SkBitmapDevice* SkBitmapDevice::Create(const SkImageInfo& origInfo,
84                                       const SkSurfaceProps& surfaceProps) {
85    SkAlphaType newAT = origInfo.alphaType();
86    if (!valid_for_bitmap_device(origInfo, &newAT)) {
87        return NULL;
88    }
89
90    const SkImageInfo info = origInfo.makeAlphaType(newAT);
91    SkBitmap bitmap;
92
93    if (kUnknown_SkColorType == info.colorType()) {
94        if (!bitmap.setInfo(info)) {
95            return NULL;
96        }
97    } else {
98        if (!bitmap.tryAllocPixels(info)) {
99            return NULL;
100        }
101        if (!bitmap.info().isOpaque()) {
102            bitmap.eraseColor(SK_ColorTRANSPARENT);
103        }
104    }
105
106    return new SkBitmapDevice(bitmap, surfaceProps);
107}
108
109SkImageInfo SkBitmapDevice::imageInfo() const {
110    return fBitmap.info();
111}
112
113void SkBitmapDevice::setNewSize(const SkISize& size) {
114    SkASSERT(!fBitmap.pixelRef());
115    fBitmap.setInfo(fBitmap.info().makeWH(size.fWidth, size.fHeight));
116}
117
118void SkBitmapDevice::replaceBitmapBackendForRasterSurface(const SkBitmap& bm) {
119    SkASSERT(bm.width() == fBitmap.width());
120    SkASSERT(bm.height() == fBitmap.height());
121    fBitmap = bm;   // intent is to use bm's pixelRef (and rowbytes/config)
122    fBitmap.lockPixels();
123}
124
125SkBaseDevice* SkBitmapDevice::onCreateDevice(const CreateInfo& cinfo, const SkPaint*) {
126    const SkSurfaceProps surfaceProps(this->surfaceProps().flags(), cinfo.fPixelGeometry);
127    return SkBitmapDevice::Create(cinfo.fInfo, surfaceProps);
128}
129
130const SkBitmap& SkBitmapDevice::onAccessBitmap() {
131    return fBitmap;
132}
133
134bool SkBitmapDevice::onAccessPixels(SkPixmap* pmap) {
135    if (fBitmap.lockPixelsAreWritable() && this->onPeekPixels(pmap)) {
136        fBitmap.notifyPixelsChanged();
137        return true;
138    }
139    return false;
140}
141
142bool SkBitmapDevice::onPeekPixels(SkPixmap* pmap) {
143    const SkImageInfo info = fBitmap.info();
144    if (fBitmap.getPixels() && (kUnknown_SkColorType != info.colorType())) {
145        SkColorTable* ctable = NULL;
146        pmap->reset(fBitmap.info(), fBitmap.getPixels(), fBitmap.rowBytes(), ctable);
147        return true;
148    }
149    return false;
150}
151
152bool SkBitmapDevice::onWritePixels(const SkImageInfo& srcInfo, const void* srcPixels,
153                                   size_t srcRowBytes, int x, int y) {
154    // since we don't stop creating un-pixeled devices yet, check for no pixels here
155    if (NULL == fBitmap.getPixels()) {
156        return false;
157    }
158
159    const SkImageInfo dstInfo = fBitmap.info().makeWH(srcInfo.width(), srcInfo.height());
160
161    void* dstPixels = fBitmap.getAddr(x, y);
162    size_t dstRowBytes = fBitmap.rowBytes();
163
164    if (SkPixelInfo::CopyPixels(dstInfo, dstPixels, dstRowBytes, srcInfo, srcPixels, srcRowBytes)) {
165        fBitmap.notifyPixelsChanged();
166        return true;
167    }
168    return false;
169}
170
171bool SkBitmapDevice::onReadPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes,
172                                  int x, int y) {
173    return fBitmap.readPixels(dstInfo, dstPixels, dstRowBytes, x, y);
174}
175
176void SkBitmapDevice::onAttachToCanvas(SkCanvas* canvas) {
177    INHERITED::onAttachToCanvas(canvas);
178    if (fBitmap.lockPixelsAreWritable()) {
179        fBitmap.lockPixels();
180    }
181}
182
183void SkBitmapDevice::onDetachFromCanvas() {
184    INHERITED::onDetachFromCanvas();
185    if (fBitmap.lockPixelsAreWritable()) {
186        fBitmap.unlockPixels();
187    }
188}
189
190///////////////////////////////////////////////////////////////////////////////
191
192void SkBitmapDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) {
193    draw.drawPaint(paint);
194}
195
196void SkBitmapDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode, size_t count,
197                                const SkPoint pts[], const SkPaint& paint) {
198    CHECK_FOR_ANNOTATION(paint);
199    draw.drawPoints(mode, count, pts, paint);
200}
201
202void SkBitmapDevice::drawRect(const SkDraw& draw, const SkRect& r, const SkPaint& paint) {
203    CHECK_FOR_ANNOTATION(paint);
204    draw.drawRect(r, paint);
205}
206
207void SkBitmapDevice::drawOval(const SkDraw& draw, const SkRect& oval, const SkPaint& paint) {
208    CHECK_FOR_ANNOTATION(paint);
209
210    SkPath path;
211    path.addOval(oval);
212    // call the VIRTUAL version, so any subclasses who do handle drawPath aren't
213    // required to override drawOval.
214    this->drawPath(draw, path, paint, NULL, true);
215}
216
217void SkBitmapDevice::drawRRect(const SkDraw& draw, const SkRRect& rrect, const SkPaint& paint) {
218    CHECK_FOR_ANNOTATION(paint);
219
220#ifdef SK_IGNORE_BLURRED_RRECT_OPT
221    SkPath  path;
222
223    path.addRRect(rrect);
224    // call the VIRTUAL version, so any subclasses who do handle drawPath aren't
225    // required to override drawRRect.
226    this->drawPath(draw, path, paint, NULL, true);
227#else
228    draw.drawRRect(rrect, paint);
229#endif
230}
231
232void SkBitmapDevice::drawPath(const SkDraw& draw, const SkPath& path,
233                              const SkPaint& paint, const SkMatrix* prePathMatrix,
234                              bool pathIsMutable) {
235    CHECK_FOR_ANNOTATION(paint);
236    draw.drawPath(path, paint, prePathMatrix, pathIsMutable);
237}
238
239void SkBitmapDevice::drawBitmap(const SkDraw& draw, const SkBitmap& bitmap,
240                                const SkMatrix& matrix, const SkPaint& paint) {
241    draw.drawBitmap(bitmap, matrix, NULL, paint);
242}
243
244void SkBitmapDevice::drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap,
245                                    const SkRect* src, const SkRect& dst,
246                                    const SkPaint& paint, SkCanvas::SrcRectConstraint constraint) {
247    SkMatrix    matrix;
248    SkRect      bitmapBounds, tmpSrc, tmpDst;
249    SkBitmap    tmpBitmap;
250
251    bitmapBounds.isetWH(bitmap.width(), bitmap.height());
252
253    // Compute matrix from the two rectangles
254    if (src) {
255        tmpSrc = *src;
256    } else {
257        tmpSrc = bitmapBounds;
258    }
259    matrix.setRectToRect(tmpSrc, dst, SkMatrix::kFill_ScaleToFit);
260
261    const SkRect* dstPtr = &dst;
262    const SkBitmap* bitmapPtr = &bitmap;
263
264    // clip the tmpSrc to the bounds of the bitmap, and recompute dstRect if
265    // needed (if the src was clipped). No check needed if src==null.
266    if (src) {
267        if (!bitmapBounds.contains(*src)) {
268            if (!tmpSrc.intersect(bitmapBounds)) {
269                return; // nothing to draw
270            }
271            // recompute dst, based on the smaller tmpSrc
272            matrix.mapRect(&tmpDst, tmpSrc);
273            dstPtr = &tmpDst;
274        }
275
276        // since we may need to clamp to the borders of the src rect within
277        // the bitmap, we extract a subset.
278        const SkIRect srcIR = tmpSrc.roundOut();
279        if(bitmap.pixelRef()->getTexture()) {
280            // Accelerated source canvas, don't use extractSubset but readPixels to get the subset.
281            // This way, the pixels are copied in CPU memory instead of GPU memory.
282            bitmap.pixelRef()->readPixels(&tmpBitmap, &srcIR);
283        } else {
284            if (!bitmap.extractSubset(&tmpBitmap, srcIR)) {
285                return;
286            }
287        }
288        bitmapPtr = &tmpBitmap;
289
290        // Since we did an extract, we need to adjust the matrix accordingly
291        SkScalar dx = 0, dy = 0;
292        if (srcIR.fLeft > 0) {
293            dx = SkIntToScalar(srcIR.fLeft);
294        }
295        if (srcIR.fTop > 0) {
296            dy = SkIntToScalar(srcIR.fTop);
297        }
298        if (dx || dy) {
299            matrix.preTranslate(dx, dy);
300        }
301
302        SkRect extractedBitmapBounds;
303        extractedBitmapBounds.isetWH(bitmapPtr->width(), bitmapPtr->height());
304        if (extractedBitmapBounds == tmpSrc) {
305            // no fractional part in src, we can just call drawBitmap
306            goto USE_DRAWBITMAP;
307        }
308    } else {
309        USE_DRAWBITMAP:
310        // We can go faster by just calling drawBitmap, which will concat the
311        // matrix with the CTM, and try to call drawSprite if it can. If not,
312        // it will make a shader and call drawRect, as we do below.
313        draw.drawBitmap(*bitmapPtr, matrix, dstPtr, paint);
314        return;
315    }
316
317    // construct a shader, so we can call drawRect with the dst
318    SkShader* s = SkShader::CreateBitmapShader(*bitmapPtr,
319                                               SkShader::kClamp_TileMode,
320                                               SkShader::kClamp_TileMode,
321                                               &matrix);
322    if (NULL == s) {
323        return;
324    }
325
326    SkPaint paintWithShader(paint);
327    paintWithShader.setStyle(SkPaint::kFill_Style);
328    paintWithShader.setShader(s)->unref();
329
330    // Call ourself, in case the subclass wanted to share this setup code
331    // but handle the drawRect code themselves.
332    this->drawRect(draw, *dstPtr, paintWithShader);
333}
334
335void SkBitmapDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
336                                int x, int y, const SkPaint& paint) {
337    draw.drawSprite(bitmap, x, y, paint);
338}
339
340void SkBitmapDevice::drawText(const SkDraw& draw, const void* text, size_t len,
341                              SkScalar x, SkScalar y, const SkPaint& paint) {
342    draw.drawText((const char*)text, len, x, y, paint);
343}
344
345void SkBitmapDevice::drawPosText(const SkDraw& draw, const void* text, size_t len,
346                                 const SkScalar xpos[], int scalarsPerPos,
347                                 const SkPoint& offset, const SkPaint& paint) {
348    draw.drawPosText((const char*)text, len, xpos, scalarsPerPos, offset, paint);
349}
350
351void SkBitmapDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
352                                  int vertexCount,
353                                  const SkPoint verts[], const SkPoint textures[],
354                                  const SkColor colors[], SkXfermode* xmode,
355                                  const uint16_t indices[], int indexCount,
356                                  const SkPaint& paint) {
357    draw.drawVertices(vmode, vertexCount, verts, textures, colors, xmode,
358                      indices, indexCount, paint);
359}
360
361void SkBitmapDevice::drawDevice(const SkDraw& draw, SkBaseDevice* device,
362                                int x, int y, const SkPaint& paint) {
363    draw.drawSprite(static_cast<SkBitmapDevice*>(device)->fBitmap, x, y, paint);
364}
365
366SkSurface* SkBitmapDevice::newSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
367    return SkSurface::NewRaster(info, &props);
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::onShouldDisableLCD(const SkPaint& paint) const {
379    if (kN32_SkColorType != fBitmap.colorType() ||
380        paint.getRasterizer() ||
381        paint.getPathEffect() ||
382        paint.isFakeBoldText() ||
383        paint.getStyle() != SkPaint::kFill_Style ||
384        !SkXfermode::IsMode(paint.getXfermode(), SkXfermode::kSrcOver_Mode))
385    {
386        return true;
387    }
388    return false;
389}
390