summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/cairo-pdf-operators-private.h16
-rw-r--r--src/cairo-pdf-operators.c293
-rw-r--r--src/cairo-pdf-surface.c20
-rw-r--r--src/cairo-ps-surface.c15
4 files changed, 264 insertions, 80 deletions
diff --git a/src/cairo-pdf-operators-private.h b/src/cairo-pdf-operators-private.h
index e29834b09..b48233513 100644
--- a/src/cairo-pdf-operators-private.h
+++ b/src/cairo-pdf-operators-private.h
@@ -71,10 +71,12 @@ typedef struct _cairo_pdf_operators {
cairo_bool_t in_text_object; /* inside BT/ET pair */
/* PDF text state */
+ cairo_bool_t is_new_text_object; /* text object started but matrix and font not yet selected */
unsigned int font_id;
unsigned int subset_id;
cairo_matrix_t text_matrix; /* PDF text matrix (Tlm in the PDF reference) */
cairo_matrix_t cairo_to_pdftext; /* translate cairo coords to PDF text space */
+ cairo_matrix_t font_matrix_inverse;
double cur_x; /* Current position in PDF text space (Tm in the PDF reference) */
double cur_y;
int hex_width;
@@ -134,9 +136,15 @@ _cairo_pdf_operators_fill_stroke (cairo_pdf_operators_t *pdf_operators,
cairo_matrix_t *ctm_inverse);
cairo_private cairo_int_status_t
-_cairo_pdf_operators_show_glyphs (cairo_pdf_operators_t *pdf_operators,
- cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_scaled_font_t *scaled_font);
+_cairo_pdf_operators_show_text_glyphs (cairo_pdf_operators_t *pdf_operators,
+ const char *utf8,
+ int utf8_len,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ const cairo_text_cluster_t *clusters,
+ int num_clusters,
+ cairo_bool_t backward,
+ cairo_scaled_font_t *scaled_font);
+
#endif /* CAIRO_PDF_OPERATORS_H */
diff --git a/src/cairo-pdf-operators.c b/src/cairo-pdf-operators.c
index af8eafeb2..ad62cfa59 100644
--- a/src/cairo-pdf-operators.c
+++ b/src/cairo-pdf-operators.c
@@ -931,7 +931,6 @@ _cairo_pdf_operators_flush_glyphs (cairo_pdf_operators_t *pdf_operators)
static cairo_status_t
_cairo_pdf_operators_add_glyph (cairo_pdf_operators_t *pdf_operators,
cairo_scaled_font_subsets_glyph_t *glyph,
- cairo_matrix_t *font_matrix_inverse,
double x_position)
{
double x, y;
@@ -939,7 +938,7 @@ _cairo_pdf_operators_add_glyph (cairo_pdf_operators_t *pdf_operators
x = glyph->x_advance;
y = glyph->y_advance;
if (glyph->is_scaled)
- cairo_matrix_transform_distance (font_matrix_inverse, &x, &y);
+ cairo_matrix_transform_distance (&pdf_operators->font_matrix_inverse, &x, &y);
pdf_operators->glyphs[pdf_operators->num_glyphs].x_position = x_position;
pdf_operators->glyphs[pdf_operators->num_glyphs].glyph_index = glyph->subset_glyph_index;
@@ -1073,7 +1072,12 @@ _cairo_pdf_operators_begin_text (cairo_pdf_operators_t *pdf_operators)
static cairo_status_t
_cairo_pdf_operators_end_text (cairo_pdf_operators_t *pdf_operators)
{
- _cairo_pdf_operators_flush_glyphs (pdf_operators);
+ cairo_status_t status;
+
+ status = _cairo_pdf_operators_flush_glyphs (pdf_operators);
+ if (status)
+ return status;
+
_cairo_output_stream_printf (pdf_operators->stream, "ET\n");
pdf_operators->in_text_object = FALSE;
@@ -1092,35 +1096,215 @@ _cairo_matrix_scale_equal (cairo_matrix_t *a, cairo_matrix_t *b)
a->yy == b->yy);
}
-cairo_int_status_t
-_cairo_pdf_operators_show_glyphs (cairo_pdf_operators_t *pdf_operators,
- cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_scaled_font_t *scaled_font)
+static cairo_status_t
+_cairo_pdf_operators_begin_actualtext (cairo_pdf_operators_t *pdf_operators,
+ const char *utf8,
+ int utf8_len)
{
- cairo_scaled_font_subsets_glyph_t subset_glyph;
+ uint16_t *utf16;
+ int utf16_len;
cairo_status_t status;
int i;
- cairo_matrix_t text_matrix, invert_y_axis, font_matrix_inverse;
+
+ _cairo_output_stream_printf (pdf_operators->stream, "/Span << /ActualText <feff");
+ if (utf8_len) {
+ status = _cairo_utf8_to_utf16 (utf8, utf8_len, &utf16, &utf16_len);
+ if (status)
+ return status;
+
+ for (i = 0; i < utf16_len; i++) {
+ _cairo_output_stream_printf (pdf_operators->stream,
+ "%04x", (int) (utf16[i]));
+ }
+ free (utf16);
+ }
+ _cairo_output_stream_printf (pdf_operators->stream, "> >> BDC\n");
+
+ return _cairo_output_stream_get_status (pdf_operators->stream);
+}
+
+static cairo_status_t
+_cairo_pdf_operators_end_actualtext (cairo_pdf_operators_t *pdf_operators)
+{
+ _cairo_output_stream_printf (pdf_operators->stream, "EMC\n");
+
+ return _cairo_output_stream_get_status (pdf_operators->stream);
+}
+
+static cairo_status_t
+_cairo_pdf_operators_emit_glyph (cairo_pdf_operators_t *pdf_operators,
+ cairo_glyph_t *glyph,
+ cairo_scaled_font_subsets_glyph_t *subset_glyph)
+{
double x, y;
- cairo_bool_t new_text_object = FALSE;
+ cairo_status_t status;
- if (num_glyphs <= 0)
- return CAIRO_STATUS_SUCCESS;
+ if (pdf_operators->is_new_text_object ||
+ pdf_operators->font_id != subset_glyph->font_id ||
+ pdf_operators->subset_id != subset_glyph->subset_id)
+ {
+ status = _cairo_pdf_operators_flush_glyphs (pdf_operators);
+ if (status)
+ return status;
+
+ status = _cairo_pdf_operators_set_font_subset (pdf_operators, subset_glyph);
+ if (status)
+ return status;
+
+ pdf_operators->is_new_text_object = FALSE;
+ }
+
+ x = glyph->x;
+ y = glyph->y;
+ cairo_matrix_transform_point (&pdf_operators->cairo_to_pdftext, &x, &y);
+
+ /* The TJ operator for displaying text strings can only set
+ * the horizontal position of the glyphs. If the y position
+ * (in text space) changes, use the Td operator to change the
+ * current position to the next glyph. We also use the Td
+ * operator to move the current position if the horizontal
+ * position changes by more than 10 (in text space
+ * units). This is becauses the horizontal glyph positioning
+ * in the TJ operator is intended for kerning and there may be
+ * PDF consumers that do not handle very large position
+ * adjustments in TJ.
+ */
+ if (fabs(x - pdf_operators->cur_x) > 10 ||
+ fabs(y - pdf_operators->cur_y) > GLYPH_POSITION_TOLERANCE)
+ {
+ status = _cairo_pdf_operators_flush_glyphs (pdf_operators);
+ if (status)
+ return status;
+
+ x = glyph->x;
+ y = glyph->y;
+ cairo_matrix_transform_point (&pdf_operators->cairo_to_pdf, &x, &y);
+ status = _cairo_pdf_operators_set_text_position (pdf_operators, x, y);
+ if (status)
+ return status;
- font_matrix_inverse = scaled_font->font_matrix;
- status = cairo_matrix_invert (&font_matrix_inverse);
+ x = 0.0;
+ y = 0.0;
+ }
+
+ status = _cairo_pdf_operators_add_glyph (pdf_operators,
+ subset_glyph,
+ x);
+ return status;
+}
+
+/* A utf8_len of -1 indicates no unicode text. A utf8_len = 0 is an
+ * empty string.
+ */
+static cairo_int_status_t
+_cairo_pdf_operators_emit_cluster (cairo_pdf_operators_t *pdf_operators,
+ const char *utf8,
+ int utf8_len,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_bool_t backward,
+ cairo_scaled_font_t *scaled_font)
+{
+ cairo_scaled_font_subsets_glyph_t subset_glyph;
+ cairo_glyph_t *cur_glyph;
+ cairo_status_t status;
+ int i;
+
+ /* If the cluster maps 1 glyph to 1 or more unicode characters, we
+ * first try _map_glyph() with the unicode string to see if it can
+ * use toUnicode to map our glyph to the unicode. This will fail
+ * if the glyph is already mapped to a different unicode string.
+ *
+ * We also go through this path if no unicode mapping was
+ * supplied (utf8_len < 0).
+ *
+ * Mapping a glyph to a zero length unicode string requires the
+ * use of ActualText.
+ */
+ if (num_glyphs == 1 && utf8_len != 0) {
+ status = _cairo_scaled_font_subsets_map_glyph (pdf_operators->font_subsets,
+ scaled_font,
+ glyphs->index,
+ utf8,
+ utf8_len < 0 ? 0 : utf8_len,
+ &subset_glyph);
+ if (status)
+ return status;
+
+ if (subset_glyph.utf8_is_mapped || utf8_len < 0) {
+ status = _cairo_pdf_operators_emit_glyph (pdf_operators,
+ glyphs,
+ &subset_glyph);
+ return 0;
+ }
+ }
+
+ /* Fallback to using ActualText to map zero or more glyphs to a
+ * unicode string. */
+ _cairo_pdf_operators_flush_glyphs (pdf_operators);
+ status = _cairo_pdf_operators_begin_actualtext (pdf_operators, utf8, utf8_len);
+ cur_glyph = glyphs;
+ for (i = 0; i < num_glyphs; i++) {
+ status = _cairo_scaled_font_subsets_map_glyph (pdf_operators->font_subsets,
+ scaled_font,
+ cur_glyph->index,
+ NULL, 0,
+ &subset_glyph);
+ if (status)
+ return status;
+
+ status = _cairo_pdf_operators_emit_glyph (pdf_operators,
+ cur_glyph,
+ &subset_glyph);
+ if (status)
+ return status;
+
+ if (backward)
+ cur_glyph--;
+ else
+ cur_glyph++;
+ }
+ status = _cairo_pdf_operators_flush_glyphs (pdf_operators);
+ if (status)
+ return status;
+
+ status = _cairo_pdf_operators_end_actualtext (pdf_operators);
+
+ return status;
+}
+
+cairo_int_status_t
+_cairo_pdf_operators_show_text_glyphs (cairo_pdf_operators_t *pdf_operators,
+ const char *utf8,
+ int utf8_len,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ const cairo_text_cluster_t *clusters,
+ int num_clusters,
+ cairo_bool_t backward,
+ cairo_scaled_font_t *scaled_font)
+{
+ cairo_status_t status;
+ int i;
+ cairo_matrix_t text_matrix, invert_y_axis;
+ double x, y;
+ const char *cur_text;
+ cairo_glyph_t *cur_glyph;
+
+ pdf_operators->font_matrix_inverse = scaled_font->font_matrix;
+ status = cairo_matrix_invert (&pdf_operators->font_matrix_inverse);
if (status == CAIRO_STATUS_INVALID_MATRIX)
return CAIRO_STATUS_SUCCESS;
if (status)
return status;
+ pdf_operators->is_new_text_object = FALSE;
if (pdf_operators->in_text_object == FALSE) {
_cairo_pdf_operators_begin_text (pdf_operators);
/* Force Tm and Tf to be emitted when starting a new text
* object.*/
- new_text_object = TRUE;
+ pdf_operators->is_new_text_object = TRUE;
}
cairo_matrix_init_scale (&invert_y_axis, 1, -1);
@@ -1132,7 +1316,7 @@ _cairo_pdf_operators_show_glyphs (cairo_pdf_operators_t *pdf_operators,
/* Invert y axis in device space */
cairo_matrix_multiply (&text_matrix, &invert_y_axis, &text_matrix);
- if (new_text_object ||
+ if (pdf_operators->is_new_text_object ||
! _cairo_matrix_scale_equal (&pdf_operators->text_matrix, &text_matrix))
{
_cairo_pdf_operators_flush_glyphs (pdf_operators);
@@ -1148,55 +1332,36 @@ _cairo_pdf_operators_show_glyphs (cairo_pdf_operators_t *pdf_operators,
return status;
}
- for (i = 0; i < num_glyphs; i++) {
- status = _cairo_scaled_font_subsets_map_glyph (pdf_operators->font_subsets,
- scaled_font, glyphs[i].index,
- NULL, 0,
- &subset_glyph);
- if (status)
- return status;
-
- if (new_text_object ||
- pdf_operators->font_id != subset_glyph.font_id ||
- pdf_operators->subset_id != subset_glyph.subset_id)
- {
- _cairo_pdf_operators_flush_glyphs (pdf_operators);
- _cairo_pdf_operators_set_font_subset (pdf_operators, &subset_glyph);
- new_text_object = FALSE;
+ if (num_clusters > 0) {
+ cur_text = utf8;
+ if (backward)
+ cur_glyph = glyphs + num_glyphs - 1;
+ else
+ cur_glyph = glyphs;
+ for (i = 0; i < num_clusters; i++) {
+ status = _cairo_pdf_operators_emit_cluster (pdf_operators,
+ cur_text,
+ clusters[i].num_bytes,
+ cur_glyph,
+ clusters[i].num_glyphs,
+ backward,
+ scaled_font);
+ cur_text += clusters[i].num_bytes;
+ if (backward)
+ cur_glyph -= clusters[i].num_glyphs;
+ else
+ cur_glyph += clusters[i].num_glyphs;
}
-
- x = glyphs[i].x;
- y = glyphs[i].y;
- cairo_matrix_transform_point (&pdf_operators->cairo_to_pdftext, &x, &y);
-
- /* The TJ operator for displaying text strings can only set
- * the horizontal position of the glyphs. If the y position
- * (in text space) changes, use the Td operator to change the
- * current position to the next glyph. We also use the Td
- * operator to move the current position if the horizontal
- * position changes by more than 10 (in text space
- * units). This is becauses the horizontal glyph positioning
- * in the TJ operator is intended for kerning and there may be
- * PDF consumers that do not handle very large position
- * adjustments in TJ.
- */
- if (fabs(x - pdf_operators->cur_x) > 10 ||
- fabs(y - pdf_operators->cur_y) > GLYPH_POSITION_TOLERANCE)
- {
- _cairo_pdf_operators_flush_glyphs (pdf_operators);
-
- x = glyphs[i].x;
- y = glyphs[i].y;
- cairo_matrix_transform_point (&pdf_operators->cairo_to_pdf, &x, &y);
- _cairo_pdf_operators_set_text_position (pdf_operators, x, y);
- x = 0.0;
- y = 0.0;
+ } else {
+ for (i = 0; i < num_glyphs; i++) {
+ status = _cairo_pdf_operators_emit_cluster (pdf_operators,
+ NULL,
+ -1, /* no unicode string available */
+ &glyphs[i],
+ 1,
+ FALSE,
+ scaled_font);
}
-
- _cairo_pdf_operators_add_glyph (pdf_operators,
- &subset_glyph,
- &font_matrix_inverse,
- x);
}
return _cairo_output_stream_get_status (pdf_operators->stream);
diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index faef96436..87edbb105 100644
--- a/src/cairo-pdf-surface.c
+++ b/src/cairo-pdf-surface.c
@@ -3959,10 +3959,12 @@ _cairo_pdf_surface_write_smask_group (cairo_pdf_surface_t *surface,
&group->ctm_inverse);
break;
case PDF_SHOW_GLYPHS:
- status = _cairo_pdf_operators_show_glyphs (&surface->pdf_operators,
- group->glyphs,
- group->num_glyphs,
- group->scaled_font);
+ status = _cairo_pdf_operators_show_text_glyphs (&surface->pdf_operators,
+ NULL, 0,
+ group->glyphs, group->num_glyphs,
+ NULL, 0,
+ FALSE,
+ group->scaled_font);
break;
}
if (status)
@@ -4797,10 +4799,12 @@ _cairo_pdf_surface_show_glyphs (void *abstract_surface,
return status;
}
- status = _cairo_pdf_operators_show_glyphs (&surface->pdf_operators,
- glyphs,
- num_glyphs,
- scaled_font);
+ status = _cairo_pdf_operators_show_text_glyphs (&surface->pdf_operators,
+ NULL, 0,
+ glyphs, num_glyphs,
+ NULL, 0,
+ FALSE,
+ scaled_font);
if (status)
return status;
diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c
index a4266d2de..326124790 100644
--- a/src/cairo-ps-surface.c
+++ b/src/cairo-ps-surface.c
@@ -175,6 +175,11 @@ _cairo_ps_surface_emit_header (cairo_ps_surface_t *surface)
"/W* { eoclip } bind def\n"
"/BT { } bind def\n"
"/ET { } bind def\n"
+ "/pdfmark where { pop globaldict /?pdfmark /exec load put }\n"
+ " { globaldict begin /?pdfmark /pop load def /pdfmark\n"
+ " /cleartomark load def end } ifelse\n"
+ "/BDC { mark 3 1 roll /BDC pdfmark } bind def\n"
+ "/EMC { mark /EMC pdfmark } bind def\n"
"/Tj { show } bind def\n"
"/TJ {\n"
" {\n"
@@ -3091,10 +3096,12 @@ _cairo_ps_surface_show_glyphs (void *abstract_surface,
if (status)
return status;
- return _cairo_pdf_operators_show_glyphs (&surface->pdf_operators,
- glyphs,
- num_glyphs,
- scaled_font);
+ return _cairo_pdf_operators_show_text_glyphs (&surface->pdf_operators,
+ NULL, 0,
+ glyphs, num_glyphs,
+ NULL, 0,
+ FALSE,
+ scaled_font);
}
static void