diff --git a/gm/pathfill.cpp b/gm/pathfill.cpp index 9d4b3c8701..6da507da34 100644 --- a/gm/pathfill.cpp +++ b/gm/pathfill.cpp @@ -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) diff --git a/src/pdf/SkPDFDevice.cpp b/src/pdf/SkPDFDevice.cpp index 733a6128b9..85917284db 100644 --- a/src/pdf/SkPDFDevice.cpp +++ b/src/pdf/SkPDFDevice.cpp @@ -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); } diff --git a/src/pdf/SkPDFFont.cpp b/src/pdf/SkPDFFont.cpp index e0e18cd933..35394b6804 100644 --- a/src/pdf/SkPDFFont.cpp +++ b/src/pdf/SkPDFFont.cpp @@ -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); } diff --git a/src/pdf/SkPDFUtils.cpp b/src/pdf/SkPDFUtils.cpp index b596a27a72..8cd3a90dd8 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 @@ 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, ¤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 5b9d74e321..1bce614554 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 @@ 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);