SkDevice.cpp revision 772c4e6d09f5e0971a584d2035ee789483d6f47a
1
2/*
3 * Copyright 2011 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8#include "SkBitmapDevice.h"
9#include "SkDevice.h"
10#include "SkDeviceProperties.h"
11#include "SkDraw.h"
12#include "SkImageFilter.h"
13#include "SkMetaData.h"
14#include "SkRasterClip.h"
15#include "SkRect.h"
16#include "SkRRect.h"
17#include "SkShader.h"
18
19SK_DEFINE_INST_COUNT(SkBaseDevice)
20SK_DEFINE_INST_COUNT(SkBitmapDevice)
21
22///////////////////////////////////////////////////////////////////////////////
23
24#define CHECK_FOR_NODRAW_ANNOTATION(paint) \
25    do { if (paint.isNoDrawAnnotation()) { return; } } while (0)
26
27///////////////////////////////////////////////////////////////////////////////
28
29SkBitmapDevice::SkBitmapDevice(const SkBitmap& bitmap)
30    : fBitmap(bitmap) {
31    SkASSERT(SkBitmap::kARGB_4444_Config != bitmap.config());
32}
33
34SkBaseDevice::SkBaseDevice()
35    : fLeakyProperties(SkDeviceProperties::MakeDefault())
36#ifdef SK_DEBUG
37    , fAttachedToCanvas(false)
38#endif
39{
40    fOrigin.setZero();
41    fMetaData = NULL;
42}
43
44SkBitmapDevice::SkBitmapDevice(const SkBitmap& bitmap, const SkDeviceProperties& deviceProperties)
45    : SkBaseDevice(deviceProperties)
46    , fBitmap(bitmap) {
47}
48
49SkBaseDevice::SkBaseDevice(const SkDeviceProperties& deviceProperties)
50    : fLeakyProperties(deviceProperties)
51#ifdef SK_DEBUG
52    , fAttachedToCanvas(false)
53#endif
54{
55    fOrigin.setZero();
56    fMetaData = NULL;
57}
58
59SkBitmapDevice::SkBitmapDevice(SkBitmap::Config config, int width, int height, bool isOpaque) {
60    fBitmap.setConfig(config, width, height);
61    fBitmap.allocPixels();
62    fBitmap.setIsOpaque(isOpaque);
63    if (!isOpaque) {
64        fBitmap.eraseColor(SK_ColorTRANSPARENT);
65    }
66}
67
68SkBitmapDevice::SkBitmapDevice(SkBitmap::Config config, int width, int height, bool isOpaque,
69                         const SkDeviceProperties& deviceProperties)
70    : SkBaseDevice(deviceProperties) {
71
72    fBitmap.setConfig(config, width, height);
73    fBitmap.allocPixels();
74    fBitmap.setIsOpaque(isOpaque);
75    if (!isOpaque) {
76        fBitmap.eraseColor(SK_ColorTRANSPARENT);
77    }
78}
79
80SkBaseDevice::~SkBaseDevice() {
81    delete fMetaData;
82}
83
84SkBitmapDevice::~SkBitmapDevice() {
85}
86
87void SkBitmapDevice::replaceBitmapBackendForRasterSurface(const SkBitmap& bm) {
88    SkASSERT(bm.width() == fBitmap.width());
89    SkASSERT(bm.height() == fBitmap.height());
90    fBitmap = bm;   // intent is to use bm's pixelRef (and rowbytes/config)
91    fBitmap.lockPixels();
92}
93
94SkBaseDevice* SkBaseDevice::createCompatibleDevice(SkBitmap::Config config,
95                                                   int width, int height,
96                                                   bool isOpaque) {
97    return this->onCreateCompatibleDevice(config, width, height,
98                                          isOpaque, kGeneral_Usage);
99}
100
101SkBaseDevice* SkBaseDevice::createCompatibleDeviceForSaveLayer(SkBitmap::Config config,
102                                                               int width, int height,
103                                                               bool isOpaque) {
104    return this->onCreateCompatibleDevice(config, width, height,
105                                          isOpaque, kSaveLayer_Usage);
106}
107
108SkBaseDevice* SkBitmapDevice::onCreateCompatibleDevice(SkBitmap::Config config,
109                                                       int width, int height,
110                                                       bool isOpaque,
111                                                       Usage usage) {
112    return SkNEW_ARGS(SkBitmapDevice,(config, width, height, isOpaque,
113                                      this->getDeviceProperties()));
114}
115
116SkMetaData& SkBaseDevice::getMetaData() {
117    // metadata users are rare, so we lazily allocate it. If that changes we
118    // can decide to just make it a field in the device (rather than a ptr)
119    if (NULL == fMetaData) {
120        fMetaData = new SkMetaData;
121    }
122    return *fMetaData;
123}
124
125void SkBitmapDevice::lockPixels() {
126    if (fBitmap.lockPixelsAreWritable()) {
127        fBitmap.lockPixels();
128    }
129}
130
131void SkBitmapDevice::unlockPixels() {
132    if (fBitmap.lockPixelsAreWritable()) {
133        fBitmap.unlockPixels();
134    }
135}
136
137const SkBitmap& SkBaseDevice::accessBitmap(bool changePixels) {
138    const SkBitmap& bitmap = this->onAccessBitmap();
139    if (changePixels) {
140        bitmap.notifyPixelsChanged();
141    }
142    return bitmap;
143}
144
145void SkBitmapDevice::getGlobalBounds(SkIRect* bounds) const {
146    if (bounds) {
147        const SkIPoint& origin = this->getOrigin();
148        bounds->setXYWH(origin.x(), origin.y(),
149                        fBitmap.width(), fBitmap.height());
150    }
151}
152
153void SkBitmapDevice::clear(SkColor color) {
154    fBitmap.eraseColor(color);
155}
156
157const SkBitmap& SkBitmapDevice::onAccessBitmap() {
158    return fBitmap;
159}
160
161bool SkBitmapDevice::canHandleImageFilter(SkImageFilter*) {
162    return false;
163}
164
165bool SkBitmapDevice::filterImage(SkImageFilter* filter, const SkBitmap& src,
166                                 const SkMatrix& ctm, SkBitmap* result,
167                                 SkIPoint* offset) {
168    return false;
169}
170
171bool SkBitmapDevice::allowImageFilter(SkImageFilter*) {
172    return true;
173}
174
175///////////////////////////////////////////////////////////////////////////////
176
177bool SkBaseDevice::readPixels(SkBitmap* bitmap, int x, int y,
178                              SkCanvas::Config8888 config8888) {
179    if (SkBitmap::kARGB_8888_Config != bitmap->config() ||
180        NULL != bitmap->getTexture()) {
181        return false;
182    }
183
184    const SkBitmap& src = this->accessBitmap(false);
185
186    SkIRect srcRect = SkIRect::MakeXYWH(x, y, bitmap->width(),
187                                              bitmap->height());
188    SkIRect devbounds = SkIRect::MakeWH(src.width(), src.height());
189    if (!srcRect.intersect(devbounds)) {
190        return false;
191    }
192
193    SkBitmap tmp;
194    SkBitmap* bmp;
195    if (bitmap->isNull()) {
196        tmp.setConfig(SkBitmap::kARGB_8888_Config, bitmap->width(),
197                                                   bitmap->height());
198        if (!tmp.allocPixels()) {
199            return false;
200        }
201        bmp = &tmp;
202    } else {
203        bmp = bitmap;
204    }
205
206    SkIRect subrect = srcRect;
207    subrect.offset(-x, -y);
208    SkBitmap bmpSubset;
209    bmp->extractSubset(&bmpSubset, subrect);
210
211    bool result = this->onReadPixels(bmpSubset,
212                                     srcRect.fLeft,
213                                     srcRect.fTop,
214                                     config8888);
215    if (result && bmp == &tmp) {
216        tmp.swap(*bitmap);
217    }
218    return result;
219}
220
221#if SK_PMCOLOR_BYTE_ORDER(B,G,R,A)
222    const SkCanvas::Config8888 SkBaseDevice::kPMColorAlias =
223        SkCanvas::kBGRA_Premul_Config8888;
224#elif SK_PMCOLOR_BYTE_ORDER(R,G,B,A)
225    const SkCanvas::Config8888 SkBaseDevice::kPMColorAlias =
226        SkCanvas::kRGBA_Premul_Config8888;
227#else
228    const SkCanvas::Config8888 SkBaseDevice::kPMColorAlias =
229        (SkCanvas::Config8888) -1;
230#endif
231
232#include <SkConfig8888.h>
233
234bool SkBitmapDevice::onReadPixels(const SkBitmap& bitmap,
235                                  int x, int y,
236                                  SkCanvas::Config8888 config8888) {
237    SkASSERT(SkBitmap::kARGB_8888_Config == bitmap.config());
238    SkASSERT(!bitmap.isNull());
239    SkASSERT(SkIRect::MakeWH(this->width(), this->height()).contains(SkIRect::MakeXYWH(x, y, bitmap.width(), bitmap.height())));
240
241    SkIRect srcRect = SkIRect::MakeXYWH(x, y, bitmap.width(),
242                                              bitmap.height());
243    const SkBitmap& src = this->accessBitmap(false);
244
245    SkBitmap subset;
246    if (!src.extractSubset(&subset, srcRect)) {
247        return false;
248    }
249    if (SkBitmap::kARGB_8888_Config != subset.config()) {
250        // It'd be preferable to do this directly to bitmap.
251        subset.copyTo(&subset, SkBitmap::kARGB_8888_Config);
252    }
253    SkAutoLockPixels alp(bitmap);
254    uint32_t* bmpPixels = reinterpret_cast<uint32_t*>(bitmap.getPixels());
255    SkCopyBitmapToConfig8888(bmpPixels, bitmap.rowBytes(), config8888, subset);
256    return true;
257}
258
259void SkBitmapDevice::writePixels(const SkBitmap& bitmap,
260                                 int x, int y,
261                                 SkCanvas::Config8888 config8888) {
262    if (bitmap.isNull() || bitmap.getTexture()) {
263        return;
264    }
265    const SkBitmap* sprite = &bitmap;
266    // check whether we have to handle a config8888 that doesn't match SkPMColor
267    if (SkBitmap::kARGB_8888_Config == bitmap.config() &&
268        SkCanvas::kNative_Premul_Config8888 != config8888 &&
269        kPMColorAlias != config8888) {
270
271        // We're going to have to convert from a config8888 to the native config
272        // First we clip to the device bounds.
273        SkBitmap dstBmp = this->accessBitmap(true);
274        SkIRect spriteRect = SkIRect::MakeXYWH(x, y,
275                                               bitmap.width(), bitmap.height());
276        SkIRect devRect = SkIRect::MakeWH(dstBmp.width(), dstBmp.height());
277        if (!spriteRect.intersect(devRect)) {
278            return;
279        }
280
281        // write directly to the device if it has pixels and is SkPMColor
282        bool drawSprite;
283        if (SkBitmap::kARGB_8888_Config == dstBmp.config() && !dstBmp.isNull()) {
284            // we can write directly to the dst when doing the conversion
285            dstBmp.extractSubset(&dstBmp, spriteRect);
286            drawSprite = false;
287        } else {
288            // we convert to a temporary bitmap and draw that as a sprite
289            dstBmp.setConfig(SkBitmap::kARGB_8888_Config,
290                             spriteRect.width(),
291                             spriteRect.height());
292            if (!dstBmp.allocPixels()) {
293                return;
294            }
295            drawSprite = true;
296        }
297
298        // copy pixels to dstBmp and convert from config8888 to native config.
299        SkAutoLockPixels alp(bitmap);
300        uint32_t* srcPixels = bitmap.getAddr32(spriteRect.fLeft - x,
301                                               spriteRect.fTop - y);
302        SkCopyConfig8888ToBitmap(dstBmp,
303                                 srcPixels,
304                                 bitmap.rowBytes(),
305                                 config8888);
306
307        if (drawSprite) {
308            // we've clipped the sprite when we made a copy
309            x = spriteRect.fLeft;
310            y = spriteRect.fTop;
311            sprite = &dstBmp;
312        } else {
313            return;
314        }
315    }
316
317    SkPaint paint;
318    paint.setXfermodeMode(SkXfermode::kSrc_Mode);
319    SkRasterClip clip(SkIRect::MakeWH(fBitmap.width(), fBitmap.height()));
320    SkDraw  draw;
321    draw.fRC = &clip;
322    draw.fClip = &clip.bwRgn();
323    draw.fBitmap = &fBitmap; // canvas should have already called accessBitmap
324    draw.fMatrix = &SkMatrix::I();
325    this->drawSprite(draw, *sprite, x, y, paint);
326}
327
328///////////////////////////////////////////////////////////////////////////////
329
330void SkBitmapDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) {
331    draw.drawPaint(paint);
332}
333
334void SkBitmapDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode, size_t count,
335                                const SkPoint pts[], const SkPaint& paint) {
336    CHECK_FOR_NODRAW_ANNOTATION(paint);
337    draw.drawPoints(mode, count, pts, paint);
338}
339
340void SkBitmapDevice::drawRect(const SkDraw& draw, const SkRect& r, const SkPaint& paint) {
341    CHECK_FOR_NODRAW_ANNOTATION(paint);
342    draw.drawRect(r, paint);
343}
344
345void SkBitmapDevice::drawOval(const SkDraw& draw, const SkRect& oval, const SkPaint& paint) {
346    CHECK_FOR_NODRAW_ANNOTATION(paint);
347
348    SkPath path;
349    path.addOval(oval);
350    // call the VIRTUAL version, so any subclasses who do handle drawPath aren't
351    // required to override drawOval.
352    this->drawPath(draw, path, paint, NULL, true);
353}
354
355void SkBitmapDevice::drawRRect(const SkDraw& draw, const SkRRect& rrect, const SkPaint& paint) {
356    CHECK_FOR_NODRAW_ANNOTATION(paint);
357
358    SkPath  path;
359    path.addRRect(rrect);
360    // call the VIRTUAL version, so any subclasses who do handle drawPath aren't
361    // required to override drawRRect.
362    this->drawPath(draw, path, paint, NULL, true);
363}
364
365void SkBitmapDevice::drawPath(const SkDraw& draw, const SkPath& path,
366                              const SkPaint& paint, const SkMatrix* prePathMatrix,
367                              bool pathIsMutable) {
368    CHECK_FOR_NODRAW_ANNOTATION(paint);
369    draw.drawPath(path, paint, prePathMatrix, pathIsMutable);
370}
371
372void SkBitmapDevice::drawBitmap(const SkDraw& draw, const SkBitmap& bitmap,
373                                const SkMatrix& matrix, const SkPaint& paint) {
374    draw.drawBitmap(bitmap, matrix, paint);
375}
376
377void SkBitmapDevice::drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap,
378                                    const SkRect* src, const SkRect& dst,
379                                    const SkPaint& paint,
380                                    SkCanvas::DrawBitmapRectFlags flags) {
381    SkMatrix    matrix;
382    SkRect      bitmapBounds, tmpSrc, tmpDst;
383    SkBitmap    tmpBitmap;
384
385    bitmapBounds.isetWH(bitmap.width(), bitmap.height());
386
387    // Compute matrix from the two rectangles
388    if (src) {
389        tmpSrc = *src;
390    } else {
391        tmpSrc = bitmapBounds;
392    }
393    matrix.setRectToRect(tmpSrc, dst, SkMatrix::kFill_ScaleToFit);
394
395    const SkRect* dstPtr = &dst;
396    const SkBitmap* bitmapPtr = &bitmap;
397
398    // clip the tmpSrc to the bounds of the bitmap, and recompute dstRect if
399    // needed (if the src was clipped). No check needed if src==null.
400    if (src) {
401        if (!bitmapBounds.contains(*src)) {
402            if (!tmpSrc.intersect(bitmapBounds)) {
403                return; // nothing to draw
404            }
405            // recompute dst, based on the smaller tmpSrc
406            matrix.mapRect(&tmpDst, tmpSrc);
407            dstPtr = &tmpDst;
408        }
409
410        // since we may need to clamp to the borders of the src rect within
411        // the bitmap, we extract a subset.
412        SkIRect srcIR;
413        tmpSrc.roundOut(&srcIR);
414        if (!bitmap.extractSubset(&tmpBitmap, srcIR)) {
415            return;
416        }
417        bitmapPtr = &tmpBitmap;
418
419        // Since we did an extract, we need to adjust the matrix accordingly
420        SkScalar dx = 0, dy = 0;
421        if (srcIR.fLeft > 0) {
422            dx = SkIntToScalar(srcIR.fLeft);
423        }
424        if (srcIR.fTop > 0) {
425            dy = SkIntToScalar(srcIR.fTop);
426        }
427        if (dx || dy) {
428            matrix.preTranslate(dx, dy);
429        }
430
431        SkRect extractedBitmapBounds;
432        extractedBitmapBounds.isetWH(bitmapPtr->width(), bitmapPtr->height());
433        if (extractedBitmapBounds == tmpSrc) {
434            // no fractional part in src, we can just call drawBitmap
435            goto USE_DRAWBITMAP;
436        }
437    } else {
438        USE_DRAWBITMAP:
439        // We can go faster by just calling drawBitmap, which will concat the
440        // matrix with the CTM, and try to call drawSprite if it can. If not,
441        // it will make a shader and call drawRect, as we do below.
442        this->drawBitmap(draw, *bitmapPtr, matrix, paint);
443        return;
444    }
445
446    // construct a shader, so we can call drawRect with the dst
447    SkShader* s = SkShader::CreateBitmapShader(*bitmapPtr,
448                                               SkShader::kClamp_TileMode,
449                                               SkShader::kClamp_TileMode);
450    if (NULL == s) {
451        return;
452    }
453    s->setLocalMatrix(matrix);
454
455    SkPaint paintWithShader(paint);
456    paintWithShader.setStyle(SkPaint::kFill_Style);
457    paintWithShader.setShader(s)->unref();
458
459    // Call ourself, in case the subclass wanted to share this setup code
460    // but handle the drawRect code themselves.
461    this->drawRect(draw, *dstPtr, paintWithShader);
462}
463
464void SkBitmapDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
465                                int x, int y, const SkPaint& paint) {
466    draw.drawSprite(bitmap, x, y, paint);
467}
468
469void SkBitmapDevice::drawText(const SkDraw& draw, const void* text, size_t len,
470                              SkScalar x, SkScalar y, const SkPaint& paint) {
471    draw.drawText((const char*)text, len, x, y, paint);
472}
473
474void SkBitmapDevice::drawPosText(const SkDraw& draw, const void* text, size_t len,
475                                 const SkScalar xpos[], SkScalar y,
476                                 int scalarsPerPos, const SkPaint& paint) {
477    draw.drawPosText((const char*)text, len, xpos, y, scalarsPerPos, paint);
478}
479
480void SkBitmapDevice::drawTextOnPath(const SkDraw& draw, const void* text,
481                                    size_t len, const SkPath& path,
482                                    const SkMatrix* matrix,
483                                    const SkPaint& paint) {
484    draw.drawTextOnPath((const char*)text, len, path, matrix, paint);
485}
486
487#ifdef SK_BUILD_FOR_ANDROID
488void SkBitmapDevice::drawPosTextOnPath(const SkDraw& draw, const void* text, size_t len,
489                                       const SkPoint pos[], const SkPaint& paint,
490                                       const SkPath& path, const SkMatrix* matrix) {
491    draw.drawPosTextOnPath((const char*)text, len, pos, paint, path, matrix);
492}
493#endif
494
495void SkBitmapDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
496                                  int vertexCount,
497                                  const SkPoint verts[], const SkPoint textures[],
498                                  const SkColor colors[], SkXfermode* xmode,
499                                  const uint16_t indices[], int indexCount,
500                                  const SkPaint& paint) {
501    draw.drawVertices(vmode, vertexCount, verts, textures, colors, xmode,
502                      indices, indexCount, paint);
503}
504
505void SkBitmapDevice::drawDevice(const SkDraw& draw, SkBaseDevice* device,
506                                int x, int y, const SkPaint& paint) {
507    const SkBitmap& src = device->accessBitmap(false);
508    draw.drawSprite(src, x, y, paint);
509}
510
511///////////////////////////////////////////////////////////////////////////////
512
513bool SkBitmapDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) {
514    if (!paint.isLCDRenderText() || !paint.isAntiAlias()) {
515        // we're cool with the paint as is
516        return false;
517    }
518
519    if (SkBitmap::kARGB_8888_Config != fBitmap.config() ||
520        paint.getRasterizer() ||
521        paint.getPathEffect() ||
522        paint.isFakeBoldText() ||
523        paint.getStyle() != SkPaint::kFill_Style ||
524        !SkXfermode::IsMode(paint.getXfermode(), SkXfermode::kSrcOver_Mode)) {
525        // turn off lcd
526        flags->fFlags = paint.getFlags() & ~SkPaint::kLCDRenderText_Flag;
527        flags->fHinting = paint.getHinting();
528        return true;
529    }
530    // we're cool with the paint as is
531    return false;
532}
533