[PDF] Ensure that filling single line paths (with no area) does not draw anything.
Add a test to a gm to confirm the new behavior.
Fixes http://crbug.com/123072
Review URL: https://codereview.appspot.com/6137060
git-svn-id: http://skia.googlecode.com/svn/trunk@3884 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/pdf/SkPDFDevice.cpp b/src/pdf/SkPDFDevice.cpp
index 733a612..8591728 100644
--- a/src/pdf/SkPDFDevice.cpp
+++ b/src/pdf/SkPDFDevice.cpp
@@ -262,7 +262,7 @@
SkPath::FillType clipFill;
if (clipPath) {
- SkPDFUtils::EmitPath(*clipPath, contentStream);
+ SkPDFUtils::EmitPath(*clipPath, SkPaint::kFill_Style, contentStream);
clipFill = clipPath->getFillType();
} else {
SkPDFUtils::AppendRectangle(*clipRect, contentStream);
@@ -765,7 +765,8 @@
if (!content.entry()) {
return;
}
- SkPDFUtils::EmitPath(*pathPtr, &content.entry()->fContent);
+ SkPDFUtils::EmitPath(*pathPtr, paint.getStyle(),
+ &content.entry()->fContent);
SkPDFUtils::PaintPath(paint.getStyle(), pathPtr->getFillType(),
&content.entry()->fContent);
}
diff --git a/src/pdf/SkPDFFont.cpp b/src/pdf/SkPDFFont.cpp
index e0e18cd..35394b6 100644
--- a/src/pdf/SkPDFFont.cpp
+++ b/src/pdf/SkPDFFont.cpp
@@ -1378,7 +1378,7 @@
&content);
const SkPath* path = cache->findPath(glyph);
if (path) {
- SkPDFUtils::EmitPath(*path, &content);
+ SkPDFUtils::EmitPath(*path, paint.getStyle(), &content);
SkPDFUtils::PaintPath(paint.getStyle(), path->getFillType(),
&content);
}
diff --git a/src/pdf/SkPDFUtils.cpp b/src/pdf/SkPDFUtils.cpp
index b596a27..8cd3a90 100644
--- a/src/pdf/SkPDFUtils.cpp
+++ b/src/pdf/SkPDFUtils.cpp
@@ -7,6 +7,7 @@
*/
+#include "SkData.h"
#include "SkGeometry.h"
#include "SkPaint.h"
#include "SkPath.h"
@@ -98,7 +99,23 @@
}
// static
-void SkPDFUtils::EmitPath(const SkPath& path, SkWStream* content) {
+void SkPDFUtils::EmitPath(const SkPath& path, SkPaint::Style paintStyle,
+ SkWStream* content) {
+ // Filling a path with no area results in a drawing in PDF renderers but
+ // Chrome expects to be able to draw some such entities with no visible
+ // result, so we detect those cases and discard the drawing for them.
+ // Specifically: moveTo(X), lineTo(Y) and moveTo(X), lineTo(X), lineTo(Y).
+ enum SkipFillState {
+ kEmpty_SkipFillState = 0,
+ kSingleLine_SkipFillState = 1,
+ kNonSingleLine_SkipFillState = 2,
+ };
+ SkipFillState fillState = kEmpty_SkipFillState;
+ if (paintStyle != SkPaint::kFill_Style) {
+ fillState = kNonSingleLine_SkipFillState;
+ }
+ SkPoint lastMovePt;
+ SkDynamicMemoryWStream currentSegment;
SkPoint args[4];
SkPath::Iter iter(path, false);
for (SkPath::Verb verb = iter.next(args);
@@ -107,30 +124,52 @@
// args gets all the points, even the implicit first point.
switch (verb) {
case SkPath::kMove_Verb:
- MoveTo(args[0].fX, args[0].fY, content);
+ MoveTo(args[0].fX, args[0].fY, ¤tSegment);
+ lastMovePt = args[0];
+ fillState = kEmpty_SkipFillState;
break;
case SkPath::kLine_Verb:
- AppendLine(args[1].fX, args[1].fY, content);
+ AppendLine(args[1].fX, args[1].fY, ¤tSegment);
+ if (fillState == kEmpty_SkipFillState) {
+ if (args[0] != lastMovePt) {
+ fillState = kSingleLine_SkipFillState;
+ }
+ } else if (fillState == kSingleLine_SkipFillState) {
+ fillState = kNonSingleLine_SkipFillState;
+ }
break;
case SkPath::kQuad_Verb: {
SkPoint cubic[4];
SkConvertQuadToCubic(args, cubic);
AppendCubic(cubic[1].fX, cubic[1].fY, cubic[2].fX, cubic[2].fY,
- cubic[3].fX, cubic[3].fY, content);
+ cubic[3].fX, cubic[3].fY, ¤tSegment);
+ fillState = kNonSingleLine_SkipFillState;
break;
}
case SkPath::kCubic_Verb:
AppendCubic(args[1].fX, args[1].fY, args[2].fX, args[2].fY,
- args[3].fX, args[3].fY, content);
+ args[3].fX, args[3].fY, ¤tSegment);
+ fillState = kNonSingleLine_SkipFillState;
break;
case SkPath::kClose_Verb:
- ClosePath(content);
+ if (fillState != kSingleLine_SkipFillState) {
+ ClosePath(¤tSegment);
+ SkData* data = currentSegment.copyToData();
+ content->write(data->data(), data->size());
+ data->unref();
+ }
+ currentSegment.reset();
break;
default:
SkASSERT(false);
break;
}
}
+ if (currentSegment.bytesWritten() > 0) {
+ SkData* data = currentSegment.copyToData();
+ content->write(data->data(), data->size());
+ data->unref();
+ }
}
// static
diff --git a/src/pdf/SkPDFUtils.h b/src/pdf/SkPDFUtils.h
index 5b9d74e..1bce614 100644
--- a/src/pdf/SkPDFUtils.h
+++ b/src/pdf/SkPDFUtils.h
@@ -10,6 +10,7 @@
#ifndef SkPDFUtils_DEFINED
#define SkPDFUtils_DEFINED
+#include "SkPaint.h"
#include "SkPath.h"
class SkMatrix;
@@ -42,7 +43,8 @@
SkScalar ctl2X, SkScalar ctl2Y,
SkScalar dstX, SkScalar dstY, SkWStream* content);
static void AppendRectangle(const SkRect& rect, SkWStream* content);
- static void EmitPath(const SkPath& path, SkWStream* content);
+ static void EmitPath(const SkPath& path, SkPaint::Style paintStyle,
+ SkWStream* content);
static void ClosePath(SkWStream* content);
static void PaintPath(SkPaint::Style style, SkPath::FillType fill,
SkWStream* content);