Beispiel #1
0
boost::optional<Geom::Point> Line::intersection_with_viewbox (SPDesktop *desktop)
{
    Geom::Rect vb = desktop->get_display_area();
    /* remaining viewbox corners */
    Geom::Point ul (vb.min()[Geom::X], vb.max()[Geom::Y]);
    Geom::Point lr (vb.max()[Geom::X], vb.min()[Geom::Y]);

    std::pair <Geom::Point, Geom::Point> e = side_of_intersection (vb.min(), lr, vb.max(), ul, this->pt, this->v_dir);
    if (e.first == e.second) {
        // perspective line lies outside the canvas
        return boost::optional<Geom::Point>();
    }

    Line line (e.first, e.second);
    return this->intersect (line);
}
Beispiel #2
0
Geom::Affine
sp_gradient_get_g2d_matrix(SPGradient const *gr, Geom::Affine const &ctm, Geom::Rect const &bbox)
{
    if (gr->getUnits() == SP_GRADIENT_UNITS_OBJECTBOUNDINGBOX) {
        return ( Geom::Scale(bbox.dimensions())
                 * Geom::Translate(bbox.min())
                 * Geom::Affine(ctm) );
    } else {
        return ctm;
    }
}
Beispiel #3
0
void FilterFlood::render_cairo(FilterSlot &slot)
{
    cairo_surface_t *input = slot.getcairo(_input);

    double r = SP_RGBA32_R_F(color);
    double g = SP_RGBA32_G_F(color);
    double b = SP_RGBA32_B_F(color);
    double a = opacity;

#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2)

    if (icc) {
        guchar ru, gu, bu;
        icc_color_to_sRGB(icc, &ru, &gu, &bu);
        r = SP_COLOR_U_TO_F(ru);
        g = SP_COLOR_U_TO_F(gu);
        b = SP_COLOR_U_TO_F(bu);
    }
#endif

    cairo_surface_t *out = ink_cairo_surface_create_same_size(input, CAIRO_CONTENT_COLOR_ALPHA);

    // Get filter primitive area in user units
    Geom::Rect fp = filter_primitive_area( slot.get_units() );

    // Convert to Cairo units
    Geom::Rect fp_cairo = fp * slot.get_units().get_matrix_user2pb();

    // Get area in slot (tile to fill)
    Geom::Rect sa = slot.get_slot_area();

    // Get overlap
    Geom::OptRect optoverlap = intersect( fp_cairo, sa );
    if( optoverlap ) {

        Geom::Rect overlap = *optoverlap;

        double dx = fp_cairo.min()[Geom::X] - sa.min()[Geom::X];
        double dy = fp_cairo.min()[Geom::Y] - sa.min()[Geom::Y];
        if( dx < 0.0 ) dx = 0.0;
        if( dy < 0.0 ) dy = 0.0;

        cairo_t *ct = cairo_create(out);
        cairo_set_source_rgba(ct, r, g, b, a);
        cairo_set_operator(ct, CAIRO_OPERATOR_SOURCE);
        cairo_rectangle(ct, dx, dy, overlap.width(), overlap.height() );
        cairo_fill(ct);
        cairo_destroy(ct);
    }

    slot.set(_output, out);
    cairo_surface_destroy(out);
}
/**
 * Given a Geom::Rect that may, for example, correspond to the bbox of an object,
 * this function fits the canvas to that rect by resizing the canvas
 * and translating the document root into position.
 */
