diff options
author | Adrian Johnson <ajohnson@redneon.com> | 2010-10-08 20:29:06 +1030 |
---|---|---|
committer | Adrian Johnson <ajohnson@redneon.com> | 2010-10-08 23:17:27 +1030 |
commit | f96187e31ed68aef9f92f008bc3f36469ffdeef4 (patch) | |
tree | bb36d45cf4087e4dc96a5d36544e06cdfbb2cd6c /src/cairo-pdf-operators.c | |
parent | dd96c4accb546870b7bf7db4af10c2762de58d78 (diff) | |
download | cairo-f96187e31ed68aef9f92f008bc3f36469ffdeef4.tar.gz |
Rewrite pdf-operators word wrapping
to fix some bugs
Diffstat (limited to 'src/cairo-pdf-operators.c')
-rw-r--r-- | src/cairo-pdf-operators.c | 231 |
1 files changed, 113 insertions, 118 deletions
diff --git a/src/cairo-pdf-operators.c b/src/cairo-pdf-operators.c index 7613b41a7..ab206270e 100644 --- a/src/cairo-pdf-operators.c +++ b/src/cairo-pdf-operators.c @@ -163,83 +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_string; - cairo_bool_t in_hexstring; - cairo_bool_t empty_string; + 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 == '(')) { - 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; + } - columns--; - if (columns < 0 && word > 1) - return word; + if (stream->column > stream->max_column) { + newline = TRUE; + break; + } + s++; } - 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 count; } /* Count up to either the end of the string or the number of columns * remaining. */ static int -_count_string_up_to (const unsigned char *s, int length, int columns, cairo_bool_t *in_escape) +_word_wrap_stream_count_string_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 (*in_escape || *s != ')') { - word++; - if (!*in_escape && *s++ == '\\') - *in_escape = TRUE; - else - *in_escape = FALSE; + 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 { - return word; + if (!_cairo_isdigit(*s) || ++stream->escape_digits == 3) + stream->in_escape = FALSE; } + s++; + } + + if (count) + _cairo_output_stream_write (stream->output, data, count); - columns--; - if (columns < 0 && word > 0) - return word; + if (newline) { + _cairo_output_stream_printf (stream->output, "\\\n"); + stream->column = 0; } - return word; + return count; } static cairo_status_t @@ -248,91 +297,39 @@ _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_string = 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, ">"); - stream->column++; - } else if (*data == '(') { - stream->in_string = TRUE; - stream->in_escape = FALSE; - stream->empty_string = TRUE; - stream->last_write_was_space = FALSE; - data++; - length--; - _cairo_output_stream_printf (stream->output, "("); - stream->column++; - } else if (*data == ')') { - stream->in_string = 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++; - if (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; } - } else if (_cairo_isspace (*data) && !stream->in_string) { - newline = (*data == '\n' || *data == '\r'); - if (! newline && stream->column >= stream->max_column) { - _cairo_output_stream_printf (stream->output, "\n"); - stream->column = 0; - } - _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 if (stream->in_string) { - word = _count_string_up_to (data, length, - MAX (stream->max_column - stream->column, 0), &stream->in_escape); - } 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_string) || - (stream->in_string && !stream->empty_string && !stream->in_escape)) - { - if (stream->in_string) - _cairo_output_stream_printf (stream->output, "\\"); - _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->in_string) - stream->empty_string = FALSE; + if (*data != '\n') + _cairo_output_stream_write (stream->output, data, 1); + + break; } + data += count; + length -= count; } return _cairo_output_stream_get_status (stream->output); @@ -367,11 +364,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->in_string = FALSE; + stream->state = WRAP_STATE_DELIMITER; stream->in_escape = FALSE; - stream->empty_string = TRUE; + stream->escape_digits = 0; return &stream->base; } |