diff options
-rw-r--r-- | include/core/SkDevice.h | 4 | ||||
-rw-r--r-- | include/core/SkImage.h | 13 | ||||
-rw-r--r-- | include/utils/SkDeferredCanvas.h | 3 | ||||
-rw-r--r-- | src/core/SkCanvas.cpp | 56 | ||||
-rw-r--r-- | src/core/SkDevice.cpp | 19 | ||||
-rw-r--r-- | src/core/SkPaintPriv.cpp | 6 | ||||
-rw-r--r-- | src/core/SkPaintPriv.h | 10 | ||||
-rw-r--r-- | src/core/SkPictureRecord.cpp | 17 | ||||
-rw-r--r-- | src/core/SkPictureRecord.h | 3 | ||||
-rw-r--r-- | src/gpu/SkGpuDevice.cpp | 42 | ||||
-rw-r--r-- | src/gpu/SkGpuDevice.h | 3 | ||||
-rw-r--r-- | src/image/SkImage.cpp | 9 | ||||
-rw-r--r-- | src/image/SkImage_Base.h | 3 | ||||
-rw-r--r-- | src/image/SkImage_Gpu.cpp | 9 | ||||
-rw-r--r-- | src/image/SkImage_Gpu.h | 3 | ||||
-rw-r--r-- | src/image/SkImage_Raster.cpp | 13 | ||||
-rw-r--r-- | src/pipe/SkGPipePriv.h | 20 | ||||
-rw-r--r-- | src/pipe/SkGPipeRead.cpp | 47 | ||||
-rw-r--r-- | src/pipe/SkGPipeWrite.cpp | 94 | ||||
-rw-r--r-- | src/utils/SkDeferredCanvas.cpp | 71 |
20 files changed, 367 insertions, 78 deletions
diff --git a/include/core/SkDevice.h b/include/core/SkDevice.h index 8a219d7053..b474687cfb 100644 --- a/include/core/SkDevice.h +++ b/include/core/SkDevice.h @@ -209,6 +209,10 @@ protected: const SkPaint& paint, SkCanvas::DrawBitmapRectFlags flags) = 0; + virtual void drawImage(const SkDraw&, const SkImage*, SkScalar x, SkScalar y, const SkPaint&); + virtual void drawImageRect(const SkDraw&, const SkImage*, const SkRect* src, const SkRect& dst, + const SkPaint&); + /** * Does not handle text decoration. * Decorations (underline and stike-thru) will be handled by SkCanvas. diff --git a/include/core/SkImage.h b/include/core/SkImage.h index ec85516619..ebc9a29394 100644 --- a/include/core/SkImage.h +++ b/include/core/SkImage.h @@ -172,19 +172,6 @@ private: static uint32_t NextUniqueID(); typedef SkRefCnt INHERITED; - - friend class SkCanvas; - - void draw(SkCanvas*, SkScalar x, SkScalar y, const SkPaint*) const; - - /** - * Draw the image, cropped to the src rect, to the dst rect of a canvas. - * If src is larger than the bounds of the image, the rest of the image is - * filled with transparent black pixels. - * - * See SkCanvas::drawBitmapRectToRect for similar behavior. - */ - void drawRect(SkCanvas*, const SkRect* src, const SkRect& dst, const SkPaint*) const; }; #endif diff --git a/include/utils/SkDeferredCanvas.h b/include/utils/SkDeferredCanvas.h index ac8556f539..a8330493a7 100644 --- a/include/utils/SkDeferredCanvas.h +++ b/include/utils/SkDeferredCanvas.h @@ -177,12 +177,9 @@ protected: void onDrawBitmap(const SkBitmap&, SkScalar left, SkScalar top, const SkPaint*) override; void onDrawBitmapRect(const SkBitmap&, const SkRect* src, const SkRect& dst, const SkPaint*, DrawBitmapRectFlags flags) override; -#if 0 - // rely on conversion to bitmap(for now) void onDrawImage(const SkImage*, SkScalar left, SkScalar top, const SkPaint*) override; void onDrawImageRect(const SkImage*, const SkRect* src, const SkRect& dst, const SkPaint*) override; -#endif void onDrawBitmapNine(const SkBitmap&, const SkIRect& center, const SkRect& dst, const SkPaint*) override; void onDrawSprite(const SkBitmap&, int left, int top, const SkPaint*) override; diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp index 3e3f714880..34d6aaa0ab 100644 --- a/src/core/SkCanvas.cpp +++ b/src/core/SkCanvas.cpp @@ -1734,12 +1734,15 @@ void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) { this->onDrawPath(path, paint); } -void SkCanvas::drawImage(const SkImage* image, SkScalar dx, SkScalar dy, const SkPaint* paint) { - this->onDrawImage(image, dx, dy, paint); +void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) { + this->onDrawImage(image, x, y, paint); } void SkCanvas::drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst, const SkPaint* paint) { + if (dst.isEmpty()) { + return; + } this->onDrawImageRect(image, src, dst, paint); } @@ -1959,15 +1962,58 @@ void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) { LOOPER_END } -void SkCanvas::onDrawImage(const SkImage* image, SkScalar dx, SkScalar dy, const SkPaint* paint) { +void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) { TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImage()"); - image->draw(this, dx, dy, paint); + SkRect bounds = SkRect::MakeXYWH(x, y, + SkIntToScalar(image->width()), SkIntToScalar(image->height())); + if (NULL == paint || paint->canComputeFastBounds()) { + if (paint) { + paint->computeFastBounds(bounds, &bounds); + } + if (this->quickReject(bounds)) { + return; + } + } + + SkLazyPaint lazy; + if (NULL == paint) { + paint = lazy.init(); + } + + LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &bounds) + + while (iter.next()) { + iter.fDevice->drawImage(iter, image, x, y, looper.paint()); + } + + LOOPER_END } void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst, const SkPaint* paint) { TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageRect()"); - image->drawRect(this, src, dst, paint); + SkRect storage; + const SkRect* bounds = &dst; + if (NULL == paint || paint->canComputeFastBounds()) { + if (paint) { + bounds = &paint->computeFastBounds(dst, &storage); + } + if (this->quickReject(*bounds)) { + return; + } + } + SkLazyPaint lazy; + if (NULL == paint) { + paint = lazy.init(); + } + + LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds) + + while (iter.next()) { + iter.fDevice->drawImageRect(iter, image, src, dst, looper.paint()); + } + + LOOPER_END } void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) { diff --git a/src/core/SkDevice.cpp b/src/core/SkDevice.cpp index 6be9178f23..37fafd8dfb 100644 --- a/src/core/SkDevice.cpp +++ b/src/core/SkDevice.cpp @@ -9,6 +9,7 @@ #include "SkDeviceProperties.h" #include "SkDraw.h" #include "SkDrawFilter.h" +#include "SkImage_Base.h" #include "SkMetaData.h" #include "SkPatchUtils.h" #include "SkPathMeasure.h" @@ -165,6 +166,24 @@ void SkBaseDevice::drawTextBlob(const SkDraw& draw, const SkTextBlob* blob, SkSc } } +void SkBaseDevice::drawImage(const SkDraw& draw, const SkImage* image, SkScalar x, SkScalar y, + const SkPaint& paint) { + // Default impl : turns everything into raster bitmap + SkBitmap bm; + if (as_IB(image)->getROPixels(&bm)) { + this->drawBitmap(draw, bm, SkMatrix::MakeTrans(x, y), paint); + } +} + +void SkBaseDevice::drawImageRect(const SkDraw& draw, const SkImage* image, const SkRect* src, + const SkRect& dst, const SkPaint& paint) { + // Default impl : turns everything into raster bitmap + SkBitmap bm; + if (as_IB(image)->getROPixels(&bm)) { + this->drawBitmapRect(draw, bm, src, dst, paint, SkCanvas::kNone_DrawBitmapRectFlag); + } +} + bool SkBaseDevice::readPixels(const SkImageInfo& info, void* dstP, size_t rowBytes, int x, int y) { #ifdef SK_DEBUG SkASSERT(info.width() > 0 && info.height() > 0); diff --git a/src/core/SkPaintPriv.cpp b/src/core/SkPaintPriv.cpp index c6957cd1ca..3ced573929 100644 --- a/src/core/SkPaintPriv.cpp +++ b/src/core/SkPaintPriv.cpp @@ -9,6 +9,7 @@ #include "SkBitmap.h" #include "SkColorFilter.h" +#include "SkImage.h" #include "SkPaint.h" #include "SkShader.h" @@ -49,3 +50,8 @@ bool isPaintOpaque(const SkPaint* paint, const SkBitmap* bmpReplacesShader) { return isPaintOpaque(paint, contentType); } + +bool isPaintOpaque(const SkPaint* paint, const SkImage* image) { + return isPaintOpaque(paint, image->isOpaque() ? + kOpaque_SkPaintBitmapOpacity : kUnknown_SkPaintBitmapOpacity); +} diff --git a/src/core/SkPaintPriv.h b/src/core/SkPaintPriv.h index 88fc4fc349..be441b8f72 100644 --- a/src/core/SkPaintPriv.h +++ b/src/core/SkPaintPriv.h @@ -8,11 +8,12 @@ #ifndef SkPaintPriv_DEFINED #define SkPaintPriv_DEFINED +#include "SkTypes.h" + class SkBitmap; +class SkImage; class SkPaint; -#include "SkTypes.h" - enum SkPaintBitmapOpacity { // No content replaces the paint's color kNoBitmap_SkPaintBitmapOpacity = 0, @@ -40,6 +41,7 @@ bool isPaintOpaque(const SkPaint* paint, SkPaintBitmapOpacity contentType); shader. @return true if paint is opaque */ -bool isPaintOpaque(const SkPaint* paint, - const SkBitmap* bmpReplacesShader = NULL); +bool isPaintOpaque(const SkPaint* paint, const SkBitmap* bmpReplacesShader = NULL); +bool isPaintOpaque(const SkPaint* paint, const SkImage* image); + #endif diff --git a/src/core/SkPictureRecord.cpp b/src/core/SkPictureRecord.cpp index 53ecdd0be6..07811fb128 100644 --- a/src/core/SkPictureRecord.cpp +++ b/src/core/SkPictureRecord.cpp @@ -7,6 +7,7 @@ #include "SkPictureRecord.h" #include "SkDevice.h" +#include "SkImage_Base.h" #include "SkPatchUtils.h" #include "SkPixelRef.h" #include "SkRRect.h" @@ -563,6 +564,22 @@ void SkPictureRecord::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src this->validate(initialOffset, size); } +void SkPictureRecord::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, + const SkPaint* paint) { + SkBitmap bm; + if (as_IB(image)->getROPixels(&bm)) { + this->SkPictureRecord::onDrawBitmap(bm, x, y, paint); + } +} + +void SkPictureRecord::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst, + const SkPaint* paint) { + SkBitmap bm; + if (as_IB(image)->getROPixels(&bm)) { + this->SkPictureRecord::onDrawBitmapRect(bm, src, dst, paint, kNone_DrawBitmapRectFlag); + } +} + void SkPictureRecord::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst, const SkPaint* paint) { // op + paint index + bitmap id + center + dst rect diff --git a/src/core/SkPictureRecord.h b/src/core/SkPictureRecord.h index 5e2d5a10e4..7a6fc813a5 100644 --- a/src/core/SkPictureRecord.h +++ b/src/core/SkPictureRecord.h @@ -184,12 +184,9 @@ protected: void onDrawBitmap(const SkBitmap&, SkScalar left, SkScalar top, const SkPaint*) override; void onDrawBitmapRect(const SkBitmap&, const SkRect* src, const SkRect& dst, const SkPaint*, DrawBitmapRectFlags flags) override; -#if 0 - // rely on conversion to bitmap (for now) void onDrawImage(const SkImage*, SkScalar left, SkScalar top, const SkPaint*) override; void onDrawImageRect(const SkImage*, const SkRect* src, const SkRect& dst, const SkPaint*) override; -#endif void onDrawBitmapNine(const SkBitmap&, const SkIRect& center, const SkRect& dst, const SkPaint*) override; void onDrawSprite(const SkBitmap&, int left, int top, const SkPaint*) override; diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp index 6ff0538ee2..9518600e99 100644 --- a/src/gpu/SkGpuDevice.cpp +++ b/src/gpu/SkGpuDevice.cpp @@ -21,6 +21,7 @@ #include "SkErrorInternals.h" #include "SkGlyphCache.h" #include "SkGrTexturePixelRef.h" +#include "SkImage_Base.h" #include "SkImageFilter.h" #include "SkLayerInfo.h" #include "SkMaskFilter.h" @@ -1730,6 +1731,47 @@ bool SkGpuDevice::filterImage(const SkImageFilter* filter, const SkBitmap& src, filter, ctx, result, offset); } +static SkImageInfo make_info(GrTexture* tex, int w, int h, bool isOpaque) { + const GrPixelConfig config = tex->config(); + SkColorType ct; + SkAlphaType at = isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType; + if (!GrPixelConfig2ColorAndProfileType(config, &ct, NULL)) { + ct = kUnknown_SkColorType; + } + return SkImageInfo::Make(w, h, ct, at); +} + +static bool wrap_as_bm(const SkImage* image, SkBitmap* bm) { + GrTexture* tex = image->getTexture(); + if (tex) { + // TODO: handle the GrTexture directly, and skip GrPixelRef + const SkImageInfo info = make_info(tex, image->width(), image->height(), image->isOpaque()); + bm->setInfo(info); + bm->setPixelRef(SkNEW_ARGS(SkGrPixelRef, (info, tex)))->unref(); + } else { + if (!as_IB(image)->getROPixels(bm)) { + return false; + } + } + return true; +} + +void SkGpuDevice::drawImage(const SkDraw& draw, const SkImage* image, SkScalar x, SkScalar y, + const SkPaint& paint) { + SkBitmap bm; + if (wrap_as_bm(image, &bm)) { + this->drawBitmap(draw, bm, SkMatrix::MakeTrans(x, y), paint); + } +} + +void SkGpuDevice::drawImageRect(const SkDraw& draw, const SkImage* image, const SkRect* src, + const SkRect& dst, const SkPaint& paint) { + SkBitmap bm; + if (wrap_as_bm(image, &bm)) { + this->drawBitmapRect(draw, bm, src, dst, paint, SkCanvas::kNone_DrawBitmapRectFlag); + } +} + /////////////////////////////////////////////////////////////////////////////// // must be in SkCanvas::VertexMode order diff --git a/src/gpu/SkGpuDevice.h b/src/gpu/SkGpuDevice.h index 30cf68daa8..89959e1f9c 100644 --- a/src/gpu/SkGpuDevice.h +++ b/src/gpu/SkGpuDevice.h @@ -115,6 +115,9 @@ public: const SkPaint&) override; virtual void drawDevice(const SkDraw&, SkBaseDevice*, int x, int y, const SkPaint&) override; + void drawImage(const SkDraw&, const SkImage*, SkScalar x, SkScalar y, const SkPaint&) override; + void drawImageRect(const SkDraw&, const SkImage*, const SkRect* src, const SkRect& dst, + const SkPaint&) override; void flush() override; diff --git a/src/image/SkImage.cpp b/src/image/SkImage.cpp index f427755d47..494e21004a 100644 --- a/src/image/SkImage.cpp +++ b/src/image/SkImage.cpp @@ -25,15 +25,6 @@ uint32_t SkImage::NextUniqueID() { return id; } -void SkImage::draw(SkCanvas* canvas, SkScalar x, SkScalar y, const SkPaint* paint) const { - as_IB(this)->onDraw(canvas, x, y, paint); -} - -void SkImage::drawRect(SkCanvas* canvas, const SkRect* src, const SkRect& dst, - const SkPaint* paint) const { - as_IB(this)->onDrawRect(canvas, src, dst, paint); -} - const void* SkImage::peekPixels(SkImageInfo* info, size_t* rowBytes) const { SkImageInfo infoStorage; size_t rowBytesStorage; diff --git a/src/image/SkImage_Base.h b/src/image/SkImage_Base.h index 512c80c44b..5daf4195e2 100644 --- a/src/image/SkImage_Base.h +++ b/src/image/SkImage_Base.h @@ -36,9 +36,6 @@ public: const SkSurfaceProps& props() const { return fProps; } - virtual void onDraw(SkCanvas*, SkScalar x, SkScalar y, const SkPaint*) const = 0; - virtual void onDrawRect(SkCanvas*, const SkRect* src, - const SkRect& dst, const SkPaint*) const = 0; virtual SkSurface* onNewSurface(const SkImageInfo&, const SkSurfaceProps&) const = 0; virtual const void* onPeekPixels(SkImageInfo*, size_t* /*rowBytes*/) const { diff --git a/src/image/SkImage_Gpu.cpp b/src/image/SkImage_Gpu.cpp index 7ccff17d9b..eec0d19760 100644 --- a/src/image/SkImage_Gpu.cpp +++ b/src/image/SkImage_Gpu.cpp @@ -26,15 +26,6 @@ SkShader* SkImage_Gpu::onNewShader(SkShader::TileMode tileX, return SkShader::CreateBitmapShader(fBitmap, tileX, tileY, localMatrix); } -void SkImage_Gpu::onDraw(SkCanvas* canvas, SkScalar x, SkScalar y, const SkPaint* paint) const { - canvas->drawBitmap(fBitmap, x, y, paint); -} - -void SkImage_Gpu::onDrawRect(SkCanvas* canvas, const SkRect* src, const SkRect& dst, - const SkPaint* paint) const { - canvas->drawBitmapRectToRect(fBitmap, src, dst, paint); -} - SkSurface* SkImage_Gpu::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) const { GrContext* ctx = this->getTexture()->getContext(); // TODO: Change signature of onNewSurface to take a budgeted param. diff --git a/src/image/SkImage_Gpu.h b/src/image/SkImage_Gpu.h index a771ddab24..7b38e60ea3 100644 --- a/src/image/SkImage_Gpu.h +++ b/src/image/SkImage_Gpu.h @@ -21,9 +21,6 @@ public: SkImage_Gpu(const SkBitmap&, int sampleCountForNewSurfaces, SkSurface::Budgeted); - void onDraw(SkCanvas*, SkScalar x, SkScalar y, const SkPaint*) const override; - void onDrawRect(SkCanvas*, const SkRect* src, const SkRect& dst, - const SkPaint*) const override; SkSurface* onNewSurface(const SkImageInfo&, const SkSurfaceProps&) const override; GrTexture* onGetTexture() const override; bool getROPixels(SkBitmap*) const override; diff --git a/src/image/SkImage_Raster.cpp b/src/image/SkImage_Raster.cpp index acf805829d..20ae62c9f7 100644 --- a/src/image/SkImage_Raster.cpp +++ b/src/image/SkImage_Raster.cpp @@ -53,8 +53,6 @@ public: SkImage_Raster(const SkImageInfo&, SkData*, size_t rb, const SkSurfaceProps*); virtual ~SkImage_Raster(); - void onDraw(SkCanvas*, SkScalar, SkScalar, const SkPaint*) const override; - void onDrawRect(SkCanvas*, const SkRect*, const SkRect&, const SkPaint*) const override; SkSurface* onNewSurface(const SkImageInfo&, const SkSurfaceProps&) const override; bool onReadPixels(const SkImageInfo&, void*, size_t, int srcX, int srcY) const override; const void* onPeekPixels(SkImageInfo*, size_t* /*rowBytes*/) const override; @@ -120,17 +118,6 @@ SkShader* SkImage_Raster::onNewShader(SkShader::TileMode tileX, SkShader::TileMo return SkShader::CreateBitmapShader(fBitmap, tileX, tileY, localMatrix); } -void SkImage_Raster::onDraw(SkCanvas* canvas, SkScalar x, SkScalar y, const SkPaint* paint) const { - SkBitmap shallowCopy(fBitmap); - canvas->drawBitmap(shallowCopy, x, y, paint); -} - -void SkImage_Raster::onDrawRect(SkCanvas* canvas, const SkRect* src, const SkRect& dst, - const SkPaint* paint) const { - SkBitmap shallowCopy(fBitmap); - canvas->drawBitmapRectToRect(shallowCopy, src, dst, paint); -} - SkSurface* SkImage_Raster::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) const { return SkSurface::NewRaster(info, &props); } diff --git a/src/pipe/SkGPipePriv.h b/src/pipe/SkGPipePriv.h index 736930b652..c3919f635b 100644 --- a/src/pipe/SkGPipePriv.h +++ b/src/pipe/SkGPipePriv.h @@ -43,6 +43,8 @@ enum DrawOps { kDrawBitmapNine_DrawOp, kDrawBitmapRectToRect_DrawOp, kDrawDRRect_DrawOp, + kDrawImage_DrawOp, + kDrawImageRect_DrawOp, kDrawOval_DrawOp, kDrawPaint_DrawOp, kDrawPatch_DrawOp, @@ -79,6 +81,7 @@ enum DrawOps { // these are signals to playback, not drawing verbs kReportFlags_DrawOp, kShareBitmapHeap_DrawOp, + kShareImageHeap_DrawOp, kDone_DrawOp, }; @@ -141,6 +144,7 @@ enum { kDrawVertices_HasIndices_DrawOpFlag = 1 << 2, kDrawVertices_HasXfermode_DrawOpFlag = 1 << 3, }; +// These are shared between drawbitmap and drawimage enum { kDrawBitmap_HasPaint_DrawOpFlag = 1 << 0, // Specific to drawBitmapRect, but needs to be different from HasPaint, @@ -213,6 +217,22 @@ static inline bool shouldFlattenBitmaps(uint32_t flags) { && !(flags & SkGPipeWriter::kSharedAddressSpace_Flag)); } +class SkImageHeap : public SkRefCnt { +public: + SkImageHeap(); + virtual ~SkImageHeap(); + + // slot must be "valid" -- 0 is never valid + const SkImage* get(int32_t slot) const; + // returns 0 if not found, else returns slot + int32_t find(const SkImage*) const; + // returns non-zero value for where the image was stored + int32_t insert(const SkImage*); + +private: + SkTDArray<const SkImage*> fArray; +}; + /////////////////////////////////////////////////////////////////////////////// enum PaintOps { diff --git a/src/pipe/SkGPipeRead.cpp b/src/pipe/SkGPipeRead.cpp index f8411f5aea..917bb50976 100644 --- a/src/pipe/SkGPipeRead.cpp +++ b/src/pipe/SkGPipeRead.cpp @@ -178,6 +178,10 @@ public: this->updateReader(); } + void setImageHeap(SkImageHeap* heap) { + fImageHeap.reset(SkRef(heap)); + } + /** * Access the shared heap. Only used in the case when bitmaps are not * flattened. @@ -198,6 +202,10 @@ public: return id ? fTypefaces[id - 1] : NULL; } + const SkImage* getImage(int32_t slot) const { + return fImageHeap->get(slot); + } + private: void updateReader() { if (NULL == fReader) { @@ -227,6 +235,7 @@ private: bool fSilent; // Only used when sharing bitmaps with the writer. SkBitmapHeap* fSharedHeap; + SkAutoTUnref<SkImageHeap> fImageHeap; unsigned fFlags; }; @@ -629,6 +638,35 @@ static void drawSprite_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32, } } +static void drawImage_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32, SkGPipeState* state) { + unsigned slot = DrawOp_unpackData(op32); + unsigned flags = DrawOp_unpackFlags(op32); + bool hasPaint = SkToBool(flags & kDrawBitmap_HasPaint_DrawOpFlag); + SkScalar x = reader->readScalar(); + SkScalar y = reader->readScalar(); + const SkImage* image = state->getImage(slot); + if (state->shouldDraw()) { + canvas->drawImage(image, x, y, hasPaint ? &state->paint() : NULL); + } +} + +static void drawImageRect_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32, + SkGPipeState* state) { + unsigned slot = DrawOp_unpackData(op32); + unsigned flags = DrawOp_unpackFlags(op32); + bool hasPaint = SkToBool(flags & kDrawBitmap_HasPaint_DrawOpFlag); + bool hasSrc = SkToBool(flags & kDrawBitmap_HasSrcRect_DrawOpFlag); + const SkRect* src = NULL; + if (hasSrc) { + src = skip<SkRect>(reader); + } + const SkRect* dst = skip<SkRect>(reader); + const SkImage* image = state->getImage(slot); + if (state->shouldDraw()) { + canvas->drawImageRect(image, src, *dst, hasPaint ? &state->paint() : NULL); + } +} + /////////////////////////////////////////////////////////////////////////////// static void drawPicture_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32, @@ -774,10 +812,14 @@ static void reportFlags_rp(SkCanvas*, SkReader32*, uint32_t op32, } static void shareBitmapHeap_rp(SkCanvas*, SkReader32* reader, uint32_t, - SkGPipeState* state) { + SkGPipeState* state) { state->setSharedHeap(static_cast<SkBitmapHeap*>(reader->readPtr())); } +static void shareImageHeap_rp(SkCanvas*, SkReader32* reader, uint32_t, SkGPipeState* state) { + state->setImageHeap(static_cast<SkImageHeap*>(reader->readPtr())); +} + static void done_rp(SkCanvas*, SkReader32*, uint32_t, SkGPipeState*) {} typedef void (*ReadProc)(SkCanvas*, SkReader32*, uint32_t op32, SkGPipeState*); @@ -793,6 +835,8 @@ static const ReadProc gReadTable[] = { drawBitmapNine_rp, drawBitmapRect_rp, drawDRRect_rp, + drawImage_rp, + drawImageRect_rp, drawOval_rp, drawPaint_rp, drawPatch_rp, @@ -828,6 +872,7 @@ static const ReadProc gReadTable[] = { reportFlags_rp, shareBitmapHeap_rp, + shareImageHeap_rp, done_rp }; diff --git a/src/pipe/SkGPipeWrite.cpp b/src/pipe/SkGPipeWrite.cpp index 83e5c57d27..2e73be83f1 100644 --- a/src/pipe/SkGPipeWrite.cpp +++ b/src/pipe/SkGPipeWrite.cpp @@ -272,12 +272,9 @@ protected: void onDrawBitmap(const SkBitmap&, SkScalar left, SkScalar top, const SkPaint*) override; void onDrawBitmapRect(const SkBitmap&, const SkRect* src, const SkRect& dst, const SkPaint*, DrawBitmapRectFlags flags) override; -#if 0 - // rely on decomposition into bitmap (for now) void onDrawImage(const SkImage*, SkScalar left, SkScalar top, const SkPaint*) override; void onDrawImageRect(const SkImage*, const SkRect* src, const SkRect& dst, const SkPaint*) override; -#endif void onDrawBitmapNine(const SkBitmap&, const SkIRect& center, const SkRect& dst, const SkPaint*) override; void onDrawSprite(const SkBitmap&, int left, int top, const SkPaint*) override; @@ -300,6 +297,7 @@ private: SkNamedFactorySet* fFactorySet; SkBitmapHeap* fBitmapHeap; + SkImageHeap* fImageHeap; SkGPipeController* fController; SkWriter32& fWriter; size_t fBlockSize; // amount allocated for writer @@ -348,8 +346,8 @@ private: // Common code used by drawBitmap*. Behaves differently depending on the // type of SkBitmapHeap being used, which is determined by the flags used. - bool commonDrawBitmap(const SkBitmap& bm, DrawOps op, unsigned flags, - size_t opBytesNeeded, const SkPaint* paint); + bool commonDrawBitmap(const SkBitmap&, DrawOps, unsigned flags, size_t bytes, const SkPaint*); + bool commonDrawImage(const SkImage*, DrawOps, unsigned flags, size_t bytes, const SkPaint*); SkPaint fPaint; void writePaint(const SkPaint&); @@ -462,6 +460,13 @@ SkGPipeCanvas::SkGPipeCanvas(SkGPipeController* controller, } } fFlattenableHeap.setBitmapStorage(fBitmapHeap); + + fImageHeap = SkNEW(SkImageHeap); + if (this->needOpBytes(sizeof(void*))) { + this->writeOp(kShareImageHeap_DrawOp); + fWriter.writePtr(static_cast<void*>(fImageHeap)); + } + this->doNotify(); } @@ -469,6 +474,7 @@ SkGPipeCanvas::~SkGPipeCanvas() { this->finish(true); SkSafeUnref(fFactorySet); SkSafeUnref(fBitmapHeap); + SkSafeUnref(fImageHeap); } bool SkGPipeCanvas::needOpBytes(size_t needed) { @@ -823,6 +829,53 @@ void SkGPipeCanvas::onDrawSprite(const SkBitmap& bm, int left, int top, const Sk } } +bool SkGPipeCanvas::commonDrawImage(const SkImage* image, DrawOps op, unsigned flags, + size_t opBytesNeeded, const SkPaint* paint) { + if (fDone) { + return false; + } + + if (paint != NULL) { + flags |= kDrawBitmap_HasPaint_DrawOpFlag; + this->writePaint(*paint); + } + // This needs to run first so its calls to needOpBytes() and its writes + // don't interlace with the needOpBytes() and write below. + int32_t slot = fImageHeap->insert(image); + SkASSERT(slot != 0); + if (this->needOpBytes(opBytesNeeded)) { + this->writeOp(op, flags, slot); + return true; + } + return false; +} + +void SkGPipeCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, + const SkPaint* paint) { + NOTIFY_SETUP(this); + if (this->commonDrawImage(image, kDrawImage_DrawOp, 0, sizeof(SkScalar) * 2, paint)) { + fWriter.writeScalar(x); + fWriter.writeScalar(y); + } +} + +void SkGPipeCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst, + const SkPaint* paint) { + NOTIFY_SETUP(this); + unsigned flags = 0; + size_t opBytesNeeded = sizeof(SkRect); // dst + if (src) { + flags |= kDrawBitmap_HasSrcRect_DrawOpFlag; + opBytesNeeded += sizeof(SkRect); // src + } + if (this->commonDrawImage(image, kDrawImageRect_DrawOp, flags, opBytesNeeded, paint)) { + if (src) { + fWriter.writeRect(*src); + } + fWriter.writeRect(dst); + } +} + void SkGPipeCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y, const SkPaint& paint) { if (byteLength) { @@ -1337,3 +1390,34 @@ void BitmapShuttle::removeCanvas() { fCanvas->unref(); fCanvas = NULL; } + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +SkImageHeap::SkImageHeap() {} + +SkImageHeap::~SkImageHeap() { + fArray.unrefAll(); +} + +const SkImage* SkImageHeap::get(int32_t slot) const { + SkASSERT(slot > 0); + return fArray[slot - 1]; +} + +int32_t SkImageHeap::find(const SkImage* img) const { + int index = fArray.find(img); + if (index >= 0) { + return index + 1; // found + } + return 0; // not found +} + +int32_t SkImageHeap::insert(const SkImage* img) { + int32_t slot = this->find(img); + if (slot) { + return slot; + } + *fArray.append() = SkRef(img); + return fArray.count(); // slot is always index+1 +} + diff --git a/src/utils/SkDeferredCanvas.cpp b/src/utils/SkDeferredCanvas.cpp index d5cf97bd04..7d0a8e8593 100644 --- a/src/utils/SkDeferredCanvas.cpp +++ b/src/utils/SkDeferredCanvas.cpp @@ -32,12 +32,31 @@ enum PlaybackMode { kSilent_PlaybackMode, }; -static bool should_draw_immediately(const SkBitmap* bitmap, const SkPaint* paint, - size_t bitmapSizeThreshold) { +static uint64_t image_area(const SkImage* image) { + return sk_64_mul(image->width(), image->height()); +} + +// HACK -- see crbug.com/485243 +// +// Work around case where Blink gives us an image, but will "mutate" it (by changing its contents +// directly using webgl). Until that is fixed at the call-site, we treat gpu-backed-images as +// mutable for now (at least for the purposes of deferred canvas) +// +static bool should_draw_gpu_image_immediately(const SkImage* image) { + return image->getTexture() != NULL; +} + +static bool should_draw_immediately(const SkBitmap* bitmap, const SkImage* image, + const SkPaint* paint, size_t bitmapSizeThreshold) { if (bitmap && ((bitmap->getTexture() && !bitmap->isImmutable()) || - (bitmap->getSize() > bitmapSizeThreshold))) { + (bitmap->getSize() > bitmapSizeThreshold))) { return true; } + if (image) { + if (should_draw_gpu_image_immediately(image) || image_area(image) > bitmapSizeThreshold) { + return true; + } + } if (paint) { SkShader* shader = paint->getShader(); // Here we detect the case where the shader is an SkBitmapProcShader @@ -202,6 +221,11 @@ protected: void drawSprite(const SkDraw&, const SkBitmap& bitmap, int x, int y, const SkPaint& paint) override {SkASSERT(0);} + void drawImage(const SkDraw&, const SkImage*, SkScalar, SkScalar, const SkPaint&) override + {SkASSERT(0);} + void drawImageRect(const SkDraw&, const SkImage*, const SkRect*, const SkRect&, + const SkPaint&) override + {SkASSERT(0);} void drawText(const SkDraw&, const void* text, size_t len, SkScalar x, SkScalar y, const SkPaint& paint) override {SkASSERT(0);} @@ -481,11 +505,15 @@ class AutoImmediateDrawIfNeeded { public: AutoImmediateDrawIfNeeded(SkDeferredCanvas& canvas, const SkBitmap* bitmap, const SkPaint* paint) { - this->init(canvas, bitmap, paint); + this->init(canvas, bitmap, NULL, paint); + } + AutoImmediateDrawIfNeeded(SkDeferredCanvas& canvas, const SkImage* image, + const SkPaint* paint) { + this->init(canvas, NULL, image, paint); } AutoImmediateDrawIfNeeded(SkDeferredCanvas& canvas, const SkPaint* paint) { - this->init(canvas, NULL, paint); + this->init(canvas, NULL, NULL, paint); } ~AutoImmediateDrawIfNeeded() { @@ -494,9 +522,10 @@ public: } } private: - void init(SkDeferredCanvas& canvas, const SkBitmap* bitmap, const SkPaint* paint) { + void init(SkDeferredCanvas& canvas, const SkBitmap* bitmap, const SkImage* image, + const SkPaint* paint) { if (canvas.isDeferredDrawing() && - should_draw_immediately(bitmap, paint, canvas.getBitmapSizeThreshold())) { + should_draw_immediately(bitmap, image, paint, canvas.getBitmapSizeThreshold())) { canvas.setDeferredDrawing(false); fCanvas = &canvas; } else { @@ -836,6 +865,34 @@ void SkDeferredCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* sr this->recordedDrawCommand(); } + +void SkDeferredCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, + const SkPaint* paint) { + SkRect bounds = SkRect::MakeXYWH(x, y, + SkIntToScalar(image->width()), SkIntToScalar(image->height())); + if (fDeferredDrawing && + this->isFullFrame(&bounds, paint) && + isPaintOpaque(paint, image)) { + this->getDeferredDevice()->skipPendingCommands(); + } + + AutoImmediateDrawIfNeeded autoDraw(*this, image, paint); + this->drawingCanvas()->drawImage(image, x, y, paint); + this->recordedDrawCommand(); +} +void SkDeferredCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst, + const SkPaint* paint) { + if (fDeferredDrawing && + this->isFullFrame(&dst, paint) && + isPaintOpaque(paint, image)) { + this->getDeferredDevice()->skipPendingCommands(); + } + + AutoImmediateDrawIfNeeded autoDraw(*this, image, paint); + this->drawingCanvas()->drawImageRect(image, src, dst, paint); + this->recordedDrawCommand(); +} + void SkDeferredCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst, const SkPaint* paint) { |