diff options
-rw-r--r-- | gm/drrect.cpp | 69 | ||||
-rw-r--r-- | gyp/gmslides.gypi | 1 | ||||
-rw-r--r-- | include/core/SkCanvas.h | 8 | ||||
-rw-r--r-- | include/core/SkDevice.h | 4 | ||||
-rw-r--r-- | src/core/SkBBoxRecord.cpp | 7 | ||||
-rw-r--r-- | src/core/SkBBoxRecord.h | 3 | ||||
-rw-r--r-- | src/core/SkCanvas.cpp | 41 | ||||
-rw-r--r-- | src/core/SkDevice.cpp | 13 | ||||
-rw-r--r-- | src/core/SkPictureFlat.h | 5 | ||||
-rw-r--r-- | src/core/SkPicturePlayback.cpp | 7 | ||||
-rw-r--r-- | src/core/SkPictureRecord.cpp | 28 | ||||
-rw-r--r-- | src/core/SkPictureRecord.h | 1 | ||||
-rw-r--r-- | src/pipe/SkGPipePriv.h | 1 | ||||
-rw-r--r-- | src/pipe/SkGPipeRead.cpp | 11 | ||||
-rw-r--r-- | src/pipe/SkGPipeWrite.cpp | 15 |
15 files changed, 211 insertions, 3 deletions
diff --git a/gm/drrect.cpp b/gm/drrect.cpp new file mode 100644 index 0000000000..5bf4a089c1 --- /dev/null +++ b/gm/drrect.cpp @@ -0,0 +1,69 @@ +/* + * Copyright 2014 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "gm.h" +#include "SkCanvas.h" +#include "SkRRect.h" +#include "SkPath.h" + +class DRRectGM : public skiagm::GM { +public: + DRRectGM() {} + +protected: + virtual SkString onShortName() SK_OVERRIDE { + return SkString("drrect"); + } + + virtual SkISize onISize() SK_OVERRIDE { + return SkISize::Make(640, 480); + } + + virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE { + SkPaint paint; + paint.setAntiAlias(true); + + SkRRect outers[4]; + // like squares/circles, to exercise fast-cases in GPU + SkRect r = { 0, 0, 100, 100 }; + SkVector radii[4] = { + { 0, 0 }, { 30, 1 }, { 10, 40 }, { 40, 40 } + }; + + const SkScalar dx = r.width() + 16; + const SkScalar dy = r.height() + 16; + + outers[0].setRect(r); + outers[1].setOval(r); + outers[2].setRectXY(r, 20, 20); + outers[3].setRectRadii(r, radii); + + SkRRect inners[5]; + r.inset(25, 25); + + inners[0].setEmpty(); + inners[1].setRect(r); + inners[2].setOval(r); + inners[3].setRectXY(r, 20, 20); + inners[4].setRectRadii(r, radii); + + canvas->translate(16, 16); + for (size_t j = 0; j < SK_ARRAY_COUNT(inners); ++j) { + for (size_t i = 0; i < SK_ARRAY_COUNT(outers); ++i) { + canvas->save(); + canvas->translate(dx * j, dy * i); + canvas->drawDRRect(outers[i], inners[j], paint); + canvas->restore(); + } + } + } + +private: + typedef GM INHERITED; +}; + +DEF_GM( return new DRRectGM; ) diff --git a/gyp/gmslides.gypi b/gyp/gmslides.gypi index 8a9d36b5e4..323a40a1e0 100644 --- a/gyp/gmslides.gypi +++ b/gyp/gmslides.gypi @@ -66,6 +66,7 @@ '../gm/drawbitmaprect.cpp', '../gm/drawlooper.cpp', '../gm/dropshadowimagefilter.cpp', + '../gm/drrect.cpp', '../gm/extractbitmap.cpp', '../gm/emptypath.cpp', '../gm/fatpathfill.cpp', diff --git a/include/core/SkCanvas.h b/include/core/SkCanvas.h index 3952705c33..754fd167a3 100644 --- a/include/core/SkCanvas.h +++ b/include/core/SkCanvas.h @@ -668,6 +668,12 @@ public: */ virtual void drawRRect(const SkRRect& rrect, const SkPaint& paint); + /** + * Draw the annulus formed by the outer and inner rrects. The results + * are undefined if the outer does not contain the inner. + */ + void drawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint&); + /** Draw the specified circle using the specified paint. If radius is <= 0, then nothing will be drawn. The circle will be filled or framed based on the Style in the paint. @@ -1061,6 +1067,8 @@ protected: // default impl defers to its device virtual const void* onPeekPixels(SkImageInfo*, size_t* rowBytes); + virtual void onDrawDRRect(const SkRRect&, const SkRRect&, const SkPaint&); + // Returns the canvas to be used by DrawIter. Default implementation // returns this. Subclasses that encapsulate an indirect canvas may // need to overload this method. The impl must keep track of this, as it diff --git a/include/core/SkDevice.h b/include/core/SkDevice.h index 2c85dbd403..899c5d3754 100644 --- a/include/core/SkDevice.h +++ b/include/core/SkDevice.h @@ -237,6 +237,10 @@ protected: virtual void drawRRect(const SkDraw&, const SkRRect& rr, const SkPaint& paint) = 0; + // Default impl calls drawPath() + virtual void drawDRRect(const SkDraw&, const SkRRect& outer, + const SkRRect& inner, const SkPaint&); + /** * If pathIsMutable, then the implementation is allowed to cast path to a * non-const pointer and modify it in place (as an optimization). Canvas diff --git a/src/core/SkBBoxRecord.cpp b/src/core/SkBBoxRecord.cpp index a757a245ce..7075cd1651 100644 --- a/src/core/SkBBoxRecord.cpp +++ b/src/core/SkBBoxRecord.cpp @@ -26,6 +26,13 @@ void SkBBoxRecord::drawRect(const SkRect& rect, const SkPaint& paint) { } } +void SkBBoxRecord::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, + const SkPaint& paint) { + if (this->transformBounds(outer.rect(), &paint)) { + this->INHERITED::onDrawDRRect(outer, inner, paint); + } +} + void SkBBoxRecord::drawPath(const SkPath& path, const SkPaint& paint) { if (path.isInverseFillType()) { // If path is inverse filled, use the current clip bounds as the diff --git a/src/core/SkBBoxRecord.h b/src/core/SkBBoxRecord.h index 2a34320148..862e48e5b5 100644 --- a/src/core/SkBBoxRecord.h +++ b/src/core/SkBBoxRecord.h @@ -64,6 +64,9 @@ public: const SkPaint& paint) SK_OVERRIDE; virtual void drawPicture(SkPicture& picture) SK_OVERRIDE; +protected: + virtual void onDrawDRRect(const SkRRect&, const SkRRect&, const SkPaint&) SK_OVERRIDE; + private: /** * Takes a bounding box in current canvas view space, accounts for stroking and effects, and diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp index 93dc14bd1e..f903fd40ce 100644 --- a/src/core/SkCanvas.cpp +++ b/src/core/SkCanvas.cpp @@ -1594,6 +1594,26 @@ GrContext* SkCanvas::getGrContext() { } +void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner, + const SkPaint& paint) { + if (outer.isEmpty()) { + return; + } + if (inner.isEmpty()) { + this->drawRRect(outer, paint); + return; + } + + // We don't have this method (yet), but technically this is what we should + // be able to assert... + // SkASSERT(outer.contains(inner)); + // + // For now at least check for containment of bounds + SkASSERT(outer.getBounds().contains(inner.getBounds())); + + this->onDrawDRRect(outer, inner, paint); +} + ////////////////////////////////////////////////////////////////////////////// // These are the virtual drawing methods ////////////////////////////////////////////////////////////////////////////// @@ -1729,6 +1749,27 @@ void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) { LOOPER_END } +void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, + const SkPaint& paint) { + CHECK_SHADER_NOSETCONTEXT(paint); + + SkRect storage; + const SkRect* bounds = NULL; + if (paint.canComputeFastBounds()) { + bounds = &paint.computeFastBounds(outer.getBounds(), &storage); + if (this->quickReject(*bounds)) { + return; + } + } + + LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds) + + while (iter.next()) { + iter.fDevice->drawDRRect(iter, outer, inner, looper.paint()); + } + + LOOPER_END +} void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) { CHECK_SHADER_NOSETCONTEXT(paint); diff --git a/src/core/SkDevice.cpp b/src/core/SkDevice.cpp index 40663b2e03..4316c0ca3f 100644 --- a/src/core/SkDevice.cpp +++ b/src/core/SkDevice.cpp @@ -158,3 +158,16 @@ bool SkBaseDevice::readPixels(SkBitmap* bitmap, int x, int y, SkSurface* SkBaseDevice::newSurface(const SkImageInfo&) { return NULL; } const void* SkBaseDevice::peekPixels(SkImageInfo*, size_t*) { return NULL; } + +void SkBaseDevice::drawDRRect(const SkDraw& draw, const SkRRect& outer, + const SkRRect& inner, const SkPaint& paint) { + SkPath path; + path.addRRect(outer); + path.addRRect(inner); + path.setFillType(SkPath::kEvenOdd_FillType); + + const SkMatrix* preMatrix = NULL; + const bool pathIsMutable = true; + this->drawPath(draw, path, paint, preMatrix, pathIsMutable); +} + diff --git a/src/core/SkPictureFlat.h b/src/core/SkPictureFlat.h index 6b4af13840..68b398482a 100644 --- a/src/core/SkPictureFlat.h +++ b/src/core/SkPictureFlat.h @@ -63,7 +63,10 @@ enum DrawType { COMMENT, END_COMMENT_GROUP, - LAST_DRAWTYPE_ENUM = END_COMMENT_GROUP + // new ops -- feel free to re-alphabetize on next version bump + DRAW_DRRECT, + + LAST_DRAWTYPE_ENUM = DRAW_DRRECT }; // In the 'match' method, this constant will match any flavor of DRAW_BITMAP* diff --git a/src/core/SkPicturePlayback.cpp b/src/core/SkPicturePlayback.cpp index 8b8c6b0862..57356459ee 100644 --- a/src/core/SkPicturePlayback.cpp +++ b/src/core/SkPicturePlayback.cpp @@ -910,6 +910,13 @@ void SkPicturePlayback::draw(SkCanvas& canvas, SkDrawPictureCallback* callback) canvas.drawData(reader.skip(length), length); // skip handles padding the read out to a multiple of 4 } break; + case DRAW_DRRECT: { + const SkPaint& paint = *getPaint(reader); + SkRRect outer, inner; + reader.readRRect(&outer); + reader.readRRect(&inner); + canvas.drawDRRect(outer, inner, paint); + } break; case BEGIN_COMMENT_GROUP: { const char* desc = reader.readString(); canvas.beginCommentGroup(desc); diff --git a/src/core/SkPictureRecord.cpp b/src/core/SkPictureRecord.cpp index c14328b7a8..aedb7dfd56 100644 --- a/src/core/SkPictureRecord.cpp +++ b/src/core/SkPictureRecord.cpp @@ -111,9 +111,11 @@ static inline uint32_t getPaintOffset(DrawType op, uint32_t opSize) { 0, // BEGIN_GROUP - no paint 0, // COMMENT - no paint 0, // END_GROUP - no paint + 1, // DRAWDRRECT - right after op code }; - SkASSERT(sizeof(gPaintOffsets) == LAST_DRAWTYPE_ENUM + 1); + SK_COMPILE_ASSERT(sizeof(gPaintOffsets) == LAST_DRAWTYPE_ENUM + 1, + need_to_be_in_sync); SkASSERT((unsigned)op <= (unsigned)LAST_DRAWTYPE_ENUM); int overflow = 0; @@ -463,6 +465,10 @@ static bool remove_save_layer2(SkWriter32* writer, int32_t offset, result[0], result[3]); } +static bool is_drawing_op(DrawType op) { + return (op > CONCAT && op < ROTATE) || DRAW_DRRECT == op; +} + /* * Restore has just been called (but not recorded), so look back at the * matching save(), and see if we can eliminate the pair of them, due to no @@ -511,7 +517,7 @@ static bool collapse_save_clip_restore(SkWriter32* writer, int32_t offset, offset += opSize; while (offset < restoreOffset) { op = peek_op_and_size(writer, offset, &opSize); - if ((op > CONCAT && op < ROTATE) || (SAVE_LAYER == op)) { + if (is_drawing_op(op) || (SAVE_LAYER == op)) { // drawing verb, abort return false; } @@ -1068,6 +1074,24 @@ void SkPictureRecord::drawRRect(const SkRRect& rrect, const SkPaint& paint) { } } +void SkPictureRecord::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, + const SkPaint& paint) { + +#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE + fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType); +#endif + + // op + paint index + rrects + uint32_t initialOffset, size; + size = 2 * kUInt32Size + SkRRect::kSizeInMemory * 2; + initialOffset = this->addDraw(DRAW_DRRECT, &size); + SkASSERT(initialOffset+getPaintOffset(DRAW_DRRECT, size) == fWriter.bytesWritten()); + this->addPaint(paint); + this->addRRect(outer); + this->addRRect(inner); + this->validate(initialOffset, size); +} + void SkPictureRecord::drawPath(const SkPath& path, const SkPaint& paint) { #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE diff --git a/src/core/SkPictureRecord.h b/src/core/SkPictureRecord.h index c000f113ba..2fb99faf37 100644 --- a/src/core/SkPictureRecord.h +++ b/src/core/SkPictureRecord.h @@ -222,6 +222,7 @@ protected: const void* onPeekPixels(SkImageInfo*, size_t*) SK_OVERRIDE { return NULL; } + virtual void onDrawDRRect(const SkRRect&, const SkRRect&, const SkPaint&) SK_OVERRIDE; // Return fontmetrics.fTop,fBottom in topbot[0,1], after they have been // tweaked by paint.computeFastBounds(). diff --git a/src/pipe/SkGPipePriv.h b/src/pipe/SkGPipePriv.h index d1970c4a69..5e0b1893cd 100644 --- a/src/pipe/SkGPipePriv.h +++ b/src/pipe/SkGPipePriv.h @@ -45,6 +45,7 @@ enum DrawOps { kDrawBitmapRectToRect_DrawOp, kDrawClear_DrawOp, kDrawData_DrawOp, + kDrawDRRect_DrawOp, kDrawOval_DrawOp, kDrawPaint_DrawOp, kDrawPath_DrawOp, diff --git a/src/pipe/SkGPipeRead.cpp b/src/pipe/SkGPipeRead.cpp index 513a34d639..8827adc73f 100644 --- a/src/pipe/SkGPipeRead.cpp +++ b/src/pipe/SkGPipeRead.cpp @@ -396,6 +396,16 @@ static void drawRRect_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32, } } +static void drawDRRect_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32, + SkGPipeState* state) { + SkRRect outer, inner; + reader->readRRect(&outer); + reader->readRRect(&inner); + if (state->shouldDraw()) { + canvas->drawDRRect(outer, inner, state->paint()); + } +} + static void drawPath_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32, SkGPipeState* state) { SkPath path; @@ -763,6 +773,7 @@ static const ReadProc gReadTable[] = { drawBitmapRect_rp, drawClear_rp, drawData_rp, + drawDRRect_rp, drawOval_rp, drawPaint_rp, drawPath_rp, diff --git a/src/pipe/SkGPipeWrite.cpp b/src/pipe/SkGPipeWrite.cpp index 17305bf24b..879ce8288b 100644 --- a/src/pipe/SkGPipeWrite.cpp +++ b/src/pipe/SkGPipeWrite.cpp @@ -290,6 +290,10 @@ public: * according to slot. */ bool shuttleBitmap(const SkBitmap&, int32_t slot); + +protected: + virtual void onDrawDRRect(const SkRRect&, const SkRRect&, const SkPaint&) SK_OVERRIDE; + private: enum { kNoSaveLayer = -1, @@ -738,6 +742,17 @@ void SkGPipeCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) { } } +void SkGPipeCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, + const SkPaint& paint) { + NOTIFY_SETUP(this); + this->writePaint(paint); + if (this->needOpBytes(kSizeOfFlatRRect * 2)) { + this->writeOp(kDrawDRRect_DrawOp); + fWriter.writeRRect(outer); + fWriter.writeRRect(inner); + } +} + void SkGPipeCanvas::drawPath(const SkPath& path, const SkPaint& paint) { NOTIFY_SETUP(this); this->writePaint(paint); |