First import
[xorg_rtime.git] / xorg-server-1.4 / afb / afbgc.c
blob59c09e0975937ad0eb75d6aa13c989f68e4c0111
1 /***********************************************************
3 Copyright (c) 1987 X Consortium
5 Permission is hereby granted, free of charge, to any person obtaining a copy
6 of this software and associated documentation files (the "Software"), to deal
7 in the Software without restriction, including without limitation the rights
8 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 copies of the Software, and to permit persons to whom the Software is
10 furnished to do so, subject to the following conditions:
12 The above copyright notice and this permission notice shall be included in
13 all copies or substantial portions of the Software.
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
19 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 Except as contained in this notice, the name of the X Consortium shall not be
23 used in advertising or otherwise to promote the sale, use or other dealings
24 in this Software without prior written authorization from the X Consortium.
27 Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
29 All Rights Reserved
31 Permission to use, copy, modify, and distribute this software and its
32 documentation for any purpose and without fee is hereby granted,
33 provided that the above copyright notice appear in all copies and that
34 both that copyright notice and this permission notice appear in
35 supporting documentation, and that the name of Digital not be
36 used in advertising or publicity pertaining to distribution of the
37 software without specific, written prior permission.
39 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
40 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
41 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
42 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
43 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
44 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
45 SOFTWARE.
47 ******************************************************************/
49 #ifdef HAVE_DIX_CONFIG_H
50 #include <dix-config.h>
51 #endif
53 #include <string.h>
55 #include <X11/X.h>
56 #include <X11/Xmd.h>
57 #include <X11/Xproto.h>
58 #include "afb.h"
59 #include "dixfontstr.h"
60 #include <X11/fonts/fontstruct.h>
61 #include "gcstruct.h"
62 #include "windowstr.h"
63 #include "pixmapstr.h"
64 #include "scrnintstr.h"
65 #include "region.h"
67 #include "mistruct.h"
68 #include "migc.h"
70 #include "maskbits.h"
72 static void afbDestroyGC(GCPtr);
73 static void afbValidateGC(GCPtr, unsigned long, DrawablePtr);
75 static GCFuncs afbFuncs = {
76 afbValidateGC,
77 miChangeGC,
78 miCopyGC,
79 afbDestroyGC,
80 miChangeClip,
81 miDestroyClip,
82 miCopyClip
85 static GCOps afbGCOps = {
86 afbSolidFS,
87 afbSetSpans,
88 afbPutImage,
89 afbCopyArea,
90 miCopyPlane,
91 afbPolyPoint,
92 afbLineSS,
93 afbSegmentSS,
94 miPolyRectangle,
95 afbZeroPolyArcSS,
96 afbFillPolygonSolid,
97 afbPolyFillRect,
98 afbPolyFillArcSolid,
99 miPolyText8,
100 miPolyText16,
101 miImageText8,
102 miImageText16,
103 afbTEGlyphBlt,
104 afbPolyGlyphBlt,
105 afbPushPixels
108 static void
109 afbReduceOpaqueStipple(PixelType fg, PixelType bg, unsigned long planemask,
110 int depth, unsigned char *rop)
112 register int d;
113 register Pixel mask = 1;
115 bg ^= fg;
117 for (d = 0; d < depth; d++, mask <<= 1) {
118 if (!(planemask & mask))
119 rop[d] = RROP_NOP;
120 else if (!(bg & mask)) {
121 /* Both fg and bg have a 0 or 1 in this plane */
122 if (fg & mask)
123 rop[d] = RROP_WHITE;
124 else
125 rop[d] = RROP_BLACK;
126 } else {
127 /* Both fg and bg have different bits on this plane */
128 if (fg & mask)
129 rop[d] = RROP_COPY;
130 else
131 rop[d] = RROP_INVERT;
136 Bool
137 afbCreateGC(pGC)
138 register GCPtr pGC;
140 afbPrivGC *pPriv;
142 pGC->clientClip = NULL;
143 pGC->clientClipType = CT_NONE;
145 /* some of the output primitives aren't really necessary, since
146 they will be filled in ValidateGC because of dix/CreateGC()
147 setting all the change bits. Others are necessary because although
148 they depend on being a monochrome frame buffer, they don't change
151 pGC->ops = &afbGCOps;
152 pGC->funcs = &afbFuncs;
154 /* afb wants to translate before scan convesion */
155 pGC->miTranslate = 1;
157 pPriv = (afbPrivGC *)(pGC->devPrivates[afbGCPrivateIndex].ptr);
158 afbReduceRop(pGC->alu, pGC->fgPixel, pGC->planemask, pGC->depth,
159 pPriv->rrops);
160 afbReduceOpaqueStipple(pGC->fgPixel, pGC->bgPixel, pGC->planemask,
161 pGC->depth, pPriv->rropOS);
163 pGC->fExpose = TRUE;
164 pGC->pRotatedPixmap = NullPixmap;
165 pGC->freeCompClip = FALSE;
166 return TRUE;
169 static void
170 afbComputeCompositeClip(GCPtr pGC, DrawablePtr pDrawable)
172 if (pDrawable->type == DRAWABLE_WINDOW) {
173 WindowPtr pWin = (WindowPtr) pDrawable;
174 RegionPtr pregWin;
175 Bool freeTmpClip, freeCompClip;
177 if (pGC->subWindowMode == IncludeInferiors) {
178 pregWin = NotClippedByChildren(pWin);
179 freeTmpClip = TRUE;
180 } else {
181 pregWin = &pWin->clipList;
182 freeTmpClip = FALSE;
184 freeCompClip = pGC->freeCompClip;
187 * if there is no client clip, we can get by with just keeping the
188 * pointer we got, and remembering whether or not should destroy (or
189 * maybe re-use) it later. this way, we avoid unnecessary copying of
190 * regions. (this wins especially if many clients clip by children
191 * and have no client clip.)
193 if (pGC->clientClipType == CT_NONE) {
194 if (freeCompClip)
195 REGION_DESTROY(pGC->pScreen, pGC->pCompositeClip);
196 pGC->pCompositeClip = pregWin;
197 pGC->freeCompClip = freeTmpClip;
198 } else {
200 * we need one 'real' region to put into the composite clip. if
201 * pregWin the current composite clip are real, we can get rid of
202 * one. if pregWin is real and the current composite clip isn't,
203 * use pregWin for the composite clip. if the current composite
204 * clip is real and pregWin isn't, use the current composite
205 * clip. if neither is real, create a new region.
208 REGION_TRANSLATE(pGC->pScreen, pGC->clientClip,
209 pDrawable->x + pGC->clipOrg.x,
210 pDrawable->y + pGC->clipOrg.y);
212 if (freeCompClip) {
213 REGION_INTERSECT(pGC->pScreen, pGC->pCompositeClip, pregWin,
214 pGC->clientClip);
215 if (freeTmpClip)
216 REGION_DESTROY(pGC->pScreen, pregWin);
217 } else if (freeTmpClip) {
218 REGION_INTERSECT(pGC->pScreen, pregWin, pregWin, pGC->clientClip);
219 pGC->pCompositeClip = pregWin;
220 } else {
221 pGC->pCompositeClip = REGION_CREATE(pGC->pScreen, NullBox, 0);
222 REGION_INTERSECT(pGC->pScreen, pGC->pCompositeClip,
223 pregWin, pGC->clientClip);
225 pGC->freeCompClip = TRUE;
226 REGION_TRANSLATE(pGC->pScreen, pGC->clientClip,
227 -(pDrawable->x + pGC->clipOrg.x),
228 -(pDrawable->y + pGC->clipOrg.y));
230 } /* end of composite clip for a window */
231 else {
232 BoxRec pixbounds;
234 /* XXX should we translate by drawable.x/y here ? */
235 pixbounds.x1 = 0;
236 pixbounds.y1 = 0;
237 pixbounds.x2 = pDrawable->width;
238 pixbounds.y2 = pDrawable->height;
240 if (pGC->freeCompClip) {
241 REGION_RESET(pGC->pScreen, pGC->pCompositeClip, &pixbounds);
242 } else {
243 pGC->freeCompClip = TRUE;
244 pGC->pCompositeClip = REGION_CREATE(pGC->pScreen, &pixbounds, 1);
247 if (pGC->clientClipType == CT_REGION) {
248 REGION_TRANSLATE(pGC->pScreen, pGC->pCompositeClip, -pGC->clipOrg.x,
249 -pGC->clipOrg.y);
250 REGION_INTERSECT(pGC->pScreen, pGC->pCompositeClip,
251 pGC->pCompositeClip, pGC->clientClip);
252 REGION_TRANSLATE(pGC->pScreen, pGC->pCompositeClip, pGC->clipOrg.x,
253 pGC->clipOrg.y);
255 } /* end of composite clip for pixmap */
256 } /* end afbComputeCompositeClip */
258 /* Clipping conventions
259 if the drawable is a window
260 CT_REGION ==> pCompositeClip really is the composite
261 CT_other ==> pCompositeClip is the window clip region
262 if the drawable is a pixmap
263 CT_REGION ==> pCompositeClip is the translated client region
264 clipped to the pixmap boundary
265 CT_other ==> pCompositeClip is the pixmap bounding box
268 /*ARGSUSED*/
269 static void
270 afbValidateGC(pGC, changes, pDrawable)
271 register GCPtr pGC;
272 unsigned long changes;
273 DrawablePtr pDrawable;
275 register afbPrivGCPtr devPriv;
276 int mask; /* stateChanges */
277 int index; /* used for stepping through bitfields */
278 int xrot, yrot; /* rotations for tile and stipple pattern */
279 /* flags for changing the proc vector
280 and updating things in devPriv
282 int new_rotate, new_rrop, new_line, new_text, new_fill;
283 DDXPointRec oldOrg; /* origin of thing GC was last used with */
285 oldOrg = pGC->lastWinOrg;
287 pGC->lastWinOrg.x = pDrawable->x;
288 pGC->lastWinOrg.y = pDrawable->y;
290 /* we need to re-rotate the tile if the previous window/pixmap
291 origin (oldOrg) differs from the new window/pixmap origin
292 (pGC->lastWinOrg)
294 new_rotate = (oldOrg.x != pGC->lastWinOrg.x) ||
295 (oldOrg.y != pGC->lastWinOrg.y);
298 devPriv = ((afbPrivGCPtr)(pGC->devPrivates[afbGCPrivateIndex].ptr));
302 if the client clip is different or moved OR
303 the subwindowMode has changed OR
304 the window's clip has changed since the last validation
305 we need to recompute the composite clip
307 if ((changes & (GCClipXOrigin|GCClipYOrigin|GCClipMask|GCSubwindowMode)) ||
308 (pDrawable->serialNumber != (pGC->serialNumber & DRAWABLE_SERIAL_BITS)))
309 afbComputeCompositeClip(pGC, pDrawable);
311 new_rrop = FALSE;
312 new_line = FALSE;
313 new_text = FALSE;
314 new_fill = FALSE;
316 mask = changes;
317 while (mask) {
318 index = lowbit(mask);
319 mask &= ~index;
321 /* this switch acculmulates a list of which procedures
322 might have to change due to changes in the GC. in
323 some cases (e.g. changing one 16 bit tile for another)
324 we might not really need a change, but the code is
325 being paranoid.
326 this sort of batching wins if, for example, the alu
327 and the font have been changed, or any other pair
328 of items that both change the same thing.
330 switch (index) {
331 case GCPlaneMask:
332 case GCFunction:
333 case GCForeground:
334 new_rrop = TRUE;
335 break;
336 case GCBackground:
337 new_rrop = TRUE; /* for opaque stipples */
338 break;
339 case GCLineStyle:
340 case GCLineWidth:
341 case GCJoinStyle:
342 new_line = TRUE;
343 break;
344 case GCCapStyle:
345 break;
346 case GCFillStyle:
347 new_fill = TRUE;
348 break;
349 case GCFillRule:
350 break;
351 case GCTile:
352 if(pGC->tileIsPixel)
353 break;
354 new_rotate = TRUE;
355 new_fill = TRUE;
356 break;
358 case GCStipple:
359 if(pGC->stipple == (PixmapPtr)NULL)
360 break;
361 new_rotate = TRUE;
362 new_fill = TRUE;
363 break;
365 case GCTileStipXOrigin:
366 new_rotate = TRUE;
367 break;
369 case GCTileStipYOrigin:
370 new_rotate = TRUE;
371 break;
373 case GCFont:
374 new_text = TRUE;
375 break;
376 case GCSubwindowMode:
377 break;
378 case GCGraphicsExposures:
379 break;
380 case GCClipXOrigin:
381 break;
382 case GCClipYOrigin:
383 break;
384 case GCClipMask:
385 break;
386 case GCDashOffset:
387 break;
388 case GCDashList:
389 break;
390 case GCArcMode:
391 break;
392 default:
393 break;
397 /* deal with the changes we've collected .
398 new_rrop must be done first because subsequent things
399 depend on it.
402 if(new_rotate || new_fill) {
403 Bool new_pix = FALSE;
405 /* figure out how much to rotate */
406 xrot = pGC->patOrg.x;
407 yrot = pGC->patOrg.y;
408 xrot += pDrawable->x;
409 yrot += pDrawable->y;
411 switch (pGC->fillStyle) {
412 case FillTiled:
413 /* copy current tile and stipple */
414 if (!pGC->tileIsPixel &&
415 (pGC->tile.pixmap->drawable.width <= PPW) &&
416 !(pGC->tile.pixmap->drawable.width &
417 (pGC->tile.pixmap->drawable.width - 1))) {
418 afbCopyRotatePixmap(pGC->tile.pixmap, &pGC->pRotatedPixmap,
419 xrot, yrot);
420 new_pix = TRUE;
422 break;
423 case FillStippled:
424 case FillOpaqueStippled:
425 if (pGC->stipple && (pGC->stipple->drawable.width <= PPW) &&
426 !(pGC->stipple->drawable.width &
427 (pGC->stipple->drawable.width - 1))) {
428 afbCopyRotatePixmap(pGC->stipple, &pGC->pRotatedPixmap,
429 xrot, yrot);
430 new_pix = TRUE;
433 /* destroy any previously rotated tile or stipple */
434 if (!new_pix && pGC->pRotatedPixmap) {
435 (*pDrawable->pScreen->DestroyPixmap)(pGC->pRotatedPixmap);
436 pGC->pRotatedPixmap = (PixmapPtr)NULL;
441 * duck out here when the GC is unchanged
444 if (!changes)
445 return;
447 if (new_rrop || new_fill) {
448 afbReduceRop(pGC->alu, pGC->fgPixel, pGC->planemask, pDrawable->depth,
449 devPriv->rrops);
450 afbReduceOpaqueStipple(pGC->fgPixel, pGC->bgPixel, pGC->planemask,
451 pGC->depth, devPriv->rropOS);
452 new_fill = TRUE;
455 if (new_line || new_fill || new_text) {
456 if (!pGC->ops->devPrivate.val) {
457 pGC->ops = miCreateGCOps(pGC->ops);
458 pGC->ops->devPrivate.val = 1;
462 if (new_line || new_fill) {
463 if (pGC->lineWidth == 0) {
464 if (pGC->lineStyle == LineSolid && pGC->fillStyle == FillSolid)
465 pGC->ops->PolyArc = afbZeroPolyArcSS;
466 else
467 pGC->ops->PolyArc = miZeroPolyArc;
468 } else
469 pGC->ops->PolyArc = miPolyArc;
470 if (pGC->lineStyle == LineSolid) {
471 if(pGC->lineWidth == 0) {
472 if (pGC->fillStyle == FillSolid) {
473 pGC->ops->PolySegment = afbSegmentSS;
474 pGC->ops->Polylines = afbLineSS;
476 else
478 pGC->ops->PolySegment = miPolySegment;
479 pGC->ops->Polylines = miZeroLine;
481 } else {
482 pGC->ops->PolySegment = miPolySegment;
483 pGC->ops->Polylines = miWideLine;
485 } else {
486 if(pGC->lineWidth == 0 && pGC->fillStyle == FillSolid) {
487 pGC->ops->PolySegment = afbSegmentSD;
488 pGC->ops->Polylines = afbLineSD;
489 } else {
490 pGC->ops->PolySegment = miPolySegment;
491 pGC->ops->Polylines = miWideDash;
496 if (new_text || new_fill) {
497 if ((pGC->font) &&
498 (FONTMAXBOUNDS(pGC->font,rightSideBearing) -
499 FONTMINBOUNDS(pGC->font,leftSideBearing) > 32 ||
500 FONTMINBOUNDS(pGC->font,characterWidth) < 0)) {
501 pGC->ops->PolyGlyphBlt = miPolyGlyphBlt;
502 pGC->ops->ImageGlyphBlt = miImageGlyphBlt;
503 } else {
504 /* special case ImageGlyphBlt for terminal emulator fonts */
505 if ((pGC->font) &&
506 TERMINALFONT(pGC->font)) {
507 pGC->ops->ImageGlyphBlt = afbTEGlyphBlt;
508 } else {
509 pGC->ops->ImageGlyphBlt = afbImageGlyphBlt;
512 /* now do PolyGlyphBlt */
513 if (pGC->fillStyle == FillSolid) {
514 pGC->ops->PolyGlyphBlt = afbPolyGlyphBlt;
515 } else {
516 pGC->ops->PolyGlyphBlt = miPolyGlyphBlt;
521 if (new_fill) {
522 /* install a suitable fillspans and pushpixels */
523 pGC->ops->PushPixels = afbPushPixels;
524 pGC->ops->FillPolygon = miFillPolygon;
525 pGC->ops->PolyFillArc = miPolyFillArc;
527 switch (pGC->fillStyle) {
528 case FillSolid:
529 pGC->ops->FillSpans = afbSolidFS;
530 pGC->ops->FillPolygon = afbFillPolygonSolid;
531 pGC->ops->PolyFillArc = afbPolyFillArcSolid;
532 break;
533 case FillTiled:
534 if (pGC->pRotatedPixmap)
535 pGC->ops->FillSpans = afbTileFS;
536 else
537 pGC->ops->FillSpans = afbUnnaturalTileFS;
538 break;
539 case FillOpaqueStippled:
540 if (pGC->pRotatedPixmap)
541 pGC->ops->FillSpans = afbOpaqueStippleFS;
542 else
543 pGC->ops->FillSpans = afbUnnaturalOpaqueStippleFS;
544 break;
546 case FillStippled:
547 if (pGC->pRotatedPixmap)
548 pGC->ops->FillSpans = afbStippleFS;
549 else
550 pGC->ops->FillSpans = afbUnnaturalStippleFS;
551 break;
553 } /* end of new_fill */
556 static void
557 afbDestroyGC(pGC)
558 GCPtr pGC;
560 if (pGC->pRotatedPixmap)
561 (*pGC->pScreen->DestroyPixmap)(pGC->pRotatedPixmap);
562 if (pGC->freeCompClip)
563 REGION_DESTROY(pGC->pScreen, pGC->pCompositeClip);
564 miDestroyGCOps(pGC->ops);
567 void
568 afbReduceRop(alu, src, planemask, depth, rop)
569 register int alu;
570 register Pixel src;
571 register unsigned long planemask;
572 int depth;
573 register unsigned char *rop;
575 register int d;
576 register Pixel mask = 1;
578 for (d = 0; d < depth; d++, mask <<= 1) {
579 if (!(planemask & mask))
580 rop[d] = RROP_NOP;
581 else if ((src & mask) == 0) /* src is black */
582 switch (alu) {
583 case GXclear:
584 rop[d] = RROP_BLACK;
585 break;
586 case GXand:
587 rop[d] = RROP_BLACK;
588 break;
589 case GXandReverse:
590 rop[d] = RROP_BLACK;
591 break;
592 case GXcopy:
593 rop[d] = RROP_BLACK;
594 break;
595 case GXandInverted:
596 rop[d] = RROP_NOP;
597 break;
598 case GXnoop:
599 rop[d] = RROP_NOP;
600 break;
601 case GXxor:
602 rop[d] = RROP_NOP;
603 break;
604 case GXor:
605 rop[d] = RROP_NOP;
606 break;
607 case GXnor:
608 rop[d] = RROP_INVERT;
609 break;
610 case GXequiv:
611 rop[d] = RROP_INVERT;
612 break;
613 case GXinvert:
614 rop[d] = RROP_INVERT;
615 break;
616 case GXorReverse:
617 rop[d] = RROP_INVERT;
618 break;
619 case GXcopyInverted:
620 rop[d] = RROP_WHITE;
621 break;
622 case GXorInverted:
623 rop[d] = RROP_WHITE;
624 break;
625 case GXnand:
626 rop[d] = RROP_WHITE;
627 break;
628 case GXset:
629 rop[d] = RROP_WHITE;
630 break;
632 else /* src is white */
633 switch (alu) {
634 case GXclear:
635 rop[d] = RROP_BLACK;
636 break;
637 case GXand:
638 rop[d] = RROP_NOP;
639 break;
640 case GXandReverse:
641 rop[d] = RROP_INVERT;
642 break;
643 case GXcopy:
644 rop[d] = RROP_WHITE;
645 break;
646 case GXandInverted:
647 rop[d] = RROP_BLACK;
648 break;
649 case GXnoop:
650 rop[d] = RROP_NOP;
651 break;
652 case GXxor:
653 rop[d] = RROP_INVERT;
654 break;
655 case GXor:
656 rop[d] = RROP_WHITE;
657 break;
658 case GXnor:
659 rop[d] = RROP_BLACK;
660 break;
661 case GXequiv:
662 rop[d] = RROP_NOP;
663 break;
664 case GXinvert:
665 rop[d] = RROP_INVERT;
666 break;
667 case GXorReverse:
668 rop[d] = RROP_WHITE;
669 break;
670 case GXcopyInverted:
671 rop[d] = RROP_BLACK;
672 break;
673 case GXorInverted:
674 rop[d] = RROP_NOP;
675 break;
676 case GXnand:
677 rop[d] = RROP_INVERT;
678 break;
679 case GXset:
680 rop[d] = RROP_WHITE;
681 break;