cairo_status_t _cairo_pen_init_copy (cairo_pen_t *pen, cairo_pen_t *other) { *pen = *other; if (pen->num_vertices) { pen->vertices = _cairo_malloc_ab (pen->num_vertices, sizeof (cairo_pen_vertex_t)); if (pen->vertices == NULL) { return CAIRO_STATUS_NO_MEMORY; } memcpy (pen->vertices, other->vertices, pen->num_vertices * sizeof (cairo_pen_vertex_t)); } return CAIRO_STATUS_SUCCESS; }
static cairo_int_status_t _cairo_image_surface_fill_rectangles (void *abstract_surface, cairo_operator_t op, const cairo_color_t *color, cairo_rectangle_int_t *rects, int num_rects) { cairo_image_surface_t *surface = abstract_surface; pixman_color_t pixman_color; pixman_rectangle16_t stack_rects[CAIRO_STACK_ARRAY_LENGTH (pixman_rectangle16_t)]; pixman_rectangle16_t *pixman_rects = stack_rects; int i; cairo_int_status_t status = CAIRO_STATUS_SUCCESS; pixman_color.red = color->red_short; pixman_color.green = color->green_short; pixman_color.blue = color->blue_short; pixman_color.alpha = color->alpha_short; if (num_rects > ARRAY_LENGTH (stack_rects)) { pixman_rects = _cairo_malloc_ab (num_rects, sizeof (pixman_rectangle16_t)); if (pixman_rects == NULL) return _cairo_error (CAIRO_STATUS_NO_MEMORY); } for (i = 0; i < num_rects; i++) { pixman_rects[i].x = rects[i].x; pixman_rects[i].y = rects[i].y; pixman_rects[i].width = rects[i].width; pixman_rects[i].height = rects[i].height; } /* XXX: pixman_fill_rectangles() should be implemented */ if (! pixman_image_fill_rectangles (_pixman_operator (op), surface->pixman_image, &pixman_color, num_rects, pixman_rects)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); } if (pixman_rects != stack_rects) free (pixman_rects); return status; }
static cairo_path_t * _cairo_path_create_internal (cairo_path_fixed_t *path_fixed, cairo_gstate_t *gstate, cairo_bool_t flatten) { cairo_path_t *path; //+EAWebKitChange //11/10/2011 path = cairo_malloc (sizeof (cairo_path_t)); //-EAWebKitChange if (path == NULL) { _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); return (cairo_path_t*) &_cairo_path_nil; } path->num_data = _cairo_path_count (path, path_fixed, _cairo_gstate_get_tolerance (gstate), flatten); if (path->num_data < 0) { //+EAWebKitChange //11/10/2011 cairo_free (path); //-EAWebKitChange return (cairo_path_t*) &_cairo_path_nil; } if (path->num_data) { path->data = _cairo_malloc_ab (path->num_data, sizeof (cairo_path_data_t)); if (path->data == NULL) { //+EAWebKitChange //11/10/2011 cairo_free (path); //-EAWebKitChange _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); return (cairo_path_t*) &_cairo_path_nil; } path->status = _cairo_path_populate (path, path_fixed, gstate, flatten); } else { path->data = NULL; path->status = CAIRO_STATUS_SUCCESS; } return path; }
cairo_status_t _cairo_polygon_init_boxes (cairo_polygon_t *polygon, const cairo_boxes_t *boxes) { const struct _cairo_boxes_chunk *chunk; int i; VG (VALGRIND_MAKE_MEM_UNDEFINED (polygon, sizeof (cairo_polygon_t))); polygon->status = CAIRO_STATUS_SUCCESS; polygon->num_edges = 0; polygon->edges = polygon->edges_embedded; polygon->edges_size = ARRAY_LENGTH (polygon->edges_embedded); if (boxes->num_boxes > ARRAY_LENGTH (polygon->edges_embedded)/2) { polygon->edges_size = 2 * boxes->num_boxes; polygon->edges = _cairo_malloc_ab (polygon->edges_size, 2*sizeof(cairo_edge_t)); if (unlikely (polygon->edges == XNULL)) return polygon->status = _cairo_error (CAIRO_STATUS_NO_MEMORY); } polygon->extents.p1.x = polygon->extents.p1.y = INT32_MAX; polygon->extents.p2.x = polygon->extents.p2.y = INT32_MIN; polygon->limits = XNULL; polygon->num_limits = 0; for (chunk = &boxes->chunks; chunk != XNULL; chunk = chunk->next) { for (i = 0; i < chunk->count; i++) { cairo_point_t p1, p2; p1 = chunk->base[i].p1; p2.x = p1.x; p2.y = chunk->base[i].p2.y; _cairo_polygon_add_edge (polygon, &p1, &p2, 1); p1 = chunk->base[i].p2; p2.x = p1.x; p2.y = chunk->base[i].p1.y; _cairo_polygon_add_edge (polygon, &p1, &p2, 1); } } return polygon->status; }
cairo_status_t _cairo_pen_init (cairo_pen_t *pen, double radius, double tolerance, cairo_matrix_t *ctm) { int i; int reflect; pen->radius = radius; pen->tolerance = tolerance; reflect = _cairo_matrix_compute_determinant (ctm) < 0.; pen->num_vertices = _cairo_pen_vertices_needed (tolerance, radius, ctm); if (pen->num_vertices > ARRAY_LENGTH (pen->vertices_embedded)) { pen->vertices = _cairo_malloc_ab (pen->num_vertices, sizeof (cairo_pen_vertex_t)); if (pen->vertices == NULL) return _cairo_error (CAIRO_STATUS_NO_MEMORY); } else { pen->vertices = pen->vertices_embedded; } /* * Compute pen coordinates. To generate the right ellipse, compute points around * a circle in user space and transform them to device space. To get a consistent * orientation in device space, flip the pen if the transformation matrix * is reflecting */ for (i=0; i < pen->num_vertices; i++) { double theta = 2 * M_PI * i / (double) pen->num_vertices; double dx = radius * cos (reflect ? -theta : theta); double dy = radius * sin (reflect ? -theta : theta); cairo_pen_vertex_t *v = &pen->vertices[i]; cairo_matrix_transform_distance (ctm, &dx, &dy); v->point.x = _cairo_fixed_from_double (dx); v->point.y = _cairo_fixed_from_double (dy); } _cairo_pen_compute_slopes (pen); return CAIRO_STATUS_SUCCESS; }
cairo_status_t _cairo_pen_add_points (cairo_pen_t *pen, cairo_point_t *point, int num_points) { cairo_status_t status; int num_vertices; int i; num_vertices = pen->num_vertices + num_points; if (num_vertices > ARRAY_LENGTH (pen->vertices_embedded) || pen->vertices != pen->vertices_embedded) { cairo_pen_vertex_t *vertices; if (pen->vertices == pen->vertices_embedded) { vertices = _cairo_malloc_ab (num_vertices, sizeof (cairo_pen_vertex_t)); if (vertices == NULL) return _cairo_error (CAIRO_STATUS_NO_MEMORY); memcpy (vertices, pen->vertices, pen->num_vertices * sizeof (cairo_pen_vertex_t)); } else { vertices = _cairo_realloc_ab (pen->vertices, num_vertices, sizeof (cairo_pen_vertex_t)); if (vertices == NULL) return _cairo_error (CAIRO_STATUS_NO_MEMORY); } pen->vertices = vertices; } pen->num_vertices = num_vertices; /* initialize new vertices */ for (i=0; i < num_points; i++) pen->vertices[pen->num_vertices-num_points+i].point = point[i]; status = _cairo_hull_compute (pen->vertices, &pen->num_vertices); if (status) return status; _cairo_pen_compute_slopes (pen); return CAIRO_STATUS_SUCCESS; }
/** * _cairo_utf8_to_ucs4: * @str: an UTF-8 string * @len: length of @str in bytes, or -1 if it is nul-terminated. * If @len is supplied and the string has an embedded nul * byte, only the portion before the nul byte is converted. * @result: location to store a pointer to a newly allocated UTF-32 * string (always native endian), or %NULL. Free with free(). A 0 * word will be written after the last character. * @items_written: location to store number of 32-bit words * written. (Not including the trailing 0) * * Converts a UTF-8 string to UCS-4. UCS-4 is an encoding of Unicode * with 1 32-bit word per character. The string is validated to * consist entirely of valid Unicode characters. * * Return value: %CAIRO_STATUS_SUCCESS if the entire string was * successfully converted. %CAIRO_STATUS_INVALID_STRING if an * invalid sequence was found. **/ cairo_status_t _cairo_utf8_to_ucs4 (const char *str, int len, uint32_t **result, int *items_written) { uint32_t *str32 = NULL; int n_chars, i; const unsigned char *in; const unsigned char * const ustr = (const unsigned char *) str; in = ustr; n_chars = 0; while ((len < 0 || ustr + len - in > 0) && *in) { uint32_t wc = _utf8_get_char_extended (in, ustr + len - in); if (wc & 0x80000000 || !UNICODE_VALID (wc)) return _cairo_error (CAIRO_STATUS_INVALID_STRING); n_chars++; if (n_chars == INT_MAX) return _cairo_error (CAIRO_STATUS_INVALID_STRING); in = UTF8_NEXT_CHAR (in); } if (result) { str32 = _cairo_malloc_ab (n_chars + 1, sizeof (uint32_t)); if (!str32) return _cairo_error (CAIRO_STATUS_NO_MEMORY); in = ustr; for (i=0; i < n_chars; i++) { str32[i] = _utf8_get_char (in); in = UTF8_NEXT_CHAR (in); } str32[i] = 0; *result = str32; } if (items_written) *items_written = n_chars; return CAIRO_STATUS_SUCCESS; }
cairo_status_t _cairo_polygon_init_box_array (cairo_polygon_t *polygon, cairo_box_t *boxes, int num_boxes) { int i; VG (VALGRIND_MAKE_MEM_UNDEFINED (polygon, sizeof (cairo_polygon_t))); polygon->status = CAIRO_STATUS_SUCCESS; polygon->num_edges = 0; polygon->edges = polygon->edges_embedded; polygon->edges_size = ARRAY_LENGTH (polygon->edges_embedded); if (num_boxes > ARRAY_LENGTH (polygon->edges_embedded)/2) { polygon->edges_size = 2 * num_boxes; polygon->edges = _cairo_malloc_ab (polygon->edges_size, 2*sizeof(cairo_edge_t)); if (unlikely (polygon->edges == XNULL)) return polygon->status = _cairo_error (CAIRO_STATUS_NO_MEMORY); } polygon->extents.p1.x = polygon->extents.p1.y = INT32_MAX; polygon->extents.p2.x = polygon->extents.p2.y = INT32_MIN; polygon->limits = XNULL; polygon->num_limits = 0; for (i = 0; i < num_boxes; i++) { cairo_point_t p1, p2; p1 = boxes[i].p1; p2.x = p1.x; p2.y = boxes[i].p2.y; _cairo_polygon_add_edge (polygon, &p1, &p2, 1); p1 = boxes[i].p2; p2.x = p1.x; p2.y = boxes[i].p1.y; _cairo_polygon_add_edge (polygon, &p1, &p2, 1); } return polygon->status; }
cairo_status_t _cairo_pen_init_copy (cairo_pen_t *pen, cairo_pen_t *other) { *pen = *other; pen->vertices = pen->vertices_embedded; if (pen->num_vertices) { if (pen->num_vertices > ARRAY_LENGTH (pen->vertices_embedded)) { pen->vertices = _cairo_malloc_ab (pen->num_vertices, sizeof (cairo_pen_vertex_t)); if (pen->vertices == NULL) return _cairo_error (CAIRO_STATUS_NO_MEMORY); } memcpy (pen->vertices, other->vertices, pen->num_vertices * sizeof (cairo_pen_vertex_t)); } return CAIRO_STATUS_SUCCESS; }
static cairo_hull_t * _cairo_hull_create (cairo_pen_vertex_t *vertices, int num_vertices) { int i; cairo_hull_t *hull; cairo_point_t *p, *extremum, tmp; extremum = &vertices[0].point; for (i = 1; i < num_vertices; i++) { p = &vertices[i].point; if (p->y < extremum->y || (p->y == extremum->y && p->x < extremum->x)) extremum = p; } /* Put the extremal point at the beginning of the array */ tmp = *extremum; *extremum = vertices[0].point; vertices[0].point = tmp; hull = _cairo_malloc_ab (num_vertices, sizeof (cairo_hull_t)); if (hull == NULL) return NULL; for (i = 0; i < num_vertices; i++) { hull[i].point = vertices[i].point; _cairo_slope_init (&hull[i].slope, &hull[0].point, &hull[i].point); /* give each point a unique id for later comparison */ hull[i].id = i; /* Don't discard by default */ hull[i].discard = 0; /* Discard all points coincident with the extremal point */ if (i != 0 && hull[i].slope.dx == 0 && hull[i].slope.dy == 0) hull[i].discard = 1; } return hull; }
static cairo_status_t _cairo_rectilinear_stroker_add_segment (cairo_rectilinear_stroker_t *stroker, const cairo_point_t *p1, const cairo_point_t *p2, cairo_bool_t is_horizontal, cairo_bool_t has_join) { if (stroker->num_segments == stroker->segments_size) { int new_size = stroker->segments_size * 2; segment_t *new_segments; if (stroker->segments == stroker->segments_embedded) { new_segments = _cairo_malloc_ab (new_size, sizeof (segment_t)); if (unlikely (new_segments == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); memcpy (new_segments, stroker->segments, stroker->num_segments * sizeof (segment_t)); } else { new_segments = _cairo_realloc_ab (stroker->segments, new_size, sizeof (segment_t)); if (unlikely (new_segments == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); } stroker->segments_size = new_size; stroker->segments = new_segments; } stroker->segments[stroker->num_segments].p1 = *p1; stroker->segments[stroker->num_segments].p2 = *p2; stroker->segments[stroker->num_segments].has_join = has_join; stroker->segments[stroker->num_segments].is_horizontal = is_horizontal; stroker->num_segments++; return CAIRO_STATUS_SUCCESS; }
static cairo_path_t * _cairo_path_create_internal (cairo_path_fixed_t *path_fixed, cairo_t *cr, cairo_bool_t flatten) { cairo_path_t *path; path = xmemory_alloc (sizeof (cairo_path_t)); if (unlikely (path == XNULL)) { _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); return (cairo_path_t*) &_cairo_path_nil; } path->num_data = _cairo_path_count (path, path_fixed, cairo_get_tolerance (cr), flatten); if (path->num_data < 0) { xmemory_free (path); return (cairo_path_t*) &_cairo_path_nil; } if (path->num_data) { path->data = _cairo_malloc_ab (path->num_data, sizeof (cairo_path_data_t)); if (unlikely (path->data == XNULL)) { xmemory_free (path); _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); return (cairo_path_t*) &_cairo_path_nil; } path->status = _cairo_path_populate (path, path_fixed, cr, flatten); } else { path->data = XNULL; path->status = CAIRO_STATUS_SUCCESS; } return path; }
static cairo_status_t _cairo_rectilinear_stroker_add_segment (cairo_rectilinear_stroker_t *stroker, const cairo_point_t *p1, const cairo_point_t *p2, unsigned flags) { if (CAIRO_INJECT_FAULT ()) return _cairo_error (CAIRO_STATUS_NO_MEMORY); if (stroker->num_segments == stroker->segments_size) { int new_size = stroker->segments_size * 2; segment_t *new_segments; if (stroker->segments == stroker->segments_embedded) { new_segments = _cairo_malloc_ab (new_size, sizeof (segment_t)); if (unlikely (new_segments == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); memcpy (new_segments, stroker->segments, stroker->num_segments * sizeof (segment_t)); } else { new_segments = _cairo_realloc_ab (stroker->segments, new_size, sizeof (segment_t)); if (unlikely (new_segments == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); } stroker->segments_size = new_size; stroker->segments = new_segments; } stroker->segments[stroker->num_segments].p1 = *p1; stroker->segments[stroker->num_segments].p2 = *p2; stroker->segments[stroker->num_segments].flags = flags; stroker->num_segments++; return CAIRO_STATUS_SUCCESS; }
/* make room for at least one more trap */ static cairo_status_t _cairo_traps_grow (cairo_traps_t *traps) { cairo_trapezoid_t *new_traps; int new_size = 2 * MAX (traps->traps_size, 16); if (traps->traps == traps->traps_embedded) { new_traps = _cairo_malloc_ab (new_size, sizeof (cairo_trapezoid_t)); if (new_traps) memcpy (new_traps, traps->traps, sizeof (traps->traps_embedded)); } else { new_traps = _cairo_realloc_ab (traps->traps, new_size, sizeof (cairo_trapezoid_t)); } if (new_traps == NULL) return _cairo_error (CAIRO_STATUS_NO_MEMORY); traps->traps = new_traps; traps->traps_size = new_size; return CAIRO_STATUS_SUCCESS; }
/* make room for at least one more trap */ static cairo_bool_t _cairo_traps_grow (cairo_traps_t *traps) { cairo_trapezoid_t *new_traps; int new_size = 2 * MAX (traps->traps_size, 16); if (traps->traps == traps->traps_embedded) { new_traps = _cairo_malloc_ab (new_size, sizeof (cairo_trapezoid_t)); if (new_traps != NULL) memcpy (new_traps, traps->traps, sizeof (traps->traps_embedded)); } else { new_traps = _cairo_realloc_ab (traps->traps, new_size, sizeof (cairo_trapezoid_t)); } if (unlikely (new_traps == NULL)) { traps->status = _cairo_error (CAIRO_STATUS_NO_MEMORY); return FALSE; } traps->traps = new_traps; traps->traps_size = new_size; return TRUE; }
/* * Construct a fan around the midpoint using the vertices from pen between * inpt and outpt. */ static cairo_status_t _tessellate_fan (cairo_stroker_t *stroker, const cairo_slope_t *in_vector, const cairo_slope_t *out_vector, const cairo_point_t *midpt, const cairo_point_t *inpt, const cairo_point_t *outpt, cairo_bool_t clockwise) { cairo_point_t stack_points[64], *points = stack_points; int start, stop, step, i, npoints; cairo_status_t status; if (clockwise) { step = -1; start = _cairo_pen_find_active_ccw_vertex_index (&stroker->pen, in_vector); if (_cairo_slope_compare (&stroker->pen.vertices[start].slope_ccw, in_vector) < 0) start = _range_step (start, -1, stroker->pen.num_vertices); stop = _cairo_pen_find_active_ccw_vertex_index (&stroker->pen, out_vector); if (_cairo_slope_compare (&stroker->pen.vertices[stop].slope_cw, out_vector) > 0) { stop = _range_step (stop, 1, stroker->pen.num_vertices); if (_cairo_slope_compare (&stroker->pen.vertices[stop].slope_ccw, in_vector) < 0) { goto BEVEL; } } npoints = start - stop; } else { step = 1; start = _cairo_pen_find_active_cw_vertex_index (&stroker->pen, in_vector); if (_cairo_slope_compare (&stroker->pen.vertices[start].slope_cw, in_vector) < 0) start = _range_step (start, 1, stroker->pen.num_vertices); stop = _cairo_pen_find_active_cw_vertex_index (&stroker->pen, out_vector); if (_cairo_slope_compare (&stroker->pen.vertices[stop].slope_ccw, out_vector) > 0) { stop = _range_step (stop, -1, stroker->pen.num_vertices); if (_cairo_slope_compare (&stroker->pen.vertices[stop].slope_cw, in_vector) < 0) { goto BEVEL; } } npoints = stop - start; } stop = _range_step (stop, step, stroker->pen.num_vertices); if (npoints < 0) npoints += stroker->pen.num_vertices; npoints += 3; if (npoints <= 1) goto BEVEL; if (npoints > ARRAY_LENGTH (stack_points)) { points = _cairo_malloc_ab (npoints, sizeof (cairo_point_t)); if (unlikely (points == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); } /* Construct the fan. */ npoints = 0; points[npoints++] = *inpt; for (i = start; i != stop; i = _range_step (i, step, stroker->pen.num_vertices)) { points[npoints] = *midpt; _translate_point (&points[npoints], &stroker->pen.vertices[i].point); npoints++; } points[npoints++] = *outpt; if (stroker->add_external_edge != NULL) { for (i = 0; i < npoints - 1; i++) { if (clockwise) { status = stroker->add_external_edge (stroker->closure, &points[i], &points[i+1]); } else { status = stroker->add_external_edge (stroker->closure, &points[i+1], &points[i]); } if (unlikely (status)) break; } } else { status = stroker->add_triangle_fan (stroker->closure, midpt, points, npoints); } if (points != stack_points) free (points); return status; BEVEL: /* Ensure a leak free connection... */ if (stroker->add_external_edge != NULL) { if (clockwise) return stroker->add_external_edge (stroker->closure, inpt, outpt); else return stroker->add_external_edge (stroker->closure, outpt, inpt); } else { stack_points[0] = *midpt; stack_points[1] = *inpt; stack_points[2] = *outpt; return stroker->add_triangle (stroker->closure, stack_points); } }
cairo_int_status_t _cairo_pdf_operators_emit_stroke_style (cairo_pdf_operators_t *pdf_operators, const cairo_stroke_style_t *style, double scale) { double *dash = style->dash; int num_dashes = style->num_dashes; double dash_offset = style->dash_offset; double line_width = style->line_width * scale; /* PostScript has "special needs" when it comes to zero-length * dash segments with butt caps. It apparently (at least * according to ghostscript) draws hairlines for this * case. That's not what the cairo semantics want, so we first * touch up the array to eliminate any 0.0 values that will * result in "on" segments. */ if (num_dashes && style->line_cap == CAIRO_LINE_CAP_BUTT) { int i; /* If there's an odd number of dash values they will each get * interpreted as both on and off. So we first explicitly * expand the array to remove the duplicate usage so that we * can modify some of the values. */ if (num_dashes % 2) { dash = _cairo_malloc_abc (num_dashes, 2, sizeof (double)); if (unlikely (dash == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); memcpy (dash, style->dash, num_dashes * sizeof (double)); memcpy (dash + num_dashes, style->dash, num_dashes * sizeof (double)); num_dashes *= 2; } for (i = 0; i < num_dashes; i += 2) { if (dash[i] == 0.0) { /* Do not modify the dashes in-place, as we may need to also * replay this stroke to an image fallback. */ if (dash == style->dash) { dash = _cairo_malloc_ab (num_dashes, sizeof (double)); if (unlikely (dash == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); memcpy (dash, style->dash, num_dashes * sizeof (double)); } /* If we're at the front of the list, we first rotate * two elements from the end of the list to the front * of the list before folding away the 0.0. Or, if * there are only two dash elements, then there is * nothing at all to draw. */ if (i == 0) { double last_two[2]; if (num_dashes == 2) { free (dash); return CAIRO_INT_STATUS_NOTHING_TO_DO; } /* The cases of num_dashes == 0, 1, or 3 elements * cannot exist, so the rotation of 2 elements * will always be safe */ memcpy (last_two, dash + num_dashes - 2, sizeof (last_two)); memmove (dash + 2, dash, (num_dashes - 2) * sizeof (double)); memcpy (dash, last_two, sizeof (last_two)); dash_offset += dash[0] + dash[1]; i = 2; } dash[i-1] += dash[i+1]; num_dashes -= 2; memmove (dash + i, dash + i + 2, (num_dashes - i) * sizeof (double)); /* If we might have just rotated, it's possible that * we rotated a 0.0 value to the front of the list. * Set i to -2 so it will get incremented to 0. */ if (i == 2) i = -2; } } } if (!pdf_operators->has_line_style || pdf_operators->line_width != line_width) { _cairo_output_stream_printf (pdf_operators->stream, "%f w\n", line_width); pdf_operators->line_width = line_width; } if (!pdf_operators->has_line_style || pdf_operators->line_cap != style->line_cap) { _cairo_output_stream_printf (pdf_operators->stream, "%d J\n", _cairo_pdf_line_cap (style->line_cap)); pdf_operators->line_cap = style->line_cap; } if (!pdf_operators->has_line_style || pdf_operators->line_join != style->line_join) { _cairo_output_stream_printf (pdf_operators->stream, "%d j\n", _cairo_pdf_line_join (style->line_join)); pdf_operators->line_join = style->line_join; } if (num_dashes) { int d; _cairo_output_stream_printf (pdf_operators->stream, "["); for (d = 0; d < num_dashes; d++) _cairo_output_stream_printf (pdf_operators->stream, " %f", dash[d] * scale); _cairo_output_stream_printf (pdf_operators->stream, "] %f d\n", dash_offset * scale); pdf_operators->has_dashes = TRUE; } else if (!pdf_operators->has_line_style || pdf_operators->has_dashes) { _cairo_output_stream_printf (pdf_operators->stream, "[] 0.0 d\n"); pdf_operators->has_dashes = FALSE; } if (dash != style->dash) free (dash); if (!pdf_operators->has_line_style || pdf_operators->miter_limit != style->miter_limit) { _cairo_output_stream_printf (pdf_operators->stream, "%f M ", style->miter_limit < 1.0 ? 1.0 : style->miter_limit); pdf_operators->miter_limit = style->miter_limit; } pdf_operators->has_line_style = TRUE; return _cairo_output_stream_get_status (pdf_operators->stream); }
/* * Construct a fan around the midpoint using the vertices from pen between * inpt and outpt. */ static cairo_status_t _tessellate_fan (cairo_stroker_t *stroker, const cairo_slope_t *in_vector, const cairo_slope_t *out_vector, const cairo_point_t *midpt, const cairo_point_t *inpt, const cairo_point_t *outpt, cairo_bool_t clockwise) { cairo_point_t stack_points[64], *points = stack_points; cairo_pen_t *pen = &stroker->pen; int start, stop, num_points = 0; cairo_status_t status; if (stroker->has_bounds && ! _cairo_box_contains_point (&stroker->bounds, midpt)) goto BEVEL; assert (stroker->pen.num_vertices); if (clockwise) { _cairo_pen_find_active_ccw_vertices (pen, in_vector, out_vector, &start, &stop); if (stroker->add_external_edge) { cairo_point_t last; last = *inpt; while (start != stop) { cairo_point_t p = *midpt; _translate_point (&p, &pen->vertices[start].point); status = stroker->add_external_edge (stroker->closure, &last, &p); if (unlikely (status)) return status; last = p; if (start-- == 0) start += pen->num_vertices; } status = stroker->add_external_edge (stroker->closure, &last, outpt); } else { if (start == stop) goto BEVEL; num_points = stop - start; if (num_points < 0) num_points += pen->num_vertices; num_points += 2; if (num_points > ARRAY_LENGTH(stack_points)) { points = _cairo_malloc_ab (num_points, sizeof (cairo_point_t)); if (unlikely (points == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); } points[0] = *inpt; num_points = 1; while (start != stop) { points[num_points] = *midpt; _translate_point (&points[num_points], &pen->vertices[start].point); num_points++; if (start-- == 0) start += pen->num_vertices; } points[num_points++] = *outpt; } } else { _cairo_pen_find_active_cw_vertices (pen, in_vector, out_vector, &start, &stop); if (stroker->add_external_edge) { cairo_point_t last; last = *inpt; while (start != stop) { cairo_point_t p = *midpt; _translate_point (&p, &pen->vertices[start].point); status = stroker->add_external_edge (stroker->closure, &p, &last); if (unlikely (status)) return status; last = p; if (++start == pen->num_vertices) start = 0; } status = stroker->add_external_edge (stroker->closure, outpt, &last); } else { if (start == stop) goto BEVEL; num_points = stop - start; if (num_points < 0) num_points += pen->num_vertices; num_points += 2; if (num_points > ARRAY_LENGTH(stack_points)) { points = _cairo_malloc_ab (num_points, sizeof (cairo_point_t)); if (unlikely (points == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); } points[0] = *inpt; num_points = 1; while (start != stop) { points[num_points] = *midpt; _translate_point (&points[num_points], &pen->vertices[start].point); num_points++; if (++start == pen->num_vertices) start = 0; } points[num_points++] = *outpt; } } if (num_points) { status = stroker->add_triangle_fan (stroker->closure, midpt, points, num_points); } if (points != stack_points) free (points); return status; BEVEL: /* Ensure a leak free connection... */ if (stroker->add_external_edge != NULL) { if (clockwise) return stroker->add_external_edge (stroker->closure, inpt, outpt); else return stroker->add_external_edge (stroker->closure, outpt, inpt); } else { stack_points[0] = *midpt; stack_points[1] = *inpt; stack_points[2] = *outpt; return stroker->add_triangle (stroker->closure, stack_points); } }
cairo_status_t _cairo_surface_fallback_fill_rectangles (cairo_surface_t *surface, cairo_operator_t op, const cairo_color_t *color, cairo_rectangle_int_t *rects, int num_rects) { fallback_state_t state; cairo_rectangle_int_t *offset_rects = NULL; cairo_status_t status; int x1, y1, x2, y2; int i; assert (! surface->is_snapshot); if (num_rects <= 0) return CAIRO_STATUS_SUCCESS; /* Compute the bounds of the rectangles, so that we know what area of the * destination surface to fetch */ x1 = rects[0].x; y1 = rects[0].y; x2 = rects[0].x + rects[0].width; y2 = rects[0].y + rects[0].height; for (i = 1; i < num_rects; i++) { if (rects[i].x < x1) x1 = rects[i].x; if (rects[i].y < y1) y1 = rects[i].y; if ((int)(rects[i].x + rects[i].width) > x2) x2 = rects[i].x + rects[i].width; if ((int)(rects[i].y + rects[i].height) > y2) y2 = rects[i].y + rects[i].height; } status = _fallback_init (&state, surface, x1, y1, x2 - x1, y2 - y1); if (status) { if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) return CAIRO_STATUS_SUCCESS; return status; } /* If the fetched image isn't at 0,0, we need to offset the rectangles */ if (state.image_rect.x != 0 || state.image_rect.y != 0) { offset_rects = _cairo_malloc_ab (num_rects, sizeof (cairo_rectangle_int_t)); if (offset_rects == NULL) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto DONE; } for (i = 0; i < num_rects; i++) { offset_rects[i].x = rects[i].x - state.image_rect.x; offset_rects[i].y = rects[i].y - state.image_rect.y; offset_rects[i].width = rects[i].width; offset_rects[i].height = rects[i].height; } rects = offset_rects; } status = _cairo_surface_fill_rectangles (&state.image->base, op, color, rects, num_rects); free (offset_rects); DONE: _fallback_fini (&state); return status; }
static cairo_status_t _cairo_recording_surface_replay_internal (cairo_surface_t *surface, const cairo_rectangle_int_t *surface_extents, cairo_surface_t *target, cairo_recording_replay_type_t type, cairo_recording_region_type_t region) { cairo_recording_surface_t *recording_surface; cairo_command_t **elements; int i, num_elements; cairo_int_status_t status; cairo_surface_wrapper_t wrapper; if (unlikely (surface->status)) return surface->status; if (unlikely (target->status)) return target->status; if (unlikely (surface->finished)) return _cairo_error (CAIRO_STATUS_SURFACE_FINISHED); if (surface->is_clear) return CAIRO_STATUS_SUCCESS; assert (_cairo_surface_is_recording (surface)); _cairo_surface_wrapper_init (&wrapper, target); _cairo_surface_wrapper_set_extents (&wrapper, surface_extents); recording_surface = (cairo_recording_surface_t *) surface; status = CAIRO_STATUS_SUCCESS; num_elements = recording_surface->commands.num_elements; elements = _cairo_array_index (&recording_surface->commands, 0); for (i = recording_surface->replay_start_idx; i < num_elements; i++) { cairo_command_t *command = elements[i]; if (type == CAIRO_RECORDING_REPLAY && region != CAIRO_RECORDING_REGION_ALL) { if (command->header.region != region) continue; } switch (command->header.type) { case CAIRO_COMMAND_PAINT: status = _cairo_surface_wrapper_paint (&wrapper, command->header.op, &command->paint.source.base, _clip (command)); break; case CAIRO_COMMAND_MASK: status = _cairo_surface_wrapper_mask (&wrapper, command->header.op, &command->mask.source.base, &command->mask.mask.base, _clip (command)); break; case CAIRO_COMMAND_STROKE: { status = _cairo_surface_wrapper_stroke (&wrapper, command->header.op, &command->stroke.source.base, &command->stroke.path, &command->stroke.style, &command->stroke.ctm, &command->stroke.ctm_inverse, command->stroke.tolerance, command->stroke.antialias, _clip (command)); break; } case CAIRO_COMMAND_FILL: { cairo_command_t *stroke_command; stroke_command = NULL; if (type != CAIRO_RECORDING_CREATE_REGIONS && i < num_elements - 1) stroke_command = elements[i + 1]; if (stroke_command != NULL && type == CAIRO_RECORDING_REPLAY && region != CAIRO_RECORDING_REGION_ALL) { if (stroke_command->header.region != region) stroke_command = NULL; } if (stroke_command != NULL && stroke_command->header.type == CAIRO_COMMAND_STROKE && _cairo_path_fixed_is_equal (&command->fill.path, &stroke_command->stroke.path)) { status = _cairo_surface_wrapper_fill_stroke (&wrapper, command->header.op, &command->fill.source.base, command->fill.fill_rule, command->fill.tolerance, command->fill.antialias, &command->fill.path, stroke_command->header.op, &stroke_command->stroke.source.base, &stroke_command->stroke.style, &stroke_command->stroke.ctm, &stroke_command->stroke.ctm_inverse, stroke_command->stroke.tolerance, stroke_command->stroke.antialias, _clip (command)); i++; } else { status = _cairo_surface_wrapper_fill (&wrapper, command->header.op, &command->fill.source.base, &command->fill.path, command->fill.fill_rule, command->fill.tolerance, command->fill.antialias, _clip (command)); } break; } case CAIRO_COMMAND_SHOW_TEXT_GLYPHS: { cairo_glyph_t *glyphs = command->show_text_glyphs.glyphs; cairo_glyph_t *glyphs_copy; int num_glyphs = command->show_text_glyphs.num_glyphs; /* show_text_glyphs is special because _cairo_surface_show_text_glyphs is allowed * to modify the glyph array that's passed in. We must always * copy the array before handing it to the backend. */ glyphs_copy = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t)); if (unlikely (glyphs_copy == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); break; } memcpy (glyphs_copy, glyphs, sizeof (cairo_glyph_t) * num_glyphs); status = _cairo_surface_wrapper_show_text_glyphs (&wrapper, command->header.op, &command->show_text_glyphs.source.base, command->show_text_glyphs.utf8, command->show_text_glyphs.utf8_len, glyphs_copy, num_glyphs, command->show_text_glyphs.clusters, command->show_text_glyphs.num_clusters, command->show_text_glyphs.cluster_flags, command->show_text_glyphs.scaled_font, _clip (command)); free (glyphs_copy); break; } default: ASSERT_NOT_REACHED; } if (type == CAIRO_RECORDING_CREATE_REGIONS) { if (status == CAIRO_STATUS_SUCCESS) { command->header.region = CAIRO_RECORDING_REGION_NATIVE; } else if (status == CAIRO_INT_STATUS_IMAGE_FALLBACK) { command->header.region = CAIRO_RECORDING_REGION_IMAGE_FALLBACK; status = CAIRO_STATUS_SUCCESS; } else { assert (_cairo_status_is_error (status)); } } if (unlikely (status)) break; } /* free up any caches */ for (i = recording_surface->replay_start_idx; i < num_elements; i++) { cairo_command_t *command = elements[i]; _cairo_clip_drop_cache (&command->header.clip); } _cairo_surface_wrapper_fini (&wrapper); return _cairo_surface_set_error (surface, status); }
cairo_status_t _cairo_surface_wrapper_show_text_glyphs (cairo_surface_wrapper_t *wrapper, cairo_operator_t op, const cairo_pattern_t *source, const char *utf8, int utf8_len, 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_scaled_font_t *scaled_font, const cairo_clip_t *clip) { cairo_status_t status; cairo_clip_t *dev_clip; cairo_glyph_t stack_glyphs [CAIRO_STACK_ARRAY_LENGTH(cairo_glyph_t)]; cairo_glyph_t *dev_glyphs = stack_glyphs; cairo_scaled_font_t *dev_scaled_font = scaled_font; cairo_pattern_union_t source_copy; cairo_font_options_t options; if (unlikely (wrapper->target->status)) return wrapper->target->status; dev_clip = _cairo_surface_wrapper_get_clip (wrapper, clip); if (_cairo_clip_is_all_clipped (dev_clip)) return CAIRO_INT_STATUS_NOTHING_TO_DO; cairo_surface_get_font_options (wrapper->target, &options); cairo_font_options_merge (&options, &scaled_font->options); if (wrapper->needs_transform) { cairo_matrix_t m; int i; _cairo_surface_wrapper_get_transform (wrapper, &m); if (! _cairo_matrix_is_translation (&wrapper->transform)) { cairo_matrix_t ctm; /* XXX No device-transform? A bug in the tangle of layers? */ _cairo_matrix_multiply (&ctm, &wrapper->transform, &scaled_font->ctm); dev_scaled_font = cairo_scaled_font_create (scaled_font->font_face, &scaled_font->font_matrix, &ctm, &options); } if (num_glyphs > ARRAY_LENGTH (stack_glyphs)) { dev_glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t)); if (unlikely (dev_glyphs == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto FINISH; } } for (i = 0; i < num_glyphs; i++) { dev_glyphs[i] = glyphs[i]; cairo_matrix_transform_point (&m, &dev_glyphs[i].x, &dev_glyphs[i].y); } status = cairo_matrix_invert (&m); assert (status == CAIRO_STATUS_SUCCESS); _copy_transformed_pattern (&source_copy.base, source, &m); source = &source_copy.base; } else { if (! cairo_font_options_equal (&options, &scaled_font->options)) { dev_scaled_font = cairo_scaled_font_create (scaled_font->font_face, &scaled_font->font_matrix, &scaled_font->ctm, &options); } /* show_text_glyphs is special because _cairo_surface_show_text_glyphs is allowed * to modify the glyph array that's passed in. We must always * copy the array before handing it to the backend. */ if (num_glyphs > ARRAY_LENGTH (stack_glyphs)) { dev_glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t)); if (unlikely (dev_glyphs == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto FINISH; } } memcpy (dev_glyphs, glyphs, sizeof (cairo_glyph_t) * num_glyphs); } status = _cairo_surface_show_text_glyphs (wrapper->target, op, source, utf8, utf8_len, dev_glyphs, num_glyphs, clusters, num_clusters, cluster_flags, dev_scaled_font, dev_clip); FINISH: _cairo_clip_destroy (dev_clip); if (dev_glyphs != stack_glyphs) free (dev_glyphs); if (dev_scaled_font != scaled_font) cairo_scaled_font_destroy (dev_scaled_font); return status; }
cairo_int_status_t _cairo_gl_gradient_create (cairo_gl_context_t *ctx, unsigned int n_stops, const cairo_gradient_stop_t *stops, cairo_gl_gradient_t **gradient_out) { unsigned long hash; cairo_gl_gradient_t *gradient; cairo_status_t status; int tex_width; GLint internal_format; void *data; if ((unsigned int) ctx->max_texture_size / 2 <= n_stops) return CAIRO_INT_STATUS_UNSUPPORTED; hash = _cairo_gl_gradient_hash (n_stops, stops); gradient = _cairo_gl_gradient_lookup (ctx, hash, n_stops, stops); if (gradient) { *gradient_out = _cairo_gl_gradient_reference (gradient); return CAIRO_STATUS_SUCCESS; } gradient = _cairo_malloc (sizeof (cairo_gl_gradient_t) + sizeof (cairo_gradient_stop_t) * (n_stops - 1)); if (gradient == NULL) return _cairo_error (CAIRO_STATUS_NO_MEMORY); tex_width = _cairo_gl_gradient_sample_width (n_stops, stops); if (tex_width > ctx->max_texture_size) tex_width = ctx->max_texture_size; CAIRO_REFERENCE_COUNT_INIT (&gradient->ref_count, 2); gradient->cache_entry.hash = hash; gradient->cache_entry.size = tex_width; gradient->device = &ctx->base; gradient->n_stops = n_stops; gradient->stops = gradient->stops_embedded; memcpy (gradient->stops_embedded, stops, n_stops * sizeof (cairo_gradient_stop_t)); glGenTextures (1, &gradient->tex); _cairo_gl_context_activate (ctx, CAIRO_GL_TEX_TEMP); glBindTexture (ctx->tex_target, gradient->tex); data = _cairo_malloc_ab (tex_width, sizeof (uint32_t)); if (unlikely (data == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto cleanup_gradient; } status = _cairo_gl_gradient_render (ctx, n_stops, stops, data, tex_width); if (unlikely (status)) goto cleanup_data; /* * In OpenGL ES 2.0 no format conversion is allowed i.e. 'internalFormat' * must match 'format' in glTexImage2D. */ if (_cairo_gl_get_flavor () == CAIRO_GL_FLAVOR_ES3 || _cairo_gl_get_flavor () == CAIRO_GL_FLAVOR_ES2) internal_format = GL_BGRA; else internal_format = GL_RGBA; glTexImage2D (ctx->tex_target, 0, internal_format, tex_width, 1, 0, GL_BGRA, GL_UNSIGNED_BYTE, data); free (data); /* we ignore errors here and just return an uncached gradient */ if (unlikely (_cairo_cache_insert (&ctx->gradients, &gradient->cache_entry))) CAIRO_REFERENCE_COUNT_INIT (&gradient->ref_count, 1); *gradient_out = gradient; return CAIRO_STATUS_SUCCESS; cleanup_data: free (data); cleanup_gradient: free (gradient); return status; }
static cairo_status_t _cairo_gl_gradient_render (const cairo_gl_context_t *ctx, unsigned int n_stops, const cairo_gradient_stop_t *stops, void *bytes, int width) { pixman_image_t *gradient, *image; pixman_gradient_stop_t pixman_stops_stack[32]; pixman_gradient_stop_t *pixman_stops; pixman_point_fixed_t p1, p2; unsigned int i; pixman_format_code_t gradient_pixman_format; /* * Ensure that the order of the gradient's components in memory is BGRA. * This is done so that the gradient's pixel data is always suitable for * texture upload using format=GL_BGRA and type=GL_UNSIGNED_BYTE. */ if (_cairo_is_little_endian ()) gradient_pixman_format = PIXMAN_a8r8g8b8; else gradient_pixman_format = PIXMAN_b8g8r8a8; pixman_stops = pixman_stops_stack; if (unlikely (n_stops > ARRAY_LENGTH (pixman_stops_stack))) { pixman_stops = _cairo_malloc_ab (n_stops, sizeof (pixman_gradient_stop_t)); if (unlikely (pixman_stops == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); } for (i = 0; i < n_stops; i++) { pixman_stops[i].x = _cairo_fixed_16_16_from_double (stops[i].offset); pixman_stops[i].color.red = stops[i].color.red_short; pixman_stops[i].color.green = stops[i].color.green_short; pixman_stops[i].color.blue = stops[i].color.blue_short; pixman_stops[i].color.alpha = stops[i].color.alpha_short; } p1.x = _cairo_fixed_16_16_from_double (0.5); p1.y = 0; p2.x = _cairo_fixed_16_16_from_double (width - 0.5); p2.y = 0; gradient = pixman_image_create_linear_gradient (&p1, &p2, pixman_stops, n_stops); if (pixman_stops != pixman_stops_stack) free (pixman_stops); if (unlikely (gradient == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); pixman_image_set_filter (gradient, PIXMAN_FILTER_BILINEAR, NULL, 0); pixman_image_set_repeat (gradient, PIXMAN_REPEAT_PAD); image = pixman_image_create_bits (gradient_pixman_format, width, 1, bytes, sizeof(uint32_t)*width); if (unlikely (image == NULL)) { pixman_image_unref (gradient); return _cairo_error (CAIRO_STATUS_NO_MEMORY); } pixman_image_composite32 (PIXMAN_OP_SRC, gradient, NULL, image, 0, 0, 0, 0, 0, 0, width, 1); pixman_image_unref (gradient); pixman_image_unref (image); /* We need to fudge pixel 0 to hold the left-most color stop and not * the neareset stop to the zeroth pixel centre in order to correctly * populate the border color. For completeness, do both edges. */ ((uint32_t*)bytes)[0] = color_stop_to_pixel(&stops[0]); ((uint32_t*)bytes)[width-1] = color_stop_to_pixel(&stops[n_stops-1]); return CAIRO_STATUS_SUCCESS; }
static cairo_int_status_t _cairo_tee_surface_show_text_glyphs (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, const char *utf8, int utf8_len, cairo_glyph_t *glyphs, int num_glyphs, const cairo_text_cluster_t *clusters, int num_clusters, cairo_text_cluster_flags_t cluster_flags, cairo_scaled_font_t *scaled_font, cairo_clip_t *clip) { cairo_tee_surface_t *surface = abstract_surface; cairo_surface_wrapper_t *slaves; int n, num_slaves; cairo_status_t status; cairo_glyph_t *glyphs_copy; const cairo_pattern_t *matched_source; cairo_surface_pattern_t temp; /* XXX: This copying is ugly. */ glyphs_copy = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t)); if (unlikely (glyphs_copy == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); memcpy (glyphs_copy, glyphs, sizeof (cairo_glyph_t) * num_glyphs); matched_source = _cairo_tee_surface_match_source (surface, source, 0, &surface->master, &temp); status = _cairo_surface_wrapper_show_text_glyphs (&surface->master, op, matched_source, utf8, utf8_len, glyphs_copy, num_glyphs, clusters, num_clusters, cluster_flags, scaled_font, clip); if (matched_source == &temp.base) { _cairo_pattern_fini (&temp.base); } if (unlikely (status)) goto CLEANUP; num_slaves = _cairo_array_num_elements (&surface->slaves); slaves = _cairo_array_index (&surface->slaves, 0); for (n = 0; n < num_slaves; n++) { memcpy (glyphs_copy, glyphs, sizeof (cairo_glyph_t) * num_glyphs); matched_source = _cairo_tee_surface_match_source (surface, source, n + 1, &slaves[n], &temp); status = _cairo_surface_wrapper_show_text_glyphs (&slaves[n], op, matched_source, utf8, utf8_len, glyphs_copy, num_glyphs, clusters, num_clusters, cluster_flags, scaled_font, clip); if (matched_source == &temp.base) { _cairo_pattern_fini (&temp.base); } if (unlikely (status)) goto CLEANUP; } CLEANUP: free (glyphs_copy); return status; }
static cairo_int_status_t _cairo_recording_surface_show_text_glyphs (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, const char *utf8, int utf8_len, cairo_glyph_t *glyphs, int num_glyphs, const cairo_text_cluster_t *clusters, int num_clusters, cairo_text_cluster_flags_t cluster_flags, cairo_scaled_font_t *scaled_font, cairo_clip_t *clip) { cairo_status_t status; cairo_recording_surface_t *recording_surface = abstract_surface; cairo_command_show_text_glyphs_t *command; command = malloc (sizeof (cairo_command_show_text_glyphs_t)); if (unlikely (command == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); status = _command_init (recording_surface, &command->header, CAIRO_COMMAND_SHOW_TEXT_GLYPHS, op, clip); if (unlikely (status)) goto CLEANUP_COMMAND; status = _cairo_pattern_init_snapshot (&command->source.base, source); if (unlikely (status)) goto CLEANUP_COMMAND; command->utf8 = NULL; command->utf8_len = utf8_len; command->glyphs = NULL; command->num_glyphs = num_glyphs; command->clusters = NULL; command->num_clusters = num_clusters; if (utf8_len) { command->utf8 = malloc (utf8_len); if (unlikely (command->utf8 == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto CLEANUP_ARRAYS; } memcpy (command->utf8, utf8, utf8_len); } if (num_glyphs) { command->glyphs = _cairo_malloc_ab (num_glyphs, sizeof (glyphs[0])); if (unlikely (command->glyphs == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto CLEANUP_ARRAYS; } memcpy (command->glyphs, glyphs, sizeof (glyphs[0]) * num_glyphs); } if (num_clusters) { command->clusters = _cairo_malloc_ab (num_clusters, sizeof (clusters[0])); if (unlikely (command->clusters == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto CLEANUP_ARRAYS; } memcpy (command->clusters, clusters, sizeof (clusters[0]) * num_clusters); } command->cluster_flags = cluster_flags; command->scaled_font = cairo_scaled_font_reference (scaled_font); status = _cairo_array_append (&recording_surface->commands, &command); if (unlikely (status)) goto CLEANUP_SCALED_FONT; return CAIRO_STATUS_SUCCESS; CLEANUP_SCALED_FONT: cairo_scaled_font_destroy (command->scaled_font); CLEANUP_ARRAYS: free (command->utf8); free (command->glyphs); free (command->clusters); _cairo_pattern_fini (&command->source.base); CLEANUP_COMMAND: _cairo_clip_fini (&command->header.clip); free (command); return status; }
cairo_status_t _cairo_bentley_ottmann_tessellate_boxes (const cairo_boxes_t *in, cairo_fill_rule_t fill_rule, cairo_boxes_t *out) { rectangle_t stack_rectangles[CAIRO_STACK_ARRAY_LENGTH (rectangle_t)]; rectangle_t *stack_rectangles_ptrs[ARRAY_LENGTH (stack_rectangles) + 3]; rectangle_t *rectangles, **rectangles_ptrs; rectangle_t *stack_rectangles_chain[CAIRO_STACK_ARRAY_LENGTH (rectangle_t *) ]; rectangle_t **rectangles_chain = NULL; const struct _cairo_boxes_chunk *chunk; cairo_status_t status; int i, j, y_min, y_max; if (unlikely (in->num_boxes == 0)) { _cairo_boxes_clear (out); return CAIRO_STATUS_SUCCESS; } if (in->num_boxes == 1) { if (in == out) { cairo_box_t *box = &in->chunks.base[0]; if (box->p1.x > box->p2.x) { cairo_fixed_t tmp = box->p1.x; box->p1.x = box->p2.x; box->p2.x = tmp; } } else { cairo_box_t box = in->chunks.base[0]; if (box.p1.x > box.p2.x) { cairo_fixed_t tmp = box.p1.x; box.p1.x = box.p2.x; box.p2.x = tmp; } _cairo_boxes_clear (out); status = _cairo_boxes_add (out, CAIRO_ANTIALIAS_DEFAULT, &box); assert (status == CAIRO_STATUS_SUCCESS); } return CAIRO_STATUS_SUCCESS; } y_min = INT_MAX; y_max = INT_MIN; for (chunk = &in->chunks; chunk != NULL; chunk = chunk->next) { const cairo_box_t *box = chunk->base; for (i = 0; i < chunk->count; i++) { if (box[i].p1.y < y_min) y_min = box[i].p1.y; if (box[i].p1.y > y_max) y_max = box[i].p1.y; } } y_min = _cairo_fixed_integer_floor (y_min); y_max = _cairo_fixed_integer_floor (y_max) + 1; y_max -= y_min; if (y_max < in->num_boxes) { rectangles_chain = stack_rectangles_chain; if (y_max > ARRAY_LENGTH (stack_rectangles_chain)) { rectangles_chain = _cairo_malloc_ab (y_max, sizeof (rectangle_t *)); if (unlikely (rectangles_chain == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); } memset (rectangles_chain, 0, y_max * sizeof (rectangle_t*)); } rectangles = stack_rectangles; rectangles_ptrs = stack_rectangles_ptrs; if (in->num_boxes > ARRAY_LENGTH (stack_rectangles)) { rectangles = _cairo_malloc_ab_plus_c (in->num_boxes, sizeof (rectangle_t) + sizeof (rectangle_t *), 3*sizeof (rectangle_t *)); if (unlikely (rectangles == NULL)) { if (rectangles_chain != stack_rectangles_chain) free (rectangles_chain); return _cairo_error (CAIRO_STATUS_NO_MEMORY); } rectangles_ptrs = (rectangle_t **) (rectangles + in->num_boxes); } j = 0; for (chunk = &in->chunks; chunk != NULL; chunk = chunk->next) { const cairo_box_t *box = chunk->base; for (i = 0; i < chunk->count; i++) { int h; if (box[i].p1.x < box[i].p2.x) { rectangles[j].left.x = box[i].p1.x; rectangles[j].left.dir = 1; rectangles[j].right.x = box[i].p2.x; rectangles[j].right.dir = -1; } else { rectangles[j].right.x = box[i].p1.x; rectangles[j].right.dir = 1; rectangles[j].left.x = box[i].p2.x; rectangles[j].left.dir = -1; } rectangles[j].left.right = NULL; rectangles[j].right.right = NULL; rectangles[j].top = box[i].p1.y; rectangles[j].bottom = box[i].p2.y; if (rectangles_chain) { h = _cairo_fixed_integer_floor (box[i].p1.y) - y_min; rectangles[j].left.next = (edge_t *)rectangles_chain[h]; rectangles_chain[h] = &rectangles[j]; } else { rectangles_ptrs[j+2] = &rectangles[j]; } j++; } } if (rectangles_chain) { j = 2; for (y_min = 0; y_min < y_max; y_min++) { rectangle_t *r; int start = j; for (r = rectangles_chain[y_min]; r; r = (rectangle_t *)r->left.next) rectangles_ptrs[j++] = r; if (j > start + 1) _rectangle_sort (rectangles_ptrs + start, j - start); } if (rectangles_chain != stack_rectangles_chain) free (rectangles_chain); j -= 2; } else { _rectangle_sort (rectangles_ptrs + 2, j); } _cairo_boxes_clear (out); status = _cairo_bentley_ottmann_tessellate_rectangular (rectangles_ptrs+2, j, fill_rule, FALSE, out); if (rectangles != stack_rectangles) free (rectangles); return status; }
cairo_rectangle_list_t * _cairo_clip_copy_rectangle_list (cairo_clip_t *clip, cairo_gstate_t *gstate) { cairo_rectangle_list_t *list; cairo_rectangle_t *rectangles = NULL; int n_boxes = 0; if (clip->all_clipped) goto DONE; if (clip->path || clip->surface) { _cairo_error_throw (CAIRO_STATUS_CLIP_NOT_REPRESENTABLE); return (cairo_rectangle_list_t*) &_cairo_rectangles_not_representable; } if (clip->has_region) { cairo_box_int_t *boxes; int i; if (_cairo_region_get_boxes (&clip->region, &n_boxes, &boxes)) return (cairo_rectangle_list_t*) &_cairo_rectangles_nil; if (n_boxes) { rectangles = _cairo_malloc_ab (n_boxes, sizeof (cairo_rectangle_t)); if (rectangles == NULL) { _cairo_region_boxes_fini (&clip->region, boxes); _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); return (cairo_rectangle_list_t*) &_cairo_rectangles_nil; } for (i = 0; i < n_boxes; ++i) { cairo_rectangle_int_t clip_rect = { boxes[i].p1.x, boxes[i].p1.y, boxes[i].p2.x - boxes[i].p1.x, boxes[i].p2.y - boxes[i].p1.y }; if (!_cairo_clip_int_rect_to_user(gstate, &clip_rect, &rectangles[i])) { _cairo_error_throw (CAIRO_STATUS_CLIP_NOT_REPRESENTABLE); _cairo_region_boxes_fini (&clip->region, boxes); free (rectangles); return (cairo_rectangle_list_t*) &_cairo_rectangles_not_representable; } } } _cairo_region_boxes_fini (&clip->region, boxes); } else { cairo_rectangle_int_t extents; n_boxes = 1; rectangles = malloc(sizeof (cairo_rectangle_t)); if (rectangles == NULL) { _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); return (cairo_rectangle_list_t*) &_cairo_rectangles_nil; } if (_cairo_surface_get_extents (_cairo_gstate_get_target (gstate), &extents) || !_cairo_clip_int_rect_to_user(gstate, &extents, rectangles)) { _cairo_error_throw (CAIRO_STATUS_CLIP_NOT_REPRESENTABLE); free (rectangles); return (cairo_rectangle_list_t*) &_cairo_rectangles_not_representable; } } DONE: list = malloc (sizeof (cairo_rectangle_list_t)); if (list == NULL) { _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); free (rectangles); return (cairo_rectangle_list_t*) &_cairo_rectangles_nil; } list->status = CAIRO_STATUS_SUCCESS; list->rectangles = rectangles; list->num_rectangles = n_boxes; return list; }
/* This special-case filler supports only a path that describes a * device-axis aligned rectangle. It exists to avoid the overhead of * the general tessellator when drawing very common rectangles. * * If the path described anything but a device-axis aligned rectangle, * this function will abort. */ cairo_region_t * _cairo_path_fixed_fill_rectilinear_to_region (const cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, const cairo_rectangle_int_t *extents) { cairo_rectangle_int_t rectangle_stack[CAIRO_STACK_ARRAY_LENGTH (cairo_rectangle_int_t)]; cairo_box_t box; cairo_region_t *region = NULL; assert (path->maybe_fill_region); assert (! path->is_empty_fill); if (_cairo_path_fixed_is_box (path, &box)) { rectangle_stack[0].x = _cairo_fixed_integer_part (box.p1.x); rectangle_stack[0].y = _cairo_fixed_integer_part (box.p1.y); rectangle_stack[0].width = _cairo_fixed_integer_part (box.p2.x) - rectangle_stack[0].x; rectangle_stack[0].height = _cairo_fixed_integer_part (box.p2.y) - rectangle_stack[0].y; if (! _cairo_rectangle_intersect (&rectangle_stack[0], extents)) region = cairo_region_create (); else region = cairo_region_create_rectangle (&rectangle_stack[0]); } else if (fill_rule == CAIRO_FILL_RULE_WINDING) { cairo_rectangle_int_t *rects = rectangle_stack; cairo_path_fixed_iter_t iter; int last_cw = -1; int size = ARRAY_LENGTH (rectangle_stack); int count = 0; /* Support a series of rectangles as can be expected to describe a * GdkRegion clip region during exposes. */ _cairo_path_fixed_iter_init (&iter, path); while (_cairo_path_fixed_iter_is_fill_box (&iter, &box)) { int cw = 0; if (box.p1.x > box.p2.x) { cairo_fixed_t t; t = box.p1.x; box.p1.x = box.p2.x; box.p2.x = t; cw = ! cw; } if (box.p1.y > box.p2.y) { cairo_fixed_t t; t = box.p1.y; box.p1.y = box.p2.y; box.p2.y = t; cw = ! cw; } if (last_cw < 0) last_cw = cw; else if (last_cw != cw) goto TESSELLATE; if (count == size) { cairo_rectangle_int_t *new_rects; size *= 4; if (rects == rectangle_stack) { new_rects = _cairo_malloc_ab (size, sizeof (cairo_rectangle_int_t)); if (unlikely (new_rects == NULL)) { /* XXX _cairo_region_nil */ break; } memcpy (new_rects, rects, sizeof (rectangle_stack)); } else { new_rects = _cairo_realloc_ab (rects, size, sizeof (cairo_rectangle_int_t)); if (unlikely (new_rects == NULL)) { /* XXX _cairo_region_nil */ break; } } rects = new_rects; } rects[count].x = _cairo_fixed_integer_part (box.p1.x); rects[count].y = _cairo_fixed_integer_part (box.p1.y); rects[count].width = _cairo_fixed_integer_part (box.p2.x) - rects[count].x; rects[count].height = _cairo_fixed_integer_part (box.p2.y) - rects[count].y; if (_cairo_rectangle_intersect (&rects[count], extents)) count++; } if (_cairo_path_fixed_iter_at_end (&iter)) region = cairo_region_create_rectangles (rects, count); TESSELLATE: if (rects != rectangle_stack) free (rects); } if (region == NULL) { /* Hmm, complex polygon */ region = _cairo_path_fixed_fill_rectilinear_tessellate_to_region (path, fill_rule, extents); } return region; }
static cairo_status_t _cairo_scaled_font_subsets_foreach_internal (cairo_scaled_font_subsets_t *font_subsets, cairo_scaled_font_subset_callback_func_t font_subset_callback, void *closure, cairo_subsets_foreach_type_t type) { cairo_sub_font_collection_t collection; cairo_sub_font_t *sub_font; cairo_bool_t is_scaled, is_user; is_scaled = FALSE; is_user = FALSE; if (type == CAIRO_SUBSETS_FOREACH_USER) is_user = TRUE; if (type == CAIRO_SUBSETS_FOREACH_SCALED || type == CAIRO_SUBSETS_FOREACH_USER) { is_scaled = TRUE; } if (is_scaled) collection.glyphs_size = font_subsets->max_glyphs_per_scaled_subset_used; else collection.glyphs_size = font_subsets->max_glyphs_per_unscaled_subset_used; if (! collection.glyphs_size) return CAIRO_STATUS_SUCCESS; collection.glyphs = _cairo_malloc_ab (collection.glyphs_size, sizeof(unsigned long)); collection.utf8 = _cairo_malloc_ab (collection.glyphs_size, sizeof(char *)); collection.to_latin_char = _cairo_malloc_ab (collection.glyphs_size, sizeof(int)); collection.latin_to_subset_glyph_index = _cairo_malloc_ab (256, sizeof(unsigned long)); if (unlikely (collection.glyphs == NULL || collection.utf8 == NULL || collection.to_latin_char == NULL || collection.latin_to_subset_glyph_index == NULL)) { free (collection.glyphs); free (collection.utf8); free (collection.to_latin_char); free (collection.latin_to_subset_glyph_index); return _cairo_error (CAIRO_STATUS_NO_MEMORY); } collection.font_subset_callback = font_subset_callback; collection.font_subset_callback_closure = closure; collection.status = CAIRO_STATUS_SUCCESS; if (is_scaled) sub_font = font_subsets->scaled_sub_fonts_list; else sub_font = font_subsets->unscaled_sub_fonts_list; while (sub_font) { if (sub_font->is_user == is_user) _cairo_sub_font_collect (sub_font, &collection); sub_font = sub_font->next; } free (collection.utf8); free (collection.glyphs); free (collection.to_latin_char); free (collection.latin_to_subset_glyph_index); return collection.status; }
cairo_int_status_t _cairo_win32_surface_emit_glyphs (cairo_win32_surface_t *dst, const cairo_pattern_t *source, cairo_glyph_t *glyphs, int num_glyphs, cairo_scaled_font_t *scaled_font, cairo_bool_t glyph_indexing) { #if CAIRO_HAS_WIN32_FONT WORD glyph_buf_stack[STACK_GLYPH_SIZE]; WORD *glyph_buf = glyph_buf_stack; int dxy_buf_stack[2 * STACK_GLYPH_SIZE]; int *dxy_buf = dxy_buf_stack; BOOL win_result = 0; int i, j; cairo_solid_pattern_t *solid_pattern; COLORREF color; cairo_matrix_t device_to_logical; int start_x, start_y; double user_x, user_y; int logical_x, logical_y; unsigned int glyph_index_option; /* We can only handle win32 fonts */ assert (cairo_scaled_font_get_type (scaled_font) == CAIRO_FONT_TYPE_WIN32); /* We can only handle opaque solid color sources and destinations */ assert (_cairo_pattern_is_opaque_solid(source)); assert (dst->format == CAIRO_FORMAT_RGB24); solid_pattern = (cairo_solid_pattern_t *)source; color = RGB(((int)solid_pattern->color.red_short) >> 8, ((int)solid_pattern->color.green_short) >> 8, ((int)solid_pattern->color.blue_short) >> 8); cairo_win32_scaled_font_get_device_to_logical(scaled_font, &device_to_logical); SaveDC(dst->dc); cairo_win32_scaled_font_select_font(scaled_font, dst->dc); SetTextColor(dst->dc, color); SetTextAlign(dst->dc, TA_BASELINE | TA_LEFT); SetBkMode(dst->dc, TRANSPARENT); if (num_glyphs > STACK_GLYPH_SIZE) { glyph_buf = (WORD *) _cairo_malloc_ab (num_glyphs, sizeof(WORD)); dxy_buf = (int *) _cairo_malloc_abc (num_glyphs, sizeof(int), 2); } /* It is vital that dx values for dxy_buf are calculated from the delta of * _logical_ x coordinates (not user x coordinates) or else the sum of all * previous dx values may start to diverge from the current glyph's x * coordinate due to accumulated rounding error. As a result strings could * be painted shorter or longer than expected. */ user_x = glyphs[0].x; user_y = glyphs[0].y; cairo_matrix_transform_point(&device_to_logical, &user_x, &user_y); logical_x = _cairo_lround (user_x); logical_y = _cairo_lround (user_y); start_x = logical_x; start_y = logical_y; for (i = 0, j = 0; i < num_glyphs; ++i, j = 2 * i) { glyph_buf[i] = (WORD) glyphs[i].index; if (i == num_glyphs - 1) { dxy_buf[j] = 0; dxy_buf[j+1] = 0; } else { double next_user_x = glyphs[i+1].x; double next_user_y = glyphs[i+1].y; int next_logical_x, next_logical_y; cairo_matrix_transform_point(&device_to_logical, &next_user_x, &next_user_y); next_logical_x = _cairo_lround (next_user_x); next_logical_y = _cairo_lround (next_user_y); dxy_buf[j] = _cairo_lround (next_logical_x - logical_x); dxy_buf[j+1] = _cairo_lround (next_logical_y - logical_y); logical_x = next_logical_x; logical_y = next_logical_y; } } if (glyph_indexing) glyph_index_option = ETO_GLYPH_INDEX; else glyph_index_option = 0; win_result = ExtTextOutW(dst->dc, start_x, start_y, glyph_index_option | ETO_PDY, NULL, glyph_buf, num_glyphs, dxy_buf); if (!win_result) { _cairo_win32_print_gdi_error("_cairo_win32_surface_show_glyphs(ExtTextOutW failed)"); } RestoreDC(dst->dc, -1); if (glyph_buf != glyph_buf_stack) { free(glyph_buf); free(dxy_buf); } return (win_result) ? CAIRO_STATUS_SUCCESS : CAIRO_INT_STATUS_UNSUPPORTED; #else return CAIRO_INT_STATUS_UNSUPPORTED; #endif }