Commit 91fafce0 authored by Adrian Johnson's avatar Adrian Johnson Committed by Carlos Garcia Campos

cairo: align strokes when Stroke Adjust is true and line width <= 1

If the stroke coordinates are not aligned, lines in cairo may be up to
1 pixel wider than the requested width. This is most obvious when the
line width is 1 and the rendered line is 2 pixels.

When Stroke Adjust is true, the PDF standard requires that stroke
coordinates be adjusted to ensure the stroke width is within half a
pixel of the requested width.

If Stroke Adjust is enabled and the width is <= 1 pixel (the previous
commit adjusts the width to be at least 1 pixel), use the method
documented at http://www.cairographics.org/FAQ/#sharp_lines to align
the coordinates to ensure the rendered width is 1 pixel.

Fixes bug #4536.
parent cfc67afe
......@@ -157,6 +157,8 @@ CairoOutputDev::CairoOutputDev() {
// the SA parameter supposedly defaults to false, but Acrobat
// apparently hardwires it to true
stroke_adjust = globalParams->getStrokeAdjust();
align_stroke_coords = gFalse;
adjusted_stroke_width = gFalse;
}
CairoOutputDev::~CairoOutputDev() {
......@@ -412,6 +414,7 @@ void CairoOutputDev::updateMiterLimit(GfxState *state) {
void CairoOutputDev::updateLineWidth(GfxState *state) {
LOG(printf ("line width: %f\n", state->getLineWidth()));
adjusted_stroke_width = gFalse;
if (state->getLineWidth() == 0.0) {
/* find out how big pixels (device unit) are in the x and y directions
* choose the smaller of the two as our line width */
......@@ -431,11 +434,12 @@ void CairoOutputDev::updateLineWidth(GfxState *state) {
/* find out line width in device units */
cairo_user_to_device_distance(cairo, &x, &y);
if (x < 0.5 && y < 0.5) {
if (x <= 1.0 && y <= 1.0) {
/* adjust width to at least one device pixel */
x = y = 0.5;
x = y = 1.0;
cairo_device_to_user_distance(cairo, &x, &y);
width = MIN(fabs(x),fabs(y));
adjusted_stroke_width = gTrue;
}
}
cairo_set_line_width (cairo, width);
......@@ -632,6 +636,15 @@ void CairoOutputDev::updateFont(GfxState *state) {
cairo_set_font_matrix (cairo, &matrix);
}
void CairoOutputDev::alignStrokeCoords(double *x, double *y)
{
/* see http://www.cairographics.org/FAQ/#sharp_lines */
cairo_user_to_device (cairo, x, y);
*x = floor(*x) + 0.5;
*y = floor(*y) + 0.5;
cairo_device_to_user (cairo, x, y);
}
void CairoOutputDev::doPath(cairo_t *cairo, GfxState *state, GfxPath *path) {
GfxSubpath *subpath;
int i, j;
......@@ -639,8 +652,15 @@ void CairoOutputDev::doPath(cairo_t *cairo, GfxState *state, GfxPath *path) {
for (i = 0; i < path->getNumSubpaths(); ++i) {
subpath = path->getSubpath(i);
if (subpath->getNumPoints() > 0) {
cairo_move_to (cairo, subpath->getX(0), subpath->getY(0));
j = 1;
if (align_stroke_coords) {
double x = subpath->getX(0);
double y = subpath->getY(0);
alignStrokeCoords(&x, &y);
cairo_move_to (cairo, x, y);
} else {
cairo_move_to (cairo, subpath->getX(0), subpath->getY(0));
}
j = 1;
while (j < subpath->getNumPoints()) {
if (subpath->getCurve(j)) {
cairo_curve_to( cairo,
......@@ -650,7 +670,14 @@ void CairoOutputDev::doPath(cairo_t *cairo, GfxState *state, GfxPath *path) {
j += 3;
} else {
cairo_line_to (cairo, subpath->getX(j), subpath->getY(j));
if (align_stroke_coords) {
double x = subpath->getX(j);
double y = subpath->getY(j);
alignStrokeCoords(&x, &y);
cairo_line_to (cairo, x, y);
} else {
cairo_line_to (cairo, subpath->getX(j), subpath->getY(j));
}
++j;
}
}
......@@ -670,7 +697,10 @@ void CairoOutputDev::stroke(GfxState *state) {
return;
}
if (adjusted_stroke_width)
align_stroke_coords = gTrue;
doPath (cairo, state, state->getPath());
align_stroke_coords = gFalse;
cairo_set_source (cairo, stroke_pattern);
LOG(printf ("stroke\n"));
cairo_stroke (cairo);
......
......@@ -282,12 +282,15 @@ protected:
GBool getStreamData (Stream *str, char **buffer, int *length);
void setMimeData(Stream *str, Object *ref, cairo_surface_t *image);
void fillToStrokePathClip();
void alignStrokeCoords(double *x, double *y);
GfxRGB fill_color, stroke_color;
cairo_pattern_t *fill_pattern, *stroke_pattern;
double fill_opacity;
double stroke_opacity;
GBool stroke_adjust;
GBool adjusted_stroke_width;
GBool align_stroke_coords;
CairoFont *currentFont;
struct StrokePathClip {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment