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