void SPDocument::fitToRect(Geom::Rect const &rect)
{
    double const w = rect.width();
    double const h = rect.height();

    double const old_height = sp_document_height(this);
    SPUnit const &px(sp_unit_get_by_id(SP_UNIT_PX));
    sp_document_set_width(this, w, &px);
    sp_document_set_height(this, h, &px);

    Geom::Translate const tr(Geom::Point(0, (old_height - h))
                             - to_2geom(rect.min()));
    SP_GROUP(root)->translateChildItems(tr);
    SPNamedView *nv = sp_document_namedview(this, 0);
    if(nv) {
        Geom::Translate tr2(-rect.min());
        nv->translateGuides(tr2);

        // update the viewport so the drawing appears to stay where it was
        nv->scrollAllDesktops(-tr2[0], tr2[1], false);
    }
}
Beispiel #5
0
void
sp_gradient_set_gs2d_matrix(SPGradient *gr, Geom::Affine const &ctm,
                            Geom::Rect const &bbox, Geom::Affine const &gs2d)
{
    gr->gradientTransform = gs2d * ctm.inverse();
    if (gr->getUnits() == SP_GRADIENT_UNITS_OBJECTBOUNDINGBOX ) {
        gr->gradientTransform = ( gr->gradientTransform
                                  * Geom::Translate(-bbox.min())
                                  * Geom::Scale(bbox.dimensions()).inverse() );
    }
    gr->gradientTransform_set = TRUE;

    gr->requestModified(SP_OBJECT_MODIFIED_FLAG);
}
void FilterTile::render_cairo(FilterSlot &slot)
{
    // FIX ME!
    static bool tile_warning = false;
    if (!tile_warning) {
        g_warning("Renderer for feTile has non-optimal implementation, expect slowness and bugs.");
        tile_warning = true;
    }

    // Fixing isn't so easy as the Inkscape renderer breaks the canvas into "rendering" tiles for
    // faster rendering. (The "rendering" tiles are not the same as the tiles in this primitive.)
    // Only if the the feTile tile source falls inside the current "rendering" tile will the tile
    // image be available.

    // This input source contains only the "rendering" tile.
    cairo_surface_t *in = slot.getcairo(_input);

    // For debugging
    // static int i = 0;
    // ++i;
    // std::stringstream filename;
    // filename << "dump." << i << ".png";
    // cairo_surface_write_to_png( in, filename.str().c_str() );

    // This is the feTile source area as determined by the input primitive area (see SVG spec).
    Geom::Rect tile_area = slot.get_primitive_area(_input);

    if( tile_area.width() == 0.0 || tile_area.height() == 0.0 ) {

        slot.set(_output, in);
        std::cerr << "FileTile::render_cairo: tile has zero width or height" << std::endl;

    } else {

        cairo_surface_t *out = ink_cairo_surface_create_identical(in);
        // color_interpolation_filters for out same as in.
        copy_cairo_surface_ci(in, out);
        cairo_t *ct = cairo_create(out);

        // The rectangle of the "rendering" tile.
        Geom::Rect sa = slot.get_slot_area();

        Geom::Affine trans = slot.get_units().get_matrix_user2pb();

        // Create feTile tile ----------------

        // Get tile area in pixbuf units (tile transformed).
        Geom::Rect tt = tile_area * trans;

        // Shift between "rendering" tile and feTile tile
        Geom::Point shift = sa.min() - tt.min();

        // Create feTile tile surface
        cairo_surface_t *tile = cairo_surface_create_similar(in, cairo_surface_get_content(in),
                                tt.width(), tt.height());
        cairo_t *ct_tile = cairo_create(tile);
        cairo_set_source_surface(ct_tile, in, shift[Geom::X], shift[Geom::Y]);
        cairo_paint(ct_tile);

        // Paint tiles ------------------

        // For debugging
        // std::stringstream filename;
        // filename << "tile." << i << ".png";
        // cairo_surface_write_to_png( tile, filename.str().c_str() );

        // Determine number of feTile rows and columns
        Geom::Rect pr = filter_primitive_area( slot.get_units() );
        int tile_cols = ceil( pr.width()  / tile_area.width() );
        int tile_rows = ceil( pr.height() / tile_area.height() );

        // Do tiling (TO DO: restrict to slot area.)
        for( int col=0; col < tile_cols; ++col ) {
            for( int row=0; row < tile_rows; ++row ) {

                Geom::Point offset( col*tile_area.width(), row*tile_area.height() );
                offset *= trans;
                offset[Geom::X] -= trans[4];
                offset[Geom::Y] -= trans[5];

                cairo_set_source_surface(ct, tile, offset[Geom::X], offset[Geom::Y]);
                cairo_paint(ct);
            }
        }
        slot.set(_output, out);

        // Clean up
        cairo_destroy(ct);
        cairo_surface_destroy(out);
        cairo_destroy(ct_tile);
        cairo_surface_destroy(tile);
    }
}
/**
 * Creates a surface with the given logical and physical extents.
 * When a drawing context is created for this surface, its pixels
 * will cover the area under the given rectangle. IT will contain
 * the number of pixels specified by the second argument.
 * @param logbox Logical extents of the surface
 * @param pixdims Pixel dimensions of the surface.
 */
