PageRenderTime 62ms CodeModel.GetById 29ms RepoModel.GetById 0ms app.codeStats 0ms

/de/draw.c

https://bitbucket.org/whitelynx/notion
C | 707 lines | 501 code | 169 blank | 37 comment | 63 complexity | 0e17c97819d1f82b5a7ecaddff24b225 MD5 | raw file
Possible License(s): LGPL-2.1
  1. /*
  2. * ion/de/draw.c
  3. *
  4. * Copyright (c) Tuomo Valkonen 1999-2009.
  5. *
  6. * See the included file LICENSE for details.
  7. */
  8. #include <string.h>
  9. #include <limits.h>
  10. #include <ioncore/global.h>
  11. #include <ioncore/common.h>
  12. #include <ioncore/gr.h>
  13. #include <ioncore/gr-util.h>
  14. #include "brush.h"
  15. #include "font.h"
  16. #include "private.h"
  17. #include <X11/extensions/shape.h>
  18. /*{{{ Colour group lookup */
  19. static DEColourGroup *destyle_get_colour_group2(DEStyle *style,
  20. const GrStyleSpec *a1,
  21. const GrStyleSpec *a2)
  22. {
  23. int i, score, maxscore=0;
  24. DEColourGroup *maxg=&(style->cgrp);
  25. while(style!=NULL){
  26. for(i=0; i<style->n_extra_cgrps; i++){
  27. score=gr_stylespec_score2(&style->extra_cgrps[i].spec, a1, a2);
  28. if(score>maxscore){
  29. maxg=&(style->extra_cgrps[i]);
  30. maxscore=score;
  31. }
  32. }
  33. style=style->based_on;
  34. }
  35. return maxg;
  36. }
  37. DEColourGroup *debrush_get_colour_group2(DEBrush *brush,
  38. const GrStyleSpec *a1,
  39. const GrStyleSpec *a2)
  40. {
  41. return destyle_get_colour_group2(brush->d, a1, a2);
  42. }
  43. DEColourGroup *debrush_get_colour_group(DEBrush *brush, const GrStyleSpec *attr)
  44. {
  45. return destyle_get_colour_group2(brush->d, attr, NULL);
  46. }
  47. DEColourGroup *debrush_get_current_colour_group(DEBrush *brush)
  48. {
  49. return debrush_get_colour_group(brush, debrush_get_current_attr(brush));
  50. }
  51. /*}}}*/
  52. /*{{{ Borders */
  53. /* Draw a border at x, y with outer width w x h. Top and left 'tl' pixels
  54. * wide with color 'tlc' and bottom and right 'br' pixels with colors 'brc'.
  55. */
  56. static void do_draw_border(Window win, GC gc, int x, int y, int w, int h,
  57. uint tl, uint br, DEColour tlc, DEColour brc)
  58. {
  59. XPoint points[3];
  60. uint i=0, a=0, b=0;
  61. w--;
  62. h--;
  63. XSetForeground(ioncore_g.dpy, gc, tlc);
  64. a=(br!=0);
  65. b=0;
  66. for(i=0; i<tl; i++){
  67. points[0].x=x+i; points[0].y=y+h+1-b;
  68. points[1].x=x+i; points[1].y=y+i;
  69. points[2].x=x+w+1-a; points[2].y=y+i;
  70. if(a<br)
  71. a++;
  72. if(b<br)
  73. b++;
  74. XDrawLines(ioncore_g.dpy, win, gc, points, 3, CoordModeOrigin);
  75. }
  76. XSetForeground(ioncore_g.dpy, gc, brc);
  77. a=(tl!=0);
  78. b=0;
  79. for(i=0; i<br; i++){
  80. points[0].x=x+w-i; points[0].y=y+b;
  81. points[1].x=x+w-i; points[1].y=y+h-i;
  82. points[2].x=x+a; points[2].y=y+h-i;
  83. if(a<tl)
  84. a++;
  85. if(b<tl)
  86. b++;
  87. XDrawLines(ioncore_g.dpy, win, gc, points, 3, CoordModeOrigin);
  88. }
  89. }
  90. static void draw_border(Window win, GC gc, WRectangle *geom,
  91. uint tl, uint br, DEColour tlc, DEColour brc)
  92. {
  93. do_draw_border(win, gc, geom->x, geom->y, geom->w, geom->h,
  94. tl, br, tlc, brc);
  95. geom->x+=tl;
  96. geom->y+=tl;
  97. geom->w-=tl+br;
  98. geom->h-=tl+br;
  99. }
  100. static void draw_borderline(Window win, GC gc, WRectangle *geom,
  101. uint tl, uint br, DEColour tlc, DEColour brc,
  102. GrBorderLine line)
  103. {
  104. if(line==GR_BORDERLINE_LEFT && geom->h>0 && tl>0){
  105. XSetForeground(ioncore_g.dpy, gc, tlc);
  106. XSetBackground(ioncore_g.dpy, gc, tlc);
  107. XFillRectangle(ioncore_g.dpy, win, gc, geom->x, geom->y, tl, geom->h);
  108. geom->x+=tl;
  109. }else if(line==GR_BORDERLINE_TOP && geom->w>0 && tl>0){
  110. XSetForeground(ioncore_g.dpy, gc, tlc);
  111. XSetBackground(ioncore_g.dpy, gc, tlc);
  112. XFillRectangle(ioncore_g.dpy, win, gc, geom->x, geom->y, geom->w, tl);
  113. geom->y+=tl;
  114. }else if(line==GR_BORDERLINE_RIGHT && geom->h>0 && br>0){
  115. XSetForeground(ioncore_g.dpy, gc, brc);
  116. XSetBackground(ioncore_g.dpy, gc, brc);
  117. XFillRectangle(ioncore_g.dpy, win, gc, geom->x+geom->w-br, geom->y, br, geom->h);
  118. geom->w-=br;
  119. }else if(line==GR_BORDERLINE_BOTTOM && geom->w>0 && br>0){
  120. XSetForeground(ioncore_g.dpy, gc, brc);
  121. XSetBackground(ioncore_g.dpy, gc, brc);
  122. XFillRectangle(ioncore_g.dpy, win, gc, geom->x, geom->y+geom->h-br, geom->w, br);
  123. geom->h-=br;
  124. }
  125. }
  126. void debrush_do_draw_borderline(DEBrush *brush, WRectangle geom,
  127. DEColourGroup *cg, GrBorderLine line)
  128. {
  129. DEBorder *bd=&(brush->d->border);
  130. GC gc=brush->d->normal_gc;
  131. Window win=brush->win;
  132. switch(bd->style){
  133. case DEBORDER_RIDGE:
  134. draw_borderline(win, gc, &geom, bd->hl, bd->sh, cg->hl, cg->sh, line);
  135. case DEBORDER_INLAID:
  136. draw_borderline(win, gc, &geom, bd->pad, bd->pad, cg->pad, cg->pad, line);
  137. draw_borderline(win, gc, &geom, bd->sh, bd->hl, cg->sh, cg->hl, line);
  138. break;
  139. case DEBORDER_GROOVE:
  140. draw_borderline(win, gc, &geom, bd->sh, bd->hl, cg->sh, cg->hl, line);
  141. draw_borderline(win, gc, &geom, bd->pad, bd->pad, cg->pad, cg->pad, line);
  142. draw_borderline(win, gc, &geom, bd->hl, bd->sh, cg->hl, cg->sh, line);
  143. break;
  144. case DEBORDER_ELEVATED:
  145. default:
  146. draw_borderline(win, gc, &geom, bd->hl, bd->sh, cg->hl, cg->sh, line);
  147. draw_borderline(win, gc, &geom, bd->pad, bd->pad, cg->pad, cg->pad, line);
  148. break;
  149. }
  150. }
  151. void debrush_do_draw_padline(DEBrush *brush, WRectangle geom,
  152. DEColourGroup *cg, GrBorderLine line)
  153. {
  154. DEBorder *bd=&(brush->d->border);
  155. GC gc=brush->d->normal_gc;
  156. Window win=brush->win;
  157. draw_borderline(win, gc, &geom, bd->pad, bd->pad, cg->pad, cg->pad, line);
  158. }
  159. void debrush_draw_borderline(DEBrush *brush, const WRectangle *geom,
  160. GrBorderLine line)
  161. {
  162. DEColourGroup *cg=debrush_get_current_colour_group(brush);
  163. if(cg!=NULL)
  164. debrush_do_draw_borderline(brush, *geom, cg, line);
  165. }
  166. static void debrush_do_do_draw_border(DEBrush *brush, WRectangle geom,
  167. DEColourGroup *cg)
  168. {
  169. DEBorder *bd=&(brush->d->border);
  170. GC gc=brush->d->normal_gc;
  171. Window win=brush->win;
  172. switch(bd->style){
  173. case DEBORDER_RIDGE:
  174. draw_border(win, gc, &geom, bd->hl, bd->sh, cg->hl, cg->sh);
  175. case DEBORDER_INLAID:
  176. draw_border(win, gc, &geom, bd->pad, bd->pad, cg->pad, cg->pad);
  177. draw_border(win, gc, &geom, bd->sh, bd->hl, cg->sh, cg->hl);
  178. break;
  179. case DEBORDER_GROOVE:
  180. draw_border(win, gc, &geom, bd->sh, bd->hl, cg->sh, cg->hl);
  181. draw_border(win, gc, &geom, bd->pad, bd->pad, cg->pad, cg->pad);
  182. draw_border(win, gc, &geom, bd->hl, bd->sh, cg->hl, cg->sh);
  183. break;
  184. case DEBORDER_ELEVATED:
  185. default:
  186. draw_border(win, gc, &geom, bd->hl, bd->sh, cg->hl, cg->sh);
  187. draw_border(win, gc, &geom, bd->pad, bd->pad, cg->pad, cg->pad);
  188. break;
  189. }
  190. }
  191. void debrush_do_draw_border(DEBrush *brush, WRectangle geom,
  192. DEColourGroup *cg)
  193. {
  194. DEBorder *bd=&(brush->d->border);
  195. switch(bd->sides){
  196. case DEBORDER_ALL:
  197. debrush_do_do_draw_border(brush, geom, cg);
  198. break;
  199. case DEBORDER_TB:
  200. debrush_do_draw_padline(brush, geom, cg, GR_BORDERLINE_LEFT);
  201. debrush_do_draw_padline(brush, geom, cg, GR_BORDERLINE_RIGHT);
  202. debrush_do_draw_borderline(brush, geom, cg, GR_BORDERLINE_TOP);
  203. debrush_do_draw_borderline(brush, geom, cg, GR_BORDERLINE_BOTTOM);
  204. break;
  205. case DEBORDER_LR:
  206. debrush_do_draw_padline(brush, geom, cg, GR_BORDERLINE_TOP);
  207. debrush_do_draw_padline(brush, geom, cg, GR_BORDERLINE_BOTTOM);
  208. debrush_do_draw_borderline(brush, geom, cg, GR_BORDERLINE_LEFT);
  209. debrush_do_draw_borderline(brush, geom, cg, GR_BORDERLINE_RIGHT);
  210. break;
  211. }
  212. }
  213. void debrush_draw_border(DEBrush *brush,
  214. const WRectangle *geom)
  215. {
  216. DEColourGroup *cg=debrush_get_current_colour_group(brush);
  217. if(cg!=NULL)
  218. debrush_do_draw_border(brush, *geom, cg);
  219. }
  220. /*}}}*/
  221. /*{{{ Boxes */
  222. static void copy_masked(DEBrush *brush, Drawable src, Drawable dst,
  223. int src_x, int src_y, int w, int h,
  224. int dst_x, int dst_y)
  225. {
  226. GC copy_gc=brush->d->copy_gc;
  227. XSetClipMask(ioncore_g.dpy, copy_gc, src);
  228. XSetClipOrigin(ioncore_g.dpy, copy_gc, dst_x, dst_y);
  229. XCopyPlane(ioncore_g.dpy, src, dst, copy_gc, src_x, src_y, w, h,
  230. dst_x, dst_y, 1);
  231. }
  232. #define ISSET(S, A) ((S)!=NULL && gr_stylespec_isset(S, A))
  233. GR_DEFATTR(dragged);
  234. GR_DEFATTR(tagged);
  235. GR_DEFATTR(submenu);
  236. GR_DEFATTR(numbered);
  237. GR_DEFATTR(tabnumber);
  238. static void ensure_attrs()
  239. {
  240. GR_ALLOCATTR_BEGIN;
  241. GR_ALLOCATTR(dragged);
  242. GR_ALLOCATTR(tagged);
  243. GR_ALLOCATTR(submenu);
  244. GR_ALLOCATTR(numbered);
  245. GR_ALLOCATTR(tabnumber);
  246. GR_ALLOCATTR_END;
  247. }
  248. static int get_ty(const WRectangle *g, const GrBorderWidths *bdw,
  249. const GrFontExtents *fnte)
  250. {
  251. return (g->y+bdw->top+fnte->baseline
  252. +(g->h-bdw->top-bdw->bottom-fnte->max_height)/2);
  253. }
  254. void debrush_tab_extras(DEBrush *brush, const WRectangle *g,
  255. DEColourGroup *cg, const GrBorderWidths *bdw,
  256. const GrFontExtents *fnte,
  257. const GrStyleSpec *a1,
  258. const GrStyleSpec *a2,
  259. bool pre, int index)
  260. {
  261. DEStyle *d=brush->d;
  262. GC tmp;
  263. /* Not thread-safe, but neither is the rest of the drawing code
  264. * with shared GC:s.
  265. */
  266. static bool swapped=FALSE;
  267. ensure_attrs();
  268. if(pre){
  269. if(ISSET(a2, GR_ATTR(dragged)) || ISSET(a1, GR_ATTR(dragged))){
  270. tmp=d->normal_gc;
  271. d->normal_gc=d->stipple_gc;
  272. d->stipple_gc=tmp;
  273. swapped=TRUE;
  274. XClearArea(ioncore_g.dpy, brush->win, g->x, g->y, g->w, g->h, False);
  275. }
  276. return;
  277. }
  278. if((ISSET(a1, GR_ATTR(numbered)) || ISSET(a2, GR_ATTR(numbered)))
  279. && index>=0){
  280. DEColourGroup *cg;
  281. GrStyleSpec tmp;
  282. gr_stylespec_init(&tmp);
  283. gr_stylespec_append(&tmp, a2);
  284. gr_stylespec_set(&tmp, GR_ATTR(tabnumber));
  285. cg=debrush_get_colour_group2(brush, a1, &tmp);
  286. gr_stylespec_unalloc(&tmp);
  287. if(cg!=NULL){
  288. char *s=NULL;
  289. libtu_asprintf(&s, "[%d]", index+1);
  290. if(s!=NULL){
  291. int l=strlen(s);
  292. uint w=debrush_get_text_width(brush, s, l);
  293. if(w < g->w-bdw->right-bdw->left){
  294. int ty=get_ty(g, bdw, fnte);
  295. int tx=(d->textalign==DEALIGN_RIGHT
  296. ? g->x+bdw->left
  297. : g->x+g->w-bdw->right-w);
  298. debrush_do_draw_string(brush, tx, ty, s, l, TRUE, cg);
  299. }
  300. free(s);
  301. }
  302. }
  303. }
  304. if(ISSET(a2, GR_ATTR(tagged)) || ISSET(a1, GR_ATTR(tagged))){
  305. XSetForeground(ioncore_g.dpy, d->copy_gc, cg->fg);
  306. copy_masked(brush, d->tag_pixmap, brush->win, 0, 0,
  307. d->tag_pixmap_w, d->tag_pixmap_h,
  308. g->x+g->w-bdw->right-d->tag_pixmap_w,
  309. g->y+bdw->top);
  310. }
  311. if(swapped){
  312. tmp=d->normal_gc;
  313. d->normal_gc=d->stipple_gc;
  314. d->stipple_gc=tmp;
  315. swapped=FALSE;
  316. }
  317. /*if(MATCHES2("*-*-*-dragged", a1, a2)){
  318. XFillRectangle(ioncore_g.dpy, win, d->stipple_gc,
  319. g->x, g->y, g->w, g->h);
  320. }*/
  321. }
  322. void debrush_menuentry_extras(DEBrush *brush,
  323. const WRectangle *g,
  324. DEColourGroup *cg,
  325. const GrBorderWidths *bdw,
  326. const GrFontExtents *fnte,
  327. const GrStyleSpec *a1,
  328. const GrStyleSpec *a2,
  329. bool pre, int index)
  330. {
  331. int tx, ty;
  332. if(pre)
  333. return;
  334. ensure_attrs();
  335. if(ISSET(a2, GR_ATTR(submenu)) || ISSET(a1, GR_ATTR(submenu))){
  336. ty=get_ty(g, bdw, fnte);
  337. tx=g->x+g->w-bdw->right;
  338. debrush_do_draw_string(brush, tx, ty, DE_SUB_IND, DE_SUB_IND_LEN,
  339. FALSE, cg);
  340. }
  341. }
  342. void debrush_do_draw_box(DEBrush *brush, const WRectangle *geom,
  343. DEColourGroup *cg, bool needfill)
  344. {
  345. GC gc=brush->d->normal_gc;
  346. if(TRUE/*needfill*/){
  347. XSetForeground(ioncore_g.dpy, gc, cg->bg);
  348. XFillRectangle(ioncore_g.dpy, brush->win, gc, geom->x, geom->y,
  349. geom->w, geom->h);
  350. }
  351. debrush_do_draw_border(brush, *geom, cg);
  352. }
  353. static void debrush_do_draw_textbox(DEBrush *brush,
  354. const WRectangle *geom,
  355. const char *text,
  356. DEColourGroup *cg,
  357. bool needfill,
  358. const GrStyleSpec *a1,
  359. const GrStyleSpec *a2,
  360. int index)
  361. {
  362. uint len;
  363. GrBorderWidths bdw;
  364. GrFontExtents fnte;
  365. uint tx, ty, tw;
  366. grbrush_get_border_widths(&(brush->grbrush), &bdw);
  367. grbrush_get_font_extents(&(brush->grbrush), &fnte);
  368. if(brush->extras_fn!=NULL)
  369. brush->extras_fn(brush, geom, cg, &bdw, &fnte, a1, a2, TRUE, index);
  370. debrush_do_draw_box(brush, geom, cg, needfill);
  371. do{ /*...while(0)*/
  372. if(text==NULL)
  373. break;
  374. len=strlen(text);
  375. if(len==0)
  376. break;
  377. if(brush->d->textalign!=DEALIGN_LEFT){
  378. tw=grbrush_get_text_width((GrBrush*)brush, text, len);
  379. if(brush->d->textalign==DEALIGN_CENTER)
  380. tx=geom->x+bdw.left+(geom->w-bdw.left-bdw.right-tw)/2;
  381. else
  382. tx=geom->x+geom->w-bdw.right-tw;
  383. }else{
  384. tx=geom->x+bdw.left;
  385. }
  386. ty=get_ty(geom, &bdw, &fnte);
  387. debrush_do_draw_string(brush, tx, ty, text, len, FALSE, cg);
  388. }while(0);
  389. if(brush->extras_fn!=NULL)
  390. brush->extras_fn(brush, geom, cg, &bdw, &fnte, a1, a2, FALSE, index);
  391. }
  392. void debrush_draw_textbox(DEBrush *brush, const WRectangle *geom,
  393. const char *text, bool needfill)
  394. {
  395. GrStyleSpec *attr=debrush_get_current_attr(brush);
  396. DEColourGroup *cg=debrush_get_colour_group(brush, attr);
  397. if(cg!=NULL){
  398. debrush_do_draw_textbox(brush, geom, text, cg, needfill,
  399. attr, NULL, -1);
  400. }
  401. }
  402. void debrush_draw_textboxes(DEBrush *brush, const WRectangle *geom,
  403. int n, const GrTextElem *elem,
  404. bool needfill)
  405. {
  406. GrStyleSpec *common_attrib;
  407. WRectangle g=*geom;
  408. DEColourGroup *cg;
  409. GrBorderWidths bdw;
  410. int i;
  411. common_attrib=debrush_get_current_attr(brush);
  412. grbrush_get_border_widths(&(brush->grbrush), &bdw);
  413. for(i=0; ; i++){
  414. g.w=bdw.left+elem[i].iw+bdw.right;
  415. cg=debrush_get_colour_group2(brush, common_attrib, &elem[i].attr);
  416. if(cg!=NULL){
  417. debrush_do_draw_textbox(brush, &g, elem[i].text, cg, needfill,
  418. common_attrib, &elem[i].attr, i);
  419. }
  420. if(i==n-1)
  421. break;
  422. g.x+=g.w;
  423. if(bdw.spacing>0 && needfill){
  424. XClearArea(ioncore_g.dpy, brush->win, g.x, g.y,
  425. brush->d->spacing, g.h, False);
  426. }
  427. g.x+=bdw.spacing;
  428. }
  429. }
  430. /*}}}*/
  431. /*{{{ Misc. */
  432. #define MAXSHAPE 16
  433. void debrush_set_window_shape(DEBrush *brush, bool rough,
  434. int n, const WRectangle *rects)
  435. {
  436. XRectangle r[MAXSHAPE];
  437. int i;
  438. if(!ioncore_g.shape_extension)
  439. return;
  440. if(n>MAXSHAPE)
  441. n=MAXSHAPE;
  442. if(n==0){
  443. /* n==0 should clear the shape. As there's absolutely no
  444. * documentation for XShape (as is typical of all sucky X
  445. * extensions), I don't know how the shape should properly
  446. * be cleared. Thus we just use a huge rectangle.
  447. */
  448. n=1;
  449. r[0].x=0;
  450. r[0].y=0;
  451. r[0].width=USHRT_MAX;
  452. r[0].height=USHRT_MAX;
  453. }else{
  454. for(i=0; i<n; i++){
  455. r[i].x=rects[i].x;
  456. r[i].y=rects[i].y;
  457. r[i].width=rects[i].w;
  458. r[i].height=rects[i].h;
  459. }
  460. }
  461. XShapeCombineRectangles(ioncore_g.dpy, brush->win,
  462. ShapeBounding, 0, 0, r, n,
  463. ShapeSet, Unsorted);
  464. }
  465. void debrush_enable_transparency(DEBrush *brush, GrTransparency mode)
  466. {
  467. XSetWindowAttributes attr;
  468. ulong attrflags=0;
  469. if(mode==GR_TRANSPARENCY_DEFAULT)
  470. mode=brush->d->transparency_mode;
  471. if(mode==GR_TRANSPARENCY_YES){
  472. attrflags=CWBackPixmap;
  473. attr.background_pixmap=ParentRelative;
  474. }else{
  475. attrflags=CWBackPixel;
  476. attr.background_pixel=brush->d->cgrp.bg;
  477. }
  478. XChangeWindowAttributes(ioncore_g.dpy, brush->win, attrflags, &attr);
  479. XClearWindow(ioncore_g.dpy, brush->win);
  480. }
  481. void debrush_fill_area(DEBrush *brush, const WRectangle *geom)
  482. {
  483. DEColourGroup *cg=debrush_get_current_colour_group(brush);
  484. GC gc=brush->d->normal_gc;
  485. if(cg==NULL)
  486. return;
  487. XSetForeground(ioncore_g.dpy, gc, cg->bg);
  488. XFillRectangle(ioncore_g.dpy, brush->win, gc,
  489. geom->x, geom->y, geom->w, geom->h);
  490. }
  491. void debrush_clear_area(DEBrush *brush, const WRectangle *geom)
  492. {
  493. XClearArea(ioncore_g.dpy, brush->win,
  494. geom->x, geom->y, geom->w, geom->h, False);
  495. }
  496. /*}}}*/
  497. /*{{{ Clipping rectangles */
  498. /* Should actually set the clipping rectangle for all GC:s and use
  499. * window-specific GC:s to do this correctly...
  500. */
  501. static void debrush_set_clipping_rectangle(DEBrush *brush,
  502. const WRectangle *geom)
  503. {
  504. XRectangle rect;
  505. assert(!brush->clip_set);
  506. rect.x=geom->x;
  507. rect.y=geom->y;
  508. rect.width=geom->w;
  509. rect.height=geom->h;
  510. XSetClipRectangles(ioncore_g.dpy, brush->d->normal_gc,
  511. 0, 0, &rect, 1, Unsorted);
  512. brush->clip_set=TRUE;
  513. }
  514. static void debrush_clear_clipping_rectangle(DEBrush *brush)
  515. {
  516. if(brush->clip_set){
  517. XSetClipMask(ioncore_g.dpy, brush->d->normal_gc, None);
  518. brush->clip_set=FALSE;
  519. }
  520. }
  521. /*}}}*/
  522. /*{{{ debrush_begin/end */
  523. void debrush_begin(DEBrush *brush, const WRectangle *geom, int flags)
  524. {
  525. if(flags&GRBRUSH_AMEND)
  526. flags|=GRBRUSH_NO_CLEAR_OK;
  527. if(!(flags&GRBRUSH_KEEP_ATTR))
  528. debrush_init_attr(brush, NULL);
  529. if(!(flags&GRBRUSH_NO_CLEAR_OK))
  530. debrush_clear_area(brush, geom);
  531. if(flags&GRBRUSH_NEED_CLIP)
  532. debrush_set_clipping_rectangle(brush, geom);
  533. }
  534. void debrush_end(DEBrush *brush)
  535. {
  536. debrush_clear_clipping_rectangle(brush);
  537. }
  538. /*}}}*/