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