DrawingSurface::DrawingSurface(Geom::Rect const &logbox, Geom::IntPoint const &pixdims)
    : _surface(NULL)
    , _origin(logbox.min())
    , _scale(pixdims[X] / logbox.width(), pixdims[Y] / logbox.height())
    , _pixels(pixdims)
{}
Beispiel #8
0
std::vector<Geom::Point> Layout::createSelectionShape(iterator const &it_start, iterator const &it_end, Geom::Affine const &transform) const
{
    std::vector<Geom::Point> quads;
    unsigned char_index;
    unsigned end_char_index;

    if (it_start._char_index < it_end._char_index) {
        char_index = it_start._char_index;
        end_char_index = it_end._char_index;
    } else {
        char_index = it_end._char_index;
        end_char_index = it_start._char_index;
    }
    for ( ; char_index < end_char_index ; ) {
        if (_characters[char_index].in_glyph == -1) {
            char_index++;
            continue;
        }
        double char_rotation = _glyphs[_characters[char_index].in_glyph].rotation;
        unsigned span_index = _characters[char_index].in_span;

        Geom::Point top_left, bottom_right;
        if (_path_fitted || char_rotation != 0.0) {
            Geom::Rect box = characterBoundingBox(iterator(this, char_index), &char_rotation);
            top_left = box.min();
            bottom_right = box.max();
            char_index++;
        } else {   // for straight text we can be faster by combining all the character boxes in a span into one box
            double span_x = _spans[span_index].x_start + _spans[span_index].chunk(this).left_x;
            top_left[Geom::X] = span_x + _characters[char_index].x;
            while (char_index < end_char_index && _characters[char_index].in_span == span_index)
                char_index++;
            if (char_index == _characters.size() || _characters[char_index].in_span != span_index)
                bottom_right[Geom::X] = _spans[span_index].x_end + _spans[span_index].chunk(this).left_x;
            else
                bottom_right[Geom::X] = span_x + _characters[char_index].x;

            double baseline_y = _spans[span_index].line(this).baseline_y + _spans[span_index].baseline_shift;
            double vertical_scale = _glyphs.back().vertical_scale;

            if (_directions_are_orthogonal(_blockProgression(), TOP_TO_BOTTOM)) {
                double span_height = vertical_scale * (_spans[span_index].line_height.ascent + _spans[span_index].line_height.descent);
                top_left[Geom::Y] = top_left[Geom::X];
                top_left[Geom::X] = baseline_y - span_height * 0.5;
                bottom_right[Geom::Y] = bottom_right[Geom::X];
                bottom_right[Geom::X] = baseline_y + span_height * 0.5;
            } else {
                top_left[Geom::Y] =  baseline_y - vertical_scale * _spans[span_index].line_height.ascent;
                bottom_right[Geom::Y] = baseline_y + vertical_scale * _spans[span_index].line_height.descent;
            }
        }

        Geom::Rect char_box(top_left, bottom_right);
        if (char_box.dimensions()[Geom::X] == 0.0 || char_box.dimensions()[Geom::Y] == 0.0)
            continue;
        Geom::Point center_of_rotation((top_left[Geom::X] + bottom_right[Geom::X]) * 0.5,
                                       top_left[Geom::Y] + _spans[span_index].line_height.ascent);
        Geom::Affine total_transform = Geom::Translate(-center_of_rotation) * Geom::Rotate(char_rotation) * Geom::Translate(center_of_rotation) * transform;
        for(int i = 0; i < 4; i ++)
            quads.push_back(char_box.corner(i) * total_transform);
    }
    return quads;
}
void FilterImage::render_cairo(FilterSlot &slot)
{
    if (!feImageHref)
        return;

    //cairo_surface_t *input = slot.getcairo(_input);

    // Viewport is filter primitive area (in user coordinates).
    // Note: viewport calculation in non-trivial. Do not rely
    // on get_matrix_primitiveunits2pb().
    Geom::Rect vp = filter_primitive_area( slot.get_units() );
    slot.set_primitive_area(_output, vp); // Needed for tiling

    double feImageX      = vp.min()[Geom::X];
    double feImageY      = vp.min()[Geom::Y];
    double feImageWidth  = vp.width();
    double feImageHeight = vp.height();

    // feImage is suppose to use the same parameters as a normal SVG image.
    // If a width or height is set to zero, the image is not suppose to be displayed.
    // This does not seem to be what Firefox or Opera does, nor does the W3C displacement
    // filter test expect this behavior. If the width and/or height are zero, we use
    // the width and height of the object bounding box.
    Geom::Affine m = slot.get_units().get_matrix_user2filterunits().inverse();
    Geom::Point bbox_00 = Geom::Point(0,0) * m;
    Geom::Point bbox_w0 = Geom::Point(1,0) * m;
    Geom::Point bbox_0h = Geom::Point(0,1) * m;
    double bbox_width = Geom::distance(bbox_00, bbox_w0);
    double bbox_height = Geom::distance(bbox_00, bbox_0h);

    if( feImageWidth  == 0 ) feImageWidth  = bbox_width;
    if( feImageHeight == 0 ) feImageHeight = bbox_height;

    // Internal image, like <use>
    if (from_element) {
        if (!SVGElem) return;

        // TODO: do not recreate the rendering tree every time
        // TODO: the entire thing is a hack, we should give filter primitives an "update" method
        //       like the one for DrawingItems
        document->ensureUpToDate();

        Drawing drawing;
        Geom::OptRect optarea = SVGElem->visualBounds();
        if (!optarea) return;

        unsigned const key = SPItem::display_key_new(1);
        DrawingItem *ai = SVGElem->invoke_show(drawing, key, SP_ITEM_SHOW_DISPLAY);
        if (!ai) {
            g_warning("feImage renderer: error creating DrawingItem for SVG Element");
            return;
        }
        drawing.setRoot(ai);

        Geom::Rect area = *optarea;
        Geom::Affine user2pb = slot.get_units().get_matrix_user2pb();

        /* FIXME: These variables are currently unused.  Why were they calculated?
        double scaleX = feImageWidth / area.width();
        double scaleY = feImageHeight / area.height();
        */

        Geom::Rect sa = slot.get_slot_area();
        cairo_surface_t *out = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
            sa.width(), sa.height());
        Inkscape::DrawingContext dc(out, sa.min());
        dc.transform(user2pb); // we are now in primitive units
        dc.translate(feImageX, feImageY);
//        dc.scale(scaleX, scaleY);  No scaling should be done

        Geom::IntRect render_rect = area.roundOutwards();
//        dc.translate(render_rect.min());  This seems incorrect

        // Update to renderable state
        drawing.update(render_rect);
        drawing.render(dc, render_rect);
        SVGElem->invoke_hide(key);

        // For the moment, we'll assume that any image is in sRGB color space
        set_cairo_surface_ci(out, SP_CSS_COLOR_INTERPOLATION_SRGB);

        slot.set(_output, out);
        cairo_surface_destroy(out);
        return;
    }

    // External image, like <image>
    if (!image && !broken_ref) {
        broken_ref = true;

        /* TODO: If feImageHref is absolute, then use that (preferably handling the
         * case that it's not a file URI).  Otherwise, go up the tree looking
         * for an xml:base attribute, and use that as the base URI for resolving
         * the relative feImageHref URI.  Otherwise, if document->base is valid,
         * then use that as the base URI.  Otherwise, use feImageHref directly
         * (i.e. interpreting it as relative to our current working directory).
         * (See http://www.w3.org/TR/xmlbase/#resolution .) */
        gchar *fullname = feImageHref;
        if ( !g_file_test( fullname, G_FILE_TEST_EXISTS ) ) {
            // Try to load from relative postion combined with document base
            if( document ) {
                fullname = g_build_filename( document->getBase(), feImageHref, NULL );
            }
        }
        if ( !g_file_test( fullname, G_FILE_TEST_EXISTS ) ) {
            // Should display Broken Image png.
            g_warning("FilterImage::render: Can not find: %s", feImageHref  );
            return;
        }
        image = Inkscape::Pixbuf::create_from_file(fullname);
        if( fullname != feImageHref ) g_free( fullname );

        if ( !image ) {
            g_warning("FilterImage::render: failed to load image: %s", feImageHref);
            return;
        }

        broken_ref = false;
    }

    if (broken_ref) {
        return;
    }

    cairo_surface_t *image_surface = image->getSurfaceRaw();

    Geom::Rect sa = slot.get_slot_area();
    cairo_surface_t *out = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
        sa.width(), sa.height());

    // For the moment, we'll assume that any image is in sRGB color space
    // set_cairo_surface_ci(out, SP_CSS_COLOR_INTERPOLATION_SRGB);
    // This seemed like a sensible thing to do but it breaks filters-displace-01-f.svg

    cairo_t *ct = cairo_create(out);
    cairo_translate(ct, -sa.min()[Geom::X], -sa.min()[Geom::Y]);

    // now ct is in pb coordinates, note the feWidth etc. are in user units
    ink_cairo_transform(ct, slot.get_units().get_matrix_user2pb());

    // now ct is in the coordinates of feImageX etc.

    // Now that we have the viewport, we must map image inside.
    // Partially copied from sp-image.cpp.

    // Do nothing if preserveAspectRatio is "none".
    if( aspect_align != SP_ASPECT_NONE ) {

        // Check aspect ratio of image vs. viewport
        double feAspect = feImageHeight/feImageWidth;
        double aspect = (double)image->height()/(double)image->width();
        bool ratio = (feAspect < aspect);

        double ax, ay; // Align side
        switch( aspect_align ) {
            case SP_ASPECT_XMIN_YMIN:
                ax = 0.0;
                ay = 0.0;
                break;
            case SP_ASPECT_XMID_YMIN:
                ax = 0.5;
                ay = 0.0;
                break;
            case SP_ASPECT_XMAX_YMIN:
                ax = 1.0;
                ay = 0.0;
                break;
            case SP_ASPECT_XMIN_YMID:
                ax = 0.0;
                ay = 0.5;
                break;
            case SP_ASPECT_XMID_YMID:
                ax = 0.5;
                ay = 0.5;
                break;
            case SP_ASPECT_XMAX_YMID:
                ax = 1.0;
                ay = 0.5;
                break;
            case SP_ASPECT_XMIN_YMAX:
                ax = 0.0;
                ay = 1.0;
                break;
            case SP_ASPECT_XMID_YMAX:
                ax = 0.5;
                ay = 1.0;
                break;
            case SP_ASPECT_XMAX_YMAX:
                ax = 1.0;
                ay = 1.0;
                break;
            default:
                ax = 0.0;
                ay = 0.0;
                break;
        }

        if( aspect_clip == SP_ASPECT_SLICE ) {
            // image clipped by viewbox

            if( ratio ) {
                // clip top/bottom
                feImageY -= ay * (feImageWidth * aspect - feImageHeight);
                feImageHeight = feImageWidth * aspect;
            } else {
                // clip sides
                feImageX -= ax * (feImageHeight / aspect - feImageWidth); 
                feImageWidth = feImageHeight / aspect;
            }

        } else {
            // image fits into viewbox

            if( ratio ) {
                // fit to height
                feImageX += ax * (feImageWidth - feImageHeight / aspect );
                feImageWidth = feImageHeight / aspect;
            } else {
                // fit to width
                feImageY += ay * (feImageHeight - feImageWidth * aspect);
                feImageHeight = feImageWidth * aspect;
            }
        }
    }

    double scaleX = feImageWidth / image->width();
    double scaleY = feImageHeight / image->height();

    cairo_translate(ct, feImageX, feImageY);
    cairo_scale(ct, scaleX, scaleY);
    cairo_set_source_surface(ct, image_surface, 0, 0);
    cairo_paint(ct);
    cairo_destroy(ct);

    slot.set(_output, out);
}
Beispiel #10
0
int main(int argc, char **argv) {
    char const *const filename = (argc >= 2
                                  ? argv[1]
                                  : "toy.svgd");
    FILE* f = fopen(filename, "r");
    if (!f) {
        perror(filename);
        return 1;
    }
    display_path = read_svgd(f);

    Geom::Rect r = display_path.bbox();
    
    display_path = display_path*Geom::translate(-r.min());
    Geom::scale sc(r.max() - r.min());
    display_path = display_path*(sc.inverse()*Geom::scale(500,500));
    
    gtk_init (&argc, &argv);

    gdk_rgb_init();

    GtkWidget* window = gtk_window_new(GTK_WINDOW_TOPLEVEL);

    gtk_window_set_title(GTK_WINDOW(window), "text toy");

    gtk_window_set_policy(GTK_WINDOW(window), TRUE, TRUE, TRUE);

    gtk_signal_connect(GTK_OBJECT(window),
                       "delete_event",
                       GTK_SIGNAL_FUNC(delete_event_cb),
                       NULL);

    gtk_widget_push_visual(gdk_rgb_get_visual());
    gtk_widget_push_colormap(gdk_rgb_get_cmap());
    canvas = gtk_drawing_area_new();

    gtk_signal_connect(GTK_OBJECT (canvas),
                       "expose_event",
                       GTK_SIGNAL_FUNC(expose_event),
                       0);
    gtk_widget_add_events(canvas, (GDK_BUTTON_PRESS_MASK |
                                   GDK_BUTTON_RELEASE_MASK |
                                   GDK_KEY_PRESS_MASK    |
                                   GDK_POINTER_MOTION_MASK));
    gtk_signal_connect(GTK_OBJECT (canvas),
                       "button_press_event",
                       GTK_SIGNAL_FUNC(mouse_event),
                       0);
    gtk_signal_connect(GTK_OBJECT (canvas),
                       "button_release_event",
                       GTK_SIGNAL_FUNC(mouse_release_event),
                       0);
    gtk_signal_connect(GTK_OBJECT (canvas),
                       "motion_notify_event",
                       GTK_SIGNAL_FUNC(mouse_motion_event),
                       0);
    gtk_signal_connect(GTK_OBJECT(canvas),
                       "key_press_event",
                       GTK_SIGNAL_FUNC(key_release_event),
                       0);

    gtk_widget_pop_colormap();
    gtk_widget_pop_visual();

    GtkWidget *vb = gtk_vbox_new(0, 0);


    gtk_container_add(GTK_CONTAINER(window), vb);

    gtk_box_pack_start(GTK_BOX(vb), canvas, TRUE, TRUE, 0);

    gtk_window_set_default_size(GTK_WINDOW(window), 600, 600);

    gtk_widget_show_all(window);

    dash_gc = gdk_gc_new(canvas->window);
    gint8 dash_list[] = {4, 4};
    gdk_gc_set_dashes(dash_gc, 0, dash_list, 2);
    GdkColor colour;
    colour.red = 0xffff;
    colour.green = 0xffff;
    colour.blue = 0xffff;

    plain_gc = gdk_gc_new(canvas->window);
    
    //gdk_gc_set_rgb_fg_color(dash_gc, &colour);
    gdk_rgb_find_color(gtk_widget_get_colormap(canvas), &colour);
    gdk_window_set_background(canvas->window, &colour);
    gdk_gc_set_line_attributes(dash_gc, 1, GDK_LINE_ON_OFF_DASH,
                               GDK_CAP_BUTT,GDK_JOIN_MITER);

    /* Make sure the canvas can receive key press events. */
    GTK_WIDGET_SET_FLAGS(canvas, GTK_CAN_FOCUS);
    assert(GTK_WIDGET_CAN_FOCUS(canvas));
    gtk_widget_grab_focus(canvas);
    assert(gtk_widget_is_focus(canvas));

    gtk_main();

    return 0;
}