1/*********************************************************************** 2 * * 3 * $Id: hpgspaint.c 375 2007-01-24 16:22:49Z softadm $ 4 * * 5 * hpgs - HPGl Script, a hpgl/2 interpreter, which uses a Postscript * 6 * API for rendering a scene and thus renders to a variety of * 7 * devices and fileformats. * 8 * * 9 * (C) 2004-2006 ev-i Informationstechnologie GmbH http://www.ev-i.at * 10 * * 11 * Author: Wolfgang Glas * 12 * * 13 * hpgs is free software; you can redistribute it and/or * 14 * modify it under the terms of the GNU Lesser General Public * 15 * License as published by the Free Software Foundation; either * 16 * version 2.1 of the License, or (at your option) any later version. * 17 * * 18 * hpgs is distributed in the hope that it will be useful, * 19 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * 21 * Lesser General Public License for more details. * 22 * * 23 * You should have received a copy of the GNU Lesser General Public * 24 * License along with this library; if not, write to the * 25 * Free Software Foundation, Inc., 59 Temple Place, Suite 330, * 26 * Boston, MA 02111-1307 USA * 27 * * 28 *********************************************************************** 29 * * 30 * The implementation of the public API for the pixel painter. * 31 * * 32 ***********************************************************************/ 33 34#include<hpgspaint.h> 35#include<math.h> 36#include<assert.h> 37#include<string.h> 38#if defined ( __MINGW32__ ) || defined ( _MSC_VER ) 39#include <malloc.h> 40#else 41#include <alloca.h> 42#endif 43 44//#define HPGS_PAINT_DEBUG_ROP3 45 46/*! \defgroup paint_device Paint device. 47 48 This module contains the workhorse for rendering a scenery to pixel 49 graphics, \c hpgs_paint_device. 50 51 Most notably, you can call \c hpgs_new_paint_device in order to 52 create a new paint device and perform the usual operations 53 \c hpgs_moveto, \c hpgs_lineto, ... on it. 54 55 Details about the implementation are explained in the documentation 56 of \c hpgs_paint_device_st and \c hpgs_paint_clipper_st and the 57 hpyerlinks therein. 58*/ 59 60/* static paint device methods for the hpgs_device vtable. */ 61static int pdv_moveto (hpgs_device *_this, const hpgs_point *p) 62{ 63 hpgs_paint_device *pdv = (hpgs_paint_device *)_this; 64 65 if (hpgs_paint_path_moveto(pdv->path,p)) 66 return hpgs_set_error(hpgs_i18n("moveto error.")); 67 68 return 0; 69} 70 71static int pdv_lineto (hpgs_device *_this, const hpgs_point *p) 72{ 73 hpgs_paint_device *pdv = (hpgs_paint_device *)_this; 74 75 if (hpgs_paint_path_lineto(pdv->path,p)) 76 return hpgs_set_error(hpgs_i18n("lineto error.")); 77 78 return 0; 79} 80 81static int pdv_curveto (hpgs_device *_this, const hpgs_point *p1, 82 const hpgs_point *p2, const hpgs_point *p3 ) 83{ 84 hpgs_paint_device *pdv = (hpgs_paint_device *)_this; 85 86 if (hpgs_paint_path_curveto(pdv->path,p1,p2,p3)) 87 return hpgs_set_error(hpgs_i18n("curveto error.")); 88 89 return 0; 90} 91 92static int pdv_newpath (hpgs_device *_this) 93{ 94 hpgs_paint_device *pdv = (hpgs_paint_device *)_this; 95 96 hpgs_paint_path_truncate(pdv->path); 97 return 0; 98} 99 100static int pdv_closepath (hpgs_device *_this) 101{ 102 hpgs_paint_device *pdv = (hpgs_paint_device *)_this; 103 104 if (hpgs_paint_path_closepath(pdv->path)) 105 return hpgs_set_error(hpgs_i18n("closepath error.")); 106 107 return 0; 108} 109 110static int pdv_stroke (hpgs_device *_this) 111{ 112 hpgs_paint_device *pdv = (hpgs_paint_device *)_this; 113 int ret = 0; 114 115 if (pdv->path->n_points > 1 || 116 (pdv->path->n_points == 1 && (pdv->path->points[0].flags&HPGS_POINT_DOT)) 117 ) 118 { 119 if (!pdv->overscan && 120 pdv->gstate->linewidth < 1.5 * pdv->path_clipper->yfac) 121 { 122 const hpgs_paint_clipper *clip = pdv->clippers[pdv->current_clipper]; 123 124 if (hpgs_paint_clipper_thin_cut(pdv->path_clipper, 125 pdv->path,pdv->gstate)) 126 return hpgs_set_error(hpgs_i18n("Out of memory cutting thin line.")); 127 128 if (hpgs_paint_clipper_emit(pdv->image, 129 pdv->path_clipper,clip, 130 &pdv->color,1,1)) 131 { 132 if (hpgs_have_error()) 133 return hpgs_error_ctxt(hpgs_i18n("stroke: Image error")); 134 135 return hpgs_set_error(hpgs_i18n("stroke: Error emitting scanlines.")); 136 } 137 138 hpgs_paint_clipper_clear(pdv->path_clipper); 139 } 140 else 141 { 142 hpgs_paint_path *p = hpgs_paint_path_stroke_path(pdv->path, 143 pdv->gstate); 144 145 if (!p) 146 return hpgs_set_error(hpgs_i18n("Out of memory creating stroke path.")); 147 148 ret = hpgs_paint_device_fill(pdv,p,HPGS_TRUE,HPGS_TRUE); 149 150 hpgs_paint_path_destroy(p); 151 } 152 } 153 154 hpgs_paint_path_truncate(pdv->path); 155 156 if (ret) 157 return hpgs_set_error(hpgs_i18n("Error filling stroke path.")); 158 159 return 0; 160} 161 162static int pdv_fill (hpgs_device *_this, hpgs_bool winding) 163{ 164 hpgs_paint_device *pdv = (hpgs_paint_device *)_this; 165 166 int ret = hpgs_paint_device_fill(pdv,pdv->path,winding,HPGS_FALSE); 167 168 hpgs_paint_path_truncate(pdv->path); 169 170 return ret; 171} 172 173static int pdv_clip (hpgs_device *_this, hpgs_bool winding) 174{ 175 hpgs_paint_device *pdv = (hpgs_paint_device *)_this; 176 177 int ret = hpgs_paint_device_clip(pdv,pdv->path,winding); 178 179 hpgs_paint_path_truncate(pdv->path); 180 181 return ret; 182} 183 184static int pdv_clipsave (hpgs_device *_this) 185{ 186 hpgs_paint_device *pdv = (hpgs_paint_device *)_this; 187 188 if (pdv->clip_depth >= HPGS_PAINT_MAX_CLIP_DEPTH) 189 return hpgs_set_error(hpgs_i18n("Maximum clip depth of %d exceeded."), 190 HPGS_PAINT_MAX_CLIP_DEPTH); 191 192 pdv->clippers[pdv->clip_depth] = 0; 193 194 ++pdv->clip_depth; 195 196 return 0; 197} 198 199static int pdv_cliprestore (hpgs_device *_this) 200{ 201 hpgs_paint_device *pdv = (hpgs_paint_device *)_this; 202 203 --pdv->clip_depth; 204 205 if (pdv->clippers[pdv->clip_depth]) 206 { 207 hpgs_paint_clipper_destroy(pdv->clippers[pdv->clip_depth]); 208 pdv->clippers[pdv->clip_depth] = 0; 209 } 210 211 if (pdv->current_clipper < pdv->clip_depth) 212 return 0; 213 214 while (pdv->current_clipper > 0) 215 { 216 --pdv->current_clipper; 217 if (pdv->clippers[pdv->current_clipper]) 218 return 0; 219 } 220 221 return hpgs_set_error(hpgs_i18n("cliprestore: No valid clipper found.")); 222} 223 224static int pdv_setrgbcolor (hpgs_device *_this, const hpgs_color *rgb) 225{ 226 hpgs_paint_device *pdv = (hpgs_paint_device *)_this; 227 228 pdv->gstate->color = *rgb; 229 230 pdv->color.r = (unsigned char)(rgb->r*255.0); 231 pdv->color.g = (unsigned char)(rgb->g*255.0); 232 pdv->color.b = (unsigned char)(rgb->b*255.0); 233 234 if (hpgs_image_define_color(pdv->image,&pdv->color)) 235 return hpgs_error_ctxt("setrgbcolor"); 236 237 pdv->gstate->pattern_color = *rgb; 238 239 hpgs_palette_color patcol; 240 241 patcol.r = pdv->color.r & (~pdv->patcol.r); 242 patcol.g = pdv->color.g & (~pdv->patcol.g); 243 patcol.b = pdv->color.b & (~pdv->patcol.b); 244 245#ifdef HPGS_PAINT_DEBUG_ROP3 246 hpgs_log("setrgbcol: patcol=%d,%d,%d.\n",patcol.r,patcol.g,patcol.b); 247#endif 248 249 return hpgs_image_setpatcol(pdv->image,&patcol); 250} 251 252static int pdv_setdash (hpgs_device *_this, const float *segs, 253 unsigned n, double d) 254{ 255 hpgs_paint_device *pdv = (hpgs_paint_device *)_this; 256 257 if (hpgs_gstate_setdash(pdv->gstate,segs,n,d)) 258 return hpgs_set_error(hpgs_i18n("setdash: Out of memory.")); 259 260 return 0; 261} 262 263static int pdv_setlinewidth(hpgs_device *_this, double lw) 264{ 265 hpgs_paint_device *pdv = (hpgs_paint_device *)_this; 266 267 if (lw < pdv->thin_alpha * pdv->path_clipper->yfac) 268 pdv->gstate->linewidth = pdv->thin_alpha * pdv->path_clipper->yfac; 269 else 270 pdv->gstate->linewidth = lw; 271 return 0; 272} 273 274static int pdv_setlinecap (hpgs_device *_this, hpgs_line_cap lc) 275{ 276 hpgs_paint_device *pdv = (hpgs_paint_device *)_this; 277 278 pdv->gstate->line_cap = lc; 279 return 0; 280} 281 282static int pdv_setlinejoin (hpgs_device *_this, hpgs_line_join lj) 283{ 284 hpgs_paint_device *pdv = (hpgs_paint_device *)_this; 285 286 pdv->gstate->line_join = lj; 287 return 0; 288} 289 290static int pdv_setmiterlimit (hpgs_device *_this, double l) 291{ 292 hpgs_paint_device *pdv = (hpgs_paint_device *)_this; 293 294 pdv->gstate->miterlimit = l; 295 return 0; 296} 297 298static int pdv_setrop3 (hpgs_device *_this, int rop, 299 hpgs_bool src_transparency, hpgs_bool pattern_transparency) 300{ 301 hpgs_paint_device *pdv = (hpgs_paint_device *)_this; 302 hpgs_rop3_func_t rop3; 303 304#ifdef HPGS_PAINT_DEBUG_ROP3 305 hpgs_log("setrop3: rop,src_trans,pat_trans=%d,%d,%d.\n", 306 rop,src_transparency,pattern_transparency); 307#endif 308 pdv->gstate->rop3 = rop; 309 pdv->gstate->src_transparency = src_transparency; 310 pdv->gstate->pattern_transparency = pattern_transparency; 311 312 rop3 = hpgs_rop3_func(rop,src_transparency,pattern_transparency); 313 314 if (!rop3) 315 return hpgs_set_error(hpgs_i18n("setrop3: Invalid ROP3 %d specified"),rop); 316 317 return hpgs_image_setrop3(pdv->image,rop3); 318} 319 320static int pdv_setpatcol(hpgs_device *_this, const hpgs_color *rgb) 321{ 322 hpgs_paint_device *pdv = (hpgs_paint_device *)_this; 323 324 pdv->gstate->pattern_color = *rgb; 325 326 pdv->patcol.r = (unsigned char)(rgb->r * 255.0); 327 pdv->patcol.g = (unsigned char)(rgb->g * 255.0); 328 pdv->patcol.b = (unsigned char)(rgb->b * 255.0); 329 330 hpgs_palette_color patcol; 331 332 patcol.r = pdv->color.r & (~pdv->patcol.r); 333 patcol.g = pdv->color.g & (~pdv->patcol.g); 334 patcol.b = pdv->color.b & (~pdv->patcol.b); 335 336#ifdef HPGS_PAINT_DEBUG_ROP3 337 hpgs_log("setpatcol: patcol=%d,%d,%d.\n",patcol.r,patcol.g,patcol.b); 338#endif 339 340 return hpgs_image_setpatcol(pdv->image,&patcol); 341} 342 343static int pdv_drawimage(hpgs_device *_this, 344 const hpgs_image *img, 345 const hpgs_point *ll, const hpgs_point *lr, 346 const hpgs_point *ur) 347{ 348 hpgs_paint_device *pdv = (hpgs_paint_device *)_this; 349 350 if (!img) 351 return hpgs_set_error(hpgs_i18n("drawimage: Null image specified.")); 352 353 hpgs_palette_color patcol; 354 patcol.r = 0; 355 patcol.g = 0; 356 patcol.b = 0; 357 358 if (hpgs_image_setpatcol(pdv->image,&patcol)) 359 return -1; 360 361 if (hpgs_paint_device_drawimage(pdv,img,ll,lr,ur)) 362 { 363 if (hpgs_have_error()) 364 return hpgs_error_ctxt(hpgs_i18n("drawimage error")); 365 366 return hpgs_set_error(hpgs_i18n("drawimage error.")); 367 } 368 369 patcol.r = pdv->color.r & (~pdv->patcol.r); 370 patcol.g = pdv->color.g & (~pdv->patcol.g); 371 patcol.b = pdv->color.b & (~pdv->patcol.b); 372 373#ifdef HPGS_PAINT_DEBUG_ROP3 374 hpgs_log("setpatcol: patcol=%d,%d,%d.\n",patcol.r,patcol.g,patcol.b); 375#endif 376 377 return hpgs_image_setpatcol(pdv->image,&patcol); 378} 379 380static int pdv_showpage (hpgs_device *_this, int i) 381{ 382 hpgs_paint_device *pdv = (hpgs_paint_device *)_this; 383 384 int ret = 0; 385 386 if (i>0 && pdv->filename) 387 { 388 int l = strlen(pdv->filename); 389 char *fn = hpgs_alloca(l+20); 390 char * dot = strrchr(pdv->filename,'.'); 391 int pos = dot ? dot-pdv->filename : l; 392 393#ifdef WIN32 394 _snprintf(fn,l+20,"%.*s%4.4d%s", 395 pos,pdv->filename,i,pdv->filename+pos); 396#else 397 snprintf(fn,l+20,"%.*s%4.4d%s", 398 pos,pdv->filename,i,pdv->filename+pos); 399#endif 400 ret = hpgs_image_write(pdv->image,fn); 401 402 if (ret == 0) 403 ret = hpgs_image_clear(pdv->image); 404 } 405 else if (pdv->filename == 0 || strlen(pdv->filename) > 0) 406 ret = hpgs_image_write(pdv->image,pdv->filename); 407 408 return ret; 409} 410 411static int pdv_setplotsize (hpgs_device *_this, const hpgs_bbox *bb) 412{ 413 hpgs_paint_device *pdv = (hpgs_paint_device *)_this; 414 int i; 415 416 if (hpgs_bbox_isequal(&pdv->page_bb,bb)) 417 return 0; 418 419 int w = (int)ceil((bb->urx-bb->llx)*pdv->xres); 420 int h = (int)ceil((bb->ury-bb->lly)*pdv->yres); 421 422 if (w<2 || h<2) 423 return hpgs_set_error(hpgs_i18n("setplotsize: The given bounding box result in a null image.")); 424 425 if (hpgs_image_resize(pdv->image,w,h)) 426 return hpgs_error_ctxt(hpgs_i18n("setplotsize: error resizing image")); 427 428 429 if (pdv->path_clipper) hpgs_paint_clipper_destroy(pdv->path_clipper); 430 431 pdv->path_clipper = hpgs_new_paint_clipper(bb, 432 pdv->image->height, 433 16,pdv->overscan); 434 if (!pdv->path_clipper) 435 return hpgs_set_error(hpgs_i18n("setplotsize: Out of memory allocating path clipper.")); 436 437 for (i=0;i<pdv->clip_depth;++i) 438 { 439 if (pdv->clippers[i]) hpgs_paint_clipper_destroy(pdv->clippers[i]); 440 pdv->clippers[i]=0; 441 } 442 443 // Initial dimension of clip segments is 4. 444 pdv->clippers[0] = hpgs_new_paint_clipper(bb, 445 pdv->image->height,4,pdv->overscan); 446 447 if (!pdv->clippers[0]) 448 return hpgs_set_error(hpgs_i18n("setplotsize: Out of memory allocating clip clipper.")); 449 450 if (hpgs_paint_clipper_reset(pdv->clippers[0],bb->llx,bb->urx)) 451 return hpgs_set_error(hpgs_i18n("setplotsize: Out of memory initializing clip clipper.")); 452 453 pdv->clip_depth = 1; 454 pdv->current_clipper = 0; 455 456 return 0; 457} 458 459static int pdv_capabilities (hpgs_device *_this) 460{ 461 hpgs_paint_device *pdv = (hpgs_paint_device *)_this; 462 463 int ret = 464 HPGS_DEVICE_CAP_RASTER | 465 HPGS_DEVICE_CAP_MULTIPAGE | 466 HPGS_DEVICE_CAP_MULTISIZE | 467 HPGS_DEVICE_CAP_DRAWIMAGE; 468 469 if (pdv->overscan) 470 ret |= HPGS_DEVICE_CAP_ANTIALIAS; 471 472 if (pdv->image->vtable->setrop3) 473 ret |= HPGS_DEVICE_CAP_ROP3; 474 475 return ret; 476} 477 478static void pdv_destroy (hpgs_device *_this) 479{ 480 hpgs_paint_device *pdv = (hpgs_paint_device *)_this; 481 int i; 482 483 if (pdv->filename) free(pdv->filename); 484 if (pdv->path) hpgs_paint_path_destroy(pdv->path); 485 if (pdv->path_clipper) hpgs_paint_clipper_destroy(pdv->path_clipper); 486 if (pdv->gstate) hpgs_gstate_destroy(pdv->gstate); 487 if (pdv->image) hpgs_image_destroy(pdv->image); 488 489 for (i=0;i<pdv->clip_depth;++i) 490 if (pdv->clippers[i]) hpgs_paint_clipper_destroy(pdv->clippers[i]); 491} 492 493static hpgs_device_vtable pdv_vtable = 494 { 495 "hpgs_paint_device", 496 pdv_moveto, 497 pdv_lineto, 498 pdv_curveto, 499 pdv_newpath, 500 pdv_closepath, 501 pdv_stroke, 502 pdv_fill, 503 pdv_clip, 504 pdv_clipsave, 505 pdv_cliprestore, 506 pdv_setrgbcolor, 507 pdv_setdash, 508 pdv_setlinewidth, 509 pdv_setlinecap, 510 pdv_setlinejoin, 511 pdv_setmiterlimit, 512 pdv_setrop3, 513 pdv_setpatcol, 514 pdv_drawimage, 515 pdv_setplotsize, 516 0 /* pdv_getplotsize */, 517 pdv_showpage, 518 0 /* pdv_finish */, 519 pdv_capabilities, 520 pdv_destroy 521 }; 522 523/*! Creates a new paint device on the heap. 524 Use \c hpgs_destroy in order to destroy the returned 525 device pointer. 526 527 The bounding box, which is mapped onto the given \c image is passed 528 in as well as the \c antialiasing switch. 529 530 A null pointer is returned, if the system is out of memory. 531*/ 532hpgs_paint_device *hpgs_new_paint_device(hpgs_image *image, 533 const char *filename, 534 const hpgs_bbox *bb, 535 hpgs_bool antialias ) 536{ 537 hpgs_paint_device *ret=(hpgs_paint_device *)malloc(sizeof(hpgs_paint_device)); 538 539 if (ret) 540 { 541 ret->image = image; 542 543 ret->path = 0; 544 ret->gstate = 0; 545 ret->overscan = antialias; 546 ret->thin_alpha = 0.25; 547 548 if (filename) 549 { 550 ret->filename = strdup(filename); 551 552 if (!ret->filename) goto fatal_error; 553 } 554 else 555 ret->filename = 0; 556 557 memset(ret->clippers, 558 0,HPGS_PAINT_MAX_CLIP_DEPTH * sizeof(hpgs_paint_clipper *)); 559 560 ret->path = hpgs_new_paint_path(); 561 if (!ret->path) goto fatal_error; 562 563 ret->path_clipper = hpgs_new_paint_clipper(bb, 564 image->height, 565 16,ret->overscan); 566 if (!ret->path_clipper) goto fatal_error; 567 568 ret->gstate = hpgs_new_gstate(); 569 if (!ret->gstate) goto fatal_error; 570 571 // Initial dimesion of clip segments is 4. 572 ret->clippers[0] = hpgs_new_paint_clipper(bb, 573 image->height,4,ret->overscan); 574 if (!ret->clippers[0]) goto fatal_error; 575 if (hpgs_paint_clipper_reset(ret->clippers[0],bb->llx,bb->urx)) 576 goto fatal_error; 577 578 ret->clip_depth = 1; 579 ret->current_clipper = 0; 580 581 ret->page_bb = *bb; 582 ret->xres = image->width/(bb->urx-bb->llx); 583 ret->yres = image->height/(bb->ury-bb->lly); 584 585 if (hpgs_image_set_resolution(image,72.0*ret->xres,72.0*ret->yres)) 586 goto fatal_error; 587 588 ret->image_interpolation = 0; 589 590 ret->color.r = 0; 591 ret->color.g = 0; 592 ret->color.b = 0; 593 ret->color.index = 0; 594 595 ret->patcol.r = 0; 596 ret->patcol.g = 0; 597 ret->patcol.b = 0; 598 599 ret->inherited.vtable = &pdv_vtable; 600 } 601 602 return ret; 603 604 fatal_error: 605 if (ret->filename) free(ret->filename); 606 if (ret->path) hpgs_paint_path_destroy(ret->path); 607 if (ret->clippers[0]) hpgs_paint_clipper_destroy(ret->clippers[0]); 608 if (ret->gstate) hpgs_gstate_destroy(ret->gstate); 609 if (ret->image) hpgs_image_destroy(ret->image); 610 free(ret); 611 return 0; 612} 613 614/*! Sets the image interpolation value of the given paint device. 615 Currently, the following values are supported: 616 617 \li 0 no image iterpolation 618 \li 1 linear image interpolation. 619 620 Other values specifiying square or cubic interpolation may be 621 supported in the future. The default value is 0. 622*/ 623void hpgs_paint_device_set_image_interpolation (hpgs_paint_device *pdv, int i) 624{ 625 pdv->image_interpolation = i; 626} 627 628/*! Sets the minimal alpha value for thin lines, when antialiasing is 629 in effect. The supplied value must be grater than or equal to 0.01 and 630 lesser than or equal to 10.0. Other values are ignored. 631*/ 632void hpgs_paint_device_set_thin_alpha (hpgs_paint_device *pdv, double a) 633{ 634 if (a > 0.01 && a <= 10.0) 635 pdv->thin_alpha = a; 636} 637 638/*! Fills the intersection of the given path with the current clip 639 path of the paint device \c pdv using the current graphics state of \c pdv. 640 641 if \c winding is \c HPGS_TRUE, the non-zero winding rule is used for filling, 642 otherwise the exclusive-or rule applies. 643 644 Return values: 645 646 \li 0 Sucess. 647 \li -1 An error ocurred. 648 Call \c hpgs_device_get_error in order to retrieve the error message. 649 650*/ 651int hpgs_paint_device_fill(hpgs_paint_device *pdv, 652 hpgs_paint_path *path, 653 hpgs_bool winding, 654 hpgs_bool stroke ) 655{ 656 const hpgs_paint_clipper *clip = pdv->clippers[pdv->current_clipper]; 657 658 if (hpgs_paint_clipper_cut(pdv->path_clipper,path)) 659 return hpgs_set_error(hpgs_i18n("fill: Error cutting current path.")); 660 661 if (hpgs_paint_clipper_emit(pdv->image, 662 pdv->path_clipper,clip, 663 &pdv->color,winding,stroke)) 664 { 665 if (hpgs_have_error()) 666 return hpgs_error_ctxt(hpgs_i18n("fill: Image error")); 667 668 return hpgs_set_error(hpgs_i18n("fill: Error emitting scanlines.")); 669 } 670 671 672 hpgs_paint_clipper_clear(pdv->path_clipper); 673 674 return 0; 675} 676 677/*! Sets the intersection of the given path with the current clip 678 path of the paint device \c pdv as the current clip path of \c pdv. 679 680 if \c winding is \c HPGS_TRUE, the non-zero winding rule is used for the 681 path intersection, otherwise the exclusive-or rule applies. 682 683 Return values: 684 685 \li 0 Sucess. 686 \li -1 An error ocurred. 687 Call \c hpgs_device_get_error in order to retrieve the error message. 688 689*/ 690int hpgs_paint_device_clip(hpgs_paint_device *pdv, 691 hpgs_paint_path *path, 692 hpgs_bool winding) 693{ 694 const hpgs_paint_clipper *clip = pdv->clippers[pdv->current_clipper]; 695 696 if (hpgs_paint_clipper_cut(pdv->path_clipper,path)) 697 return hpgs_set_error(hpgs_i18n("clip: Error cutting current path.")); 698 699 hpgs_paint_clipper *nclip = 700 hpgs_paint_clipper_clip(pdv->path_clipper,clip,winding); 701 702 if (!nclip) 703 return hpgs_set_error(hpgs_i18n("clip: Out of memory creating new clipper.")); 704 705 // push the new clipper onto the stack of clippers. 706 pdv->current_clipper = pdv->clip_depth-1; 707 708 if (pdv->clippers[pdv->current_clipper]) 709 hpgs_paint_clipper_destroy(pdv->clippers[pdv->current_clipper]); 710 711 pdv->clippers[pdv->current_clipper] = nclip; 712 713 hpgs_paint_clipper_clear(pdv->path_clipper); 714 715 return 0; 716} 717