aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar bsalomon@google.com <bsalomon@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2011-10-05 19:57:55 +0000
committerGravatar bsalomon@google.com <bsalomon@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2011-10-05 19:57:55 +0000
commitfa6ac938e64fe11b442d05fe8a90ddac2d1951f9 (patch)
tree09e1bfdb59c0549a9cff72d1551376a25e262ce7
parent322878907f6c5c5fb8abdbce7d348a3cd66ff2fa (diff)
Fixup rendering of empty paths (including inverted fills)
Add GM and Sample that draw empty paths with various styles and fills Review URL: http://codereview.appspot.com/5185047/ git-svn-id: http://skia.googlecode.com/svn/trunk@2414 2bbb7eff-a529-9590-31e7-b0007b416f81
-rw-r--r--gm/emptypath.cpp138
-rw-r--r--gpu/include/GrTypes.h4
-rw-r--r--gpu/src/GrContext.cpp12
-rw-r--r--gpu/src/GrGpu.cpp4
-rw-r--r--gpu/src/GrTesselatedPathRenderer.cpp2
-rw-r--r--gyp/SampleApp.gyp1
-rw-r--r--gyp/gm.gyp1
-rw-r--r--include/core/SkCanvas.h2
-rw-r--r--samplecode/SampleEmptyPath.cpp130
-rw-r--r--src/core/SkCanvas.cpp12
10 files changed, 299 insertions, 7 deletions
diff --git a/gm/emptypath.cpp b/gm/emptypath.cpp
new file mode 100644
index 0000000000..dd33f68742
--- /dev/null
+++ b/gm/emptypath.cpp
@@ -0,0 +1,138 @@
+
+/*
+ * Copyright 2011 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 "SkPaint.h"
+#include "SkRandom.h"
+
+namespace skiagm {
+
+class EmptyPathGM : public GM {
+public:
+ EmptyPathGM() {}
+
+protected:
+ SkString onShortName() {
+ return SkString("emptypath");
+ }
+
+ SkISize onISize() { return make_isize(600, 280); }
+
+ void drawBG(SkCanvas* canvas) {
+ canvas->drawColor(SK_ColorWHITE);
+ }
+
+ void drawEmpty(SkCanvas* canvas,
+ SkColor color,
+ const SkRect& clip,
+ SkPaint::Style style,
+ SkPath::FillType fill) {
+ SkPath path;
+ path.setFillType(fill);
+ SkPaint paint;
+ paint.setColor(color);
+ paint.setStyle(style);
+ canvas->save();
+ canvas->clipRect(clip);
+ canvas->drawPath(path, paint);
+ canvas->restore();
+ }
+
+ virtual void onDraw(SkCanvas* canvas) {
+ this->drawBG(canvas);
+ struct FillAndName {
+ SkPath::FillType fFill;
+ const char* fName;
+ };
+ static const FillAndName gFills[] = {
+ {SkPath::kWinding_FillType, "Winding"},
+ {SkPath::kEvenOdd_FillType, "Even / Odd"},
+ {SkPath::kInverseWinding_FillType, "Inverse Winding"},
+ {SkPath::kInverseEvenOdd_FillType, "Inverse Even / Odd"},
+ };
+ struct StyleAndName {
+ SkPaint::Style fStyle;
+ const char* fName;
+ };
+ static const StyleAndName gStyles[] = {
+ {SkPaint::kFill_Style, "Fill"},
+ {SkPaint::kStroke_Style, "Stroke"},
+ {SkPaint::kStrokeAndFill_Style, "Stroke And Fill"},
+ };
+
+ SkPaint titlePaint;
+ titlePaint.setColor(SK_ColorBLACK);
+ titlePaint.setAntiAlias(true);
+ titlePaint.setLCDRenderText(true);
+ titlePaint.setTextSize(15 * SK_Scalar1);
+ const char title[] = "Empty Paths Drawn Into Rectangle Clips With "
+ "Indicated Style and Fill";
+ canvas->drawText(title, strlen(title),
+ 20 * SK_Scalar1,
+ 20 * SK_Scalar1,
+ titlePaint);
+
+ SkRandom rand;
+ SkRect rect = SkRect::MakeWH(100*SK_Scalar1, 30*SK_Scalar1);
+ int i = 0;
+ canvas->save();
+ canvas->translate(10 * SK_Scalar1, 0);
+ canvas->save();
+ for (int style = 0; style < SK_ARRAY_COUNT(gStyles); ++style) {
+ for (int fill = 0; fill < SK_ARRAY_COUNT(gFills); ++fill) {
+ if (0 == i % 4) {
+ canvas->restore();
+ canvas->translate(0, rect.height() + 40 * SK_Scalar1);
+ canvas->save();
+ } else {
+ canvas->translate(rect.width() + 40 * SK_Scalar1, 0);
+ }
+ ++i;
+
+
+ SkColor color = rand.nextU();
+ color = 0xff000000| color; // force solid
+ this->drawEmpty(canvas, color, rect,
+ gStyles[style].fStyle, gFills[fill].fFill);
+
+ SkPaint rectPaint;
+ rectPaint.setColor(SK_ColorBLACK);
+ rectPaint.setStyle(SkPaint::kStroke_Style);
+ rectPaint.setStrokeWidth(-1);
+ rectPaint.setAntiAlias(true);
+ canvas->drawRect(rect, rectPaint);
+
+ SkPaint labelPaint;
+ labelPaint.setColor(color);
+ labelPaint.setAntiAlias(true);
+ labelPaint.setLCDRenderText(true);
+ labelPaint.setTextSize(12 * SK_Scalar1);
+ canvas->drawText(gStyles[style].fName,
+ strlen(gStyles[style].fName),
+ 0, rect.height() + 15 * SK_Scalar1,
+ labelPaint);
+ canvas->drawText(gFills[fill].fName,
+ strlen(gFills[fill].fName),
+ 0, rect.height() + 28 * SK_Scalar1,
+ labelPaint);
+ }
+ }
+ canvas->restore();
+ canvas->restore();
+ }
+
+private:
+ typedef GM INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static GM* MyFactory(void*) { return new EmptyPathGM; }
+static GMRegistry reg(MyFactory);
+
+}
diff --git a/gpu/include/GrTypes.h b/gpu/include/GrTypes.h
index af43c1f540..8bbdecf7dc 100644
--- a/gpu/include/GrTypes.h
+++ b/gpu/include/GrTypes.h
@@ -435,7 +435,7 @@ enum GrPathFill {
kPathFillCount
};
-static inline GrPathFill NonInvertedFill(GrPathFill fill) {
+static inline GrPathFill GrNonInvertedFill(GrPathFill fill) {
static const GrPathFill gNonInvertedFills[] = {
kWinding_PathFill, // kWinding_PathFill
kEvenOdd_PathFill, // kEvenOdd_PathFill
@@ -452,7 +452,7 @@ static inline GrPathFill NonInvertedFill(GrPathFill fill) {
return gNonInvertedFills[fill];
}
-static inline bool IsFillInverted(GrPathFill fill) {
+static inline bool GrIsFillInverted(GrPathFill fill) {
static const bool gIsFillInverted[] = {
false, // kWinding_PathFill
false, // kEvenOdd_PathFill
diff --git a/gpu/src/GrContext.cpp b/gpu/src/GrContext.cpp
index e0c7b5559f..d9fb9e85c8 100644
--- a/gpu/src/GrContext.cpp
+++ b/gpu/src/GrContext.cpp
@@ -1445,6 +1445,16 @@ void GrContext::drawVertices(const GrPaint& paint,
void GrContext::drawPath(const GrPaint& paint, const GrPath& path,
GrPathFill fill, const GrPoint* translate) {
+ if (path.isEmpty()) {
+#if GR_DEBUG
+ GrPrintf("Empty path should have been caught by canvas.\n");
+#endif
+ if (GrIsFillInverted(fill)) {
+ this->drawPaint(paint);
+ }
+ return;
+ }
+
GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
// An Assumption here is that path renderer would use some form of tweaking
@@ -1503,7 +1513,7 @@ void GrContext::drawPath(const GrPaint& paint, const GrPath& path,
}
}
this->cleanupOffscreenAA(target, pr, &record);
- if (IsFillInverted(fill) && bound != clipIBounds) {
+ if (GrIsFillInverted(fill) && bound != clipIBounds) {
GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
GrRect rect;
if (clipIBounds.fTop < bound.fTop) {
diff --git a/gpu/src/GrGpu.cpp b/gpu/src/GrGpu.cpp
index 7b98ffa0b0..850fa60c4e 100644
--- a/gpu/src/GrGpu.cpp
+++ b/gpu/src/GrGpu.cpp
@@ -596,8 +596,8 @@ bool GrGpu::setupClipAndFlushState(GrPrimitiveType type) {
fillInverted = false;
} else {
fill = clip.getPathFill(c);
- fillInverted = IsFillInverted(fill);
- fill = NonInvertedFill(fill);
+ fillInverted = GrIsFillInverted(fill);
+ fill = GrNonInvertedFill(fill);
clipPath = &clip.getPath(c);
pr = this->getClipPathRenderer(*clipPath, fill);
if (NULL == pr) {
diff --git a/gpu/src/GrTesselatedPathRenderer.cpp b/gpu/src/GrTesselatedPathRenderer.cpp
index 5d544f2912..3c4bb0100c 100644
--- a/gpu/src/GrTesselatedPathRenderer.cpp
+++ b/gpu/src/GrTesselatedPathRenderer.cpp
@@ -366,7 +366,7 @@ void GrTesselatedPathRenderer::drawPath(GrDrawTarget::StageBitfield stages) {
}
}
- bool inverted = IsFillInverted(fFill);
+ bool inverted = GrIsFillInverted(fFill);
if (inverted) {
maxPts += 4;
subpathCnt++;
diff --git a/gyp/SampleApp.gyp b/gyp/SampleApp.gyp
index fd84893f62..dfd1e4c352 100644
--- a/gyp/SampleApp.gyp
+++ b/gyp/SampleApp.gyp
@@ -59,6 +59,7 @@
'../samplecode/SampleDrawLooper.cpp',
'../samplecode/SampleEffects.cpp',
'../samplecode/SampleEmboss.cpp',
+ '../samplecode/SampleEmptyPath.cpp',
'../samplecode/SampleEncode.cpp',
'../samplecode/SampleExtractAlpha.cpp',
'../samplecode/SampleFillType.cpp',
diff --git a/gyp/gm.gyp b/gyp/gm.gyp
index f0aeb64714..6226546b3f 100644
--- a/gyp/gm.gyp
+++ b/gyp/gm.gyp
@@ -14,6 +14,7 @@
'../gm/blurs.cpp',
'../gm/complexclip.cpp',
'../gm/complexclip2.cpp',
+ '../gm/emptypath.cpp',
'../gm/filltypes.cpp',
'../gm/filltypespersp.cpp',
'../gm/gmmain.cpp',
diff --git a/include/core/SkCanvas.h b/include/core/SkCanvas.h
index a6c95285b6..6ca9fa08a9 100644
--- a/include/core/SkCanvas.h
+++ b/include/core/SkCanvas.h
@@ -854,6 +854,8 @@ private:
const SkRect& dst, const SkPaint* paint);
void internalDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
const SkRect& dst, const SkPaint* paint);
+ void internalDrawPaint(const SkPaint& paint);
+
void drawDevice(SkDevice*, int x, int y, const SkPaint*);
// shared by save() and saveLayer()
diff --git a/samplecode/SampleEmptyPath.cpp b/samplecode/SampleEmptyPath.cpp
new file mode 100644
index 0000000000..5c865c66fd
--- /dev/null
+++ b/samplecode/SampleEmptyPath.cpp
@@ -0,0 +1,130 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkPaint.h"
+#include "SkRandom.h"
+
+class EmptyPathView : public SampleView {
+public:
+ EmptyPathView() {}
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "EmptyPath");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ void drawEmpty(SkCanvas* canvas,
+ SkColor color,
+ const SkRect& clip,
+ SkPaint::Style style,
+ SkPath::FillType fill) {
+ SkPath path;
+ path.setFillType(fill);
+ SkPaint paint;
+ paint.setColor(color);
+ paint.setStyle(style);
+ canvas->save();
+ canvas->clipRect(clip);
+ canvas->drawPath(path, paint);
+ canvas->restore();
+ }
+
+ virtual void onDrawContent(SkCanvas* canvas) {
+ struct FillAndName {
+ SkPath::FillType fFill;
+ const char* fName;
+ };
+ static const FillAndName gFills[] = {
+ {SkPath::kWinding_FillType, "Winding"},
+ {SkPath::kEvenOdd_FillType, "Even / Odd"},
+ {SkPath::kInverseWinding_FillType, "Inverse Winding"},
+ {SkPath::kInverseEvenOdd_FillType, "Inverse Even / Odd"},
+ };
+ struct StyleAndName {
+ SkPaint::Style fStyle;
+ const char* fName;
+ };
+ static const StyleAndName gStyles[] = {
+ {SkPaint::kFill_Style, "Fill"},
+ {SkPaint::kStroke_Style, "Stroke"},
+ {SkPaint::kStrokeAndFill_Style, "Stroke And Fill"},
+ };
+
+ SkPaint titlePaint;
+ titlePaint.setColor(SK_ColorBLACK);
+ titlePaint.setAntiAlias(true);
+ titlePaint.setLCDRenderText(true);
+ titlePaint.setTextSize(24 * SK_Scalar1);
+ const char title[] = "Empty Paths Drawn Into Rectangle Clips With Indicated Style and Fill";
+ canvas->drawText(title, strlen(title),
+ 40 * SK_Scalar1,
+ 100*SK_Scalar1,
+ titlePaint);
+
+ SkRandom rand;
+ SkRect rect = SkRect::MakeWH(125*SK_Scalar1, 100*SK_Scalar1);
+ int i = 0;
+ canvas->save();
+ canvas->translate(80 * SK_Scalar1, 0);
+ canvas->save();
+ for (int style = 0; style < SK_ARRAY_COUNT(gStyles); ++style) {
+ for (int fill = 0; fill < SK_ARRAY_COUNT(gFills); ++fill) {
+ if (0 == i % 4) {
+ canvas->restore();
+ canvas->translate(0, rect.height() + 50 * SK_Scalar1);
+ canvas->save();
+ } else {
+ canvas->translate(rect.width() + 100 * SK_Scalar1, 0);
+ }
+ ++i;
+
+
+ SkColor color = rand.nextU();
+ color = 0xff000000| color; // force solid
+ this->drawEmpty(canvas, color, rect,
+ gStyles[style].fStyle, gFills[fill].fFill);
+
+ SkPaint rectPaint;
+ rectPaint.setColor(SK_ColorBLACK);
+ rectPaint.setStyle(SkPaint::kStroke_Style);
+ rectPaint.setStrokeWidth(-1);
+ rectPaint.setAntiAlias(true);
+ canvas->drawRect(rect, rectPaint);
+
+ char label[1024];
+ sprintf(label, "%s, %s", gStyles[style].fName,
+ gFills[fill].fName);
+ SkPaint labelPaint;
+ labelPaint.setColor(color);
+ labelPaint.setAntiAlias(true);
+ labelPaint.setLCDRenderText(true);
+ canvas->drawText(label, strlen(label),
+ 0, rect.height() + 15 * SK_Scalar1,
+ labelPaint);
+ }
+ }
+ canvas->restore();
+ canvas->restore();
+ }
+
+private:
+ typedef SampleView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new EmptyPathView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp
index 3ee13bccc5..70b53fe994 100644
--- a/src/core/SkCanvas.cpp
+++ b/src/core/SkCanvas.cpp
@@ -1217,6 +1217,10 @@ void SkCanvas::clear(SkColor color) {
}
void SkCanvas::drawPaint(const SkPaint& paint) {
+ this->internalDrawPaint(paint);
+}
+
+void SkCanvas::internalDrawPaint(const SkPaint& paint) {
CHECK_NOTHING_TO_DRAW(paint);
LOOPER_BEGIN(paint, SkDrawFilter::kPaint_Type)
@@ -1269,7 +1273,7 @@ void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
CHECK_NOTHING_TO_DRAW(paint);
- if (paint.canComputeFastBounds()) {
+ if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
SkRect storage;
const SkRect& bounds = path.getBounds();
if (this->quickReject(paint.computeFastBounds(bounds, &storage),
@@ -1277,6 +1281,12 @@ void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
return;
}
}
+ if (path.isEmpty()) {
+ if (path.isInverseFillType()) {
+ this->internalDrawPaint(paint);
+ }
+ return;
+ }
LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type)