Skip to content

Commit

Permalink
win32-print: print as unicode where possible
Browse files Browse the repository at this point in the history
One of the problems identified in
https://bugzilla.mozilla.org/show_bug.cgi?id=454532 is that there are
some older printer drivers that do not work with ExtTextOut and the
ETO_GLYPH_INDEX option.

Fix this by where possible mapping glyph indices back to unicode and
calling ExtTextOut without ETO_GLYPH_INDEX. Glyphs that can not be
mapped back to unicode are printed with ETO_GLYPH_INDEX.
  • Loading branch information
Adrian Johnson committed Nov 16, 2010
1 parent eb29a25 commit d565639
Show file tree
Hide file tree
Showing 3 changed files with 141 additions and 81 deletions.
157 changes: 96 additions & 61 deletions src/cairo-win32-printing-surface.c
Original file line number Diff line number Diff line change
Expand Up @@ -1430,6 +1430,94 @@ _cairo_win32_printing_surface_fill (void *abstract_surface,
return status;
}

static cairo_int_status_t
_cairo_win32_printing_surface_emit_win32_glyphs (cairo_win32_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
cairo_clip_t *clip,
int *remaining_glyphs)
{
cairo_matrix_t ctm;
cairo_glyph_t *unicode_glyphs;
cairo_scaled_font_subsets_glyph_t subset_glyph;
int i, first;
cairo_bool_t sequence_is_unicode;
cairo_status_t status = CAIRO_STATUS_SUCCESS;

/* Where possible reverse the glyph indices back to unicode
* characters. Strings of glyphs that could not be reversed to
* unicode will be printed with ETO_GLYPH_INDEX.
*
* As _cairo_win32_scaled_font_index_to_ucs4() is a slow
* operation, the font subsetting function
* _cairo_scaled_font_subsets_map_glyph() is used to obtain
* the unicode value because it caches the reverse mapping in
* the subsets.
*/

if (surface->has_ctm) {
for (i = 0; i < num_glyphs; i++)
cairo_matrix_transform_point (&surface->ctm, &glyphs[i].x, &glyphs[i].y);
cairo_matrix_multiply (&ctm, &scaled_font->ctm, &surface->ctm);
scaled_font = cairo_scaled_font_create (scaled_font->font_face,
&scaled_font->font_matrix,
&ctm,
&scaled_font->options);
}

unicode_glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t));
if (unicode_glyphs == NULL)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);

memcpy (unicode_glyphs, glyphs, num_glyphs * sizeof (cairo_glyph_t));
for (i = 0; i < num_glyphs; i++) {
status = _cairo_scaled_font_subsets_map_glyph (surface->font_subsets,
scaled_font,
glyphs[i].index,
NULL, 0,
&subset_glyph);
if (status)
goto fail;

unicode_glyphs[i].index = subset_glyph.unicode;
}

i = 0;
first = 0;
sequence_is_unicode = unicode_glyphs[0].index <= 0xffff;
while (i < num_glyphs) {
if (i == num_glyphs - 1 ||
((unicode_glyphs[i + 1].index < 0xffff) != sequence_is_unicode))
{
status = _cairo_win32_surface_show_glyphs_internal (
surface,
op,
source,
sequence_is_unicode ? &unicode_glyphs[first] : &glyphs[first],
i - first + 1,
scaled_font,
clip,
remaining_glyphs,
! sequence_is_unicode);
first = i + 1;
if (i < num_glyphs - 1)
sequence_is_unicode = unicode_glyphs[i + 1].index <= 0xffff;
}
i++;
}

fail:
if (surface->has_ctm)
cairo_scaled_font_destroy (scaled_font);

free (unicode_glyphs);

return status;
}

static cairo_int_status_t
_cairo_win32_printing_surface_show_glyphs (void *abstract_surface,
cairo_operator_t op,
Expand Down Expand Up @@ -1514,67 +1602,14 @@ _cairo_win32_printing_surface_show_glyphs (void *abstract_surfac
if (cairo_scaled_font_get_type (scaled_font) == CAIRO_FONT_TYPE_WIN32 &&
source->type == CAIRO_PATTERN_TYPE_SOLID)
{
cairo_matrix_t ctm;
cairo_glyph_t *type1_glyphs = NULL;
cairo_scaled_font_subsets_glyph_t subset_glyph;

/* Calling ExtTextOutW() with ETO_GLYPH_INDEX and a Type 1
* font on a printer DC prints garbled text. The text displays
* correctly on a display DC. When using a printer
* DC, ExtTextOutW() only works with characters and not glyph
* indices.
*
* For Type 1 fonts the glyph indices are converted back to
* unicode characters before calling _cairo_win32_surface_show_glyphs().
*
* As _cairo_win32_scaled_font_index_to_ucs4() is a slow
* operation, the font subsetting function
* _cairo_scaled_font_subsets_map_glyph() is used to obtain
* the unicode value because it caches the reverse mapping in
* the subsets.
*/
if (_cairo_win32_scaled_font_is_type1 (scaled_font)) {
type1_glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t));
if (type1_glyphs == NULL)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);

memcpy (type1_glyphs, glyphs, num_glyphs * sizeof (cairo_glyph_t));
for (i = 0; i < num_glyphs; i++) {
status = _cairo_scaled_font_subsets_map_glyph (surface->font_subsets,
scaled_font,
type1_glyphs[i].index,
NULL, 0,
&subset_glyph);
if (status)
return status;

type1_glyphs[i].index = subset_glyph.unicode;
}
glyphs = type1_glyphs;
}

