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 "src/core/SkBitmapDevice.h"
9
10 #include "include/core/SkBlender.h"
11 #include "include/core/SkImageFilter.h"
12 #include "include/core/SkMatrix.h"
13 #include "include/core/SkPaint.h"
14 #include "include/core/SkPath.h"
15 #include "include/core/SkPixmap.h"
16 #include "include/core/SkRasterHandleAllocator.h"
17 #include "include/core/SkShader.h"
18 #include "include/core/SkSurface.h"
19 #include "include/core/SkVertices.h"
20 #include "src/base/SkTLazy.h"
21 #include "src/core/SkDraw.h"
22 #include "src/core/SkImageFilterCache.h"
23 #include "src/core/SkImageFilter_Base.h"
24 #include "src/core/SkImagePriv.h"
25 #include "src/core/SkRasterClip.h"
26 #include "src/core/SkSpecialImage.h"
27 #include "src/core/SkStrikeCache.h"
28 #include "src/image/SkImage_Base.h"
29 #include "src/text/GlyphRun.h"
30
31 struct Bounder {
32 SkRect fBounds;
33 bool fHasBounds;
34
BounderBounder35 Bounder(const SkRect& r, const SkPaint& paint) {
36 if ((fHasBounds = paint.canComputeFastBounds())) {
37 fBounds = paint.computeFastBounds(r, &fBounds);
38 }
39 }
40
hasBoundsBounder41 bool hasBounds() const { return fHasBounds; }
boundsBounder42 const SkRect* bounds() const { return fHasBounds ? &fBounds : nullptr; }
operator const SkRect*Bounder43 operator const SkRect* () const { return this->bounds(); }
44 };
45
46 class SkDrawTiler {
47 enum {
48 // 8K is 1 too big, since 8K << supersample == 32768 which is too big for SkFixed
49 kMaxDim = 8192 - 1
50 };
51
52 SkBitmapDevice* fDevice;
53 SkPixmap fRootPixmap;
54 SkIRect fSrcBounds;
55
56 // Used for tiling and non-tiling
57 SkDraw fDraw;
58
59 // fCurr... are only used if fNeedTiling
60 SkTLazy<SkPostTranslateMatrixProvider> fTileMatrixProvider;
61 SkRasterClip fTileRC;
62 SkIPoint fOrigin;
63
64 bool fDone, fNeedsTiling;
65
66 public:
NeedsTiling(SkBitmapDevice * dev)67 static bool NeedsTiling(SkBitmapDevice* dev) {
68 return dev->width() > kMaxDim || dev->height() > kMaxDim;
69 }
70
SkDrawTiler(SkBitmapDevice * dev,const SkRect * bounds)71 SkDrawTiler(SkBitmapDevice* dev, const SkRect* bounds) : fDevice(dev) {
72 fDone = false;
73
74 // we need fDst to be set, and if we're actually drawing, to dirty the genID
75 if (!dev->accessPixels(&fRootPixmap)) {
76 // NoDrawDevice uses us (why?) so we have to catch this case w/ no pixels
77 fRootPixmap.reset(dev->imageInfo(), nullptr, 0);
78 }
79
80 // do a quick check, so we don't even have to process "bounds" if there is no need
81 const SkIRect clipR = dev->fRCStack.rc().getBounds();
82 fNeedsTiling = clipR.right() > kMaxDim || clipR.bottom() > kMaxDim;
83 if (fNeedsTiling) {
84 if (bounds) {
85 // Make sure we round first, and then intersect. We can't rely on promoting the
86 // clipR to floats (and then intersecting with devBounds) since promoting
87 // int --> float can make the float larger than the int.
88 // rounding(out) first runs the risk of clamping if the float is larger an intmax
89 // but our roundOut() is saturating, which is fine for this use case
90 //
91 // e.g. the older version of this code did this:
92 // devBounds = mapRect(bounds);
93 // if (devBounds.intersect(SkRect::Make(clipR))) {
94 // fSrcBounds = devBounds.roundOut();
95 // The problem being that the promotion of clipR to SkRect was unreliable
96 //
97 fSrcBounds = dev->localToDevice().mapRect(*bounds).roundOut();
98 if (fSrcBounds.intersect(clipR)) {
99 // Check again, now that we have computed srcbounds.
100 fNeedsTiling = fSrcBounds.right() > kMaxDim || fSrcBounds.bottom() > kMaxDim;
101 } else {
102 fNeedsTiling = false;
103 fDone = true;
104 }
105 } else {
106 fSrcBounds = clipR;
107 }
108 }
109
110 if (fNeedsTiling) {
111 // fDraw.fDst and fMatrixProvider are reset each time in setupTileDraw()
112 fDraw.fRC = &fTileRC;
113 // we'll step/increase it before using it
114 fOrigin.set(fSrcBounds.fLeft - kMaxDim, fSrcBounds.fTop);
115 } else {
116 // don't reference fSrcBounds, as it may not have been set
117 fDraw.fDst = fRootPixmap;
118 fDraw.fMatrixProvider = dev;
119 fDraw.fRC = &dev->fRCStack.rc();
120 fOrigin.set(0, 0);
121 }
122
123 fDraw.fProps = &fDevice->surfaceProps();
124 }
125
needsTiling() const126 bool needsTiling() const { return fNeedsTiling; }
127
next()128 const SkDraw* next() {
129 if (fDone) {
130 return nullptr;
131 }
132 if (fNeedsTiling) {
133 do {
134 this->stepAndSetupTileDraw(); // might set the clip to empty and fDone to true
135 } while (!fDone && fTileRC.isEmpty());
136 // if we exit the loop and we're still empty, we're (past) done
137 if (fTileRC.isEmpty()) {
138 SkASSERT(fDone);
139 return nullptr;
140 }
141 SkASSERT(!fTileRC.isEmpty());
142 } else {
143 fDone = true; // only draw untiled once
144 }
145 return &fDraw;
146 }
147
148 private:
stepAndSetupTileDraw()149 void stepAndSetupTileDraw() {
150 SkASSERT(!fDone);
151 SkASSERT(fNeedsTiling);
152
153 // We do fRootPixmap.width() - kMaxDim instead of fOrigin.fX + kMaxDim to avoid overflow.
154 if (fOrigin.fX >= fSrcBounds.fRight - kMaxDim) { // too far
155 fOrigin.fX = fSrcBounds.fLeft;
156 fOrigin.fY += kMaxDim;
157 } else {
158 fOrigin.fX += kMaxDim;
159 }
160 // fDone = next origin will be invalid.
161 fDone = fOrigin.fX >= fSrcBounds.fRight - kMaxDim &&
162 fOrigin.fY >= fSrcBounds.fBottom - kMaxDim;
163
164 SkIRect bounds = SkIRect::MakeXYWH(fOrigin.x(), fOrigin.y(), kMaxDim, kMaxDim);
165 SkASSERT(!bounds.isEmpty());
166 bool success = fRootPixmap.extractSubset(&fDraw.fDst, bounds);
167 SkASSERT_RELEASE(success);
168 // now don't use bounds, since fDst has the clipped dimensions.
169
170 fDraw.fMatrixProvider = fTileMatrixProvider.init(fDevice->asMatrixProvider(),
171 SkIntToScalar(-fOrigin.x()),
172 SkIntToScalar(-fOrigin.y()));
173 fDevice->fRCStack.rc().translate(-fOrigin.x(), -fOrigin.y(), &fTileRC);
174 fTileRC.op(SkIRect::MakeWH(fDraw.fDst.width(), fDraw.fDst.height()),
175 SkClipOp::kIntersect);
176 }
177 };
178
179 // Passing a bounds allows the tiler to only visit the dst-tiles that might intersect the
180 // drawing. If null is passed, the tiler has to visit everywhere. The bounds is expected to be
181 // in local coordinates, as the tiler itself will transform that into device coordinates.
182 //
183 #define LOOP_TILER(code, boundsPtr) \
184 SkDrawTiler priv_tiler(this, boundsPtr); \
185 while (const SkDraw* priv_draw = priv_tiler.next()) { \
186 priv_draw->code; \
187 }
188
189 // Helper to create an SkDraw from a device
190 class SkBitmapDevice::BDDraw : public SkDraw {
191 public:
BDDraw(SkBitmapDevice * dev)192 BDDraw(SkBitmapDevice* dev) {
193 // we need fDst to be set, and if we're actually drawing, to dirty the genID
194 if (!dev->accessPixels(&fDst)) {
195 // NoDrawDevice uses us (why?) so we have to catch this case w/ no pixels
196 fDst.reset(dev->imageInfo(), nullptr, 0);
197 }
198 fMatrixProvider = dev;
199 fRC = &dev->fRCStack.rc();
200 }
201 };
202
valid_for_bitmap_device(const SkImageInfo & info,SkAlphaType * newAlphaType)203 static bool valid_for_bitmap_device(const SkImageInfo& info,
204 SkAlphaType* newAlphaType) {
205 if (info.width() < 0 || info.height() < 0 || kUnknown_SkColorType == info.colorType()) {
206 return false;
207 }
208
209 if (newAlphaType) {
210 *newAlphaType = SkColorTypeIsAlwaysOpaque(info.colorType()) ? kOpaque_SkAlphaType
211 : info.alphaType();
212 }
213
214 return true;
215 }
216
SkBitmapDevice(const SkBitmap & bitmap)217 SkBitmapDevice::SkBitmapDevice(const SkBitmap& bitmap)
218 : INHERITED(bitmap.info(), SkSurfaceProps())
219 , fBitmap(bitmap)
220 , fRCStack(bitmap.width(), bitmap.height())
221 , fGlyphPainter(this->surfaceProps(), bitmap.colorType(), bitmap.colorSpace()) {
222 SkASSERT(valid_for_bitmap_device(bitmap.info(), nullptr));
223 }
224
Create(const SkImageInfo & info)225 SkBitmapDevice* SkBitmapDevice::Create(const SkImageInfo& info) {
226 return Create(info, SkSurfaceProps());
227 }
228
SkBitmapDevice(const SkBitmap & bitmap,const SkSurfaceProps & surfaceProps,SkRasterHandleAllocator::Handle hndl)229 SkBitmapDevice::SkBitmapDevice(const SkBitmap& bitmap, const SkSurfaceProps& surfaceProps,
230 SkRasterHandleAllocator::Handle hndl)
231 : INHERITED(bitmap.info(), surfaceProps)
232 , fBitmap(bitmap)
233 , fRasterHandle(hndl)
234 , fRCStack(bitmap.width(), bitmap.height())
235 , fGlyphPainter(this->surfaceProps(), bitmap.colorType(), bitmap.colorSpace()) {
236 SkASSERT(valid_for_bitmap_device(bitmap.info(), nullptr));
237 }
238
Create(const SkImageInfo & origInfo,const SkSurfaceProps & surfaceProps,SkRasterHandleAllocator * allocator)239 SkBitmapDevice* SkBitmapDevice::Create(const SkImageInfo& origInfo,
240 const SkSurfaceProps& surfaceProps,
241 SkRasterHandleAllocator* allocator) {
242 SkAlphaType newAT = origInfo.alphaType();
243 if (!valid_for_bitmap_device(origInfo, &newAT)) {
244 return nullptr;
245 }
246
247 SkRasterHandleAllocator::Handle hndl = nullptr;
248 const SkImageInfo info = origInfo.makeAlphaType(newAT);
249 SkBitmap bitmap;
250
251 if (kUnknown_SkColorType == info.colorType()) {
252 if (!bitmap.setInfo(info)) {
253 return nullptr;
254 }
255 } else if (allocator) {
256 hndl = allocator->allocBitmap(info, &bitmap);
257 if (!hndl) {
258 return nullptr;
259 }
260 } else if (info.isOpaque()) {
261 // If this bitmap is opaque, we don't have any sensible default color,
262 // so we just return uninitialized pixels.
263 if (!bitmap.tryAllocPixels(info)) {
264 return nullptr;
265 }
266 } else {
267 // This bitmap has transparency, so we'll zero the pixels (to transparent).
268 // We use the flag as a faster alloc-then-eraseColor(SK_ColorTRANSPARENT).
269 if (!bitmap.tryAllocPixelsFlags(info, SkBitmap::kZeroPixels_AllocFlag)) {
270 return nullptr;
271 }
272 }
273
274 return new SkBitmapDevice(bitmap, surfaceProps, hndl);
275 }
276
replaceBitmapBackendForRasterSurface(const SkBitmap & bm)277 void SkBitmapDevice::replaceBitmapBackendForRasterSurface(const SkBitmap& bm) {
278 SkASSERT(bm.width() == fBitmap.width());
279 SkASSERT(bm.height() == fBitmap.height());
280 fBitmap = bm; // intent is to use bm's pixelRef (and rowbytes/config)
281 this->privateResize(fBitmap.info().width(), fBitmap.info().height());
282 }
283
onCreateDevice(const CreateInfo & cinfo,const SkPaint * layerPaint)284 SkBaseDevice* SkBitmapDevice::onCreateDevice(const CreateInfo& cinfo, const SkPaint* layerPaint) {
285 const SkSurfaceProps surfaceProps(this->surfaceProps().flags(), cinfo.fPixelGeometry);
286
287 // Need to force L32 for now if we have an image filter.
288 // If filters ever support other colortypes, e.g. F16, we can modify this check.
289 SkImageInfo info = cinfo.fInfo;
290 if (layerPaint && layerPaint->getImageFilter()) {
291 // TODO: can we query the imagefilter, to see if it can handle floats (so we don't always
292 // use N32 when the layer itself was float)?
293 info = info.makeColorType(kN32_SkColorType);
294 }
295
296 return SkBitmapDevice::Create(info, surfaceProps, cinfo.fAllocator);
297 }
298
onAccessPixels(SkPixmap * pmap)299 bool SkBitmapDevice::onAccessPixels(SkPixmap* pmap) {
300 if (this->onPeekPixels(pmap)) {
301 fBitmap.notifyPixelsChanged();
302 return true;
303 }
304 return false;
305 }
306
onPeekPixels(SkPixmap * pmap)307 bool SkBitmapDevice::onPeekPixels(SkPixmap* pmap) {
308 const SkImageInfo info = fBitmap.info();
309 if (fBitmap.getPixels() && (kUnknown_SkColorType != info.colorType())) {
310 pmap->reset(fBitmap.info(), fBitmap.getPixels(), fBitmap.rowBytes());
311 return true;
312 }
313 return false;
314 }
315
onWritePixels(const SkPixmap & pm,int x,int y)316 bool SkBitmapDevice::onWritePixels(const SkPixmap& pm, int x, int y) {
317 // since we don't stop creating un-pixeled devices yet, check for no pixels here
318 if (nullptr == fBitmap.getPixels()) {
319 return false;
320 }
321
322 if (fBitmap.writePixels(pm, x, y)) {
323 fBitmap.notifyPixelsChanged();
324 return true;
325 }
326 return false;
327 }
328
onReadPixels(const SkPixmap & pm,int x,int y)329 bool SkBitmapDevice::onReadPixels(const SkPixmap& pm, int x, int y) {
330 return fBitmap.readPixels(pm, x, y);
331 }
332
333 ///////////////////////////////////////////////////////////////////////////////
334
drawPaint(const SkPaint & paint)335 void SkBitmapDevice::drawPaint(const SkPaint& paint) {
336 BDDraw(this).drawPaint(paint);
337 }
338
drawPoints(SkCanvas::PointMode mode,size_t count,const SkPoint pts[],const SkPaint & paint)339 void SkBitmapDevice::drawPoints(SkCanvas::PointMode mode, size_t count,
340 const SkPoint pts[], const SkPaint& paint) {
341 LOOP_TILER( drawPoints(mode, count, pts, paint, nullptr), nullptr)
342 }
343
drawRect(const SkRect & r,const SkPaint & paint)344 void SkBitmapDevice::drawRect(const SkRect& r, const SkPaint& paint) {
345 LOOP_TILER( drawRect(r, paint), Bounder(r, paint))
346 }
347
drawOval(const SkRect & oval,const SkPaint & paint)348 void SkBitmapDevice::drawOval(const SkRect& oval, const SkPaint& paint) {
349 // call the VIRTUAL version, so any subclasses who do handle drawPath aren't
350 // required to override drawOval.
351 this->drawPath(SkPath::Oval(oval), paint, true);
352 }
353
drawRRect(const SkRRect & rrect,const SkPaint & paint)354 void SkBitmapDevice::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
355 #ifdef SK_IGNORE_BLURRED_RRECT_OPT
356 // call the VIRTUAL version, so any subclasses who do handle drawPath aren't
357 // required to override drawRRect.
358 this->drawPath(SkPath::RRect(rrect), paint, true);
359 #else
360 LOOP_TILER( drawRRect(rrect, paint), Bounder(rrect.getBounds(), paint))
361 #endif
362 }
363
drawPath(const SkPath & path,const SkPaint & paint,bool pathIsMutable)364 void SkBitmapDevice::drawPath(const SkPath& path,
365 const SkPaint& paint,
366 bool pathIsMutable) {
367 const SkRect* bounds = nullptr;
368 if (SkDrawTiler::NeedsTiling(this) && !path.isInverseFillType()) {
369 bounds = &path.getBounds();
370 }
371 SkDrawTiler tiler(this, bounds ? Bounder(*bounds, paint).bounds() : nullptr);
372 if (tiler.needsTiling()) {
373 pathIsMutable = false;
374 }
375 while (const SkDraw* draw = tiler.next()) {
376 draw->drawPath(path, paint, nullptr, pathIsMutable);
377 }
378 }
379
drawBitmap(const SkBitmap & bitmap,const SkMatrix & matrix,const SkRect * dstOrNull,const SkSamplingOptions & sampling,const SkPaint & paint)380 void SkBitmapDevice::drawBitmap(const SkBitmap& bitmap, const SkMatrix& matrix,
381 const SkRect* dstOrNull, const SkSamplingOptions& sampling,
382 const SkPaint& paint) {
383 const SkRect* bounds = dstOrNull;
384 SkRect storage;
385 if (!bounds && SkDrawTiler::NeedsTiling(this)) {
386 matrix.mapRect(&storage, SkRect::MakeIWH(bitmap.width(), bitmap.height()));
387 Bounder b(storage, paint);
388 if (b.hasBounds()) {
389 storage = *b.bounds();
390 bounds = &storage;
391 }
392 }
393 LOOP_TILER(drawBitmap(bitmap, matrix, dstOrNull, sampling, paint), bounds)
394 }
395
CanApplyDstMatrixAsCTM(const SkMatrix & m,const SkPaint & paint)396 static inline bool CanApplyDstMatrixAsCTM(const SkMatrix& m, const SkPaint& paint) {
397 if (!paint.getMaskFilter()) {
398 return true;
399 }
400
401 // Some mask filters parameters (sigma) depend on the CTM/scale.
402 return m.getType() <= SkMatrix::kTranslate_Mask;
403 }
404
drawImageRect(const SkImage * image,const SkRect * src,const SkRect & dst,const SkSamplingOptions & sampling,const SkPaint & paint,SkCanvas::SrcRectConstraint constraint)405 void SkBitmapDevice::drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
406 const SkSamplingOptions& sampling, const SkPaint& paint,
407 SkCanvas::SrcRectConstraint constraint) {
408 SkASSERT(dst.isFinite());
409 SkASSERT(dst.isSorted());
410
411 SkBitmap bitmap;
412 // TODO: Elevate direct context requirement to public API and remove cheat.
413 auto dContext = as_IB(image)->directContext();
414 if (!as_IB(image)->getROPixels(dContext, &bitmap)) {
415 return;
416 }
417
418 SkRect bitmapBounds, tmpSrc, tmpDst;
419 SkBitmap tmpBitmap;
420
421 bitmapBounds.setIWH(bitmap.width(), bitmap.height());
422
423 // Compute matrix from the two rectangles
424 if (src) {
425 tmpSrc = *src;
426 } else {
427 tmpSrc = bitmapBounds;
428 }
429 SkMatrix matrix = SkMatrix::RectToRect(tmpSrc, dst);
430
431 const SkRect* dstPtr = &dst;
432 const SkBitmap* bitmapPtr = &bitmap;
433
434 // clip the tmpSrc to the bounds of the bitmap, and recompute dstRect if
435 // needed (if the src was clipped). No check needed if src==null.
436 if (src) {
437 if (!bitmapBounds.contains(*src)) {
438 if (!tmpSrc.intersect(bitmapBounds)) {
439 return; // nothing to draw
440 }
441 // recompute dst, based on the smaller tmpSrc
442 matrix.mapRect(&tmpDst, tmpSrc);
443 if (!tmpDst.isFinite()) {
444 return;
445 }
446 dstPtr = &tmpDst;
447 }
448 }
449
450 if (src && !src->contains(bitmapBounds) &&
451 SkCanvas::kFast_SrcRectConstraint == constraint &&
452 sampling != SkSamplingOptions()) {
453 // src is smaller than the bounds of the bitmap, and we are filtering, so we don't know
454 // how much more of the bitmap we need, so we can't use extractSubset or drawBitmap,
455 // but we must use a shader w/ dst bounds (which can access all of the bitmap needed).
456 goto USE_SHADER;
457 }
458
459 if (src) {
460 // since we may need to clamp to the borders of the src rect within
461 // the bitmap, we extract a subset.
462 const SkIRect srcIR = tmpSrc.roundOut();
463 if (!bitmap.extractSubset(&tmpBitmap, srcIR)) {
464 return;
465 }
466 bitmapPtr = &tmpBitmap;
467
468 // Since we did an extract, we need to adjust the matrix accordingly
469 SkScalar dx = 0, dy = 0;
470 if (srcIR.fLeft > 0) {
471 dx = SkIntToScalar(srcIR.fLeft);
472 }
473 if (srcIR.fTop > 0) {
474 dy = SkIntToScalar(srcIR.fTop);
475 }
476 if (dx || dy) {
477 matrix.preTranslate(dx, dy);
478 }
479
480 #ifdef SK_DRAWBITMAPRECT_FAST_OFFSET
481 SkRect extractedBitmapBounds = SkRect::MakeXYWH(dx, dy,
482 SkIntToScalar(bitmapPtr->width()),
483 SkIntToScalar(bitmapPtr->height()));
484 #else
485 SkRect extractedBitmapBounds;
486 extractedBitmapBounds.setIWH(bitmapPtr->width(), bitmapPtr->height());
487 #endif
488 if (extractedBitmapBounds == tmpSrc) {
489 // no fractional part in src, we can just call drawBitmap
490 goto USE_DRAWBITMAP;
491 }
492 } else {
493 USE_DRAWBITMAP:
494 // We can go faster by just calling drawBitmap, which will concat the
495 // matrix with the CTM, and try to call drawSprite if it can. If not,
496 // it will make a shader and call drawRect, as we do below.
497 if (CanApplyDstMatrixAsCTM(matrix, paint)) {
498 this->drawBitmap(*bitmapPtr, matrix, dstPtr, sampling, paint);
499 return;
500 }
501 }
502
503 USE_SHADER:
504
505 // construct a shader, so we can call drawRect with the dst
506 auto s = SkMakeBitmapShaderForPaint(paint, *bitmapPtr, SkTileMode::kClamp, SkTileMode::kClamp,
507 sampling, &matrix, kNever_SkCopyPixelsMode);
508 if (!s) {
509 return;
510 }
511
512 SkPaint paintWithShader(paint);
513 paintWithShader.setStyle(SkPaint::kFill_Style);
514 paintWithShader.setShader(std::move(s));
515
516 // Call ourself, in case the subclass wanted to share this setup code
517 // but handle the drawRect code themselves.
518 this->drawRect(*dstPtr, paintWithShader);
519 }
520
onDrawGlyphRunList(SkCanvas * canvas,const sktext::GlyphRunList & glyphRunList,const SkPaint & initialPaint,const SkPaint & drawingPaint)521 void SkBitmapDevice::onDrawGlyphRunList(SkCanvas* canvas,
522 const sktext::GlyphRunList& glyphRunList,
523 const SkPaint& initialPaint,
524 const SkPaint& drawingPaint) {
525 SkASSERT(!glyphRunList.hasRSXForm());
526 LOOP_TILER( drawGlyphRunList(canvas, &fGlyphPainter, glyphRunList, drawingPaint), nullptr )
527 }
528
drawVertices(const SkVertices * vertices,sk_sp<SkBlender> blender,const SkPaint & paint,bool skipColorXform)529 void SkBitmapDevice::drawVertices(const SkVertices* vertices,
530 sk_sp<SkBlender> blender,
531 const SkPaint& paint,
532 bool skipColorXform) {
533 #ifdef SK_LEGACY_IGNORE_DRAW_VERTICES_BLEND_WITH_NO_SHADER
534 if (!paint.getShader()) {
535 blender = SkBlender::Mode(SkBlendMode::kDst);
536 }
537 #endif
538 BDDraw(this).drawVertices(vertices, std::move(blender), paint, skipColorXform);
539 }
540
541 #ifdef SK_ENABLE_SKSL
drawMesh(const SkMesh &,sk_sp<SkBlender>,const SkPaint &)542 void SkBitmapDevice::drawMesh(const SkMesh&, sk_sp<SkBlender>, const SkPaint&) {
543 // TODO: Implement
544 }
545 #endif
546
drawAtlas(const SkRSXform xform[],const SkRect tex[],const SkColor colors[],int count,sk_sp<SkBlender> blender,const SkPaint & paint)547 void SkBitmapDevice::drawAtlas(const SkRSXform xform[],
548 const SkRect tex[],
549 const SkColor colors[],
550 int count,
551 sk_sp<SkBlender> blender,
552 const SkPaint& paint) {
553 // set this to true for performance comparisons with the old drawVertices way
554 if ((false)) {
555 this->INHERITED::drawAtlas(xform, tex, colors, count, std::move(blender), paint);
556 return;
557 }
558 BDDraw(this).drawAtlas(xform, tex, colors, count, std::move(blender), paint);
559 }
560
561 ///////////////////////////////////////////////////////////////////////////////
562
drawDevice(SkBaseDevice * device,const SkSamplingOptions & sampling,const SkPaint & paint)563 void SkBitmapDevice::drawDevice(SkBaseDevice* device, const SkSamplingOptions& sampling,
564 const SkPaint& paint) {
565 SkASSERT(!paint.getImageFilter());
566 SkASSERT(!paint.getMaskFilter());
567
568 this->INHERITED::drawDevice(device, sampling, paint);
569 }
570
drawSpecial(SkSpecialImage * src,const SkMatrix & localToDevice,const SkSamplingOptions & sampling,const SkPaint & paint)571 void SkBitmapDevice::drawSpecial(SkSpecialImage* src,
572 const SkMatrix& localToDevice,
573 const SkSamplingOptions& sampling,
574 const SkPaint& paint) {
575 SkASSERT(!paint.getImageFilter());
576 SkASSERT(!paint.getMaskFilter());
577 SkASSERT(!src->isTextureBacked());
578
579 SkBitmap resultBM;
580 if (src->getROPixels(&resultBM)) {
581 SkDraw draw;
582 SkMatrixProvider matrixProvider(localToDevice);
583 if (!this->accessPixels(&draw.fDst)) {
584 return; // no pixels to draw to so skip it
585 }
586 draw.fMatrixProvider = &matrixProvider;
587 draw.fRC = &fRCStack.rc();
588 draw.drawBitmap(resultBM, SkMatrix::I(), nullptr, sampling, paint);
589 }
590 }
makeSpecial(const SkBitmap & bitmap)591 sk_sp<SkSpecialImage> SkBitmapDevice::makeSpecial(const SkBitmap& bitmap) {
592 return SkSpecialImage::MakeFromRaster(bitmap.bounds(), bitmap, this->surfaceProps());
593 }
594
makeSpecial(const SkImage * image)595 sk_sp<SkSpecialImage> SkBitmapDevice::makeSpecial(const SkImage* image) {
596 return SkSpecialImage::MakeFromImage(nullptr, SkIRect::MakeWH(image->width(), image->height()),
597 image->makeNonTextureImage(), this->surfaceProps());
598 }
599
snapSpecial(const SkIRect & bounds,bool forceCopy)600 sk_sp<SkSpecialImage> SkBitmapDevice::snapSpecial(const SkIRect& bounds, bool forceCopy) {
601 if (forceCopy) {
602 return SkSpecialImage::CopyFromRaster(bounds, fBitmap, this->surfaceProps());
603 } else {
604 return SkSpecialImage::MakeFromRaster(bounds, fBitmap, this->surfaceProps());
605 }
606 }
607
608 ///////////////////////////////////////////////////////////////////////////////
609
makeSurface(const SkImageInfo & info,const SkSurfaceProps & props)610 sk_sp<SkSurface> SkBitmapDevice::makeSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
611 return SkSurface::MakeRaster(info, &props);
612 }
613
getImageFilterCache()614 SkImageFilterCache* SkBitmapDevice::getImageFilterCache() {
615 SkImageFilterCache* cache = SkImageFilterCache::Get();
616 cache->ref();
617 return cache;
618 }
619
620 ///////////////////////////////////////////////////////////////////////////////////////////////////
621
onSave()622 void SkBitmapDevice::onSave() {
623 fRCStack.save();
624 }
625
onRestore()626 void SkBitmapDevice::onRestore() {
627 fRCStack.restore();
628 }
629
onClipRect(const SkRect & rect,SkClipOp op,bool aa)630 void SkBitmapDevice::onClipRect(const SkRect& rect, SkClipOp op, bool aa) {
631 fRCStack.clipRect(this->localToDevice(), rect, op, aa);
632 }
633
onClipRRect(const SkRRect & rrect,SkClipOp op,bool aa)634 void SkBitmapDevice::onClipRRect(const SkRRect& rrect, SkClipOp op, bool aa) {
635 fRCStack.clipRRect(this->localToDevice(), rrect, op, aa);
636 }
637
onClipPath(const SkPath & path,SkClipOp op,bool aa)638 void SkBitmapDevice::onClipPath(const SkPath& path, SkClipOp op, bool aa) {
639 fRCStack.clipPath(this->localToDevice(), path, op, aa);
640 }
641
onClipShader(sk_sp<SkShader> sh)642 void SkBitmapDevice::onClipShader(sk_sp<SkShader> sh) {
643 fRCStack.clipShader(std::move(sh));
644 }
645
onClipRegion(const SkRegion & rgn,SkClipOp op)646 void SkBitmapDevice::onClipRegion(const SkRegion& rgn, SkClipOp op) {
647 SkIPoint origin = this->getOrigin();
648 SkRegion tmp;
649 const SkRegion* ptr = &rgn;
650 if (origin.fX | origin.fY) {
651 // translate from "global/canvas" coordinates to relative to this device
652 rgn.translate(-origin.fX, -origin.fY, &tmp);
653 ptr = &tmp;
654 }
655 fRCStack.clipRegion(*ptr, op);
656 }
657
onReplaceClip(const SkIRect & rect)658 void SkBitmapDevice::onReplaceClip(const SkIRect& rect) {
659 // Transform from "global/canvas" coordinates to relative to this device
660 SkRect deviceRect = SkMatrixPriv::MapRect(this->globalToDevice(), SkRect::Make(rect));
661 fRCStack.replaceClip(deviceRect.round());
662 }
663
onClipIsWideOpen() const664 bool SkBitmapDevice::onClipIsWideOpen() const {
665 const SkRasterClip& rc = fRCStack.rc();
666 // If we're AA, we can't be wide-open (we would represent that as BW)
667 return rc.isBW() && rc.bwRgn().isRect() &&
668 rc.bwRgn().getBounds() == SkIRect{0, 0, this->width(), this->height()};
669 }
670
onClipIsAA() const671 bool SkBitmapDevice::onClipIsAA() const {
672 const SkRasterClip& rc = fRCStack.rc();
673 return !rc.isEmpty() && rc.isAA();
674 }
675
onAsRgnClip(SkRegion * rgn) const676 void SkBitmapDevice::onAsRgnClip(SkRegion* rgn) const {
677 const SkRasterClip& rc = fRCStack.rc();
678 if (rc.isAA()) {
679 rgn->setRect(rc.getBounds());
680 } else {
681 *rgn = rc.bwRgn();
682 }
683 }
684
validateDevBounds(const SkIRect & drawClipBounds)685 void SkBitmapDevice::validateDevBounds(const SkIRect& drawClipBounds) {
686 #ifdef SK_DEBUG
687 const SkIRect& stackBounds = fRCStack.rc().getBounds();
688 SkASSERT(drawClipBounds == stackBounds);
689 #endif
690 }
691
onGetClipType() const692 SkBaseDevice::ClipType SkBitmapDevice::onGetClipType() const {
693 const SkRasterClip& rc = fRCStack.rc();
694 if (rc.isEmpty()) {
695 return ClipType::kEmpty;
696 } else if (rc.isRect() && !SkToBool(rc.clipShader())) {
697 return ClipType::kRect;
698 } else {
699 return ClipType::kComplex;
700 }
701 }
702
onDevClipBounds() const703 SkIRect SkBitmapDevice::onDevClipBounds() const {
704 return fRCStack.rc().getBounds();
705 }
706