Added hairline support to cairo
|
|
@ -68,6 +68,7 @@ struct _cairo_backend {
|
|||
cairo_status_t (*set_line_cap) (void *cr, cairo_line_cap_t line_cap);
|
||||
cairo_status_t (*set_line_join) (void *cr, cairo_line_join_t line_join);
|
||||
cairo_status_t (*set_line_width) (void *cr, double line_width);
|
||||
cairo_status_t (*set_hairline) (void *cr, cairo_bool_t set_hairline);
|
||||
cairo_status_t (*set_miter_limit) (void *cr, double limit);
|
||||
cairo_status_t (*set_opacity) (void *cr, double opacity);
|
||||
cairo_status_t (*set_operator) (void *cr, cairo_operator_t op);
|
||||
|
|
@ -79,6 +80,7 @@ struct _cairo_backend {
|
|||
cairo_line_cap_t (*get_line_cap) (void *cr);
|
||||
cairo_line_join_t (*get_line_join) (void *cr);
|
||||
double (*get_line_width) (void *cr);
|
||||
cairo_bool_t (*get_hairline) (void *cr);
|
||||
double (*get_miter_limit) (void *cr);
|
||||
double (*get_opacity) (void *cr);
|
||||
cairo_operator_t (*get_operator) (void *cr);
|
||||
|
|
|
|||
|
|
@ -122,18 +122,18 @@ _cairo_compositor_mask (const cairo_compositor_t *compositor,
|
|||
return status;
|
||||
}
|
||||
|
||||
cairo_int_status_t
|
||||
_cairo_compositor_stroke (const cairo_compositor_t *compositor,
|
||||
cairo_surface_t *surface,
|
||||
cairo_operator_t op,
|
||||
const cairo_pattern_t *source,
|
||||
const cairo_path_fixed_t *path,
|
||||
const cairo_stroke_style_t *style,
|
||||
const cairo_matrix_t *ctm,
|
||||
const cairo_matrix_t *ctm_inverse,
|
||||
double tolerance,
|
||||
cairo_antialias_t antialias,
|
||||
const cairo_clip_t *clip)
|
||||
static cairo_int_status_t
|
||||
_cairo_compositor_stroke_impl (const cairo_compositor_t *compositor,
|
||||
cairo_surface_t *surface,
|
||||
cairo_operator_t op,
|
||||
const cairo_pattern_t *source,
|
||||
const cairo_path_fixed_t *path,
|
||||
const cairo_stroke_style_t *style,
|
||||
const cairo_matrix_t *ctm,
|
||||
const cairo_matrix_t *ctm_inverse,
|
||||
double tolerance,
|
||||
cairo_antialias_t antialias,
|
||||
const cairo_clip_t *clip)
|
||||
{
|
||||
cairo_composite_rectangles_t extents;
|
||||
cairo_int_status_t status;
|
||||
|
|
@ -175,6 +175,48 @@ _cairo_compositor_stroke (const cairo_compositor_t *compositor,
|
|||
return status;
|
||||
}
|
||||
|
||||
cairo_int_status_t
|
||||
_cairo_compositor_stroke (const cairo_compositor_t *compositor,
|
||||
cairo_surface_t *surface,
|
||||
cairo_operator_t op,
|
||||
const cairo_pattern_t *source,
|
||||
const cairo_path_fixed_t *path,
|
||||
const cairo_stroke_style_t *style,
|
||||
const cairo_matrix_t *ctm,
|
||||
const cairo_matrix_t *ctm_inverse,
|
||||
double tolerance,
|
||||
cairo_antialias_t antialias,
|
||||
const cairo_clip_t *clip)
|
||||
{
|
||||
if (!style->is_hairline)
|
||||
return _cairo_compositor_stroke_impl (compositor, surface,
|
||||
op, source, path,
|
||||
style, ctm, ctm_inverse,
|
||||
tolerance, antialias, clip);
|
||||
else {
|
||||
cairo_stroke_style_t hairline_style;
|
||||
cairo_status_t status;
|
||||
cairo_matrix_t identity;
|
||||
|
||||
status = _cairo_stroke_style_init_copy (&hairline_style, style);
|
||||
if (unlikely (status))
|
||||
return status;
|
||||
|
||||
hairline_style.line_width = 1.0;
|
||||
|
||||
cairo_matrix_init_identity (&identity);
|
||||
|
||||
status = _cairo_compositor_stroke_impl (compositor, surface,
|
||||
op, source, path,
|
||||
&hairline_style, &identity, &identity,
|
||||
tolerance, antialias, clip);
|
||||
|
||||
_cairo_stroke_style_fini (&hairline_style);
|
||||
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
cairo_int_status_t
|
||||
_cairo_compositor_fill (const cairo_compositor_t *compositor,
|
||||
cairo_surface_t *surface,
|
||||
|
|
|
|||
|
|
@ -403,6 +403,14 @@ _cairo_default_context_set_line_width (void *abstract_cr,
|
|||
return _cairo_gstate_set_line_width (cr->gstate, line_width);
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_default_context_set_hairline (void *abstract_cr, cairo_bool_t set_hairline)
|
||||
{
|
||||
cairo_default_context_t *cr = abstract_cr;
|
||||
|
||||
return _cairo_gstate_set_hairline (cr->gstate, set_hairline);
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_default_context_set_line_cap (void *abstract_cr,
|
||||
cairo_line_cap_t line_cap)
|
||||
|
|
@ -477,6 +485,14 @@ _cairo_default_context_get_line_width (void *abstract_cr)
|
|||
return _cairo_gstate_get_line_width (cr->gstate);
|
||||
}
|
||||
|
||||
static cairo_bool_t
|
||||
_cairo_default_context_get_hairline (void *abstract_cr)
|
||||
{
|
||||
cairo_default_context_t *cr = abstract_cr;
|
||||
|
||||
return _cairo_gstate_get_hairline (cr->gstate);
|
||||
}
|
||||
|
||||
static cairo_line_cap_t
|
||||
_cairo_default_context_get_line_cap (void *abstract_cr)
|
||||
{
|
||||
|
|
@ -1365,6 +1381,7 @@ static const cairo_backend_t _cairo_default_context_backend = {
|
|||
_cairo_default_context_set_line_cap,
|
||||
_cairo_default_context_set_line_join,
|
||||
_cairo_default_context_set_line_width,
|
||||
_cairo_default_context_set_hairline,
|
||||
_cairo_default_context_set_miter_limit,
|
||||
_cairo_default_context_set_opacity,
|
||||
_cairo_default_context_set_operator,
|
||||
|
|
@ -1375,6 +1392,7 @@ static const cairo_backend_t _cairo_default_context_backend = {
|
|||
_cairo_default_context_get_line_cap,
|
||||
_cairo_default_context_get_line_join,
|
||||
_cairo_default_context_get_line_width,
|
||||
_cairo_default_context_get_hairline,
|
||||
_cairo_default_context_get_miter_limit,
|
||||
_cairo_default_context_get_opacity,
|
||||
_cairo_default_context_get_operator,
|
||||
|
|
|
|||
|
|
@ -139,6 +139,12 @@ _cairo_gstate_set_line_width (cairo_gstate_t *gstate, double width);
|
|||
cairo_private double
|
||||
_cairo_gstate_get_line_width (cairo_gstate_t *gstate);
|
||||
|
||||
cairo_private cairo_status_t
|
||||
_cairo_gstate_set_hairline (cairo_gstate_t *gstate, cairo_bool_t set_hairline);
|
||||
|
||||
cairo_private cairo_bool_t
|
||||
_cairo_gstate_get_hairline (cairo_gstate_t *gstate);
|
||||
|
||||
cairo_private cairo_status_t
|
||||
_cairo_gstate_set_line_cap (cairo_gstate_t *gstate, cairo_line_cap_t line_cap);
|
||||
|
||||
|
|
|
|||
|
|
@ -470,7 +470,10 @@ _cairo_gstate_get_fill_rule (cairo_gstate_t *gstate)
|
|||
cairo_status_t
|
||||
_cairo_gstate_set_line_width (cairo_gstate_t *gstate, double width)
|
||||
{
|
||||
gstate->stroke_style.line_width = width;
|
||||
if (gstate->stroke_style.is_hairline)
|
||||
gstate->stroke_style.pre_hairline_line_width = width;
|
||||
else
|
||||
gstate->stroke_style.line_width = width;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
|
@ -481,6 +484,29 @@ _cairo_gstate_get_line_width (cairo_gstate_t *gstate)
|
|||
return gstate->stroke_style.line_width;
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_gstate_set_hairline (cairo_gstate_t *gstate, cairo_bool_t set_hairline)
|
||||
{
|
||||
if (gstate->stroke_style.is_hairline != set_hairline) {
|
||||
gstate->stroke_style.is_hairline = set_hairline;
|
||||
|
||||
if (set_hairline) {
|
||||
gstate->stroke_style.pre_hairline_line_width = gstate->stroke_style.line_width;
|
||||
gstate->stroke_style.line_width = 0.0;
|
||||
} else {
|
||||
gstate->stroke_style.line_width = gstate->stroke_style.pre_hairline_line_width;
|
||||
}
|
||||
}
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
cairo_bool_t
|
||||
_cairo_gstate_get_hairline (cairo_gstate_t *gstate)
|
||||
{
|
||||
return gstate->stroke_style.is_hairline;
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_gstate_set_line_cap (cairo_gstate_t *gstate, cairo_line_cap_t line_cap)
|
||||
{
|
||||
|
|
@ -1172,7 +1198,7 @@ _cairo_gstate_stroke (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
|
|||
if (gstate->op == CAIRO_OPERATOR_DEST)
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
|
||||
if (gstate->stroke_style.line_width <= 0.0)
|
||||
if (gstate->stroke_style.line_width <= 0.0 && !gstate->stroke_style.is_hairline)
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
|
||||
if (_cairo_clip_is_all_clipped (gstate->clip))
|
||||
|
|
|
|||
|
|
@ -708,6 +708,24 @@ _emit_line_width (cairo_script_surface_t *surface,
|
|||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
_emit_hairline (cairo_script_surface_t *surface, cairo_bool_t set_hairline)
|
||||
{
|
||||
assert (target_is_active (surface));
|
||||
|
||||
if (surface->cr.current_style.is_hairline == set_hairline)
|
||||
{
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
surface->cr.current_style.is_hairline = set_hairline;
|
||||
|
||||
_cairo_output_stream_printf (to_context (surface)->stream,
|
||||
"%d set-hairline\n",
|
||||
set_hairline);
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
_emit_line_cap (cairo_script_surface_t *surface,
|
||||
cairo_line_cap_t line_cap)
|
||||
|
|
@ -858,6 +876,10 @@ _emit_stroke_style (cairo_script_surface_t *surface,
|
|||
if (unlikely (status))
|
||||
return status;
|
||||
|
||||
status = _emit_hairline (surface, style->is_hairline);
|
||||
if (unlikely (status))
|
||||
return status;
|
||||
|
||||
status = _emit_dash (surface,
|
||||
style->dash, style->num_dashes, style->dash_offset,
|
||||
force);
|
||||
|
|
|
|||
|
|
@ -49,6 +49,8 @@ _cairo_stroke_style_init (cairo_stroke_style_t *style)
|
|||
style->dash = NULL;
|
||||
style->num_dashes = 0;
|
||||
style->dash_offset = 0.0;
|
||||
|
||||
style->is_hairline = FALSE;
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
|
|
@ -80,6 +82,8 @@ _cairo_stroke_style_init_copy (cairo_stroke_style_t *style,
|
|||
|
||||
style->dash_offset = other->dash_offset;
|
||||
|
||||
style->is_hairline = other->is_hairline;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2992,13 +2992,23 @@ _cairo_svg_surface_emit_stroke_style (cairo_svg_stream_t *output,
|
|||
ASSERT_NOT_REACHED;
|
||||
}
|
||||
|
||||
_cairo_svg_stream_printf (output,
|
||||
" stroke-width=\"%f\""
|
||||
" stroke-linecap=\"%s\""
|
||||
" stroke-linejoin=\"%s\"",
|
||||
stroke_style->line_width,
|
||||
line_cap,
|
||||
line_join);
|
||||
if (stroke_style->is_hairline) {
|
||||
_cairo_svg_stream_printf (output,
|
||||
" stroke-width=\"1px\""
|
||||
" stroke-linecap=\"%s\""
|
||||
" stroke-linejoin=\"%s\""
|
||||
" style=\"vector-effect: non-scaling-stroke\"",
|
||||
line_cap,
|
||||
line_join);
|
||||
} else {
|
||||
_cairo_svg_stream_printf (output,
|
||||
" stroke-width=\"%f\""
|
||||
" stroke-linecap=\"%s\""
|
||||
" stroke-linejoin=\"%s\"",
|
||||
stroke_style->line_width,
|
||||
line_cap,
|
||||
line_join);
|
||||
}
|
||||
|
||||
status = _cairo_svg_surface_emit_pattern (surface, source, output, TRUE, parent_matrix);
|
||||
if (unlikely (status)) {
|
||||
|
|
|
|||
|
|
@ -376,6 +376,8 @@ typedef struct _cairo_stroke_style {
|
|||
double *dash;
|
||||
unsigned int num_dashes;
|
||||
double dash_offset;
|
||||
cairo_bool_t is_hairline;
|
||||
double pre_hairline_line_width;
|
||||
} cairo_stroke_style_t;
|
||||
|
||||
typedef struct _cairo_format_masks {
|
||||
|
|
|
|||
61
src/cairo.c
|
|
@ -1184,6 +1184,47 @@ cairo_set_line_width (cairo_t *cr, double width)
|
|||
}
|
||||
slim_hidden_def (cairo_set_line_width);
|
||||
|
||||
/**
|
||||
* cairo_set_hairline:
|
||||
* @cr: a #cairo_t
|
||||
* @set_hairline: whether or not to set hairline mode
|
||||
*
|
||||
* Sets lines within the cairo context to be hairlines.
|
||||
* Hairlines are logically zero-width lines that are drawn at the
|
||||
* thinnest renderable width possible in the current context.
|
||||
*
|
||||
* On surfaces with native hairline support, the native hairline
|
||||
* functionality will be used. Surfaces that support hairlines include:
|
||||
* - pdf/ps: Encoded as 0-width line.
|
||||
* - win32_printing: Rendered with PS_COSMETIC pen.
|
||||
* - svg: Encoded as 1px non-scaling-stroke.
|
||||
* - script: Encoded with set-hairline function.
|
||||
*
|
||||
* Cairo will always render hairlines at 1 device unit wide, even if
|
||||
* an anisotropic scaling was applied to the stroke width. In the wild,
|
||||
* handling of this situation is not well-defined. Some PDF, PS, and SVG
|
||||
* renderers match Cairo's output, but some very popular implementations
|
||||
* (Acrobat, Chrome, rsvg) will scale the hairline unevenly.
|
||||
* As such, best practice is to reset any anisotropic scaling before calling
|
||||
* cairo_stroke(). See https://cairographics.org/cookbook/ellipses/
|
||||
* for an example.
|
||||
*
|
||||
* Since: 1.18
|
||||
**/
|
||||
void
|
||||
cairo_set_hairline (cairo_t *cr, cairo_bool_t set_hairline)
|
||||
{
|
||||
cairo_status_t status;
|
||||
|
||||
if (unlikely (cr->status))
|
||||
return;
|
||||
|
||||
status = cr->backend->set_hairline (cr, set_hairline);
|
||||
if (unlikely (status))
|
||||
_cairo_set_error (cr, status);
|
||||
}
|
||||
slim_hidden_def (cairo_set_hairline);
|
||||
|
||||
/**
|
||||
* cairo_set_line_cap:
|
||||
* @cr: a cairo context
|
||||
|
|
@ -4057,6 +4098,26 @@ cairo_get_line_width (cairo_t *cr)
|
|||
}
|
||||
slim_hidden_def (cairo_get_line_width);
|
||||
|
||||
/**
|
||||
* cairo_get_hairline:
|
||||
* @cr: a cairo context
|
||||
*
|
||||
* Returns whether or not hairline mode is set, as set by cairo_set_hairline().
|
||||
*
|
||||
* Return value: whether hairline mode is set.
|
||||
*
|
||||
* Since: 1.18
|
||||
**/
|
||||
cairo_bool_t
|
||||
cairo_get_hairline (cairo_t *cr)
|
||||
{
|
||||
if (unlikely (cr->status))
|
||||
return FALSE;
|
||||
|
||||
return cr->backend->get_hairline (cr);
|
||||
}
|
||||
slim_hidden_def (cairo_get_hairline);
|
||||
|
||||
/**
|
||||
* cairo_get_line_cap:
|
||||
* @cr: a cairo context
|
||||
|
|
|
|||
|
|
@ -765,6 +765,9 @@ cairo_set_fill_rule (cairo_t *cr, cairo_fill_rule_t fill_rule);
|
|||
cairo_public void
|
||||
cairo_set_line_width (cairo_t *cr, double width);
|
||||
|
||||
cairo_public void
|
||||
cairo_set_hairline (cairo_t *cr, cairo_bool_t set_hairline);
|
||||
|
||||
/**
|
||||
* cairo_line_cap_t:
|
||||
* @CAIRO_LINE_CAP_BUTT: start(stop) the line exactly at the start(end) point (Since 1.0)
|
||||
|
|
@ -1957,6 +1960,9 @@ cairo_get_fill_rule (cairo_t *cr);
|
|||
cairo_public double
|
||||
cairo_get_line_width (cairo_t *cr);
|
||||
|
||||
cairo_public cairo_bool_t
|
||||
cairo_get_hairline (cairo_t *cr);
|
||||
|
||||
cairo_public cairo_line_cap_t
|
||||
cairo_get_line_cap (cairo_t *cr);
|
||||
|
||||
|
|
|
|||
|
|
@ -1959,6 +1959,7 @@ slim_hidden_proto (cairo_font_options_status);
|
|||
slim_hidden_proto (cairo_format_stride_for_width);
|
||||
slim_hidden_proto (cairo_get_current_point);
|
||||
slim_hidden_proto (cairo_get_line_width);
|
||||
slim_hidden_proto (cairo_get_hairline);
|
||||
slim_hidden_proto (cairo_get_matrix);
|
||||
slim_hidden_proto (cairo_get_scaled_font);
|
||||
slim_hidden_proto (cairo_get_target);
|
||||
|
|
@ -2031,6 +2032,7 @@ slim_hidden_proto (cairo_set_font_size);
|
|||
slim_hidden_proto (cairo_set_line_cap);
|
||||
slim_hidden_proto (cairo_set_line_join);
|
||||
slim_hidden_proto (cairo_set_line_width);
|
||||
slim_hidden_proto (cairo_set_hairline);
|
||||
slim_hidden_proto (cairo_set_matrix);
|
||||
slim_hidden_proto (cairo_set_operator);
|
||||
slim_hidden_proto (cairo_set_source);
|
||||
|
|
|
|||
|
|
@ -1520,7 +1520,7 @@ _cairo_win32_printing_surface_stroke (void *abstract_surface,
|
|||
cairo_matrix_multiply (&mat, stroke_ctm, &surface->ctm);
|
||||
_cairo_matrix_factor_out_scale (&mat, &scale);
|
||||
|
||||
pen_style = PS_GEOMETRIC;
|
||||
pen_style = style->is_hairline ? PS_COSMETIC : PS_GEOMETRIC;
|
||||
dash_array = NULL;
|
||||
if (style->num_dashes) {
|
||||
pen_style |= PS_USERSTYLE;
|
||||
|
|
@ -1546,10 +1546,12 @@ _cairo_win32_printing_surface_stroke (void *abstract_surface,
|
|||
brush.lbStyle = BS_SOLID;
|
||||
brush.lbColor = color;
|
||||
brush.lbHatch = 0;
|
||||
pen_style |= _cairo_win32_line_cap (style->line_cap);
|
||||
pen_style |= _cairo_win32_line_join (style->line_join);
|
||||
if (!style->is_hairline) {
|
||||
pen_style |= _cairo_win32_line_cap (style->line_cap);
|
||||
pen_style |= _cairo_win32_line_join (style->line_join);
|
||||
}
|
||||
pen = ExtCreatePen(pen_style,
|
||||
scale * style->line_width,
|
||||
style->is_hairline ? 1 : scale * style->line_width,
|
||||
&brush,
|
||||
style->num_dashes,
|
||||
dash_array);
|
||||
|
|
|
|||
|
|
@ -162,6 +162,7 @@ test_sources = \
|
|||
group-paint.c \
|
||||
group-state.c \
|
||||
group-unaligned.c \
|
||||
hairline.c \
|
||||
half-coverage.c \
|
||||
halo.c \
|
||||
hatchings.c \
|
||||
|
|
|
|||
175
test/hairline.c
Normal file
|
|
@ -0,0 +1,175 @@
|
|||
#include "cairo-test.h"
|
||||
|
||||
/**
|
||||
* draw:
|
||||
* @cr: a #cairo_t
|
||||
* @width: Width of the test image
|
||||
* @height: Height of the test image
|
||||
* @scale_width: Percentage to scale the width
|
||||
* @scale_height: Percentage to scale the height
|
||||
* @fit_to_scale: Whether or not to adjust the image to fit in the scale parameters
|
||||
* regardless of the scale parameters
|
||||
* @correct_scale: Tests if the hairlines render correctly regardless of
|
||||
* whether or not the scale is set "correctly", as per
|
||||
* https://cairographics.org/cookbook/ellipses/
|
||||
*/
|
||||
static cairo_test_status_t
|
||||
draw (cairo_t *cr, int width, int height, double scale_width, double scale_height, cairo_bool_t fit_to_scale, cairo_bool_t correct_scale)
|
||||
{
|
||||
cairo_matrix_t save_matrix;
|
||||
double fit_width = fit_to_scale ? scale_width : 1.0;
|
||||
double fit_height = fit_to_scale ? scale_height : 1.0;
|
||||
double fit_max = MAX(fit_width, fit_height);
|
||||
double dash[] = {3.0};
|
||||
|
||||
if (cairo_get_hairline (cr) == TRUE) {
|
||||
return CAIRO_TEST_ERROR;
|
||||
}
|
||||
|
||||
/* Clear background */
|
||||
cairo_set_source_rgb (cr, 1, 1, 1);
|
||||
cairo_paint (cr);
|
||||
|
||||
cairo_set_source_rgb (cr, 0, 0, 0);
|
||||
cairo_set_line_width (cr, 100.0); /* If everything is working right, this value should never get used */
|
||||
|
||||
/* Hairline sample */
|
||||
if (correct_scale) {
|
||||
cairo_get_matrix (cr, &save_matrix);
|
||||
}
|
||||
cairo_scale (cr, scale_width, scale_height);
|
||||
|
||||
cairo_set_hairline (cr, TRUE);
|
||||
if (cairo_get_hairline (cr) == FALSE) {
|
||||
return CAIRO_TEST_ERROR;
|
||||
}
|
||||
|
||||
cairo_move_to (cr, 0, 0);
|
||||
cairo_line_to (cr, width/fit_width/2, height/fit_height/2);
|
||||
cairo_move_to (cr, width/fit_width/2, 0);
|
||||
cairo_line_to (cr, width/fit_width/2, height/fit_height/2);
|
||||
cairo_move_to (cr, 0, height/fit_height/2);
|
||||
cairo_line_to (cr, width/fit_width/2, height/fit_height/2);
|
||||
cairo_move_to (cr, width/fit_width/4, 0);
|
||||
cairo_line_to (cr, width/fit_width/2, height/fit_height/2);
|
||||
cairo_arc (cr, width/fit_width/2, height/fit_height/2, width/fit_max/4, M_PI*0.5, M_PI*1.0);
|
||||
|
||||
if (correct_scale) {
|
||||
cairo_set_matrix (cr, &save_matrix);
|
||||
}
|
||||
cairo_stroke (cr);
|
||||
|
||||
/* Dashed sample */
|
||||
if (correct_scale) {
|
||||
cairo_get_matrix (cr, &save_matrix);
|
||||
cairo_scale (cr, scale_width, scale_height);
|
||||
}
|
||||
cairo_set_dash (cr, dash, 1, 0);
|
||||
cairo_arc (cr, width/fit_width/2, height/fit_height/2, width/fit_max/4, M_PI*1.0, M_PI*1.5);
|
||||
if (correct_scale) {
|
||||
cairo_set_matrix (cr, &save_matrix);
|
||||
}
|
||||
cairo_stroke (cr);
|
||||
|
||||
/* Control sample */
|
||||
if (correct_scale) {
|
||||
cairo_get_matrix (cr, &save_matrix);
|
||||
cairo_scale (cr, scale_width, scale_height);
|
||||
}
|
||||
|
||||
cairo_set_line_width (cr, 3.0);
|
||||
cairo_set_hairline (cr, FALSE);
|
||||
if (cairo_get_hairline (cr) == TRUE) {
|
||||
return CAIRO_TEST_ERROR;
|
||||
}
|
||||
|
||||
cairo_set_dash (cr, 0, 0, 0);
|
||||
|
||||
cairo_move_to (cr, width/fit_width, height/fit_height);
|
||||
cairo_line_to (cr, width/fit_width/2, height/fit_height/2);
|
||||
cairo_move_to (cr, width/fit_width/2, height/fit_height);
|
||||
cairo_line_to (cr, width/fit_width/2, height/fit_height/2);
|
||||
cairo_move_to (cr, width/fit_width, height/fit_height/2);
|
||||
cairo_line_to (cr, width/fit_width/2, height/fit_height/2);
|
||||
cairo_move_to (cr, width/fit_width*0.75, height/fit_height);
|
||||
cairo_line_to (cr, width/fit_width/2, height/fit_height/2);
|
||||
cairo_arc (cr, width/fit_width/2, height/fit_height/2, width/fit_max/4, M_PI*1.5, M_PI*2.0);
|
||||
|
||||
if (correct_scale) {
|
||||
cairo_set_matrix (cr, &save_matrix);
|
||||
}
|
||||
cairo_stroke (cr);
|
||||
|
||||
/* Dashed sample */
|
||||
if (correct_scale) {
|
||||
cairo_get_matrix (cr, &save_matrix);
|
||||
cairo_scale (cr, scale_width, scale_height);
|
||||
}
|
||||
cairo_set_dash (cr, dash, 1, 0);
|
||||
cairo_arc (cr, width/fit_width/2, height/fit_height/2, width/fit_max/4, 0, M_PI*0.5);
|
||||
if (correct_scale) {
|
||||
cairo_set_matrix (cr, &save_matrix);
|
||||
}
|
||||
cairo_stroke (cr);
|
||||
|
||||
return CAIRO_TEST_SUCCESS;
|
||||
}
|
||||
|
||||
static cairo_test_status_t
|
||||
draw_typical (cairo_t *cr, int width, int height)
|
||||
{
|
||||
return draw (cr, width, height, 1.0, 1.0, TRUE, TRUE);
|
||||
}
|
||||
|
||||
static cairo_test_status_t
|
||||
draw_scaled (cairo_t *cr, int width, int height)
|
||||
{
|
||||
return draw (cr, width, height, 0.5, 0.5, FALSE, TRUE);
|
||||
}
|
||||
|
||||
static cairo_test_status_t
|
||||
draw_anisotropic (cairo_t *cr, int width, int height)
|
||||
{
|
||||
return draw (cr, width, height, 2.0, 5.0, TRUE, TRUE);
|
||||
}
|
||||
|
||||
static cairo_test_status_t
|
||||
draw_anisotropic_incorrect (cairo_t *cr, int width, int height)
|
||||
{
|
||||
return draw (cr, width, height, 2.0, 5.0, TRUE, FALSE);
|
||||
}
|
||||
|
||||
CAIRO_TEST (hairline,
|
||||
"Tests hairlines are drawn at a single pixel width",
|
||||
"path, stroke, hairline", /* keywords */
|
||||
NULL, /* requirements */
|
||||
49, 49,
|
||||
NULL, draw_typical)
|
||||
|
||||
CAIRO_TEST (hairline_big,
|
||||
"Tests hairlines are drawn at a single pixel width",
|
||||
"path, stroke, hairline", /* keywords */
|
||||
NULL, /* requirements */
|
||||
99, 99,
|
||||
NULL, draw_typical)
|
||||
|
||||
CAIRO_TEST (hairline_scaled,
|
||||
"Tests hairlines are drawn at a single pixel width",
|
||||
"path, stroke, hairline", /* keywords */
|
||||
NULL, /* requirements */
|
||||
99, 99,
|
||||
NULL, draw_scaled)
|
||||
|
||||
CAIRO_TEST (hairline_anisotropic,
|
||||
"Tests hairlines with a really lopsided scale parameter",
|
||||
"path, stroke, hairline", /* keywords */
|
||||
NULL, /* requirements */
|
||||
99, 99,
|
||||
NULL, draw_anisotropic)
|
||||
|
||||
CAIRO_TEST (hairline_anisotropic_incorrect,
|
||||
"Tests hairlines with a really lopsided scale parameter",
|
||||
"path, stroke, hairline", /* keywords */
|
||||
NULL, /* requirements */
|
||||
99, 99,
|
||||
NULL, draw_anisotropic_incorrect)
|
||||
|
|
@ -162,6 +162,7 @@ test_sources = [
|
|||
'group-paint.c',
|
||||
'group-state.c',
|
||||
'group-unaligned.c',
|
||||
'hairline.c',
|
||||
'half-coverage.c',
|
||||
'halo.c',
|
||||
'hatchings.c',
|
||||
|
|
|
|||
BIN
test/reference/hairline-anisotropic-incorrect.image16.ref.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
test/reference/hairline-anisotropic-incorrect.pdf.ref.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
test/reference/hairline-anisotropic-incorrect.quartz.ref.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
test/reference/hairline-anisotropic-incorrect.ref.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 2 KiB |
|
After Width: | Height: | Size: 2 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
BIN
test/reference/hairline-anisotropic-incorrect.xcb-window.ref.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
test/reference/hairline-anisotropic-incorrect.xcb.ref.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
BIN
test/reference/hairline-anisotropic-incorrect.xlib.ref.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
test/reference/hairline-anisotropic.image16.ref.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
test/reference/hairline-anisotropic.pdf.ref.png
Normal file
|
After Width: | Height: | Size: 2 KiB |
BIN
test/reference/hairline-anisotropic.quartz.ref.png
Normal file
|
After Width: | Height: | Size: 2 KiB |
BIN
test/reference/hairline-anisotropic.ref.png
Normal file
|
After Width: | Height: | Size: 2 KiB |
BIN
test/reference/hairline-anisotropic.xcb-window&.ref.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
test/reference/hairline-anisotropic.xcb-window.ref.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
test/reference/hairline-anisotropic.xcb.ref.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
test/reference/hairline-anisotropic.xlib-window.ref.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
test/reference/hairline-anisotropic.xlib.ref.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
test/reference/hairline-big.image16.ref.png
Normal file
|
After Width: | Height: | Size: 2 KiB |
BIN
test/reference/hairline-big.pdf.ref.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
test/reference/hairline-big.quartz.ref.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
test/reference/hairline-big.ref.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
test/reference/hairline-big.xcb-window&.ref.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
test/reference/hairline-big.xcb-window.ref.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
test/reference/hairline-big.xcb.ref.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
test/reference/hairline-big.xlib-window.ref.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
test/reference/hairline-big.xlib.ref.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
test/reference/hairline-scaled.image16.ref.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
test/reference/hairline-scaled.pdf.ref.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
test/reference/hairline-scaled.quartz.ref.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
test/reference/hairline-scaled.ref.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
test/reference/hairline-scaled.svg11.ref.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
test/reference/hairline-scaled.xcb-window&.ref.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
test/reference/hairline-scaled.xcb-window.ref.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
test/reference/hairline-scaled.xcb.ref.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
test/reference/hairline-scaled.xlib-window.ref.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
test/reference/hairline-scaled.xlib.ref.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
test/reference/hairline.image16.ref.png
Normal file
|
After Width: | Height: | Size: 884 B |
BIN
test/reference/hairline.pdf.ref.png
Normal file
|
After Width: | Height: | Size: 1,014 B |
BIN
test/reference/hairline.quartz.ref.png
Normal file
|
After Width: | Height: | Size: 968 B |
BIN
test/reference/hairline.ref.png
Normal file
|
After Width: | Height: | Size: 995 B |
BIN
test/reference/hairline.svg11.ref.png
Normal file
|
After Width: | Height: | Size: 988 B |
BIN
test/reference/hairline.xcb-window&.ref.png
Normal file
|
After Width: | Height: | Size: 950 B |
BIN
test/reference/hairline.xcb-window.ref.png
Normal file
|
After Width: | Height: | Size: 950 B |
BIN
test/reference/hairline.xcb.ref.png
Normal file
|
After Width: | Height: | Size: 950 B |
BIN
test/reference/hairline.xlib-window.ref.png
Normal file
|
After Width: | Height: | Size: 943 B |
BIN
test/reference/hairline.xlib.ref.png
Normal file
|
After Width: | Height: | Size: 943 B |
|
|
@ -5161,6 +5161,27 @@ _set_line_width (csi_t *ctx)
|
|||
return CSI_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static csi_status_t
|
||||
_set_hairline (csi_t *ctx)
|
||||
{
|
||||
csi_status_t status;
|
||||
cairo_t *cr;
|
||||
cairo_bool_t set_hairline = FALSE; /* silence the compiler */
|
||||
|
||||
check (2);
|
||||
|
||||
status = _csi_ostack_get_boolean (ctx, 0, &set_hairline);
|
||||
if (_csi_unlikely (status))
|
||||
return status;
|
||||
status = _csi_ostack_get_context (ctx, 1, &cr);
|
||||
if (_csi_unlikely (status))
|
||||
return status;
|
||||
|
||||
cairo_set_hairline (cr, set_hairline);
|
||||
pop (1);
|
||||
return CSI_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static csi_status_t
|
||||
_set_matrix (csi_t *ctx)
|
||||
{
|
||||
|
|
@ -6625,6 +6646,7 @@ _defs[] = {
|
|||
{ "set-line-cap", _set_line_cap },
|
||||
{ "set-line-join", _set_line_join },
|
||||
{ "set-line-width", _set_line_width },
|
||||
{ "set-hairline", _set_hairline },
|
||||
{ "set-matrix", _set_matrix },
|
||||
{ "set-miter-limit", _set_miter_limit },
|
||||
{ "set-mime-data", _set_mime_data },
|
||||
|
|
|
|||