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