xref: /OK3568_Linux_fs/external/xserver/hw/dmx/dmxgc.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /*
2  * Copyright 2001-2004 Red Hat Inc., Durham, North Carolina.
3  *
4  * All Rights Reserved.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining
7  * a copy of this software and associated documentation files (the
8  * "Software"), to deal in the Software without restriction, including
9  * without limitation on the rights to use, copy, modify, merge,
10  * publish, distribute, sublicense, and/or sell copies of the Software,
11  * and to permit persons to whom the Software is furnished to do so,
12  * subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice (including the
15  * next paragraph) shall be included in all copies or substantial
16  * portions of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21  * NON-INFRINGEMENT.  IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
22  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
23  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25  * SOFTWARE.
26  */
27 
28 /*
29  * Authors:
30  *   Kevin E. Martin <kem@redhat.com>
31  *
32  */
33 
34 /** \file
35  * This file provides support for GCs. */
36 
37 #ifdef HAVE_DMX_CONFIG_H
38 #include <dmx-config.h>
39 #endif
40 
41 #include "dmx.h"
42 #include "dmxsync.h"
43 #include "dmxgc.h"
44 #include "dmxgcops.h"
45 #include "dmxpixmap.h"
46 #include "dmxfont.h"
47 
48 #include "gcstruct.h"
49 #include "pixmapstr.h"
50 #include "migc.h"
51 
52 static const GCFuncs dmxGCFuncs = {
53     dmxValidateGC,
54     dmxChangeGC,
55     dmxCopyGC,
56     dmxDestroyGC,
57     dmxChangeClip,
58     dmxDestroyClip,
59     dmxCopyClip,
60 };
61 
62 static const GCOps dmxGCOps = {
63     dmxFillSpans,
64     dmxSetSpans,
65     dmxPutImage,
66     dmxCopyArea,
67     dmxCopyPlane,
68     dmxPolyPoint,
69     dmxPolylines,
70     dmxPolySegment,
71     dmxPolyRectangle,
72     dmxPolyArc,
73     dmxFillPolygon,
74     dmxPolyFillRect,
75     dmxPolyFillArc,
76     dmxPolyText8,
77     dmxPolyText16,
78     dmxImageText8,
79     dmxImageText16,
80     dmxImageGlyphBlt,
81     dmxPolyGlyphBlt,
82     dmxPushPixels
83 };
84 
85 /** Initialize the GC on \a pScreen */
86 Bool
dmxInitGC(ScreenPtr pScreen)87 dmxInitGC(ScreenPtr pScreen)
88 {
89     if (!dixRegisterPrivateKey
90         (&dmxGCPrivateKeyRec, PRIVATE_GC, sizeof(dmxGCPrivRec)))
91         return FALSE;
92     return TRUE;
93 }
94 
95 /** Create the GC on the back-end server. */
96 void
dmxBECreateGC(ScreenPtr pScreen,GCPtr pGC)97 dmxBECreateGC(ScreenPtr pScreen, GCPtr pGC)
98 {
99     DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
100     dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC);
101     int i;
102 
103     for (i = 0; i < dmxScreen->beNumPixmapFormats; i++) {
104         if (pGC->depth == dmxScreen->bePixmapFormats[i].depth) {
105             unsigned long mask;
106             XGCValues gcvals;
107 
108             mask = GCGraphicsExposures;
109             gcvals.graphics_exposures = FALSE;
110 
111             /* Create GC in the back-end servers */
112             pGCPriv->gc = XCreateGC(dmxScreen->beDisplay,
113                                     dmxScreen->scrnDefDrawables[i],
114                                     mask, &gcvals);
115             break;
116         }
117     }
118 }
119 
120 /** Create a graphics context on the back-end server associated /a pGC's
121  *  screen. */
122 Bool
dmxCreateGC(GCPtr pGC)123 dmxCreateGC(GCPtr pGC)
124 {
125     ScreenPtr pScreen = pGC->pScreen;
126     DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
127     dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC);
128     Bool ret;
129 
130     DMX_UNWRAP(CreateGC, dmxScreen, pScreen);
131     if ((ret = pScreen->CreateGC(pGC))) {
132         /* Save the old funcs */
133         pGCPriv->funcs = pGC->funcs;
134         pGCPriv->ops = NULL;
135 
136         pGC->funcs = &dmxGCFuncs;
137 
138         if (dmxScreen->beDisplay) {
139             dmxBECreateGC(pScreen, pGC);
140         }
141         else {
142             pGCPriv->gc = NULL;
143         }
144 
145         /* Check for "magic special case"
146          * 1. see CreateGC in dix/gc.c for more info
147          * 2. see dmxChangeGC for more info
148          */
149         pGCPriv->msc = (!pGC->tileIsPixel && !pGC->tile.pixmap);
150     }
151     DMX_WRAP(CreateGC, dmxCreateGC, dmxScreen, pScreen);
152 
153     return ret;
154 }
155 
156 /** Validate a graphics context, \a pGC, locally in the DMX server and
157  *  recompute the composite clip, if necessary. */
158 void
dmxValidateGC(GCPtr pGC,unsigned long changes,DrawablePtr pDrawable)159 dmxValidateGC(GCPtr pGC, unsigned long changes, DrawablePtr pDrawable)
160 {
161     dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC);
162 
163     DMX_GC_FUNC_PROLOGUE(pGC);
164 #if 0
165     pGC->funcs->ValidateGC(pGC, changes, pDrawable);
166 #endif
167 
168     if (pDrawable->type == DRAWABLE_WINDOW ||
169         pDrawable->type == DRAWABLE_PIXMAP) {
170         /* Save the old ops, since we're about to change the ops in the
171          * epilogue.
172          */
173         pGCPriv->ops = pGC->ops;
174     }
175     else {
176         pGCPriv->ops = NULL;
177     }
178 
179     /* If the client clip is different or moved OR the subwindowMode has
180      * changed OR the window's clip has changed since the last
181      * validation, then we need to recompute the composite clip.
182      */
183     if ((changes & (GCClipXOrigin |
184                     GCClipYOrigin |
185                     GCClipMask |
186                     GCSubwindowMode)) ||
187         (pDrawable->serialNumber !=
188          (pGC->serialNumber & DRAWABLE_SERIAL_BITS))) {
189         miComputeCompositeClip(pGC, pDrawable);
190     }
191 
192     DMX_GC_FUNC_EPILOGUE(pGC);
193 }
194 
195 /** Set the values in the graphics context on the back-end server
196  *  associated with \a pGC's screen. */
197 void
dmxChangeGC(GCPtr pGC,unsigned long mask)198 dmxChangeGC(GCPtr pGC, unsigned long mask)
199 {
200     ScreenPtr pScreen = pGC->pScreen;
201     DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
202     dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC);
203     XGCValues v;
204 
205     DMX_GC_FUNC_PROLOGUE(pGC);
206 #if 0
207     pGC->funcs->ChangeGC(pGC, mask);
208 #endif
209 
210     /* Handle "magic special case" from CreateGC */
211     if (pGCPriv->msc) {
212         /* The "magic special case" is used to handle the case where a
213          * foreground pixel is set when the GC is created so that a
214          * "pseudo default-tile" can be created and used in case the
215          * fillstyle was set to FillTiled.  This specific case is tested
216          * in xtest (XCreateGC test #3).  What has happened in dix by
217          * the time it reaches here is (1) the pGC->tile.pixel has been
218          * set to pGC->fgPixel and pGC->tileIsPixel is set, (2) if a
219          * tile has also been set, then pGC->tileIsPixel is unset and
220          * pGC->tile.pixmap is initialized; else, the default tile is
221          * created and pGC->tileIsPixel is unset and pGC->tile.pixmap is
222          * initialized to the "pseudo default-tile".  In either case,
223          * pGC->tile.pixmap is set; however, in the "magic special case"
224          * the mask is not updated to allow us to detect that we should
225          * initialize the GCTile in the back-end server.  Thus, we catch
226          * this case in dmxCreateGC and add GCTile to the mask here.
227          * Are there any cases that I've missed?
228          */
229 
230         /* Make sure that the tile.pixmap is set, just in case the user
231          * set GCTile in the mask but forgot to set vals.pixmap
232          */
233         if (pGC->tile.pixmap)
234             mask |= GCTile;
235 
236         /* This only happens once when the GC is created */
237         pGCPriv->msc = FALSE;
238     }
239 
240     /* Update back-end server's gc */
241     if (mask & GCFunction)
242         v.function = pGC->alu;
243     if (mask & GCPlaneMask)
244         v.plane_mask = pGC->planemask;
245     if (mask & GCForeground)
246         v.foreground = pGC->fgPixel;
247     if (mask & GCBackground)
248         v.background = pGC->bgPixel;
249     if (mask & GCLineWidth)
250         v.line_width = pGC->lineWidth;
251     if (mask & GCLineStyle)
252         v.line_style = pGC->lineStyle;
253     if (mask & GCCapStyle)
254         v.cap_style = pGC->capStyle;
255     if (mask & GCJoinStyle)
256         v.join_style = pGC->joinStyle;
257     if (mask & GCFillStyle)
258         v.fill_style = pGC->fillStyle;
259     if (mask & GCFillRule)
260         v.fill_rule = pGC->fillRule;
261     if (mask & GCTile) {
262         if (pGC->tileIsPixel) {
263             mask &= ~GCTile;
264         }
265         else {
266             dmxPixPrivPtr pPixPriv = DMX_GET_PIXMAP_PRIV(pGC->tile.pixmap);
267 
268             v.tile = (Drawable) pPixPriv->pixmap;
269         }
270     }
271     if (mask & GCStipple) {
272         dmxPixPrivPtr pPixPriv = DMX_GET_PIXMAP_PRIV(pGC->stipple);
273 
274         v.stipple = (Drawable) pPixPriv->pixmap;
275     }
276     if (mask & GCTileStipXOrigin)
277         v.ts_x_origin = pGC->patOrg.x;
278     if (mask & GCTileStipYOrigin)
279         v.ts_y_origin = pGC->patOrg.y;
280     if (mask & GCFont) {
281         if (dmxScreen->beDisplay) {
282             dmxFontPrivPtr pFontPriv;
283 
284             pFontPriv = FontGetPrivate(pGC->font, dmxFontPrivateIndex);
285             v.font = pFontPriv->font[pScreen->myNum]->fid;
286         }
287         else {
288             mask &= ~GCFont;
289         }
290     }
291     if (mask & GCSubwindowMode)
292         v.subwindow_mode = pGC->subWindowMode;
293 
294     /* Graphics exposures are not needed on the back-ends since they can
295        be generated on the front-end thereby saving bandwidth. */
296     if (mask & GCGraphicsExposures)
297         mask &= ~GCGraphicsExposures;
298 
299     if (mask & GCClipXOrigin)
300         v.clip_x_origin = pGC->clipOrg.x;
301     if (mask & GCClipYOrigin)
302         v.clip_y_origin = pGC->clipOrg.y;
303     if (mask & GCClipMask)
304         mask &= ~GCClipMask;    /* See ChangeClip */
305     if (mask & GCDashOffset)
306         v.dash_offset = pGC->dashOffset;
307     if (mask & GCDashList) {
308         mask &= ~GCDashList;
309         if (dmxScreen->beDisplay)
310             XSetDashes(dmxScreen->beDisplay, pGCPriv->gc,
311                        pGC->dashOffset, (char *) pGC->dash, pGC->numInDashList);
312     }
313     if (mask & GCArcMode)
314         v.arc_mode = pGC->arcMode;
315 
316     if (mask && dmxScreen->beDisplay) {
317         XChangeGC(dmxScreen->beDisplay, pGCPriv->gc, mask, &v);
318         dmxSync(dmxScreen, FALSE);
319     }
320 
321     DMX_GC_FUNC_EPILOGUE(pGC);
322 }
323 
324 /** Copy \a pGCSrc to \a pGCDst on the back-end server associated with
325  *  \a pGCSrc's screen. */
326 void
dmxCopyGC(GCPtr pGCSrc,unsigned long changes,GCPtr pGCDst)327 dmxCopyGC(GCPtr pGCSrc, unsigned long changes, GCPtr pGCDst)
328 {
329     ScreenPtr pScreen = pGCSrc->pScreen;
330     DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
331     dmxGCPrivPtr pGCSrcPriv = DMX_GET_GC_PRIV(pGCSrc);
332     dmxGCPrivPtr pGCDstPriv = DMX_GET_GC_PRIV(pGCDst);
333 
334     DMX_GC_FUNC_PROLOGUE(pGCDst);
335     pGCDst->funcs->CopyGC(pGCSrc, changes, pGCDst);
336 
337     /* Copy the GC on the back-end server */
338     if (dmxScreen->beDisplay)
339         XCopyGC(dmxScreen->beDisplay, pGCSrcPriv->gc, changes, pGCDstPriv->gc);
340 
341     DMX_GC_FUNC_EPILOGUE(pGCDst);
342 }
343 
344 /** Free the \a pGC on the back-end server. */
345 Bool
dmxBEFreeGC(GCPtr pGC)346 dmxBEFreeGC(GCPtr pGC)
347 {
348     ScreenPtr pScreen = pGC->pScreen;
349     DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
350     dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC);
351 
352     if (pGCPriv->gc) {
353         XFreeGC(dmxScreen->beDisplay, pGCPriv->gc);
354         pGCPriv->gc = NULL;
355         return TRUE;
356     }
357 
358     return FALSE;
359 }
360 
361 /** Destroy the graphics context, \a pGC and free the corresponding GC
362  *  on the back-end server. */
363 void
dmxDestroyGC(GCPtr pGC)364 dmxDestroyGC(GCPtr pGC)
365 {
366     ScreenPtr pScreen = pGC->pScreen;
367     DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
368 
369     DMX_GC_FUNC_PROLOGUE(pGC);
370 
371     /* Free the GC on the back-end server */
372     if (dmxScreen->beDisplay)
373         dmxBEFreeGC(pGC);
374 
375     pGC->funcs->DestroyGC(pGC);
376     DMX_GC_FUNC_EPILOGUE(pGC);
377 }
378 
379 /** Change the clip rects for a GC. */
380 void
dmxChangeClip(GCPtr pGC,int type,void * pvalue,int nrects)381 dmxChangeClip(GCPtr pGC, int type, void *pvalue, int nrects)
382 {
383     ScreenPtr pScreen = pGC->pScreen;
384     DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
385     dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC);
386     XRectangle *pRects;
387     BoxPtr pBox;
388     int i, nRects;
389 
390     DMX_GC_FUNC_PROLOGUE(pGC);
391     pGC->funcs->ChangeClip(pGC, type, pvalue, nrects);
392 
393     /* Set the client clip on the back-end server */
394     if (!pGC->clientClip) {
395         if (dmxScreen->beDisplay)
396             XSetClipMask(dmxScreen->beDisplay, pGCPriv->gc, None);
397     } else {
398         if (dmxScreen->beDisplay) {
399             nRects = RegionNumRects((RegionPtr) pGC->clientClip);
400             pRects = xallocarray(nRects, sizeof(*pRects));
401             pBox = RegionRects((RegionPtr) pGC->clientClip);
402 
403             for (i = 0; i < nRects; i++) {
404                 pRects[i].x = pBox[i].x1;
405                 pRects[i].y = pBox[i].y1;
406                 pRects[i].width = pBox[i].x2 - pBox[i].x1;
407                 pRects[i].height = pBox[i].y2 - pBox[i].y1;
408             }
409 
410             XSetClipRectangles(dmxScreen->beDisplay, pGCPriv->gc,
411                                pGC->clipOrg.x, pGC->clipOrg.y,
412                                pRects, nRects, Unsorted);
413 
414             free(pRects);
415         }
416     }
417 
418     DMX_GC_FUNC_EPILOGUE(pGC);
419 }
420 
421 /** Destroy a GC's clip rects. */
422 void
dmxDestroyClip(GCPtr pGC)423 dmxDestroyClip(GCPtr pGC)
424 {
425     ScreenPtr pScreen = pGC->pScreen;
426     DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
427     dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC);
428 
429     DMX_GC_FUNC_PROLOGUE(pGC);
430     pGC->funcs->DestroyClip(pGC);
431 
432     /* Set the client clip on the back-end server to None */
433     if (dmxScreen->beDisplay)
434         XSetClipMask(dmxScreen->beDisplay, pGCPriv->gc, None);
435 
436     DMX_GC_FUNC_EPILOGUE(pGC);
437 }
438 
439 /** Copy a GC's clip rects. */
440 void
dmxCopyClip(GCPtr pGCDst,GCPtr pGCSrc)441 dmxCopyClip(GCPtr pGCDst, GCPtr pGCSrc)
442 {
443     DMX_GC_FUNC_PROLOGUE(pGCDst);
444     pGCDst->funcs->CopyClip(pGCDst, pGCSrc);
445     DMX_GC_FUNC_EPILOGUE(pGCDst);
446 }
447