aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--gm/drrect.cpp69
-rw-r--r--gyp/gmslides.gypi1
-rw-r--r--include/core/SkCanvas.h8
-rw-r--r--include/core/SkDevice.h4
-rw-r--r--src/core/SkBBoxRecord.cpp7
-rw-r--r--src/core/SkBBoxRecord.h3
-rw-r--r--src/core/SkCanvas.cpp41
-rw-r--r--src/core/SkDevice.cpp13
-rw-r--r--src/core/SkPictureFlat.h5
-rw-r--r--src/core/SkPicturePlayback.cpp7
-rw-r--r--src/core/SkPictureRecord.cpp28
-rw-r--r--src/core/SkPictureRecord.h1
-rw-r--r--src/pipe/SkGPipePriv.h1
-rw-r--r--src/pipe/SkGPipeRead.cpp11
-rw-r--r--src/pipe/SkGPipeWrite.cpp15
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);