/** * cpml_segment_reverse: * @segment: a #CpmlSegment * * Reverses @segment in-place. The resulting rendering will be the same, * but with the primitives generated in reverse order. * * It is assumed that @segment has already been sanitized, e.g. when it * is returned by some CPML API or it is a cairo path already conforming * to the segment rules described in cpml_segment_from_cairo(). * * Since: 1.0 **/ void cpml_segment_reverse(CpmlSegment *segment) { cairo_path_data_t *data, *dst_data; size_t data_size; double end_x, end_y; int n, length; size_t n_points, n_point; const cairo_path_data_t *src_data; data_size = sizeof(cairo_path_data_t) * segment->num_data; data = malloc(data_size); src_data = segment->data; dst_data = data + segment->num_data; end_x = src_data[1].point.x; end_y = src_data[1].point.y; n = src_data->header.length; data->header.type = CPML_MOVE; data->header.length = n; while (n < segment->num_data) { src_data = segment->data + n; if (src_data->header.type == CPML_CLOSE) break; n_points = cpml_primitive_type_get_n_points(src_data->header.type); length = src_data->header.length; n += length; dst_data -= length; dst_data->header.type = src_data->header.type; dst_data->header.length = length; for (n_point = 1; n_point < n_points; ++n_point) { dst_data[n_points - n_point].point.x = end_x; dst_data[n_points - n_point].point.y = end_y; end_x = src_data[n_point].point.x; end_y = src_data[n_point].point.y; } /* Copy also the embedded data, if any */ if (n_points < length) { size_t size = (length - n_points) * sizeof(cairo_path_data_t); memcpy(dst_data + n_points, src_data + n_points, size); } } if (src_data->header.type == CPML_CLOSE) { memcpy(segment->data + segment->data->header.length, dst_data, data_size - ((char *) dst_data - (char *) data)); } else { memcpy(segment->data, data, data_size); } free(data); segment->data[1].point.x = end_x; segment->data[1].point.y = end_y; }
static gint _adg_primitive_length(CpmlPrimitiveType type) { if (type == CPML_CLOSE) return 1; else if (type == CPML_MOVE) return 2; return cpml_primitive_type_get_n_points(type); }
static void _adg_append_primitive(AdgPath *path, CpmlPrimitive *current) { AdgPathPrivate *data; cairo_path_data_t *path_data; CpmlPrimitiveType type; int length; gconstpointer old_data; gpointer new_data; data = path->data; path_data = current->data; length = path_data->header.length; type = path_data->header.type; /* Execute any pending operation */ _adg_do_operation(path, path_data); /* Append the path data to the internal path array */ old_data = (data->cairo.array)->data; data->cairo.array = g_array_append_vals(data->cairo.array, path_data, length); new_data = (data->cairo.array)->data; /* Set path data to point to the recently appended cairo_path_data_t * primitive: the first struct is the header */ path_data = (cairo_path_data_t *) new_data + (data->cairo.array)->len - length; if (type == CPML_MOVE) { /* Remap last and over, but do not change their content */ _adg_primitive_remap(&data->last, new_data, &data->last, old_data); _adg_primitive_remap(&data->over, new_data, &data->over, old_data); } else { /* Store the last primitive into over */ _adg_primitive_remap(&data->over, new_data, &data->last, old_data); /* Set the last primitive for subsequent binary operations */ /* TODO: the assumption path_data - 1 is the last point is not true * e.g. when there are embeeded data in primitives */ data->last.org = data->cp_is_valid ? path_data - 1 : NULL; data->last.segment = NULL; data->last.data = path_data; } data->cp_is_valid = type != CPML_CLOSE; if (data->cp_is_valid) { /* Save the last point in the current point */ size_t n = type == CPML_MOVE ? 1 : cpml_primitive_type_get_n_points(type) - 1; cpml_pair_from_cairo(&data->cp, &path_data[n]); } /* Invalidate cairo_path: should be recomputed */ _adg_clear_parent((AdgModel *) path); }
static void _cpml_method_type_get_n_points(void) { size_t n_points; n_points = cpml_primitive_type_get_n_points(CPML_MOVE); g_assert_cmpuint(n_points, ==, 0); n_points = cpml_primitive_type_get_n_points(CPML_LINE); g_assert_cmpuint(n_points, ==, 2); n_points = cpml_primitive_type_get_n_points(CPML_ARC); g_assert_cmpuint(n_points, ==, 3); n_points = cpml_primitive_type_get_n_points(CPML_CURVE); g_assert_cmpuint(n_points, ==, 4); n_points = cpml_primitive_type_get_n_points(CPML_CLOSE); g_assert_cmpuint(n_points, ==, 2); }
/* * reshape: * @segment: a #CpmlSegment * * Looks for the segment termination, that is the end of the underlying * cairo path or if the current primitive is a %CPML_MOVE or if the * last primitive was a %CPML_CLOSE. <structfield>num_data</structfield> * field is modified to properly point to the end of @segment. @segment * must have only one leading %CPML_MOVE and it is supposed to be non-empty, * conditions already imposed by ensure_one_leading_move(). * * This function also checks that all the components of @segment * are valid primitives. * * Returns: 1 on success, 0 on invalid primitive found. **/ static int reshape(CpmlSegment *segment) { cairo_path_data_t *data = segment->data; cairo_path_data_type_t type; int length, n_points, num_data = 0; /* Always include the trailing CPML_MOVE */ length = data->header.length; data += length; num_data += length; while (num_data < segment->num_data) { type = data->header.type; /* A CPML_MOVE is usually the start of the next segment */ if (type == CPML_MOVE) break; length = data->header.length; data += length; num_data += length; /* Ensure the next primitive is valid and has enough data points */ n_points = type == CPML_CLOSE ? 1 : cpml_primitive_type_get_n_points(type); if (length < 1 || n_points == 0 || length < n_points) return 0; /* A CPML_CLOSE ends the current segment */ if (type == CPML_CLOSE) break; } /* The sum of the primitive lengths must *not* be greater than * the whole segment length */ if (num_data > segment->num_data) return 0; segment->num_data = num_data; return 1; }