/* Finish writing out any pending commands to the stream. This * function must be called by the surface before emitting anything * into the PDF stream. * * pdf_operators may leave the emitted PDF for some operations * unfinished in case subsequent operations can be merged. This * function will finish off any incomplete operation so the stream * will be in a state where the surface may emit its own PDF * operations (eg changing patterns). * */ cairo_status_t _cairo_pdf_operators_flush (cairo_pdf_operators_t *pdf_operators) { cairo_status_t status = CAIRO_STATUS_SUCCESS; if (pdf_operators->in_text_object) status = _cairo_pdf_operators_end_text (pdf_operators); return status; }
cairo_int_status_t _cairo_pdf_operators_tag_end (cairo_pdf_operators_t *pdf_operators) { cairo_status_t status; if (pdf_operators->in_text_object) { status = _cairo_pdf_operators_end_text (pdf_operators); if (unlikely (status)) return status; } _cairo_output_stream_printf (pdf_operators->stream, "EMC\n"); return _cairo_output_stream_get_status (pdf_operators->stream); }
cairo_int_status_t _cairo_pdf_operators_clip (cairo_pdf_operators_t *pdf_operators, const cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule) { const char *pdf_operator; cairo_status_t status; if (pdf_operators->in_text_object) { status = _cairo_pdf_operators_end_text (pdf_operators); if (unlikely (status)) return status; } if (! path->has_current_point) { /* construct an empty path */ _cairo_output_stream_printf (pdf_operators->stream, "0 0 m "); } else { status = _cairo_pdf_operators_emit_path (pdf_operators, path, &pdf_operators->cairo_to_pdf, CAIRO_LINE_CAP_ROUND); if (unlikely (status)) return status; } switch (fill_rule) { default: ASSERT_NOT_REACHED; case CAIRO_FILL_RULE_WINDING: pdf_operator = "W"; break; case CAIRO_FILL_RULE_EVEN_ODD: pdf_operator = "W*"; break; } _cairo_output_stream_printf (pdf_operators->stream, "%s n\n", pdf_operator); return _cairo_output_stream_get_status (pdf_operators->stream); }
cairo_int_status_t _cairo_pdf_operators_tag_begin (cairo_pdf_operators_t *pdf_operators, const char *tag_name, int mcid) { cairo_status_t status; if (pdf_operators->in_text_object) { status = _cairo_pdf_operators_end_text (pdf_operators); if (unlikely (status)) return status; } _cairo_output_stream_printf (pdf_operators->stream, "/%s << /MCID %d >> BDC\n", tag_name, mcid); return _cairo_output_stream_get_status (pdf_operators->stream); }
cairo_int_status_t _cairo_pdf_operators_fill (cairo_pdf_operators_t *pdf_operators, const cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule) { const char *pdf_operator; cairo_status_t status; if (pdf_operators->in_text_object) { status = _cairo_pdf_operators_end_text (pdf_operators); if (unlikely (status)) return status; } status = _cairo_pdf_operators_emit_path (pdf_operators, path, &pdf_operators->cairo_to_pdf, CAIRO_LINE_CAP_ROUND); if (unlikely (status)) return status; switch (fill_rule) { default: ASSERT_NOT_REACHED; case CAIRO_FILL_RULE_WINDING: pdf_operator = "f"; break; case CAIRO_FILL_RULE_EVEN_ODD: pdf_operator = "f*"; break; } _cairo_output_stream_printf (pdf_operators->stream, "%s\n", pdf_operator); return _cairo_output_stream_get_status (pdf_operators->stream); }
static cairo_int_status_t _cairo_pdf_operators_emit_stroke (cairo_pdf_operators_t *pdf_operators, const cairo_path_fixed_t *path, const cairo_stroke_style_t *style, const cairo_matrix_t *ctm, const cairo_matrix_t *ctm_inverse, const char *pdf_operator) { cairo_int_status_t status; cairo_matrix_t m, path_transform; cairo_bool_t has_ctm = TRUE; double scale = 1.0; if (pdf_operators->in_text_object) { status = _cairo_pdf_operators_end_text (pdf_operators); if (unlikely (status)) return status; } /* Optimize away the stroke ctm when it does not affect the * stroke. There are other ctm cases that could be optimized * however this is the most common. */ if (fabs(ctm->xx) == 1.0 && fabs(ctm->yy) == 1.0 && fabs(ctm->xy) == 0.0 && fabs(ctm->yx) == 0.0) { has_ctm = FALSE; } /* The PDF CTM is transformed to the user space CTM when stroking * so the corect pen shape will be used. This also requires that * the path be transformed to user space when emitted. The * conversion of path coordinates to user space may cause rounding * errors. For example the device space point (1.234, 3.142) when * transformed to a user space CTM of [100 0 0 100 0 0] will be * emitted as (0.012, 0.031). * * To avoid the rounding problem we scale the user space CTM * matrix so that all the non translation components of the matrix * are <= 1. The line width and and dashes are scaled by the * inverse of the scale applied to the CTM. This maintains the * shape of the stroke pen while keeping the user space CTM within * the range that maximizes the precision of the emitted path. */ if (has_ctm) { m = *ctm; /* Zero out the translation since it does not affect the pen * shape however it may cause unnecessary digits to be emitted. */ m.x0 = 0.0; m.y0 = 0.0; _cairo_matrix_factor_out_scale (&m, &scale); path_transform = m; status = cairo_matrix_invert (&path_transform); if (unlikely (status)) return status; cairo_matrix_multiply (&m, &m, &pdf_operators->cairo_to_pdf); } status = _cairo_pdf_operators_emit_stroke_style (pdf_operators, style, scale); if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) return CAIRO_STATUS_SUCCESS; if (unlikely (status)) return status; if (has_ctm) { _cairo_output_stream_printf (pdf_operators->stream, "q %f %f %f %f %f %f cm\n", m.xx, m.yx, m.xy, m.yy, m.x0, m.y0); } else { path_transform = pdf_operators->cairo_to_pdf; } status = _cairo_pdf_operators_emit_path (pdf_operators, path, &path_transform, style->line_cap); if (unlikely (status)) return status; _cairo_output_stream_printf (pdf_operators->stream, "%s", pdf_operator); if (has_ctm) _cairo_output_stream_printf (pdf_operators->stream, " Q"); _cairo_output_stream_printf (pdf_operators->stream, "\n"); return _cairo_output_stream_get_status (pdf_operators->stream); }