Beispiel #1
0
/**
 * 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;
}
Beispiel #2
0
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);
}
Beispiel #3
0
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);
}
Beispiel #4
0
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);
}
Beispiel #5
0
/*
 * 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;
}