[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:
parent
b1af07aa43
commit
683001ce0d
@ -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)
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user