mirror of
https://gitlab.freedesktop.org/cairo/cairo.git
synced 2026-05-06 03:28:09 +02:00
[gstate] Remove culled glyphs from clusters.
Sascha Steinbiss reported a bug where the PDF backend was reading beyond the end of the glyph array: http://lists.cairographics.org/archives/cairo/2008-December/015976.html. It transpires that in the early glyph culling in the gstate we were not updating the clusters to skip culled glyphs.
This commit is contained in:
parent
834f1d7b70
commit
095a1fd786
2 changed files with 182 additions and 48 deletions
|
|
@ -64,8 +64,12 @@ static cairo_status_t
|
|||
_cairo_gstate_transform_glyphs_to_backend (cairo_gstate_t *gstate,
|
||||
const cairo_glyph_t *glyphs,
|
||||
int num_glyphs,
|
||||
const cairo_text_cluster_t *clusters,
|
||||
int num_clusters,
|
||||
cairo_text_cluster_flags_t cluster_flags,
|
||||
cairo_glyph_t *transformed_glyphs,
|
||||
int *num_transformed_glyphs);
|
||||
int *num_transformed_glyphs,
|
||||
cairo_text_cluster_t *transformed_clusters);
|
||||
|
||||
cairo_status_t
|
||||
_cairo_gstate_init (cairo_gstate_t *gstate,
|
||||
|
|
@ -1594,11 +1598,13 @@ _cairo_gstate_show_text_glyphs (cairo_gstate_t *gstate,
|
|||
int num_clusters,
|
||||
cairo_text_cluster_flags_t cluster_flags)
|
||||
{
|
||||
cairo_status_t status;
|
||||
cairo_pattern_union_t source_pattern_stack;
|
||||
cairo_pattern_t *source_pattern;
|
||||
cairo_glyph_t *transformed_glyphs;
|
||||
cairo_glyph_t stack_transformed_glyphs[CAIRO_STACK_ARRAY_LENGTH (cairo_glyph_t)];
|
||||
cairo_glyph_t *transformed_glyphs;
|
||||
cairo_text_cluster_t stack_transformed_clusters[CAIRO_STACK_ARRAY_LENGTH (cairo_text_cluster_t)];
|
||||
cairo_text_cluster_t *transformed_clusters;
|
||||
cairo_status_t status;
|
||||
|
||||
if (gstate->source->status)
|
||||
return gstate->source->status;
|
||||
|
|
@ -1611,18 +1617,37 @@ _cairo_gstate_show_text_glyphs (cairo_gstate_t *gstate,
|
|||
if (unlikely (status))
|
||||
return status;
|
||||
|
||||
if (num_glyphs <= ARRAY_LENGTH (stack_transformed_glyphs)) {
|
||||
transformed_glyphs = stack_transformed_glyphs;
|
||||
} else {
|
||||
transformed_glyphs = stack_transformed_glyphs;
|
||||
transformed_clusters = stack_transformed_clusters;
|
||||
|
||||
if (num_glyphs > ARRAY_LENGTH (stack_transformed_glyphs)) {
|
||||
transformed_glyphs = cairo_glyph_allocate (num_glyphs);
|
||||
if (unlikely (transformed_glyphs == NULL))
|
||||
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
||||
if (unlikely (transformed_glyphs == NULL)) {
|
||||
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
||||
goto CLEANUP_GLYPHS;
|
||||
}
|
||||
}
|
||||
|
||||
/* Just in case */
|
||||
if (!clusters)
|
||||
num_clusters = 0;
|
||||
|
||||
if (num_clusters > ARRAY_LENGTH (stack_transformed_clusters)) {
|
||||
transformed_clusters = cairo_text_cluster_allocate (num_clusters);
|
||||
if (unlikely (transformed_clusters == NULL)) {
|
||||
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
||||
goto CLEANUP_GLYPHS;
|
||||
}
|
||||
}
|
||||
|
||||
status = _cairo_gstate_transform_glyphs_to_backend (gstate,
|
||||
glyphs, num_glyphs,
|
||||
clusters,
|
||||
num_clusters,
|
||||
cluster_flags,
|
||||
transformed_glyphs,
|
||||
&num_glyphs);
|
||||
&num_glyphs,
|
||||
transformed_clusters);
|
||||
|
||||
if (status || num_glyphs == 0)
|
||||
goto CLEANUP_GLYPHS;
|
||||
|
|
@ -1632,10 +1657,6 @@ _cairo_gstate_show_text_glyphs (cairo_gstate_t *gstate,
|
|||
if (unlikely (status))
|
||||
goto CLEANUP_GLYPHS;
|
||||
|
||||
/* Just in case */
|
||||
if (!clusters)
|
||||
num_clusters = 0;
|
||||
|
||||
/* For really huge font sizes, we can just do path;fill instead of
|
||||
* show_glyphs, as show_glyphs would put excess pressure on the cache,
|
||||
* and moreover, not all components below us correctly handle huge font
|
||||
|
|
@ -1653,7 +1674,7 @@ _cairo_gstate_show_text_glyphs (cairo_gstate_t *gstate,
|
|||
source_pattern,
|
||||
utf8, utf8_len,
|
||||
transformed_glyphs, num_glyphs,
|
||||
clusters, num_clusters,
|
||||
transformed_clusters, num_clusters,
|
||||
cluster_flags,
|
||||
gstate->scaled_font, NULL);
|
||||
} else {
|
||||
|
|
@ -1683,6 +1704,8 @@ _cairo_gstate_show_text_glyphs (cairo_gstate_t *gstate,
|
|||
CLEANUP_GLYPHS:
|
||||
if (transformed_glyphs != stack_transformed_glyphs)
|
||||
cairo_glyph_free (transformed_glyphs);
|
||||
if (transformed_clusters != stack_transformed_clusters)
|
||||
cairo_text_cluster_free (transformed_clusters);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
|
@ -1711,8 +1734,9 @@ _cairo_gstate_glyph_path (cairo_gstate_t *gstate,
|
|||
|
||||
status = _cairo_gstate_transform_glyphs_to_backend (gstate,
|
||||
glyphs, num_glyphs,
|
||||
NULL, 0, 0,
|
||||
transformed_glyphs,
|
||||
NULL);
|
||||
NULL, NULL);
|
||||
if (unlikely (status))
|
||||
goto CLEANUP_GLYPHS;
|
||||
|
||||
|
|
@ -1761,13 +1785,17 @@ _cairo_gstate_get_antialias (cairo_gstate_t *gstate)
|
|||
* cull/drop glyphs that will not be visible.
|
||||
**/
|
||||
static cairo_status_t
|
||||
_cairo_gstate_transform_glyphs_to_backend (cairo_gstate_t *gstate,
|
||||
const cairo_glyph_t *glyphs,
|
||||
int num_glyphs,
|
||||
cairo_glyph_t *transformed_glyphs,
|
||||
int *num_transformed_glyphs)
|
||||
_cairo_gstate_transform_glyphs_to_backend (cairo_gstate_t *gstate,
|
||||
const cairo_glyph_t *glyphs,
|
||||
int num_glyphs,
|
||||
const cairo_text_cluster_t *clusters,
|
||||
int num_clusters,
|
||||
cairo_text_cluster_flags_t cluster_flags,
|
||||
cairo_glyph_t *transformed_glyphs,
|
||||
int *num_transformed_glyphs,
|
||||
cairo_text_cluster_t *transformed_clusters)
|
||||
{
|
||||
int i, j;
|
||||
int i, j, k;
|
||||
cairo_matrix_t *ctm = &gstate->ctm;
|
||||
cairo_matrix_t *font_matrix = &gstate->font_matrix;
|
||||
cairo_matrix_t *device_transform = &gstate->target->device_transform;
|
||||
|
|
@ -1813,22 +1841,52 @@ _cairo_gstate_transform_glyphs_to_backend (cairo_gstate_t *gstate,
|
|||
|
||||
#define KEEP_GLYPH(glyph) (x1 <= glyph.x && glyph.x <= x2 && y1 <= glyph.y && glyph.y <= y2)
|
||||
|
||||
j = 0;
|
||||
if (_cairo_matrix_is_identity (ctm) &&
|
||||
_cairo_matrix_is_identity (device_transform) &&
|
||||
font_matrix->x0 == 0 && font_matrix->y0 == 0)
|
||||
{
|
||||
if (!drop)
|
||||
memcpy (transformed_glyphs, glyphs, num_glyphs * sizeof (cairo_glyph_t));
|
||||
else {
|
||||
for (j = 0, i = 0; i < num_glyphs; i++)
|
||||
{
|
||||
if (! drop) {
|
||||
memcpy (transformed_glyphs, glyphs,
|
||||
num_glyphs * sizeof (cairo_glyph_t));
|
||||
} else if (num_clusters == 0) {
|
||||
for (i = 0; i < num_glyphs; i++) {
|
||||
transformed_glyphs[j].index = glyphs[i].index;
|
||||
transformed_glyphs[j].x = glyphs[i].x;
|
||||
transformed_glyphs[j].y = glyphs[i].y;
|
||||
if (KEEP_GLYPH (transformed_glyphs[j]))
|
||||
j++;
|
||||
}
|
||||
*num_transformed_glyphs = j;
|
||||
} else {
|
||||
const cairo_glyph_t *cur_glyph;
|
||||
|
||||
if (cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD)
|
||||
cur_glyph = glyphs + num_glyphs - 1;
|
||||
else
|
||||
cur_glyph = glyphs;
|
||||
|
||||
for (i = 0; i < num_clusters; i++) {
|
||||
cairo_bool_t cluster_visible = FALSE;
|
||||
|
||||
for (k = 0; k < clusters[i].num_glyphs; k++) {
|
||||
transformed_glyphs[j+k].index = cur_glyph->index;
|
||||
transformed_glyphs[j+k].x = cur_glyph->x;
|
||||
transformed_glyphs[j+k].y = cur_glyph->y;
|
||||
if (KEEP_GLYPH (transformed_glyphs[j+k]))
|
||||
cluster_visible = TRUE;
|
||||
|
||||
if (cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD)
|
||||
cur_glyph--;
|
||||
else
|
||||
cur_glyph++;
|
||||
}
|
||||
|
||||
transformed_clusters[i] = clusters[i];
|
||||
if (cluster_visible)
|
||||
j += k;
|
||||
else
|
||||
transformed_clusters[i].num_glyphs = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (_cairo_matrix_is_translation (ctm) &&
|
||||
|
|
@ -1837,15 +1895,45 @@ _cairo_gstate_transform_glyphs_to_backend (cairo_gstate_t *gstate,
|
|||
double tx = font_matrix->x0 + ctm->x0 + device_transform->x0;
|
||||
double ty = font_matrix->y0 + ctm->y0 + device_transform->y0;
|
||||
|
||||
for (j = 0, i = 0; i < num_glyphs; i++)
|
||||
{
|
||||
transformed_glyphs[j].index = glyphs[i].index;
|
||||
transformed_glyphs[j].x = glyphs[i].x + tx;
|
||||
transformed_glyphs[j].y = glyphs[i].y + ty;
|
||||
if (!drop || KEEP_GLYPH (transformed_glyphs[j]))
|
||||
j++;
|
||||
}
|
||||
*num_transformed_glyphs = j;
|
||||
if (! drop || num_clusters == 0) {
|
||||
for (i = 0; i < num_glyphs; i++) {
|
||||
transformed_glyphs[j].index = glyphs[i].index;
|
||||
transformed_glyphs[j].x = glyphs[i].x + tx;
|
||||
transformed_glyphs[j].y = glyphs[i].y + ty;
|
||||
if (!drop || KEEP_GLYPH (transformed_glyphs[j]))
|
||||
j++;
|
||||
}
|
||||
} else {
|
||||
const cairo_glyph_t *cur_glyph;
|
||||
|
||||
if (cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD)
|
||||
cur_glyph = glyphs + num_glyphs - 1;
|
||||
else
|
||||
cur_glyph = glyphs;
|
||||
|
||||
for (i = 0; i < num_clusters; i++) {
|
||||
cairo_bool_t cluster_visible = FALSE;
|
||||
|
||||
for (k = 0; k < clusters[i].num_glyphs; k++) {
|
||||
transformed_glyphs[j+k].index = cur_glyph->index;
|
||||
transformed_glyphs[j+k].x = cur_glyph->x + tx;
|
||||
transformed_glyphs[j+k].y = cur_glyph->y + ty;
|
||||
if (KEEP_GLYPH (transformed_glyphs[j+k]))
|
||||
cluster_visible = TRUE;
|
||||
|
||||
if (cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD)
|
||||
cur_glyph--;
|
||||
else
|
||||
cur_glyph++;
|
||||
}
|
||||
|
||||
transformed_clusters[i] = clusters[i];
|
||||
if (cluster_visible)
|
||||
j += k;
|
||||
else
|
||||
transformed_clusters[i].num_glyphs = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -1859,16 +1947,57 @@ _cairo_gstate_transform_glyphs_to_backend (cairo_gstate_t *gstate,
|
|||
cairo_matrix_multiply (&aggregate_transform,
|
||||
&aggregate_transform, device_transform);
|
||||
|
||||
for (j = 0, i = 0; i < num_glyphs; i++)
|
||||
{
|
||||
transformed_glyphs[j] = glyphs[i];
|
||||
cairo_matrix_transform_point (&aggregate_transform,
|
||||
&transformed_glyphs[j].x,
|
||||
&transformed_glyphs[j].y);
|
||||
if (!drop || KEEP_GLYPH (transformed_glyphs[j]))
|
||||
j++;
|
||||
}
|
||||
*num_transformed_glyphs = j;
|
||||
if (! drop || num_clusters == 0) {
|
||||
for (i = 0; i < num_glyphs; i++) {
|
||||
transformed_glyphs[j] = glyphs[i];
|
||||
cairo_matrix_transform_point (&aggregate_transform,
|
||||
&transformed_glyphs[j].x,
|
||||
&transformed_glyphs[j].y);
|
||||
if (! drop || KEEP_GLYPH (transformed_glyphs[j]))
|
||||
j++;
|
||||
}
|
||||
} else {
|
||||
const cairo_glyph_t *cur_glyph;
|
||||
|
||||
if (cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD)
|
||||
cur_glyph = glyphs + num_glyphs - 1;
|
||||
else
|
||||
cur_glyph = glyphs;
|
||||
|
||||
for (i = 0; i < num_clusters; i++) {
|
||||
cairo_bool_t cluster_visible = FALSE;
|
||||
for (k = 0; k < clusters[i].num_glyphs; k++) {
|
||||
transformed_glyphs[j+k] = *cur_glyph;
|
||||
cairo_matrix_transform_point (&aggregate_transform,
|
||||
&transformed_glyphs[j+k].x,
|
||||
&transformed_glyphs[j+k].y);
|
||||
if (KEEP_GLYPH (transformed_glyphs[j+k]))
|
||||
cluster_visible = TRUE;
|
||||
|
||||
if (cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD)
|
||||
cur_glyph--;
|
||||
else
|
||||
cur_glyph++;
|
||||
}
|
||||
|
||||
transformed_clusters[i] = clusters[i];
|
||||
if (cluster_visible)
|
||||
j += k;
|
||||
else
|
||||
transformed_clusters[i].num_glyphs = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
*num_transformed_glyphs = j;
|
||||
|
||||
if (num_clusters != 0 && cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD) {
|
||||
for (i = 0; i < --j; i++) {
|
||||
cairo_glyph_t tmp;
|
||||
|
||||
tmp = transformed_glyphs[i];
|
||||
transformed_glyphs[i] = transformed_glyphs[j];
|
||||
transformed_glyphs[j] = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
|
|
|
|||
|
|
@ -3104,8 +3104,13 @@ cairo_show_text (cairo_t *cr, const char *utf8)
|
|||
glyphs = stack_glyphs;
|
||||
num_glyphs = ARRAY_LENGTH (stack_glyphs);
|
||||
|
||||
clusters = stack_clusters;
|
||||
num_clusters = ARRAY_LENGTH (stack_clusters);
|
||||
if (has_show_text_glyphs) {
|
||||
clusters = stack_clusters;
|
||||
num_clusters = ARRAY_LENGTH (stack_clusters);
|
||||
} else {
|
||||
clusters = NULL;
|
||||
num_clusters = 0;
|
||||
}
|
||||
|
||||
status = _cairo_gstate_text_to_glyphs (cr->gstate,
|
||||
x, y,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue