Code

Fixed SVG compliance problems with feMorphology (bug 181995 at least)
[inkscape.git] / src / display / inkscape-cairo.cpp
1 /*
2  * Helper functions to use cairo with inkscape
3  *
4  * Copyright (C) 2007 bulia byak
5  *
6  * Released under GNU GPL
7  *
8  */
10 #include <cairo.h>
12 #ifdef HAVE_CONFIG_H
13 # include <config.h>
14 #endif
15 #include <libnr/n-art-bpath.h>
16 #include <libnr/nr-matrix-ops.h>
17 #include <libnr/nr-matrix-fns.h>
18 #include <libnr/nr-pixblock.h>
19 #include "../style.h"
20 #include "nr-arena.h"
23 /** Creates a cairo context to render to the given pixblock on the given area */
24 cairo_t *
25 nr_create_cairo_context (NRRectL *area, NRPixBlock *pb)
26 {
27     if (!nr_rect_l_test_intersect (&pb->area, area)) 
28         return NULL;
30     NRRectL clip;
31     nr_rect_l_intersect (&clip, &pb->area, area);
32     unsigned char *dpx = NR_PIXBLOCK_PX (pb) + (clip.y0 - pb->area.y0) * pb->rs + NR_PIXBLOCK_BPP (pb) * (clip.x0 - pb->area.x0);
33     int width = area->x1 - area->x0;
34     int height = area->y1 - area->y0;
35     // even though cairo cannot draw in nonpremul mode, select ARGB32 for R8G8B8A8N as the closest; later eliminate R8G8B8A8N everywhere
36     cairo_surface_t* cst = cairo_image_surface_create_for_data
37         (dpx,
38          ((pb->mode == NR_PIXBLOCK_MODE_R8G8B8A8P || pb->mode == NR_PIXBLOCK_MODE_R8G8B8A8N) ? CAIRO_FORMAT_ARGB32 : (pb->mode == NR_PIXBLOCK_MODE_R8G8B8? CAIRO_FORMAT_RGB24 : CAIRO_FORMAT_A8)),
39          width,
40          height,
41          pb->rs);
42     cairo_t *ct = cairo_create (cst);
44     return ct;
45 }
47 /** Feeds path-creating calls to the cairo context translating them from the SPCurve, with the given transform and shift */
48 void
49 feed_curve_to_cairo (cairo_t *ct, NArtBpath const *bpath, NR::Matrix trans, NR::Maybe<NR::Rect> area, bool optimize_stroke, double stroke_width)
50 {
51     NR::Point next(0,0), last(0,0);
52     if (!area || area->isEmpty()) 
53         return;
54     NR::Point shift = area->min();
55     NR::Rect view = *area;
56     view.growBy (stroke_width);
57     NR::Rect swept;
58     bool  closed = false;
59     NR::Point startpath(0,0);
60     for (int i = 0; bpath[i].code != NR_END; i++) {
61         switch (bpath[i].code) {
62             case NR_MOVETO_OPEN:
63             case NR_MOVETO:
64                 if (closed) {
65                     // we cannot use close_path because some of the curves/lines may have been optimized out
66                     cairo_line_to(ct, startpath[NR::X], startpath[NR::Y]);
67                 }
68                 next[NR::X] = bpath[i].x3;
69                 next[NR::Y] = bpath[i].y3;
70                 next *= trans;
71                 last = next;
72                 next -= shift;
73                 if (bpath[i].code == NR_MOVETO) {
74                     // remember the start point of the subpath, for closing it later
75                     closed = true;
76                     startpath = next;
77                 } else {
78                     closed = false;
79                 }
80                 cairo_move_to(ct, next[NR::X], next[NR::Y]);
81                 break;
83             case NR_LINETO:
84                 next[NR::X] = bpath[i].x3;
85                 next[NR::Y] = bpath[i].y3;
86                 next *= trans;
87                 if (optimize_stroke) {
88                     swept = NR::Rect(last, next);
89                     //std::cout << "swept: " << swept;
90                     //std::cout << "view: " << view;
91                     //std::cout << "intersects? " << (swept.intersects(view)? "YES" : "NO") << "\n";
92                 }
93                 last = next;
94                 next -= shift;
95                 if (!optimize_stroke || swept.intersects(view)) 
96                     cairo_line_to(ct, next[NR::X], next[NR::Y]);
97                 else 
98                     cairo_move_to(ct, next[NR::X], next[NR::Y]);
99                 break;
101             case NR_CURVETO: {
102                 NR::Point  tm1, tm2, tm3;
103                 tm1[0]=bpath[i].x1;
104                 tm1[1]=bpath[i].y1;
105                 tm2[0]=bpath[i].x2;
106                 tm2[1]=bpath[i].y2;
107                 tm3[0]=bpath[i].x3;
108                 tm3[1]=bpath[i].y3;
109                 tm1 *= trans;
110                 tm2 *= trans;
111                 tm3 *= trans;
112                 if (optimize_stroke) {
113                     swept = NR::Rect(last, last);
114                     swept.expandTo(tm1);
115                     swept.expandTo(tm2);
116                     swept.expandTo(tm3);
117                 }
118                 last = tm3;
119                 tm1 -= shift;
120                 tm2 -= shift;
121                 tm3 -= shift;
122                 if (!optimize_stroke || swept.intersects(view)) 
123                     cairo_curve_to (ct, tm1[NR::X], tm1[NR::Y], tm2[NR::X], tm2[NR::Y], tm3[NR::X], tm3[NR::Y]);
124                 else
125                     cairo_move_to(ct, tm3[NR::X], tm3[NR::Y]);
126                 break;
127             }
129             default:
130                 break;
131         }
132     }
136 /*
137   Local Variables:
138   mode:c++
139   c-file-style:"stroustrup"
140   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
141   indent-tabs-mode:nil
142   fill-column:99
143   End:
144 */
145 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :