summaryrefslogtreecommitdiff
path: root/src/cairo-pdf-operators.c
diff options
context:
space:
mode:
authorAdrian Johnson <ajohnson@redneon.com>2010-10-08 20:29:06 +1030
committerAdrian Johnson <ajohnson@redneon.com>2010-10-08 23:17:27 +1030
commitf96187e31ed68aef9f92f008bc3f36469ffdeef4 (patch)
treebb36d45cf4087e4dc96a5d36544e06cdfbb2cd6c /src/cairo-pdf-operators.c
parentdd96c4accb546870b7bf7db4af10c2762de58d78 (diff)
downloadcairo-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.c231
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;
}