Code

use LoadPathVector instead of LoadArtBPath everywhere
[inkscape.git] / src / display / canvas-bpath.cpp
1 #define __SP_CANVAS_BPATH_C__
3 /*
4  * Simple bezier bpath CanvasItem for inkscape
5  *
6  * Authors:
7  *   Lauris Kaplinski <lauris@ximian.com>
8  *
9  * Copyright (C) 2001 Lauris Kaplinski and Ximian, Inc.
10  *
11  * Released under GNU GPL
12  *
13  */
15 #ifdef HAVE_CONFIG_H
16 # include "config.h"
17 #endif
18 #include "sp-canvas-util.h"
19 #include "canvas-bpath.h"
20 #include "display/display-forward.h"
21 #include "display/curve.h"
22 #include <livarot/Shape.h>
23 #include <livarot/Path.h>
24 #include <livarot/int-line.h>
25 #include <livarot/BitLigne.h>
26 #include <libnr/nr-pixops.h>
27 #include <libnr/nr-convert2geom.h>
29 void nr_pixblock_render_bpath_rgba (Shape* theS,uint32_t color,NRRectL &area,char* destBuf,int stride);
31 static void sp_canvas_bpath_class_init (SPCanvasBPathClass *klass);
32 static void sp_canvas_bpath_init (SPCanvasBPath *path);
33 static void sp_canvas_bpath_destroy (GtkObject *object);
35 static void sp_canvas_bpath_update (SPCanvasItem *item, NR::Matrix const &affine, unsigned int flags);
36 static void sp_canvas_bpath_render (SPCanvasItem *item, SPCanvasBuf *buf);
37 static double sp_canvas_bpath_point (SPCanvasItem *item, NR::Point p, SPCanvasItem **actual_item);
39 static SPCanvasItemClass *parent_class;
41 GtkType
42 sp_canvas_bpath_get_type (void)
43 {
44     static GtkType type = 0;
45     if (!type) {
46         GtkTypeInfo info = {
47             (gchar *)"SPCanvasBPath",
48             sizeof (SPCanvasBPath),
49             sizeof (SPCanvasBPathClass),
50             (GtkClassInitFunc) sp_canvas_bpath_class_init,
51             (GtkObjectInitFunc) sp_canvas_bpath_init,
52             NULL, NULL, NULL
53         };
54         type = gtk_type_unique (SP_TYPE_CANVAS_ITEM, &info);
55     }
56     return type;
57 }
59 static void
60 sp_canvas_bpath_class_init (SPCanvasBPathClass *klass)
61 {
62     GtkObjectClass *object_class;
63     SPCanvasItemClass *item_class;
65     object_class = GTK_OBJECT_CLASS (klass);
66     item_class = (SPCanvasItemClass *) klass;
68     parent_class = (SPCanvasItemClass*)gtk_type_class (SP_TYPE_CANVAS_ITEM);
70     object_class->destroy = sp_canvas_bpath_destroy;
72     item_class->update = sp_canvas_bpath_update;
73     item_class->render = sp_canvas_bpath_render;
74     item_class->point = sp_canvas_bpath_point;
75 }
77 static void
78 sp_canvas_bpath_init (SPCanvasBPath * bpath)
79 {
80     bpath->fill_rgba = 0x000000ff;
81     bpath->fill_rule = SP_WIND_RULE_EVENODD;
83     bpath->stroke_rgba = 0x00000000;
84     bpath->stroke_width = 1.0;
85     bpath->stroke_linejoin = SP_STROKE_LINEJOIN_MITER;
86     bpath->stroke_linecap = SP_STROKE_LINECAP_BUTT;
87     bpath->stroke_miterlimit = 11.0;
89     bpath->fill_shp=NULL;
90     bpath->stroke_shp=NULL;
91 }
93 static void
94 sp_canvas_bpath_destroy (GtkObject *object)
95 {
96     SPCanvasBPath *cbp = SP_CANVAS_BPATH (object);
97     if (cbp->fill_shp) {
98         delete cbp->fill_shp;
99         cbp->fill_shp = NULL;
100     }
102     if (cbp->stroke_shp) {
103         delete cbp->stroke_shp;
104         cbp->stroke_shp = NULL;
105     }
106     if (cbp->curve) {
107         cbp->curve = cbp->curve->unref();
108     }
110     if (GTK_OBJECT_CLASS (parent_class)->destroy)
111         (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
114 static void
115 sp_canvas_bpath_update (SPCanvasItem *item, NR::Matrix const &affine, unsigned int flags)
117     SPCanvasBPath *cbp = SP_CANVAS_BPATH (item);
119     sp_canvas_request_redraw (item->canvas, (int)item->x1, (int)item->y1, (int)item->x2, (int)item->y2);
121     if (((SPCanvasItemClass *) parent_class)->update)
122         ((SPCanvasItemClass *) parent_class)->update (item, affine, flags);
124     sp_canvas_item_reset_bounds (item);
126     if (cbp->fill_shp) {
127         delete cbp->fill_shp;
128         cbp->fill_shp = NULL;
129     }
131     if (cbp->stroke_shp) {
132         delete cbp->stroke_shp;
133         cbp->stroke_shp = NULL;
134     }
135     if (!cbp->curve) return;
137     NRRect dbox;
139     dbox.x0 = dbox.y0 = 0.0;
140     dbox.x1 = dbox.y1 = -1.0;
142     if ((cbp->fill_rgba & 0xff) || (cbp->stroke_rgba & 0xff)) {
143         Path*  thePath=new Path;
144         thePath->LoadPathVector(cbp->curve->get_pathvector(), to_2geom(affine), true);
145         thePath->Convert(0.25);
146         if ((cbp->fill_rgba & 0xff) && (cbp->curve->get_length() > 2)) {
147             Shape* theShape=new Shape;
148             thePath->Fill(theShape,0);
149             if ( cbp->fill_shp == NULL ) cbp->fill_shp=new Shape;
150             if ( cbp->fill_rule == SP_WIND_RULE_EVENODD ) {
151                 cbp->fill_shp->ConvertToShape(theShape,fill_oddEven);
152             } else {
153                 cbp->fill_shp->ConvertToShape(theShape,fill_nonZero);
154             }
155             delete theShape;
156             cbp->fill_shp->CalcBBox();
157             if ( cbp->fill_shp->leftX < cbp->fill_shp->rightX ) {
158                 if ( dbox.x0 >= dbox.x1 ) {
159                     dbox.x0 = cbp->fill_shp->leftX; dbox.x1 = cbp->fill_shp->rightX;
160                     dbox.y0 = cbp->fill_shp->topY; dbox.y1 = cbp->fill_shp->bottomY;
161                 } else {
162                     if ( cbp->fill_shp->leftX < dbox.x0 ) dbox.x0=cbp->fill_shp->leftX;
163                     if ( cbp->fill_shp->rightX > dbox.x1 ) dbox.x1=cbp->fill_shp->rightX;
164                     if ( cbp->fill_shp->topY < dbox.y0 ) dbox.y0=cbp->fill_shp->topY;
165                     if ( cbp->fill_shp->bottomY > dbox.y1 ) dbox.y1=cbp->fill_shp->bottomY;
166                 }
167             }
168         }
169         if ((cbp->stroke_rgba & 0xff) && (cbp->curve->get_length() > 1)) {
170             JoinType join=join_straight;
171 //      Shape* theShape=new Shape;
172             ButtType butt=butt_straight;
173             if ( cbp->stroke_shp == NULL ) cbp->stroke_shp=new Shape;
174             if ( cbp->stroke_linecap == SP_STROKE_LINECAP_BUTT ) butt=butt_straight;
175             if ( cbp->stroke_linecap == SP_STROKE_LINECAP_ROUND ) butt=butt_round;
176             if ( cbp->stroke_linecap == SP_STROKE_LINECAP_SQUARE ) butt=butt_square;
177             if ( cbp->stroke_linejoin == SP_STROKE_LINEJOIN_MITER ) join=join_pointy;
178             if ( cbp->stroke_linejoin == SP_STROKE_LINEJOIN_ROUND ) join=join_round;
179             if ( cbp->stroke_linejoin == SP_STROKE_LINEJOIN_BEVEL ) join=join_straight;
180             thePath->Stroke(cbp->stroke_shp,false,0.5*cbp->stroke_width, join,butt,cbp->stroke_width*cbp->stroke_miterlimit );
181             //     thePath->Stroke(theShape,false,0.5*cbp->stroke_width, join,butt,cbp->stroke_width*cbp->stroke_miterlimit );
182             //     cbp->stroke_shp->ConvertToShape(theShape,fill_nonZero);
184             cbp->stroke_shp->CalcBBox();
185             if ( cbp->stroke_shp->leftX < cbp->stroke_shp->rightX ) {
186                 if ( dbox.x0 >= dbox.x1 ) {
187                     dbox.x0 = cbp->stroke_shp->leftX;dbox.x1 = cbp->stroke_shp->rightX;
188                     dbox.y0 = cbp->stroke_shp->topY;dbox.y1 = cbp->stroke_shp->bottomY;
189                 } else {
190                     if ( cbp->stroke_shp->leftX < dbox.x0 ) dbox.x0 = cbp->stroke_shp->leftX;
191                     if ( cbp->stroke_shp->rightX > dbox.x1 ) dbox.x1 = cbp->stroke_shp->rightX;
192                     if ( cbp->stroke_shp->topY < dbox.y0 ) dbox.y0 = cbp->stroke_shp->topY;
193                     if ( cbp->stroke_shp->bottomY > dbox.y1 ) dbox.y1 = cbp->stroke_shp->bottomY;
194                 }
195             }
196 //      delete theShape;
197         }
198         delete thePath;
199     }
202     item->x1 = (int)dbox.x0;
203     item->y1 = (int)dbox.y0;
204     item->x2 = (int)dbox.x1;
205     item->y2 = (int)dbox.y1;
207     sp_canvas_request_redraw (item->canvas, (int)item->x1, (int)item->y1, (int)item->x2, (int)item->y2);
210 static void
211 sp_canvas_bpath_render (SPCanvasItem *item, SPCanvasBuf *buf)
213     SPCanvasBPath *cbp = SP_CANVAS_BPATH (item);
215     sp_canvas_prepare_buffer(buf);
217     NRRectL  area;
218     area.x0=buf->rect.x0;
219     area.x1=buf->rect.x1;
220     area.y0=buf->rect.y0;
221     area.y1=buf->rect.y1;
222     if ( cbp->fill_shp ) {
223         nr_pixblock_render_bpath_rgba (cbp->fill_shp,cbp->fill_rgba,area,(char*)buf->buf, buf->buf_rowstride);
224     }
225     if ( cbp->stroke_shp ) {
226         nr_pixblock_render_bpath_rgba (cbp->stroke_shp,cbp->stroke_rgba,area,(char*)buf->buf, buf->buf_rowstride);
227     }
231 #define BIGVAL 1e18
233 static double
234 sp_canvas_bpath_point (SPCanvasItem *item, NR::Point p, SPCanvasItem **actual_item)
236     SPCanvasBPath *cbp = SP_CANVAS_BPATH (item);
238     if (cbp->fill_shp && (cbp->fill_shp->PtWinding(p) > 0 )) {
239         *actual_item = item;
240         return 0.0;
241     }
242     if (cbp->stroke_shp ) {
243         if (cbp->stroke_shp->PtWinding(p) > 0 ) {
244             *actual_item = item;
245             return 0.0;
246         }
247         return distance(cbp->stroke_shp, p);
248     }
249     if (cbp->fill_shp) {
250         return distance(cbp->fill_shp, p);
251     }
253     return BIGVAL;
256 SPCanvasItem *
257 sp_canvas_bpath_new (SPCanvasGroup *parent, SPCurve *curve)
259     g_return_val_if_fail (parent != NULL, NULL);
260     g_return_val_if_fail (SP_IS_CANVAS_GROUP (parent), NULL);
262     SPCanvasItem *item = sp_canvas_item_new (parent, SP_TYPE_CANVAS_BPATH, NULL);
264     sp_canvas_bpath_set_bpath (SP_CANVAS_BPATH (item), curve);
266     return item;
269 void
270 sp_canvas_bpath_set_bpath (SPCanvasBPath *cbp, SPCurve *curve)
272     g_return_if_fail (cbp != NULL);
273     g_return_if_fail (SP_IS_CANVAS_BPATH (cbp));
275     if (cbp->curve) {
276         cbp->curve = cbp->curve->unref();
277     }
279     if (curve) {
280         cbp->curve = curve->ref();
281     }
283     sp_canvas_item_request_update (SP_CANVAS_ITEM (cbp));
286 void
287 sp_canvas_bpath_set_fill (SPCanvasBPath *cbp, guint32 rgba, SPWindRule rule)
289     g_return_if_fail (cbp != NULL);
290     g_return_if_fail (SP_IS_CANVAS_BPATH (cbp));
292     cbp->fill_rgba = rgba;
293     cbp->fill_rule = rule;
295     sp_canvas_item_request_update (SP_CANVAS_ITEM (cbp));
298 void
299 sp_canvas_bpath_set_stroke (SPCanvasBPath *cbp, guint32 rgba, gdouble width, SPStrokeJoinType join, SPStrokeCapType cap)
301     g_return_if_fail (cbp != NULL);
302     g_return_if_fail (SP_IS_CANVAS_BPATH (cbp));
304     cbp->stroke_rgba = rgba;
305     cbp->stroke_width = MAX (width, 0.1);
306     cbp->stroke_linejoin = join;
307     cbp->stroke_linecap = cap;
309     sp_canvas_item_request_update (SP_CANVAS_ITEM (cbp));
314 static void
315 bpath_run_A8_OR (raster_info &dest,void *data,int st,float vst,int en,float ven)
317     union {
318         uint8_t  comp[4];
319         uint32_t col;
320     } tempCol;
321     if ( st >= en ) return;
322     tempCol.col=*(uint32_t*)data;
324     unsigned int r, g, b, a;
325     r = NR_RGBA32_R (tempCol.col);
326     g = NR_RGBA32_G (tempCol.col);
327     b = NR_RGBA32_B (tempCol.col);
328     a = NR_RGBA32_A (tempCol.col);
329     if (a == 0) return;
331     vst*=a;
332     ven*=a;
334     if ( vst < 0 ) vst=0;
335     if ( vst > 255 ) vst=255;
336     if ( ven < 0 ) ven=0;
337     if ( ven > 255 ) ven=255;
338     float      sv=vst;
339     float      dv=ven-vst;
340     int        len=en-st;
341     uint8_t*   d=(uint8_t*)dest.buffer;
343     d+=3*(st-dest.startPix);
344     if ( fabs(dv) < 0.001 ) {
345         if ( sv > 249.999 ) {
346             /* Simple copy */
347             while (len > 0) {
348                 d[0] = NR_COMPOSEN11_1111 (r, 255, d[0]);
349                 d[1] = NR_COMPOSEN11_1111 (g, 255, d[1]);
350                 d[2] = NR_COMPOSEN11_1111 (b, 255, d[2]);
351                 d += 3;
352                 len -= 1;
353             }
354         } else {
355             unsigned int c0_24=(int)sv;
356             c0_24&=0xFF;
357             while (len > 0) {
358                 d[0] = NR_COMPOSEN11_1111 (r, c0_24, d[0]);
359                 d[1] = NR_COMPOSEN11_1111 (g, c0_24, d[1]);
360                 d[2] = NR_COMPOSEN11_1111 (b, c0_24, d[2]);
361                 d += 3;
362                 len -= 1;
363             }
364         }
365     } else {
366         if ( en <= st+1 ) {
367             sv=0.5*(vst+ven);
368             unsigned int c0_24=(int)sv;
369             c0_24&=0xFF;
370             d[0] = NR_COMPOSEN11_1111 (r, c0_24, d[0]);
371             d[1] = NR_COMPOSEN11_1111 (g, c0_24, d[1]);
372             d[2] = NR_COMPOSEN11_1111 (b, c0_24, d[2]);
373         } else {
374             dv/=len;
375             sv+=0.5*dv; // correction trapezoidale
376             sv*=65536;
377             dv*=65536;
378             int c0_24 = static_cast<int>(CLAMP(sv, 0, 16777216));
379             int s0_24 = static_cast<int>(dv);
380             while (len > 0) {
381                 unsigned int ca;
382                 /* Draw */
383                 ca = c0_24 >> 16;
384                 if ( ca > 255 ) ca=255;
385                 d[0] = NR_COMPOSEN11_1111 (r, ca, d[0]);
386                 d[1] = NR_COMPOSEN11_1111 (g, ca, d[1]);
387                 d[2] = NR_COMPOSEN11_1111 (b, ca, d[2]);
388                 d += 3;
389                 c0_24 += s0_24;
390                 c0_24 = CLAMP (c0_24, 0, 16777216);
391                 len -= 1;
392             }
393         }
394     }
397 void nr_pixblock_render_bpath_rgba (Shape* theS,uint32_t color,NRRectL &area,char* destBuf,int stride)
400     theS->CalcBBox();
401     float  l=theS->leftX,r=theS->rightX,t=theS->topY,b=theS->bottomY;
402     int    il,ir,it,ib;
403     il=(int)floor(l);
404     ir=(int)ceil(r);
405     it=(int)floor(t);
406     ib=(int)ceil(b);
408     if ( il >= area.x1 || ir <= area.x0 || it >= area.y1 || ib <= area.y0 ) return;
409     if ( il < area.x0 ) il=area.x0;
410     if ( it < area.y0 ) it=area.y0;
411     if ( ir > area.x1 ) ir=area.x1;
412     if ( ib > area.y1 ) ib=area.y1;
414 /*  // version par FloatLigne
415     int    curPt;
416     float  curY;
417     theS->BeginRaster(curY,curPt,1.0);
419     FloatLigne* theI=new FloatLigne();
420     IntLigne*   theIL=new IntLigne();
422     theS->Scan(curY,curPt,(float)(it),1.0);
424     char* mdata=(char*)destBuf;
425     uint32_t* ligStart=((uint32_t*)(mdata+(3*(il-area.x0)+stride*(it-area.y0))));
426     for (int y=it;y<ib;y++) {
427     theI->Reset();
428     if ( y&0x00000003 ) {
429     theS->Scan(curY,curPt,((float)(y+1)),theI,false,1.0);
430     } else {
431     theS->Scan(curY,curPt,((float)(y+1)),theI,true,1.0);
432     }
433     theI->Flatten();
434     theIL->Copy(theI);
436     raster_info  dest;
437     dest.startPix=il;
438     dest.endPix=ir;
439     dest.sth=il;
440     dest.stv=y;
441     dest.buffer=ligStart;
442     theIL->Raster(dest,&color,bpath_run_A8_OR);
443     ligStart=((uint32_t*)(((char*)ligStart)+stride));
444     }
445     theS->EndRaster();
446     delete theI;
447     delete theIL;  */
449     // version par BitLigne directe
450     int    curPt;
451     float  curY;
452     theS->BeginQuickRaster(curY, curPt);
454     BitLigne*   theI[4];
455     for (int i=0;i<4;i++) theI[i]=new BitLigne(il,ir);
456     IntLigne*   theIL=new IntLigne();
458     theS->DirectQuickScan(curY,curPt,(float)(it),true,0.25);
460     char* mdata=(char*)destBuf;
461     uint32_t* ligStart=((uint32_t*)(mdata+(3*(il-area.x0)+stride*(it-area.y0))));
462     for (int y=it;y<ib;y++) {
463         for (int i = 0; i < 4; i++)
464             theI[i]->Reset();
466         for (int i = 0; i < 4; i++)
467             theS->QuickScan(curY, curPt, ((float)(y+0.25*(i+1))),
468                             fill_oddEven, theI[i], 0.25);
470         theIL->Copy(4,theI);
471         //   theI[0]->Affiche();
472         //   theIL->Affiche();
474         raster_info  dest;
475         dest.startPix=il;
476         dest.endPix=ir;
477         dest.sth=il;
478         dest.stv=y;
479         dest.buffer=ligStart;
480         theIL->Raster(dest,&color,bpath_run_A8_OR);
481         ligStart=((uint32_t*)(((char*)ligStart)+stride));
482     }
483     theS->EndQuickRaster();
484     for (int i=0;i<4;i++) delete theI[i];
485     delete theIL;
489 /*
490   Local Variables:
491   mode:c++
492   c-file-style:"stroustrup"
493   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
494   indent-tabs-mode:nil
495   fill-column:99
496   End:
497 */
498 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :