Imported Upstream version 1.15.1
[deb_xorg-server.git] / hw / dmx / dmxgc.c
CommitLineData
a09e091a
JB
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
52static GCFuncs dmxGCFuncs = {
53 dmxValidateGC,
54 dmxChangeGC,
55 dmxCopyGC,
56 dmxDestroyGC,
57 dmxChangeClip,
58 dmxDestroyClip,
59 dmxCopyClip,
60};
61
62static 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 */
86Bool
87dmxInitGC(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. */
96void
97dmxBECreateGC(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. */
122Bool
123dmxCreateGC(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. */
158void
159dmxValidateGC(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. */
197void
198dmxChangeGC(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. */
326void
327dmxCopyGC(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. */
345Bool
346dmxBEFreeGC(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. */
363void
364dmxDestroyGC(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. */
380void
381dmxChangeClip(GCPtr pGC, int type, pointer 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 switch (pGC->clientClipType) {
395 case CT_NONE:
396 if (dmxScreen->beDisplay)
397 XSetClipMask(dmxScreen->beDisplay, pGCPriv->gc, None);
398 break;
399
400 case CT_REGION:
401 if (dmxScreen->beDisplay) {
402 nRects = RegionNumRects((RegionPtr) pGC->clientClip);
403 pRects = malloc(nRects * sizeof(*pRects));
404 pBox = RegionRects((RegionPtr) pGC->clientClip);
405
406 for (i = 0; i < nRects; i++) {
407 pRects[i].x = pBox[i].x1;
408 pRects[i].y = pBox[i].y1;
409 pRects[i].width = pBox[i].x2 - pBox[i].x1;
410 pRects[i].height = pBox[i].y2 - pBox[i].y1;
411 }
412
413 XSetClipRectangles(dmxScreen->beDisplay, pGCPriv->gc,
414 pGC->clipOrg.x, pGC->clipOrg.y,
415 pRects, nRects, Unsorted);
416
417 free(pRects);
418 }
419 break;
420
421 case CT_PIXMAP:
422 /* Condensed down to REGION in the mi code */
423 break;
424 }
425
426 DMX_GC_FUNC_EPILOGUE(pGC);
427}
428
429/** Destroy a GC's clip rects. */
430void
431dmxDestroyClip(GCPtr pGC)
432{
433 ScreenPtr pScreen = pGC->pScreen;
434 DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
435 dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC);
436
437 DMX_GC_FUNC_PROLOGUE(pGC);
438 pGC->funcs->DestroyClip(pGC);
439
440 /* Set the client clip on the back-end server to None */
441 if (dmxScreen->beDisplay)
442 XSetClipMask(dmxScreen->beDisplay, pGCPriv->gc, None);
443
444 DMX_GC_FUNC_EPILOGUE(pGC);
445}
446
447/** Copy a GC's clip rects. */
448void
449dmxCopyClip(GCPtr pGCDst, GCPtr pGCSrc)
450{
451 DMX_GC_FUNC_PROLOGUE(pGCDst);
452 pGCDst->funcs->CopyClip(pGCDst, pGCSrc);
453 DMX_GC_FUNC_EPILOGUE(pGCDst);
454}