[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_5(SkPath* path) { return make_star(path, 5); }
|
||||||
static SkScalar make_star_13(SkPath* path) { return make_star(path, 13); }
|
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[] = {
|
static const MakePathProc gProcs[] = {
|
||||||
make_frame,
|
make_frame,
|
||||||
make_triangle,
|
make_triangle,
|
||||||
@ -99,7 +111,8 @@ static const MakePathProc gProcs[] = {
|
|||||||
make_oval,
|
make_oval,
|
||||||
make_sawtooth,
|
make_sawtooth,
|
||||||
make_star_5,
|
make_star_5,
|
||||||
make_star_13
|
make_star_13,
|
||||||
|
make_line,
|
||||||
};
|
};
|
||||||
|
|
||||||
#define N SK_ARRAY_COUNT(gProcs)
|
#define N SK_ARRAY_COUNT(gProcs)
|
||||||
|
@ -262,7 +262,7 @@ static void emit_clip(SkPath* clipPath, SkRect* clipRect,
|
|||||||
|
|
||||||
SkPath::FillType clipFill;
|
SkPath::FillType clipFill;
|
||||||
if (clipPath) {
|
if (clipPath) {
|
||||||
SkPDFUtils::EmitPath(*clipPath, contentStream);
|
SkPDFUtils::EmitPath(*clipPath, SkPaint::kFill_Style, contentStream);
|
||||||
clipFill = clipPath->getFillType();
|
clipFill = clipPath->getFillType();
|
||||||
} else {
|
} else {
|
||||||
SkPDFUtils::AppendRectangle(*clipRect, contentStream);
|
SkPDFUtils::AppendRectangle(*clipRect, contentStream);
|
||||||
@ -765,7 +765,8 @@ void SkPDFDevice::drawPath(const SkDraw& d, const SkPath& origPath,
|
|||||||
if (!content.entry()) {
|
if (!content.entry()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
SkPDFUtils::EmitPath(*pathPtr, &content.entry()->fContent);
|
SkPDFUtils::EmitPath(*pathPtr, paint.getStyle(),
|
||||||
|
&content.entry()->fContent);
|
||||||
SkPDFUtils::PaintPath(paint.getStyle(), pathPtr->getFillType(),
|
SkPDFUtils::PaintPath(paint.getStyle(), pathPtr->getFillType(),
|
||||||
&content.entry()->fContent);
|
&content.entry()->fContent);
|
||||||
}
|
}
|
||||||
|
@ -1378,7 +1378,7 @@ bool SkPDFType3Font::populate(int16_t glyphID) {
|
|||||||
&content);
|
&content);
|
||||||
const SkPath* path = cache->findPath(glyph);
|
const SkPath* path = cache->findPath(glyph);
|
||||||
if (path) {
|
if (path) {
|
||||||
SkPDFUtils::EmitPath(*path, &content);
|
SkPDFUtils::EmitPath(*path, paint.getStyle(), &content);
|
||||||
SkPDFUtils::PaintPath(paint.getStyle(), path->getFillType(),
|
SkPDFUtils::PaintPath(paint.getStyle(), path->getFillType(),
|
||||||
&content);
|
&content);
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "SkData.h"
|
||||||
#include "SkGeometry.h"
|
#include "SkGeometry.h"
|
||||||
#include "SkPaint.h"
|
#include "SkPaint.h"
|
||||||
#include "SkPath.h"
|
#include "SkPath.h"
|
||||||
@ -98,7 +99,23 @@ void SkPDFUtils::AppendRectangle(const SkRect& rect, SkWStream* content) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// static
|
// 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];
|
SkPoint args[4];
|
||||||
SkPath::Iter iter(path, false);
|
SkPath::Iter iter(path, false);
|
||||||
for (SkPath::Verb verb = iter.next(args);
|
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.
|
// args gets all the points, even the implicit first point.
|
||||||
switch (verb) {
|
switch (verb) {
|
||||||
case SkPath::kMove_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;
|
break;
|
||||||
case SkPath::kLine_Verb:
|
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;
|
break;
|
||||||
case SkPath::kQuad_Verb: {
|
case SkPath::kQuad_Verb: {
|
||||||
SkPoint cubic[4];
|
SkPoint cubic[4];
|
||||||
SkConvertQuadToCubic(args, cubic);
|
SkConvertQuadToCubic(args, cubic);
|
||||||
AppendCubic(cubic[1].fX, cubic[1].fY, cubic[2].fX, cubic[2].fY,
|
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;
|
break;
|
||||||
}
|
}
|
||||||
case SkPath::kCubic_Verb:
|
case SkPath::kCubic_Verb:
|
||||||
AppendCubic(args[1].fX, args[1].fY, args[2].fX, args[2].fY,
|
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;
|
break;
|
||||||
case SkPath::kClose_Verb:
|
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;
|
break;
|
||||||
default:
|
default:
|
||||||
SkASSERT(false);
|
SkASSERT(false);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (currentSegment.bytesWritten() > 0) {
|
||||||
|
SkData* data = currentSegment.copyToData();
|
||||||
|
content->write(data->data(), data->size());
|
||||||
|
data->unref();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
#ifndef SkPDFUtils_DEFINED
|
#ifndef SkPDFUtils_DEFINED
|
||||||
#define SkPDFUtils_DEFINED
|
#define SkPDFUtils_DEFINED
|
||||||
|
|
||||||
|
#include "SkPaint.h"
|
||||||
#include "SkPath.h"
|
#include "SkPath.h"
|
||||||
|
|
||||||
class SkMatrix;
|
class SkMatrix;
|
||||||
@ -42,7 +43,8 @@ public:
|
|||||||
SkScalar ctl2X, SkScalar ctl2Y,
|
SkScalar ctl2X, SkScalar ctl2Y,
|
||||||
SkScalar dstX, SkScalar dstY, SkWStream* content);
|
SkScalar dstX, SkScalar dstY, SkWStream* content);
|
||||||
static void AppendRectangle(const SkRect& rect, 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 ClosePath(SkWStream* content);
|
||||||
static void PaintPath(SkPaint::Style style, SkPath::FillType fill,
|
static void PaintPath(SkPaint::Style style, SkPath::FillType fill,
|
||||||
SkWStream* content);
|
SkWStream* content);
|
||||||
|
Loading…
Reference in New Issue
Block a user