diff options
Diffstat (limited to 'src/cairo-pdf-operators.c')
-rw-r--r-- | src/cairo-pdf-operators.c | 268 |
1 files changed, 175 insertions, 93 deletions
diff --git a/src/cairo-pdf-operators.c b/src/cairo-pdf-operators.c index 8d7a97d..0f2500e 100644 --- a/src/cairo-pdf-operators.c +++ b/src/cairo-pdf-operators.c @@ -163,54 +163,132 @@ _cairo_pdf_operators_reset (cairo_pdf_operators_t *pdf_operators) * exceed max_column. In particular, if a single word is larger than * max_column it will not be broken up. */ + +typedef enum _cairo_word_wrap_state { + WRAP_STATE_DELIMITER, + WRAP_STATE_WORD, + WRAP_STATE_STRING, + WRAP_STATE_HEXSTRING +} cairo_word_wrap_state_t; + + typedef struct _word_wrap_stream { cairo_output_stream_t base; cairo_output_stream_t *output; int max_column; int column; - cairo_bool_t last_write_was_space; - cairo_bool_t in_hexstring; - cairo_bool_t empty_hexstring; + cairo_word_wrap_state_t state; + cairo_bool_t in_escape; + int escape_digits; } word_wrap_stream_t; + + +/* Emit word bytes up to the next delimiter character */ static int -_count_word_up_to (const unsigned char *s, int length) +_word_wrap_stream_count_word_up_to (word_wrap_stream_t *stream, + const unsigned char *data, int length) { - int word = 0; + const unsigned char *s = data; + int count = 0; while (length--) { - if (! (_cairo_isspace (*s) || *s == '<')) { - s++; - word++; - } else { - return word; + if (_cairo_isspace (*s) || *s == '<' || *s == '(') { + stream->state = WRAP_STATE_DELIMITER; + break; } + + count++; + stream->column++; + s++; } - return word; + if (count) + _cairo_output_stream_write (stream->output, data, count); + + return count; } -/* Count up to either the end of the ASCII hexstring or the number +/* Emit hexstring bytes up to either the end of the ASCII hexstring or the number * of columns remaining. */ static int -_count_hexstring_up_to (const unsigned char *s, int length, int columns) +_word_wrap_stream_count_hexstring_up_to (word_wrap_stream_t *stream, + const unsigned char *data, int length) { - int word = 0; + const unsigned char *s = data; + int count = 0; + cairo_bool_t newline = FALSE; while (length--) { - if (*s++ != '>') - word++; - else - return word; + count++; + stream->column++; + if (*s == '>') { + stream->state = WRAP_STATE_DELIMITER; + break; + } + + if (stream->column > stream->max_column) { + newline = TRUE; + break; + } + s++; + } - columns--; - if (columns < 0 && word > 1) - return word; + if (count) + _cairo_output_stream_write (stream->output, data, count); + + if (newline) { + _cairo_output_stream_printf (stream->output, "\n"); + stream->column = 0; } - return word; + return count; +} + +/* Count up to either the end of the string or the number of columns + * remaining. + */ +static int +_word_wrap_stream_count_string_up_to (word_wrap_stream_t *stream, + const unsigned char *data, int length) +{ + const unsigned char *s = data; + int count = 0; + cairo_bool_t newline = FALSE; + + while (length--) { + count++; + stream->column++; + if (!stream->in_escape) { + if (*s == ')') { + stream->state = WRAP_STATE_DELIMITER; + break; + } + if (*s == '\\') { + stream->in_escape = TRUE; + stream->escape_digits = 0; + } else if (stream->column > stream->max_column) { + newline = TRUE; + break; + } + } else { + if (!_cairo_isdigit(*s) || ++stream->escape_digits == 3) + stream->in_escape = FALSE; + } + s++; + } + + if (count) + _cairo_output_stream_write (stream->output, data, count); + + if (newline) { + _cairo_output_stream_printf (stream->output, "\\\n"); + stream->column = 0; + } + + return count; } static cairo_status_t @@ -219,65 +297,43 @@ _word_wrap_stream_write (cairo_output_stream_t *base, unsigned int length) { word_wrap_stream_t *stream = (word_wrap_stream_t *) base; - cairo_bool_t newline; - int word; + int count; while (length) { - if (*data == '<') { - stream->in_hexstring = TRUE; - stream->empty_hexstring = TRUE; - stream->last_write_was_space = FALSE; - data++; - length--; - _cairo_output_stream_printf (stream->output, "<"); - stream->column++; - } else if (*data == '>') { - stream->in_hexstring = FALSE; - stream->last_write_was_space = FALSE; - data++; - length--; - _cairo_output_stream_printf (stream->output, ">"); + switch (stream->state) { + case WRAP_STATE_WORD: + count = _word_wrap_stream_count_word_up_to (stream, data, length); + break; + case WRAP_STATE_HEXSTRING: + count = _word_wrap_stream_count_hexstring_up_to (stream, data, length); + break; + case WRAP_STATE_STRING: + count = _word_wrap_stream_count_string_up_to (stream, data, length); + break; + case WRAP_STATE_DELIMITER: + count = 1; stream->column++; - } else if (_cairo_isspace (*data)) { - newline = (*data == '\n' || *data == '\r'); - if (! newline && stream->column >= stream->max_column) { + if (*data == '\n' || stream->column >= stream->max_column) { _cairo_output_stream_printf (stream->output, "\n"); stream->column = 0; + } else if (*data == '<') { + stream->state = WRAP_STATE_HEXSTRING; + } else if (*data == '(') { + stream->state = WRAP_STATE_STRING; + } else if (!_cairo_isspace (*data)) { + stream->state = WRAP_STATE_WORD; } - _cairo_output_stream_write (stream->output, data, 1); - data++; - length--; - if (newline) { - stream->column = 0; - } - else - stream->column++; - stream->last_write_was_space = TRUE; - } else { - if (stream->in_hexstring) { - word = _count_hexstring_up_to (data, length, - MAX (stream->max_column - stream->column, 0)); - } else { - word = _count_word_up_to (data, length); - } - /* Don't wrap if this word is a continuation of a non hex - * string word from a previous call to write. */ - if (stream->column + word >= stream->max_column) { - if (stream->last_write_was_space || - (stream->in_hexstring && !stream->empty_hexstring)) - { - _cairo_output_stream_printf (stream->output, "\n"); - stream->column = 0; - } - } - _cairo_output_stream_write (stream->output, data, word); - data += word; - length -= word; - stream->column += word; - stream->last_write_was_space = FALSE; - if (stream->in_hexstring) - stream->empty_hexstring = FALSE; + if (*data != '\n') + _cairo_output_stream_write (stream->output, data, 1); + break; + + default: + ASSERT_NOT_REACHED; + count = length; + break; } + data += count; + length -= count; } return _cairo_output_stream_get_status (stream->output); @@ -312,9 +368,9 @@ _word_wrap_stream_create (cairo_output_stream_t *output, int max_column) stream->output = output; stream->max_column = max_column; stream->column = 0; - stream->last_write_was_space = FALSE; - stream->in_hexstring = FALSE; - stream->empty_hexstring = TRUE; + stream->state = WRAP_STATE_DELIMITER; + stream->in_escape = FALSE; + stream->escape_digits = 0; return &stream->base; } @@ -458,7 +514,6 @@ _cairo_pdf_operators_emit_path (cairo_pdf_operators_t *pdf_operators, status = _cairo_pdf_path_rectangle (&info, &box); } else { status = _cairo_path_fixed_interpret (path, - CAIRO_DIRECTION_FORWARD, _cairo_pdf_path_move_to, _cairo_pdf_path_line_to, _cairo_pdf_path_curve_to, @@ -880,6 +935,26 @@ _cairo_pdf_operators_fill_stroke (cairo_pdf_operators_t *pdf_operators, operator); } +static void +_cairo_pdf_operators_emit_glyph_index (cairo_pdf_operators_t *pdf_operators, + cairo_output_stream_t *stream, + unsigned int glyph) +{ + if (pdf_operators->is_latin) { + if (glyph == '(' || glyph == ')' || glyph == '\\') + _cairo_output_stream_printf (stream, "\\%c", glyph); + else if (glyph >= 0x20 && glyph <= 0x7e) + _cairo_output_stream_printf (stream, "%c", glyph); + else + _cairo_output_stream_printf (stream, "\\%03o", glyph); + } else { + _cairo_output_stream_printf (stream, + "%0*x", + pdf_operators->hex_width, + glyph); + } +} + #define GLYPH_POSITION_TOLERANCE 0.001 /* Emit the string of glyphs using the 'Tj' operator. This requires @@ -890,15 +965,14 @@ _cairo_pdf_operators_emit_glyph_string (cairo_pdf_operators_t *pdf_operators, { int i; - _cairo_output_stream_printf (stream, "<"); + _cairo_output_stream_printf (stream, "%s", pdf_operators->is_latin ? "(" : "<"); for (i = 0; i < pdf_operators->num_glyphs; i++) { - _cairo_output_stream_printf (stream, - "%0*x", - pdf_operators->hex_width, - pdf_operators->glyphs[i].glyph_index); + _cairo_pdf_operators_emit_glyph_index (pdf_operators, + stream, + pdf_operators->glyphs[i].glyph_index); pdf_operators->cur_x += pdf_operators->glyphs[i].x_advance; } - _cairo_output_stream_printf (stream, ">Tj\n"); + _cairo_output_stream_printf (stream, "%sTj\n", pdf_operators->is_latin ? ")" : ">"); return _cairo_output_stream_get_status (stream); } @@ -918,7 +992,7 @@ _cairo_pdf_operators_emit_glyph_string_with_positioning ( { int i; - _cairo_output_stream_printf (stream, "[<"); + _cairo_output_stream_printf (stream, "[%s", pdf_operators->is_latin ? "(" : "<"); for (i = 0; i < pdf_operators->num_glyphs; i++) { if (pdf_operators->glyphs[i].x_position != pdf_operators->cur_x) { @@ -934,10 +1008,18 @@ _cairo_pdf_operators_emit_glyph_string_with_positioning ( * calculating subsequent deltas. */ rounded_delta = _cairo_lround (delta); + if (abs(rounded_delta) < 3) + rounded_delta = 0; if (rounded_delta != 0) { - _cairo_output_stream_printf (stream, - ">%d<", - rounded_delta); + if (pdf_operators->is_latin) { + _cairo_output_stream_printf (stream, + ")%d(", + rounded_delta); + } else { + _cairo_output_stream_printf (stream, + ">%d<", + rounded_delta); + } } /* Convert the rounded delta back to text @@ -947,13 +1029,12 @@ _cairo_pdf_operators_emit_glyph_string_with_positioning ( pdf_operators->cur_x += delta; } - _cairo_output_stream_printf (stream, - "%0*x", - pdf_operators->hex_width, - pdf_operators->glyphs[i].glyph_index); + _cairo_pdf_operators_emit_glyph_index (pdf_operators, + stream, + pdf_operators->glyphs[i].glyph_index); pdf_operators->cur_x += pdf_operators->glyphs[i].x_advance; } - _cairo_output_stream_printf (stream, ">]TJ\n"); + _cairo_output_stream_printf (stream, "%s]TJ\n", pdf_operators->is_latin ? ")" : ">"); return _cairo_output_stream_get_status (stream); } @@ -1128,6 +1209,7 @@ _cairo_pdf_operators_set_font_subset (cairo_pdf_operators_t *pdf_ope } pdf_operators->font_id = subset_glyph->font_id; pdf_operators->subset_id = subset_glyph->subset_id; + pdf_operators->is_latin = subset_glyph->is_latin; if (subset_glyph->is_composite) pdf_operators->hex_width = 4; |