Imported Upstream version 1.15.1
[deb_xorg-server.git] / miext / rootless / rootlessGC.c
CommitLineData
a09e091a
JB
1/*
2 * Graphics Context support for generic rootless X server
3 */
4/*
5 * Copyright (c) 2001 Greg Parker. All Rights Reserved.
6 * Copyright (c) 2002-2003 Torrey T. Lyons. All Rights Reserved.
7 * Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
23 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
24 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 * DEALINGS IN THE SOFTWARE.
26 *
27 * Except as contained in this notice, the name(s) of the above copyright
28 * holders shall not be used in advertising or otherwise to promote the sale,
29 * use or other dealings in this Software without prior written authorization.
30 */
31
32#ifdef HAVE_DIX_CONFIG_H
33#include <dix-config.h>
34#endif
35
36#include <stddef.h> /* For NULL */
37#include "mi.h"
38#include "scrnintstr.h"
39#include "gcstruct.h"
40#include "pixmapstr.h"
41#include "windowstr.h"
42#include "dixfontstr.h"
43#include "mivalidate.h"
44#include "fb.h"
45
46#include <sys/types.h>
47#include <sys/stat.h>
48#include <fcntl.h>
49
50#include "rootlessCommon.h"
51
52// GC functions
53static void RootlessValidateGC(GCPtr pGC, unsigned long changes,
54 DrawablePtr pDrawable);
55static void RootlessChangeGC(GCPtr pGC, unsigned long mask);
56static void RootlessCopyGC(GCPtr pGCSrc, unsigned long mask, GCPtr pGCDst);
57static void RootlessDestroyGC(GCPtr pGC);
58static void RootlessChangeClip(GCPtr pGC, int type, pointer pvalue, int nrects);
59static void RootlessDestroyClip(GCPtr pGC);
60static void RootlessCopyClip(GCPtr pgcDst, GCPtr pgcSrc);
61
62Bool RootlessCreateGC(GCPtr pGC);
63
64GCFuncs rootlessGCFuncs = {
65 RootlessValidateGC,
66 RootlessChangeGC,
67 RootlessCopyGC,
68 RootlessDestroyGC,
69 RootlessChangeClip,
70 RootlessDestroyClip,
71 RootlessCopyClip,
72};
73
74// GC operations
75static void RootlessFillSpans(DrawablePtr dst, GCPtr pGC, int nInit,
76 DDXPointPtr pptInit, int *pwidthInit, int sorted);
77static void RootlessSetSpans(DrawablePtr dst, GCPtr pGC, char *pSrc,
78 DDXPointPtr pptInit, int *pwidthInit,
79 int nspans, int sorted);
80static void RootlessPutImage(DrawablePtr dst, GCPtr pGC,
81 int depth, int x, int y, int w, int h,
82 int leftPad, int format, char *pBits);
83static RegionPtr RootlessCopyArea(DrawablePtr pSrc, DrawablePtr dst, GCPtr pGC,
84 int srcx, int srcy, int w, int h,
85 int dstx, int dsty);
86static RegionPtr RootlessCopyPlane(DrawablePtr pSrc, DrawablePtr dst,
87 GCPtr pGC, int srcx, int srcy,
88 int w, int h, int dstx, int dsty,
89 unsigned long plane);
90static void RootlessPolyPoint(DrawablePtr dst, GCPtr pGC,
91 int mode, int npt, DDXPointPtr pptInit);
92static void RootlessPolylines(DrawablePtr dst, GCPtr pGC,
93 int mode, int npt, DDXPointPtr pptInit);
94static void RootlessPolySegment(DrawablePtr dst, GCPtr pGC,
95 int nseg, xSegment * pSeg);
96static void RootlessPolyRectangle(DrawablePtr dst, GCPtr pGC,
97 int nRects, xRectangle *pRects);
98static void RootlessPolyArc(DrawablePtr dst, GCPtr pGC, int narcs,
99 xArc * parcs);
100static void RootlessFillPolygon(DrawablePtr dst, GCPtr pGC, int shape, int mode,
101 int count, DDXPointPtr pptInit);
102static void RootlessPolyFillRect(DrawablePtr dst, GCPtr pGC, int nRectsInit,
103 xRectangle *pRectsInit);
104static void RootlessPolyFillArc(DrawablePtr dst, GCPtr pGC, int narcsInit,
105 xArc * parcsInit);
106static int RootlessPolyText8(DrawablePtr dst, GCPtr pGC, int x, int y,
107 int count, char *chars);
108static int RootlessPolyText16(DrawablePtr dst, GCPtr pGC, int x, int y,
109 int count, unsigned short *chars);
110static void RootlessImageText8(DrawablePtr dst, GCPtr pGC, int x, int y,
111 int count, char *chars);
112static void RootlessImageText16(DrawablePtr dst, GCPtr pGC, int x, int y,
113 int count, unsigned short *chars);
114static void RootlessImageGlyphBlt(DrawablePtr dst, GCPtr pGC, int x, int y,
115 unsigned int nglyphInit,
116 CharInfoPtr * ppciInit, pointer unused);
117static void RootlessPolyGlyphBlt(DrawablePtr dst, GCPtr pGC, int x, int y,
118 unsigned int nglyph, CharInfoPtr * ppci,
119 pointer pglyphBase);
120static void RootlessPushPixels(GCPtr pGC, PixmapPtr pBitMap, DrawablePtr dst,
121 int dx, int dy, int xOrg, int yOrg);
122
123static GCOps rootlessGCOps = {
124 RootlessFillSpans,
125 RootlessSetSpans,
126 RootlessPutImage,
127 RootlessCopyArea,
128 RootlessCopyPlane,
129 RootlessPolyPoint,
130 RootlessPolylines,
131 RootlessPolySegment,
132 RootlessPolyRectangle,
133 RootlessPolyArc,
134 RootlessFillPolygon,
135 RootlessPolyFillRect,
136 RootlessPolyFillArc,
137 RootlessPolyText8,
138 RootlessPolyText16,
139 RootlessImageText8,
140 RootlessImageText16,
141 RootlessImageGlyphBlt,
142 RootlessPolyGlyphBlt,
143 RootlessPushPixels
144};
145
146/*
147 If ROOTLESS_PROTECT_ALPHA is set, we have to make sure that the alpha
148 channel of the on screen windows is always opaque. fb makes this harder
149 than it would otherwise be by noticing that a planemask of 0x00ffffff
150 includes all bits when depth==24, and so it "optimizes" the planemask to
151 0xffffffff. We work around this by temporarily setting depth=bpp while
152 changing the GC.
153
154 So the normal situation (in 32 bit mode) is that the planemask is
155 0x00ffffff and thus fb leaves the alpha channel alone. The rootless
156 implementation is responsible for setting the alpha channel opaque
157 initially.
158
159 Unfortunately drawing with a planemask that doesn't have all bits set
160 normally causes fb to fall off its fastest paths when blitting and
161 filling. So we try to recognize when we can relax the planemask back to
162 0xffffffff, and do that for the duration of the drawing operation,
163 setting the alpha channel in fg/bg pixels to opaque at the same time. We
164 can do this when drawing op is GXcopy. We can also do this when copying
165 from another window since its alpha channel must also be opaque.
166
167 The three macros below are used to implement this. Drawing ops that can
168 potentially have their planemask relaxed look like:
169
170 OP {
171 GC_SAVE(gc);
172 GCOP_UNWRAP(gc);
173
174 ...
175
176 if (canAccelxxx(..) && otherwise-suitable)
177 GC_UNSET_PM(gc, dst);
178
179 gc->funcs->OP(gc, ...);
180
181 GC_RESTORE(gc, dst);
182 GCOP_WRAP(gc);
183 }
184
185 */
186
187#define GC_SAVE(pGC) \
188 unsigned long _save_fg = (pGC)->fgPixel; \
189 unsigned long _save_bg = (pGC)->bgPixel; \
190 unsigned long _save_pm = (pGC)->planemask; \
191 Bool _changed = FALSE
192
193#define GC_RESTORE(pGC, pDraw) \
194 do { \
195 if (_changed) { \
196 unsigned int depth = (pDraw)->depth; \
197 (pGC)->fgPixel = _save_fg; \
198 (pGC)->bgPixel = _save_bg; \
199 (pGC)->planemask = _save_pm; \
200 (pDraw)->depth = (pDraw)->bitsPerPixel; \
201 VALIDATE_GC(pGC, GCForeground | GCBackground | \
202 GCPlaneMask, pDraw); \
203 (pDraw)->depth = depth; \
204 } \
205 } while (0)
206
207#define GC_UNSET_PM(pGC, pDraw) \
208 do { \
209 unsigned int mask = RootlessAlphaMask ((pDraw)->bitsPerPixel); \
210 if (((pGC)->planemask & mask) != mask) { \
211 unsigned int depth = (pDraw)->depth; \
212 (pGC)->fgPixel |= mask; \
213 (pGC)->bgPixel |= mask; \
214 (pGC)->planemask |= mask; \
215 (pDraw)->depth = (pDraw)->bitsPerPixel; \
216 VALIDATE_GC(pGC, GCForeground | \
217 GCBackground | GCPlaneMask, pDraw); \
218 (pDraw)->depth = depth; \
219 _changed = TRUE; \
220 } \
221 } while (0)
222
223#define VALIDATE_GC(pGC, changes, pDrawable) \
224 do { \
225 pGC->funcs->ValidateGC(pGC, changes, pDrawable); \
226 if (((WindowPtr) pDrawable)->viewable) { \
227 gcrec->originalOps = pGC->ops; \
228 } \
229 } while(0)
230
231static RootlessWindowRec *
232canAccelBlit(DrawablePtr pDraw, GCPtr pGC)
233{
234 WindowPtr pTop;
235 RootlessWindowRec *winRec;
236 unsigned int pm;
237
238 if (pGC->alu != GXcopy)
239 return NULL;
240
241 if (pDraw->type != DRAWABLE_WINDOW)
242 return NULL;
243
244 pm = ~RootlessAlphaMask(pDraw->bitsPerPixel);
245 if ((pGC->planemask & pm) != pm)
246 return NULL;
247
248 pTop = TopLevelParent((WindowPtr) pDraw);
249 if (pTop == NULL)
250 return NULL;
251
252 winRec = WINREC(pTop);
253 if (winRec == NULL)
254 return NULL;
255
256 return winRec;
257}
258
259static inline RootlessWindowRec *
260canAccelFill(DrawablePtr pDraw, GCPtr pGC)
261{
262 if (pGC->fillStyle != FillSolid)
263 return NULL;
264
265 return canAccelBlit(pDraw, pGC);
266}
267
268/*
269 * Screen function to create a graphics context
270 */
271Bool
272RootlessCreateGC(GCPtr pGC)
273{
274 RootlessGCRec *gcrec;
275 RootlessScreenRec *s;
276 Bool result;
277
278 SCREEN_UNWRAP(pGC->pScreen, CreateGC);
279 s = SCREENREC(pGC->pScreen);
280 result = s->CreateGC(pGC);
281
282 gcrec = (RootlessGCRec *)
283 dixLookupPrivate(&pGC->devPrivates, rootlessGCPrivateKey);
284 gcrec->originalOps = NULL; // don't wrap ops yet
285 gcrec->originalFuncs = pGC->funcs;
286 pGC->funcs = &rootlessGCFuncs;
287
288 SCREEN_WRAP(pGC->pScreen, CreateGC);
289 return result;
290}
291
292/*
293 * GC funcs
294 *
295 * These wrap lower level GC funcs.
296 * ValidateGC wraps the GC ops iff dest is viewable.
297 * All the others just unwrap and call.
298 */
299
300// GCFUNC_UNRAP assumes funcs have been wrapped and
301// does not assume ops have been wrapped
302#define GCFUNC_UNWRAP(pGC) \
303 RootlessGCRec *gcrec = (RootlessGCRec *) \
304 dixLookupPrivate(&(pGC)->devPrivates, rootlessGCPrivateKey); \
305 (pGC)->funcs = gcrec->originalFuncs; \
306 if (gcrec->originalOps) { \
307 (pGC)->ops = gcrec->originalOps; \
308}
309
310#define GCFUNC_WRAP(pGC) \
311 gcrec->originalFuncs = (pGC)->funcs; \
312 (pGC)->funcs = &rootlessGCFuncs; \
313 if (gcrec->originalOps) { \
314 gcrec->originalOps = (pGC)->ops; \
315 (pGC)->ops = &rootlessGCOps; \
316}
317
318static void
319RootlessValidateGC(GCPtr pGC, unsigned long changes, DrawablePtr pDrawable)
320{
321 GCFUNC_UNWRAP(pGC);
322
323 gcrec->originalOps = NULL;
324
325 if (pDrawable->type == DRAWABLE_WINDOW) {
326#ifdef ROOTLESS_PROTECT_ALPHA
327 unsigned int depth = pDrawable->depth;
328
329 // We force a planemask so fb doesn't overwrite the alpha channel.
330 // Left to its own devices, fb will optimize away the planemask.
331 pDrawable->depth = pDrawable->bitsPerPixel;
332 pGC->planemask &= ~RootlessAlphaMask(pDrawable->bitsPerPixel);
333 VALIDATE_GC(pGC, changes | GCPlaneMask, pDrawable);
334 pDrawable->depth = depth;
335#else
336 VALIDATE_GC(pGC, changes, pDrawable);
337#endif
338 }
339 else {
340 pGC->funcs->ValidateGC(pGC, changes, pDrawable);
341 }
342
343 GCFUNC_WRAP(pGC);
344}
345
346static void
347RootlessChangeGC(GCPtr pGC, unsigned long mask)
348{
349 GCFUNC_UNWRAP(pGC);
350 pGC->funcs->ChangeGC(pGC, mask);
351 GCFUNC_WRAP(pGC);
352}
353
354static void
355RootlessCopyGC(GCPtr pGCSrc, unsigned long mask, GCPtr pGCDst)
356{
357 GCFUNC_UNWRAP(pGCDst);
358 pGCDst->funcs->CopyGC(pGCSrc, mask, pGCDst);
359 GCFUNC_WRAP(pGCDst);
360}
361
362static void
363RootlessDestroyGC(GCPtr pGC)
364{
365 GCFUNC_UNWRAP(pGC);
366 pGC->funcs->DestroyGC(pGC);
367 GCFUNC_WRAP(pGC);
368}
369
370static void
371RootlessChangeClip(GCPtr pGC, int type, pointer pvalue, int nrects)
372{
373 GCFUNC_UNWRAP(pGC);
374 pGC->funcs->ChangeClip(pGC, type, pvalue, nrects);
375 GCFUNC_WRAP(pGC);
376}
377
378static void
379RootlessDestroyClip(GCPtr pGC)
380{
381 GCFUNC_UNWRAP(pGC);
382 pGC->funcs->DestroyClip(pGC);
383 GCFUNC_WRAP(pGC);
384}
385
386static void
387RootlessCopyClip(GCPtr pgcDst, GCPtr pgcSrc)
388{
389 GCFUNC_UNWRAP(pgcDst);
390 pgcDst->funcs->CopyClip(pgcDst, pgcSrc);
391 GCFUNC_WRAP(pgcDst);
392}
393
394/*
395 * GC ops
396 *
397 * We can't use shadowfb because shadowfb assumes one pixmap
398 * and our root window is a special case.
399 * However, much of this code is copied from shadowfb.
400 */
401
402// assumes both funcs and ops are wrapped
403#define GCOP_UNWRAP(pGC) \
404 RootlessGCRec *gcrec = (RootlessGCRec *) \
405 dixLookupPrivate(&(pGC)->devPrivates, rootlessGCPrivateKey); \
406 GCFuncs *saveFuncs = pGC->funcs; \
407 (pGC)->funcs = gcrec->originalFuncs; \
408 (pGC)->ops = gcrec->originalOps;
409
410#define GCOP_WRAP(pGC) \
411 gcrec->originalOps = (pGC)->ops; \
412 (pGC)->funcs = saveFuncs; \
413 (pGC)->ops = &rootlessGCOps;
414
415static void
416RootlessFillSpans(DrawablePtr dst, GCPtr pGC, int nInit,
417 DDXPointPtr pptInit, int *pwidthInit, int sorted)
418{
419 GC_SAVE(pGC);
420 GCOP_UNWRAP(pGC);
421 RL_DEBUG_MSG("fill spans start ");
422
423 if (nInit <= 0) {
424 pGC->ops->FillSpans(dst, pGC, nInit, pptInit, pwidthInit, sorted);
425 }
426 else {
427 DDXPointPtr ppt = pptInit;
428 int *pwidth = pwidthInit;
429 int i = nInit;
430 BoxRec box;
431
432 box.x1 = ppt->x;
433 box.x2 = box.x1 + *pwidth;
434 box.y2 = box.y1 = ppt->y;
435
436 while (--i) {
437 ppt++;
438 pwidth++;
439 if (box.x1 > ppt->x)
440 box.x1 = ppt->x;
441 if (box.x2 < (ppt->x + *pwidth))
442 box.x2 = ppt->x + *pwidth;
443 if (box.y1 > ppt->y)
444 box.y1 = ppt->y;
445 else if (box.y2 < ppt->y)
446 box.y2 = ppt->y;
447 }
448
449 box.y2++;
450
451 RootlessStartDrawing((WindowPtr) dst);
452
453 if (canAccelFill(dst, pGC)) {
454 GC_UNSET_PM(pGC, dst);
455 }
456
457 pGC->ops->FillSpans(dst, pGC, nInit, pptInit, pwidthInit, sorted);
458
459 TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
460 if (BOX_NOT_EMPTY(box))
461 RootlessDamageBox((WindowPtr) dst, &box);
462 }
463
464 GC_RESTORE(pGC, dst);
465 GCOP_WRAP(pGC);
466 RL_DEBUG_MSG("fill spans end\n");
467}
468
469static void
470RootlessSetSpans(DrawablePtr dst, GCPtr pGC, char *pSrc,
471 DDXPointPtr pptInit, int *pwidthInit, int nspans, int sorted)
472{
473 GCOP_UNWRAP(pGC);
474 RL_DEBUG_MSG("set spans start ");
475
476 if (nspans <= 0) {
477 pGC->ops->SetSpans(dst, pGC, pSrc, pptInit, pwidthInit, nspans, sorted);
478 }
479 else {
480 DDXPointPtr ppt = pptInit;
481 int *pwidth = pwidthInit;
482 int i = nspans;
483 BoxRec box;
484
485 box.x1 = ppt->x;
486 box.x2 = box.x1 + *pwidth;
487 box.y2 = box.y1 = ppt->y;
488
489 while (--i) {
490 ppt++;
491 pwidth++;
492 if (box.x1 > ppt->x)
493 box.x1 = ppt->x;
494 if (box.x2 < (ppt->x + *pwidth))
495 box.x2 = ppt->x + *pwidth;
496 if (box.y1 > ppt->y)
497 box.y1 = ppt->y;
498 else if (box.y2 < ppt->y)
499 box.y2 = ppt->y;
500 }
501
502 box.y2++;
503
504 RootlessStartDrawing((WindowPtr) dst);
505 pGC->ops->SetSpans(dst, pGC, pSrc, pptInit, pwidthInit, nspans, sorted);
506
507 TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
508 if (BOX_NOT_EMPTY(box))
509 RootlessDamageBox((WindowPtr) dst, &box);
510 }
511 GCOP_WRAP(pGC);
512 RL_DEBUG_MSG("set spans end\n");
513}
514
515static void
516RootlessPutImage(DrawablePtr dst, GCPtr pGC,
517 int depth, int x, int y, int w, int h,
518 int leftPad, int format, char *pBits)
519{
520 BoxRec box;
521
522 GCOP_UNWRAP(pGC);
523 RL_DEBUG_MSG("put image start ");
524
525 RootlessStartDrawing((WindowPtr) dst);
526 pGC->ops->PutImage(dst, pGC, depth, x, y, w, h, leftPad, format, pBits);
527
528 box.x1 = x + dst->x;
529 box.x2 = box.x1 + w;
530 box.y1 = y + dst->y;
531 box.y2 = box.y1 + h;
532
533 TRIM_BOX(box, pGC);
534 if (BOX_NOT_EMPTY(box))
535 RootlessDamageBox((WindowPtr) dst, &box);
536
537 GCOP_WRAP(pGC);
538 RL_DEBUG_MSG("put image end\n");
539}
540
541/* changed area is *dest* rect */
542static RegionPtr
543RootlessCopyArea(DrawablePtr pSrc, DrawablePtr dst, GCPtr pGC,
544 int srcx, int srcy, int w, int h, int dstx, int dsty)
545{
546 RegionPtr result;
547 BoxRec box;
548
549 GC_SAVE(pGC);
550 GCOP_UNWRAP(pGC);
551
552 RL_DEBUG_MSG("copy area start (src 0x%x, dst 0x%x)", pSrc, dst);
553
554 if (pSrc->type == DRAWABLE_WINDOW && IsFramedWindow((WindowPtr) pSrc)) {
555 /* If both source and dest are windows, and we're doing
556 a simple copy operation, we can remove the alpha-protecting
557 planemask (since source has opaque alpha as well) */
558
559 if (canAccelBlit(pSrc, pGC)) {
560 GC_UNSET_PM(pGC, dst);
561 }
562
563 RootlessStartDrawing((WindowPtr) pSrc);
564 }
565 RootlessStartDrawing((WindowPtr) dst);
566 result = pGC->ops->CopyArea(pSrc, dst, pGC, srcx, srcy, w, h, dstx, dsty);
567
568 box.x1 = dstx + dst->x;
569 box.x2 = box.x1 + w;
570 box.y1 = dsty + dst->y;
571 box.y2 = box.y1 + h;
572
573 TRIM_BOX(box, pGC);
574 if (BOX_NOT_EMPTY(box))
575 RootlessDamageBox((WindowPtr) dst, &box);
576
577 GC_RESTORE(pGC, dst);
578 GCOP_WRAP(pGC);
579 RL_DEBUG_MSG("copy area end\n");
580 return result;
581}
582
583/* changed area is *dest* rect */
584static RegionPtr
585RootlessCopyPlane(DrawablePtr pSrc, DrawablePtr dst,
586 GCPtr pGC, int srcx, int srcy,
587 int w, int h, int dstx, int dsty, unsigned long plane)
588{
589 RegionPtr result;
590 BoxRec box;
591
592 GCOP_UNWRAP(pGC);
593
594 RL_DEBUG_MSG("copy plane start ");
595
596 if (pSrc->type == DRAWABLE_WINDOW && IsFramedWindow((WindowPtr) pSrc)) {
597 RootlessStartDrawing((WindowPtr) pSrc);
598 }
599 RootlessStartDrawing((WindowPtr) dst);
600 result = pGC->ops->CopyPlane(pSrc, dst, pGC, srcx, srcy, w, h,
601 dstx, dsty, plane);
602
603 box.x1 = dstx + dst->x;
604 box.x2 = box.x1 + w;
605 box.y1 = dsty + dst->y;
606 box.y2 = box.y1 + h;
607
608 TRIM_BOX(box, pGC);
609 if (BOX_NOT_EMPTY(box))
610 RootlessDamageBox((WindowPtr) dst, &box);
611
612 GCOP_WRAP(pGC);
613 RL_DEBUG_MSG("copy plane end\n");
614 return result;
615}
616
617// Options for size of changed area:
618// 0 = box per point
619// 1 = big box around all points
620// 2 = accumulate point in 20 pixel radius
621#define ROOTLESS_CHANGED_AREA 1
622#define abs(a) ((a) > 0 ? (a) : -(a))
623
624/* changed area is box around all points */
625static void
626RootlessPolyPoint(DrawablePtr dst, GCPtr pGC,
627 int mode, int npt, DDXPointPtr pptInit)
628{
629 GCOP_UNWRAP(pGC);
630 RL_DEBUG_MSG("polypoint start ");
631
632 RootlessStartDrawing((WindowPtr) dst);
633 pGC->ops->PolyPoint(dst, pGC, mode, npt, pptInit);
634
635 if (npt > 0) {
636#if ROOTLESS_CHANGED_AREA==0
637 // box per point
638 BoxRec box;
639
640 while (npt) {
641 box.x1 = pptInit->x;
642 box.y1 = pptInit->y;
643 box.x2 = box.x1 + 1;
644 box.y2 = box.y1 + 1;
645
646 TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
647 if (BOX_NOT_EMPTY(box))
648 RootlessDamageBox((WindowPtr) dst, &box);
649
650 npt--;
651 pptInit++;
652 }
653
654#elif ROOTLESS_CHANGED_AREA==1
655 // one big box
656 BoxRec box;
657
658 box.x2 = box.x1 = pptInit->x;
659 box.y2 = box.y1 = pptInit->y;
660 while (--npt) {
661 pptInit++;
662 if (box.x1 > pptInit->x)
663 box.x1 = pptInit->x;
664 else if (box.x2 < pptInit->x)
665 box.x2 = pptInit->x;
666 if (box.y1 > pptInit->y)
667 box.y1 = pptInit->y;
668 else if (box.y2 < pptInit->y)
669 box.y2 = pptInit->y;
670 }
671
672 box.x2++;
673 box.y2++;
674
675 TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
676 if (BOX_NOT_EMPTY(box))
677 RootlessDamageBox((WindowPtr) dst, &box);
678
679#elif ROOTLESS_CHANGED_AREA==2
680 // clever(?) method: accumulate point in 20-pixel radius
681 BoxRec box;
682 int firstx, firsty;
683
684 box.x2 = box.x1 = firstx = pptInit->x;
685 box.y2 = box.y1 = firsty = pptInit->y;
686 while (--npt) {
687 pptInit++;
688 if (abs(pptInit->x - firstx) > 20 || abs(pptInit->y - firsty) > 20) {
689 box.x2++;
690 box.y2++;
691 TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
692 if (BOX_NOT_EMPTY(box))
693 RootlessDamageBox((WindowPtr) dst, &box);
694 box.x2 = box.x1 = firstx = pptInit->x;
695 box.y2 = box.y1 = firsty = pptInit->y;
696 }
697 else {
698 if (box.x1 > pptInit->x)
699 box.x1 = pptInit->x;
700 else if (box.x2 < pptInit->x)
701 box.x2 = pptInit->x;
702 if (box.y1 > pptInit->y)
703 box.y1 = pptInit->y;
704 else if (box.y2 < pptInit->y)
705 box.y2 = pptInit->y;
706 }
707 }
708 box.x2++;
709 box.y2++;
710 TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
711 if (BOX_NOT_EMPTY(box))
712 RootlessDamageBox((WindowPtr) dst, &box);
713#endif /* ROOTLESS_CHANGED_AREA */
714 }
715
716 GCOP_WRAP(pGC);
717 RL_DEBUG_MSG("polypoint end\n");
718}
719
720#undef ROOTLESS_CHANGED_AREA
721
722/* changed area is box around each line */
723static void
724RootlessPolylines(DrawablePtr dst, GCPtr pGC,
725 int mode, int npt, DDXPointPtr pptInit)
726{
727 GCOP_UNWRAP(pGC);
728 RL_DEBUG_MSG("poly lines start ");
729
730 RootlessStartDrawing((WindowPtr) dst);
731 pGC->ops->Polylines(dst, pGC, mode, npt, pptInit);
732
733 if (npt > 0) {
734 BoxRec box;
735 int extra = pGC->lineWidth >> 1;
736
737 box.x2 = box.x1 = pptInit->x;
738 box.y2 = box.y1 = pptInit->y;
739
740 if (npt > 1) {
741 if (pGC->joinStyle == JoinMiter)
742 extra = 6 * pGC->lineWidth;
743 else if (pGC->capStyle == CapProjecting)
744 extra = pGC->lineWidth;
745 }
746
747 if (mode == CoordModePrevious) {
748 int x = box.x1;
749 int y = box.y1;
750
751 while (--npt) {
752 pptInit++;
753 x += pptInit->x;
754 y += pptInit->y;
755 if (box.x1 > x)
756 box.x1 = x;
757 else if (box.x2 < x)
758 box.x2 = x;
759 if (box.y1 > y)
760 box.y1 = y;
761 else if (box.y2 < y)
762 box.y2 = y;
763 }
764 }
765 else {
766 while (--npt) {
767 pptInit++;
768 if (box.x1 > pptInit->x)
769 box.x1 = pptInit->x;
770 else if (box.x2 < pptInit->x)
771 box.x2 = pptInit->x;
772 if (box.y1 > pptInit->y)
773 box.y1 = pptInit->y;
774 else if (box.y2 < pptInit->y)
775 box.y2 = pptInit->y;
776 }
777 }
778
779 box.x2++;
780 box.y2++;
781
782 if (extra) {
783 box.x1 -= extra;
784 box.x2 += extra;
785 box.y1 -= extra;
786 box.y2 += extra;
787 }
788
789 TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
790 if (BOX_NOT_EMPTY(box))
791 RootlessDamageBox((WindowPtr) dst, &box);
792 }
793
794 GCOP_WRAP(pGC);
795 RL_DEBUG_MSG("poly lines end\n");
796}
797
798/* changed area is box around each line segment */
799static void
800RootlessPolySegment(DrawablePtr dst, GCPtr pGC, int nseg, xSegment * pSeg)
801{
802 GCOP_UNWRAP(pGC);
803 RL_DEBUG_MSG("poly segment start (win 0x%x)", dst);
804
805 RootlessStartDrawing((WindowPtr) dst);
806 pGC->ops->PolySegment(dst, pGC, nseg, pSeg);
807
808 if (nseg > 0) {
809 BoxRec box;
810 int extra = pGC->lineWidth;
811
812 if (pGC->capStyle != CapProjecting)
813 extra >>= 1;
814
815 if (pSeg->x2 > pSeg->x1) {
816 box.x1 = pSeg->x1;
817 box.x2 = pSeg->x2;
818 }
819 else {
820 box.x2 = pSeg->x1;
821 box.x1 = pSeg->x2;
822 }
823
824 if (pSeg->y2 > pSeg->y1) {
825 box.y1 = pSeg->y1;
826 box.y2 = pSeg->y2;
827 }
828 else {
829 box.y2 = pSeg->y1;
830 box.y1 = pSeg->y2;
831 }
832
833 while (--nseg) {
834 pSeg++;
835 if (pSeg->x2 > pSeg->x1) {
836 if (pSeg->x1 < box.x1)
837 box.x1 = pSeg->x1;
838 if (pSeg->x2 > box.x2)
839 box.x2 = pSeg->x2;
840 }
841 else {
842 if (pSeg->x2 < box.x1)
843 box.x1 = pSeg->x2;
844 if (pSeg->x1 > box.x2)
845 box.x2 = pSeg->x1;
846 }
847 if (pSeg->y2 > pSeg->y1) {
848 if (pSeg->y1 < box.y1)
849 box.y1 = pSeg->y1;
850 if (pSeg->y2 > box.y2)
851 box.y2 = pSeg->y2;
852 }
853 else {
854 if (pSeg->y2 < box.y1)
855 box.y1 = pSeg->y2;
856 if (pSeg->y1 > box.y2)
857 box.y2 = pSeg->y1;
858 }
859 }
860
861 box.x2++;
862 box.y2++;
863
864 if (extra) {
865 box.x1 -= extra;
866 box.x2 += extra;
867 box.y1 -= extra;
868 box.y2 += extra;
869 }
870
871 TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
872 if (BOX_NOT_EMPTY(box))
873 RootlessDamageBox((WindowPtr) dst, &box);
874 }
875
876 GCOP_WRAP(pGC);
877 RL_DEBUG_MSG("poly segment end\n");
878}
879
880/* changed area is box around each line (not entire rects) */
881static void
882RootlessPolyRectangle(DrawablePtr dst, GCPtr pGC,
883 int nRects, xRectangle *pRects)
884{
885 GCOP_UNWRAP(pGC);
886 RL_DEBUG_MSG("poly rectangle start ");
887
888 RootlessStartDrawing((WindowPtr) dst);
889 pGC->ops->PolyRectangle(dst, pGC, nRects, pRects);
890
891 if (nRects > 0) {
892 BoxRec box;
893 int offset1, offset2, offset3;
894
895 offset2 = pGC->lineWidth;
896 if (!offset2)
897 offset2 = 1;
898 offset1 = offset2 >> 1;
899 offset3 = offset2 - offset1;
900
901 while (nRects--) {
902 box.x1 = pRects->x - offset1;
903 box.y1 = pRects->y - offset1;
904 box.x2 = box.x1 + pRects->width + offset2;
905 box.y2 = box.y1 + offset2;
906 TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
907 if (BOX_NOT_EMPTY(box))
908 RootlessDamageBox((WindowPtr) dst, &box);
909
910 box.x1 = pRects->x - offset1;
911 box.y1 = pRects->y + offset3;
912 box.x2 = box.x1 + offset2;
913 box.y2 = box.y1 + pRects->height - offset2;
914 TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
915 if (BOX_NOT_EMPTY(box))
916 RootlessDamageBox((WindowPtr) dst, &box);
917
918 box.x1 = pRects->x + pRects->width - offset1;
919 box.y1 = pRects->y + offset3;
920 box.x2 = box.x1 + offset2;
921 box.y2 = box.y1 + pRects->height - offset2;
922 TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
923 if (BOX_NOT_EMPTY(box))
924 RootlessDamageBox((WindowPtr) dst, &box);
925
926 box.x1 = pRects->x - offset1;
927 box.y1 = pRects->y + pRects->height - offset1;
928 box.x2 = box.x1 + pRects->width + offset2;
929 box.y2 = box.y1 + offset2;
930 TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
931 if (BOX_NOT_EMPTY(box))
932 RootlessDamageBox((WindowPtr) dst, &box);
933
934 pRects++;
935 }
936 }
937
938 GCOP_WRAP(pGC);
939 RL_DEBUG_MSG("poly rectangle end\n");
940}
941
942/* changed area is box around each arc (assumes all arcs are 360 degrees) */
943static void
944RootlessPolyArc(DrawablePtr dst, GCPtr pGC, int narcs, xArc * parcs)
945{
946 GCOP_UNWRAP(pGC);
947 RL_DEBUG_MSG("poly arc start ");
948
949 RootlessStartDrawing((WindowPtr) dst);
950 pGC->ops->PolyArc(dst, pGC, narcs, parcs);
951
952 if (narcs > 0) {
953 int extra = pGC->lineWidth >> 1;
954 BoxRec box;
955
956 box.x1 = parcs->x;
957 box.x2 = box.x1 + parcs->width;
958 box.y1 = parcs->y;
959 box.y2 = box.y1 + parcs->height;
960
961 /* should I break these up instead ? */
962
963 while (--narcs) {
964 parcs++;
965 if (box.x1 > parcs->x)
966 box.x1 = parcs->x;
967 if (box.x2 < (parcs->x + parcs->width))
968 box.x2 = parcs->x + parcs->width;
969 if (box.y1 > parcs->y)
970 box.y1 = parcs->y;
971 if (box.y2 < (parcs->y + parcs->height))
972 box.y2 = parcs->y + parcs->height;
973 }
974
975 if (extra) {
976 box.x1 -= extra;
977 box.x2 += extra;
978 box.y1 -= extra;
979 box.y2 += extra;
980 }
981
982 box.x2++;
983 box.y2++;
984
985 TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
986 if (BOX_NOT_EMPTY(box))
987 RootlessDamageBox((WindowPtr) dst, &box);
988 }
989
990 GCOP_WRAP(pGC);
991 RL_DEBUG_MSG("poly arc end\n");
992}
993
994/* changed area is box around each poly */
995static void
996RootlessFillPolygon(DrawablePtr dst, GCPtr pGC,
997 int shape, int mode, int count, DDXPointPtr pptInit)
998{
999 GC_SAVE(pGC);
1000 GCOP_UNWRAP(pGC);
1001 RL_DEBUG_MSG("fill poly start (win 0x%x, fillStyle 0x%x)", dst,
1002 pGC->fillStyle);
1003
1004 if (count <= 2) {
1005 pGC->ops->FillPolygon(dst, pGC, shape, mode, count, pptInit);
1006 }
1007 else {
1008 DDXPointPtr ppt = pptInit;
1009 int i = count;
1010 BoxRec box;
1011
1012 box.x2 = box.x1 = ppt->x;
1013 box.y2 = box.y1 = ppt->y;
1014
1015 if (mode != CoordModeOrigin) {
1016 int x = box.x1;
1017 int y = box.y1;
1018
1019 while (--i) {
1020 ppt++;
1021 x += ppt->x;
1022 y += ppt->y;
1023 if (box.x1 > x)
1024 box.x1 = x;
1025 else if (box.x2 < x)
1026 box.x2 = x;
1027 if (box.y1 > y)
1028 box.y1 = y;
1029 else if (box.y2 < y)
1030 box.y2 = y;
1031 }
1032 }
1033 else {
1034 while (--i) {
1035 ppt++;
1036 if (box.x1 > ppt->x)
1037 box.x1 = ppt->x;
1038 else if (box.x2 < ppt->x)
1039 box.x2 = ppt->x;
1040 if (box.y1 > ppt->y)
1041 box.y1 = ppt->y;
1042 else if (box.y2 < ppt->y)
1043 box.y2 = ppt->y;
1044 }
1045 }
1046
1047 box.x2++;
1048 box.y2++;
1049
1050 RootlessStartDrawing((WindowPtr) dst);
1051
1052 if (canAccelFill(dst, pGC)) {
1053 GC_UNSET_PM(pGC, dst);
1054 }
1055
1056 pGC->ops->FillPolygon(dst, pGC, shape, mode, count, pptInit);
1057
1058 TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
1059 if (BOX_NOT_EMPTY(box))
1060 RootlessDamageBox((WindowPtr) dst, &box);
1061 }
1062
1063 GC_RESTORE(pGC, dst);
1064 GCOP_WRAP(pGC);
1065 RL_DEBUG_MSG("fill poly end\n");
1066}
1067
1068/* changed area is the rects */
1069static void
1070RootlessPolyFillRect(DrawablePtr dst, GCPtr pGC,
1071 int nRectsInit, xRectangle *pRectsInit)
1072{
1073 GC_SAVE(pGC);
1074 GCOP_UNWRAP(pGC);
1075 RL_DEBUG_MSG("fill rect start (win 0x%x, fillStyle 0x%x)", dst,
1076 pGC->fillStyle);
1077
1078 if (nRectsInit <= 0) {
1079 pGC->ops->PolyFillRect(dst, pGC, nRectsInit, pRectsInit);
1080 }
1081 else {
1082 BoxRec box;
1083 xRectangle *pRects = pRectsInit;
1084 int nRects = nRectsInit;
1085
1086 box.x1 = pRects->x;
1087 box.x2 = box.x1 + pRects->width;
1088 box.y1 = pRects->y;
1089 box.y2 = box.y1 + pRects->height;
1090
1091 while (--nRects) {
1092 pRects++;
1093 if (box.x1 > pRects->x)
1094 box.x1 = pRects->x;
1095 if (box.x2 < (pRects->x + pRects->width))
1096 box.x2 = pRects->x + pRects->width;
1097 if (box.y1 > pRects->y)
1098 box.y1 = pRects->y;
1099 if (box.y2 < (pRects->y + pRects->height))
1100 box.y2 = pRects->y + pRects->height;
1101 }
1102
1103 RootlessStartDrawing((WindowPtr) dst);
1104
1105 if (canAccelFill(dst, pGC)) {
1106 GC_UNSET_PM(pGC, dst);
1107 }
1108
1109 pGC->ops->PolyFillRect(dst, pGC, nRectsInit, pRectsInit);
1110
1111 TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
1112 if (BOX_NOT_EMPTY(box))
1113 RootlessDamageBox((WindowPtr) dst, &box);
1114 }
1115
1116 GC_RESTORE(pGC, dst);
1117 GCOP_WRAP(pGC);
1118 RL_DEBUG_MSG("fill rect end\n");
1119}
1120
1121/* changed area is box around each arc (assuming arcs are all 360 degrees) */
1122static void
1123RootlessPolyFillArc(DrawablePtr dst, GCPtr pGC, int narcsInit, xArc * parcsInit)
1124{
1125 GC_SAVE(pGC);
1126 GCOP_UNWRAP(pGC);
1127 RL_DEBUG_MSG("fill arc start ");
1128
1129 if (narcsInit > 0) {
1130 BoxRec box;
1131 int narcs = narcsInit;
1132 xArc *parcs = parcsInit;
1133
1134 box.x1 = parcs->x;
1135 box.x2 = box.x1 + parcs->width;
1136 box.y1 = parcs->y;
1137 box.y2 = box.y1 + parcs->height;
1138
1139 /* should I break these up instead ? */
1140
1141 while (--narcs) {
1142 parcs++;
1143 if (box.x1 > parcs->x)
1144 box.x1 = parcs->x;
1145 if (box.x2 < (parcs->x + parcs->width))
1146 box.x2 = parcs->x + parcs->width;
1147 if (box.y1 > parcs->y)
1148 box.y1 = parcs->y;
1149 if (box.y2 < (parcs->y + parcs->height))
1150 box.y2 = parcs->y + parcs->height;
1151 }
1152
1153 RootlessStartDrawing((WindowPtr) dst);
1154
1155 if (canAccelFill(dst, pGC)) {
1156 GC_UNSET_PM(pGC, dst);
1157 }
1158
1159 pGC->ops->PolyFillArc(dst, pGC, narcsInit, parcsInit);
1160
1161 TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
1162 if (BOX_NOT_EMPTY(box))
1163 RootlessDamageBox((WindowPtr) dst, &box);
1164 }
1165 else {
1166 pGC->ops->PolyFillArc(dst, pGC, narcsInit, parcsInit);
1167 }
1168
1169 GC_RESTORE(pGC, dst);
1170 GCOP_WRAP(pGC);
1171 RL_DEBUG_MSG("fill arc end\n");
1172}
1173
1174static void
1175RootlessImageText8(DrawablePtr dst, GCPtr pGC,
1176 int x, int y, int count, char *chars)
1177{
1178 GC_SAVE(pGC);
1179 GCOP_UNWRAP(pGC);
1180 RL_DEBUG_MSG("imagetext8 start ");
1181
1182 if (count > 0) {
1183 int top, bot, Min, Max;
1184 BoxRec box;
1185
1186 top = max(FONTMAXBOUNDS(pGC->font, ascent), FONTASCENT(pGC->font));
1187 bot = max(FONTMAXBOUNDS(pGC->font, descent), FONTDESCENT(pGC->font));
1188
1189 Min = count * FONTMINBOUNDS(pGC->font, characterWidth);
1190 if (Min > 0)
1191 Min = 0;
1192 Max = count * FONTMAXBOUNDS(pGC->font, characterWidth);
1193 if (Max < 0)
1194 Max = 0;
1195
1196 /* ugh */
1197 box.x1 = dst->x + x + Min + FONTMINBOUNDS(pGC->font, leftSideBearing);
1198 box.x2 = dst->x + x + Max + FONTMAXBOUNDS(pGC->font, rightSideBearing);
1199
1200 box.y1 = dst->y + y - top;
1201 box.y2 = dst->y + y + bot;
1202
1203 RootlessStartDrawing((WindowPtr) dst);
1204
1205 if (canAccelFill(dst, pGC)) {
1206 GC_UNSET_PM(pGC, dst);
1207 }
1208
1209 pGC->ops->ImageText8(dst, pGC, x, y, count, chars);
1210
1211 TRIM_BOX(box, pGC);
1212 if (BOX_NOT_EMPTY(box))
1213 RootlessDamageBox((WindowPtr) dst, &box);
1214 }
1215 else {
1216 pGC->ops->ImageText8(dst, pGC, x, y, count, chars);
1217 }
1218
1219 GC_RESTORE(pGC, dst);
1220 GCOP_WRAP(pGC);
1221 RL_DEBUG_MSG("imagetext8 end\n");
1222}
1223
1224static int
1225RootlessPolyText8(DrawablePtr dst, GCPtr pGC,
1226 int x, int y, int count, char *chars)
1227{
1228 int width; // the result, sorta
1229
1230 GCOP_UNWRAP(pGC);
1231
1232 RL_DEBUG_MSG("polytext8 start ");
1233
1234 RootlessStartDrawing((WindowPtr) dst);
1235 width = pGC->ops->PolyText8(dst, pGC, x, y, count, chars);
1236 width -= x;
1237
1238 if (width > 0) {
1239 BoxRec box;
1240
1241 /* ugh */
1242 box.x1 = dst->x + x + FONTMINBOUNDS(pGC->font, leftSideBearing);
1243 box.x2 = dst->x + x + FONTMAXBOUNDS(pGC->font, rightSideBearing);
1244
1245 if (count > 1) {
1246 if (width > 0)
1247 box.x2 += width;
1248 else
1249 box.x1 += width;
1250 }
1251
1252 box.y1 = dst->y + y - FONTMAXBOUNDS(pGC->font, ascent);
1253 box.y2 = dst->y + y + FONTMAXBOUNDS(pGC->font, descent);
1254
1255 TRIM_BOX(box, pGC);
1256 if (BOX_NOT_EMPTY(box))
1257 RootlessDamageBox((WindowPtr) dst, &box);
1258 }
1259
1260 GCOP_WRAP(pGC);
1261 RL_DEBUG_MSG("polytext8 end\n");
1262 return width + x;
1263}
1264
1265static void
1266RootlessImageText16(DrawablePtr dst, GCPtr pGC,
1267 int x, int y, int count, unsigned short *chars)
1268{
1269 GC_SAVE(pGC);
1270 GCOP_UNWRAP(pGC);
1271 RL_DEBUG_MSG("imagetext16 start ");
1272
1273 if (count > 0) {
1274 int top, bot, Min, Max;
1275 BoxRec box;
1276
1277 top = max(FONTMAXBOUNDS(pGC->font, ascent), FONTASCENT(pGC->font));
1278 bot = max(FONTMAXBOUNDS(pGC->font, descent), FONTDESCENT(pGC->font));
1279
1280 Min = count * FONTMINBOUNDS(pGC->font, characterWidth);
1281 if (Min > 0)
1282 Min = 0;
1283 Max = count * FONTMAXBOUNDS(pGC->font, characterWidth);
1284 if (Max < 0)
1285 Max = 0;
1286
1287 /* ugh */
1288 box.x1 = dst->x + x + Min + FONTMINBOUNDS(pGC->font, leftSideBearing);
1289 box.x2 = dst->x + x + Max + FONTMAXBOUNDS(pGC->font, rightSideBearing);
1290
1291 box.y1 = dst->y + y - top;
1292 box.y2 = dst->y + y + bot;
1293
1294 RootlessStartDrawing((WindowPtr) dst);
1295
1296 if (canAccelFill(dst, pGC)) {
1297 GC_UNSET_PM(pGC, dst);
1298 }
1299
1300 pGC->ops->ImageText16(dst, pGC, x, y, count, chars);
1301
1302 TRIM_BOX(box, pGC);
1303 if (BOX_NOT_EMPTY(box))
1304 RootlessDamageBox((WindowPtr) dst, &box);
1305 }
1306 else {
1307 pGC->ops->ImageText16(dst, pGC, x, y, count, chars);
1308 }
1309
1310 GC_RESTORE(pGC, dst);
1311 GCOP_WRAP(pGC);
1312 RL_DEBUG_MSG("imagetext16 end\n");
1313}
1314
1315static int
1316RootlessPolyText16(DrawablePtr dst, GCPtr pGC,
1317 int x, int y, int count, unsigned short *chars)
1318{
1319 int width; // the result, sorta
1320
1321 GCOP_UNWRAP(pGC);
1322
1323 RL_DEBUG_MSG("polytext16 start ");
1324
1325 RootlessStartDrawing((WindowPtr) dst);
1326 width = pGC->ops->PolyText16(dst, pGC, x, y, count, chars);
1327 width -= x;
1328
1329 if (width > 0) {
1330 BoxRec box;
1331
1332 /* ugh */
1333 box.x1 = dst->x + x + FONTMINBOUNDS(pGC->font, leftSideBearing);
1334 box.x2 = dst->x + x + FONTMAXBOUNDS(pGC->font, rightSideBearing);
1335
1336 if (count > 1) {
1337 if (width > 0)
1338 box.x2 += width;
1339 else
1340 box.x1 += width;
1341 }
1342
1343 box.y1 = dst->y + y - FONTMAXBOUNDS(pGC->font, ascent);
1344 box.y2 = dst->y + y + FONTMAXBOUNDS(pGC->font, descent);
1345
1346 TRIM_BOX(box, pGC);
1347 if (BOX_NOT_EMPTY(box))
1348 RootlessDamageBox((WindowPtr) dst, &box);
1349 }
1350
1351 GCOP_WRAP(pGC);
1352 RL_DEBUG_MSG("polytext16 end\n");
1353 return width + x;
1354}
1355
1356static void
1357RootlessImageGlyphBlt(DrawablePtr dst, GCPtr pGC,
1358 int x, int y, unsigned int nglyphInit,
1359 CharInfoPtr * ppciInit, pointer unused)
1360{
1361 GC_SAVE(pGC);
1362 GCOP_UNWRAP(pGC);
1363 RL_DEBUG_MSG("imageglyph start ");
1364
1365 if (nglyphInit > 0) {
1366 int top, bot, width = 0;
1367 BoxRec box;
1368 unsigned int nglyph = nglyphInit;
1369 CharInfoPtr *ppci = ppciInit;
1370
1371 top = max(FONTMAXBOUNDS(pGC->font, ascent), FONTASCENT(pGC->font));
1372 bot = max(FONTMAXBOUNDS(pGC->font, descent), FONTDESCENT(pGC->font));
1373
1374 box.x1 = ppci[0]->metrics.leftSideBearing;
1375 if (box.x1 > 0)
1376 box.x1 = 0;
1377 box.x2 = ppci[nglyph - 1]->metrics.rightSideBearing -
1378 ppci[nglyph - 1]->metrics.characterWidth;
1379 if (box.x2 < 0)
1380 box.x2 = 0;
1381
1382 box.x2 += dst->x + x;
1383 box.x1 += dst->x + x;
1384
1385 while (nglyph--) {
1386 width += (*ppci)->metrics.characterWidth;
1387 ppci++;
1388 }
1389
1390 if (width > 0)
1391 box.x2 += width;
1392 else
1393 box.x1 += width;
1394
1395 box.y1 = dst->y + y - top;
1396 box.y2 = dst->y + y + bot;
1397
1398 RootlessStartDrawing((WindowPtr) dst);
1399
1400 if (canAccelFill(dst, pGC)) {
1401 GC_UNSET_PM(pGC, dst);
1402 }
1403
1404 pGC->ops->ImageGlyphBlt(dst, pGC, x, y, nglyphInit, ppciInit, unused);
1405
1406 TRIM_BOX(box, pGC);
1407 if (BOX_NOT_EMPTY(box))
1408 RootlessDamageBox((WindowPtr) dst, &box);
1409 }
1410 else {
1411 pGC->ops->ImageGlyphBlt(dst, pGC, x, y, nglyphInit, ppciInit, unused);
1412 }
1413
1414 GC_RESTORE(pGC, dst);
1415 GCOP_WRAP(pGC);
1416 RL_DEBUG_MSG("imageglyph end\n");
1417}
1418
1419static void
1420RootlessPolyGlyphBlt(DrawablePtr dst, GCPtr pGC,
1421 int x, int y, unsigned int nglyph,
1422 CharInfoPtr * ppci, pointer pglyphBase)
1423{
1424 GCOP_UNWRAP(pGC);
1425 RL_DEBUG_MSG("polyglyph start ");
1426
1427 RootlessStartDrawing((WindowPtr) dst);
1428 pGC->ops->PolyGlyphBlt(dst, pGC, x, y, nglyph, ppci, pglyphBase);
1429
1430 if (nglyph > 0) {
1431 BoxRec box;
1432
1433 /* ugh */
1434 box.x1 = dst->x + x + ppci[0]->metrics.leftSideBearing;
1435 box.x2 = dst->x + x + ppci[nglyph - 1]->metrics.rightSideBearing;
1436
1437 if (nglyph > 1) {
1438 int width = 0;
1439
1440 while (--nglyph) {
1441 width += (*ppci)->metrics.characterWidth;
1442 ppci++;
1443 }
1444
1445 if (width > 0)
1446 box.x2 += width;
1447 else
1448 box.x1 += width;
1449 }
1450
1451 box.y1 = dst->y + y - FONTMAXBOUNDS(pGC->font, ascent);
1452 box.y2 = dst->y + y + FONTMAXBOUNDS(pGC->font, descent);
1453
1454 TRIM_BOX(box, pGC);
1455 if (BOX_NOT_EMPTY(box))
1456 RootlessDamageBox((WindowPtr) dst, &box);
1457 }
1458
1459 GCOP_WRAP(pGC);
1460 RL_DEBUG_MSG("polyglyph end\n");
1461}
1462
1463/* changed area is in dest */
1464static void
1465RootlessPushPixels(GCPtr pGC, PixmapPtr pBitMap, DrawablePtr dst,
1466 int dx, int dy, int xOrg, int yOrg)
1467{
1468 BoxRec box;
1469
1470 GCOP_UNWRAP(pGC);
1471 RL_DEBUG_MSG("push pixels start ");
1472
1473 RootlessStartDrawing((WindowPtr) dst);
1474 pGC->ops->PushPixels(pGC, pBitMap, dst, dx, dy, xOrg, yOrg);
1475
1476 box.x1 = xOrg + dst->x;
1477 box.x2 = box.x1 + dx;
1478 box.y1 = yOrg + dst->y;
1479 box.y2 = box.y1 + dy;
1480
1481 TRIM_BOX(box, pGC);
1482 if (BOX_NOT_EMPTY(box))
1483 RootlessDamageBox((WindowPtr) dst, &box);
1484
1485 GCOP_WRAP(pGC);
1486 RL_DEBUG_MSG("push pixels end\n");
1487}