add SkCanvas::drawDRRect
authorcommit-bot@chromium.org <commit-bot@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81>
Fri, 21 Feb 2014 02:32:36 +0000 (02:32 +0000)
committercommit-bot@chromium.org <commit-bot@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81>
Fri, 21 Feb 2014 02:32:36 +0000 (02:32 +0000)
BUG=skia:
R=bsalomon@google.com, robertphillips@google.com, humper@google.com

Author: reed@google.com

Review URL: https://codereview.chromium.org/174243003

git-svn-id: http://skia.googlecode.com/svn/trunk@13524 2bbb7eff-a529-9590-31e7-b0007b416f81

15 files changed:
gm/drrect.cpp [new file with mode: 0644]
gyp/gmslides.gypi
include/core/SkCanvas.h
include/core/SkDevice.h
src/core/SkBBoxRecord.cpp
src/core/SkBBoxRecord.h
src/core/SkCanvas.cpp
src/core/SkDevice.cpp
src/core/SkPictureFlat.h
src/core/SkPicturePlayback.cpp
src/core/SkPictureRecord.cpp
src/core/SkPictureRecord.h
src/pipe/SkGPipePriv.h
src/pipe/SkGPipeRead.cpp
src/pipe/SkGPipeWrite.cpp

diff --git a/gm/drrect.cpp b/gm/drrect.cpp
new file mode 100644 (file)
index 0000000..5bf4a08
--- /dev/null
@@ -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; )
index 8a9d36b..323a40a 100644 (file)
@@ -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',
index 3952705..754fd16 100644 (file)
@@ -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
index 2c85dbd..899c5d3 100644 (file)
@@ -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
index a757a24..7075cd1 100644 (file)
@@ -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
index 2a34320..862e48e 100644 (file)
@@ -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
index 93dc14b..f903fd4 100644 (file)
@@ -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);
index 40663b2..4316c0c 100644 (file)
@@ -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);
+}
+
index 6b4af13..68b3984 100644 (file)
@@ -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*
index 8b8c6b0..5735645 100644 (file)
@@ -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);
index c14328b..aedb7df 100644 (file)
@@ -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
index c000f11..2fb99fa 100644 (file)
@@ -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().
index d1970c4..5e0b189 100644 (file)
@@ -45,6 +45,7 @@ enum DrawOps {
     kDrawBitmapRectToRect_DrawOp,
     kDrawClear_DrawOp,
     kDrawData_DrawOp,
+    kDrawDRRect_DrawOp,
     kDrawOval_DrawOp,
     kDrawPaint_DrawOp,
     kDrawPath_DrawOp,
index 513a34d..8827adc 100644 (file)
@@ -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,
index 17305bf..879ce82 100644 (file)
@@ -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);