Plumb dst color space in many places, rather than "mode"
[platform/upstream/libSkiaSharp.git] / src / core / SkBitmapDevice.cpp
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 "SkImageFilter.h"
12 #include "SkImageFilterCache.h"
13 #include "SkMallocPixelRef.h"
14 #include "SkMatrix.h"
15 #include "SkPaint.h"
16 #include "SkPath.h"
17 #include "SkPixelRef.h"
18 #include "SkPixmap.h"
19 #include "SkRasterClip.h"
20 #include "SkShader.h"
21 #include "SkSpecialImage.h"
22 #include "SkSurface.h"
23
24 class SkColorTable;
25
26 static 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
70 SkBitmapDevice::SkBitmapDevice(const SkBitmap& bitmap)
71     : INHERITED(bitmap.info(), SkSurfaceProps(SkSurfaceProps::kLegacyFontHost_InitType))
72     , fBitmap(bitmap)
73 {
74     SkASSERT(valid_for_bitmap_device(bitmap.info(), nullptr));
75     fBitmap.lockPixels();
76 }
77
78 SkBitmapDevice* SkBitmapDevice::Create(const SkImageInfo& info) {
79     return Create(info, SkSurfaceProps(SkSurfaceProps::kLegacyFontHost_InitType));
80 }
81
82 SkBitmapDevice::SkBitmapDevice(const SkBitmap& bitmap, const SkSurfaceProps& surfaceProps)
83     : INHERITED(bitmap.info(), surfaceProps)
84     , fBitmap(bitmap)
85 {
86     SkASSERT(valid_for_bitmap_device(bitmap.info(), nullptr));
87     fBitmap.lockPixels();
88 }
89
90 SkBitmapDevice* SkBitmapDevice::Create(const SkImageInfo& origInfo,
91                                        const SkSurfaceProps& surfaceProps) {
92     SkAlphaType newAT = origInfo.alphaType();
93     if (!valid_for_bitmap_device(origInfo, &newAT)) {
94         return nullptr;
95     }
96
97     const SkImageInfo info = origInfo.makeAlphaType(newAT);
98     SkBitmap bitmap;
99
100     if (kUnknown_SkColorType == info.colorType()) {
101         if (!bitmap.setInfo(info)) {
102             return nullptr;
103         }
104     } else if (info.isOpaque()) {
105         // If this bitmap is opaque, we don't have any sensible default color,
106         // so we just return uninitialized pixels.
107         if (!bitmap.tryAllocPixels(info)) {
108             return nullptr;
109         }
110     } else {
111         // This bitmap has transparency, so we'll zero the pixels (to transparent).
112         // We use a ZeroedPRFactory as a faster alloc-then-eraseColor(SK_ColorTRANSPARENT).
113         SkMallocPixelRef::ZeroedPRFactory factory;
114         if (!bitmap.tryAllocPixels(info, &factory, nullptr/*color table*/)) {
115             return nullptr;
116         }
117     }
118
119     return new SkBitmapDevice(bitmap, surfaceProps);
120 }
121
122 void SkBitmapDevice::setNewSize(const SkISize& size) {
123     SkASSERT(!fBitmap.pixelRef());
124     fBitmap.setInfo(fBitmap.info().makeWH(size.fWidth, size.fHeight));
125     this->privateResize(fBitmap.info().width(), fBitmap.info().height());
126 }
127
128 void SkBitmapDevice::replaceBitmapBackendForRasterSurface(const SkBitmap& bm) {
129     SkASSERT(bm.width() == fBitmap.width());
130     SkASSERT(bm.height() == fBitmap.height());
131     fBitmap = bm;   // intent is to use bm's pixelRef (and rowbytes/config)
132     fBitmap.lockPixels();
133     this->privateResize(fBitmap.info().width(), fBitmap.info().height());
134 }
135
136 SkBaseDevice* SkBitmapDevice::onCreateDevice(const CreateInfo& cinfo, const SkPaint*) {
137     const SkSurfaceProps surfaceProps(this->surfaceProps().flags(), cinfo.fPixelGeometry);
138     return SkBitmapDevice::Create(cinfo.fInfo, surfaceProps);
139 }
140
141 const SkBitmap& SkBitmapDevice::onAccessBitmap() {
142     return fBitmap;
143 }
144
145 bool SkBitmapDevice::onAccessPixels(SkPixmap* pmap) {
146     if (this->onPeekPixels(pmap)) {
147         fBitmap.notifyPixelsChanged();
148         return true;
149     }
150     return false;
151 }
152
153 bool SkBitmapDevice::onPeekPixels(SkPixmap* pmap) {
154     const SkImageInfo info = fBitmap.info();
155     if (fBitmap.getPixels() && (kUnknown_SkColorType != info.colorType())) {
156         SkColorTable* ctable = nullptr;
157         pmap->reset(fBitmap.info(), fBitmap.getPixels(), fBitmap.rowBytes(), ctable);
158         return true;
159     }
160     return false;
161 }
162
163 bool SkBitmapDevice::onWritePixels(const SkImageInfo& srcInfo, const void* srcPixels,
164                                    size_t srcRowBytes, int x, int y) {
165     // since we don't stop creating un-pixeled devices yet, check for no pixels here
166     if (nullptr == fBitmap.getPixels()) {
167         return false;
168     }
169
170     const SkImageInfo dstInfo = fBitmap.info().makeWH(srcInfo.width(), srcInfo.height());
171
172     void* dstPixels = fBitmap.getAddr(x, y);
173     size_t dstRowBytes = fBitmap.rowBytes();
174
175     if (SkPixelInfo::CopyPixels(dstInfo, dstPixels, dstRowBytes, srcInfo, srcPixels, srcRowBytes)) {
176         fBitmap.notifyPixelsChanged();
177         return true;
178     }
179     return false;
180 }
181
182 bool SkBitmapDevice::onReadPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes,
183                                   int x, int y) {
184     return fBitmap.readPixels(dstInfo, dstPixels, dstRowBytes, x, y);
185 }
186
187 ///////////////////////////////////////////////////////////////////////////////
188
189 void SkBitmapDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) {
190     draw.drawPaint(paint);
191 }
192
193 void SkBitmapDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode, size_t count,
194                                 const SkPoint pts[], const SkPaint& paint) {
195     draw.drawPoints(mode, count, pts, paint);
196 }
197
198 void SkBitmapDevice::drawRect(const SkDraw& draw, const SkRect& r, const SkPaint& paint) {
199     draw.drawRect(r, paint);
200 }
201
202 void SkBitmapDevice::drawOval(const SkDraw& draw, const SkRect& oval, const SkPaint& paint) {
203     SkPath path;
204     path.addOval(oval);
205     // call the VIRTUAL version, so any subclasses who do handle drawPath aren't
206     // required to override drawOval.
207     this->drawPath(draw, path, paint, nullptr, true);
208 }
209
210 void SkBitmapDevice::drawRRect(const SkDraw& draw, const SkRRect& rrect, const SkPaint& paint) {
211 #ifdef SK_IGNORE_BLURRED_RRECT_OPT
212     SkPath  path;
213
214     path.addRRect(rrect);
215     // call the VIRTUAL version, so any subclasses who do handle drawPath aren't
216     // required to override drawRRect.
217     this->drawPath(draw, path, paint, nullptr, true);
218 #else
219     draw.drawRRect(rrect, paint);
220 #endif
221 }
222
223 void SkBitmapDevice::drawPath(const SkDraw& draw, const SkPath& path,
224                               const SkPaint& paint, const SkMatrix* prePathMatrix,
225                               bool pathIsMutable) {
226     draw.drawPath(path, paint, prePathMatrix, pathIsMutable);
227 }
228
229 void SkBitmapDevice::drawBitmap(const SkDraw& draw, const SkBitmap& bitmap,
230                                 const SkMatrix& matrix, const SkPaint& paint) {
231     LogDrawScaleFactor(SkMatrix::Concat(*draw.fMatrix, matrix), paint.getFilterQuality());
232     draw.drawBitmap(bitmap, matrix, nullptr, paint);
233 }
234
235 static inline bool CanApplyDstMatrixAsCTM(const SkMatrix& m, const SkPaint& paint) {
236     if (!paint.getMaskFilter()) {
237         return true;
238     }
239
240     // Some mask filters parameters (sigma) depend on the CTM/scale.
241     return m.getType() <= SkMatrix::kTranslate_Mask;
242 }
243
244 void 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     LogDrawScaleFactor(SkMatrix::Concat(*draw.fMatrix, matrix), paint.getFilterQuality());
262
263     const SkRect* dstPtr = &dst;
264     const SkBitmap* bitmapPtr = &bitmap;
265
266     // clip the tmpSrc to the bounds of the bitmap, and recompute dstRect if
267     // needed (if the src was clipped). No check needed if src==null.
268     if (src) {
269         if (!bitmapBounds.contains(*src)) {
270             if (!tmpSrc.intersect(bitmapBounds)) {
271                 return; // nothing to draw
272             }
273             // recompute dst, based on the smaller tmpSrc
274             matrix.mapRect(&tmpDst, tmpSrc);
275             dstPtr = &tmpDst;
276         }
277     }
278
279     if (src && !src->contains(bitmapBounds) &&
280         SkCanvas::kFast_SrcRectConstraint == constraint &&
281         paint.getFilterQuality() != kNone_SkFilterQuality) {
282         // src is smaller than the bounds of the bitmap, and we are filtering, so we don't know
283         // how much more of the bitmap we need, so we can't use extractSubset or drawBitmap,
284         // but we must use a shader w/ dst bounds (which can access all of the bitmap needed).
285         goto USE_SHADER;
286     }
287
288     if (src) {
289         // since we may need to clamp to the borders of the src rect within
290         // the bitmap, we extract a subset.
291         const SkIRect srcIR = tmpSrc.roundOut();
292         if (!bitmap.extractSubset(&tmpBitmap, srcIR)) {
293             return;
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         if (CanApplyDstMatrixAsCTM(matrix, paint)) {
321             draw.drawBitmap(*bitmapPtr, matrix, dstPtr, paint);
322             return;
323         }
324     }
325
326     USE_SHADER:
327
328     // Since the shader need only live for our stack-frame, pass in a custom allocator. This
329     // can save malloc calls, and signals to SkMakeBitmapShader to not try to copy the bitmap
330     // if its mutable, since that precaution is not needed (give the short lifetime of the shader).
331     SkTBlitterAllocator allocator;
332     // construct a shader, so we can call drawRect with the dst
333     auto s = SkMakeBitmapShader(*bitmapPtr, SkShader::kClamp_TileMode, SkShader::kClamp_TileMode,
334                                 &matrix, kNever_SkCopyPixelsMode, &allocator);
335     if (!s) {
336         return;
337     }
338     // we deliberately add a ref, since the allocator wants to be the last owner
339     s.get()->ref();
340
341     SkPaint paintWithShader(paint);
342     paintWithShader.setStyle(SkPaint::kFill_Style);
343     paintWithShader.setShader(s);
344
345     // Call ourself, in case the subclass wanted to share this setup code
346     // but handle the drawRect code themselves.
347     this->drawRect(draw, *dstPtr, paintWithShader);
348 }
349
350 void SkBitmapDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
351                                 int x, int y, const SkPaint& paint) {
352     draw.drawSprite(bitmap, x, y, paint);
353 }
354
355 void SkBitmapDevice::drawText(const SkDraw& draw, const void* text, size_t len,
356                               SkScalar x, SkScalar y, const SkPaint& paint) {
357     draw.drawText((const char*)text, len, x, y, paint);
358 }
359
360 void SkBitmapDevice::drawPosText(const SkDraw& draw, const void* text, size_t len,
361                                  const SkScalar xpos[], int scalarsPerPos,
362                                  const SkPoint& offset, const SkPaint& paint) {
363     draw.drawPosText((const char*)text, len, xpos, scalarsPerPos, offset, paint);
364 }
365
366 void SkBitmapDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
367                                   int vertexCount,
368                                   const SkPoint verts[], const SkPoint textures[],
369                                   const SkColor colors[], SkBlendMode bmode,
370                                   const uint16_t indices[], int indexCount,
371                                   const SkPaint& paint) {
372     draw.drawVertices(vmode, vertexCount, verts, textures, colors, bmode,
373                       indices, indexCount, paint);
374 }
375
376 void SkBitmapDevice::drawDevice(const SkDraw& draw, SkBaseDevice* device,
377                                 int x, int y, const SkPaint& paint) {
378     SkASSERT(!paint.getImageFilter());
379     draw.drawSprite(static_cast<SkBitmapDevice*>(device)->fBitmap, x, y, paint);
380 }
381
382 ///////////////////////////////////////////////////////////////////////////////
383
384 void SkBitmapDevice::drawSpecial(const SkDraw& draw, SkSpecialImage* srcImg, int x, int y,
385                                  const SkPaint& paint) {
386     SkASSERT(!srcImg->isTextureBacked());
387
388     SkBitmap resultBM;
389
390     SkImageFilter* filter = paint.getImageFilter();
391     if (filter) {
392         SkIPoint offset = SkIPoint::Make(0, 0);
393         SkMatrix matrix = *draw.fMatrix;
394         matrix.postTranslate(SkIntToScalar(-x), SkIntToScalar(-y));
395         const SkIRect clipBounds = draw.fRC->getBounds().makeOffset(-x, -y);
396         sk_sp<SkImageFilterCache> cache(this->getImageFilterCache());
397         SkImageFilter::OutputProperties outputProperties(fBitmap.colorSpace());
398         SkImageFilter::Context ctx(matrix, clipBounds, cache.get(), outputProperties);
399
400         sk_sp<SkSpecialImage> resultImg(filter->filterImage(srcImg, ctx, &offset));
401         if (resultImg) {
402             SkPaint tmpUnfiltered(paint);
403             tmpUnfiltered.setImageFilter(nullptr);
404             if (resultImg->getROPixels(&resultBM)) {
405                 this->drawSprite(draw, resultBM, x + offset.x(), y + offset.y(), tmpUnfiltered);
406             }
407         }
408     } else {
409         if (srcImg->getROPixels(&resultBM)) {
410             this->drawSprite(draw, resultBM, x, y, paint);
411         }
412     }
413 }
414
415 sk_sp<SkSpecialImage> SkBitmapDevice::makeSpecial(const SkBitmap& bitmap) {
416     return SkSpecialImage::MakeFromRaster(bitmap.bounds(), bitmap);
417 }
418
419 sk_sp<SkSpecialImage> SkBitmapDevice::makeSpecial(const SkImage* image) {
420     return SkSpecialImage::MakeFromImage(SkIRect::MakeWH(image->width(), image->height()),
421                                          image->makeNonTextureImage(), fBitmap.colorSpace());
422 }
423
424 sk_sp<SkSpecialImage> SkBitmapDevice::snapSpecial() {
425     return this->makeSpecial(fBitmap);
426 }
427
428 ///////////////////////////////////////////////////////////////////////////////
429
430 sk_sp<SkSurface> SkBitmapDevice::makeSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
431     return SkSurface::MakeRaster(info, &props);
432 }
433
434 SkImageFilterCache* SkBitmapDevice::getImageFilterCache() {
435     SkImageFilterCache* cache = SkImageFilterCache::Get();
436     cache->ref();
437     return cache;
438 }
439
440 ///////////////////////////////////////////////////////////////////////////////
441
442 bool SkBitmapDevice::onShouldDisableLCD(const SkPaint& paint) const {
443     if (kN32_SkColorType != fBitmap.colorType() ||
444         paint.getRasterizer() ||
445         paint.getPathEffect() ||
446         paint.isFakeBoldText() ||
447         paint.getStyle() != SkPaint::kFill_Style ||
448         !paint.isSrcOver())
449     {
450         return true;
451     }
452     return false;
453 }