summaryrefslogtreecommitdiff
path: root/src/cairo-pdf-operators.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cairo-pdf-operators.c')
-rw-r--r--src/cairo-pdf-operators.c268
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;