[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
This commit is contained in:
vandebo@chromium.org 2012-05-09 17:17:51 +00:00
parent b1af07aa43
commit 683001ce0d
5 changed files with 66 additions and 11 deletions

View File

@ -92,6 +92,18 @@ static SkScalar make_star(SkPath* path, int n) {
static SkScalar make_star_5(SkPath* path) { return make_star(path, 5); }
static SkScalar make_star_13(SkPath* path) { return make_star(path, 13); }
// We don't expect any output from this path.
static SkScalar make_line(SkPath* path) {
path->moveTo(SkIntToScalar(30), SkIntToScalar(30));
path->lineTo(SkIntToScalar(120), SkIntToScalar(40));
path->close();
path->moveTo(SkIntToScalar(150), SkIntToScalar(30));
path->lineTo(SkIntToScalar(150), SkIntToScalar(30));
path->lineTo(SkIntToScalar(300), SkIntToScalar(40));
path->close();
return SkIntToScalar(40);
}
static const MakePathProc gProcs[] = {
make_frame,
make_triangle,
@ -99,7 +111,8 @@ static const MakePathProc gProcs[] = {
make_oval,
make_sawtooth,
make_star_5,
make_star_13
make_star_13,
make_line,
};
#define N SK_ARRAY_COUNT(gProcs)

View File

@ -262,7 +262,7 @@ static void emit_clip(SkPath* clipPath, SkRect* clipRect,
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 @@ void SkPDFDevice::drawPath(const SkDraw& d, const SkPath& origPath,
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);
}

View File

@ -1378,7 +1378,7 @@ bool SkPDFType3Font::populate(int16_t glyphID) {
&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);
}

View File

@ -7,6 +7,7 @@
*/
#include "SkData.h"
#include "SkGeometry.h"
#include "SkPaint.h"
#include "SkPath.h"
@ -98,7 +99,23 @@ void SkPDFUtils::AppendRectangle(const SkRect& rect, SkWStream* content) {
}
// 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 @@ void SkPDFUtils::EmitPath(const SkPath& path, SkWStream* content) {
// 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, &currentSegment);
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, &currentSegment);
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, &currentSegment);
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, &currentSegment);
fillState = kNonSingleLine_SkipFillState;
break;
case SkPath::kClose_Verb:
ClosePath(content);
if (fillState != kSingleLine_SkipFillState) {
ClosePath(&currentSegment);
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

View File

@ -10,6 +10,7 @@
#ifndef SkPDFUtils_DEFINED
#define SkPDFUtils_DEFINED
#include "SkPaint.h"
#include "SkPath.h"
class SkMatrix;
@ -42,7 +43,8 @@ public:
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);