if (surface->has_ctm || surface->has_gdi_ctm) {
cairo_matrix_multiply (&ctm, &surface->ctm, &surface->gdi_ctm);
for (i = 0; i < num_glyphs; i++)
cairo_matrix_transform_point (&ctm, &glyphs[i].x, &glyphs[i].y);
cairo_matrix_multiply (&ctm, &scaled_font->ctm, &ctm);
scaled_font = cairo_scaled_font_create (scaled_font->font_face,
&scaled_font->font_matrix,
&ctm,
&scaled_font->options);
}
status = _cairo_win32_surface_show_glyphs (surface, op,
source, glyphs,
num_glyphs, scaled_font,
clip,
remaining_glyphs);
if (surface->has_ctm)
cairo_scaled_font_destroy (scaled_font);

if (type1_glyphs != NULL)
free (type1_glyphs);

return status;
return _cairo_win32_printing_surface_emit_win32_glyphs (surface,
op,
source,
glyphs,
num_glyphs,
scaled_font,
clip,
remaining_glyphs);
}
#endif

Expand Down
11 changes: 11 additions & 0 deletions src/cairo-win32-private.h
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,17 @@ cairo_status_t
_cairo_win32_surface_set_clip_region (void *abstract_surface,
cairo_region_t *region);

cairo_int_status_t
_cairo_win32_surface_show_glyphs_internal (void *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
cairo_clip_t *clip,
int *remaining_glyphs,
cairo_bool_t glyph_indices);

cairo_int_status_t
_cairo_win32_surface_show_glyphs (void *surface,
cairo_operator_t op,
Expand Down
54 changes: 34 additions & 20 deletions src/cairo-win32-surface.c
Original file line number Diff line number Diff line change
Expand Up @@ -1494,14 +1494,15 @@ _cairo_win32_surface_flush (void *abstract_surface)
#define STACK_GLYPH_SIZE 256

cairo_int_status_t
_cairo_win32_surface_show_glyphs (void *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
cairo_clip_t *clip,
int *remaining_glyphs)
_cairo_win32_surface_show_glyphs_internal (void *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
cairo_clip_t *clip,
int *remaining_glyphs,
cairo_bool_t glyph_indexing)
{
#if CAIRO_HAS_WIN32_FONT
cairo_win32_surface_t *dst = surface;
Expand Down Expand Up @@ -1616,19 +1617,10 @@ _cairo_win32_surface_show_glyphs (void *surface,
}
}

/* Using glyph indices for a Type 1 font does not work on a
* printer DC. The win32 printing surface will convert the the
* glyph indices of Type 1 fonts to the unicode values.
*/
if ((dst->flags & CAIRO_WIN32_SURFACE_FOR_PRINTING) &&
_cairo_win32_scaled_font_is_type1 (scaled_font))
{
glyph_index_option = 0;
}
else
{
if (glyph_indexing)
glyph_index_option = ETO_GLYPH_INDEX;
}
else
glyph_index_option = 0;

win_result = ExtTextOutW(dst->dc,
start_x,
Expand Down Expand Up @@ -1656,6 +1648,28 @@ _cairo_win32_surface_show_glyphs (void *surface,

#undef STACK_GLYPH_SIZE

cairo_int_status_t
_cairo_win32_surface_show_glyphs (void *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
cairo_clip_t *clip,
int *remaining_glyphs)
{
return _cairo_win32_surface_show_glyphs_internal (surface,
op,
source,
glyphs,
num_glyphs,
scaled_font,
clip,
remaining_glyphs,
TRUE);
}


/**
* cairo_win32_surface_create:
* @hdc: the DC to create a surface for
Expand Down

0 comments on commit d565639

Please sign in to comment.